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 |