OLD | NEW |
---|---|
1 //===- subzero/src/IceInstARM32.cpp - ARM32 instruction implementation ----===// | 1 //===- subzero/src/IceInstARM32.cpp - ARM32 instruction implementation ----===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 // | 9 // |
10 // This file implements the InstARM32 and OperandARM32 classes, | 10 // This file implements the InstARM32 and OperandARM32 classes, |
(...skipping 19 matching lines...) Expand all Loading... | |
30 int8_t SExtAddrOffsetBits; | 30 int8_t SExtAddrOffsetBits; |
31 int8_t ZExtAddrOffsetBits; | 31 int8_t ZExtAddrOffsetBits; |
32 } TypeARM32Attributes[] = { | 32 } TypeARM32Attributes[] = { |
33 #define X(tag, elementty, width, sbits, ubits) \ | 33 #define X(tag, elementty, width, sbits, ubits) \ |
34 { width, sbits, ubits } \ | 34 { width, sbits, ubits } \ |
35 , | 35 , |
36 ICETYPEARM32_TABLE | 36 ICETYPEARM32_TABLE |
37 #undef X | 37 #undef X |
38 }; | 38 }; |
39 | 39 |
40 const struct InstARM32ShiftAttributes_ { | |
41 const char *EmitString; | |
42 } InstARM32ShiftAttributes[] = { | |
43 #define X(tag, emit) \ | |
44 { emit } \ | |
45 , | |
46 ICEINSTARM32SHIFT_TABLE | |
47 #undef X | |
48 }; | |
49 | |
40 } // end of anonymous namespace | 50 } // end of anonymous namespace |
41 | 51 |
42 const char *InstARM32::getWidthString(Type Ty) { | 52 const char *InstARM32::getWidthString(Type Ty) { |
43 return TypeARM32Attributes[Ty].WidthString; | 53 return TypeARM32Attributes[Ty].WidthString; |
44 } | 54 } |
45 | 55 |
56 void emitTwoAddr(const char *Opcode, const Inst *Inst, const Cfg *Func) { | |
57 if (!ALLOW_DUMP) | |
58 return; | |
59 Ostream &Str = Func->getContext()->getStrEmit(); | |
60 assert(Inst->getSrcSize() == 2); | |
61 Variable *Dest = Inst->getDest(); | |
62 Operand *Src1 = Inst->getSrc(1); | |
63 Str << "\t" << Opcode << "\t"; | |
64 Dest->emit(Func); | |
65 Str << ", "; | |
66 Src1->emit(Func); | |
67 } | |
68 | |
69 OperandARM32Mem::OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, | |
70 ConstantInteger32 *ImmOffset, AddrMode Mode) | |
71 : OperandARM32(kMem, Ty), Base(Base), ImmOffset(ImmOffset), Index(nullptr), | |
72 ShiftOp(kNoShift), ShiftAmt(0), Mode(Mode) { | |
73 // The Neg modes are only needed for Reg +/- Reg. | |
74 assert(!isNegAddrMode()); | |
75 NumVars = 1; | |
76 Vars = Func->allocateArrayOf<Variable *>(1); | |
77 Vars[0] = Base; | |
78 } | |
79 | |
80 OperandARM32Mem::OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, | |
81 Variable *Index, ShiftKind ShiftOp, | |
82 uint16_t ShiftAmt, AddrMode Mode) | |
83 : OperandARM32(kMem, Ty), Base(Base), ImmOffset(0), Index(Index), | |
84 ShiftOp(ShiftOp), ShiftAmt(ShiftAmt), Mode(Mode) { | |
85 NumVars = 2; | |
86 Vars = Func->allocateArrayOf<Variable *>(2); | |
87 Vars[0] = Base; | |
88 Vars[1] = Index; | |
89 } | |
90 | |
46 bool OperandARM32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) { | 91 bool OperandARM32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) { |
47 int32_t Bits = SignExt ? TypeARM32Attributes[Ty].SExtAddrOffsetBits | 92 int32_t Bits = SignExt ? TypeARM32Attributes[Ty].SExtAddrOffsetBits |
48 : TypeARM32Attributes[Ty].ZExtAddrOffsetBits; | 93 : TypeARM32Attributes[Ty].ZExtAddrOffsetBits; |
49 if (Bits == 0) | 94 if (Bits == 0) |
50 return Offset == 0; | 95 return Offset == 0; |
51 // Note that encodings for offsets are sign-magnitude for ARM, so we check | 96 // Note that encodings for offsets are sign-magnitude for ARM, so we check |
52 // with IsAbsoluteUint(). | 97 // with IsAbsoluteUint(). |
53 if (isScalarFloatingType(Ty)) | 98 if (isScalarFloatingType(Ty)) |
54 return Utils::IsAligned(Offset, 4) && Utils::IsAbsoluteUint(Bits, Offset); | 99 return Utils::IsAligned(Offset, 4) && Utils::IsAbsoluteUint(Bits, Offset); |
55 return Utils::IsAbsoluteUint(Bits, Offset); | 100 return Utils::IsAbsoluteUint(Bits, Offset); |
56 } | 101 } |
57 | 102 |
103 OperandARM32FlexImm::OperandARM32FlexImm(Cfg * /* Func */, Type Ty, | |
104 uint32_t Imm, uint32_t RotateAmt) | |
105 : OperandARM32Flex(kFlexImm, Ty), Imm(Imm), RotateAmt(RotateAmt) { | |
106 NumVars = 0; | |
107 Vars = nullptr; | |
108 } | |
109 | |
110 bool OperandARM32FlexImm::canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, | |
111 uint32_t *Immed_8) { | |
112 // Avoid the more expensive test for frequent small immediate values. | |
jvoung (off chromium)
2015/05/14 22:42:07
Sort of borrowed from Dart and V8. They are both a
| |
113 if (Immediate <= (0xFF)) { | |
114 *RotateAmt = 0; | |
115 *Immed_8 = Immediate; | |
116 return true; | |
117 } | |
118 // Note that immediate must be unsigned for the test to work correctly. | |
119 for (int Rot = 1; Rot < 16; Rot++) { | |
120 uint32_t Imm8 = Utils::rotateLeft32(Immediate, 2 * Rot); | |
121 if (Imm8 <= 0xFF) { | |
122 *RotateAmt = Rot; | |
123 *Immed_8 = Imm8; | |
124 return true; | |
125 } | |
126 } | |
127 return false; | |
128 } | |
129 | |
130 OperandARM32FlexReg::OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, | |
131 ShiftKind ShiftOp, Operand *ShiftAmt) | |
132 : OperandARM32Flex(kFlexReg, Ty), Reg(Reg), ShiftOp(ShiftOp), | |
133 ShiftAmt(ShiftAmt) { | |
134 NumVars = 1; | |
135 Variable *ShiftVar = llvm::dyn_cast_or_null<Variable>(ShiftAmt); | |
136 if (ShiftVar) | |
137 ++NumVars; | |
138 Vars = Func->allocateArrayOf<Variable *>(NumVars); | |
139 Vars[0] = Reg; | |
140 if (ShiftVar) | |
141 Vars[1] = ShiftVar; | |
142 } | |
143 | |
144 InstARM32Ldr::InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem) | |
145 : InstARM32(Func, InstARM32::Ldr, 1, Dest) { | |
146 addSource(Mem); | |
147 } | |
148 | |
58 InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source) | 149 InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source) |
59 : InstARM32(Func, InstARM32::Ret, Source ? 2 : 1, nullptr) { | 150 : InstARM32(Func, InstARM32::Ret, Source ? 2 : 1, nullptr) { |
60 addSource(LR); | 151 addSource(LR); |
61 if (Source) | 152 if (Source) |
62 addSource(Source); | 153 addSource(Source); |
63 } | 154 } |
64 | 155 |
65 // ======================== Dump routines ======================== // | 156 // ======================== Dump routines ======================== // |
66 | 157 |
158 // Two-addr ops | |
159 template <> const char *InstARM32Movt::Opcode = "movt"; | |
160 // Unary ops | |
161 template <> const char *InstARM32Movw::Opcode = "movw"; | |
162 template <> const char *InstARM32Mvn::Opcode = "mvn"; | |
163 // Mov-like ops | |
164 template <> const char *InstARM32Mov::Opcode = "mov"; | |
165 | |
67 void InstARM32::dump(const Cfg *Func) const { | 166 void InstARM32::dump(const Cfg *Func) const { |
68 if (!ALLOW_DUMP) | 167 if (!ALLOW_DUMP) |
69 return; | 168 return; |
70 Ostream &Str = Func->getContext()->getStrDump(); | 169 Ostream &Str = Func->getContext()->getStrDump(); |
71 Str << "[ARM32] "; | 170 Str << "[ARM32] "; |
72 Inst::dump(Func); | 171 Inst::dump(Func); |
73 } | 172 } |
74 | 173 |
174 template <> void InstARM32Mov::emit(const Cfg *Func) const { | |
175 if (!ALLOW_DUMP) | |
176 return; | |
177 Ostream &Str = Func->getContext()->getStrEmit(); | |
178 assert(getSrcSize() == 1); | |
179 Variable *Dest = getDest(); | |
180 if (Dest->hasReg()) { | |
181 Str << "\t" | |
182 << "mov" | |
183 << "\t"; | |
184 getDest()->emit(Func); | |
185 Str << ", "; | |
186 getSrc(0)->emit(Func); | |
187 } else { | |
188 Variable *Src0 = llvm::cast<Variable>(getSrc(0)); | |
189 assert(Src0->hasReg()); | |
190 Str << "\t" | |
191 << "str" | |
192 << "\t"; | |
193 Src0->emit(Func); | |
194 Str << ", "; | |
195 Dest->emit(Func); | |
196 } | |
197 } | |
198 | |
199 template <> void InstARM32Mov::emitIAS(const Cfg *Func) const { | |
200 assert(getSrcSize() == 1); | |
201 (void)Func; | |
202 llvm_unreachable("Not yet implemented"); | |
203 } | |
204 | |
205 void InstARM32Ldr::emit(const Cfg *Func) const { | |
206 if (!ALLOW_DUMP) | |
207 return; | |
208 Ostream &Str = Func->getContext()->getStrEmit(); | |
209 assert(getSrcSize() == 1); | |
210 assert(getDest()->hasReg()); | |
211 Type Ty = getSrc(0)->getType(); | |
212 Str << "\tldr" << getWidthString(Ty) << "\t"; | |
213 getDest()->emit(Func); | |
214 Str << ", "; | |
215 getSrc(0)->emit(Func); | |
216 } | |
217 | |
218 void InstARM32Ldr::emitIAS(const Cfg *Func) const { | |
219 assert(getSrcSize() == 2); | |
220 (void)Func; | |
221 llvm_unreachable("Not yet implemented"); | |
222 } | |
223 | |
224 void InstARM32Ldr::dump(const Cfg *Func) const { | |
225 if (!ALLOW_DUMP) | |
226 return; | |
227 Ostream &Str = Func->getContext()->getStrDump(); | |
228 dumpDest(Func); | |
229 Str << "ldr." << getSrc(0)->getType() << " "; | |
230 dumpSources(Func); | |
231 } | |
232 | |
233 template <> void InstARM32Movw::emit(const Cfg *Func) const { | |
234 if (!ALLOW_DUMP) | |
235 return; | |
236 Ostream &Str = Func->getContext()->getStrEmit(); | |
237 assert(getSrcSize() == 1); | |
238 Str << "\t" << Opcode << "\t"; | |
239 getDest()->emit(Func); | |
240 Str << ", "; | |
241 Constant *Src0 = llvm::cast<Constant>(getSrc(0)); | |
242 if (auto CR = llvm::dyn_cast<ConstantRelocatable>(Src0)) { | |
243 Str << "#:lower16:"; | |
244 CR->emitWithoutPrefix(Func->getTarget()); | |
245 } else { | |
246 Src0->emit(Func); | |
247 } | |
248 } | |
249 | |
250 template <> void InstARM32Movt::emit(const Cfg *Func) const { | |
251 if (!ALLOW_DUMP) | |
252 return; | |
253 Ostream &Str = Func->getContext()->getStrEmit(); | |
254 assert(getSrcSize() == 2); | |
255 Variable *Dest = getDest(); | |
256 Constant *Src1 = llvm::cast<Constant>(getSrc(1)); | |
257 Str << "\t" << Opcode << "\t"; | |
258 Dest->emit(Func); | |
259 Str << ", "; | |
260 if (auto CR = llvm::dyn_cast<ConstantRelocatable>(Src1)) { | |
261 Str << "#:upper16:"; | |
262 CR->emitWithoutPrefix(Func->getTarget()); | |
263 } else { | |
264 Src1->emit(Func); | |
265 } | |
266 } | |
267 | |
75 void InstARM32Ret::emit(const Cfg *Func) const { | 268 void InstARM32Ret::emit(const Cfg *Func) const { |
76 if (!ALLOW_DUMP) | 269 if (!ALLOW_DUMP) |
77 return; | 270 return; |
78 assert(getSrcSize() > 0); | 271 assert(getSrcSize() > 0); |
79 Variable *LR = llvm::cast<Variable>(getSrc(0)); | 272 Variable *LR = llvm::cast<Variable>(getSrc(0)); |
80 assert(LR->hasReg()); | 273 assert(LR->hasReg()); |
81 assert(LR->getRegNum() == RegARM32::Reg_lr); | 274 assert(LR->getRegNum() == RegARM32::Reg_lr); |
82 Ostream &Str = Func->getContext()->getStrEmit(); | 275 Ostream &Str = Func->getContext()->getStrEmit(); |
83 Str << "\tbx\t"; | 276 Str << "\tbx\t"; |
84 LR->emit(Func); | 277 LR->emit(Func); |
85 } | 278 } |
86 | 279 |
87 void InstARM32Ret::emitIAS(const Cfg *Func) const { | 280 void InstARM32Ret::emitIAS(const Cfg *Func) const { |
88 (void)Func; | 281 (void)Func; |
89 llvm_unreachable("Not yet implemented"); | 282 llvm_unreachable("Not yet implemented"); |
90 } | 283 } |
91 | 284 |
92 void InstARM32Ret::dump(const Cfg *Func) const { | 285 void InstARM32Ret::dump(const Cfg *Func) const { |
93 if (!ALLOW_DUMP) | 286 if (!ALLOW_DUMP) |
94 return; | 287 return; |
95 Ostream &Str = Func->getContext()->getStrDump(); | 288 Ostream &Str = Func->getContext()->getStrDump(); |
96 Type Ty = (getSrcSize() == 1 ? IceType_void : getSrc(0)->getType()); | 289 Type Ty = (getSrcSize() == 1 ? IceType_void : getSrc(0)->getType()); |
97 Str << "ret." << Ty << " "; | 290 Str << "ret." << Ty << " "; |
98 dumpSources(Func); | 291 dumpSources(Func); |
99 } | 292 } |
100 | 293 |
294 void OperandARM32Mem::emit(const Cfg *Func) const { | |
295 if (!ALLOW_DUMP) | |
296 return; | |
297 Ostream &Str = Func->getContext()->getStrEmit(); | |
298 Str << "["; | |
299 getBase()->emit(Func); | |
300 switch (getAddrMode()) { | |
301 case PostIndex: | |
302 case NegPostIndex: | |
303 Str << "], "; | |
304 break; | |
305 default: | |
306 Str << ", "; | |
307 break; | |
308 } | |
309 if (isRegReg()) { | |
310 if (isNegAddrMode()) { | |
311 Str << "-"; | |
312 } | |
313 getIndex()->emit(Func); | |
314 if (getShiftOp() != kNoShift) { | |
315 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #" | |
316 << getShiftAmt(); | |
317 } | |
318 } else { | |
319 getOffset()->emit(Func); | |
320 } | |
321 switch (getAddrMode()) { | |
322 case Offset: | |
323 case NegOffset: | |
324 Str << "]"; | |
325 break; | |
326 case PreIndex: | |
327 case NegPreIndex: | |
328 Str << "]!"; | |
329 break; | |
330 case PostIndex: | |
331 case NegPostIndex: | |
332 // Brace is already closed off. | |
333 break; | |
334 } | |
335 } | |
336 | |
337 void OperandARM32Mem::dump(const Cfg *Func, Ostream &Str) const { | |
338 if (!ALLOW_DUMP) | |
339 return; | |
340 Str << "["; | |
341 if (Func) | |
342 getBase()->dump(Func); | |
343 else | |
344 getBase()->dump(Str); | |
345 Str << ", "; | |
346 if (isRegReg()) { | |
347 if (isNegAddrMode()) { | |
348 Str << "-"; | |
349 } | |
350 if (Func) | |
351 getIndex()->dump(Func); | |
352 else | |
353 getIndex()->dump(Str); | |
354 if (getShiftOp() != kNoShift) { | |
355 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #" | |
356 << getShiftAmt(); | |
357 } | |
358 } else { | |
359 getOffset()->dump(Func, Str); | |
360 } | |
361 Str << "] AddrMode==" << getAddrMode() << "\n"; | |
362 } | |
363 | |
364 void OperandARM32FlexImm::emit(const Cfg *Func) const { | |
365 if (!ALLOW_DUMP) | |
366 return; | |
367 Ostream &Str = Func->getContext()->getStrEmit(); | |
368 uint32_t Imm = getImm(); | |
369 uint32_t RotateAmt = getRotateAmt(); | |
370 Str << "#" << Utils::rotateRight32(Imm, 2 * RotateAmt); | |
371 } | |
372 | |
373 void OperandARM32FlexImm::dump(const Cfg * /* Func */, Ostream &Str) const { | |
374 if (!ALLOW_DUMP) | |
375 return; | |
376 uint32_t Imm = getImm(); | |
377 uint32_t RotateAmt = getRotateAmt(); | |
378 Str << "#(" << Imm << " ror 2*" << RotateAmt << ")"; | |
379 } | |
380 | |
381 void OperandARM32FlexReg::emit(const Cfg *Func) const { | |
382 if (!ALLOW_DUMP) | |
383 return; | |
384 Ostream &Str = Func->getContext()->getStrEmit(); | |
385 getReg()->emit(Func); | |
386 if (getShiftOp() != kNoShift) { | |
387 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; | |
388 getShiftAmt()->emit(Func); | |
389 } | |
390 } | |
391 | |
392 void OperandARM32FlexReg::dump(const Cfg *Func, Ostream &Str) const { | |
393 if (!ALLOW_DUMP) | |
394 return; | |
395 Variable *Reg = getReg(); | |
396 if (Func) | |
397 Reg->dump(Func); | |
398 else | |
399 Reg->dump(Str); | |
400 if (getShiftOp() != kNoShift) { | |
401 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; | |
402 if (Func) | |
403 getShiftAmt()->dump(Func); | |
404 else | |
405 getShiftAmt()->dump(Str); | |
406 } | |
407 } | |
408 | |
101 } // end of namespace Ice | 409 } // end of namespace Ice |
OLD | NEW |