1 //===- subzero/src/IceInstARM32.cpp - ARM32 instruction implementation ----===// 2 // 3 // The Subzero Code Generator 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// \brief Implements the InstARM32 and OperandARM32 classes, primarily the 12 /// constructors and the dump()/emit() methods. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #include "IceInstARM32.h" 17 18 #include "IceAssemblerARM32.h" 19 #include "IceCfg.h" 20 #include "IceCfgNode.h" 21 #include "IceInst.h" 22 #include "IceOperand.h" 23 #include "IceTargetLoweringARM32.h" 24 25 namespace Ice { 26 namespace ARM32 { 27 28 namespace { 29 30 using Register = RegARM32::AllRegisters; 31 32 // maximum number of registers allowed in vpush/vpop. 33 static constexpr SizeT VpushVpopMaxConsecRegs = 16; 34 35 const struct TypeARM32Attributes_ { 36 const char *WidthString; // b, h, <blank>, or d 37 const char *FpWidthString; // i8, i16, i32, f32, f64 38 const char *SVecWidthString; // s8, s16, s32, f32 39 const char *UVecWidthString; // u8, u16, u32, f32 40 int8_t SExtAddrOffsetBits; 41 int8_t ZExtAddrOffsetBits; 42 } TypeARM32Attributes[] = { 43 #define X(tag, elementty, int_width, fp_width, uvec_width, svec_width, sbits, \ 44 ubits, rraddr, shaddr) \ 45 { int_width, fp_width, svec_width, uvec_width, sbits, ubits } \ 46 , 47 ICETYPEARM32_TABLE 48 #undef X 49 }; 50 51 const struct InstARM32ShiftAttributes_ { 52 const char *EmitString; 53 } InstARM32ShiftAttributes[] = { 54 #define X(tag, emit) \ 55 { emit } \ 56 , 57 ICEINSTARM32SHIFT_TABLE 58 #undef X 59 }; 60 61 const struct InstARM32CondAttributes_ { 62 CondARM32::Cond Opposite; 63 const char *EmitString; 64 } InstARM32CondAttributes[] = { 65 #define X(tag, encode, opp, emit) \ 66 { CondARM32::opp, emit } \ 67 , 68 ICEINSTARM32COND_TABLE 69 #undef X 70 }; 71 72 size_t getVecElmtBitsize(Type Ty) { 73 return typeWidthInBytes(typeElementType(Ty)) * CHAR_BIT; 74 } 75 76 const char *getWidthString(Type Ty) { 77 return TypeARM32Attributes[Ty].WidthString; 78 } 79 80 const char *getFpWidthString(Type Ty) { 81 return TypeARM32Attributes[Ty].FpWidthString; 82 } 83 84 const char *getSVecWidthString(Type Ty) { 85 return TypeARM32Attributes[Ty].SVecWidthString; 86 } 87 88 const char *getUVecWidthString(Type Ty) { 89 return TypeARM32Attributes[Ty].UVecWidthString; 90 } 91 92 const char *getVWidthString(Type Ty, InstARM32::FPSign SignType) { 93 switch (SignType) { 94 case InstARM32::FS_None: 95 return getFpWidthString(Ty); 96 case InstARM32::FS_Signed: 97 return getSVecWidthString(Ty); 98 case InstARM32::FS_Unsigned: 99 return getUVecWidthString(Ty); 100 } 101 llvm_unreachable("Invalid Sign Type."); 102 return getFpWidthString(Ty); 103 } 104 105 } // end of anonymous namespace 106 107 const char *InstARM32Pred::predString(CondARM32::Cond Pred) { 108 return InstARM32CondAttributes[Pred].EmitString; 109 } 110 111 void InstARM32Pred::dumpOpcodePred(Ostream &Str, const char *Opcode, 112 Type Ty) const { 113 Str << Opcode << getPredicate() << "." << Ty; 114 } 115 116 CondARM32::Cond InstARM32::getOppositeCondition(CondARM32::Cond Cond) { 117 return InstARM32CondAttributes[Cond].Opposite; 118 } 119 120 void InstARM32::startNextInst(const Cfg *Func) const { 121 if (auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>()) 122 Asm->incEmitTextSize(InstSize); 123 } 124 125 void InstARM32::emitUsingTextFixup(const Cfg *Func) const { 126 if (!BuildDefs::dump()) 127 return; 128 GlobalContext *Ctx = Func->getContext(); 129 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 130 if (getFlags().getDisableHybridAssembly() && 131 getFlags().getSkipUnimplemented()) { 132 Asm->trap(); 133 Asm->resetNeedsTextFixup(); 134 return; 135 } 136 std::string Buffer; 137 llvm::raw_string_ostream StrBuf(Buffer); 138 OstreamLocker L(Ctx); 139 Ostream &OldStr = Ctx->getStrEmit(); 140 Ctx->setStrEmit(StrBuf); 141 // Start counting instructions here, so that emit() methods don't 142 // need to call this for the first instruction. 143 Asm->resetEmitTextSize(); 144 Asm->incEmitTextSize(InstSize); 145 emit(Func); 146 Ctx->setStrEmit(OldStr); 147 if (getFlags().getDisableHybridAssembly()) { 148 if (getFlags().getSkipUnimplemented()) { 149 Asm->trap(); 150 } else { 151 llvm::errs() << "Can't assemble: " << StrBuf.str() << "\n"; 152 UnimplementedError(getFlags()); 153 } 154 Asm->resetNeedsTextFixup(); 155 return; 156 } 157 Asm->emitTextInst(StrBuf.str(), Asm->getEmitTextSize()); 158 } 159 160 void InstARM32::emitIAS(const Cfg *Func) const { emitUsingTextFixup(Func); } 161 162 void InstARM32Pred::emitUnaryopGPR(const char *Opcode, 163 const InstARM32Pred *Instr, const Cfg *Func, 164 bool NeedsWidthSuffix) { 165 Ostream &Str = Func->getContext()->getStrEmit(); 166 assert(Instr->getSrcSize() == 1); 167 Type SrcTy = Instr->getSrc(0)->getType(); 168 Str << "\t" << Opcode; 169 if (NeedsWidthSuffix) 170 Str << getWidthString(SrcTy); 171 Str << Instr->getPredicate() << "\t"; 172 Instr->getDest()->emit(Func); 173 Str << ", "; 174 Instr->getSrc(0)->emit(Func); 175 } 176 177 void InstARM32Pred::emitUnaryopFP(const char *Opcode, FPSign Sign, 178 const InstARM32Pred *Instr, const Cfg *Func) { 179 Ostream &Str = Func->getContext()->getStrEmit(); 180 assert(Instr->getSrcSize() == 1); 181 Type SrcTy = Instr->getSrc(0)->getType(); 182 Str << "\t" << Opcode << Instr->getPredicate(); 183 switch (Sign) { 184 case FS_None: 185 Str << getFpWidthString(SrcTy); 186 break; 187 case FS_Signed: 188 Str << getSVecWidthString(SrcTy); 189 break; 190 case FS_Unsigned: 191 Str << getUVecWidthString(SrcTy); 192 break; 193 } 194 Str << "\t"; 195 Instr->getDest()->emit(Func); 196 Str << ", "; 197 Instr->getSrc(0)->emit(Func); 198 } 199 200 void InstARM32Pred::emitTwoAddr(const char *Opcode, const InstARM32Pred *Instr, 201 const Cfg *Func) { 202 if (!BuildDefs::dump()) 203 return; 204 Ostream &Str = Func->getContext()->getStrEmit(); 205 assert(Instr->getSrcSize() == 2); 206 Variable *Dest = Instr->getDest(); 207 assert(Dest == Instr->getSrc(0)); 208 Str << "\t" << Opcode << Instr->getPredicate() << "\t"; 209 Dest->emit(Func); 210 Str << ", "; 211 Instr->getSrc(1)->emit(Func); 212 } 213 214 void InstARM32Pred::emitThreeAddr(const char *Opcode, 215 const InstARM32Pred *Instr, const Cfg *Func, 216 bool SetFlags) { 217 if (!BuildDefs::dump()) 218 return; 219 Ostream &Str = Func->getContext()->getStrEmit(); 220 assert(Instr->getSrcSize() == 2); 221 Str << "\t" << Opcode << (SetFlags ? "s" : "") << Instr->getPredicate() 222 << "\t"; 223 Instr->getDest()->emit(Func); 224 Str << ", "; 225 Instr->getSrc(0)->emit(Func); 226 Str << ", "; 227 Instr->getSrc(1)->emit(Func); 228 } 229 230 void InstARM32::emitThreeAddrFP(const char *Opcode, FPSign SignType, 231 const InstARM32 *Instr, const Cfg *Func, 232 Type OpType) { 233 if (!BuildDefs::dump()) 234 return; 235 Ostream &Str = Func->getContext()->getStrEmit(); 236 assert(Instr->getSrcSize() == 2); 237 Str << "\t" << Opcode << getVWidthString(OpType, SignType) << "\t"; 238 Instr->getDest()->emit(Func); 239 Str << ", "; 240 Instr->getSrc(0)->emit(Func); 241 Str << ", "; 242 Instr->getSrc(1)->emit(Func); 243 } 244 245 void InstARM32::emitFourAddrFP(const char *Opcode, FPSign SignType, 246 const InstARM32 *Instr, const Cfg *Func) { 247 if (!BuildDefs::dump()) 248 return; 249 Ostream &Str = Func->getContext()->getStrEmit(); 250 assert(Instr->getSrcSize() == 3); 251 assert(Instr->getSrc(0) == Instr->getDest()); 252 Str << "\t" << Opcode 253 << getVWidthString(Instr->getDest()->getType(), SignType) << "\t"; 254 Instr->getDest()->emit(Func); 255 Str << ", "; 256 Instr->getSrc(1)->emit(Func); 257 Str << ", "; 258 Instr->getSrc(2)->emit(Func); 259 } 260 261 void InstARM32Pred::emitFourAddr(const char *Opcode, const InstARM32Pred *Instr, 262 const Cfg *Func) { 263 if (!BuildDefs::dump()) 264 return; 265 Ostream &Str = Func->getContext()->getStrEmit(); 266 assert(Instr->getSrcSize() == 3); 267 Str << "\t" << Opcode << Instr->getPredicate() << "\t"; 268 Instr->getDest()->emit(Func); 269 Str << ", "; 270 Instr->getSrc(0)->emit(Func); 271 Str << ", "; 272 Instr->getSrc(1)->emit(Func); 273 Str << ", "; 274 Instr->getSrc(2)->emit(Func); 275 } 276 277 template <InstARM32::InstKindARM32 K> 278 void InstARM32FourAddrGPR<K>::emitIAS(const Cfg *Func) const { 279 emitUsingTextFixup(Func); 280 } 281 282 template <InstARM32::InstKindARM32 K> 283 void InstARM32FourAddrFP<K>::emitIAS(const Cfg *Func) const { 284 emitUsingTextFixup(Func); 285 } 286 287 template <InstARM32::InstKindARM32 K> 288 void InstARM32ThreeAddrFP<K>::emitIAS(const Cfg *Func) const { 289 emitUsingTextFixup(Func); 290 } 291 292 template <InstARM32::InstKindARM32 K> 293 void InstARM32ThreeAddrSignAwareFP<K>::emitIAS(const Cfg *Func) const { 294 InstARM32::emitUsingTextFixup(Func); 295 } 296 297 template <> void InstARM32Mla::emitIAS(const Cfg *Func) const { 298 assert(getSrcSize() == 3); 299 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 300 Asm->mla(getDest(), getSrc(0), getSrc(1), getSrc(2), getPredicate()); 301 if (Asm->needsTextFixup()) 302 emitUsingTextFixup(Func); 303 } 304 305 template <> void InstARM32Mls::emitIAS(const Cfg *Func) const { 306 assert(getSrcSize() == 3); 307 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 308 Asm->mls(getDest(), getSrc(0), getSrc(1), getSrc(2), getPredicate()); 309 if (Asm->needsTextFixup()) 310 emitUsingTextFixup(Func); 311 } 312 313 void InstARM32Pred::emitCmpLike(const char *Opcode, const InstARM32Pred *Instr, 314 const Cfg *Func) { 315 if (!BuildDefs::dump()) 316 return; 317 Ostream &Str = Func->getContext()->getStrEmit(); 318 assert(Instr->getSrcSize() == 2); 319 Str << "\t" << Opcode << Instr->getPredicate() << "\t"; 320 Instr->getSrc(0)->emit(Func); 321 Str << ", "; 322 Instr->getSrc(1)->emit(Func); 323 } 324 325 OperandARM32Mem::OperandARM32Mem(Cfg * /* Func */, Type Ty, Variable *Base, 326 ConstantInteger32 *ImmOffset, AddrMode Mode) 327 : OperandARM32(kMem, Ty), Base(Base), ImmOffset(ImmOffset), Index(nullptr), 328 ShiftOp(kNoShift), ShiftAmt(0), Mode(Mode) { 329 // The Neg modes are only needed for Reg +/- Reg. 330 assert(!isNegAddrMode()); 331 NumVars = 1; 332 Vars = &this->Base; 333 } 334 335 OperandARM32Mem::OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, 336 Variable *Index, ShiftKind ShiftOp, 337 uint16_t ShiftAmt, AddrMode Mode) 338 : OperandARM32(kMem, Ty), Base(Base), ImmOffset(0), Index(Index), 339 ShiftOp(ShiftOp), ShiftAmt(ShiftAmt), Mode(Mode) { 340 if (Index->isRematerializable()) { 341 llvm::report_fatal_error("Rematerializable Index Register is not allowed."); 342 } 343 NumVars = 2; 344 Vars = Func->allocateArrayOf<Variable *>(2); 345 Vars[0] = Base; 346 Vars[1] = Index; 347 } 348 349 OperandARM32ShAmtImm::OperandARM32ShAmtImm(ConstantInteger32 *SA) 350 : OperandARM32(kShAmtImm, IceType_i8), ShAmt(SA) {} 351 352 bool OperandARM32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) { 353 int32_t Bits = SignExt ? TypeARM32Attributes[Ty].SExtAddrOffsetBits 354 : TypeARM32Attributes[Ty].ZExtAddrOffsetBits; 355 if (Bits == 0) 356 return Offset == 0; 357 // Note that encodings for offsets are sign-magnitude for ARM, so we check 358 // with IsAbsoluteUint(). 359 // Scalar fp, and vector types require an offset that is aligned to a multiple 360 // of 4. 361 if (isScalarFloatingType(Ty) || isVectorType(Ty)) 362 return Utils::IsAligned(Offset, 4) && Utils::IsAbsoluteUint(Bits, Offset); 363 return Utils::IsAbsoluteUint(Bits, Offset); 364 } 365 366 OperandARM32FlexImm::OperandARM32FlexImm(Cfg * /* Func */, Type Ty, 367 uint32_t Imm, uint32_t RotateAmt) 368 : OperandARM32Flex(kFlexImm, Ty), Imm(Imm), RotateAmt(RotateAmt) { 369 NumVars = 0; 370 Vars = nullptr; 371 } 372 373 bool OperandARM32FlexImm::canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, 374 uint32_t *Immed_8) { 375 // Avoid the more expensive test for frequent small immediate values. 376 if (Immediate <= 0xFF) { 377 *RotateAmt = 0; 378 *Immed_8 = Immediate; 379 return true; 380 } 381 // Note that immediate must be unsigned for the test to work correctly. 382 for (int Rot = 1; Rot < 16; Rot++) { 383 uint32_t Imm8 = Utils::rotateLeft32(Immediate, 2 * Rot); 384 if (Imm8 <= 0xFF) { 385 *RotateAmt = Rot; 386 *Immed_8 = Imm8; 387 return true; 388 } 389 } 390 return false; 391 } 392 393 OperandARM32FlexFpImm::OperandARM32FlexFpImm(Cfg * /*Func*/, Type Ty, 394 uint32_t ModifiedImm) 395 : OperandARM32Flex(kFlexFpImm, Ty), ModifiedImm(ModifiedImm) {} 396 397 bool OperandARM32FlexFpImm::canHoldImm(const Operand *C, 398 uint32_t *ModifiedImm) { 399 switch (C->getType()) { 400 default: 401 llvm::report_fatal_error("Unhandled fp constant type."); 402 case IceType_f32: { 403 // We violate llvm naming conventions a bit here so that the constants are 404 // named after the bit fields they represent. See "A7.5.1 Operation of 405 // modified immediate constants, Floating-point" in the ARM ARM. 406 static constexpr uint32_t a = 0x80000000u; 407 static constexpr uint32_t B = 0x40000000; 408 static constexpr uint32_t bbbbb = 0x3E000000; 409 static constexpr uint32_t cdefgh = 0x01F80000; 410 static constexpr uint32_t AllowedBits = a | B | bbbbb | cdefgh; 411 static_assert(AllowedBits == 0xFFF80000u, 412 "Invalid mask for f32 modified immediates."); 413 const float F32 = llvm::cast<const ConstantFloat>(C)->getValue(); 414 const uint32_t I32 = Utils::bitCopy<uint32_t>(F32); 415 if (I32 & ~AllowedBits) { 416 // constant has disallowed bits. 417 return false; 418 } 419 420 if ((I32 & bbbbb) != bbbbb && (I32 & bbbbb)) { 421 // not all bbbbb bits are 0 or 1. 422 return false; 423 } 424 425 if (((I32 & B) != 0) == ((I32 & bbbbb) != 0)) { 426 // B ^ b = 0; 427 return false; 428 } 429 430 *ModifiedImm = ((I32 & a) ? 0x80 : 0x00) | ((I32 & bbbbb) ? 0x40 : 0x00) | 431 ((I32 & cdefgh) >> 19); 432 return true; 433 } 434 case IceType_f64: { 435 static constexpr uint32_t a = 0x80000000u; 436 static constexpr uint32_t B = 0x40000000; 437 static constexpr uint32_t bbbbbbbb = 0x3FC00000; 438 static constexpr uint32_t cdefgh = 0x003F0000; 439 static constexpr uint32_t AllowedBits = a | B | bbbbbbbb | cdefgh; 440 static_assert(AllowedBits == 0xFFFF0000u, 441 "Invalid mask for f64 modified immediates."); 442 const double F64 = llvm::cast<const ConstantDouble>(C)->getValue(); 443 const uint64_t I64 = Utils::bitCopy<uint64_t>(F64); 444 if (I64 & 0xFFFFFFFFu) { 445 // constant has disallowed bits. 446 return false; 447 } 448 const uint32_t I32 = I64 >> 32; 449 450 if (I32 & ~AllowedBits) { 451 // constant has disallowed bits. 452 return false; 453 } 454 455 if ((I32 & bbbbbbbb) != bbbbbbbb && (I32 & bbbbbbbb)) { 456 // not all bbbbb bits are 0 or 1. 457 return false; 458 } 459 460 if (((I32 & B) != 0) == ((I32 & bbbbbbbb) != 0)) { 461 // B ^ b = 0; 462 return false; 463 } 464 465 *ModifiedImm = ((I32 & a) ? 0x80 : 0x00) | 466 ((I32 & bbbbbbbb) ? 0x40 : 0x00) | ((I32 & cdefgh) >> 16); 467 return true; 468 } 469 } 470 } 471 472 OperandARM32FlexFpZero::OperandARM32FlexFpZero(Cfg * /*Func*/, Type Ty) 473 : OperandARM32Flex(kFlexFpZero, Ty) {} 474 475 OperandARM32FlexReg::OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, 476 ShiftKind ShiftOp, Operand *ShiftAmt) 477 : OperandARM32Flex(kFlexReg, Ty), Reg(Reg), ShiftOp(ShiftOp), 478 ShiftAmt(ShiftAmt) { 479 NumVars = 1; 480 auto *ShiftVar = llvm::dyn_cast_or_null<Variable>(ShiftAmt); 481 if (ShiftVar) 482 ++NumVars; 483 Vars = Func->allocateArrayOf<Variable *>(NumVars); 484 Vars[0] = Reg; 485 if (ShiftVar) 486 Vars[1] = ShiftVar; 487 } 488 489 InstARM32Br::InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, 490 const CfgNode *TargetFalse, 491 const InstARM32Label *Label, CondARM32::Cond Pred) 492 : InstARM32Pred(Func, InstARM32::Br, 0, nullptr, Pred), 493 TargetTrue(TargetTrue), TargetFalse(TargetFalse), Label(Label) {} 494 495 bool InstARM32Br::optimizeBranch(const CfgNode *NextNode) { 496 // If there is no next block, then there can be no fallthrough to optimize. 497 if (NextNode == nullptr) 498 return false; 499 // Intra-block conditional branches can't be optimized. 500 if (Label) 501 return false; 502 // If there is no fallthrough node, such as a non-default case label for a 503 // switch instruction, then there is no opportunity to optimize. 504 if (getTargetFalse() == nullptr) 505 return false; 506 507 // Unconditional branch to the next node can be removed. 508 if (isUnconditionalBranch() && getTargetFalse() == NextNode) { 509 assert(getTargetTrue() == nullptr); 510 setDeleted(); 511 return true; 512 } 513 // If the fallthrough is to the next node, set fallthrough to nullptr to 514 // indicate. 515 if (getTargetFalse() == NextNode) { 516 TargetFalse = nullptr; 517 return true; 518 } 519 // If TargetTrue is the next node, and TargetFalse is not nullptr (which was 520 // already tested above), then invert the branch condition, swap the targets, 521 // and set new fallthrough to nullptr. 522 if (getTargetTrue() == NextNode) { 523 assert(Predicate != CondARM32::AL); 524 setPredicate(getOppositeCondition(getPredicate())); 525 TargetTrue = getTargetFalse(); 526 TargetFalse = nullptr; 527 return true; 528 } 529 return false; 530 } 531 532 bool InstARM32Br::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { 533 bool Found = false; 534 if (TargetFalse == OldNode) { 535 TargetFalse = NewNode; 536 Found = true; 537 } 538 if (TargetTrue == OldNode) { 539 TargetTrue = NewNode; 540 Found = true; 541 } 542 return Found; 543 } 544 545 template <InstARM32::InstKindARM32 K> 546 void InstARM32ThreeAddrGPR<K>::emitIAS(const Cfg *Func) const { 547 emitUsingTextFixup(Func); 548 } 549 550 template <> void InstARM32Adc::emitIAS(const Cfg *Func) const { 551 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 552 Asm->adc(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 553 if (Asm->needsTextFixup()) 554 emitUsingTextFixup(Func); 555 } 556 557 template <> void InstARM32Add::emitIAS(const Cfg *Func) const { 558 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 559 Asm->add(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 560 assert(!Asm->needsTextFixup()); 561 } 562 563 template <> void InstARM32And::emitIAS(const Cfg *Func) const { 564 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 565 Asm->and_(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 566 if (Asm->needsTextFixup()) 567 emitUsingTextFixup(Func); 568 } 569 570 template <> void InstARM32Bic::emitIAS(const Cfg *Func) const { 571 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 572 Asm->bic(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 573 if (Asm->needsTextFixup()) 574 emitUsingTextFixup(Func); 575 } 576 577 template <> void InstARM32Eor::emitIAS(const Cfg *Func) const { 578 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 579 Asm->eor(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 580 if (Asm->needsTextFixup()) 581 emitUsingTextFixup(Func); 582 } 583 584 template <> void InstARM32Asr::emitIAS(const Cfg *Func) const { 585 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 586 Asm->asr(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 587 if (Asm->needsTextFixup()) 588 emitUsingTextFixup(Func); 589 } 590 591 template <> void InstARM32Lsl::emitIAS(const Cfg *Func) const { 592 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 593 Asm->lsl(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 594 if (Asm->needsTextFixup()) 595 emitUsingTextFixup(Func); 596 } 597 598 template <> void InstARM32Lsr::emitIAS(const Cfg *Func) const { 599 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 600 Asm->lsr(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 601 if (Asm->needsTextFixup()) 602 emitUsingTextFixup(Func); 603 } 604 605 template <> void InstARM32Orr::emitIAS(const Cfg *Func) const { 606 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 607 Asm->orr(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 608 if (Asm->needsTextFixup()) 609 emitUsingTextFixup(Func); 610 } 611 612 template <> void InstARM32Mul::emitIAS(const Cfg *Func) const { 613 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 614 Asm->mul(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 615 if (Asm->needsTextFixup()) 616 emitUsingTextFixup(Func); 617 } 618 619 template <> void InstARM32Rsb::emitIAS(const Cfg *Func) const { 620 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 621 Asm->rsb(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 622 if (Asm->needsTextFixup()) 623 emitUsingTextFixup(Func); 624 } 625 626 template <> void InstARM32Rsc::emitIAS(const Cfg *Func) const { 627 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 628 Asm->rsc(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 629 if (Asm->needsTextFixup()) 630 emitUsingTextFixup(Func); 631 } 632 633 template <> void InstARM32Sbc::emitIAS(const Cfg *Func) const { 634 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 635 Asm->sbc(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 636 if (Asm->needsTextFixup()) 637 emitUsingTextFixup(Func); 638 } 639 640 template <> void InstARM32Sdiv::emitIAS(const Cfg *Func) const { 641 assert(!SetFlags); 642 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 643 Asm->sdiv(getDest(), getSrc(0), getSrc(1), getPredicate()); 644 if (Asm->needsTextFixup()) 645 emitUsingTextFixup(Func); 646 } 647 648 template <> void InstARM32Sub::emitIAS(const Cfg *Func) const { 649 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 650 Asm->sub(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); 651 if (Asm->needsTextFixup()) 652 emitUsingTextFixup(Func); 653 } 654 655 template <> void InstARM32Udiv::emitIAS(const Cfg *Func) const { 656 assert(!SetFlags); 657 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 658 Asm->udiv(getDest(), getSrc(0), getSrc(1), getPredicate()); 659 if (Asm->needsTextFixup()) 660 emitUsingTextFixup(Func); 661 } 662 663 template <> void InstARM32Vadd::emitIAS(const Cfg *Func) const { 664 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 665 const Variable *Dest = getDest(); 666 Type DestTy = Dest->getType(); 667 switch (DestTy) { 668 default: 669 llvm::report_fatal_error("Vadd not defined on type " + 670 typeStdString(DestTy)); 671 case IceType_v16i8: 672 case IceType_v8i16: 673 case IceType_v4i32: 674 Asm->vaddqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1)); 675 break; 676 case IceType_v4f32: 677 Asm->vaddqf(Dest, getSrc(0), getSrc(1)); 678 break; 679 case IceType_f32: 680 Asm->vadds(Dest, getSrc(0), getSrc(1), CondARM32::AL); 681 break; 682 case IceType_f64: 683 Asm->vaddd(Dest, getSrc(0), getSrc(1), CondARM32::AL); 684 break; 685 } 686 assert(!Asm->needsTextFixup()); 687 } 688 689 template <> void InstARM32Vand::emitIAS(const Cfg *Func) const { 690 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 691 const Variable *Dest = getDest(); 692 switch (Dest->getType()) { 693 default: 694 llvm::report_fatal_error("Vand not defined on type " + 695 typeStdString(Dest->getType())); 696 case IceType_v4i1: 697 case IceType_v8i1: 698 case IceType_v16i1: 699 case IceType_v16i8: 700 case IceType_v8i16: 701 case IceType_v4i32: 702 Asm->vandq(Dest, getSrc(0), getSrc(1)); 703 } 704 assert(!Asm->needsTextFixup()); 705 } 706 707 template <> void InstARM32Vceq::emitIAS(const Cfg *Func) const { 708 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 709 const Variable *Dest = getDest(); 710 const Type SrcTy = getSrc(0)->getType(); 711 switch (SrcTy) { 712 default: 713 llvm::report_fatal_error("Vceq not defined on type " + 714 typeStdString(SrcTy)); 715 case IceType_v4i1: 716 case IceType_v8i1: 717 case IceType_v16i1: 718 case IceType_v16i8: 719 case IceType_v8i16: 720 case IceType_v4i32: 721 Asm->vceqqi(typeElementType(SrcTy), Dest, getSrc(0), getSrc(1)); 722 break; 723 case IceType_v4f32: 724 Asm->vceqqs(Dest, getSrc(0), getSrc(1)); 725 break; 726 } 727 assert(!Asm->needsTextFixup()); 728 } 729 730 template <> void InstARM32Vcge::emitIAS(const Cfg *Func) const { 731 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 732 const Variable *Dest = getDest(); 733 const Type SrcTy = getSrc(0)->getType(); 734 switch (SrcTy) { 735 default: 736 llvm::report_fatal_error("Vcge not defined on type " + 737 typeStdString(Dest->getType())); 738 case IceType_v4i1: 739 case IceType_v8i1: 740 case IceType_v16i1: 741 case IceType_v16i8: 742 case IceType_v8i16: 743 case IceType_v4i32: { 744 const Type ElmtTy = typeElementType(SrcTy); 745 assert(Sign != InstARM32::FS_None); 746 switch (Sign) { 747 case InstARM32::FS_None: // defaults to unsigned. 748 llvm_unreachable("Sign should not be FS_None."); 749 case InstARM32::FS_Unsigned: 750 Asm->vcugeqi(ElmtTy, Dest, getSrc(0), getSrc(1)); 751 break; 752 case InstARM32::FS_Signed: 753 Asm->vcgeqi(ElmtTy, Dest, getSrc(0), getSrc(1)); 754 break; 755 } 756 } break; 757 case IceType_v4f32: 758 Asm->vcgeqs(Dest, getSrc(0), getSrc(1)); 759 break; 760 } 761 } 762 763 template <> void InstARM32Vcgt::emitIAS(const Cfg *Func) const { 764 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 765 const Variable *Dest = getDest(); 766 const Type SrcTy = getSrc(0)->getType(); 767 switch (SrcTy) { 768 default: 769 llvm::report_fatal_error("Vcgt not defined on type " + 770 typeStdString(Dest->getType())); 771 case IceType_v4i1: 772 case IceType_v8i1: 773 case IceType_v16i1: 774 case IceType_v16i8: 775 case IceType_v8i16: 776 case IceType_v4i32: { 777 const Type ElmtTy = typeElementType(SrcTy); 778 assert(Sign != InstARM32::FS_None); 779 switch (Sign) { 780 case InstARM32::FS_None: // defaults to unsigned. 781 llvm_unreachable("Sign should not be FS_None."); 782 case InstARM32::FS_Unsigned: 783 Asm->vcugtqi(ElmtTy, Dest, getSrc(0), getSrc(1)); 784 break; 785 case InstARM32::FS_Signed: 786 Asm->vcgtqi(ElmtTy, Dest, getSrc(0), getSrc(1)); 787 break; 788 } 789 } break; 790 case IceType_v4f32: 791 Asm->vcgtqs(Dest, getSrc(0), getSrc(1)); 792 break; 793 } 794 } 795 796 template <> void InstARM32Vbsl::emitIAS(const Cfg *Func) const { 797 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 798 const Variable *Dest = getDest(); 799 switch (Dest->getType()) { 800 default: 801 llvm::report_fatal_error("Vbsl not defined on type " + 802 typeStdString(Dest->getType())); 803 case IceType_v4i1: 804 case IceType_v8i1: 805 case IceType_v16i1: 806 case IceType_v16i8: 807 case IceType_v8i16: 808 case IceType_v4i32: 809 Asm->vbslq(Dest, getSrc(0), getSrc(1)); 810 } 811 assert(!Asm->needsTextFixup()); 812 } 813 814 template <> void InstARM32Vdiv::emitIAS(const Cfg *Func) const { 815 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 816 const Variable *Dest = getDest(); 817 switch (Dest->getType()) { 818 default: 819 // TODO(kschimpf) Figure if more cases are needed. 820 Asm->setNeedsTextFixup(); 821 break; 822 case IceType_f32: 823 Asm->vdivs(getDest(), getSrc(0), getSrc(1), CondARM32::AL); 824 break; 825 case IceType_f64: 826 Asm->vdivd(getDest(), getSrc(0), getSrc(1), CondARM32::AL); 827 break; 828 } 829 assert(!Asm->needsTextFixup()); 830 } 831 832 template <> void InstARM32Veor::emitIAS(const Cfg *Func) const { 833 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 834 const Variable *Dest = getDest(); 835 if (isVectorType(Dest->getType())) { 836 Asm->veorq(Dest, getSrc(0), getSrc(1)); 837 assert(!Asm->needsTextFixup()); 838 return; 839 } 840 assert(Dest->getType() == IceType_f64); 841 Asm->veord(Dest, getSrc(0), getSrc(1)); 842 assert(!Asm->needsTextFixup()); 843 } 844 845 template <> void InstARM32Vmla::emitIAS(const Cfg *Func) const { 846 // Note: Dest == getSrc(0) for four address FP instructions. 847 assert(getSrcSize() == 3); 848 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 849 const Variable *Dest = getDest(); 850 switch (Dest->getType()) { 851 default: 852 // TODO(kschimpf) Figure out how vector operations apply. 853 emitUsingTextFixup(Func); 854 return; 855 case IceType_f32: 856 Asm->vmlas(getDest(), getSrc(1), getSrc(2), CondARM32::AL); 857 assert(!Asm->needsTextFixup()); 858 return; 859 case IceType_f64: 860 Asm->vmlad(getDest(), getSrc(1), getSrc(2), CondARM32::AL); 861 assert(!Asm->needsTextFixup()); 862 return; 863 } 864 } 865 866 template <> void InstARM32Vmls::emitIAS(const Cfg *Func) const { 867 // Note: Dest == getSrc(0) for four address FP instructions. 868 assert(getSrcSize() == 3); 869 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 870 const Variable *Dest = getDest(); 871 switch (Dest->getType()) { 872 default: 873 // TODO(kschimpf) Figure out how vector operations apply. 874 emitUsingTextFixup(Func); 875 return; 876 case IceType_f32: 877 Asm->vmlss(getDest(), getSrc(1), getSrc(2), CondARM32::AL); 878 assert(!Asm->needsTextFixup()); 879 return; 880 case IceType_f64: 881 Asm->vmlsd(getDest(), getSrc(1), getSrc(2), CondARM32::AL); 882 assert(!Asm->needsTextFixup()); 883 return; 884 } 885 } 886 887 template <> void InstARM32Vmvn::emitIAS(const Cfg *Func) const { 888 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 889 const Variable *Dest = getDest(); 890 switch (Dest->getType()) { 891 default: 892 llvm::report_fatal_error("Vmvn not defined on type " + 893 typeStdString(Dest->getType())); 894 case IceType_v4i1: 895 case IceType_v8i1: 896 case IceType_v16i1: 897 case IceType_v16i8: 898 case IceType_v8i16: 899 case IceType_v4i32: 900 case IceType_v4f32: { 901 Asm->vmvnq(Dest, getSrc(0)); 902 } break; 903 } 904 } 905 906 template <> void InstARM32Vneg::emitIAS(const Cfg *Func) const { 907 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 908 const Variable *Dest = getDest(); 909 const Type DestTy = Dest->getType(); 910 switch (Dest->getType()) { 911 default: 912 llvm::report_fatal_error("Vneg not defined on type " + 913 typeStdString(Dest->getType())); 914 case IceType_v4i1: 915 case IceType_v8i1: 916 case IceType_v16i1: 917 case IceType_v16i8: 918 case IceType_v8i16: 919 case IceType_v4i32: 920 case IceType_v4f32: { 921 const Type ElmtTy = typeElementType(DestTy); 922 Asm->vnegqs(ElmtTy, Dest, getSrc(0)); 923 } break; 924 } 925 } 926 927 template <> void InstARM32Vorr::emitIAS(const Cfg *Func) const { 928 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 929 const Variable *Dest = getDest(); 930 switch (Dest->getType()) { 931 default: 932 llvm::report_fatal_error("Vorr not defined on type " + 933 typeStdString(Dest->getType())); 934 case IceType_v4i1: 935 case IceType_v8i1: 936 case IceType_v16i1: 937 case IceType_v16i8: 938 case IceType_v8i16: 939 case IceType_v4i32: 940 Asm->vorrq(Dest, getSrc(0), getSrc(1)); 941 } 942 assert(!Asm->needsTextFixup()); 943 } 944 945 template <> void InstARM32Vshl::emitIAS(const Cfg *Func) const { 946 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 947 const Variable *Dest = getDest(); 948 const Type DestTy = Dest->getType(); 949 switch (DestTy) { 950 default: 951 llvm::report_fatal_error("Vshl not defined on type " + 952 typeStdString(Dest->getType())); 953 // TODO(jpp): handle i1 vectors in terms of element count instead of element 954 // type. 955 case IceType_v4i1: 956 case IceType_v8i1: 957 case IceType_v16i1: 958 case IceType_v16i8: 959 case IceType_v8i16: 960 case IceType_v4i32: { 961 const Type ElmtTy = typeElementType(DestTy); 962 assert(Sign != InstARM32::FS_None); 963 switch (Sign) { 964 case InstARM32::FS_None: // defaults to unsigned. 965 case InstARM32::FS_Unsigned: 966 if (const auto *Imm6 = llvm::dyn_cast<ConstantInteger32>(getSrc(1))) { 967 Asm->vshlqc(ElmtTy, Dest, getSrc(0), Imm6); 968 } else { 969 Asm->vshlqu(ElmtTy, Dest, getSrc(0), getSrc(1)); 970 } 971 break; 972 case InstARM32::FS_Signed: 973 if (const auto *Imm6 = llvm::dyn_cast<ConstantInteger32>(getSrc(1))) { 974 Asm->vshlqc(ElmtTy, Dest, getSrc(0), Imm6); 975 } else { 976 Asm->vshlqi(ElmtTy, Dest, getSrc(0), getSrc(1)); 977 } 978 break; 979 } 980 } break; 981 } 982 } 983 984 template <> void InstARM32Vshr::emitIAS(const Cfg *Func) const { 985 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 986 const Variable *Dest = getDest(); 987 const Type DestTy = Dest->getType(); 988 switch (DestTy) { 989 default: 990 llvm::report_fatal_error("Vshr not defined on type " + 991 typeStdString(Dest->getType())); 992 // TODO(jpp): handle i1 vectors in terms of element count instead of element 993 // type. 994 case IceType_v4i1: 995 case IceType_v8i1: 996 case IceType_v16i1: 997 case IceType_v16i8: 998 case IceType_v8i16: 999 case IceType_v4i32: { 1000 const Type ElmtTy = typeElementType(DestTy); 1001 const auto *Imm6 = llvm::cast<ConstantInteger32>(getSrc(1)); 1002 assert(Sign != InstARM32::FS_None); 1003 switch (Sign) { 1004 case InstARM32::FS_None: // defaults to unsigned. 1005 case InstARM32::FS_Unsigned: 1006 Asm->vshrquc(ElmtTy, Dest, getSrc(0), Imm6); 1007 break; 1008 case InstARM32::FS_Signed: 1009 Asm->vshrqic(ElmtTy, Dest, getSrc(0), Imm6); 1010 break; 1011 } 1012 } break; 1013 } 1014 } 1015 1016 template <> void InstARM32Vsub::emitIAS(const Cfg *Func) const { 1017 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1018 const Variable *Dest = getDest(); 1019 Type DestTy = Dest->getType(); 1020 switch (DestTy) { 1021 default: 1022 llvm::report_fatal_error("Vsub not defined on type " + 1023 typeStdString(DestTy)); 1024 case IceType_v16i8: 1025 case IceType_v8i16: 1026 case IceType_v4i32: 1027 Asm->vsubqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1)); 1028 break; 1029 case IceType_v4f32: 1030 Asm->vsubqf(Dest, getSrc(0), getSrc(1)); 1031 break; 1032 case IceType_f32: 1033 Asm->vsubs(getDest(), getSrc(0), getSrc(1), CondARM32::AL); 1034 break; 1035 case IceType_f64: 1036 Asm->vsubd(getDest(), getSrc(0), getSrc(1), CondARM32::AL); 1037 break; 1038 } 1039 assert(!Asm->needsTextFixup()); 1040 } 1041 1042 template <> void InstARM32Vmul::emitIAS(const Cfg *Func) const { 1043 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1044 const Variable *Dest = getDest(); 1045 const Type DestTy = Dest->getType(); 1046 switch (DestTy) { 1047 default: 1048 llvm::report_fatal_error("Vmul not defined on type " + 1049 typeStdString(DestTy)); 1050 1051 case IceType_v16i8: 1052 case IceType_v8i16: 1053 case IceType_v4i32: 1054 Asm->vmulqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1)); 1055 break; 1056 case IceType_v4f32: 1057 Asm->vmulqf(Dest, getSrc(0), getSrc(1)); 1058 break; 1059 case IceType_f32: 1060 Asm->vmuls(Dest, getSrc(0), getSrc(1), CondARM32::AL); 1061 break; 1062 case IceType_f64: 1063 Asm->vmuld(Dest, getSrc(0), getSrc(1), CondARM32::AL); 1064 break; 1065 } 1066 } 1067 1068 InstARM32Call::InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget) 1069 : InstARM32(Func, InstARM32::Call, 1, Dest) { 1070 HasSideEffects = true; 1071 addSource(CallTarget); 1072 } 1073 1074 InstARM32Label::InstARM32Label(Cfg *Func, TargetARM32 *Target) 1075 : InstARM32(Func, InstARM32::Label, 0, nullptr), 1076 Number(Target->makeNextLabelNumber()) { 1077 if (BuildDefs::dump()) { 1078 Name = GlobalString::createWithString( 1079 Func->getContext(), 1080 ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number)); 1081 } else { 1082 Name = GlobalString::createWithoutString(Func->getContext()); 1083 } 1084 } 1085 1086 namespace { 1087 // Requirements for Push/Pop: 1088 // 1) All the Variables have the same type; 1089 // 2) All the variables have registers assigned to them. 1090 void validatePushOrPopRegisterListOrDie(const VarList &RegList) { 1091 Type PreviousTy = IceType_void; 1092 for (Variable *Reg : RegList) { 1093 if (PreviousTy != IceType_void && Reg->getType() != PreviousTy) { 1094 llvm::report_fatal_error("Type mismatch when popping/pushing " 1095 "registers."); 1096 } 1097 1098 if (!Reg->hasReg()) { 1099 llvm::report_fatal_error("Push/pop operand does not have a register " 1100 "assigned to it."); 1101 } 1102 1103 PreviousTy = Reg->getType(); 1104 } 1105 } 1106 } // end of anonymous namespace 1107 1108 void InstARM32RegisterStackOp::emit(const Cfg *Func) const { 1109 if (!BuildDefs::dump()) 1110 return; 1111 emitUsingForm(Func, Emit_Text); 1112 } 1113 1114 void InstARM32RegisterStackOp::emitIAS(const Cfg *Func) const { 1115 emitUsingForm(Func, Emit_Binary); 1116 assert(!Func->getAssembler<ARM32::AssemblerARM32>()->needsTextFixup()); 1117 } 1118 1119 void InstARM32RegisterStackOp::dump(const Cfg *Func) const { 1120 if (!BuildDefs::dump()) 1121 return; 1122 Ostream &Str = Func->getContext()->getStrDump(); 1123 Str << getDumpOpcode() << " "; 1124 SizeT NumRegs = getNumStackRegs(); 1125 for (SizeT I = 0; I < NumRegs; ++I) { 1126 if (I > 0) 1127 Str << ", "; 1128 getStackReg(I)->dump(Func); 1129 } 1130 } 1131 1132 void InstARM32RegisterStackOp::emitGPRsAsText(const Cfg *Func) const { 1133 if (!BuildDefs::dump()) 1134 return; 1135 Ostream &Str = Func->getContext()->getStrEmit(); 1136 Str << "\t" << getGPROpcode() << "\t{"; 1137 getStackReg(0)->emit(Func); 1138 const SizeT NumRegs = getNumStackRegs(); 1139 for (SizeT i = 1; i < NumRegs; ++i) { 1140 Str << ", "; 1141 getStackReg(i)->emit(Func); 1142 } 1143 Str << "}"; 1144 } 1145 1146 void InstARM32RegisterStackOp::emitSRegsAsText(const Cfg *Func, 1147 const Variable *BaseReg, 1148 SizeT RegCount) const { 1149 if (!BuildDefs::dump()) 1150 return; 1151 Ostream &Str = Func->getContext()->getStrEmit(); 1152 Str << "\t" << getSRegOpcode() << "\t{"; 1153 bool IsFirst = true; 1154 const auto Base = BaseReg->getRegNum(); 1155 for (SizeT i = 0; i < RegCount; ++i) { 1156 if (IsFirst) 1157 IsFirst = false; 1158 else 1159 Str << ", "; 1160 Str << RegARM32::getRegName(RegNumT::fixme(Base + i)); 1161 } 1162 Str << "}"; 1163 } 1164 1165 void InstARM32RegisterStackOp::emitSRegsOp(const Cfg *Func, EmitForm Form, 1166 const Variable *BaseReg, 1167 SizeT RegCount, 1168 SizeT InstIndex) const { 1169 if (Form == Emit_Text && BuildDefs::dump() && InstIndex > 0) { 1170 startNextInst(Func); 1171 Func->getContext()->getStrEmit() << "\n"; 1172 } 1173 emitSRegs(Func, Form, BaseReg, RegCount); 1174 } 1175 1176 namespace { 1177 1178 bool isAssignedConsecutiveRegisters(const Variable *Before, 1179 const Variable *After) { 1180 assert(Before->hasReg()); 1181 assert(After->hasReg()); 1182 return RegNumT::fixme(Before->getRegNum() + 1) == After->getRegNum(); 1183 } 1184 1185 } // end of anonymous namespace 1186 1187 void InstARM32RegisterStackOp::emitUsingForm(const Cfg *Func, 1188 const EmitForm Form) const { 1189 SizeT NumRegs = getNumStackRegs(); 1190 assert(NumRegs); 1191 1192 const auto *Reg = llvm::cast<Variable>(getStackReg(0)); 1193 if (isScalarIntegerType(Reg->getType())) { 1194 // Push/pop GPR registers. 1195 SizeT IntegerCount = 0; 1196 ARM32::IValueT GPRegisters = 0; 1197 const Variable *LastDest = nullptr; 1198 for (SizeT i = 0; i < NumRegs; ++i) { 1199 const Variable *Var = getStackReg(i); 1200 assert(Var->hasReg() && "stack op only applies to registers"); 1201 const RegARM32::GPRRegister Reg = 1202 RegARM32::getEncodedGPR(Var->getRegNum()); 1203 LastDest = Var; 1204 GPRegisters |= (1 << Reg); 1205 ++IntegerCount; 1206 } 1207 if (IntegerCount == 1) { 1208 emitSingleGPR(Func, Form, LastDest); 1209 } else { 1210 emitMultipleGPRs(Func, Form, GPRegisters); 1211 } 1212 return; 1213 } 1214 1215 // Push/pop floating point registers. Divide into a list of instructions, 1216 // defined on consecutive register ranges. Then generate the corresponding 1217 // instructions. 1218 1219 // Typical max number of registers ranges pushed/popd is no more than 5. 1220 llvm::SmallVector<std::pair<const Variable *, SizeT>, 5> InstData; 1221 const Variable *BaseReg = nullptr; 1222 SizeT RegCount = 0; 1223 for (SizeT i = 0; i < NumRegs; ++i) { 1224 const Variable *NextReg = getStackReg(i); 1225 assert(NextReg->hasReg()); 1226 if (BaseReg == nullptr) { 1227 BaseReg = NextReg; 1228 RegCount = 1; 1229 } else if (RegCount < VpushVpopMaxConsecRegs && 1230 isAssignedConsecutiveRegisters(Reg, NextReg)) { 1231 ++RegCount; 1232 } else { 1233 InstData.emplace_back(BaseReg, RegCount); 1234 BaseReg = NextReg; 1235 RegCount = 1; 1236 } 1237 Reg = NextReg; 1238 } 1239 if (RegCount) { 1240 InstData.emplace_back(BaseReg, RegCount); 1241 } 1242 SizeT InstCount = 0; 1243 if (llvm::isa<InstARM32Push>(*this)) { 1244 for (const auto &Pair : InstData) 1245 emitSRegsOp(Func, Form, Pair.first, Pair.second, InstCount++); 1246 return; 1247 } 1248 assert(llvm::isa<InstARM32Pop>(*this)); 1249 for (const auto &Pair : reverse_range(InstData)) 1250 emitSRegsOp(Func, Form, Pair.first, Pair.second, InstCount++); 1251 } 1252 1253 InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests) 1254 : InstARM32RegisterStackOp(Func, InstARM32::Pop, 0, nullptr), Dests(Dests) { 1255 // Track modifications to Dests separately via FakeDefs. Also, a pop 1256 // instruction affects the stack pointer and so it should not be allowed to 1257 // be automatically dead-code eliminated. This is automatic since we leave 1258 // the Dest as nullptr. 1259 validatePushOrPopRegisterListOrDie(Dests); 1260 } 1261 1262 InstARM32Push::InstARM32Push(Cfg *Func, const VarList &Srcs) 1263 : InstARM32RegisterStackOp(Func, InstARM32::Push, Srcs.size(), nullptr) { 1264 validatePushOrPopRegisterListOrDie(Srcs); 1265 for (Variable *Source : Srcs) { 1266 addSource(Source); 1267 } 1268 } 1269 1270 InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source) 1271 : InstARM32(Func, InstARM32::Ret, Source ? 2 : 1, nullptr) { 1272 addSource(LR); 1273 if (Source) 1274 addSource(Source); 1275 } 1276 1277 InstARM32Str::InstARM32Str(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, 1278 CondARM32::Cond Predicate) 1279 : InstARM32Pred(Func, InstARM32::Str, 2, nullptr, Predicate) { 1280 addSource(Value); 1281 addSource(Mem); 1282 } 1283 1284 InstARM32Strex::InstARM32Strex(Cfg *Func, Variable *Dest, Variable *Value, 1285 OperandARM32Mem *Mem, CondARM32::Cond Predicate) 1286 : InstARM32Pred(Func, InstARM32::Strex, 2, Dest, Predicate) { 1287 addSource(Value); 1288 addSource(Mem); 1289 } 1290 1291 InstARM32Trap::InstARM32Trap(Cfg *Func) 1292 : InstARM32(Func, InstARM32::Trap, 0, nullptr) {} 1293 1294 InstARM32Umull::InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, 1295 Variable *Src0, Variable *Src1, 1296 CondARM32::Cond Predicate) 1297 : InstARM32Pred(Func, InstARM32::Umull, 2, DestLo, Predicate), 1298 // DestHi is expected to have a FakeDef inserted by the lowering code. 1299 DestHi(DestHi) { 1300 addSource(Src0); 1301 addSource(Src1); 1302 } 1303 1304 InstARM32Vcvt::InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src, 1305 VcvtVariant Variant, CondARM32::Cond Predicate) 1306 : InstARM32Pred(Func, InstARM32::Vcvt, 1, Dest, Predicate), 1307 Variant(Variant) { 1308 addSource(Src); 1309 } 1310 1311 InstARM32Mov::InstARM32Mov(Cfg *Func, Variable *Dest, Operand *Src, 1312 CondARM32::Cond Predicate) 1313 : InstARM32Pred(Func, InstARM32::Mov, 2, Dest, Predicate) { 1314 auto *Dest64 = llvm::dyn_cast<Variable64On32>(Dest); 1315 auto *Src64 = llvm::dyn_cast<Variable64On32>(Src); 1316 1317 assert(Dest64 == nullptr || Src64 == nullptr); 1318 1319 if (Dest64 != nullptr) { 1320 // this-> is needed below because there is a parameter named Dest. 1321 this->Dest = Dest64->getLo(); 1322 DestHi = Dest64->getHi(); 1323 } 1324 1325 if (Src64 == nullptr) { 1326 addSource(Src); 1327 } else { 1328 addSource(Src64->getLo()); 1329 addSource(Src64->getHi()); 1330 } 1331 } 1332 1333 namespace { 1334 1335 // These next two functions find the D register that maps to the half of the Q 1336 // register that this instruction is accessing. 1337 Register getDRegister(const Variable *Src, uint32_t Index) { 1338 assert(Src->hasReg()); 1339 const auto SrcReg = Src->getRegNum(); 1340 1341 const RegARM32::RegTableType &SrcEntry = RegARM32::RegTable[SrcReg]; 1342 assert(SrcEntry.IsVec128); 1343 1344 const uint32_t NumElements = typeNumElements(Src->getType()); 1345 1346 // This code assumes the Aliases list goes Q_n, S_2n, S_2n+1. The asserts in 1347 // the next two branches help to check that this is still true. 1348 if (Index < NumElements / 2) { 1349 // We have a Q register that's made up of two D registers. This assert is 1350 // to help ensure that we picked the right D register. 1351 // 1352 // TODO(jpp): find a way to do this that doesn't rely on ordering of the 1353 // alias list. 1354 assert(RegARM32::RegTable[SrcEntry.Aliases[1]].Encoding + 1 == 1355 RegARM32::RegTable[SrcEntry.Aliases[2]].Encoding); 1356 return static_cast<Register>(SrcEntry.Aliases[1]); 1357 } else { 1358 // We have a Q register that's made up of two D registers. This assert is 1359 // to help ensure that we picked the right D register. 1360 // 1361 // TODO(jpp): find a way to do this that doesn't rely on ordering of the 1362 // alias list. 1363 assert(RegARM32::RegTable[SrcEntry.Aliases[2]].Encoding - 1 == 1364 RegARM32::RegTable[SrcEntry.Aliases[1]].Encoding); 1365 return static_cast<Register>(SrcEntry.Aliases[2]); 1366 } 1367 } 1368 1369 uint32_t adjustDIndex(Type Ty, uint32_t DIndex) { 1370 // If Ty is a vector of i1, we may need to adjust DIndex. This is needed 1371 // because, e.g., the second i1 in a v4i1 is accessed with a 1372 // 1373 // vmov.s8 Qd[4], Rn 1374 switch (Ty) { 1375 case IceType_v4i1: 1376 return DIndex * 4; 1377 case IceType_v8i1: 1378 return DIndex * 2; 1379 case IceType_v16i1: 1380 return DIndex; 1381 default: 1382 return DIndex; 1383 } 1384 } 1385 1386 uint32_t getDIndex(Type Ty, uint32_t NumElements, uint32_t Index) { 1387 const uint32_t DIndex = 1388 (Index < NumElements / 2) ? Index : Index - (NumElements / 2); 1389 return adjustDIndex(Ty, DIndex); 1390 } 1391 1392 // For floating point values, we can insertelement or extractelement by moving 1393 // directly from an S register. This function finds the right one. 1394 Register getSRegister(const Variable *Src, uint32_t Index) { 1395 assert(Src->hasReg()); 1396 const auto SrcReg = Src->getRegNum(); 1397 1398 // For floating point values, we need to be allocated to Q0 - Q7, so we can 1399 // directly access the value we want as one of the S registers. 1400 assert(Src->getType() == IceType_v4f32); 1401 assert(SrcReg < RegARM32::Reg_q8); 1402 1403 // This part assumes the register alias list goes q0, d0, d1, s0, s1, s2, s3. 1404 assert(Index < 4); 1405 1406 // TODO(jpp): find a way to do this that doesn't rely on ordering of the alias 1407 // list. 1408 return static_cast<Register>(RegARM32::RegTable[SrcReg].Aliases[Index + 3]); 1409 } 1410 1411 } // end of anonymous namespace 1412 1413 void InstARM32Extract::emit(const Cfg *Func) const { 1414 Ostream &Str = Func->getContext()->getStrEmit(); 1415 const Type DestTy = getDest()->getType(); 1416 1417 const auto *Src = llvm::cast<Variable>(getSrc(0)); 1418 1419 if (isIntegerType(DestTy)) { 1420 Str << "\t" 1421 << "vmov" << getPredicate(); 1422 const uint32_t BitSize = typeWidthInBytes(DestTy) * CHAR_BIT; 1423 if (BitSize < 32) { 1424 Str << ".s" << BitSize; 1425 } else { 1426 Str << "." << BitSize; 1427 } 1428 Str << "\t"; 1429 getDest()->emit(Func); 1430 Str << ", "; 1431 1432 const Type SrcTy = Src->getType(); 1433 const size_t VectorSize = typeNumElements(SrcTy); 1434 1435 const Register SrcReg = getDRegister(Src, Index); 1436 1437 Str << RegARM32::RegTable[SrcReg].Name; 1438 Str << "[" << getDIndex(SrcTy, VectorSize, Index) << "]"; 1439 } else if (isFloatingType(DestTy)) { 1440 const Register SrcReg = getSRegister(Src, Index); 1441 1442 Str << "\t" 1443 << "vmov" << getPredicate() << ".f32" 1444 << "\t"; 1445 getDest()->emit(Func); 1446 Str << ", " << RegARM32::RegTable[SrcReg].Name; 1447 } else { 1448 assert(false && "Invalid extract type"); 1449 } 1450 } 1451 1452 void InstARM32Extract::emitIAS(const Cfg *Func) const { 1453 const Operand *Dest = getDest(); 1454 const Type DestTy = Dest->getType(); 1455 const Operand *Src = getSrc(0); 1456 const Type SrcTy = Src->getType(); 1457 assert(isVectorType(Src->getType())); 1458 assert(DestTy == typeElementType(Src->getType())); 1459 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1460 if (isIntegerType(DestTy)) { 1461 Asm->vmovrqi(Dest, Src, adjustDIndex(SrcTy, Index), getPredicate()); 1462 assert(!Asm->needsTextFixup()); 1463 return; 1464 } 1465 assert(isFloatingType(DestTy)); 1466 Asm->vmovsqi(Dest, Src, Index, getPredicate()); 1467 assert(!Asm->needsTextFixup()); 1468 } 1469 1470 namespace { 1471 Type insertionType(Type Ty) { 1472 assert(isVectorType(Ty)); 1473 switch (Ty) { 1474 case IceType_v4i1: 1475 return IceType_v4i32; 1476 case IceType_v8i1: 1477 return IceType_v8i16; 1478 case IceType_v16i1: 1479 return IceType_v16i8; 1480 default: 1481 return Ty; 1482 } 1483 } 1484 } // end of anonymous namespace 1485 1486 void InstARM32Insert::emit(const Cfg *Func) const { 1487 Ostream &Str = Func->getContext()->getStrEmit(); 1488 const Variable *Dest = getDest(); 1489 const auto *Src = llvm::cast<Variable>(getSrc(0)); 1490 const Type DestTy = insertionType(getDest()->getType()); 1491 assert(isVectorType(DestTy)); 1492 1493 if (isIntegerType(DestTy)) { 1494 Str << "\t" 1495 << "vmov" << getPredicate(); 1496 const size_t BitSize = typeWidthInBytes(typeElementType(DestTy)) * CHAR_BIT; 1497 Str << "." << BitSize << "\t"; 1498 1499 const size_t VectorSize = typeNumElements(DestTy); 1500 const Register DestReg = getDRegister(Dest, Index); 1501 const uint32_t Index = 1502 getDIndex(insertionType(DestTy), VectorSize, this->Index); 1503 Str << RegARM32::RegTable[DestReg].Name; 1504 Str << "[" << Index << "], "; 1505 Src->emit(Func); 1506 } else if (isFloatingType(DestTy)) { 1507 Str << "\t" 1508 << "vmov" << getPredicate() << ".f32" 1509 << "\t"; 1510 const Register DestReg = getSRegister(Dest, Index); 1511 Str << RegARM32::RegTable[DestReg].Name << ", "; 1512 Src->emit(Func); 1513 } else { 1514 assert(false && "Invalid insert type"); 1515 } 1516 } 1517 1518 void InstARM32Insert::emitIAS(const Cfg *Func) const { 1519 const Variable *Dest = getDest(); 1520 const auto *Src = llvm::cast<Variable>(getSrc(0)); 1521 const Type DestTy = insertionType(Dest->getType()); 1522 const Type SrcTy = typeElementType(DestTy); 1523 assert(SrcTy == Src->getType() || Src->getType() == IceType_i1); 1524 assert(isVectorType(DestTy)); 1525 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1526 if (isIntegerType(SrcTy)) { 1527 Asm->vmovqir(Dest->asType(Func, DestTy, Dest->getRegNum()), 1528 adjustDIndex(DestTy, Index), 1529 Src->asType(Func, SrcTy, Src->getRegNum()), getPredicate()); 1530 assert(!Asm->needsTextFixup()); 1531 return; 1532 } 1533 assert(isFloatingType(SrcTy)); 1534 Asm->vmovqis(Dest, Index, Src, getPredicate()); 1535 assert(!Asm->needsTextFixup()); 1536 } 1537 1538 template <InstARM32::InstKindARM32 K> 1539 void InstARM32CmpLike<K>::emitIAS(const Cfg *Func) const { 1540 emitUsingTextFixup(Func); 1541 } 1542 1543 template <> void InstARM32Cmn::emitIAS(const Cfg *Func) const { 1544 assert(getSrcSize() == 2); 1545 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1546 Asm->cmn(getSrc(0), getSrc(1), getPredicate()); 1547 if (Asm->needsTextFixup()) 1548 emitUsingTextFixup(Func); 1549 } 1550 1551 template <> void InstARM32Cmp::emitIAS(const Cfg *Func) const { 1552 assert(getSrcSize() == 2); 1553 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1554 Asm->cmp(getSrc(0), getSrc(1), getPredicate()); 1555 if (Asm->needsTextFixup()) 1556 emitUsingTextFixup(Func); 1557 } 1558 1559 template <> void InstARM32Tst::emitIAS(const Cfg *Func) const { 1560 assert(getSrcSize() == 2); 1561 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1562 Asm->tst(getSrc(0), getSrc(1), getPredicate()); 1563 if (Asm->needsTextFixup()) 1564 emitUsingTextFixup(Func); 1565 } 1566 1567 InstARM32Dmb::InstARM32Dmb(Cfg *Func) 1568 : InstARM32Pred(Func, InstARM32::Dmb, 0, nullptr, CondARM32::AL) {} 1569 1570 InstARM32Nop::InstARM32Nop(Cfg *Func) 1571 : InstARM32Pred(Func, InstARM32::Nop, 0, nullptr, CondARM32::AL) {} 1572 1573 InstARM32Vcmp::InstARM32Vcmp(Cfg *Func, Variable *Src0, Operand *Src1, 1574 CondARM32::Cond Predicate) 1575 : InstARM32Pred(Func, InstARM32::Vcmp, 2, nullptr, Predicate) { 1576 HasSideEffects = true; 1577 addSource(Src0); 1578 addSource(Src1); 1579 } 1580 1581 InstARM32Vmrs::InstARM32Vmrs(Cfg *Func, CondARM32::Cond Predicate) 1582 : InstARM32Pred(Func, InstARM32::Vmrs, 0, nullptr, Predicate) { 1583 HasSideEffects = true; 1584 } 1585 1586 InstARM32Vabs::InstARM32Vabs(Cfg *Func, Variable *Dest, Variable *Src, 1587 CondARM32::Cond Predicate) 1588 : InstARM32Pred(Func, InstARM32::Vabs, 1, Dest, Predicate) { 1589 addSource(Src); 1590 } 1591 1592 // ======================== Dump routines ======================== // 1593 1594 // Two-addr ops 1595 template <> const char *InstARM32Movt::Opcode = "movt"; 1596 // Unary ops 1597 template <> const char *InstARM32Movw::Opcode = "movw"; 1598 template <> const char *InstARM32Clz::Opcode = "clz"; 1599 template <> const char *InstARM32Mvn::Opcode = "mvn"; 1600 template <> const char *InstARM32Rbit::Opcode = "rbit"; 1601 template <> const char *InstARM32Rev::Opcode = "rev"; 1602 template <> const char *InstARM32Sxt::Opcode = "sxt"; // still requires b/h 1603 template <> const char *InstARM32Uxt::Opcode = "uxt"; // still requires b/h 1604 // FP 1605 template <> const char *InstARM32Vsqrt::Opcode = "vsqrt"; 1606 // Mov-like ops 1607 template <> const char *InstARM32Ldr::Opcode = "ldr"; 1608 template <> const char *InstARM32Ldrex::Opcode = "ldrex"; 1609 // Three-addr ops 1610 template <> const char *InstARM32Adc::Opcode = "adc"; 1611 template <> const char *InstARM32Add::Opcode = "add"; 1612 template <> const char *InstARM32And::Opcode = "and"; 1613 template <> const char *InstARM32Asr::Opcode = "asr"; 1614 template <> const char *InstARM32Bic::Opcode = "bic"; 1615 template <> const char *InstARM32Eor::Opcode = "eor"; 1616 template <> const char *InstARM32Lsl::Opcode = "lsl"; 1617 template <> const char *InstARM32Lsr::Opcode = "lsr"; 1618 template <> const char *InstARM32Mul::Opcode = "mul"; 1619 template <> const char *InstARM32Orr::Opcode = "orr"; 1620 template <> const char *InstARM32Rsb::Opcode = "rsb"; 1621 template <> const char *InstARM32Rsc::Opcode = "rsc"; 1622 template <> const char *InstARM32Sbc::Opcode = "sbc"; 1623 template <> const char *InstARM32Sdiv::Opcode = "sdiv"; 1624 template <> const char *InstARM32Sub::Opcode = "sub"; 1625 template <> const char *InstARM32Udiv::Opcode = "udiv"; 1626 // FP 1627 template <> const char *InstARM32Vadd::Opcode = "vadd"; 1628 template <> const char *InstARM32Vand::Opcode = "vand"; 1629 template <> const char *InstARM32Vbsl::Opcode = "vbsl"; 1630 template <> const char *InstARM32Vceq::Opcode = "vceq"; 1631 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vcge>::Opcode = "vcge"; 1632 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vcgt>::Opcode = "vcgt"; 1633 template <> const char *InstARM32Vdiv::Opcode = "vdiv"; 1634 template <> const char *InstARM32Veor::Opcode = "veor"; 1635 template <> const char *InstARM32Vmla::Opcode = "vmla"; 1636 template <> const char *InstARM32Vmls::Opcode = "vmls"; 1637 template <> const char *InstARM32Vmul::Opcode = "vmul"; 1638 template <> const char *InstARM32Vmvn::Opcode = "vmvn"; 1639 template <> const char *InstARM32Vorr::Opcode = "vorr"; 1640 template <> const char *InstARM32UnaryopFP<InstARM32::Vneg>::Opcode = "vneg"; 1641 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vshl>::Opcode = "vshl"; 1642 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vshr>::Opcode = "vshr"; 1643 template <> const char *InstARM32Vsub::Opcode = "vsub"; 1644 // Four-addr ops 1645 template <> const char *InstARM32Mla::Opcode = "mla"; 1646 template <> const char *InstARM32Mls::Opcode = "mls"; 1647 // Cmp-like ops 1648 template <> const char *InstARM32Cmn::Opcode = "cmn"; 1649 template <> const char *InstARM32Cmp::Opcode = "cmp"; 1650 template <> const char *InstARM32Tst::Opcode = "tst"; 1651 1652 void InstARM32::dump(const Cfg *Func) const { 1653 if (!BuildDefs::dump()) 1654 return; 1655 Ostream &Str = Func->getContext()->getStrDump(); 1656 Str << "[ARM32] "; 1657 Inst::dump(Func); 1658 } 1659 1660 void InstARM32Mov::emitMultiDestSingleSource(const Cfg *Func) const { 1661 if (!BuildDefs::dump()) 1662 return; 1663 Ostream &Str = Func->getContext()->getStrEmit(); 1664 Variable *DestLo = getDest(); 1665 Variable *DestHi = getDestHi(); 1666 auto *Src = llvm::cast<Variable>(getSrc(0)); 1667 1668 assert(DestHi->hasReg()); 1669 assert(DestLo->hasReg()); 1670 assert(Src->hasReg()); 1671 1672 Str << "\t" 1673 "vmov" << getPredicate() << "\t"; 1674 DestLo->emit(Func); 1675 Str << ", "; 1676 DestHi->emit(Func); 1677 Str << ", "; 1678 Src->emit(Func); 1679 } 1680 1681 void InstARM32Mov::emitSingleDestMultiSource(const Cfg *Func) const { 1682 if (!BuildDefs::dump()) 1683 return; 1684 Ostream &Str = Func->getContext()->getStrEmit(); 1685 Variable *Dest = getDest(); 1686 auto *SrcLo = llvm::cast<Variable>(getSrc(0)); 1687 auto *SrcHi = llvm::cast<Variable>(getSrc(1)); 1688 1689 assert(SrcHi->hasReg()); 1690 assert(SrcLo->hasReg()); 1691 assert(Dest->hasReg()); 1692 assert(getSrcSize() == 2); 1693 1694 Str << "\t" 1695 "vmov" << getPredicate() << "\t"; 1696 Dest->emit(Func); 1697 Str << ", "; 1698 SrcLo->emit(Func); 1699 Str << ", "; 1700 SrcHi->emit(Func); 1701 } 1702 1703 namespace { 1704 1705 bool isVariableWithoutRegister(const Operand *Op) { 1706 if (const auto *OpV = llvm::dyn_cast<Variable>(Op)) { 1707 return !OpV->hasReg(); 1708 } 1709 return false; 1710 } 1711 bool isMemoryAccess(Operand *Op) { 1712 return isVariableWithoutRegister(Op) || llvm::isa<OperandARM32Mem>(Op); 1713 } 1714 1715 bool isMoveBetweenCoreAndVFPRegisters(Variable *Dest, Operand *Src) { 1716 const Type DestTy = Dest->getType(); 1717 const Type SrcTy = Src->getType(); 1718 return !isVectorType(DestTy) && !isVectorType(SrcTy) && 1719 (isScalarIntegerType(DestTy) == isScalarFloatingType(SrcTy)); 1720 } 1721 1722 } // end of anonymous namespace 1723 1724 void InstARM32Mov::emitSingleDestSingleSource(const Cfg *Func) const { 1725 if (!BuildDefs::dump()) 1726 return; 1727 Ostream &Str = Func->getContext()->getStrEmit(); 1728 Variable *Dest = getDest(); 1729 1730 if (!Dest->hasReg()) { 1731 llvm::report_fatal_error("mov can't store."); 1732 } 1733 1734 Operand *Src0 = getSrc(0); 1735 if (isMemoryAccess(Src0)) { 1736 llvm::report_fatal_error("mov can't load."); 1737 } 1738 1739 Type Ty = Dest->getType(); 1740 const bool IsVector = isVectorType(Ty); 1741 const bool IsScalarFP = isScalarFloatingType(Ty); 1742 const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0); 1743 const bool IsVMove = (IsVector || IsScalarFP || CoreVFPMove); 1744 const char *Opcode = IsVMove ? "vmov" : "mov"; 1745 // when vmov{c}'ing, we need to emit a width string. Otherwise, the 1746 // assembler might be tempted to assume we want a vector vmov{c}, and that 1747 // is disallowed because ARM. 1748 const char *WidthString = !CoreVFPMove ? getFpWidthString(Ty) : ""; 1749 CondARM32::Cond Cond = getPredicate(); 1750 if (IsVector) 1751 assert(CondARM32::isUnconditional(Cond) && 1752 "Moves on vectors must be unconditional!"); 1753 Str << "\t" << Opcode; 1754 if (IsVMove) { 1755 Str << Cond << WidthString; 1756 } else { 1757 Str << WidthString << Cond; 1758 } 1759 Str << "\t"; 1760 Dest->emit(Func); 1761 Str << ", "; 1762 Src0->emit(Func); 1763 } 1764 1765 void InstARM32Mov::emit(const Cfg *Func) const { 1766 if (!BuildDefs::dump()) 1767 return; 1768 assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type."); 1769 if (isMultiDest()) { 1770 emitMultiDestSingleSource(Func); 1771 return; 1772 } 1773 1774 if (isMultiSource()) { 1775 emitSingleDestMultiSource(Func); 1776 return; 1777 } 1778 1779 emitSingleDestSingleSource(Func); 1780 } 1781 1782 void InstARM32Mov::emitIAS(const Cfg *Func) const { 1783 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1784 const Variable *Dest = getDest(); 1785 Operand *Src0 = getSrc(0); 1786 const CondARM32::Cond Cond = getPredicate(); 1787 if (!Dest->hasReg()) { 1788 llvm::report_fatal_error("mov can't store."); 1789 } 1790 if (isMemoryAccess(Src0)) { 1791 llvm::report_fatal_error("mov can't load."); 1792 } 1793 1794 assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type."); 1795 if (isMultiDest()) { 1796 Asm->vmovrrd(Dest, getDestHi(), Src0, Cond); 1797 return; 1798 } 1799 if (isMultiSource()) { 1800 Asm->vmovdrr(Dest, Src0, getSrc(1), Cond); 1801 return; 1802 } 1803 1804 const Type DestTy = Dest->getType(); 1805 const Type SrcTy = Src0->getType(); 1806 switch (DestTy) { 1807 default: 1808 break; // Error 1809 case IceType_i1: 1810 case IceType_i8: 1811 case IceType_i16: 1812 case IceType_i32: 1813 switch (SrcTy) { 1814 default: 1815 break; // Error 1816 case IceType_i1: 1817 case IceType_i8: 1818 case IceType_i16: 1819 case IceType_i32: 1820 case IceType_i64: 1821 Asm->mov(Dest, Src0, Cond); 1822 return; 1823 case IceType_f32: 1824 Asm->vmovrs(Dest, Src0, Cond); 1825 return; 1826 } 1827 break; // Error 1828 case IceType_i64: 1829 if (isScalarIntegerType(SrcTy)) { 1830 Asm->mov(Dest, Src0, Cond); 1831 return; 1832 } 1833 if (SrcTy == IceType_f64) { 1834 if (const auto *Var = llvm::dyn_cast<Variable>(Src0)) { 1835 Asm->vmovdd(Dest, Var, Cond); 1836 return; 1837 } 1838 if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) { 1839 Asm->vmovd(Dest, FpImm, Cond); 1840 return; 1841 } 1842 } 1843 break; // Error 1844 case IceType_f32: 1845 switch (SrcTy) { 1846 default: 1847 break; // Error 1848 case IceType_i1: 1849 case IceType_i8: 1850 case IceType_i16: 1851 case IceType_i32: 1852 return Asm->vmovsr(Dest, Src0, Cond); 1853 case IceType_f32: 1854 if (const auto *Var = llvm::dyn_cast<Variable>(Src0)) { 1855 Asm->vmovss(Dest, Var, Cond); 1856 return; 1857 } 1858 if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) { 1859 Asm->vmovs(Dest, FpImm, Cond); 1860 return; 1861 } 1862 break; // Error 1863 } 1864 break; // Error 1865 case IceType_f64: 1866 if (SrcTy == IceType_f64) { 1867 if (const auto *Var = llvm::dyn_cast<Variable>(Src0)) { 1868 Asm->vmovdd(Dest, Var, Cond); 1869 return; 1870 } 1871 if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) { 1872 Asm->vmovd(Dest, FpImm, Cond); 1873 return; 1874 } 1875 } 1876 break; // Error 1877 // TODO(jpp): Remove vectors of i1. 1878 case IceType_v4i1: 1879 case IceType_v8i1: 1880 case IceType_v16i1: 1881 case IceType_v16i8: 1882 case IceType_v8i16: 1883 case IceType_v4i32: 1884 case IceType_v4f32: 1885 assert(CondARM32::isUnconditional(Cond) && 1886 "Moves on vector must be unconditional!"); 1887 if (isVectorType(SrcTy)) { 1888 // Mov between different Src and Dest types is used for bitcasting 1889 // vectors. We still want to make sure SrcTy is a vector type. 1890 Asm->vorrq(Dest, Src0, Src0); 1891 return; 1892 } else if (const auto *C = llvm::dyn_cast<ConstantInteger32>(Src0)) { 1893 // Mov with constant argument, allowing the initializing all elements of 1894 // the vector. 1895 if (Asm->vmovqc(Dest, C)) 1896 return; 1897 } 1898 } 1899 llvm::report_fatal_error("Mov: don't know how to move " + 1900 typeStdString(SrcTy) + " to " + 1901 typeStdString(DestTy)); 1902 } 1903 1904 void InstARM32Mov::dump(const Cfg *Func) const { 1905 if (!BuildDefs::dump()) 1906 return; 1907 assert(getSrcSize() == 1 || getSrcSize() == 2); 1908 Ostream &Str = Func->getContext()->getStrDump(); 1909 Variable *Dest = getDest(); 1910 Variable *DestHi = getDestHi(); 1911 Dest->dump(Func); 1912 if (DestHi) { 1913 Str << ", "; 1914 DestHi->dump(Func); 1915 } 1916 1917 dumpOpcodePred(Str, " = mov", getDest()->getType()); 1918 Str << " "; 1919 1920 dumpSources(Func); 1921 } 1922 1923 void InstARM32Br::emit(const Cfg *Func) const { 1924 if (!BuildDefs::dump()) 1925 return; 1926 Ostream &Str = Func->getContext()->getStrEmit(); 1927 Str << "\t" 1928 "b" << getPredicate() << "\t"; 1929 if (Label) { 1930 Str << Label->getLabelName(); 1931 } else { 1932 if (isUnconditionalBranch()) { 1933 Str << getTargetFalse()->getAsmName(); 1934 } else { 1935 Str << getTargetTrue()->getAsmName(); 1936 if (getTargetFalse()) { 1937 startNextInst(Func); 1938 Str << "\n\t" 1939 << "b" 1940 << "\t" << getTargetFalse()->getAsmName(); 1941 } 1942 } 1943 } 1944 } 1945 1946 void InstARM32Br::emitIAS(const Cfg *Func) const { 1947 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1948 if (Label) { 1949 Asm->b(Asm->getOrCreateLocalLabel(Label->getNumber()), getPredicate()); 1950 } else if (isUnconditionalBranch()) { 1951 Asm->b(Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex()), 1952 getPredicate()); 1953 } else { 1954 Asm->b(Asm->getOrCreateCfgNodeLabel(getTargetTrue()->getIndex()), 1955 getPredicate()); 1956 if (const CfgNode *False = getTargetFalse()) 1957 Asm->b(Asm->getOrCreateCfgNodeLabel(False->getIndex()), CondARM32::AL); 1958 } 1959 if (Asm->needsTextFixup()) 1960 emitUsingTextFixup(Func); 1961 } 1962 1963 void InstARM32Br::dump(const Cfg *Func) const { 1964 if (!BuildDefs::dump()) 1965 return; 1966 Ostream &Str = Func->getContext()->getStrDump(); 1967 Str << "br "; 1968 1969 if (getPredicate() == CondARM32::AL) { 1970 if (Label) { 1971 Str << "label %" << Label->getLabelName(); 1972 } else { 1973 Str << "label %" << getTargetFalse()->getName(); 1974 } 1975 return; 1976 } 1977 1978 if (Label) { 1979 Str << getPredicate() << ", label %" << Label->getLabelName(); 1980 } else { 1981 Str << getPredicate() << ", label %" << getTargetTrue()->getName(); 1982 if (getTargetFalse()) { 1983 Str << ", label %" << getTargetFalse()->getName(); 1984 } 1985 } 1986 } 1987 1988 void InstARM32Call::emit(const Cfg *Func) const { 1989 if (!BuildDefs::dump()) 1990 return; 1991 Ostream &Str = Func->getContext()->getStrEmit(); 1992 assert(getSrcSize() == 1); 1993 if (llvm::isa<ConstantInteger32>(getCallTarget())) { 1994 // This shouldn't happen (typically have to copy the full 32-bits to a 1995 // register and do an indirect jump). 1996 llvm::report_fatal_error("ARM32Call to ConstantInteger32"); 1997 } else if (const auto *CallTarget = 1998 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { 1999 // Calls only have 24-bits, but the linker should insert veneers to extend 2000 // the range if needed. 2001 Str << "\t" 2002 "bl" 2003 "\t"; 2004 CallTarget->emitWithoutPrefix(Func->getTarget()); 2005 } else { 2006 Str << "\t" 2007 "blx" 2008 "\t"; 2009 getCallTarget()->emit(Func); 2010 } 2011 } 2012 2013 void InstARM32Call::emitIAS(const Cfg *Func) const { 2014 assert(getSrcSize() == 1); 2015 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2016 if (llvm::isa<ConstantInteger32>(getCallTarget())) { 2017 // This shouldn't happen (typically have to copy the full 32-bits to a 2018 // register and do an indirect jump). 2019 llvm::report_fatal_error("ARM32Call to ConstantInteger32"); 2020 } else if (const auto *CallTarget = 2021 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { 2022 // Calls only have 24-bits, but the linker should insert veneers to extend 2023 // the range if needed. 2024 Asm->bl(CallTarget); 2025 } else { 2026 Asm->blx(getCallTarget()); 2027 } 2028 if (Asm->needsTextFixup()) 2029 return emitUsingTextFixup(Func); 2030 } 2031 2032 void InstARM32Call::dump(const Cfg *Func) const { 2033 if (!BuildDefs::dump()) 2034 return; 2035 Ostream &Str = Func->getContext()->getStrDump(); 2036 if (getDest()) { 2037 dumpDest(Func); 2038 Str << " = "; 2039 } 2040 Str << "call "; 2041 getCallTarget()->dump(Func); 2042 } 2043 2044 void InstARM32Label::emit(const Cfg *Func) const { 2045 if (!BuildDefs::dump()) 2046 return; 2047 // A label is not really an instruction. Hence, we need to fix the 2048 // emitted text size. 2049 if (auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>()) 2050 Asm->decEmitTextSize(InstSize); 2051 Ostream &Str = Func->getContext()->getStrEmit(); 2052 Str << getLabelName() << ":"; 2053 } 2054 2055 void InstARM32Label::emitIAS(const Cfg *Func) const { 2056 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2057 Asm->bindLocalLabel(this, Number); 2058 if (OffsetReloc != nullptr) { 2059 Asm->bindRelocOffset(OffsetReloc); 2060 } 2061 if (Asm->needsTextFixup()) 2062 emitUsingTextFixup(Func); 2063 } 2064 2065 void InstARM32Label::dump(const Cfg *Func) const { 2066 if (!BuildDefs::dump()) 2067 return; 2068 Ostream &Str = Func->getContext()->getStrDump(); 2069 Str << getLabelName() << ":"; 2070 } 2071 2072 template <InstARM32::InstKindARM32 K> 2073 void InstARM32LoadBase<K>::emitIAS(const Cfg *Func) const { 2074 emitUsingTextFixup(Func); 2075 } 2076 2077 template <> void InstARM32Ldr::emit(const Cfg *Func) const { 2078 if (!BuildDefs::dump()) 2079 return; 2080 Ostream &Str = Func->getContext()->getStrEmit(); 2081 assert(getSrcSize() == 1); 2082 assert(getDest()->hasReg()); 2083 Variable *Dest = getDest(); 2084 Type Ty = Dest->getType(); 2085 const bool IsVector = isVectorType(Ty); 2086 const bool IsScalarFloat = isScalarFloatingType(Ty); 2087 const char *ActualOpcode = 2088 IsVector ? "vld1" : (IsScalarFloat ? "vldr" : "ldr"); 2089 const char *WidthString = IsVector ? "" : getWidthString(Ty); 2090 Str << "\t" << ActualOpcode; 2091 const bool IsVInst = IsVector || IsScalarFloat; 2092 if (IsVInst) { 2093 Str << getPredicate() << WidthString; 2094 } else { 2095 Str << WidthString << getPredicate(); 2096 } 2097 if (IsVector) 2098 Str << "." << getVecElmtBitsize(Ty); 2099 Str << "\t"; 2100 getDest()->emit(Func); 2101 Str << ", "; 2102 getSrc(0)->emit(Func); 2103 } 2104 2105 template <> void InstARM32Ldr::emitIAS(const Cfg *Func) const { 2106 assert(getSrcSize() == 1); 2107 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2108 Variable *Dest = getDest(); 2109 const Type DestTy = Dest->getType(); 2110 switch (DestTy) { 2111 default: 2112 llvm::report_fatal_error("Ldr on unknown type: " + typeStdString(DestTy)); 2113 case IceType_i1: 2114 case IceType_i8: 2115 case IceType_i16: 2116 case IceType_i32: 2117 case IceType_i64: 2118 Asm->ldr(Dest, getSrc(0), getPredicate(), Func->getTarget()); 2119 break; 2120 case IceType_f32: 2121 Asm->vldrs(Dest, getSrc(0), getPredicate(), Func->getTarget()); 2122 break; 2123 case IceType_f64: 2124 Asm->vldrd(Dest, getSrc(0), getPredicate(), Func->getTarget()); 2125 break; 2126 case IceType_v16i8: 2127 case IceType_v8i16: 2128 case IceType_v4i32: 2129 case IceType_v4f32: 2130 case IceType_v16i1: 2131 case IceType_v8i1: 2132 case IceType_v4i1: 2133 Asm->vld1qr(getVecElmtBitsize(DestTy), Dest, getSrc(0), Func->getTarget()); 2134 break; 2135 } 2136 } 2137 2138 template <> void InstARM32Ldrex::emit(const Cfg *Func) const { 2139 if (!BuildDefs::dump()) 2140 return; 2141 Ostream &Str = Func->getContext()->getStrEmit(); 2142 assert(getSrcSize() == 1); 2143 assert(getDest()->hasReg()); 2144 Variable *Dest = getDest(); 2145 Type DestTy = Dest->getType(); 2146 assert(isScalarIntegerType(DestTy)); 2147 const char *WidthString = getWidthString(DestTy); 2148 Str << "\t" << Opcode << WidthString << getPredicate() << "\t"; 2149 getDest()->emit(Func); 2150 Str << ", "; 2151 getSrc(0)->emit(Func); 2152 } 2153 2154 template <> void InstARM32Ldrex::emitIAS(const Cfg *Func) const { 2155 assert(getSrcSize() == 1); 2156 assert(getDest()->hasReg()); 2157 Variable *Dest = getDest(); 2158 assert(isScalarIntegerType(Dest->getType())); 2159 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2160 Asm->ldrex(Dest, getSrc(0), getPredicate(), Func->getTarget()); 2161 if (Asm->needsTextFixup()) 2162 emitUsingTextFixup(Func); 2163 } 2164 2165 template <InstARM32::InstKindARM32 K> 2166 void InstARM32TwoAddrGPR<K>::emitIAS(const Cfg *Func) const { 2167 emitUsingTextFixup(Func); 2168 } 2169 2170 template <InstARM32::InstKindARM32 K, bool Nws> 2171 void InstARM32UnaryopGPR<K, Nws>::emitIAS(const Cfg *Func) const { 2172 emitUsingTextFixup(Func); 2173 } 2174 2175 template <> void InstARM32Rbit::emitIAS(const Cfg *Func) const { 2176 assert(getSrcSize() == 1); 2177 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2178 Asm->rbit(getDest(), getSrc(0), getPredicate()); 2179 if (Asm->needsTextFixup()) 2180 emitUsingTextFixup(Func); 2181 } 2182 2183 template <> void InstARM32Rev::emitIAS(const Cfg *Func) const { 2184 assert(getSrcSize() == 1); 2185 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2186 Asm->rev(getDest(), getSrc(0), getPredicate()); 2187 if (Asm->needsTextFixup()) 2188 emitUsingTextFixup(Func); 2189 } 2190 2191 template <> void InstARM32Movw::emit(const Cfg *Func) const { 2192 if (!BuildDefs::dump()) 2193 return; 2194 Ostream &Str = Func->getContext()->getStrEmit(); 2195 assert(getSrcSize() == 1); 2196 Str << "\t" << Opcode << getPredicate() << "\t"; 2197 getDest()->emit(Func); 2198 Str << ", "; 2199 auto *Src0 = llvm::cast<Constant>(getSrc(0)); 2200 if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src0)) { 2201 Str << "#:lower16:"; 2202 CR->emitWithoutPrefix(Func->getTarget()); 2203 if (getFlags().getUseNonsfi()) { 2204 Str << " - ."; 2205 } 2206 } else { 2207 Src0->emit(Func); 2208 } 2209 } 2210 2211 template <> void InstARM32Movw::emitIAS(const Cfg *Func) const { 2212 assert(getSrcSize() == 1); 2213 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2214 Asm->movw(getDest(), getSrc(0), getPredicate()); 2215 if (Asm->needsTextFixup()) 2216 emitUsingTextFixup(Func); 2217 } 2218 2219 template <> void InstARM32Movt::emit(const Cfg *Func) const { 2220 if (!BuildDefs::dump()) 2221 return; 2222 Ostream &Str = Func->getContext()->getStrEmit(); 2223 assert(getSrcSize() == 2); 2224 Variable *Dest = getDest(); 2225 auto *Src1 = llvm::cast<Constant>(getSrc(1)); 2226 Str << "\t" << Opcode << getPredicate() << "\t"; 2227 Dest->emit(Func); 2228 Str << ", "; 2229 if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src1)) { 2230 Str << "#:upper16:"; 2231 CR->emitWithoutPrefix(Func->getTarget()); 2232 if (getFlags().getUseNonsfi()) { 2233 Str << " - ."; 2234 } 2235 } else { 2236 Src1->emit(Func); 2237 } 2238 } 2239 2240 template <> void InstARM32Movt::emitIAS(const Cfg *Func) const { 2241 assert(getSrcSize() == 2); 2242 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2243 Asm->movt(getDest(), getSrc(1), getPredicate()); 2244 if (Asm->needsTextFixup()) 2245 emitUsingTextFixup(Func); 2246 } 2247 2248 template <> void InstARM32Clz::emitIAS(const Cfg *Func) const { 2249 assert(getSrcSize() == 1); 2250 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2251 Asm->clz(getDest(), getSrc(0), getPredicate()); 2252 if (Asm->needsTextFixup()) 2253 emitUsingTextFixup(Func); 2254 } 2255 2256 template <> void InstARM32Mvn::emitIAS(const Cfg *Func) const { 2257 assert(getSrcSize() == 1); 2258 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2259 Asm->mvn(getDest(), getSrc(0), getPredicate()); 2260 if (Asm->needsTextFixup()) 2261 emitUsingTextFixup(Func); 2262 } 2263 2264 template <> void InstARM32Sxt::emitIAS(const Cfg *Func) const { 2265 assert(getSrcSize() == 1); 2266 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2267 Asm->sxt(getDest(), getSrc(0), getPredicate()); 2268 if (Asm->needsTextFixup()) 2269 emitUsingTextFixup(Func); 2270 } 2271 2272 template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const { 2273 assert(getSrcSize() == 1); 2274 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2275 Asm->uxt(getDest(), getSrc(0), getPredicate()); 2276 if (Asm->needsTextFixup()) 2277 emitUsingTextFixup(Func); 2278 } 2279 2280 template <InstARM32::InstKindARM32 K> 2281 void InstARM32UnaryopFP<K>::emitIAS(const Cfg *Func) const { 2282 emitUsingTextFixup(Func); 2283 } 2284 2285 template <InstARM32::InstKindARM32 K> 2286 void InstARM32UnaryopSignAwareFP<K>::emitIAS(const Cfg *Func) const { 2287 InstARM32::emitUsingTextFixup(Func); 2288 } 2289 2290 template <> void InstARM32Vsqrt::emitIAS(const Cfg *Func) const { 2291 assert(getSrcSize() == 1); 2292 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2293 const Operand *Dest = getDest(); 2294 switch (Dest->getType()) { 2295 case IceType_f32: 2296 Asm->vsqrts(Dest, getSrc(0), getPredicate()); 2297 break; 2298 case IceType_f64: 2299 Asm->vsqrtd(Dest, getSrc(0), getPredicate()); 2300 break; 2301 default: 2302 llvm::report_fatal_error("Vsqrt of non-floating type"); 2303 } 2304 if (Asm->needsTextFixup()) 2305 emitUsingTextFixup(Func); 2306 } 2307 2308 const char *InstARM32Pop::getGPROpcode() const { return "pop"; } 2309 2310 const char *InstARM32Pop::getSRegOpcode() const { return "vpop"; } 2311 2312 Variable *InstARM32Pop::getStackReg(SizeT Index) const { return Dests[Index]; } 2313 2314 SizeT InstARM32Pop::getNumStackRegs() const { return Dests.size(); } 2315 2316 void InstARM32Pop::emitSingleGPR(const Cfg *Func, const EmitForm Form, 2317 const Variable *Reg) const { 2318 switch (Form) { 2319 case Emit_Text: 2320 emitGPRsAsText(Func); 2321 return; 2322 case Emit_Binary: 2323 Func->getAssembler<ARM32::AssemblerARM32>()->pop(Reg, CondARM32::AL); 2324 return; 2325 } 2326 } 2327 2328 void InstARM32Pop::emitMultipleGPRs(const Cfg *Func, const EmitForm Form, 2329 IValueT Registers) const { 2330 switch (Form) { 2331 case Emit_Text: 2332 emitGPRsAsText(Func); 2333 return; 2334 case Emit_Binary: 2335 Func->getAssembler<ARM32::AssemblerARM32>()->popList(Registers, 2336 CondARM32::AL); 2337 return; 2338 } 2339 } 2340 2341 void InstARM32Pop::emitSRegs(const Cfg *Func, const EmitForm Form, 2342 const Variable *BaseReg, SizeT RegCount) const { 2343 switch (Form) { 2344 case Emit_Text: 2345 emitSRegsAsText(Func, BaseReg, RegCount); 2346 return; 2347 case Emit_Binary: 2348 Func->getAssembler<ARM32::AssemblerARM32>()->vpop(BaseReg, RegCount, 2349 CondARM32::AL); 2350 return; 2351 } 2352 } 2353 2354 const char *InstARM32Push::getGPROpcode() const { return "push"; } 2355 2356 const char *InstARM32Push::getSRegOpcode() const { return "vpush"; } 2357 2358 Variable *InstARM32Push::getStackReg(SizeT Index) const { 2359 return llvm::cast<Variable>(getSrc(Index)); 2360 } 2361 2362 SizeT InstARM32Push::getNumStackRegs() const { return getSrcSize(); } 2363 2364 void InstARM32Push::emitSingleGPR(const Cfg *Func, const EmitForm Form, 2365 const Variable *Reg) const { 2366 switch (Form) { 2367 case Emit_Text: 2368 emitGPRsAsText(Func); 2369 return; 2370 case Emit_Binary: 2371 Func->getAssembler<ARM32::AssemblerARM32>()->push(Reg, CondARM32::AL); 2372 return; 2373 } 2374 } 2375 2376 void InstARM32Push::emitMultipleGPRs(const Cfg *Func, const EmitForm Form, 2377 IValueT Registers) const { 2378 switch (Form) { 2379 case Emit_Text: 2380 emitGPRsAsText(Func); 2381 return; 2382 case Emit_Binary: 2383 Func->getAssembler<ARM32::AssemblerARM32>()->pushList(Registers, 2384 CondARM32::AL); 2385 return; 2386 } 2387 } 2388 2389 void InstARM32Push::emitSRegs(const Cfg *Func, const EmitForm Form, 2390 const Variable *BaseReg, SizeT RegCount) const { 2391 switch (Form) { 2392 case Emit_Text: 2393 emitSRegsAsText(Func, BaseReg, RegCount); 2394 return; 2395 case Emit_Binary: 2396 Func->getAssembler<ARM32::AssemblerARM32>()->vpush(BaseReg, RegCount, 2397 CondARM32::AL); 2398 return; 2399 } 2400 } 2401 2402 void InstARM32Ret::emit(const Cfg *Func) const { 2403 if (!BuildDefs::dump()) 2404 return; 2405 assert(getSrcSize() > 0); 2406 auto *LR = llvm::cast<Variable>(getSrc(0)); 2407 assert(LR->hasReg()); 2408 assert(LR->getRegNum() == RegARM32::Reg_lr); 2409 Ostream &Str = Func->getContext()->getStrEmit(); 2410 Str << "\t" 2411 "bx" 2412 "\t"; 2413 LR->emit(Func); 2414 } 2415 2416 void InstARM32Ret::emitIAS(const Cfg *Func) const { 2417 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2418 Asm->bx(RegARM32::Encoded_Reg_lr); 2419 if (Asm->needsTextFixup()) 2420 emitUsingTextFixup(Func); 2421 } 2422 2423 void InstARM32Ret::dump(const Cfg *Func) const { 2424 if (!BuildDefs::dump()) 2425 return; 2426 Ostream &Str = Func->getContext()->getStrDump(); 2427 Type Ty = (getSrcSize() == 1 ? IceType_void : getSrc(0)->getType()); 2428 Str << "ret." << Ty << " "; 2429 dumpSources(Func); 2430 } 2431 2432 void InstARM32Str::emit(const Cfg *Func) const { 2433 if (!BuildDefs::dump()) 2434 return; 2435 Ostream &Str = Func->getContext()->getStrEmit(); 2436 assert(getSrcSize() == 2); 2437 Type Ty = getSrc(0)->getType(); 2438 const bool IsVectorStore = isVectorType(Ty); 2439 const bool IsScalarFloat = isScalarFloatingType(Ty); 2440 const char *Opcode = 2441 IsVectorStore ? "vst1" : (IsScalarFloat ? "vstr" : "str"); 2442 Str << "\t" << Opcode; 2443 const bool IsVInst = IsVectorStore || IsScalarFloat; 2444 if (IsVInst) { 2445 Str << getPredicate() << getWidthString(Ty); 2446 } else { 2447 Str << getWidthString(Ty) << getPredicate(); 2448 } 2449 if (IsVectorStore) 2450 Str << "." << getVecElmtBitsize(Ty); 2451 Str << "\t"; 2452 getSrc(0)->emit(Func); 2453 Str << ", "; 2454 getSrc(1)->emit(Func); 2455 } 2456 2457 void InstARM32Str::emitIAS(const Cfg *Func) const { 2458 assert(getSrcSize() == 2); 2459 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2460 const Operand *Src0 = getSrc(0); 2461 const Operand *Src1 = getSrc(1); 2462 Type Ty = Src0->getType(); 2463 switch (Ty) { 2464 default: 2465 llvm::report_fatal_error("Str on unknown type: " + typeStdString(Ty)); 2466 case IceType_i1: 2467 case IceType_i8: 2468 case IceType_i16: 2469 case IceType_i32: 2470 case IceType_i64: 2471 Asm->str(Src0, Src1, getPredicate(), Func->getTarget()); 2472 break; 2473 case IceType_f32: 2474 Asm->vstrs(Src0, Src1, getPredicate(), Func->getTarget()); 2475 break; 2476 case IceType_f64: 2477 Asm->vstrd(Src0, Src1, getPredicate(), Func->getTarget()); 2478 break; 2479 case IceType_v16i8: 2480 case IceType_v8i16: 2481 case IceType_v4i32: 2482 case IceType_v4f32: 2483 case IceType_v16i1: 2484 case IceType_v8i1: 2485 case IceType_v4i1: 2486 Asm->vst1qr(getVecElmtBitsize(Ty), Src0, Src1, Func->getTarget()); 2487 break; 2488 } 2489 } 2490 2491 void InstARM32Str::dump(const Cfg *Func) const { 2492 if (!BuildDefs::dump()) 2493 return; 2494 Ostream &Str = Func->getContext()->getStrDump(); 2495 Type Ty = getSrc(0)->getType(); 2496 dumpOpcodePred(Str, "str", Ty); 2497 Str << " "; 2498 getSrc(1)->dump(Func); 2499 Str << ", "; 2500 getSrc(0)->dump(Func); 2501 } 2502 2503 void InstARM32Strex::emit(const Cfg *Func) const { 2504 if (!BuildDefs::dump()) 2505 return; 2506 assert(getSrcSize() == 2); 2507 Type Ty = getSrc(0)->getType(); 2508 assert(isScalarIntegerType(Ty)); 2509 Variable *Dest = getDest(); 2510 Ostream &Str = Func->getContext()->getStrEmit(); 2511 static constexpr char Opcode[] = "strex"; 2512 const char *WidthString = getWidthString(Ty); 2513 Str << "\t" << Opcode << WidthString << getPredicate() << "\t"; 2514 Dest->emit(Func); 2515 Str << ", "; 2516 emitSources(Func); 2517 } 2518 2519 void InstARM32Strex::emitIAS(const Cfg *Func) const { 2520 assert(getSrcSize() == 2); 2521 const Operand *Src0 = getSrc(0); 2522 assert(isScalarIntegerType(Src0->getType())); 2523 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2524 Asm->strex(Dest, Src0, getSrc(1), getPredicate(), Func->getTarget()); 2525 if (Asm->needsTextFixup()) 2526 emitUsingTextFixup(Func); 2527 } 2528 2529 void InstARM32Strex::dump(const Cfg *Func) const { 2530 if (!BuildDefs::dump()) 2531 return; 2532 Ostream &Str = Func->getContext()->getStrDump(); 2533 Variable *Dest = getDest(); 2534 Dest->dump(Func); 2535 Str << " = "; 2536 Type Ty = getSrc(0)->getType(); 2537 dumpOpcodePred(Str, "strex", Ty); 2538 Str << " "; 2539 getSrc(1)->dump(Func); 2540 Str << ", "; 2541 getSrc(0)->dump(Func); 2542 } 2543 2544 void InstARM32Trap::emit(const Cfg *Func) const { 2545 if (!BuildDefs::dump()) 2546 return; 2547 Ostream &Str = Func->getContext()->getStrEmit(); 2548 assert(getSrcSize() == 0); 2549 // There isn't a mnemonic for the special NaCl Trap encoding, so dump 2550 // the raw bytes. 2551 Str << "\t.long 0x"; 2552 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2553 for (uint8_t I : Asm->getNonExecBundlePadding()) { 2554 Str.write_hex(I); 2555 } 2556 } 2557 2558 void InstARM32Trap::emitIAS(const Cfg *Func) const { 2559 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2560 Asm->trap(); 2561 assert(!Asm->needsTextFixup()); 2562 } 2563 2564 void InstARM32Trap::dump(const Cfg *Func) const { 2565 if (!BuildDefs::dump()) 2566 return; 2567 Ostream &Str = Func->getContext()->getStrDump(); 2568 Str << "trap"; 2569 } 2570 2571 void InstARM32Umull::emit(const Cfg *Func) const { 2572 if (!BuildDefs::dump()) 2573 return; 2574 Ostream &Str = Func->getContext()->getStrEmit(); 2575 assert(getSrcSize() == 2); 2576 assert(getDest()->hasReg()); 2577 Str << "\t" 2578 "umull" << getPredicate() << "\t"; 2579 getDest()->emit(Func); 2580 Str << ", "; 2581 DestHi->emit(Func); 2582 Str << ", "; 2583 getSrc(0)->emit(Func); 2584 Str << ", "; 2585 getSrc(1)->emit(Func); 2586 } 2587 2588 void InstARM32Umull::emitIAS(const Cfg *Func) const { 2589 assert(getSrcSize() == 2); 2590 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2591 Asm->umull(getDest(), DestHi, getSrc(0), getSrc(1), getPredicate()); 2592 if (Asm->needsTextFixup()) 2593 emitUsingTextFixup(Func); 2594 } 2595 2596 void InstARM32Umull::dump(const Cfg *Func) const { 2597 if (!BuildDefs::dump()) 2598 return; 2599 Ostream &Str = Func->getContext()->getStrDump(); 2600 dumpDest(Func); 2601 Str << " = "; 2602 dumpOpcodePred(Str, "umull", getDest()->getType()); 2603 Str << " "; 2604 dumpSources(Func); 2605 } 2606 2607 namespace { 2608 const char *vcvtVariantSuffix(const InstARM32Vcvt::VcvtVariant Variant) { 2609 switch (Variant) { 2610 case InstARM32Vcvt::S2si: 2611 return ".s32.f32"; 2612 case InstARM32Vcvt::S2ui: 2613 return ".u32.f32"; 2614 case InstARM32Vcvt::Si2s: 2615 return ".f32.s32"; 2616 case InstARM32Vcvt::Ui2s: 2617 return ".f32.u32"; 2618 case InstARM32Vcvt::D2si: 2619 return ".s32.f64"; 2620 case InstARM32Vcvt::D2ui: 2621 return ".u32.f64"; 2622 case InstARM32Vcvt::Si2d: 2623 return ".f64.s32"; 2624 case InstARM32Vcvt::Ui2d: 2625 return ".f64.u32"; 2626 case InstARM32Vcvt::S2d: 2627 return ".f64.f32"; 2628 case InstARM32Vcvt::D2s: 2629 return ".f32.f64"; 2630 case InstARM32Vcvt::Vs2si: 2631 return ".s32.f32"; 2632 case InstARM32Vcvt::Vs2ui: 2633 return ".u32.f32"; 2634 case InstARM32Vcvt::Vsi2s: 2635 return ".f32.s32"; 2636 case InstARM32Vcvt::Vui2s: 2637 return ".f32.u32"; 2638 } 2639 llvm::report_fatal_error("Invalid VcvtVariant enum."); 2640 } 2641 } // end of anonymous namespace 2642 2643 void InstARM32Vcvt::emit(const Cfg *Func) const { 2644 if (!BuildDefs::dump()) 2645 return; 2646 Ostream &Str = Func->getContext()->getStrEmit(); 2647 assert(getSrcSize() == 1); 2648 assert(getDest()->hasReg()); 2649 Str << "\t" 2650 "vcvt" << getPredicate() << vcvtVariantSuffix(Variant) << "\t"; 2651 getDest()->emit(Func); 2652 Str << ", "; 2653 getSrc(0)->emit(Func); 2654 } 2655 2656 void InstARM32Vcvt::emitIAS(const Cfg *Func) const { 2657 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2658 switch (Variant) { 2659 case S2si: 2660 Asm->vcvtis(getDest(), getSrc(0), getPredicate()); 2661 break; 2662 case S2ui: 2663 Asm->vcvtus(getDest(), getSrc(0), getPredicate()); 2664 break; 2665 case Si2s: 2666 Asm->vcvtsi(getDest(), getSrc(0), getPredicate()); 2667 break; 2668 case Ui2s: 2669 Asm->vcvtsu(getDest(), getSrc(0), getPredicate()); 2670 break; 2671 case D2si: 2672 Asm->vcvtid(getDest(), getSrc(0), getPredicate()); 2673 break; 2674 case D2ui: 2675 Asm->vcvtud(getDest(), getSrc(0), getPredicate()); 2676 break; 2677 case Si2d: 2678 Asm->vcvtdi(getDest(), getSrc(0), getPredicate()); 2679 break; 2680 case Ui2d: 2681 Asm->vcvtdu(getDest(), getSrc(0), getPredicate()); 2682 break; 2683 case S2d: 2684 Asm->vcvtds(getDest(), getSrc(0), getPredicate()); 2685 break; 2686 case D2s: 2687 Asm->vcvtsd(getDest(), getSrc(0), getPredicate()); 2688 break; 2689 case Vs2si: 2690 Asm->vcvtqsi(getDest(), getSrc(0)); 2691 break; 2692 case Vs2ui: 2693 Asm->vcvtqsu(getDest(), getSrc(0)); 2694 break; 2695 case Vsi2s: 2696 Asm->vcvtqis(getDest(), getSrc(0)); 2697 break; 2698 case Vui2s: 2699 Asm->vcvtqus(getDest(), getSrc(0)); 2700 break; 2701 } 2702 assert(!Asm->needsTextFixup()); 2703 } 2704 2705 void InstARM32Vcvt::dump(const Cfg *Func) const { 2706 if (!BuildDefs::dump()) 2707 return; 2708 Ostream &Str = Func->getContext()->getStrDump(); 2709 dumpDest(Func); 2710 Str << " = " 2711 << "vcvt" << getPredicate() << vcvtVariantSuffix(Variant) << " "; 2712 dumpSources(Func); 2713 } 2714 2715 void InstARM32Vcmp::emit(const Cfg *Func) const { 2716 if (!BuildDefs::dump()) 2717 return; 2718 Ostream &Str = Func->getContext()->getStrEmit(); 2719 assert(getSrcSize() == 2); 2720 Str << "\t" 2721 "vcmp" << getPredicate() << getFpWidthString(getSrc(0)->getType()) 2722 << "\t"; 2723 getSrc(0)->emit(Func); 2724 Str << ", "; 2725 getSrc(1)->emit(Func); 2726 } 2727 2728 void InstARM32Vcmp::emitIAS(const Cfg *Func) const { 2729 assert(getSrcSize() == 2); 2730 const Operand *Src0 = getSrc(0); 2731 const Type Ty = Src0->getType(); 2732 const Operand *Src1 = getSrc(1); 2733 const CondARM32::Cond Cond = getPredicate(); 2734 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2735 if (llvm::isa<OperandARM32FlexFpZero>(Src1)) { 2736 switch (Ty) { 2737 case IceType_f32: 2738 Asm->vcmpsz(Src0, Cond); 2739 break; 2740 case IceType_f64: 2741 Asm->vcmpdz(Src0, Cond); 2742 break; 2743 default: 2744 llvm::report_fatal_error("Vcvt on non floating value"); 2745 } 2746 } else { 2747 switch (Ty) { 2748 case IceType_f32: 2749 Asm->vcmps(Src0, Src1, Cond); 2750 break; 2751 case IceType_f64: 2752 Asm->vcmpd(Src0, Src1, Cond); 2753 break; 2754 default: 2755 llvm::report_fatal_error("Vcvt on non floating value"); 2756 } 2757 } 2758 assert(!Asm->needsTextFixup()); 2759 } 2760 2761 void InstARM32Vcmp::dump(const Cfg *Func) const { 2762 if (!BuildDefs::dump()) 2763 return; 2764 Ostream &Str = Func->getContext()->getStrDump(); 2765 Str << "vcmp" << getPredicate() << getFpWidthString(getSrc(0)->getType()); 2766 dumpSources(Func); 2767 } 2768 2769 void InstARM32Vmrs::emit(const Cfg *Func) const { 2770 if (!BuildDefs::dump()) 2771 return; 2772 Ostream &Str = Func->getContext()->getStrEmit(); 2773 assert(getSrcSize() == 0); 2774 Str << "\t" 2775 "vmrs" << getPredicate() << "\t" 2776 "APSR_nzcv" 2777 ", " 2778 "FPSCR"; 2779 } 2780 2781 void InstARM32Vmrs::emitIAS(const Cfg *Func) const { 2782 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2783 Asm->vmrsAPSR_nzcv(getPredicate()); 2784 assert(!Asm->needsTextFixup()); 2785 } 2786 2787 void InstARM32Vmrs::dump(const Cfg *Func) const { 2788 if (!BuildDefs::dump()) 2789 return; 2790 Ostream &Str = Func->getContext()->getStrDump(); 2791 Str << "APSR{n,z,v,c} = vmrs" << getPredicate() << "\t" 2792 "FPSCR{n,z,c,v}"; 2793 } 2794 2795 void InstARM32Vabs::emit(const Cfg *Func) const { 2796 if (!BuildDefs::dump()) 2797 return; 2798 Ostream &Str = Func->getContext()->getStrEmit(); 2799 assert(getSrcSize() == 1); 2800 Str << "\t" 2801 "vabs" << getPredicate() << getFpWidthString(getSrc(0)->getType()) 2802 << "\t"; 2803 getDest()->emit(Func); 2804 Str << ", "; 2805 getSrc(0)->emit(Func); 2806 } 2807 2808 void InstARM32Vabs::emitIAS(const Cfg *Func) const { 2809 assert(getSrcSize() == 1); 2810 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2811 const Variable *Dest = getDest(); 2812 switch (Dest->getType()) { 2813 default: 2814 llvm::report_fatal_error("fabs not defined on type " + 2815 typeStdString(Dest->getType())); 2816 case IceType_f32: 2817 Asm->vabss(Dest, getSrc(0), getPredicate()); 2818 break; 2819 case IceType_f64: 2820 Asm->vabsd(Dest, getSrc(0), getPredicate()); 2821 break; 2822 case IceType_v4f32: 2823 assert(CondARM32::isUnconditional(getPredicate()) && 2824 "fabs must be unconditional"); 2825 Asm->vabsq(Dest, getSrc(0)); 2826 } 2827 assert(!Asm->needsTextFixup()); 2828 } 2829 2830 void InstARM32Vabs::dump(const Cfg *Func) const { 2831 if (!BuildDefs::dump()) 2832 return; 2833 Ostream &Str = Func->getContext()->getStrDump(); 2834 dumpDest(Func); 2835 Str << " = vabs" << getPredicate() << getFpWidthString(getSrc(0)->getType()); 2836 } 2837 2838 void InstARM32Dmb::emit(const Cfg *Func) const { 2839 if (!BuildDefs::dump()) 2840 return; 2841 Ostream &Str = Func->getContext()->getStrEmit(); 2842 assert(getSrcSize() == 0); 2843 Str << "\t" 2844 "dmb" 2845 "\t" 2846 "sy"; 2847 } 2848 2849 void InstARM32Dmb::emitIAS(const Cfg *Func) const { 2850 assert(getSrcSize() == 0); 2851 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2852 constexpr ARM32::IValueT SyOption = 0xF; // i.e. 1111 2853 Asm->dmb(SyOption); 2854 if (Asm->needsTextFixup()) 2855 emitUsingTextFixup(Func); 2856 } 2857 2858 void InstARM32Dmb::dump(const Cfg *Func) const { 2859 if (!BuildDefs::dump()) 2860 return; 2861 Func->getContext()->getStrDump() << "dmb\t" 2862 "sy"; 2863 } 2864 2865 void InstARM32Nop::emit(const Cfg *Func) const { 2866 if (!BuildDefs::dump()) 2867 return; 2868 assert(getSrcSize() == 0); 2869 Func->getContext()->getStrEmit() << "\t" 2870 << "nop"; 2871 } 2872 2873 void InstARM32Nop::emitIAS(const Cfg *Func) const { 2874 assert(getSrcSize() == 0); 2875 Func->getAssembler<ARM32::AssemblerARM32>()->nop(); 2876 } 2877 2878 void InstARM32Nop::dump(const Cfg *Func) const { 2879 if (!BuildDefs::dump()) 2880 return; 2881 assert(getSrcSize() == 0); 2882 Func->getContext()->getStrDump() << "nop"; 2883 } 2884 2885 void OperandARM32Mem::emit(const Cfg *Func) const { 2886 if (!BuildDefs::dump()) 2887 return; 2888 Ostream &Str = Func->getContext()->getStrEmit(); 2889 Str << "["; 2890 getBase()->emit(Func); 2891 switch (getAddrMode()) { 2892 case PostIndex: 2893 case NegPostIndex: 2894 Str << "]"; 2895 break; 2896 default: 2897 break; 2898 } 2899 if (isRegReg()) { 2900 Str << ", "; 2901 if (isNegAddrMode()) { 2902 Str << "-"; 2903 } 2904 getIndex()->emit(Func); 2905 if (getShiftOp() != kNoShift) { 2906 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #" 2907 << getShiftAmt(); 2908 } 2909 } else { 2910 ConstantInteger32 *Offset = getOffset(); 2911 if (Offset && Offset->getValue() != 0) { 2912 Str << ", "; 2913 Offset->emit(Func); 2914 } 2915 } 2916 switch (getAddrMode()) { 2917 case Offset: 2918 case NegOffset: 2919 Str << "]"; 2920 break; 2921 case PreIndex: 2922 case NegPreIndex: 2923 Str << "]!"; 2924 break; 2925 case PostIndex: 2926 case NegPostIndex: 2927 // Brace is already closed off. 2928 break; 2929 } 2930 } 2931 2932 void OperandARM32Mem::dump(const Cfg *Func, Ostream &Str) const { 2933 if (!BuildDefs::dump()) 2934 return; 2935 Str << "["; 2936 if (Func) 2937 getBase()->dump(Func); 2938 else 2939 getBase()->dump(Str); 2940 Str << ", "; 2941 if (isRegReg()) { 2942 if (isNegAddrMode()) { 2943 Str << "-"; 2944 } 2945 if (Func) 2946 getIndex()->dump(Func); 2947 else 2948 getIndex()->dump(Str); 2949 if (getShiftOp() != kNoShift) { 2950 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #" 2951 << getShiftAmt(); 2952 } 2953 } else { 2954 getOffset()->dump(Func, Str); 2955 } 2956 Str << "] AddrMode==" << getAddrMode(); 2957 } 2958 2959 void OperandARM32ShAmtImm::emit(const Cfg *Func) const { ShAmt->emit(Func); } 2960 2961 void OperandARM32ShAmtImm::dump(const Cfg *, Ostream &Str) const { 2962 ShAmt->dump(Str); 2963 } 2964 2965 OperandARM32FlexImm *OperandARM32FlexImm::create(Cfg *Func, Type Ty, 2966 uint32_t Imm, 2967 uint32_t RotateAmt) { 2968 // The assembler wants the smallest rotation. Rotate if needed. Note: Imm is 2969 // an 8-bit value. 2970 assert(Utils::IsUint(8, Imm) && 2971 "Flex immediates can only be defined on 8-bit immediates"); 2972 while ((Imm & 0x03) == 0 && RotateAmt > 0) { 2973 --RotateAmt; 2974 Imm = Imm >> 2; 2975 } 2976 return new (Func->allocate<OperandARM32FlexImm>()) 2977 OperandARM32FlexImm(Func, Ty, Imm, RotateAmt); 2978 } 2979 2980 void OperandARM32FlexImm::emit(const Cfg *Func) const { 2981 if (!BuildDefs::dump()) 2982 return; 2983 Ostream &Str = Func->getContext()->getStrEmit(); 2984 uint32_t Imm = getImm(); 2985 uint32_t RotateAmt = getRotateAmt(); 2986 Str << "#" << Utils::rotateRight32(Imm, 2 * RotateAmt); 2987 } 2988 2989 void OperandARM32FlexImm::dump(const Cfg * /* Func */, Ostream &Str) const { 2990 if (!BuildDefs::dump()) 2991 return; 2992 uint32_t Imm = getImm(); 2993 uint32_t RotateAmt = getRotateAmt(); 2994 Str << "#(" << Imm << " ror 2*" << RotateAmt << ")"; 2995 } 2996 2997 namespace { 2998 static constexpr uint32_t a = 0x80; 2999 static constexpr uint32_t b = 0x40; 3000 static constexpr uint32_t cdefgh = 0x3F; 3001 static constexpr uint32_t AllowedBits = a | b | cdefgh; 3002 static_assert(AllowedBits == 0xFF, 3003 "Invalid mask for f32/f64 constant rematerialization."); 3004 3005 // There's no loss in always returning the modified immediate as float. 3006 // TODO(jpp): returning a double causes problems when outputting the constants 3007 // for filetype=asm. Why? 3008 float materializeFloatImmediate(uint32_t ModifiedImm) { 3009 const uint32_t Ret = ((ModifiedImm & a) ? 0x80000000 : 0) | 3010 ((ModifiedImm & b) ? 0x3E000000 : 0x40000000) | 3011 ((ModifiedImm & cdefgh) << 19); 3012 return Utils::bitCopy<float>(Ret); 3013 } 3014 3015 } // end of anonymous namespace 3016 3017 void OperandARM32FlexFpImm::emit(const Cfg *Func) const { 3018 if (!BuildDefs::dump()) 3019 return; 3020 Ostream &Str = Func->getContext()->getStrEmit(); 3021 switch (Ty) { 3022 default: 3023 llvm::report_fatal_error("Invalid flex fp imm type."); 3024 case IceType_f64: 3025 case IceType_f32: 3026 Str << "#" << materializeFloatImmediate(ModifiedImm) 3027 << " @ Modified: " << ModifiedImm; 3028 break; 3029 } 3030 } 3031 3032 void OperandARM32FlexFpImm::dump(const Cfg * /*Func*/, Ostream &Str) const { 3033 if (!BuildDefs::dump()) 3034 return; 3035 Str << "#" << materializeFloatImmediate(ModifiedImm) << getFpWidthString(Ty); 3036 } 3037 3038 void OperandARM32FlexFpZero::emit(const Cfg *Func) const { 3039 if (!BuildDefs::dump()) 3040 return; 3041 Ostream &Str = Func->getContext()->getStrEmit(); 3042 switch (Ty) { 3043 default: 3044 llvm::report_fatal_error("Invalid flex fp imm type."); 3045 case IceType_f64: 3046 case IceType_f32: 3047 Str << "#0.0"; 3048 } 3049 } 3050 3051 void OperandARM32FlexFpZero::dump(const Cfg * /*Func*/, Ostream &Str) const { 3052 if (!BuildDefs::dump()) 3053 return; 3054 Str << "#0.0" << getFpWidthString(Ty); 3055 } 3056 3057 void OperandARM32FlexReg::emit(const Cfg *Func) const { 3058 if (!BuildDefs::dump()) 3059 return; 3060 Ostream &Str = Func->getContext()->getStrEmit(); 3061 getReg()->emit(Func); 3062 if (getShiftOp() != kNoShift) { 3063 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; 3064 getShiftAmt()->emit(Func); 3065 } 3066 } 3067 3068 void OperandARM32FlexReg::dump(const Cfg *Func, Ostream &Str) const { 3069 if (!BuildDefs::dump()) 3070 return; 3071 Variable *Reg = getReg(); 3072 if (Func) 3073 Reg->dump(Func); 3074 else 3075 Reg->dump(Str); 3076 if (getShiftOp() != kNoShift) { 3077 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; 3078 if (Func) 3079 getShiftAmt()->dump(Func); 3080 else 3081 getShiftAmt()->dump(Str); 3082 } 3083 } 3084 3085 // Force instantition of template classes 3086 template class InstARM32ThreeAddrGPR<InstARM32::Adc>; 3087 template class InstARM32ThreeAddrGPR<InstARM32::Add>; 3088 template class InstARM32ThreeAddrGPR<InstARM32::And>; 3089 template class InstARM32ThreeAddrGPR<InstARM32::Asr>; 3090 template class InstARM32ThreeAddrGPR<InstARM32::Bic>; 3091 template class InstARM32ThreeAddrGPR<InstARM32::Eor>; 3092 template class InstARM32ThreeAddrGPR<InstARM32::Lsl>; 3093 template class InstARM32ThreeAddrGPR<InstARM32::Lsr>; 3094 template class InstARM32ThreeAddrGPR<InstARM32::Mul>; 3095 template class InstARM32ThreeAddrGPR<InstARM32::Orr>; 3096 template class InstARM32ThreeAddrGPR<InstARM32::Rsb>; 3097 template class InstARM32ThreeAddrGPR<InstARM32::Rsc>; 3098 template class InstARM32ThreeAddrGPR<InstARM32::Sbc>; 3099 template class InstARM32ThreeAddrGPR<InstARM32::Sdiv>; 3100 template class InstARM32ThreeAddrGPR<InstARM32::Sub>; 3101 template class InstARM32ThreeAddrGPR<InstARM32::Udiv>; 3102 3103 template class InstARM32ThreeAddrFP<InstARM32::Vadd>; 3104 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vcge>; 3105 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vcgt>; 3106 template class InstARM32ThreeAddrFP<InstARM32::Vdiv>; 3107 template class InstARM32ThreeAddrFP<InstARM32::Veor>; 3108 template class InstARM32FourAddrFP<InstARM32::Vmla>; 3109 template class InstARM32FourAddrFP<InstARM32::Vmls>; 3110 template class InstARM32ThreeAddrFP<InstARM32::Vmul>; 3111 template class InstARM32UnaryopSignAwareFP<InstARM32::Vneg>; 3112 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vshl>; 3113 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vshr>; 3114 template class InstARM32ThreeAddrFP<InstARM32::Vsub>; 3115 3116 template class InstARM32LoadBase<InstARM32::Ldr>; 3117 template class InstARM32LoadBase<InstARM32::Ldrex>; 3118 3119 template class InstARM32TwoAddrGPR<InstARM32::Movt>; 3120 3121 template class InstARM32UnaryopGPR<InstARM32::Movw, false>; 3122 template class InstARM32UnaryopGPR<InstARM32::Clz, false>; 3123 template class InstARM32UnaryopGPR<InstARM32::Mvn, false>; 3124 template class InstARM32UnaryopGPR<InstARM32::Rbit, false>; 3125 template class InstARM32UnaryopGPR<InstARM32::Rev, false>; 3126 template class InstARM32UnaryopGPR<InstARM32::Sxt, true>; 3127 template class InstARM32UnaryopGPR<InstARM32::Uxt, true>; 3128 template class InstARM32UnaryopFP<InstARM32::Vsqrt>; 3129 3130 template class InstARM32FourAddrGPR<InstARM32::Mla>; 3131 template class InstARM32FourAddrGPR<InstARM32::Mls>; 3132 3133 template class InstARM32CmpLike<InstARM32::Cmn>; 3134 template class InstARM32CmpLike<InstARM32::Cmp>; 3135 template class InstARM32CmpLike<InstARM32::Tst>; 3136 3137 } // end of namespace ARM32 3138 } // end of namespace Ice 3139