Chromium Code Reviews| 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 |