| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 // | 4 // |
| 5 // Modified by the Subzero authors. | 5 // Modified by the Subzero authors. |
| 6 // | 6 // |
| 7 //===- subzero/src/assembler_ia32.cpp - Assembler for x86-32 -------------===// | 7 //===- subzero/src/assembler_ia32.cpp - Assembler for x86-32 -------------===// |
| 8 // | 8 // |
| 9 // The Subzero Code Generator | 9 // The Subzero Code Generator |
| 10 // | 10 // |
| 11 // This file is distributed under the University of Illinois Open Source | 11 // This file is distributed under the University of Illinois Open Source |
| 12 // License. See LICENSE.TXT for details. | 12 // License. See LICENSE.TXT for details. |
| 13 // | 13 // |
| 14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
| 15 // | 15 // |
| 16 // This file implements the Assembler class for x86-32. | 16 // This file implements the Assembler class for x86-32. |
| 17 // | 17 // |
| 18 //===----------------------------------------------------------------------===// | 18 //===----------------------------------------------------------------------===// |
| 19 | 19 |
| 20 #include "assembler_ia32.h" | 20 #include "assembler_ia32.h" |
| 21 #include "IceCfg.h" | 21 #include "IceCfg.h" |
| 22 #include "IceMemoryRegion.h" | 22 #include "IceMemoryRegion.h" |
| 23 #include "IceOperand.h" | 23 #include "IceOperand.h" |
| 24 | 24 |
| 25 namespace Ice { | 25 namespace Ice { |
| 26 namespace x86 { | 26 namespace x86 { |
| 27 | 27 |
| 28 const Type BrokenType = IceType_i32; | |
| 29 | |
| 30 class DirectCallRelocation : public AssemblerFixup { | 28 class DirectCallRelocation : public AssemblerFixup { |
| 31 public: | 29 public: |
| 32 static DirectCallRelocation *create(Assembler *Asm, FixupKind Kind, | 30 static DirectCallRelocation *create(Assembler *Asm, FixupKind Kind, |
| 33 const ConstantRelocatable *Sym) { | 31 const ConstantRelocatable *Sym) { |
| 34 return new (Asm->Allocate<DirectCallRelocation>()) | 32 return new (Asm->Allocate<DirectCallRelocation>()) |
| 35 DirectCallRelocation(Kind, Sym); | 33 DirectCallRelocation(Kind, Sym); |
| 36 } | 34 } |
| 37 | 35 |
| 38 void Process(const MemoryRegion ®ion, intptr_t position) override { | 36 void Process(const MemoryRegion ®ion, intptr_t position) override { |
| 39 // Direct calls are relative to the following instruction on x86. | 37 // Direct calls are relative to the following instruction on x86. |
| 40 int32_t pointer = region.Load<int32_t>(position); | 38 int32_t pointer = region.Load<int32_t>(position); |
| 41 int32_t delta = region.start() + position + sizeof(int32_t); | 39 int32_t delta = region.start() + position + sizeof(int32_t); |
| 42 region.Store<int32_t>(position, pointer - delta); | 40 region.Store<int32_t>(position, pointer - delta); |
| 43 } | 41 } |
| 44 | 42 |
| 45 private: | 43 private: |
| 46 DirectCallRelocation(FixupKind Kind, const ConstantRelocatable *Sym) | 44 DirectCallRelocation(FixupKind Kind, const ConstantRelocatable *Sym) |
| 47 : AssemblerFixup(Kind, Sym) {} | 45 : AssemblerFixup(Kind, Sym) {} |
| 48 }; | 46 }; |
| 49 | 47 |
| 50 Address Address::ofConstPool(GlobalContext *Ctx, Assembler *Asm, | 48 Address Address::ofConstPool(GlobalContext *Ctx, Assembler *Asm, |
| 51 const Constant *Imm) { | 49 const Constant *Imm) { |
| 52 // We should make this much lighter-weight. E.g., just record the const pool | 50 // We should make this much lighter-weight. E.g., just record the const pool |
| 53 // entry ID. | 51 // entry ID. |
| 54 std::string Buffer; | 52 std::string Buffer; |
| 55 llvm::raw_string_ostream StrBuf(Buffer); | 53 llvm::raw_string_ostream StrBuf(Buffer); |
| 56 Type Ty = Imm->getType(); | 54 Type Ty = Imm->getType(); |
| 57 assert(llvm::isa<ConstantFloat>(Imm) || llvm::isa<ConstantDouble>(Imm)); | 55 assert(llvm::isa<ConstantFloat>(Imm) || llvm::isa<ConstantDouble>(Imm)); |
| 58 StrBuf << "L$" << Ty << "$" << Imm->getPoolEntryID(); | 56 StrBuf << "L$" << Ty << "$" << Imm->getPoolEntryID(); |
| 59 const int64_t Offset = 0; | 57 const RelocOffsetT Offset = 0; |
| 60 const bool SuppressMangling = true; | 58 const bool SuppressMangling = true; |
| 61 Constant *Sym = | 59 Constant *Sym = |
| 62 Ctx->getConstantSym(Ty, Offset, StrBuf.str(), SuppressMangling); | 60 Ctx->getConstantSym(Ty, Offset, StrBuf.str(), SuppressMangling); |
| 63 AssemblerFixup *Fixup = x86::DisplacementRelocation::create( | 61 AssemblerFixup *Fixup = x86::DisplacementRelocation::create( |
| 64 Asm, FK_Abs_4, llvm::cast<ConstantRelocatable>(Sym)); | 62 Asm, FK_Abs_4, llvm::cast<ConstantRelocatable>(Sym)); |
| 65 return x86::Address::Absolute(Offset, Fixup); | 63 return x86::Address::Absolute(Fixup); |
| 66 } | 64 } |
| 67 | 65 |
| 68 void AssemblerX86::call(GPRRegister reg) { | 66 void AssemblerX86::call(GPRRegister reg) { |
| 69 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 67 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 70 EmitUint8(0xFF); | 68 EmitUint8(0xFF); |
| 71 EmitRegisterOperand(2, reg); | 69 EmitRegisterOperand(2, reg); |
| 72 } | 70 } |
| 73 | 71 |
| 74 void AssemblerX86::call(const Address &address) { | 72 void AssemblerX86::call(const Address &address) { |
| 75 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 73 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 EmitUint8(0x61); | 118 EmitUint8(0x61); |
| 121 } | 119 } |
| 122 | 120 |
| 123 void AssemblerX86::setcc(CondX86::BrCond condition, ByteRegister dst) { | 121 void AssemblerX86::setcc(CondX86::BrCond condition, ByteRegister dst) { |
| 124 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 122 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 125 EmitUint8(0x0F); | 123 EmitUint8(0x0F); |
| 126 EmitUint8(0x90 + condition); | 124 EmitUint8(0x90 + condition); |
| 127 EmitUint8(0xC0 + dst); | 125 EmitUint8(0xC0 + dst); |
| 128 } | 126 } |
| 129 | 127 |
| 130 void AssemblerX86::movl(GPRRegister dst, const Immediate &imm) { | 128 void AssemblerX86::mov(Type Ty, GPRRegister dst, const Immediate &imm) { |
| 131 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 129 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 130 if (isByteSizedType(Ty)) { |
| 131 EmitUint8(0xB0 + dst); |
| 132 EmitUint8(imm.value() & 0xFF); |
| 133 return; |
| 134 } |
| 135 if (Ty == IceType_i16) |
| 136 EmitOperandSizeOverride(); |
| 132 EmitUint8(0xB8 + dst); | 137 EmitUint8(0xB8 + dst); |
| 133 EmitImmediate(BrokenType, imm); | 138 EmitImmediate(Ty, imm); |
| 134 } | 139 } |
| 135 | 140 |
| 136 void AssemblerX86::movl(GPRRegister dst, GPRRegister src) { | 141 void AssemblerX86::mov(Type Ty, GPRRegister dst, GPRRegister src) { |
| 137 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 142 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 138 EmitUint8(0x89); | 143 if (Ty == IceType_i16) |
| 144 EmitOperandSizeOverride(); |
| 145 if (isByteSizedType(Ty)) { |
| 146 EmitUint8(0x88); |
| 147 } else { |
| 148 EmitUint8(0x89); |
| 149 } |
| 139 EmitRegisterOperand(src, dst); | 150 EmitRegisterOperand(src, dst); |
| 140 } | 151 } |
| 141 | 152 |
| 142 void AssemblerX86::movl(GPRRegister dst, const Address &src) { | 153 void AssemblerX86::mov(Type Ty, GPRRegister dst, const Address &src) { |
| 143 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 154 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 144 EmitUint8(0x8B); | 155 if (Ty == IceType_i16) |
| 156 EmitOperandSizeOverride(); |
| 157 if (isByteSizedType(Ty)) { |
| 158 EmitUint8(0x8A); |
| 159 } else { |
| 160 EmitUint8(0x8B); |
| 161 } |
| 145 EmitOperand(dst, src); | 162 EmitOperand(dst, src); |
| 146 } | 163 } |
| 147 | 164 |
| 148 void AssemblerX86::movl(const Address &dst, GPRRegister src) { | 165 void AssemblerX86::mov(Type Ty, const Address &dst, GPRRegister src) { |
| 149 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 166 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 150 EmitUint8(0x89); | 167 if (Ty == IceType_i16) |
| 168 EmitOperandSizeOverride(); |
| 169 if (isByteSizedType(Ty)) { |
| 170 EmitUint8(0x88); |
| 171 } else { |
| 172 EmitUint8(0x89); |
| 173 } |
| 151 EmitOperand(src, dst); | 174 EmitOperand(src, dst); |
| 152 } | 175 } |
| 153 | 176 |
| 154 void AssemblerX86::movl(const Address &dst, const Immediate &imm) { | 177 void AssemblerX86::mov(Type Ty, const Address &dst, const Immediate &imm) { |
| 155 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 178 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 156 EmitUint8(0xC7); | 179 if (Ty == IceType_i16) |
| 157 EmitOperand(0, dst); | 180 EmitOperandSizeOverride(); |
| 158 EmitImmediate(BrokenType, imm); | 181 if (isByteSizedType(Ty)) { |
| 182 EmitUint8(0xC6); |
| 183 EmitOperand(0, dst); |
| 184 EmitUint8(imm.value() & 0xFF); |
| 185 } else { |
| 186 EmitUint8(0xC7); |
| 187 EmitOperand(0, dst); |
| 188 EmitImmediate(Ty, imm); |
| 189 } |
| 159 } | 190 } |
| 160 | 191 |
| 161 void AssemblerX86::movzxb(GPRRegister dst, ByteRegister src) { | 192 void AssemblerX86::movzxb(GPRRegister dst, ByteRegister src) { |
| 162 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 193 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 163 EmitUint8(0x0F); | 194 EmitUint8(0x0F); |
| 164 EmitUint8(0xB6); | 195 EmitUint8(0xB6); |
| 165 EmitRegisterOperand(dst, src); | 196 EmitRegisterOperand(dst, src); |
| 166 } | 197 } |
| 167 | 198 |
| 168 void AssemblerX86::movzxb(GPRRegister dst, const Address &src) { | 199 void AssemblerX86::movzxb(GPRRegister dst, const Address &src) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 179 EmitRegisterOperand(dst, src); | 210 EmitRegisterOperand(dst, src); |
| 180 } | 211 } |
| 181 | 212 |
| 182 void AssemblerX86::movsxb(GPRRegister dst, const Address &src) { | 213 void AssemblerX86::movsxb(GPRRegister dst, const Address &src) { |
| 183 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 214 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 184 EmitUint8(0x0F); | 215 EmitUint8(0x0F); |
| 185 EmitUint8(0xBE); | 216 EmitUint8(0xBE); |
| 186 EmitOperand(dst, src); | 217 EmitOperand(dst, src); |
| 187 } | 218 } |
| 188 | 219 |
| 189 void AssemblerX86::movb(ByteRegister dst, const Address &src) { | |
| 190 (void)dst; | |
| 191 (void)src; | |
| 192 // FATAL | |
| 193 llvm_unreachable("Use movzxb or movsxb instead."); | |
| 194 } | |
| 195 | |
| 196 void AssemblerX86::movb(const Address &dst, ByteRegister src) { | |
| 197 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | |
| 198 EmitUint8(0x88); | |
| 199 EmitOperand(src, dst); | |
| 200 } | |
| 201 | |
| 202 void AssemblerX86::movb(const Address &dst, const Immediate &imm) { | |
| 203 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | |
| 204 EmitUint8(0xC6); | |
| 205 EmitOperand(RegX8632::Encoded_Reg_eax, dst); | |
| 206 assert(imm.is_int8()); | |
| 207 EmitUint8(imm.value() & 0xFF); | |
| 208 } | |
| 209 | |
| 210 void AssemblerX86::movzxw(GPRRegister dst, GPRRegister src) { | 220 void AssemblerX86::movzxw(GPRRegister dst, GPRRegister src) { |
| 211 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 221 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 212 EmitUint8(0x0F); | 222 EmitUint8(0x0F); |
| 213 EmitUint8(0xB7); | 223 EmitUint8(0xB7); |
| 214 EmitRegisterOperand(dst, src); | 224 EmitRegisterOperand(dst, src); |
| 215 } | 225 } |
| 216 | 226 |
| 217 void AssemblerX86::movzxw(GPRRegister dst, const Address &src) { | 227 void AssemblerX86::movzxw(GPRRegister dst, const Address &src) { |
| 218 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 228 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 219 EmitUint8(0x0F); | 229 EmitUint8(0x0F); |
| 220 EmitUint8(0xB7); | 230 EmitUint8(0xB7); |
| 221 EmitOperand(dst, src); | 231 EmitOperand(dst, src); |
| 222 } | 232 } |
| 223 | 233 |
| 224 void AssemblerX86::movsxw(GPRRegister dst, GPRRegister src) { | 234 void AssemblerX86::movsxw(GPRRegister dst, GPRRegister src) { |
| 225 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 235 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 226 EmitUint8(0x0F); | 236 EmitUint8(0x0F); |
| 227 EmitUint8(0xBF); | 237 EmitUint8(0xBF); |
| 228 EmitRegisterOperand(dst, src); | 238 EmitRegisterOperand(dst, src); |
| 229 } | 239 } |
| 230 | 240 |
| 231 void AssemblerX86::movsxw(GPRRegister dst, const Address &src) { | 241 void AssemblerX86::movsxw(GPRRegister dst, const Address &src) { |
| 232 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 242 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 233 EmitUint8(0x0F); | 243 EmitUint8(0x0F); |
| 234 EmitUint8(0xBF); | 244 EmitUint8(0xBF); |
| 235 EmitOperand(dst, src); | 245 EmitOperand(dst, src); |
| 236 } | 246 } |
| 237 | 247 |
| 238 void AssemblerX86::movw(GPRRegister dst, const Address &src) { | |
| 239 (void)dst; | |
| 240 (void)src; | |
| 241 // FATAL | |
| 242 llvm_unreachable("Use movzxw or movsxw instead."); | |
| 243 } | |
| 244 | |
| 245 void AssemblerX86::movw(const Address &dst, GPRRegister src) { | |
| 246 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | |
| 247 EmitOperandSizeOverride(); | |
| 248 EmitUint8(0x89); | |
| 249 EmitOperand(src, dst); | |
| 250 } | |
| 251 | |
| 252 void AssemblerX86::lea(Type Ty, GPRRegister dst, const Address &src) { | 248 void AssemblerX86::lea(Type Ty, GPRRegister dst, const Address &src) { |
| 253 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 249 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 254 assert(Ty == IceType_i16 || Ty == IceType_i32); | 250 assert(Ty == IceType_i16 || Ty == IceType_i32); |
| 255 if (Ty == IceType_i16) | 251 if (Ty == IceType_i16) |
| 256 EmitOperandSizeOverride(); | 252 EmitOperandSizeOverride(); |
| 257 EmitUint8(0x8D); | 253 EmitUint8(0x8D); |
| 258 EmitOperand(dst, src); | 254 EmitOperand(dst, src); |
| 259 } | 255 } |
| 260 | 256 |
| 261 void AssemblerX86::cmov(CondX86::BrCond cond, GPRRegister dst, | 257 void AssemblerX86::cmov(CondX86::BrCond cond, GPRRegister dst, |
| (...skipping 658 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 920 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 916 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 921 EmitUint8(0x66); | 917 EmitUint8(0x66); |
| 922 EmitUint8(0x0F); | 918 EmitUint8(0x0F); |
| 923 EmitUint8(0x15); | 919 EmitUint8(0x15); |
| 924 EmitXmmRegisterOperand(dst, src); | 920 EmitXmmRegisterOperand(dst, src); |
| 925 } | 921 } |
| 926 | 922 |
| 927 void AssemblerX86::set1ps(XmmRegister dst, GPRRegister tmp1, | 923 void AssemblerX86::set1ps(XmmRegister dst, GPRRegister tmp1, |
| 928 const Immediate &imm) { | 924 const Immediate &imm) { |
| 929 // Load 32-bit immediate value into tmp1. | 925 // Load 32-bit immediate value into tmp1. |
| 930 movl(tmp1, imm); | 926 mov(IceType_i32, tmp1, imm); |
| 931 // Move value from tmp1 into dst. | 927 // Move value from tmp1 into dst. |
| 932 movd(dst, tmp1); | 928 movd(dst, tmp1); |
| 933 // Broadcast low lane into other three lanes. | 929 // Broadcast low lane into other three lanes. |
| 934 shufps(dst, dst, Immediate(0x0)); | 930 shufps(dst, dst, Immediate(0x0)); |
| 935 } | 931 } |
| 936 | 932 |
| 937 void AssemblerX86::shufps(XmmRegister dst, XmmRegister src, | 933 void AssemblerX86::shufps(XmmRegister dst, XmmRegister src, |
| 938 const Immediate &imm) { | 934 const Immediate &imm) { |
| 939 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 935 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 940 EmitUint8(0x0F); | 936 EmitUint8(0x0F); |
| (...skipping 1318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2259 if (operand.fixup()) { | 2255 if (operand.fixup()) { |
| 2260 EmitFixup(operand.fixup()); | 2256 EmitFixup(operand.fixup()); |
| 2261 } | 2257 } |
| 2262 // Emit the rest of the encoded operand. | 2258 // Emit the rest of the encoded operand. |
| 2263 for (intptr_t i = 1; i < length; i++) { | 2259 for (intptr_t i = 1; i < length; i++) { |
| 2264 EmitUint8(operand.encoding_[i]); | 2260 EmitUint8(operand.encoding_[i]); |
| 2265 } | 2261 } |
| 2266 } | 2262 } |
| 2267 | 2263 |
| 2268 void AssemblerX86::EmitImmediate(Type Ty, const Immediate &imm) { | 2264 void AssemblerX86::EmitImmediate(Type Ty, const Immediate &imm) { |
| 2269 if (Ty == IceType_i16) | 2265 if (Ty == IceType_i16) { |
| 2266 assert(!imm.fixup()); |
| 2270 EmitInt16(imm.value()); | 2267 EmitInt16(imm.value()); |
| 2271 else | 2268 } else { |
| 2269 if (imm.fixup()) { |
| 2270 EmitFixup(imm.fixup()); |
| 2271 } |
| 2272 EmitInt32(imm.value()); | 2272 EmitInt32(imm.value()); |
| 2273 } |
| 2273 } | 2274 } |
| 2274 | 2275 |
| 2275 void AssemblerX86::EmitComplexI8(int rm, const Operand &operand, | 2276 void AssemblerX86::EmitComplexI8(int rm, const Operand &operand, |
| 2276 const Immediate &immediate) { | 2277 const Immediate &immediate) { |
| 2277 assert(rm >= 0 && rm < 8); | 2278 assert(rm >= 0 && rm < 8); |
| 2278 assert(immediate.is_int8()); | 2279 assert(immediate.is_int8()); |
| 2279 if (operand.IsRegister(RegX8632::Encoded_Reg_eax)) { | 2280 if (operand.IsRegister(RegX8632::Encoded_Reg_eax)) { |
| 2280 // Use short form if the destination is al. | 2281 // Use short form if the destination is al. |
| 2281 EmitUint8(0x04 + (rm << 3)); | 2282 EmitUint8(0x04 + (rm << 3)); |
| 2282 EmitUint8(immediate.value() & 0xFF); | 2283 EmitUint8(immediate.value() & 0xFF); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2353 assert(shifter == RegX8632::Encoded_Reg_ecx); | 2354 assert(shifter == RegX8632::Encoded_Reg_ecx); |
| 2354 (void)shifter; | 2355 (void)shifter; |
| 2355 if (Ty == IceType_i16) | 2356 if (Ty == IceType_i16) |
| 2356 EmitOperandSizeOverride(); | 2357 EmitOperandSizeOverride(); |
| 2357 EmitUint8(isByteSizedArithType(Ty) ? 0xD2 : 0xD3); | 2358 EmitUint8(isByteSizedArithType(Ty) ? 0xD2 : 0xD3); |
| 2358 EmitOperand(rm, operand); | 2359 EmitOperand(rm, operand); |
| 2359 } | 2360 } |
| 2360 | 2361 |
| 2361 } // end of namespace x86 | 2362 } // end of namespace x86 |
| 2362 } // end of namespace Ice | 2363 } // end of namespace Ice |
| OLD | NEW |