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 assert(Dest == Inst->getSrc(0)); |
| 63 Operand *Src1 = Inst->getSrc(1); |
| 64 Str << "\t" << Opcode << "\t"; |
| 65 Dest->emit(Func); |
| 66 Str << ", "; |
| 67 Src1->emit(Func); |
| 68 } |
| 69 |
| 70 OperandARM32Mem::OperandARM32Mem(Cfg * /* Func */, Type Ty, Variable *Base, |
| 71 ConstantInteger32 *ImmOffset, AddrMode Mode) |
| 72 : OperandARM32(kMem, Ty), Base(Base), ImmOffset(ImmOffset), Index(nullptr), |
| 73 ShiftOp(kNoShift), ShiftAmt(0), Mode(Mode) { |
| 74 // The Neg modes are only needed for Reg +/- Reg. |
| 75 assert(!isNegAddrMode()); |
| 76 NumVars = 1; |
| 77 Vars = &this->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. |
| 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 << "\t" |
| 213 << "ldr" << getWidthString(Ty) << "\t"; |
| 214 getDest()->emit(Func); |
| 215 Str << ", "; |
| 216 getSrc(0)->emit(Func); |
| 217 } |
| 218 |
| 219 void InstARM32Ldr::emitIAS(const Cfg *Func) const { |
| 220 assert(getSrcSize() == 2); |
| 221 (void)Func; |
| 222 llvm_unreachable("Not yet implemented"); |
| 223 } |
| 224 |
| 225 void InstARM32Ldr::dump(const Cfg *Func) const { |
| 226 if (!ALLOW_DUMP) |
| 227 return; |
| 228 Ostream &Str = Func->getContext()->getStrDump(); |
| 229 dumpDest(Func); |
| 230 Str << "ldr." << getSrc(0)->getType() << " "; |
| 231 dumpSources(Func); |
| 232 } |
| 233 |
| 234 template <> void InstARM32Movw::emit(const Cfg *Func) const { |
| 235 if (!ALLOW_DUMP) |
| 236 return; |
| 237 Ostream &Str = Func->getContext()->getStrEmit(); |
| 238 assert(getSrcSize() == 1); |
| 239 Str << "\t" << Opcode << "\t"; |
| 240 getDest()->emit(Func); |
| 241 Str << ", "; |
| 242 Constant *Src0 = llvm::cast<Constant>(getSrc(0)); |
| 243 if (auto CR = llvm::dyn_cast<ConstantRelocatable>(Src0)) { |
| 244 Str << "#:lower16:"; |
| 245 CR->emitWithoutPrefix(Func->getTarget()); |
| 246 } else { |
| 247 Src0->emit(Func); |
| 248 } |
| 249 } |
| 250 |
| 251 template <> void InstARM32Movt::emit(const Cfg *Func) const { |
| 252 if (!ALLOW_DUMP) |
| 253 return; |
| 254 Ostream &Str = Func->getContext()->getStrEmit(); |
| 255 assert(getSrcSize() == 2); |
| 256 Variable *Dest = getDest(); |
| 257 Constant *Src1 = llvm::cast<Constant>(getSrc(1)); |
| 258 Str << "\t" << Opcode << "\t"; |
| 259 Dest->emit(Func); |
| 260 Str << ", "; |
| 261 if (auto CR = llvm::dyn_cast<ConstantRelocatable>(Src1)) { |
| 262 Str << "#:upper16:"; |
| 263 CR->emitWithoutPrefix(Func->getTarget()); |
| 264 } else { |
| 265 Src1->emit(Func); |
| 266 } |
| 267 } |
| 268 |
75 void InstARM32Ret::emit(const Cfg *Func) const { | 269 void InstARM32Ret::emit(const Cfg *Func) const { |
76 if (!ALLOW_DUMP) | 270 if (!ALLOW_DUMP) |
77 return; | 271 return; |
78 assert(getSrcSize() > 0); | 272 assert(getSrcSize() > 0); |
79 Variable *LR = llvm::cast<Variable>(getSrc(0)); | 273 Variable *LR = llvm::cast<Variable>(getSrc(0)); |
80 assert(LR->hasReg()); | 274 assert(LR->hasReg()); |
81 assert(LR->getRegNum() == RegARM32::Reg_lr); | 275 assert(LR->getRegNum() == RegARM32::Reg_lr); |
82 Ostream &Str = Func->getContext()->getStrEmit(); | 276 Ostream &Str = Func->getContext()->getStrEmit(); |
83 Str << "\tbx\t"; | 277 Str << "\tbx\t"; |
84 LR->emit(Func); | 278 LR->emit(Func); |
85 } | 279 } |
86 | 280 |
87 void InstARM32Ret::emitIAS(const Cfg *Func) const { | 281 void InstARM32Ret::emitIAS(const Cfg *Func) const { |
88 (void)Func; | 282 (void)Func; |
89 llvm_unreachable("Not yet implemented"); | 283 llvm_unreachable("Not yet implemented"); |
90 } | 284 } |
91 | 285 |
92 void InstARM32Ret::dump(const Cfg *Func) const { | 286 void InstARM32Ret::dump(const Cfg *Func) const { |
93 if (!ALLOW_DUMP) | 287 if (!ALLOW_DUMP) |
94 return; | 288 return; |
95 Ostream &Str = Func->getContext()->getStrDump(); | 289 Ostream &Str = Func->getContext()->getStrDump(); |
96 Type Ty = (getSrcSize() == 1 ? IceType_void : getSrc(0)->getType()); | 290 Type Ty = (getSrcSize() == 1 ? IceType_void : getSrc(0)->getType()); |
97 Str << "ret." << Ty << " "; | 291 Str << "ret." << Ty << " "; |
98 dumpSources(Func); | 292 dumpSources(Func); |
99 } | 293 } |
100 | 294 |
| 295 void OperandARM32Mem::emit(const Cfg *Func) const { |
| 296 if (!ALLOW_DUMP) |
| 297 return; |
| 298 Ostream &Str = Func->getContext()->getStrEmit(); |
| 299 Str << "["; |
| 300 getBase()->emit(Func); |
| 301 switch (getAddrMode()) { |
| 302 case PostIndex: |
| 303 case NegPostIndex: |
| 304 Str << "], "; |
| 305 break; |
| 306 default: |
| 307 Str << ", "; |
| 308 break; |
| 309 } |
| 310 if (isRegReg()) { |
| 311 if (isNegAddrMode()) { |
| 312 Str << "-"; |
| 313 } |
| 314 getIndex()->emit(Func); |
| 315 if (getShiftOp() != kNoShift) { |
| 316 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #" |
| 317 << getShiftAmt(); |
| 318 } |
| 319 } else { |
| 320 getOffset()->emit(Func); |
| 321 } |
| 322 switch (getAddrMode()) { |
| 323 case Offset: |
| 324 case NegOffset: |
| 325 Str << "]"; |
| 326 break; |
| 327 case PreIndex: |
| 328 case NegPreIndex: |
| 329 Str << "]!"; |
| 330 break; |
| 331 case PostIndex: |
| 332 case NegPostIndex: |
| 333 // Brace is already closed off. |
| 334 break; |
| 335 } |
| 336 } |
| 337 |
| 338 void OperandARM32Mem::dump(const Cfg *Func, Ostream &Str) const { |
| 339 if (!ALLOW_DUMP) |
| 340 return; |
| 341 Str << "["; |
| 342 if (Func) |
| 343 getBase()->dump(Func); |
| 344 else |
| 345 getBase()->dump(Str); |
| 346 Str << ", "; |
| 347 if (isRegReg()) { |
| 348 if (isNegAddrMode()) { |
| 349 Str << "-"; |
| 350 } |
| 351 if (Func) |
| 352 getIndex()->dump(Func); |
| 353 else |
| 354 getIndex()->dump(Str); |
| 355 if (getShiftOp() != kNoShift) { |
| 356 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #" |
| 357 << getShiftAmt(); |
| 358 } |
| 359 } else { |
| 360 getOffset()->dump(Func, Str); |
| 361 } |
| 362 Str << "] AddrMode==" << getAddrMode() << "\n"; |
| 363 } |
| 364 |
| 365 void OperandARM32FlexImm::emit(const Cfg *Func) const { |
| 366 if (!ALLOW_DUMP) |
| 367 return; |
| 368 Ostream &Str = Func->getContext()->getStrEmit(); |
| 369 uint32_t Imm = getImm(); |
| 370 uint32_t RotateAmt = getRotateAmt(); |
| 371 Str << "#" << Utils::rotateRight32(Imm, 2 * RotateAmt); |
| 372 } |
| 373 |
| 374 void OperandARM32FlexImm::dump(const Cfg * /* Func */, Ostream &Str) const { |
| 375 if (!ALLOW_DUMP) |
| 376 return; |
| 377 uint32_t Imm = getImm(); |
| 378 uint32_t RotateAmt = getRotateAmt(); |
| 379 Str << "#(" << Imm << " ror 2*" << RotateAmt << ")"; |
| 380 } |
| 381 |
| 382 void OperandARM32FlexReg::emit(const Cfg *Func) const { |
| 383 if (!ALLOW_DUMP) |
| 384 return; |
| 385 Ostream &Str = Func->getContext()->getStrEmit(); |
| 386 getReg()->emit(Func); |
| 387 if (getShiftOp() != kNoShift) { |
| 388 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; |
| 389 getShiftAmt()->emit(Func); |
| 390 } |
| 391 } |
| 392 |
| 393 void OperandARM32FlexReg::dump(const Cfg *Func, Ostream &Str) const { |
| 394 if (!ALLOW_DUMP) |
| 395 return; |
| 396 Variable *Reg = getReg(); |
| 397 if (Func) |
| 398 Reg->dump(Func); |
| 399 else |
| 400 Reg->dump(Str); |
| 401 if (getShiftOp() != kNoShift) { |
| 402 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; |
| 403 if (Func) |
| 404 getShiftAmt()->dump(Func); |
| 405 else |
| 406 getShiftAmt()->dump(Str); |
| 407 } |
| 408 } |
| 409 |
101 } // end of namespace Ice | 410 } // end of namespace Ice |
OLD | NEW |