| OLD | NEW |
| 1 //===- subzero/src/assembler_ia32.h - Assembler for x86-32 ------*- C++ -*-===// |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 2 // 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 | 3 // 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. | 4 // BSD-style license that can be found in the LICENSE file. |
| 4 // | 5 // |
| 5 // Modified by the Subzero authors. | 6 // Modified by the Subzero authors. |
| 6 // | 7 // |
| 7 //===- subzero/src/assembler_ia32.h - Assembler for x86-32 ----------------===// | 8 //===----------------------------------------------------------------------===// |
| 8 // | 9 // |
| 9 // The Subzero Code Generator | 10 // The Subzero Code Generator |
| 10 // | 11 // |
| 11 // This file is distributed under the University of Illinois Open Source | 12 // This file is distributed under the University of Illinois Open Source |
| 12 // License. See LICENSE.TXT for details. | 13 // License. See LICENSE.TXT for details. |
| 13 // | 14 // |
| 14 //===----------------------------------------------------------------------===// | 15 //===----------------------------------------------------------------------===// |
| 15 // | 16 // |
| 16 // This file implements the Assembler class for x86-32. | 17 // This file implements the Assembler class for x86-32. |
| 17 // | 18 // |
| (...skipping 20 matching lines...) Expand all Loading... |
| 38 using RegX8632::ByteRegister; | 39 using RegX8632::ByteRegister; |
| 39 using RegX8632::X87STRegister; | 40 using RegX8632::X87STRegister; |
| 40 | 41 |
| 41 namespace x86 { | 42 namespace x86 { |
| 42 | 43 |
| 43 const int MAX_NOP_SIZE = 8; | 44 const int MAX_NOP_SIZE = 8; |
| 44 | 45 |
| 45 enum ScaleFactor { TIMES_1 = 0, TIMES_2 = 1, TIMES_4 = 2, TIMES_8 = 3 }; | 46 enum ScaleFactor { TIMES_1 = 0, TIMES_2 = 1, TIMES_4 = 2, TIMES_8 = 3 }; |
| 46 | 47 |
| 47 class DisplacementRelocation : public AssemblerFixup { | 48 class DisplacementRelocation : public AssemblerFixup { |
| 49 DisplacementRelocation(const DisplacementRelocation &) = delete; |
| 50 DisplacementRelocation &operator=(const DisplacementRelocation &) = delete; |
| 51 |
| 48 public: | 52 public: |
| 49 static DisplacementRelocation *create(Assembler *Asm, FixupKind Kind, | 53 static DisplacementRelocation *create(Assembler *Asm, FixupKind Kind, |
| 50 const ConstantRelocatable *Sym) { | 54 const ConstantRelocatable *Sym) { |
| 51 return new (Asm->Allocate<DisplacementRelocation>()) | 55 return new (Asm->Allocate<DisplacementRelocation>()) |
| 52 DisplacementRelocation(Kind, Sym); | 56 DisplacementRelocation(Kind, Sym); |
| 53 } | 57 } |
| 54 | 58 |
| 55 void Process(const MemoryRegion ®ion, intptr_t position) override { | 59 void Process(const MemoryRegion ®ion, intptr_t position) override { |
| 56 (void)region; | 60 (void)region; |
| 57 (void)position; | 61 (void)position; |
| 58 llvm_unreachable("We might not be using this Process() method later."); | 62 llvm_unreachable("We might not be using this Process() method later."); |
| 59 } | 63 } |
| 60 | 64 |
| 61 private: | 65 private: |
| 62 DisplacementRelocation(FixupKind Kind, const ConstantRelocatable *Sym) | 66 DisplacementRelocation(FixupKind Kind, const ConstantRelocatable *Sym) |
| 63 : AssemblerFixup(Kind, Sym) {} | 67 : AssemblerFixup(Kind, Sym) {} |
| 64 DisplacementRelocation(const DisplacementRelocation &) = delete; | |
| 65 DisplacementRelocation &operator=(const DisplacementRelocation &) = delete; | |
| 66 }; | 68 }; |
| 67 | 69 |
| 68 class Immediate { | 70 class Immediate { |
| 71 Immediate(const Immediate &) = delete; |
| 72 Immediate &operator=(const Immediate &) = delete; |
| 73 |
| 69 public: | 74 public: |
| 70 explicit Immediate(int32_t value) : value_(value), fixup_(NULL) {} | 75 explicit Immediate(int32_t value) : value_(value), fixup_(NULL) {} |
| 71 | 76 |
| 72 explicit Immediate(const Immediate &other) | |
| 73 : value_(other.value_), fixup_(other.fixup_) {} | |
| 74 | |
| 75 explicit Immediate(AssemblerFixup *fixup) | 77 explicit Immediate(AssemblerFixup *fixup) |
| 76 : value_(fixup->value()->getOffset()), fixup_(fixup) { | 78 : value_(fixup->value()->getOffset()), fixup_(fixup) { |
| 77 // Use the Offset in the "value" for now. If the symbol is part of | 79 // Use the Offset in the "value" for now. If the symbol is part of |
| 78 // ".bss", then the relocation's symbol will be plain ".bss" and | 80 // ".bss", then the relocation's symbol will be plain ".bss" and |
| 79 // the value will need to be adjusted further to be sym's | 81 // the value will need to be adjusted further to be sym's |
| 80 // bss offset + Offset. | 82 // bss offset + Offset. |
| 81 } | 83 } |
| 82 | 84 |
| 83 int32_t value() const { return value_; } | 85 int32_t value() const { return value_; } |
| 84 AssemblerFixup *fixup() const { return fixup_; } | 86 AssemblerFixup *fixup() const { return fixup_; } |
| 85 | 87 |
| 86 bool is_int8() const { | 88 bool is_int8() const { |
| 87 // We currently only allow 32-bit fixups, and they usually have value = 0, | 89 // We currently only allow 32-bit fixups, and they usually have value = 0, |
| 88 // so if fixup_ != NULL, it shouldn't be classified as int8/16. | 90 // so if fixup_ != NULL, it shouldn't be classified as int8/16. |
| 89 return fixup_ == NULL && Utils::IsInt(8, value_); | 91 return fixup_ == NULL && Utils::IsInt(8, value_); |
| 90 } | 92 } |
| 91 bool is_uint8() const { return fixup_ == NULL && Utils::IsUint(8, value_); } | 93 bool is_uint8() const { return fixup_ == NULL && Utils::IsUint(8, value_); } |
| 92 bool is_uint16() const { return fixup_ == NULL && Utils::IsUint(16, value_); } | 94 bool is_uint16() const { return fixup_ == NULL && Utils::IsUint(16, value_); } |
| 93 | 95 |
| 94 private: | 96 private: |
| 95 const int32_t value_; | 97 const int32_t value_; |
| 96 AssemblerFixup *fixup_; | 98 AssemblerFixup *fixup_; |
| 97 }; | 99 }; |
| 98 | 100 |
| 99 class Operand { | 101 class Operand { |
| 100 public: | 102 public: |
| 103 Operand(const Operand &other) : length_(other.length_), fixup_(other.fixup_) { |
| 104 memmove(&encoding_[0], &other.encoding_[0], other.length_); |
| 105 } |
| 106 |
| 107 Operand &operator=(const Operand &other) { |
| 108 length_ = other.length_; |
| 109 fixup_ = other.fixup_; |
| 110 memmove(&encoding_[0], &other.encoding_[0], other.length_); |
| 111 return *this; |
| 112 } |
| 113 |
| 101 uint8_t mod() const { return (encoding_at(0) >> 6) & 3; } | 114 uint8_t mod() const { return (encoding_at(0) >> 6) & 3; } |
| 102 | 115 |
| 103 GPRRegister rm() const { | 116 GPRRegister rm() const { |
| 104 return static_cast<GPRRegister>(encoding_at(0) & 7); | 117 return static_cast<GPRRegister>(encoding_at(0) & 7); |
| 105 } | 118 } |
| 106 | 119 |
| 107 ScaleFactor scale() const { | 120 ScaleFactor scale() const { |
| 108 return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3); | 121 return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3); |
| 109 } | 122 } |
| 110 | 123 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 121 return static_cast<int8_t>(encoding_[length_ - 1]); | 134 return static_cast<int8_t>(encoding_[length_ - 1]); |
| 122 } | 135 } |
| 123 | 136 |
| 124 int32_t disp32() const { | 137 int32_t disp32() const { |
| 125 assert(length_ >= 5); | 138 assert(length_ >= 5); |
| 126 return bit_copy<int32_t>(encoding_[length_ - 4]); | 139 return bit_copy<int32_t>(encoding_[length_ - 4]); |
| 127 } | 140 } |
| 128 | 141 |
| 129 AssemblerFixup *fixup() const { return fixup_; } | 142 AssemblerFixup *fixup() const { return fixup_; } |
| 130 | 143 |
| 131 Operand(const Operand &other) : length_(other.length_), fixup_(other.fixup_) { | |
| 132 memmove(&encoding_[0], &other.encoding_[0], other.length_); | |
| 133 } | |
| 134 | |
| 135 Operand &operator=(const Operand &other) { | |
| 136 length_ = other.length_; | |
| 137 fixup_ = other.fixup_; | |
| 138 memmove(&encoding_[0], &other.encoding_[0], other.length_); | |
| 139 return *this; | |
| 140 } | |
| 141 | |
| 142 protected: | 144 protected: |
| 143 Operand() : length_(0), fixup_(NULL) {} // Needed by subclass Address. | 145 Operand() : length_(0), fixup_(NULL) {} // Needed by subclass Address. |
| 144 | 146 |
| 145 void SetModRM(int mod, GPRRegister rm) { | 147 void SetModRM(int mod, GPRRegister rm) { |
| 146 assert((mod & ~3) == 0); | 148 assert((mod & ~3) == 0); |
| 147 encoding_[0] = (mod << 6) | rm; | 149 encoding_[0] = (mod << 6) | rm; |
| 148 length_ = 1; | 150 length_ = 1; |
| 149 } | 151 } |
| 150 | 152 |
| 151 void SetSIB(ScaleFactor scale, GPRRegister index, GPRRegister base) { | 153 void SetSIB(ScaleFactor scale, GPRRegister index, GPRRegister base) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 bool IsRegister(GPRRegister reg) const { | 189 bool IsRegister(GPRRegister reg) const { |
| 188 return ((encoding_[0] & 0xF8) == 0xC0) // Addressing mode is register only. | 190 return ((encoding_[0] & 0xF8) == 0xC0) // Addressing mode is register only. |
| 189 && ((encoding_[0] & 0x07) == reg); // Register codes match. | 191 && ((encoding_[0] & 0x07) == reg); // Register codes match. |
| 190 } | 192 } |
| 191 | 193 |
| 192 friend class AssemblerX86; | 194 friend class AssemblerX86; |
| 193 }; | 195 }; |
| 194 | 196 |
| 195 class Address : public Operand { | 197 class Address : public Operand { |
| 196 public: | 198 public: |
| 199 Address(const Address &other) : Operand(other) {} |
| 200 |
| 201 Address &operator=(const Address &other) { |
| 202 Operand::operator=(other); |
| 203 return *this; |
| 204 } |
| 205 |
| 197 Address(GPRRegister base, int32_t disp) { | 206 Address(GPRRegister base, int32_t disp) { |
| 198 if (disp == 0 && base != RegX8632::Encoded_Reg_ebp) { | 207 if (disp == 0 && base != RegX8632::Encoded_Reg_ebp) { |
| 199 SetModRM(0, base); | 208 SetModRM(0, base); |
| 200 if (base == RegX8632::Encoded_Reg_esp) | 209 if (base == RegX8632::Encoded_Reg_esp) |
| 201 SetSIB(TIMES_1, RegX8632::Encoded_Reg_esp, base); | 210 SetSIB(TIMES_1, RegX8632::Encoded_Reg_esp, base); |
| 202 } else if (Utils::IsInt(8, disp)) { | 211 } else if (Utils::IsInt(8, disp)) { |
| 203 SetModRM(1, base); | 212 SetModRM(1, base); |
| 204 if (base == RegX8632::Encoded_Reg_esp) | 213 if (base == RegX8632::Encoded_Reg_esp) |
| 205 SetSIB(TIMES_1, RegX8632::Encoded_Reg_esp, base); | 214 SetSIB(TIMES_1, RegX8632::Encoded_Reg_esp, base); |
| 206 SetDisp8(disp); | 215 SetDisp8(disp); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 229 SetModRM(1, RegX8632::Encoded_Reg_esp); | 238 SetModRM(1, RegX8632::Encoded_Reg_esp); |
| 230 SetSIB(scale, index, base); | 239 SetSIB(scale, index, base); |
| 231 SetDisp8(disp); | 240 SetDisp8(disp); |
| 232 } else { | 241 } else { |
| 233 SetModRM(2, RegX8632::Encoded_Reg_esp); | 242 SetModRM(2, RegX8632::Encoded_Reg_esp); |
| 234 SetSIB(scale, index, base); | 243 SetSIB(scale, index, base); |
| 235 SetDisp32(disp); | 244 SetDisp32(disp); |
| 236 } | 245 } |
| 237 } | 246 } |
| 238 | 247 |
| 239 Address(const Address &other) : Operand(other) {} | |
| 240 | |
| 241 Address &operator=(const Address &other) { | |
| 242 Operand::operator=(other); | |
| 243 return *this; | |
| 244 } | |
| 245 | |
| 246 static Address Absolute(const uintptr_t addr) { | 248 static Address Absolute(const uintptr_t addr) { |
| 247 Address result; | 249 Address result; |
| 248 result.SetModRM(0, RegX8632::Encoded_Reg_ebp); | 250 result.SetModRM(0, RegX8632::Encoded_Reg_ebp); |
| 249 result.SetDisp32(addr); | 251 result.SetDisp32(addr); |
| 250 return result; | 252 return result; |
| 251 } | 253 } |
| 252 | 254 |
| 253 static Address Absolute(AssemblerFixup *fixup) { | 255 static Address Absolute(AssemblerFixup *fixup) { |
| 254 Address result; | 256 Address result; |
| 255 result.SetModRM(0, RegX8632::Encoded_Reg_ebp); | 257 result.SetModRM(0, RegX8632::Encoded_Reg_ebp); |
| 256 // Use the Offset in the displacement for now. If the symbol is part of | 258 // Use the Offset in the displacement for now. If the symbol is part of |
| 257 // ".bss", then the relocation's symbol will be plain .bss and the | 259 // ".bss", then the relocation's symbol will be plain .bss and the |
| 258 // displacement will need to be adjusted further to be sym's | 260 // displacement will need to be adjusted further to be sym's |
| 259 // bss offset + Offset. | 261 // bss offset + Offset. |
| 260 result.SetDisp32(fixup->value()->getOffset()); | 262 result.SetDisp32(fixup->value()->getOffset()); |
| 261 result.SetFixup(fixup); | 263 result.SetFixup(fixup); |
| 262 return result; | 264 return result; |
| 263 } | 265 } |
| 264 | 266 |
| 265 static Address ofConstPool(GlobalContext *Ctx, Assembler *Asm, | 267 static Address ofConstPool(GlobalContext *Ctx, Assembler *Asm, |
| 266 const Constant *Imm); | 268 const Constant *Imm); |
| 267 | 269 |
| 268 private: | 270 private: |
| 269 Address() {} // Needed by Address::Absolute. | 271 Address() {} // Needed by Address::Absolute. |
| 270 }; | 272 }; |
| 271 | 273 |
| 272 class Label { | 274 class Label { |
| 275 Label(const Label &) = delete; |
| 276 Label &operator=(const Label &) = delete; |
| 277 |
| 273 public: | 278 public: |
| 274 Label() : position_(0), num_unresolved_(0) { | 279 Label() : position_(0), num_unresolved_(0) { |
| 275 #ifdef DEBUG | 280 #ifndef NDEBUG |
| 276 for (int i = 0; i < kMaxUnresolvedBranches; i++) { | 281 for (int i = 0; i < kMaxUnresolvedBranches; i++) { |
| 277 unresolved_near_positions_[i] = -1; | 282 unresolved_near_positions_[i] = -1; |
| 278 } | 283 } |
| 279 #endif // DEBUG | 284 #endif // !NDEBUG |
| 280 } | 285 } |
| 281 | 286 |
| 282 ~Label() { | 287 ~Label() { |
| 283 // Assert if label is being destroyed with unresolved branches pending. | 288 // Assert if label is being destroyed with unresolved branches pending. |
| 284 assert(!IsLinked()); | 289 assert(!IsLinked()); |
| 285 assert(!HasNear()); | 290 assert(!HasNear()); |
| 286 } | 291 } |
| 287 | 292 |
| 288 // TODO(jvoung): why are labels offset by this? | 293 // TODO(jvoung): why are labels offset by this? |
| 289 static const uint32_t kWordSize = sizeof(uint32_t); | 294 static const uint32_t kWordSize = sizeof(uint32_t); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 unresolved_near_positions_[num_unresolved_++] = position; | 344 unresolved_near_positions_[num_unresolved_++] = position; |
| 340 } | 345 } |
| 341 | 346 |
| 342 static const int kMaxUnresolvedBranches = 20; | 347 static const int kMaxUnresolvedBranches = 20; |
| 343 | 348 |
| 344 intptr_t position_; | 349 intptr_t position_; |
| 345 intptr_t num_unresolved_; | 350 intptr_t num_unresolved_; |
| 346 intptr_t unresolved_near_positions_[kMaxUnresolvedBranches]; | 351 intptr_t unresolved_near_positions_[kMaxUnresolvedBranches]; |
| 347 | 352 |
| 348 friend class AssemblerX86; | 353 friend class AssemblerX86; |
| 349 Label(const Label &) = delete; | |
| 350 Label &operator=(const Label &) = delete; | |
| 351 }; | 354 }; |
| 352 | 355 |
| 353 class AssemblerX86 : public Assembler { | 356 class AssemblerX86 : public Assembler { |
| 357 AssemblerX86(const AssemblerX86 &) = delete; |
| 358 AssemblerX86 &operator=(const AssemblerX86 &) = delete; |
| 359 |
| 354 public: | 360 public: |
| 355 explicit AssemblerX86(bool use_far_branches = false) : buffer_(*this) { | 361 explicit AssemblerX86(bool use_far_branches = false) : buffer_(*this) { |
| 356 // This mode is only needed and implemented for MIPS and ARM. | 362 // This mode is only needed and implemented for MIPS and ARM. |
| 357 assert(!use_far_branches); | 363 assert(!use_far_branches); |
| 358 (void)use_far_branches; | 364 (void)use_far_branches; |
| 359 } | 365 } |
| 360 ~AssemblerX86() {} | 366 ~AssemblerX86() {} |
| 361 | 367 |
| 362 static const bool kNearJump = true; | 368 static const bool kNearJump = true; |
| 363 static const bool kFarJump = false; | 369 static const bool kFarJump = false; |
| (...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 793 void cmpxchg(Type Ty, const Address &address, GPRRegister reg); | 799 void cmpxchg(Type Ty, const Address &address, GPRRegister reg); |
| 794 void cmpxchg8b(const Address &address); | 800 void cmpxchg8b(const Address &address); |
| 795 void xadd(Type Ty, const Address &address, GPRRegister reg); | 801 void xadd(Type Ty, const Address &address, GPRRegister reg); |
| 796 void xchg(Type Ty, const Address &address, GPRRegister reg); | 802 void xchg(Type Ty, const Address &address, GPRRegister reg); |
| 797 | 803 |
| 798 void LockCmpxchg(Type Ty, const Address &address, GPRRegister reg) { | 804 void LockCmpxchg(Type Ty, const Address &address, GPRRegister reg) { |
| 799 lock(); | 805 lock(); |
| 800 cmpxchg(Ty, address, reg); | 806 cmpxchg(Ty, address, reg); |
| 801 } | 807 } |
| 802 | 808 |
| 803 void EmitSegmentOverride(uint8_t prefix) { EmitUint8(prefix); } | 809 void EmitSegmentOverride(uint8_t prefix); |
| 804 | 810 |
| 805 intptr_t PreferredLoopAlignment() { return 16; } | 811 intptr_t PreferredLoopAlignment() { return 16; } |
| 806 void Align(intptr_t alignment, intptr_t offset); | 812 void Align(intptr_t alignment, intptr_t offset); |
| 807 void Bind(Label *label); | 813 void Bind(Label *label); |
| 808 | 814 |
| 809 intptr_t CodeSize() const { return buffer_.Size(); } | 815 intptr_t CodeSize() const { return buffer_.Size(); } |
| 810 | 816 |
| 811 void FinalizeInstructions(const MemoryRegion ®ion) { | 817 void FinalizeInstructions(const MemoryRegion ®ion) { |
| 812 buffer_.FinalizeInstructions(region); | 818 buffer_.FinalizeInstructions(region); |
| 813 } | 819 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 836 const Immediate &immediate); | 842 const Immediate &immediate); |
| 837 void EmitLabel(Label *label, intptr_t instruction_size); | 843 void EmitLabel(Label *label, intptr_t instruction_size); |
| 838 void EmitLabelLink(Label *label); | 844 void EmitLabelLink(Label *label); |
| 839 void EmitNearLabelLink(Label *label); | 845 void EmitNearLabelLink(Label *label); |
| 840 | 846 |
| 841 void EmitGenericShift(int rm, Type Ty, GPRRegister reg, const Immediate &imm); | 847 void EmitGenericShift(int rm, Type Ty, GPRRegister reg, const Immediate &imm); |
| 842 void EmitGenericShift(int rm, Type Ty, const Operand &operand, | 848 void EmitGenericShift(int rm, Type Ty, const Operand &operand, |
| 843 GPRRegister shifter); | 849 GPRRegister shifter); |
| 844 | 850 |
| 845 AssemblerBuffer buffer_; | 851 AssemblerBuffer buffer_; |
| 846 | |
| 847 AssemblerX86(const AssemblerX86 &) = delete; | |
| 848 AssemblerX86 &operator=(const AssemblerX86 &) = delete; | |
| 849 }; | 852 }; |
| 850 | 853 |
| 851 inline void AssemblerX86::EmitUint8(uint8_t value) { | 854 inline void AssemblerX86::EmitUint8(uint8_t value) { |
| 852 buffer_.Emit<uint8_t>(value); | 855 buffer_.Emit<uint8_t>(value); |
| 853 } | 856 } |
| 854 | 857 |
| 855 inline void AssemblerX86::EmitInt16(int16_t value) { | 858 inline void AssemblerX86::EmitInt16(int16_t value) { |
| 856 buffer_.Emit<int16_t>(value); | 859 buffer_.Emit<int16_t>(value); |
| 857 } | 860 } |
| 858 | 861 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 872 inline void AssemblerX86::EmitFixup(AssemblerFixup *fixup) { | 875 inline void AssemblerX86::EmitFixup(AssemblerFixup *fixup) { |
| 873 buffer_.EmitFixup(fixup); | 876 buffer_.EmitFixup(fixup); |
| 874 } | 877 } |
| 875 | 878 |
| 876 inline void AssemblerX86::EmitOperandSizeOverride() { EmitUint8(0x66); } | 879 inline void AssemblerX86::EmitOperandSizeOverride() { EmitUint8(0x66); } |
| 877 | 880 |
| 878 } // end of namespace x86 | 881 } // end of namespace x86 |
| 879 } // end of namespace Ice | 882 } // end of namespace Ice |
| 880 | 883 |
| 881 #endif // SUBZERO_SRC_ASSEMBLER_IA32_H_ | 884 #endif // SUBZERO_SRC_ASSEMBLER_IA32_H_ |
| OLD | NEW |