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 InstARM32Vmovl::emitIAS(const Cfg *Func) const { 907 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 908 const Variable *Dest = getDest(); 909 switch (Dest->getType()) { 910 default: 911 llvm::report_fatal_error("Vmovlq not defined on type " + 912 typeStdString(Dest->getType())); 913 case IceType_v4i1: 914 case IceType_v8i1: 915 case IceType_v16i1: 916 case IceType_v16i8: 917 case IceType_v8i16: 918 case IceType_v4i32: 919 case IceType_v4f32: { 920 Asm->vmovlq(Dest, getSrc(0), getSrc(1)); 921 } break; 922 } 923 } 924 925 template <> void InstARM32Vmovh::emitIAS(const Cfg *Func) const { 926 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 927 const Variable *Dest = getDest(); 928 switch (Dest->getType()) { 929 default: 930 llvm::report_fatal_error("Vmovhq not defined on type " + 931 typeStdString(Dest->getType())); 932 case IceType_v4i1: 933 case IceType_v8i1: 934 case IceType_v16i1: 935 case IceType_v16i8: 936 case IceType_v8i16: 937 case IceType_v4i32: 938 case IceType_v4f32: { 939 Asm->vmovhq(Dest, getSrc(0), getSrc(1)); 940 } break; 941 } 942 } 943 944 template <> void InstARM32Vmovhl::emitIAS(const Cfg *Func) const { 945 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 946 const Variable *Dest = getDest(); 947 switch (Dest->getType()) { 948 default: 949 llvm::report_fatal_error("Vmovhlq not defined on type " + 950 typeStdString(Dest->getType())); 951 case IceType_v4i1: 952 case IceType_v8i1: 953 case IceType_v16i1: 954 case IceType_v16i8: 955 case IceType_v8i16: 956 case IceType_v4i32: 957 case IceType_v4f32: { 958 Asm->vmovhlq(Dest, getSrc(0), getSrc(1)); 959 } break; 960 } 961 } 962 963 template <> void InstARM32Vmovlh::emitIAS(const Cfg *Func) const { 964 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 965 const Variable *Dest = getDest(); 966 switch (Dest->getType()) { 967 default: 968 llvm::report_fatal_error("Vmovlhq not defined on type " + 969 typeStdString(Dest->getType())); 970 case IceType_v4i1: 971 case IceType_v8i1: 972 case IceType_v16i1: 973 case IceType_v16i8: 974 case IceType_v8i16: 975 case IceType_v4i32: 976 case IceType_v4f32: { 977 Asm->vmovlhq(Dest, getSrc(0), getSrc(1)); 978 } break; 979 } 980 } 981 982 template <> void InstARM32Vneg::emitIAS(const Cfg *Func) const { 983 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 984 const Variable *Dest = getDest(); 985 const Type DestTy = Dest->getType(); 986 switch (Dest->getType()) { 987 default: 988 llvm::report_fatal_error("Vneg not defined on type " + 989 typeStdString(Dest->getType())); 990 case IceType_v4i1: 991 case IceType_v8i1: 992 case IceType_v16i1: 993 case IceType_v16i8: 994 case IceType_v8i16: 995 case IceType_v4i32: 996 case IceType_v4f32: { 997 const Type ElmtTy = typeElementType(DestTy); 998 Asm->vnegqs(ElmtTy, Dest, getSrc(0)); 999 } break; 1000 } 1001 } 1002 1003 template <> void InstARM32Vorr::emitIAS(const Cfg *Func) const { 1004 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1005 const Variable *Dest = getDest(); 1006 switch (Dest->getType()) { 1007 default: 1008 llvm::report_fatal_error("Vorr not defined on type " + 1009 typeStdString(Dest->getType())); 1010 case IceType_v4i1: 1011 case IceType_v8i1: 1012 case IceType_v16i1: 1013 case IceType_v16i8: 1014 case IceType_v8i16: 1015 case IceType_v4i32: 1016 Asm->vorrq(Dest, getSrc(0), getSrc(1)); 1017 } 1018 assert(!Asm->needsTextFixup()); 1019 } 1020 1021 template <> void InstARM32Vshl::emitIAS(const Cfg *Func) const { 1022 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1023 const Variable *Dest = getDest(); 1024 const Type DestTy = Dest->getType(); 1025 switch (DestTy) { 1026 default: 1027 llvm::report_fatal_error("Vshl not defined on type " + 1028 typeStdString(Dest->getType())); 1029 // TODO(jpp): handle i1 vectors in terms of element count instead of element 1030 // type. 1031 case IceType_v4i1: 1032 case IceType_v8i1: 1033 case IceType_v16i1: 1034 case IceType_v16i8: 1035 case IceType_v8i16: 1036 case IceType_v4i32: { 1037 const Type ElmtTy = typeElementType(DestTy); 1038 assert(Sign != InstARM32::FS_None); 1039 switch (Sign) { 1040 case InstARM32::FS_None: // defaults to unsigned. 1041 case InstARM32::FS_Unsigned: 1042 if (const auto *Imm6 = llvm::dyn_cast<ConstantInteger32>(getSrc(1))) { 1043 Asm->vshlqc(ElmtTy, Dest, getSrc(0), Imm6); 1044 } else { 1045 Asm->vshlqu(ElmtTy, Dest, getSrc(0), getSrc(1)); 1046 } 1047 break; 1048 case InstARM32::FS_Signed: 1049 if (const auto *Imm6 = llvm::dyn_cast<ConstantInteger32>(getSrc(1))) { 1050 Asm->vshlqc(ElmtTy, Dest, getSrc(0), Imm6); 1051 } else { 1052 Asm->vshlqi(ElmtTy, Dest, getSrc(0), getSrc(1)); 1053 } 1054 break; 1055 } 1056 } break; 1057 } 1058 } 1059 1060 template <> void InstARM32Vshr::emitIAS(const Cfg *Func) const { 1061 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1062 const Variable *Dest = getDest(); 1063 const Type DestTy = Dest->getType(); 1064 switch (DestTy) { 1065 default: 1066 llvm::report_fatal_error("Vshr not defined on type " + 1067 typeStdString(Dest->getType())); 1068 // TODO(jpp): handle i1 vectors in terms of element count instead of element 1069 // type. 1070 case IceType_v4i1: 1071 case IceType_v8i1: 1072 case IceType_v16i1: 1073 case IceType_v16i8: 1074 case IceType_v8i16: 1075 case IceType_v4i32: { 1076 const Type ElmtTy = typeElementType(DestTy); 1077 const auto *Imm6 = llvm::cast<ConstantInteger32>(getSrc(1)); 1078 switch (Sign) { 1079 case InstARM32::FS_Signed: 1080 case InstARM32::FS_Unsigned: 1081 Asm->vshrqc(ElmtTy, Dest, getSrc(0), Imm6, Sign); 1082 break; 1083 default: 1084 assert(false && "Vshr requires signedness specification."); 1085 } 1086 } break; 1087 } 1088 } 1089 1090 template <> void InstARM32Vsub::emitIAS(const Cfg *Func) const { 1091 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1092 const Variable *Dest = getDest(); 1093 Type DestTy = Dest->getType(); 1094 switch (DestTy) { 1095 default: 1096 llvm::report_fatal_error("Vsub not defined on type " + 1097 typeStdString(DestTy)); 1098 case IceType_v16i8: 1099 case IceType_v8i16: 1100 case IceType_v4i32: 1101 Asm->vsubqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1)); 1102 break; 1103 case IceType_v4f32: 1104 Asm->vsubqf(Dest, getSrc(0), getSrc(1)); 1105 break; 1106 case IceType_f32: 1107 Asm->vsubs(getDest(), getSrc(0), getSrc(1), CondARM32::AL); 1108 break; 1109 case IceType_f64: 1110 Asm->vsubd(getDest(), getSrc(0), getSrc(1), CondARM32::AL); 1111 break; 1112 } 1113 assert(!Asm->needsTextFixup()); 1114 } 1115 1116 template <> void InstARM32Vqadd::emitIAS(const Cfg *Func) const { 1117 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1118 const Variable *Dest = getDest(); 1119 Type DestTy = Dest->getType(); 1120 switch (DestTy) { 1121 default: 1122 llvm::report_fatal_error("Vqadd not defined on type " + 1123 typeStdString(DestTy)); 1124 case IceType_v16i8: 1125 case IceType_v8i16: 1126 case IceType_v4i32: 1127 switch (Sign) { 1128 case InstARM32::FS_None: // defaults to unsigned. 1129 case InstARM32::FS_Unsigned: 1130 Asm->vqaddqu(typeElementType(DestTy), Dest, getSrc(0), getSrc(1)); 1131 break; 1132 case InstARM32::FS_Signed: 1133 Asm->vqaddqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1)); 1134 break; 1135 } 1136 break; 1137 } 1138 assert(!Asm->needsTextFixup()); 1139 } 1140 1141 template <> void InstARM32Vqsub::emitIAS(const Cfg *Func) const { 1142 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1143 const Variable *Dest = getDest(); 1144 Type DestTy = Dest->getType(); 1145 switch (DestTy) { 1146 default: 1147 llvm::report_fatal_error("Vqsub not defined on type " + 1148 typeStdString(DestTy)); 1149 case IceType_v16i8: 1150 case IceType_v8i16: 1151 case IceType_v4i32: 1152 switch (Sign) { 1153 case InstARM32::FS_None: // defaults to unsigned. 1154 case InstARM32::FS_Unsigned: 1155 Asm->vqsubqu(typeElementType(DestTy), Dest, getSrc(0), getSrc(1)); 1156 break; 1157 case InstARM32::FS_Signed: 1158 Asm->vqsubqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1)); 1159 break; 1160 } 1161 break; 1162 } 1163 assert(!Asm->needsTextFixup()); 1164 } 1165 1166 template <> void InstARM32Vqmovn2::emitIAS(const Cfg *Func) const { 1167 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1168 const Operand *Src0 = getSrc(0); 1169 const Operand *Src1 = getSrc(1); 1170 Type SrcTy = Src0->getType(); 1171 Type DestTy = Dest->getType(); 1172 bool Unsigned = true; 1173 bool Saturating = true; 1174 switch (SrcTy) { 1175 default: 1176 llvm::report_fatal_error("Vqmovn2 not defined on type " + 1177 typeStdString(SrcTy)); 1178 case IceType_v8i16: 1179 case IceType_v4i32: 1180 switch (Sign) { 1181 case InstARM32::FS_None: 1182 Unsigned = true; 1183 Saturating = false; 1184 Asm->vqmovn2(typeElementType(DestTy), Dest, Src0, Src1, Unsigned, 1185 Saturating); 1186 break; 1187 case InstARM32::FS_Unsigned: 1188 Unsigned = true; 1189 Saturating = true; 1190 Asm->vqmovn2(typeElementType(DestTy), Dest, Src0, Src1, Unsigned, 1191 Saturating); 1192 break; 1193 case InstARM32::FS_Signed: 1194 Unsigned = false; 1195 Saturating = true; 1196 Asm->vqmovn2(typeElementType(DestTy), Dest, Src0, Src1, Unsigned, 1197 Saturating); 1198 break; 1199 } 1200 break; 1201 } 1202 assert(!Asm->needsTextFixup()); 1203 } 1204 1205 template <> void InstARM32Vmulh::emitIAS(const Cfg *Func) const { 1206 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1207 const Operand *Src0 = getSrc(0); 1208 Type SrcTy = Src0->getType(); 1209 bool Unsigned = true; 1210 switch (SrcTy) { 1211 default: 1212 llvm::report_fatal_error("Vmulh not defined on type " + 1213 typeStdString(SrcTy)); 1214 case IceType_v8i16: 1215 switch (Sign) { 1216 case InstARM32::FS_None: // defaults to unsigned. 1217 case InstARM32::FS_Unsigned: 1218 Unsigned = true; 1219 Asm->vmulh(typeElementType(SrcTy), Dest, getSrc(0), getSrc(1), Unsigned); 1220 break; 1221 case InstARM32::FS_Signed: 1222 Unsigned = false; 1223 Asm->vmulh(typeElementType(SrcTy), Dest, getSrc(0), getSrc(1), Unsigned); 1224 break; 1225 } 1226 break; 1227 } 1228 assert(!Asm->needsTextFixup()); 1229 } 1230 1231 template <> void InstARM32Vmlap::emitIAS(const Cfg *Func) const { 1232 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1233 const Operand *Src0 = getSrc(0); 1234 const Operand *Src1 = getSrc(1); 1235 Type SrcTy = Src0->getType(); 1236 switch (SrcTy) { 1237 default: 1238 llvm::report_fatal_error("Vmlap not defined on type " + 1239 typeStdString(SrcTy)); 1240 case IceType_v8i16: 1241 Asm->vmlap(typeElementType(SrcTy), Dest, Src0, Src1); 1242 break; 1243 } 1244 assert(!Asm->needsTextFixup()); 1245 } 1246 1247 template <> void InstARM32Vzip::emitIAS(const Cfg *Func) const { 1248 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1249 const Operand *Src0 = getSrc(0); 1250 const Operand *Src1 = getSrc(1); 1251 Type DestTy = Dest->getType(); 1252 Asm->vzip(typeElementType(DestTy), Dest, Src0, Src1); 1253 assert(!Asm->needsTextFixup()); 1254 } 1255 1256 template <> void InstARM32Vmul::emitIAS(const Cfg *Func) const { 1257 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1258 const Variable *Dest = getDest(); 1259 const Type DestTy = Dest->getType(); 1260 switch (DestTy) { 1261 default: 1262 llvm::report_fatal_error("Vmul not defined on type " + 1263 typeStdString(DestTy)); 1264 1265 case IceType_v16i8: 1266 case IceType_v8i16: 1267 case IceType_v4i32: 1268 Asm->vmulqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1)); 1269 break; 1270 case IceType_v4f32: 1271 Asm->vmulqf(Dest, getSrc(0), getSrc(1)); 1272 break; 1273 case IceType_f32: 1274 Asm->vmuls(Dest, getSrc(0), getSrc(1), CondARM32::AL); 1275 break; 1276 case IceType_f64: 1277 Asm->vmuld(Dest, getSrc(0), getSrc(1), CondARM32::AL); 1278 break; 1279 } 1280 } 1281 1282 InstARM32Call::InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget) 1283 : InstARM32(Func, InstARM32::Call, 1, Dest) { 1284 HasSideEffects = true; 1285 addSource(CallTarget); 1286 } 1287 1288 InstARM32Label::InstARM32Label(Cfg *Func, TargetARM32 *Target) 1289 : InstARM32(Func, InstARM32::Label, 0, nullptr), 1290 Number(Target->makeNextLabelNumber()) { 1291 if (BuildDefs::dump()) { 1292 Name = GlobalString::createWithString( 1293 Func->getContext(), 1294 ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number)); 1295 } else { 1296 Name = GlobalString::createWithoutString(Func->getContext()); 1297 } 1298 } 1299 1300 namespace { 1301 // Requirements for Push/Pop: 1302 // 1) All the Variables have the same type; 1303 // 2) All the variables have registers assigned to them. 1304 void validatePushOrPopRegisterListOrDie(const VarList &RegList) { 1305 Type PreviousTy = IceType_void; 1306 for (Variable *Reg : RegList) { 1307 if (PreviousTy != IceType_void && Reg->getType() != PreviousTy) { 1308 llvm::report_fatal_error("Type mismatch when popping/pushing " 1309 "registers."); 1310 } 1311 1312 if (!Reg->hasReg()) { 1313 llvm::report_fatal_error("Push/pop operand does not have a register " 1314 "assigned to it."); 1315 } 1316 1317 PreviousTy = Reg->getType(); 1318 } 1319 } 1320 } // end of anonymous namespace 1321 1322 void InstARM32RegisterStackOp::emit(const Cfg *Func) const { 1323 if (!BuildDefs::dump()) 1324 return; 1325 emitUsingForm(Func, Emit_Text); 1326 } 1327 1328 void InstARM32RegisterStackOp::emitIAS(const Cfg *Func) const { 1329 emitUsingForm(Func, Emit_Binary); 1330 assert(!Func->getAssembler<ARM32::AssemblerARM32>()->needsTextFixup()); 1331 } 1332 1333 void InstARM32RegisterStackOp::dump(const Cfg *Func) const { 1334 if (!BuildDefs::dump()) 1335 return; 1336 Ostream &Str = Func->getContext()->getStrDump(); 1337 Str << getDumpOpcode() << " "; 1338 SizeT NumRegs = getNumStackRegs(); 1339 for (SizeT I = 0; I < NumRegs; ++I) { 1340 if (I > 0) 1341 Str << ", "; 1342 getStackReg(I)->dump(Func); 1343 } 1344 } 1345 1346 void InstARM32RegisterStackOp::emitGPRsAsText(const Cfg *Func) const { 1347 if (!BuildDefs::dump()) 1348 return; 1349 Ostream &Str = Func->getContext()->getStrEmit(); 1350 Str << "\t" << getGPROpcode() << "\t{"; 1351 getStackReg(0)->emit(Func); 1352 const SizeT NumRegs = getNumStackRegs(); 1353 for (SizeT i = 1; i < NumRegs; ++i) { 1354 Str << ", "; 1355 getStackReg(i)->emit(Func); 1356 } 1357 Str << "}"; 1358 } 1359 1360 void InstARM32RegisterStackOp::emitSRegsAsText(const Cfg *Func, 1361 const Variable *BaseReg, 1362 SizeT RegCount) const { 1363 if (!BuildDefs::dump()) 1364 return; 1365 Ostream &Str = Func->getContext()->getStrEmit(); 1366 Str << "\t" << getSRegOpcode() << "\t{"; 1367 bool IsFirst = true; 1368 const auto Base = BaseReg->getRegNum(); 1369 for (SizeT i = 0; i < RegCount; ++i) { 1370 if (IsFirst) 1371 IsFirst = false; 1372 else 1373 Str << ", "; 1374 Str << RegARM32::getRegName(RegNumT::fixme(Base + i)); 1375 } 1376 Str << "}"; 1377 } 1378 1379 void InstARM32RegisterStackOp::emitSRegsOp(const Cfg *Func, EmitForm Form, 1380 const Variable *BaseReg, 1381 SizeT RegCount, 1382 SizeT InstIndex) const { 1383 if (Form == Emit_Text && BuildDefs::dump() && InstIndex > 0) { 1384 startNextInst(Func); 1385 Func->getContext()->getStrEmit() << "\n"; 1386 } 1387 emitSRegs(Func, Form, BaseReg, RegCount); 1388 } 1389 1390 namespace { 1391 1392 bool isAssignedConsecutiveRegisters(const Variable *Before, 1393 const Variable *After) { 1394 assert(Before->hasReg()); 1395 assert(After->hasReg()); 1396 return RegNumT::fixme(Before->getRegNum() + 1) == After->getRegNum(); 1397 } 1398 1399 } // end of anonymous namespace 1400 1401 void InstARM32RegisterStackOp::emitUsingForm(const Cfg *Func, 1402 const EmitForm Form) const { 1403 SizeT NumRegs = getNumStackRegs(); 1404 assert(NumRegs); 1405 1406 const auto *Reg = llvm::cast<Variable>(getStackReg(0)); 1407 if (isScalarIntegerType(Reg->getType())) { 1408 // Push/pop GPR registers. 1409 SizeT IntegerCount = 0; 1410 ARM32::IValueT GPRegisters = 0; 1411 const Variable *LastDest = nullptr; 1412 for (SizeT i = 0; i < NumRegs; ++i) { 1413 const Variable *Var = getStackReg(i); 1414 assert(Var->hasReg() && "stack op only applies to registers"); 1415 const RegARM32::GPRRegister Reg = 1416 RegARM32::getEncodedGPR(Var->getRegNum()); 1417 LastDest = Var; 1418 GPRegisters |= (1 << Reg); 1419 ++IntegerCount; 1420 } 1421 if (IntegerCount == 1) { 1422 emitSingleGPR(Func, Form, LastDest); 1423 } else { 1424 emitMultipleGPRs(Func, Form, GPRegisters); 1425 } 1426 return; 1427 } 1428 1429 // Push/pop floating point registers. Divide into a list of instructions, 1430 // defined on consecutive register ranges. Then generate the corresponding 1431 // instructions. 1432 1433 // Typical max number of registers ranges pushed/popd is no more than 5. 1434 llvm::SmallVector<std::pair<const Variable *, SizeT>, 5> InstData; 1435 const Variable *BaseReg = nullptr; 1436 SizeT RegCount = 0; 1437 for (SizeT i = 0; i < NumRegs; ++i) { 1438 const Variable *NextReg = getStackReg(i); 1439 assert(NextReg->hasReg()); 1440 if (BaseReg == nullptr) { 1441 BaseReg = NextReg; 1442 RegCount = 1; 1443 } else if (RegCount < VpushVpopMaxConsecRegs && 1444 isAssignedConsecutiveRegisters(Reg, NextReg)) { 1445 ++RegCount; 1446 } else { 1447 InstData.emplace_back(BaseReg, RegCount); 1448 BaseReg = NextReg; 1449 RegCount = 1; 1450 } 1451 Reg = NextReg; 1452 } 1453 if (RegCount) { 1454 InstData.emplace_back(BaseReg, RegCount); 1455 } 1456 SizeT InstCount = 0; 1457 if (llvm::isa<InstARM32Push>(*this)) { 1458 for (const auto &Pair : InstData) 1459 emitSRegsOp(Func, Form, Pair.first, Pair.second, InstCount++); 1460 return; 1461 } 1462 assert(llvm::isa<InstARM32Pop>(*this)); 1463 for (const auto &Pair : reverse_range(InstData)) 1464 emitSRegsOp(Func, Form, Pair.first, Pair.second, InstCount++); 1465 } 1466 1467 InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests) 1468 : InstARM32RegisterStackOp(Func, InstARM32::Pop, 0, nullptr), Dests(Dests) { 1469 // Track modifications to Dests separately via FakeDefs. Also, a pop 1470 // instruction affects the stack pointer and so it should not be allowed to 1471 // be automatically dead-code eliminated. This is automatic since we leave 1472 // the Dest as nullptr. 1473 validatePushOrPopRegisterListOrDie(Dests); 1474 } 1475 1476 InstARM32Push::InstARM32Push(Cfg *Func, const VarList &Srcs) 1477 : InstARM32RegisterStackOp(Func, InstARM32::Push, Srcs.size(), nullptr) { 1478 validatePushOrPopRegisterListOrDie(Srcs); 1479 for (Variable *Source : Srcs) { 1480 addSource(Source); 1481 } 1482 } 1483 1484 InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source) 1485 : InstARM32(Func, InstARM32::Ret, Source ? 2 : 1, nullptr) { 1486 addSource(LR); 1487 if (Source) 1488 addSource(Source); 1489 } 1490 1491 InstARM32Str::InstARM32Str(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, 1492 CondARM32::Cond Predicate) 1493 : InstARM32Pred(Func, InstARM32::Str, 2, nullptr, Predicate) { 1494 addSource(Value); 1495 addSource(Mem); 1496 } 1497 1498 InstARM32Strex::InstARM32Strex(Cfg *Func, Variable *Dest, Variable *Value, 1499 OperandARM32Mem *Mem, CondARM32::Cond Predicate) 1500 : InstARM32Pred(Func, InstARM32::Strex, 2, Dest, Predicate) { 1501 addSource(Value); 1502 addSource(Mem); 1503 } 1504 1505 InstARM32Vstr1::InstARM32Vstr1(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, 1506 CondARM32::Cond Predicate, SizeT Size) 1507 : InstARM32Pred(Func, InstARM32::Vstr1, 2, nullptr, Predicate) { 1508 addSource(Value); 1509 addSource(Mem); 1510 this->Size = Size; 1511 } 1512 1513 InstARM32Vdup::InstARM32Vdup(Cfg *Func, Variable *Dest, Variable *Src, 1514 IValueT Idx) 1515 : InstARM32Pred(Func, InstARM32::Vdup, 1, Dest, CondARM32::AL), Idx(Idx) { 1516 addSource(Src); 1517 } 1518 1519 InstARM32Trap::InstARM32Trap(Cfg *Func) 1520 : InstARM32(Func, InstARM32::Trap, 0, nullptr) {} 1521 1522 InstARM32Umull::InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, 1523 Variable *Src0, Variable *Src1, 1524 CondARM32::Cond Predicate) 1525 : InstARM32Pred(Func, InstARM32::Umull, 2, DestLo, Predicate), 1526 // DestHi is expected to have a FakeDef inserted by the lowering code. 1527 DestHi(DestHi) { 1528 addSource(Src0); 1529 addSource(Src1); 1530 } 1531 1532 InstARM32Vcvt::InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src, 1533 VcvtVariant Variant, CondARM32::Cond Predicate) 1534 : InstARM32Pred(Func, InstARM32::Vcvt, 1, Dest, Predicate), 1535 Variant(Variant) { 1536 addSource(Src); 1537 } 1538 1539 InstARM32Mov::InstARM32Mov(Cfg *Func, Variable *Dest, Operand *Src, 1540 CondARM32::Cond Predicate) 1541 : InstARM32Pred(Func, InstARM32::Mov, 2, Dest, Predicate) { 1542 auto *Dest64 = llvm::dyn_cast<Variable64On32>(Dest); 1543 auto *Src64 = llvm::dyn_cast<Variable64On32>(Src); 1544 1545 assert(Dest64 == nullptr || Src64 == nullptr); 1546 1547 if (Dest64 != nullptr) { 1548 // this-> is needed below because there is a parameter named Dest. 1549 this->Dest = Dest64->getLo(); 1550 DestHi = Dest64->getHi(); 1551 } 1552 1553 if (Src64 == nullptr) { 1554 addSource(Src); 1555 } else { 1556 addSource(Src64->getLo()); 1557 addSource(Src64->getHi()); 1558 } 1559 } 1560 1561 namespace { 1562 1563 // These next two functions find the D register that maps to the half of the Q 1564 // register that this instruction is accessing. 1565 Register getDRegister(const Variable *Src, uint32_t Index) { 1566 assert(Src->hasReg()); 1567 const auto SrcReg = Src->getRegNum(); 1568 1569 const RegARM32::RegTableType &SrcEntry = RegARM32::RegTable[SrcReg]; 1570 assert(SrcEntry.IsVec128); 1571 1572 const uint32_t NumElements = typeNumElements(Src->getType()); 1573 1574 // This code assumes the Aliases list goes Q_n, S_2n, S_2n+1. The asserts in 1575 // the next two branches help to check that this is still true. 1576 if (Index < NumElements / 2) { 1577 // We have a Q register that's made up of two D registers. This assert is 1578 // to help ensure that we picked the right D register. 1579 // 1580 // TODO(jpp): find a way to do this that doesn't rely on ordering of the 1581 // alias list. 1582 assert(RegARM32::RegTable[SrcEntry.Aliases[1]].Encoding + 1 == 1583 RegARM32::RegTable[SrcEntry.Aliases[2]].Encoding); 1584 return static_cast<Register>(SrcEntry.Aliases[1]); 1585 } else { 1586 // We have a Q register that's made up of two D registers. This assert is 1587 // to help ensure that we picked the right D register. 1588 // 1589 // TODO(jpp): find a way to do this that doesn't rely on ordering of the 1590 // alias list. 1591 assert(RegARM32::RegTable[SrcEntry.Aliases[2]].Encoding - 1 == 1592 RegARM32::RegTable[SrcEntry.Aliases[1]].Encoding); 1593 return static_cast<Register>(SrcEntry.Aliases[2]); 1594 } 1595 } 1596 1597 uint32_t adjustDIndex(Type Ty, uint32_t DIndex) { 1598 // If Ty is a vector of i1, we may need to adjust DIndex. This is needed 1599 // because, e.g., the second i1 in a v4i1 is accessed with a 1600 // 1601 // vmov.s8 Qd[4], Rn 1602 switch (Ty) { 1603 case IceType_v4i1: 1604 return DIndex * 4; 1605 case IceType_v8i1: 1606 return DIndex * 2; 1607 case IceType_v16i1: 1608 return DIndex; 1609 default: 1610 return DIndex; 1611 } 1612 } 1613 1614 uint32_t getDIndex(Type Ty, uint32_t NumElements, uint32_t Index) { 1615 const uint32_t DIndex = 1616 (Index < NumElements / 2) ? Index : Index - (NumElements / 2); 1617 return adjustDIndex(Ty, DIndex); 1618 } 1619 1620 // For floating point values, we can insertelement or extractelement by moving 1621 // directly from an S register. This function finds the right one. 1622 Register getSRegister(const Variable *Src, uint32_t Index) { 1623 assert(Src->hasReg()); 1624 const auto SrcReg = Src->getRegNum(); 1625 1626 // For floating point values, we need to be allocated to Q0 - Q7, so we can 1627 // directly access the value we want as one of the S registers. 1628 assert(Src->getType() == IceType_v4f32); 1629 assert(SrcReg < RegARM32::Reg_q8); 1630 1631 // This part assumes the register alias list goes q0, d0, d1, s0, s1, s2, s3. 1632 assert(Index < 4); 1633 1634 // TODO(jpp): find a way to do this that doesn't rely on ordering of the alias 1635 // list. 1636 return static_cast<Register>(RegARM32::RegTable[SrcReg].Aliases[Index + 3]); 1637 } 1638 1639 } // end of anonymous namespace 1640 1641 void InstARM32Extract::emit(const Cfg *Func) const { 1642 Ostream &Str = Func->getContext()->getStrEmit(); 1643 const Type DestTy = getDest()->getType(); 1644 1645 const auto *Src = llvm::cast<Variable>(getSrc(0)); 1646 1647 if (isIntegerType(DestTy)) { 1648 Str << "\t" 1649 << "vmov" << getPredicate(); 1650 const uint32_t BitSize = typeWidthInBytes(DestTy) * CHAR_BIT; 1651 if (BitSize < 32) { 1652 Str << ".s" << BitSize; 1653 } else { 1654 Str << "." << BitSize; 1655 } 1656 Str << "\t"; 1657 getDest()->emit(Func); 1658 Str << ", "; 1659 1660 const Type SrcTy = Src->getType(); 1661 const size_t VectorSize = typeNumElements(SrcTy); 1662 1663 const Register SrcReg = getDRegister(Src, Index); 1664 1665 Str << RegARM32::RegTable[SrcReg].Name; 1666 Str << "[" << getDIndex(SrcTy, VectorSize, Index) << "]"; 1667 } else if (isFloatingType(DestTy)) { 1668 const Register SrcReg = getSRegister(Src, Index); 1669 1670 Str << "\t" 1671 << "vmov" << getPredicate() << ".f32" 1672 << "\t"; 1673 getDest()->emit(Func); 1674 Str << ", " << RegARM32::RegTable[SrcReg].Name; 1675 } else { 1676 assert(false && "Invalid extract type"); 1677 } 1678 } 1679 1680 void InstARM32Extract::emitIAS(const Cfg *Func) const { 1681 const Operand *Dest = getDest(); 1682 const Type DestTy = Dest->getType(); 1683 const Operand *Src = getSrc(0); 1684 const Type SrcTy = Src->getType(); 1685 assert(isVectorType(Src->getType())); 1686 assert(DestTy == typeElementType(Src->getType())); 1687 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1688 if (isIntegerType(DestTy)) { 1689 Asm->vmovrqi(Dest, Src, adjustDIndex(SrcTy, Index), getPredicate()); 1690 assert(!Asm->needsTextFixup()); 1691 return; 1692 } 1693 assert(isFloatingType(DestTy)); 1694 Asm->vmovsqi(Dest, Src, Index, getPredicate()); 1695 assert(!Asm->needsTextFixup()); 1696 } 1697 1698 namespace { 1699 Type insertionType(Type Ty) { 1700 assert(isVectorType(Ty)); 1701 switch (Ty) { 1702 case IceType_v4i1: 1703 return IceType_v4i32; 1704 case IceType_v8i1: 1705 return IceType_v8i16; 1706 case IceType_v16i1: 1707 return IceType_v16i8; 1708 default: 1709 return Ty; 1710 } 1711 } 1712 } // end of anonymous namespace 1713 1714 void InstARM32Insert::emit(const Cfg *Func) const { 1715 Ostream &Str = Func->getContext()->getStrEmit(); 1716 const Variable *Dest = getDest(); 1717 const auto *Src = llvm::cast<Variable>(getSrc(0)); 1718 const Type DestTy = insertionType(getDest()->getType()); 1719 assert(isVectorType(DestTy)); 1720 1721 if (isIntegerType(DestTy)) { 1722 Str << "\t" 1723 << "vmov" << getPredicate(); 1724 const size_t BitSize = typeWidthInBytes(typeElementType(DestTy)) * CHAR_BIT; 1725 Str << "." << BitSize << "\t"; 1726 1727 const size_t VectorSize = typeNumElements(DestTy); 1728 const Register DestReg = getDRegister(Dest, Index); 1729 const uint32_t Index = 1730 getDIndex(insertionType(DestTy), VectorSize, this->Index); 1731 Str << RegARM32::RegTable[DestReg].Name; 1732 Str << "[" << Index << "], "; 1733 Src->emit(Func); 1734 } else if (isFloatingType(DestTy)) { 1735 Str << "\t" 1736 << "vmov" << getPredicate() << ".f32" 1737 << "\t"; 1738 const Register DestReg = getSRegister(Dest, Index); 1739 Str << RegARM32::RegTable[DestReg].Name << ", "; 1740 Src->emit(Func); 1741 } else { 1742 assert(false && "Invalid insert type"); 1743 } 1744 } 1745 1746 void InstARM32Insert::emitIAS(const Cfg *Func) const { 1747 const Variable *Dest = getDest(); 1748 const auto *Src = llvm::cast<Variable>(getSrc(0)); 1749 const Type DestTy = insertionType(Dest->getType()); 1750 const Type SrcTy = typeElementType(DestTy); 1751 assert(SrcTy == Src->getType() || Src->getType() == IceType_i1); 1752 assert(isVectorType(DestTy)); 1753 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1754 if (isIntegerType(SrcTy)) { 1755 Asm->vmovqir(Dest->asType(Func, DestTy, Dest->getRegNum()), 1756 adjustDIndex(DestTy, Index), 1757 Src->asType(Func, SrcTy, Src->getRegNum()), getPredicate()); 1758 assert(!Asm->needsTextFixup()); 1759 return; 1760 } 1761 assert(isFloatingType(SrcTy)); 1762 Asm->vmovqis(Dest, Index, Src, getPredicate()); 1763 assert(!Asm->needsTextFixup()); 1764 } 1765 1766 template <InstARM32::InstKindARM32 K> 1767 void InstARM32CmpLike<K>::emitIAS(const Cfg *Func) const { 1768 emitUsingTextFixup(Func); 1769 } 1770 1771 template <> void InstARM32Cmn::emitIAS(const Cfg *Func) const { 1772 assert(getSrcSize() == 2); 1773 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1774 Asm->cmn(getSrc(0), getSrc(1), getPredicate()); 1775 if (Asm->needsTextFixup()) 1776 emitUsingTextFixup(Func); 1777 } 1778 1779 template <> void InstARM32Cmp::emitIAS(const Cfg *Func) const { 1780 assert(getSrcSize() == 2); 1781 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1782 Asm->cmp(getSrc(0), getSrc(1), getPredicate()); 1783 if (Asm->needsTextFixup()) 1784 emitUsingTextFixup(Func); 1785 } 1786 1787 template <> void InstARM32Tst::emitIAS(const Cfg *Func) const { 1788 assert(getSrcSize() == 2); 1789 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 1790 Asm->tst(getSrc(0), getSrc(1), getPredicate()); 1791 if (Asm->needsTextFixup()) 1792 emitUsingTextFixup(Func); 1793 } 1794 1795 InstARM32Dmb::InstARM32Dmb(Cfg *Func) 1796 : InstARM32Pred(Func, InstARM32::Dmb, 0, nullptr, CondARM32::AL) {} 1797 1798 InstARM32Nop::InstARM32Nop(Cfg *Func) 1799 : InstARM32Pred(Func, InstARM32::Nop, 0, nullptr, CondARM32::AL) {} 1800 1801 InstARM32Vcmp::InstARM32Vcmp(Cfg *Func, Variable *Src0, Operand *Src1, 1802 CondARM32::Cond Predicate) 1803 : InstARM32Pred(Func, InstARM32::Vcmp, 2, nullptr, Predicate) { 1804 HasSideEffects = true; 1805 addSource(Src0); 1806 addSource(Src1); 1807 } 1808 1809 InstARM32Vmrs::InstARM32Vmrs(Cfg *Func, CondARM32::Cond Predicate) 1810 : InstARM32Pred(Func, InstARM32::Vmrs, 0, nullptr, Predicate) { 1811 HasSideEffects = true; 1812 } 1813 1814 InstARM32Vabs::InstARM32Vabs(Cfg *Func, Variable *Dest, Variable *Src, 1815 CondARM32::Cond Predicate) 1816 : InstARM32Pred(Func, InstARM32::Vabs, 1, Dest, Predicate) { 1817 addSource(Src); 1818 } 1819 1820 // ======================== Dump routines ======================== // 1821 1822 // Two-addr ops 1823 template <> const char *InstARM32Movt::Opcode = "movt"; 1824 // Unary ops 1825 template <> const char *InstARM32Movw::Opcode = "movw"; 1826 template <> const char *InstARM32Clz::Opcode = "clz"; 1827 template <> const char *InstARM32Mvn::Opcode = "mvn"; 1828 template <> const char *InstARM32Rbit::Opcode = "rbit"; 1829 template <> const char *InstARM32Rev::Opcode = "rev"; 1830 template <> const char *InstARM32Sxt::Opcode = "sxt"; // still requires b/h 1831 template <> const char *InstARM32Uxt::Opcode = "uxt"; // still requires b/h 1832 // FP 1833 template <> const char *InstARM32Vsqrt::Opcode = "vsqrt"; 1834 // Mov-like ops 1835 template <> const char *InstARM32Ldr::Opcode = "ldr"; 1836 template <> const char *InstARM32Ldrex::Opcode = "ldrex"; 1837 template <> const char *InstARM32Vldr1d::Opcode = "vldr1d"; 1838 template <> const char *InstARM32Vldr1q::Opcode = "vldr1q"; 1839 // Three-addr ops 1840 template <> const char *InstARM32Adc::Opcode = "adc"; 1841 template <> const char *InstARM32Add::Opcode = "add"; 1842 template <> const char *InstARM32And::Opcode = "and"; 1843 template <> const char *InstARM32Asr::Opcode = "asr"; 1844 template <> const char *InstARM32Bic::Opcode = "bic"; 1845 template <> const char *InstARM32Eor::Opcode = "eor"; 1846 template <> const char *InstARM32Lsl::Opcode = "lsl"; 1847 template <> const char *InstARM32Lsr::Opcode = "lsr"; 1848 template <> const char *InstARM32Mul::Opcode = "mul"; 1849 template <> const char *InstARM32Orr::Opcode = "orr"; 1850 template <> const char *InstARM32Rsb::Opcode = "rsb"; 1851 template <> const char *InstARM32Rsc::Opcode = "rsc"; 1852 template <> const char *InstARM32Sbc::Opcode = "sbc"; 1853 template <> const char *InstARM32Sdiv::Opcode = "sdiv"; 1854 template <> const char *InstARM32Sub::Opcode = "sub"; 1855 template <> const char *InstARM32Udiv::Opcode = "udiv"; 1856 // FP 1857 template <> const char *InstARM32Vadd::Opcode = "vadd"; 1858 template <> const char *InstARM32Vand::Opcode = "vand"; 1859 template <> const char *InstARM32Vbsl::Opcode = "vbsl"; 1860 template <> const char *InstARM32Vceq::Opcode = "vceq"; 1861 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vcge>::Opcode = "vcge"; 1862 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vcgt>::Opcode = "vcgt"; 1863 template <> const char *InstARM32Vdiv::Opcode = "vdiv"; 1864 template <> const char *InstARM32Veor::Opcode = "veor"; 1865 template <> const char *InstARM32Vmla::Opcode = "vmla"; 1866 template <> const char *InstARM32Vmls::Opcode = "vmls"; 1867 template <> const char *InstARM32Vmul::Opcode = "vmul"; 1868 template <> const char *InstARM32Vmvn::Opcode = "vmvn"; 1869 template <> const char *InstARM32Vmovl::Opcode = "vmovl"; 1870 template <> const char *InstARM32Vmovh::Opcode = "vmovh"; 1871 template <> const char *InstARM32Vmovhl::Opcode = "vmovhl"; 1872 template <> const char *InstARM32Vmovlh::Opcode = "vmovlh"; 1873 template <> const char *InstARM32Vorr::Opcode = "vorr"; 1874 template <> const char *InstARM32UnaryopFP<InstARM32::Vneg>::Opcode = "vneg"; 1875 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vshl>::Opcode = "vshl"; 1876 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vshr>::Opcode = "vshr"; 1877 template <> const char *InstARM32Vsub::Opcode = "vsub"; 1878 template <> 1879 const char *InstARM32ThreeAddrFP<InstARM32::Vqadd>::Opcode = "vqadd"; 1880 template <> 1881 const char *InstARM32ThreeAddrFP<InstARM32::Vqsub>::Opcode = "vqsub"; 1882 template <> 1883 const char *InstARM32ThreeAddrFP<InstARM32::Vqmovn2>::Opcode = "vqmovn2"; 1884 template <> 1885 const char *InstARM32ThreeAddrFP<InstARM32::Vmulh>::Opcode = "vmulh"; 1886 template <> 1887 const char *InstARM32ThreeAddrFP<InstARM32::Vmlap>::Opcode = "vmlap"; 1888 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vzip>::Opcode = "vzip"; 1889 // Four-addr ops 1890 template <> const char *InstARM32Mla::Opcode = "mla"; 1891 template <> const char *InstARM32Mls::Opcode = "mls"; 1892 // Cmp-like ops 1893 template <> const char *InstARM32Cmn::Opcode = "cmn"; 1894 template <> const char *InstARM32Cmp::Opcode = "cmp"; 1895 template <> const char *InstARM32Tst::Opcode = "tst"; 1896 1897 void InstARM32::dump(const Cfg *Func) const { 1898 if (!BuildDefs::dump()) 1899 return; 1900 Ostream &Str = Func->getContext()->getStrDump(); 1901 Str << "[ARM32] "; 1902 Inst::dump(Func); 1903 } 1904 1905 void InstARM32Mov::emitMultiDestSingleSource(const Cfg *Func) const { 1906 if (!BuildDefs::dump()) 1907 return; 1908 Ostream &Str = Func->getContext()->getStrEmit(); 1909 Variable *DestLo = getDest(); 1910 Variable *DestHi = getDestHi(); 1911 auto *Src = llvm::cast<Variable>(getSrc(0)); 1912 1913 assert(DestHi->hasReg()); 1914 assert(DestLo->hasReg()); 1915 assert(Src->hasReg()); 1916 1917 Str << "\t" 1918 "vmov" << getPredicate() << "\t"; 1919 DestLo->emit(Func); 1920 Str << ", "; 1921 DestHi->emit(Func); 1922 Str << ", "; 1923 Src->emit(Func); 1924 } 1925 1926 void InstARM32Mov::emitSingleDestMultiSource(const Cfg *Func) const { 1927 if (!BuildDefs::dump()) 1928 return; 1929 Ostream &Str = Func->getContext()->getStrEmit(); 1930 Variable *Dest = getDest(); 1931 auto *SrcLo = llvm::cast<Variable>(getSrc(0)); 1932 auto *SrcHi = llvm::cast<Variable>(getSrc(1)); 1933 1934 assert(SrcHi->hasReg()); 1935 assert(SrcLo->hasReg()); 1936 assert(Dest->hasReg()); 1937 assert(getSrcSize() == 2); 1938 1939 Str << "\t" 1940 "vmov" << getPredicate() << "\t"; 1941 Dest->emit(Func); 1942 Str << ", "; 1943 SrcLo->emit(Func); 1944 Str << ", "; 1945 SrcHi->emit(Func); 1946 } 1947 1948 namespace { 1949 1950 bool isVariableWithoutRegister(const Operand *Op) { 1951 if (const auto *OpV = llvm::dyn_cast<Variable>(Op)) { 1952 return !OpV->hasReg(); 1953 } 1954 return false; 1955 } 1956 bool isMemoryAccess(Operand *Op) { 1957 return isVariableWithoutRegister(Op) || llvm::isa<OperandARM32Mem>(Op); 1958 } 1959 1960 bool isMoveBetweenCoreAndVFPRegisters(Variable *Dest, Operand *Src) { 1961 const Type DestTy = Dest->getType(); 1962 const Type SrcTy = Src->getType(); 1963 return !isVectorType(DestTy) && !isVectorType(SrcTy) && 1964 (isScalarIntegerType(DestTy) == isScalarFloatingType(SrcTy)); 1965 } 1966 1967 } // end of anonymous namespace 1968 1969 void InstARM32Mov::emitSingleDestSingleSource(const Cfg *Func) const { 1970 if (!BuildDefs::dump()) 1971 return; 1972 Ostream &Str = Func->getContext()->getStrEmit(); 1973 Variable *Dest = getDest(); 1974 1975 if (!Dest->hasReg()) { 1976 llvm::report_fatal_error("mov can't store."); 1977 } 1978 1979 Operand *Src0 = getSrc(0); 1980 if (isMemoryAccess(Src0)) { 1981 llvm::report_fatal_error("mov can't load."); 1982 } 1983 1984 Type Ty = Dest->getType(); 1985 const bool IsVector = isVectorType(Ty); 1986 const bool IsScalarFP = isScalarFloatingType(Ty); 1987 const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0); 1988 const bool IsVMove = (IsVector || IsScalarFP || CoreVFPMove); 1989 const char *Opcode = IsVMove ? "vmov" : "mov"; 1990 // when vmov{c}'ing, we need to emit a width string. Otherwise, the 1991 // assembler might be tempted to assume we want a vector vmov{c}, and that 1992 // is disallowed because ARM. 1993 const char *WidthString = !CoreVFPMove ? getFpWidthString(Ty) : ""; 1994 CondARM32::Cond Cond = getPredicate(); 1995 if (IsVector) 1996 assert(CondARM32::isUnconditional(Cond) && 1997 "Moves on vectors must be unconditional!"); 1998 Str << "\t" << Opcode; 1999 if (IsVMove) { 2000 Str << Cond << WidthString; 2001 } else { 2002 Str << WidthString << Cond; 2003 } 2004 Str << "\t"; 2005 Dest->emit(Func); 2006 Str << ", "; 2007 Src0->emit(Func); 2008 } 2009 2010 void InstARM32Mov::emit(const Cfg *Func) const { 2011 if (!BuildDefs::dump()) 2012 return; 2013 assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type."); 2014 if (isMultiDest()) { 2015 emitMultiDestSingleSource(Func); 2016 return; 2017 } 2018 2019 if (isMultiSource()) { 2020 emitSingleDestMultiSource(Func); 2021 return; 2022 } 2023 2024 emitSingleDestSingleSource(Func); 2025 } 2026 2027 void InstARM32Mov::emitIAS(const Cfg *Func) const { 2028 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2029 const Variable *Dest = getDest(); 2030 Operand *Src0 = getSrc(0); 2031 const CondARM32::Cond Cond = getPredicate(); 2032 if (!Dest->hasReg()) { 2033 llvm::report_fatal_error("mov can't store."); 2034 } 2035 if (isMemoryAccess(Src0)) { 2036 llvm::report_fatal_error("mov can't load."); 2037 } 2038 2039 assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type."); 2040 if (isMultiDest()) { 2041 Asm->vmovrrd(Dest, getDestHi(), Src0, Cond); 2042 return; 2043 } 2044 if (isMultiSource()) { 2045 Asm->vmovdrr(Dest, Src0, getSrc(1), Cond); 2046 return; 2047 } 2048 2049 const Type DestTy = Dest->getType(); 2050 const Type SrcTy = Src0->getType(); 2051 switch (DestTy) { 2052 default: 2053 break; // Error 2054 case IceType_i1: 2055 case IceType_i8: 2056 case IceType_i16: 2057 case IceType_i32: 2058 switch (SrcTy) { 2059 default: 2060 break; // Error 2061 case IceType_i1: 2062 case IceType_i8: 2063 case IceType_i16: 2064 case IceType_i32: 2065 case IceType_i64: 2066 Asm->mov(Dest, Src0, Cond); 2067 return; 2068 case IceType_f32: 2069 Asm->vmovrs(Dest, Src0, Cond); 2070 return; 2071 } 2072 break; // Error 2073 case IceType_i64: 2074 if (isScalarIntegerType(SrcTy)) { 2075 Asm->mov(Dest, Src0, Cond); 2076 return; 2077 } 2078 if (SrcTy == IceType_f64) { 2079 if (const auto *Var = llvm::dyn_cast<Variable>(Src0)) { 2080 Asm->vmovdd(Dest, Var, Cond); 2081 return; 2082 } 2083 if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) { 2084 Asm->vmovd(Dest, FpImm, Cond); 2085 return; 2086 } 2087 } 2088 break; // Error 2089 case IceType_f32: 2090 switch (SrcTy) { 2091 default: 2092 break; // Error 2093 case IceType_i1: 2094 case IceType_i8: 2095 case IceType_i16: 2096 case IceType_i32: 2097 return Asm->vmovsr(Dest, Src0, Cond); 2098 case IceType_f32: 2099 if (const auto *Var = llvm::dyn_cast<Variable>(Src0)) { 2100 Asm->vmovss(Dest, Var, Cond); 2101 return; 2102 } 2103 if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) { 2104 Asm->vmovs(Dest, FpImm, Cond); 2105 return; 2106 } 2107 break; // Error 2108 } 2109 break; // Error 2110 case IceType_f64: 2111 if (SrcTy == IceType_f64) { 2112 if (const auto *Var = llvm::dyn_cast<Variable>(Src0)) { 2113 Asm->vmovdd(Dest, Var, Cond); 2114 return; 2115 } 2116 if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) { 2117 Asm->vmovd(Dest, FpImm, Cond); 2118 return; 2119 } 2120 } 2121 break; // Error 2122 // TODO(jpp): Remove vectors of i1. 2123 case IceType_v4i1: 2124 case IceType_v8i1: 2125 case IceType_v16i1: 2126 case IceType_v16i8: 2127 case IceType_v8i16: 2128 case IceType_v4i32: 2129 case IceType_v4f32: 2130 assert(CondARM32::isUnconditional(Cond) && 2131 "Moves on vector must be unconditional!"); 2132 if (isVectorType(SrcTy)) { 2133 // Mov between different Src and Dest types is used for bitcasting 2134 // vectors. We still want to make sure SrcTy is a vector type. 2135 Asm->vorrq(Dest, Src0, Src0); 2136 return; 2137 } else if (const auto *C = llvm::dyn_cast<ConstantInteger32>(Src0)) { 2138 // Mov with constant argument, allowing the initializing all elements of 2139 // the vector. 2140 if (Asm->vmovqc(Dest, C)) 2141 return; 2142 } 2143 } 2144 llvm::report_fatal_error("Mov: don't know how to move " + 2145 typeStdString(SrcTy) + " to " + 2146 typeStdString(DestTy)); 2147 } 2148 2149 void InstARM32Mov::dump(const Cfg *Func) const { 2150 if (!BuildDefs::dump()) 2151 return; 2152 assert(getSrcSize() == 1 || getSrcSize() == 2); 2153 Ostream &Str = Func->getContext()->getStrDump(); 2154 Variable *Dest = getDest(); 2155 Variable *DestHi = getDestHi(); 2156 Dest->dump(Func); 2157 if (DestHi) { 2158 Str << ", "; 2159 DestHi->dump(Func); 2160 } 2161 2162 dumpOpcodePred(Str, " = mov", getDest()->getType()); 2163 Str << " "; 2164 2165 dumpSources(Func); 2166 } 2167 2168 void InstARM32Br::emit(const Cfg *Func) const { 2169 if (!BuildDefs::dump()) 2170 return; 2171 Ostream &Str = Func->getContext()->getStrEmit(); 2172 Str << "\t" 2173 "b" << getPredicate() << "\t"; 2174 if (Label) { 2175 Str << Label->getLabelName(); 2176 } else { 2177 if (isUnconditionalBranch()) { 2178 Str << getTargetFalse()->getAsmName(); 2179 } else { 2180 Str << getTargetTrue()->getAsmName(); 2181 if (getTargetFalse()) { 2182 startNextInst(Func); 2183 Str << "\n\t" 2184 << "b" 2185 << "\t" << getTargetFalse()->getAsmName(); 2186 } 2187 } 2188 } 2189 } 2190 2191 void InstARM32Br::emitIAS(const Cfg *Func) const { 2192 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2193 if (Label) { 2194 Asm->b(Asm->getOrCreateLocalLabel(Label->getNumber()), getPredicate()); 2195 } else if (isUnconditionalBranch()) { 2196 Asm->b(Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex()), 2197 getPredicate()); 2198 } else { 2199 Asm->b(Asm->getOrCreateCfgNodeLabel(getTargetTrue()->getIndex()), 2200 getPredicate()); 2201 if (const CfgNode *False = getTargetFalse()) 2202 Asm->b(Asm->getOrCreateCfgNodeLabel(False->getIndex()), CondARM32::AL); 2203 } 2204 if (Asm->needsTextFixup()) 2205 emitUsingTextFixup(Func); 2206 } 2207 2208 void InstARM32Br::dump(const Cfg *Func) const { 2209 if (!BuildDefs::dump()) 2210 return; 2211 Ostream &Str = Func->getContext()->getStrDump(); 2212 Str << "br "; 2213 2214 if (getPredicate() == CondARM32::AL) { 2215 if (Label) { 2216 Str << "label %" << Label->getLabelName(); 2217 } else { 2218 Str << "label %" << getTargetFalse()->getName(); 2219 } 2220 return; 2221 } 2222 2223 if (Label) { 2224 Str << getPredicate() << ", label %" << Label->getLabelName(); 2225 } else { 2226 Str << getPredicate() << ", label %" << getTargetTrue()->getName(); 2227 if (getTargetFalse()) { 2228 Str << ", label %" << getTargetFalse()->getName(); 2229 } 2230 } 2231 } 2232 2233 void InstARM32Call::emit(const Cfg *Func) const { 2234 if (!BuildDefs::dump()) 2235 return; 2236 Ostream &Str = Func->getContext()->getStrEmit(); 2237 assert(getSrcSize() == 1); 2238 if (llvm::isa<ConstantInteger32>(getCallTarget())) { 2239 // This shouldn't happen (typically have to copy the full 32-bits to a 2240 // register and do an indirect jump). 2241 llvm::report_fatal_error("ARM32Call to ConstantInteger32"); 2242 } else if (const auto *CallTarget = 2243 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { 2244 // Calls only have 24-bits, but the linker should insert veneers to extend 2245 // the range if needed. 2246 Str << "\t" 2247 "bl" 2248 "\t"; 2249 CallTarget->emitWithoutPrefix(Func->getTarget()); 2250 } else { 2251 Str << "\t" 2252 "blx" 2253 "\t"; 2254 getCallTarget()->emit(Func); 2255 } 2256 } 2257 2258 void InstARM32Call::emitIAS(const Cfg *Func) const { 2259 assert(getSrcSize() == 1); 2260 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2261 if (llvm::isa<ConstantInteger32>(getCallTarget())) { 2262 // This shouldn't happen (typically have to copy the full 32-bits to a 2263 // register and do an indirect jump). 2264 llvm::report_fatal_error("ARM32Call to ConstantInteger32"); 2265 } else if (const auto *CallTarget = 2266 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { 2267 // Calls only have 24-bits, but the linker should insert veneers to extend 2268 // the range if needed. 2269 Asm->bl(CallTarget); 2270 } else { 2271 Asm->blx(getCallTarget()); 2272 } 2273 if (Asm->needsTextFixup()) 2274 return emitUsingTextFixup(Func); 2275 } 2276 2277 void InstARM32Call::dump(const Cfg *Func) const { 2278 if (!BuildDefs::dump()) 2279 return; 2280 Ostream &Str = Func->getContext()->getStrDump(); 2281 if (getDest()) { 2282 dumpDest(Func); 2283 Str << " = "; 2284 } 2285 Str << "call "; 2286 getCallTarget()->dump(Func); 2287 } 2288 2289 void InstARM32Label::emit(const Cfg *Func) const { 2290 if (!BuildDefs::dump()) 2291 return; 2292 // A label is not really an instruction. Hence, we need to fix the 2293 // emitted text size. 2294 if (auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>()) 2295 Asm->decEmitTextSize(InstSize); 2296 Ostream &Str = Func->getContext()->getStrEmit(); 2297 Str << getLabelName() << ":"; 2298 } 2299 2300 void InstARM32Label::emitIAS(const Cfg *Func) const { 2301 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2302 Asm->bindLocalLabel(this, Number); 2303 if (OffsetReloc != nullptr) { 2304 Asm->bindRelocOffset(OffsetReloc); 2305 } 2306 if (Asm->needsTextFixup()) 2307 emitUsingTextFixup(Func); 2308 } 2309 2310 void InstARM32Label::dump(const Cfg *Func) const { 2311 if (!BuildDefs::dump()) 2312 return; 2313 Ostream &Str = Func->getContext()->getStrDump(); 2314 Str << getLabelName() << ":"; 2315 } 2316 2317 template <InstARM32::InstKindARM32 K> 2318 void InstARM32LoadBase<K>::emitIAS(const Cfg *Func) const { 2319 emitUsingTextFixup(Func); 2320 } 2321 2322 template <> void InstARM32Ldr::emit(const Cfg *Func) const { 2323 if (!BuildDefs::dump()) 2324 return; 2325 Ostream &Str = Func->getContext()->getStrEmit(); 2326 assert(getSrcSize() == 1); 2327 assert(getDest()->hasReg()); 2328 Variable *Dest = getDest(); 2329 Type Ty = Dest->getType(); 2330 const bool IsVector = isVectorType(Ty); 2331 const bool IsScalarFloat = isScalarFloatingType(Ty); 2332 const char *ActualOpcode = 2333 IsVector ? "vld1" : (IsScalarFloat ? "vldr" : "ldr"); 2334 const char *WidthString = IsVector ? "" : getWidthString(Ty); 2335 Str << "\t" << ActualOpcode; 2336 const bool IsVInst = IsVector || IsScalarFloat; 2337 if (IsVInst) { 2338 Str << getPredicate() << WidthString; 2339 } else { 2340 Str << WidthString << getPredicate(); 2341 } 2342 if (IsVector) 2343 Str << "." << getVecElmtBitsize(Ty); 2344 Str << "\t"; 2345 getDest()->emit(Func); 2346 Str << ", "; 2347 getSrc(0)->emit(Func); 2348 } 2349 2350 template <> void InstARM32Vldr1d::emit(const Cfg *Func) const { 2351 if (!BuildDefs::dump()) 2352 return; 2353 Ostream &Str = Func->getContext()->getStrEmit(); 2354 assert(getSrcSize() == 1); 2355 assert(getDest()->hasReg()); 2356 Variable *Dest = getDest(); 2357 Type Ty = Dest->getType(); 2358 const bool IsVector = isVectorType(Ty); 2359 const bool IsScalarFloat = isScalarFloatingType(Ty); 2360 const char *ActualOpcode = 2361 IsVector ? "vld1" : (IsScalarFloat ? "vldr" : "ldr"); 2362 const char *WidthString = IsVector ? "" : getWidthString(Ty); 2363 Str << "\t" << ActualOpcode; 2364 const bool IsVInst = IsVector || IsScalarFloat; 2365 if (IsVInst) { 2366 Str << getPredicate() << WidthString; 2367 } else { 2368 Str << WidthString << getPredicate(); 2369 } 2370 if (IsVector) 2371 Str << "." << getVecElmtBitsize(Ty); 2372 Str << "\t"; 2373 getDest()->emit(Func); 2374 Str << ", "; 2375 getSrc(0)->emit(Func); 2376 } 2377 2378 template <> void InstARM32Vldr1q::emit(const Cfg *Func) const { 2379 if (!BuildDefs::dump()) 2380 return; 2381 Ostream &Str = Func->getContext()->getStrEmit(); 2382 assert(getSrcSize() == 1); 2383 assert(getDest()->hasReg()); 2384 Variable *Dest = getDest(); 2385 Type Ty = Dest->getType(); 2386 const bool IsVector = isVectorType(Ty); 2387 const bool IsScalarFloat = isScalarFloatingType(Ty); 2388 const char *ActualOpcode = 2389 IsVector ? "vld1" : (IsScalarFloat ? "vldr" : "ldr"); 2390 const char *WidthString = IsVector ? "" : getWidthString(Ty); 2391 Str << "\t" << ActualOpcode; 2392 const bool IsVInst = IsVector || IsScalarFloat; 2393 if (IsVInst) { 2394 Str << getPredicate() << WidthString; 2395 } else { 2396 Str << WidthString << getPredicate(); 2397 } 2398 if (IsVector) 2399 Str << "." << getVecElmtBitsize(Ty); 2400 Str << "\t"; 2401 getDest()->emit(Func); 2402 Str << ", "; 2403 getSrc(0)->emit(Func); 2404 } 2405 2406 template <> void InstARM32Ldr::emitIAS(const Cfg *Func) const { 2407 assert(getSrcSize() == 1); 2408 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2409 Variable *Dest = getDest(); 2410 const Type DestTy = Dest->getType(); 2411 switch (DestTy) { 2412 default: 2413 llvm::report_fatal_error("Ldr on unknown type: " + typeStdString(DestTy)); 2414 case IceType_i1: 2415 case IceType_i8: 2416 case IceType_i16: 2417 case IceType_i32: 2418 case IceType_i64: 2419 Asm->ldr(Dest, getSrc(0), getPredicate(), Func->getTarget()); 2420 break; 2421 case IceType_f32: 2422 Asm->vldrs(Dest, getSrc(0), getPredicate(), Func->getTarget()); 2423 break; 2424 case IceType_f64: 2425 Asm->vldrd(Dest, getSrc(0), getPredicate(), Func->getTarget()); 2426 break; 2427 case IceType_v16i8: 2428 case IceType_v8i16: 2429 case IceType_v4i32: 2430 case IceType_v4f32: 2431 case IceType_v16i1: 2432 case IceType_v8i1: 2433 case IceType_v4i1: 2434 Asm->vld1qr(getVecElmtBitsize(DestTy), Dest, getSrc(0), Func->getTarget()); 2435 break; 2436 } 2437 } 2438 2439 template <> void InstARM32Vldr1d::emitIAS(const Cfg *Func) const { 2440 assert(getSrcSize() == 1); 2441 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2442 Variable *Dest = getDest(); 2443 Asm->vld1(32, Dest, getSrc(0), Func->getTarget()); 2444 } 2445 2446 template <> void InstARM32Vldr1q::emitIAS(const Cfg *Func) const { 2447 assert(getSrcSize() == 1); 2448 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2449 Variable *Dest = getDest(); 2450 Asm->vld1(64, Dest, getSrc(0), Func->getTarget()); 2451 } 2452 2453 template <> void InstARM32Ldrex::emit(const Cfg *Func) const { 2454 if (!BuildDefs::dump()) 2455 return; 2456 Ostream &Str = Func->getContext()->getStrEmit(); 2457 assert(getSrcSize() == 1); 2458 assert(getDest()->hasReg()); 2459 Variable *Dest = getDest(); 2460 Type DestTy = Dest->getType(); 2461 assert(isScalarIntegerType(DestTy)); 2462 const char *WidthString = getWidthString(DestTy); 2463 Str << "\t" << Opcode << WidthString << getPredicate() << "\t"; 2464 getDest()->emit(Func); 2465 Str << ", "; 2466 getSrc(0)->emit(Func); 2467 } 2468 2469 template <> void InstARM32Ldrex::emitIAS(const Cfg *Func) const { 2470 assert(getSrcSize() == 1); 2471 assert(getDest()->hasReg()); 2472 Variable *Dest = getDest(); 2473 assert(isScalarIntegerType(Dest->getType())); 2474 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2475 Asm->ldrex(Dest, getSrc(0), getPredicate(), Func->getTarget()); 2476 if (Asm->needsTextFixup()) 2477 emitUsingTextFixup(Func); 2478 } 2479 2480 template <InstARM32::InstKindARM32 K> 2481 void InstARM32TwoAddrGPR<K>::emitIAS(const Cfg *Func) const { 2482 emitUsingTextFixup(Func); 2483 } 2484 2485 template <InstARM32::InstKindARM32 K, bool Nws> 2486 void InstARM32UnaryopGPR<K, Nws>::emitIAS(const Cfg *Func) const { 2487 emitUsingTextFixup(Func); 2488 } 2489 2490 template <> void InstARM32Rbit::emitIAS(const Cfg *Func) const { 2491 assert(getSrcSize() == 1); 2492 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2493 Asm->rbit(getDest(), getSrc(0), getPredicate()); 2494 if (Asm->needsTextFixup()) 2495 emitUsingTextFixup(Func); 2496 } 2497 2498 template <> void InstARM32Rev::emitIAS(const Cfg *Func) const { 2499 assert(getSrcSize() == 1); 2500 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2501 Asm->rev(getDest(), getSrc(0), getPredicate()); 2502 if (Asm->needsTextFixup()) 2503 emitUsingTextFixup(Func); 2504 } 2505 2506 template <> void InstARM32Movw::emit(const Cfg *Func) const { 2507 if (!BuildDefs::dump()) 2508 return; 2509 Ostream &Str = Func->getContext()->getStrEmit(); 2510 assert(getSrcSize() == 1); 2511 Str << "\t" << Opcode << getPredicate() << "\t"; 2512 getDest()->emit(Func); 2513 Str << ", "; 2514 auto *Src0 = llvm::cast<Constant>(getSrc(0)); 2515 if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src0)) { 2516 Str << "#:lower16:"; 2517 CR->emitWithoutPrefix(Func->getTarget()); 2518 if (getFlags().getUseNonsfi()) { 2519 Str << " - ."; 2520 } 2521 } else { 2522 Src0->emit(Func); 2523 } 2524 } 2525 2526 template <> void InstARM32Movw::emitIAS(const Cfg *Func) const { 2527 assert(getSrcSize() == 1); 2528 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2529 Asm->movw(getDest(), getSrc(0), getPredicate()); 2530 if (Asm->needsTextFixup()) 2531 emitUsingTextFixup(Func); 2532 } 2533 2534 template <> void InstARM32Movt::emit(const Cfg *Func) const { 2535 if (!BuildDefs::dump()) 2536 return; 2537 Ostream &Str = Func->getContext()->getStrEmit(); 2538 assert(getSrcSize() == 2); 2539 Variable *Dest = getDest(); 2540 auto *Src1 = llvm::cast<Constant>(getSrc(1)); 2541 Str << "\t" << Opcode << getPredicate() << "\t"; 2542 Dest->emit(Func); 2543 Str << ", "; 2544 if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src1)) { 2545 Str << "#:upper16:"; 2546 CR->emitWithoutPrefix(Func->getTarget()); 2547 if (getFlags().getUseNonsfi()) { 2548 Str << " - ."; 2549 } 2550 } else { 2551 Src1->emit(Func); 2552 } 2553 } 2554 2555 template <> void InstARM32Movt::emitIAS(const Cfg *Func) const { 2556 assert(getSrcSize() == 2); 2557 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2558 Asm->movt(getDest(), getSrc(1), getPredicate()); 2559 if (Asm->needsTextFixup()) 2560 emitUsingTextFixup(Func); 2561 } 2562 2563 template <> void InstARM32Clz::emitIAS(const Cfg *Func) const { 2564 assert(getSrcSize() == 1); 2565 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2566 Asm->clz(getDest(), getSrc(0), getPredicate()); 2567 if (Asm->needsTextFixup()) 2568 emitUsingTextFixup(Func); 2569 } 2570 2571 template <> void InstARM32Mvn::emitIAS(const Cfg *Func) const { 2572 assert(getSrcSize() == 1); 2573 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2574 Asm->mvn(getDest(), getSrc(0), getPredicate()); 2575 if (Asm->needsTextFixup()) 2576 emitUsingTextFixup(Func); 2577 } 2578 2579 template <> void InstARM32Sxt::emitIAS(const Cfg *Func) const { 2580 assert(getSrcSize() == 1); 2581 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2582 Asm->sxt(getDest(), getSrc(0), getPredicate()); 2583 if (Asm->needsTextFixup()) 2584 emitUsingTextFixup(Func); 2585 } 2586 2587 template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const { 2588 assert(getSrcSize() == 1); 2589 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2590 Asm->uxt(getDest(), getSrc(0), getPredicate()); 2591 if (Asm->needsTextFixup()) 2592 emitUsingTextFixup(Func); 2593 } 2594 2595 template <InstARM32::InstKindARM32 K> 2596 void InstARM32UnaryopFP<K>::emitIAS(const Cfg *Func) const { 2597 emitUsingTextFixup(Func); 2598 } 2599 2600 template <InstARM32::InstKindARM32 K> 2601 void InstARM32UnaryopSignAwareFP<K>::emitIAS(const Cfg *Func) const { 2602 InstARM32::emitUsingTextFixup(Func); 2603 } 2604 2605 template <> void InstARM32Vsqrt::emitIAS(const Cfg *Func) const { 2606 assert(getSrcSize() == 1); 2607 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2608 const Operand *Dest = getDest(); 2609 switch (Dest->getType()) { 2610 case IceType_f32: 2611 Asm->vsqrts(Dest, getSrc(0), getPredicate()); 2612 break; 2613 case IceType_f64: 2614 Asm->vsqrtd(Dest, getSrc(0), getPredicate()); 2615 break; 2616 default: 2617 llvm::report_fatal_error("Vsqrt of non-floating type"); 2618 } 2619 if (Asm->needsTextFixup()) 2620 emitUsingTextFixup(Func); 2621 } 2622 2623 const char *InstARM32Pop::getGPROpcode() const { return "pop"; } 2624 2625 const char *InstARM32Pop::getSRegOpcode() const { return "vpop"; } 2626 2627 Variable *InstARM32Pop::getStackReg(SizeT Index) const { return Dests[Index]; } 2628 2629 SizeT InstARM32Pop::getNumStackRegs() const { return Dests.size(); } 2630 2631 void InstARM32Pop::emitSingleGPR(const Cfg *Func, const EmitForm Form, 2632 const Variable *Reg) const { 2633 switch (Form) { 2634 case Emit_Text: 2635 emitGPRsAsText(Func); 2636 return; 2637 case Emit_Binary: 2638 Func->getAssembler<ARM32::AssemblerARM32>()->pop(Reg, CondARM32::AL); 2639 return; 2640 } 2641 } 2642 2643 void InstARM32Pop::emitMultipleGPRs(const Cfg *Func, const EmitForm Form, 2644 IValueT Registers) const { 2645 switch (Form) { 2646 case Emit_Text: 2647 emitGPRsAsText(Func); 2648 return; 2649 case Emit_Binary: 2650 Func->getAssembler<ARM32::AssemblerARM32>()->popList(Registers, 2651 CondARM32::AL); 2652 return; 2653 } 2654 } 2655 2656 void InstARM32Pop::emitSRegs(const Cfg *Func, const EmitForm Form, 2657 const Variable *BaseReg, SizeT RegCount) const { 2658 switch (Form) { 2659 case Emit_Text: 2660 emitSRegsAsText(Func, BaseReg, RegCount); 2661 return; 2662 case Emit_Binary: 2663 Func->getAssembler<ARM32::AssemblerARM32>()->vpop(BaseReg, RegCount, 2664 CondARM32::AL); 2665 return; 2666 } 2667 } 2668 2669 const char *InstARM32Push::getGPROpcode() const { return "push"; } 2670 2671 const char *InstARM32Push::getSRegOpcode() const { return "vpush"; } 2672 2673 Variable *InstARM32Push::getStackReg(SizeT Index) const { 2674 return llvm::cast<Variable>(getSrc(Index)); 2675 } 2676 2677 SizeT InstARM32Push::getNumStackRegs() const { return getSrcSize(); } 2678 2679 void InstARM32Push::emitSingleGPR(const Cfg *Func, const EmitForm Form, 2680 const Variable *Reg) const { 2681 switch (Form) { 2682 case Emit_Text: 2683 emitGPRsAsText(Func); 2684 return; 2685 case Emit_Binary: 2686 Func->getAssembler<ARM32::AssemblerARM32>()->push(Reg, CondARM32::AL); 2687 return; 2688 } 2689 } 2690 2691 void InstARM32Push::emitMultipleGPRs(const Cfg *Func, const EmitForm Form, 2692 IValueT Registers) const { 2693 switch (Form) { 2694 case Emit_Text: 2695 emitGPRsAsText(Func); 2696 return; 2697 case Emit_Binary: 2698 Func->getAssembler<ARM32::AssemblerARM32>()->pushList(Registers, 2699 CondARM32::AL); 2700 return; 2701 } 2702 } 2703 2704 void InstARM32Push::emitSRegs(const Cfg *Func, const EmitForm Form, 2705 const Variable *BaseReg, SizeT RegCount) const { 2706 switch (Form) { 2707 case Emit_Text: 2708 emitSRegsAsText(Func, BaseReg, RegCount); 2709 return; 2710 case Emit_Binary: 2711 Func->getAssembler<ARM32::AssemblerARM32>()->vpush(BaseReg, RegCount, 2712 CondARM32::AL); 2713 return; 2714 } 2715 } 2716 2717 void InstARM32Ret::emit(const Cfg *Func) const { 2718 if (!BuildDefs::dump()) 2719 return; 2720 assert(getSrcSize() > 0); 2721 auto *LR = llvm::cast<Variable>(getSrc(0)); 2722 assert(LR->hasReg()); 2723 assert(LR->getRegNum() == RegARM32::Reg_lr); 2724 Ostream &Str = Func->getContext()->getStrEmit(); 2725 Str << "\t" 2726 "bx" 2727 "\t"; 2728 LR->emit(Func); 2729 } 2730 2731 void InstARM32Ret::emitIAS(const Cfg *Func) const { 2732 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2733 Asm->bx(RegARM32::Encoded_Reg_lr); 2734 if (Asm->needsTextFixup()) 2735 emitUsingTextFixup(Func); 2736 } 2737 2738 void InstARM32Ret::dump(const Cfg *Func) const { 2739 if (!BuildDefs::dump()) 2740 return; 2741 Ostream &Str = Func->getContext()->getStrDump(); 2742 Type Ty = (getSrcSize() == 1 ? IceType_void : getSrc(0)->getType()); 2743 Str << "ret." << Ty << " "; 2744 dumpSources(Func); 2745 } 2746 2747 void InstARM32Str::emit(const Cfg *Func) const { 2748 if (!BuildDefs::dump()) 2749 return; 2750 Ostream &Str = Func->getContext()->getStrEmit(); 2751 assert(getSrcSize() == 2); 2752 Type Ty = getSrc(0)->getType(); 2753 const bool IsVectorStore = isVectorType(Ty); 2754 const bool IsScalarFloat = isScalarFloatingType(Ty); 2755 const char *Opcode = 2756 IsVectorStore ? "vst1" : (IsScalarFloat ? "vstr" : "str"); 2757 Str << "\t" << Opcode; 2758 const bool IsVInst = IsVectorStore || IsScalarFloat; 2759 if (IsVInst) { 2760 Str << getPredicate() << getWidthString(Ty); 2761 } else { 2762 Str << getWidthString(Ty) << getPredicate(); 2763 } 2764 if (IsVectorStore) 2765 Str << "." << getVecElmtBitsize(Ty); 2766 Str << "\t"; 2767 getSrc(0)->emit(Func); 2768 Str << ", "; 2769 getSrc(1)->emit(Func); 2770 } 2771 2772 void InstARM32Str::emitIAS(const Cfg *Func) const { 2773 assert(getSrcSize() == 2); 2774 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2775 const Operand *Src0 = getSrc(0); 2776 const Operand *Src1 = getSrc(1); 2777 Type Ty = Src0->getType(); 2778 switch (Ty) { 2779 default: 2780 llvm::report_fatal_error("Str on unknown type: " + typeStdString(Ty)); 2781 case IceType_i1: 2782 case IceType_i8: 2783 case IceType_i16: 2784 case IceType_i32: 2785 case IceType_i64: 2786 Asm->str(Src0, Src1, getPredicate(), Func->getTarget()); 2787 break; 2788 case IceType_f32: 2789 Asm->vstrs(Src0, Src1, getPredicate(), Func->getTarget()); 2790 break; 2791 case IceType_f64: 2792 Asm->vstrd(Src0, Src1, getPredicate(), Func->getTarget()); 2793 break; 2794 case IceType_v16i8: 2795 case IceType_v8i16: 2796 case IceType_v4i32: 2797 case IceType_v4f32: 2798 case IceType_v16i1: 2799 case IceType_v8i1: 2800 case IceType_v4i1: 2801 Asm->vst1qr(getVecElmtBitsize(Ty), Src0, Src1, Func->getTarget()); 2802 break; 2803 } 2804 } 2805 2806 void InstARM32Str::dump(const Cfg *Func) const { 2807 if (!BuildDefs::dump()) 2808 return; 2809 Ostream &Str = Func->getContext()->getStrDump(); 2810 Type Ty = getSrc(0)->getType(); 2811 dumpOpcodePred(Str, "str", Ty); 2812 Str << " "; 2813 getSrc(1)->dump(Func); 2814 Str << ", "; 2815 getSrc(0)->dump(Func); 2816 } 2817 2818 void InstARM32Strex::emit(const Cfg *Func) const { 2819 if (!BuildDefs::dump()) 2820 return; 2821 assert(getSrcSize() == 2); 2822 Type Ty = getSrc(0)->getType(); 2823 assert(isScalarIntegerType(Ty)); 2824 Variable *Dest = getDest(); 2825 Ostream &Str = Func->getContext()->getStrEmit(); 2826 static constexpr char Opcode[] = "strex"; 2827 const char *WidthString = getWidthString(Ty); 2828 Str << "\t" << Opcode << WidthString << getPredicate() << "\t"; 2829 Dest->emit(Func); 2830 Str << ", "; 2831 emitSources(Func); 2832 } 2833 2834 void InstARM32Strex::emitIAS(const Cfg *Func) const { 2835 assert(getSrcSize() == 2); 2836 const Operand *Src0 = getSrc(0); 2837 assert(isScalarIntegerType(Src0->getType())); 2838 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2839 Asm->strex(Dest, Src0, getSrc(1), getPredicate(), Func->getTarget()); 2840 if (Asm->needsTextFixup()) 2841 emitUsingTextFixup(Func); 2842 } 2843 2844 void InstARM32Strex::dump(const Cfg *Func) const { 2845 if (!BuildDefs::dump()) 2846 return; 2847 Ostream &Str = Func->getContext()->getStrDump(); 2848 Variable *Dest = getDest(); 2849 Dest->dump(Func); 2850 Str << " = "; 2851 Type Ty = getSrc(0)->getType(); 2852 dumpOpcodePred(Str, "strex", Ty); 2853 Str << " "; 2854 getSrc(1)->dump(Func); 2855 Str << ", "; 2856 getSrc(0)->dump(Func); 2857 } 2858 2859 void InstARM32Vstr1::emit(const Cfg *Func) const { 2860 if (!BuildDefs::dump()) 2861 return; 2862 Ostream &Str = Func->getContext()->getStrEmit(); 2863 assert(getSrcSize() == 2); 2864 Type Ty = getSrc(0)->getType(); 2865 const bool IsVectorStore = isVectorType(Ty); 2866 const bool IsScalarFloat = isScalarFloatingType(Ty); 2867 const char *Opcode = 2868 IsVectorStore ? "vst1" : (IsScalarFloat ? "vstr" : "str"); 2869 Str << "\t" << Opcode; 2870 const bool IsVInst = IsVectorStore || IsScalarFloat; 2871 if (IsVInst) { 2872 Str << getPredicate() << getWidthString(Ty); 2873 } else { 2874 Str << getWidthString(Ty) << getPredicate(); 2875 } 2876 if (IsVectorStore) 2877 Str << "." << getVecElmtBitsize(Ty); 2878 Str << "\t"; 2879 getSrc(0)->emit(Func); 2880 Str << ", "; 2881 getSrc(1)->emit(Func); 2882 } 2883 2884 void InstARM32Vstr1::emitIAS(const Cfg *Func) const { 2885 assert(getSrcSize() == 2); 2886 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2887 const Operand *Src0 = getSrc(0); 2888 const Operand *Src1 = getSrc(1); 2889 Asm->vst1(Size, Src0, Src1, Func->getTarget()); 2890 } 2891 2892 void InstARM32Vstr1::dump(const Cfg *Func) const { 2893 if (!BuildDefs::dump()) 2894 return; 2895 Ostream &Str = Func->getContext()->getStrDump(); 2896 Type Ty = getSrc(0)->getType(); 2897 dumpOpcodePred(Str, "str", Ty); 2898 Str << " "; 2899 getSrc(1)->dump(Func); 2900 Str << ", "; 2901 getSrc(0)->dump(Func); 2902 } 2903 2904 void InstARM32Vdup::emit(const Cfg *Func) const { 2905 if (!BuildDefs::dump()) 2906 return; 2907 Ostream &Str = Func->getContext()->getStrEmit(); 2908 assert(getSrcSize() == 2); 2909 Type Ty = getSrc(0)->getType(); 2910 const char *Opcode = "vdup"; 2911 Str << "\t" << Opcode; 2912 Str << getPredicate() << "." << getWidthString(Ty) << getVecElmtBitsize(Ty); 2913 Str << "\t"; 2914 getSrc(0)->emit(Func); 2915 Str << ", "; 2916 getSrc(1)->emit(Func); 2917 Str << ", " << Idx; 2918 } 2919 2920 void InstARM32Vdup::emitIAS(const Cfg *Func) const { 2921 assert(getSrcSize() == 1); 2922 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2923 const Operand *Dest = getDest(); 2924 const Operand *Src = getSrc(0); 2925 Type DestTy = Dest->getType(); 2926 Asm->vdup(typeElementType(DestTy), Dest, Src, Idx); 2927 } 2928 2929 void InstARM32Vdup::dump(const Cfg *Func) const { 2930 if (!BuildDefs::dump()) 2931 return; 2932 Ostream &Str = Func->getContext()->getStrDump(); 2933 dumpDest(Func); 2934 Str << " = "; 2935 dumpOpcodePred(Str, "vdup", getDest()->getType()); 2936 Str << " "; 2937 dumpSources(Func); 2938 Str << ", " << Idx; 2939 } 2940 2941 void InstARM32Trap::emit(const Cfg *Func) const { 2942 if (!BuildDefs::dump()) 2943 return; 2944 Ostream &Str = Func->getContext()->getStrEmit(); 2945 assert(getSrcSize() == 0); 2946 // There isn't a mnemonic for the special NaCl Trap encoding, so dump 2947 // the raw bytes. 2948 Str << "\t.long 0x"; 2949 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2950 for (uint8_t I : Asm->getNonExecBundlePadding()) { 2951 Str.write_hex(I); 2952 } 2953 } 2954 2955 void InstARM32Trap::emitIAS(const Cfg *Func) const { 2956 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2957 Asm->trap(); 2958 assert(!Asm->needsTextFixup()); 2959 } 2960 2961 void InstARM32Trap::dump(const Cfg *Func) const { 2962 if (!BuildDefs::dump()) 2963 return; 2964 Ostream &Str = Func->getContext()->getStrDump(); 2965 Str << "trap"; 2966 } 2967 2968 void InstARM32Umull::emit(const Cfg *Func) const { 2969 if (!BuildDefs::dump()) 2970 return; 2971 Ostream &Str = Func->getContext()->getStrEmit(); 2972 assert(getSrcSize() == 2); 2973 assert(getDest()->hasReg()); 2974 Str << "\t" 2975 "umull" << getPredicate() << "\t"; 2976 getDest()->emit(Func); 2977 Str << ", "; 2978 DestHi->emit(Func); 2979 Str << ", "; 2980 getSrc(0)->emit(Func); 2981 Str << ", "; 2982 getSrc(1)->emit(Func); 2983 } 2984 2985 void InstARM32Umull::emitIAS(const Cfg *Func) const { 2986 assert(getSrcSize() == 2); 2987 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 2988 Asm->umull(getDest(), DestHi, getSrc(0), getSrc(1), getPredicate()); 2989 if (Asm->needsTextFixup()) 2990 emitUsingTextFixup(Func); 2991 } 2992 2993 void InstARM32Umull::dump(const Cfg *Func) const { 2994 if (!BuildDefs::dump()) 2995 return; 2996 Ostream &Str = Func->getContext()->getStrDump(); 2997 dumpDest(Func); 2998 Str << " = "; 2999 dumpOpcodePred(Str, "umull", getDest()->getType()); 3000 Str << " "; 3001 dumpSources(Func); 3002 } 3003 3004 namespace { 3005 const char *vcvtVariantSuffix(const InstARM32Vcvt::VcvtVariant Variant) { 3006 switch (Variant) { 3007 case InstARM32Vcvt::S2si: 3008 return ".s32.f32"; 3009 case InstARM32Vcvt::S2ui: 3010 return ".u32.f32"; 3011 case InstARM32Vcvt::Si2s: 3012 return ".f32.s32"; 3013 case InstARM32Vcvt::Ui2s: 3014 return ".f32.u32"; 3015 case InstARM32Vcvt::D2si: 3016 return ".s32.f64"; 3017 case InstARM32Vcvt::D2ui: 3018 return ".u32.f64"; 3019 case InstARM32Vcvt::Si2d: 3020 return ".f64.s32"; 3021 case InstARM32Vcvt::Ui2d: 3022 return ".f64.u32"; 3023 case InstARM32Vcvt::S2d: 3024 return ".f64.f32"; 3025 case InstARM32Vcvt::D2s: 3026 return ".f32.f64"; 3027 case InstARM32Vcvt::Vs2si: 3028 return ".s32.f32"; 3029 case InstARM32Vcvt::Vs2ui: 3030 return ".u32.f32"; 3031 case InstARM32Vcvt::Vsi2s: 3032 return ".f32.s32"; 3033 case InstARM32Vcvt::Vui2s: 3034 return ".f32.u32"; 3035 } 3036 llvm::report_fatal_error("Invalid VcvtVariant enum."); 3037 } 3038 } // end of anonymous namespace 3039 3040 void InstARM32Vcvt::emit(const Cfg *Func) const { 3041 if (!BuildDefs::dump()) 3042 return; 3043 Ostream &Str = Func->getContext()->getStrEmit(); 3044 assert(getSrcSize() == 1); 3045 assert(getDest()->hasReg()); 3046 Str << "\t" 3047 "vcvt" << getPredicate() << vcvtVariantSuffix(Variant) << "\t"; 3048 getDest()->emit(Func); 3049 Str << ", "; 3050 getSrc(0)->emit(Func); 3051 } 3052 3053 void InstARM32Vcvt::emitIAS(const Cfg *Func) const { 3054 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 3055 switch (Variant) { 3056 case S2si: 3057 Asm->vcvtis(getDest(), getSrc(0), getPredicate()); 3058 break; 3059 case S2ui: 3060 Asm->vcvtus(getDest(), getSrc(0), getPredicate()); 3061 break; 3062 case Si2s: 3063 Asm->vcvtsi(getDest(), getSrc(0), getPredicate()); 3064 break; 3065 case Ui2s: 3066 Asm->vcvtsu(getDest(), getSrc(0), getPredicate()); 3067 break; 3068 case D2si: 3069 Asm->vcvtid(getDest(), getSrc(0), getPredicate()); 3070 break; 3071 case D2ui: 3072 Asm->vcvtud(getDest(), getSrc(0), getPredicate()); 3073 break; 3074 case Si2d: 3075 Asm->vcvtdi(getDest(), getSrc(0), getPredicate()); 3076 break; 3077 case Ui2d: 3078 Asm->vcvtdu(getDest(), getSrc(0), getPredicate()); 3079 break; 3080 case S2d: 3081 Asm->vcvtds(getDest(), getSrc(0), getPredicate()); 3082 break; 3083 case D2s: 3084 Asm->vcvtsd(getDest(), getSrc(0), getPredicate()); 3085 break; 3086 case Vs2si: 3087 Asm->vcvtqsi(getDest(), getSrc(0)); 3088 break; 3089 case Vs2ui: 3090 Asm->vcvtqsu(getDest(), getSrc(0)); 3091 break; 3092 case Vsi2s: 3093 Asm->vcvtqis(getDest(), getSrc(0)); 3094 break; 3095 case Vui2s: 3096 Asm->vcvtqus(getDest(), getSrc(0)); 3097 break; 3098 } 3099 assert(!Asm->needsTextFixup()); 3100 } 3101 3102 void InstARM32Vcvt::dump(const Cfg *Func) const { 3103 if (!BuildDefs::dump()) 3104 return; 3105 Ostream &Str = Func->getContext()->getStrDump(); 3106 dumpDest(Func); 3107 Str << " = " 3108 << "vcvt" << getPredicate() << vcvtVariantSuffix(Variant) << " "; 3109 dumpSources(Func); 3110 } 3111 3112 void InstARM32Vcmp::emit(const Cfg *Func) const { 3113 if (!BuildDefs::dump()) 3114 return; 3115 Ostream &Str = Func->getContext()->getStrEmit(); 3116 assert(getSrcSize() == 2); 3117 Str << "\t" 3118 "vcmp" << getPredicate() << getFpWidthString(getSrc(0)->getType()) 3119 << "\t"; 3120 getSrc(0)->emit(Func); 3121 Str << ", "; 3122 getSrc(1)->emit(Func); 3123 } 3124 3125 void InstARM32Vcmp::emitIAS(const Cfg *Func) const { 3126 assert(getSrcSize() == 2); 3127 const Operand *Src0 = getSrc(0); 3128 const Type Ty = Src0->getType(); 3129 const Operand *Src1 = getSrc(1); 3130 const CondARM32::Cond Cond = getPredicate(); 3131 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 3132 if (llvm::isa<OperandARM32FlexFpZero>(Src1)) { 3133 switch (Ty) { 3134 case IceType_f32: 3135 Asm->vcmpsz(Src0, Cond); 3136 break; 3137 case IceType_f64: 3138 Asm->vcmpdz(Src0, Cond); 3139 break; 3140 default: 3141 llvm::report_fatal_error("Vcvt on non floating value"); 3142 } 3143 } else { 3144 switch (Ty) { 3145 case IceType_f32: 3146 Asm->vcmps(Src0, Src1, Cond); 3147 break; 3148 case IceType_f64: 3149 Asm->vcmpd(Src0, Src1, Cond); 3150 break; 3151 default: 3152 llvm::report_fatal_error("Vcvt on non floating value"); 3153 } 3154 } 3155 assert(!Asm->needsTextFixup()); 3156 } 3157 3158 void InstARM32Vcmp::dump(const Cfg *Func) const { 3159 if (!BuildDefs::dump()) 3160 return; 3161 Ostream &Str = Func->getContext()->getStrDump(); 3162 Str << "vcmp" << getPredicate() << getFpWidthString(getSrc(0)->getType()); 3163 dumpSources(Func); 3164 } 3165 3166 void InstARM32Vmrs::emit(const Cfg *Func) const { 3167 if (!BuildDefs::dump()) 3168 return; 3169 Ostream &Str = Func->getContext()->getStrEmit(); 3170 assert(getSrcSize() == 0); 3171 Str << "\t" 3172 "vmrs" << getPredicate() << "\t" 3173 "APSR_nzcv" 3174 ", " 3175 "FPSCR"; 3176 } 3177 3178 void InstARM32Vmrs::emitIAS(const Cfg *Func) const { 3179 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 3180 Asm->vmrsAPSR_nzcv(getPredicate()); 3181 assert(!Asm->needsTextFixup()); 3182 } 3183 3184 void InstARM32Vmrs::dump(const Cfg *Func) const { 3185 if (!BuildDefs::dump()) 3186 return; 3187 Ostream &Str = Func->getContext()->getStrDump(); 3188 Str << "APSR{n,z,v,c} = vmrs" << getPredicate() << "\t" 3189 "FPSCR{n,z,c,v}"; 3190 } 3191 3192 void InstARM32Vabs::emit(const Cfg *Func) const { 3193 if (!BuildDefs::dump()) 3194 return; 3195 Ostream &Str = Func->getContext()->getStrEmit(); 3196 assert(getSrcSize() == 1); 3197 Str << "\t" 3198 "vabs" << getPredicate() << getFpWidthString(getSrc(0)->getType()) 3199 << "\t"; 3200 getDest()->emit(Func); 3201 Str << ", "; 3202 getSrc(0)->emit(Func); 3203 } 3204 3205 void InstARM32Vabs::emitIAS(const Cfg *Func) const { 3206 assert(getSrcSize() == 1); 3207 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 3208 const Variable *Dest = getDest(); 3209 switch (Dest->getType()) { 3210 default: 3211 llvm::report_fatal_error("fabs not defined on type " + 3212 typeStdString(Dest->getType())); 3213 case IceType_f32: 3214 Asm->vabss(Dest, getSrc(0), getPredicate()); 3215 break; 3216 case IceType_f64: 3217 Asm->vabsd(Dest, getSrc(0), getPredicate()); 3218 break; 3219 case IceType_v4f32: 3220 assert(CondARM32::isUnconditional(getPredicate()) && 3221 "fabs must be unconditional"); 3222 Asm->vabsq(Dest, getSrc(0)); 3223 } 3224 assert(!Asm->needsTextFixup()); 3225 } 3226 3227 void InstARM32Vabs::dump(const Cfg *Func) const { 3228 if (!BuildDefs::dump()) 3229 return; 3230 Ostream &Str = Func->getContext()->getStrDump(); 3231 dumpDest(Func); 3232 Str << " = vabs" << getPredicate() << getFpWidthString(getSrc(0)->getType()); 3233 } 3234 3235 void InstARM32Dmb::emit(const Cfg *Func) const { 3236 if (!BuildDefs::dump()) 3237 return; 3238 Ostream &Str = Func->getContext()->getStrEmit(); 3239 assert(getSrcSize() == 0); 3240 Str << "\t" 3241 "dmb" 3242 "\t" 3243 "sy"; 3244 } 3245 3246 void InstARM32Dmb::emitIAS(const Cfg *Func) const { 3247 assert(getSrcSize() == 0); 3248 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); 3249 constexpr ARM32::IValueT SyOption = 0xF; // i.e. 1111 3250 Asm->dmb(SyOption); 3251 if (Asm->needsTextFixup()) 3252 emitUsingTextFixup(Func); 3253 } 3254 3255 void InstARM32Dmb::dump(const Cfg *Func) const { 3256 if (!BuildDefs::dump()) 3257 return; 3258 Func->getContext()->getStrDump() << "dmb\t" 3259 "sy"; 3260 } 3261 3262 void InstARM32Nop::emit(const Cfg *Func) const { 3263 if (!BuildDefs::dump()) 3264 return; 3265 assert(getSrcSize() == 0); 3266 Func->getContext()->getStrEmit() << "\t" 3267 << "nop"; 3268 } 3269 3270 void InstARM32Nop::emitIAS(const Cfg *Func) const { 3271 assert(getSrcSize() == 0); 3272 Func->getAssembler<ARM32::AssemblerARM32>()->nop(); 3273 } 3274 3275 void InstARM32Nop::dump(const Cfg *Func) const { 3276 if (!BuildDefs::dump()) 3277 return; 3278 assert(getSrcSize() == 0); 3279 Func->getContext()->getStrDump() << "nop"; 3280 } 3281 3282 void OperandARM32Mem::emit(const Cfg *Func) const { 3283 if (!BuildDefs::dump()) 3284 return; 3285 Ostream &Str = Func->getContext()->getStrEmit(); 3286 Str << "["; 3287 getBase()->emit(Func); 3288 switch (getAddrMode()) { 3289 case PostIndex: 3290 case NegPostIndex: 3291 Str << "]"; 3292 break; 3293 default: 3294 break; 3295 } 3296 if (isRegReg()) { 3297 Str << ", "; 3298 if (isNegAddrMode()) { 3299 Str << "-"; 3300 } 3301 getIndex()->emit(Func); 3302 if (getShiftOp() != kNoShift) { 3303 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #" 3304 << getShiftAmt(); 3305 } 3306 } else { 3307 ConstantInteger32 *Offset = getOffset(); 3308 if (Offset && Offset->getValue() != 0) { 3309 Str << ", "; 3310 Offset->emit(Func); 3311 } 3312 } 3313 switch (getAddrMode()) { 3314 case Offset: 3315 case NegOffset: 3316 Str << "]"; 3317 break; 3318 case PreIndex: 3319 case NegPreIndex: 3320 Str << "]!"; 3321 break; 3322 case PostIndex: 3323 case NegPostIndex: 3324 // Brace is already closed off. 3325 break; 3326 } 3327 } 3328 3329 void OperandARM32Mem::dump(const Cfg *Func, Ostream &Str) const { 3330 if (!BuildDefs::dump()) 3331 return; 3332 Str << "["; 3333 if (Func) 3334 getBase()->dump(Func); 3335 else 3336 getBase()->dump(Str); 3337 Str << ", "; 3338 if (isRegReg()) { 3339 if (isNegAddrMode()) { 3340 Str << "-"; 3341 } 3342 if (Func) 3343 getIndex()->dump(Func); 3344 else 3345 getIndex()->dump(Str); 3346 if (getShiftOp() != kNoShift) { 3347 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #" 3348 << getShiftAmt(); 3349 } 3350 } else { 3351 getOffset()->dump(Func, Str); 3352 } 3353 Str << "] AddrMode==" << getAddrMode(); 3354 } 3355 3356 void OperandARM32ShAmtImm::emit(const Cfg *Func) const { ShAmt->emit(Func); } 3357 3358 void OperandARM32ShAmtImm::dump(const Cfg *, Ostream &Str) const { 3359 ShAmt->dump(Str); 3360 } 3361 3362 OperandARM32FlexImm *OperandARM32FlexImm::create(Cfg *Func, Type Ty, 3363 uint32_t Imm, 3364 uint32_t RotateAmt) { 3365 // The assembler wants the smallest rotation. Rotate if needed. Note: Imm is 3366 // an 8-bit value. 3367 assert(Utils::IsUint(8, Imm) && 3368 "Flex immediates can only be defined on 8-bit immediates"); 3369 while ((Imm & 0x03) == 0 && RotateAmt > 0) { 3370 --RotateAmt; 3371 Imm = Imm >> 2; 3372 } 3373 return new (Func->allocate<OperandARM32FlexImm>()) 3374 OperandARM32FlexImm(Func, Ty, Imm, RotateAmt); 3375 } 3376 3377 void OperandARM32FlexImm::emit(const Cfg *Func) const { 3378 if (!BuildDefs::dump()) 3379 return; 3380 Ostream &Str = Func->getContext()->getStrEmit(); 3381 uint32_t Imm = getImm(); 3382 uint32_t RotateAmt = getRotateAmt(); 3383 Str << "#" << Utils::rotateRight32(Imm, 2 * RotateAmt); 3384 } 3385 3386 void OperandARM32FlexImm::dump(const Cfg * /* Func */, Ostream &Str) const { 3387 if (!BuildDefs::dump()) 3388 return; 3389 uint32_t Imm = getImm(); 3390 uint32_t RotateAmt = getRotateAmt(); 3391 Str << "#(" << Imm << " ror 2*" << RotateAmt << ")"; 3392 } 3393 3394 namespace { 3395 static constexpr uint32_t a = 0x80; 3396 static constexpr uint32_t b = 0x40; 3397 static constexpr uint32_t cdefgh = 0x3F; 3398 static constexpr uint32_t AllowedBits = a | b | cdefgh; 3399 static_assert(AllowedBits == 0xFF, 3400 "Invalid mask for f32/f64 constant rematerialization."); 3401 3402 // There's no loss in always returning the modified immediate as float. 3403 // TODO(jpp): returning a double causes problems when outputting the constants 3404 // for filetype=asm. Why? 3405 float materializeFloatImmediate(uint32_t ModifiedImm) { 3406 const uint32_t Ret = ((ModifiedImm & a) ? 0x80000000 : 0) | 3407 ((ModifiedImm & b) ? 0x3E000000 : 0x40000000) | 3408 ((ModifiedImm & cdefgh) << 19); 3409 return Utils::bitCopy<float>(Ret); 3410 } 3411 3412 } // end of anonymous namespace 3413 3414 void OperandARM32FlexFpImm::emit(const Cfg *Func) const { 3415 if (!BuildDefs::dump()) 3416 return; 3417 Ostream &Str = Func->getContext()->getStrEmit(); 3418 switch (Ty) { 3419 default: 3420 llvm::report_fatal_error("Invalid flex fp imm type."); 3421 case IceType_f64: 3422 case IceType_f32: 3423 Str << "#" << materializeFloatImmediate(ModifiedImm) 3424 << " @ Modified: " << ModifiedImm; 3425 break; 3426 } 3427 } 3428 3429 void OperandARM32FlexFpImm::dump(const Cfg * /*Func*/, Ostream &Str) const { 3430 if (!BuildDefs::dump()) 3431 return; 3432 Str << "#" << materializeFloatImmediate(ModifiedImm) << getFpWidthString(Ty); 3433 } 3434 3435 void OperandARM32FlexFpZero::emit(const Cfg *Func) const { 3436 if (!BuildDefs::dump()) 3437 return; 3438 Ostream &Str = Func->getContext()->getStrEmit(); 3439 switch (Ty) { 3440 default: 3441 llvm::report_fatal_error("Invalid flex fp imm type."); 3442 case IceType_f64: 3443 case IceType_f32: 3444 Str << "#0.0"; 3445 } 3446 } 3447 3448 void OperandARM32FlexFpZero::dump(const Cfg * /*Func*/, Ostream &Str) const { 3449 if (!BuildDefs::dump()) 3450 return; 3451 Str << "#0.0" << getFpWidthString(Ty); 3452 } 3453 3454 void OperandARM32FlexReg::emit(const Cfg *Func) const { 3455 if (!BuildDefs::dump()) 3456 return; 3457 Ostream &Str = Func->getContext()->getStrEmit(); 3458 getReg()->emit(Func); 3459 if (getShiftOp() != kNoShift) { 3460 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; 3461 getShiftAmt()->emit(Func); 3462 } 3463 } 3464 3465 void OperandARM32FlexReg::dump(const Cfg *Func, Ostream &Str) const { 3466 if (!BuildDefs::dump()) 3467 return; 3468 Variable *Reg = getReg(); 3469 if (Func) 3470 Reg->dump(Func); 3471 else 3472 Reg->dump(Str); 3473 if (getShiftOp() != kNoShift) { 3474 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; 3475 if (Func) 3476 getShiftAmt()->dump(Func); 3477 else 3478 getShiftAmt()->dump(Str); 3479 } 3480 } 3481 3482 // Force instantition of template classes 3483 template class InstARM32ThreeAddrGPR<InstARM32::Adc>; 3484 template class InstARM32ThreeAddrGPR<InstARM32::Add>; 3485 template class InstARM32ThreeAddrGPR<InstARM32::And>; 3486 template class InstARM32ThreeAddrGPR<InstARM32::Asr>; 3487 template class InstARM32ThreeAddrGPR<InstARM32::Bic>; 3488 template class InstARM32ThreeAddrGPR<InstARM32::Eor>; 3489 template class InstARM32ThreeAddrGPR<InstARM32::Lsl>; 3490 template class InstARM32ThreeAddrGPR<InstARM32::Lsr>; 3491 template class InstARM32ThreeAddrGPR<InstARM32::Mul>; 3492 template class InstARM32ThreeAddrGPR<InstARM32::Orr>; 3493 template class InstARM32ThreeAddrGPR<InstARM32::Rsb>; 3494 template class InstARM32ThreeAddrGPR<InstARM32::Rsc>; 3495 template class InstARM32ThreeAddrGPR<InstARM32::Sbc>; 3496 template class InstARM32ThreeAddrGPR<InstARM32::Sdiv>; 3497 template class InstARM32ThreeAddrGPR<InstARM32::Sub>; 3498 template class InstARM32ThreeAddrGPR<InstARM32::Udiv>; 3499 3500 template class InstARM32ThreeAddrFP<InstARM32::Vadd>; 3501 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vcge>; 3502 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vcgt>; 3503 template class InstARM32ThreeAddrFP<InstARM32::Vdiv>; 3504 template class InstARM32ThreeAddrFP<InstARM32::Veor>; 3505 template class InstARM32FourAddrFP<InstARM32::Vmla>; 3506 template class InstARM32FourAddrFP<InstARM32::Vmls>; 3507 template class InstARM32ThreeAddrFP<InstARM32::Vmul>; 3508 template class InstARM32UnaryopSignAwareFP<InstARM32::Vneg>; 3509 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vshl>; 3510 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vshr>; 3511 template class InstARM32ThreeAddrFP<InstARM32::Vsub>; 3512 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vqadd>; 3513 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vqsub>; 3514 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vqmovn2>; 3515 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vmulh>; 3516 template class InstARM32ThreeAddrFP<InstARM32::Vmlap>; 3517 3518 template class InstARM32LoadBase<InstARM32::Ldr>; 3519 template class InstARM32LoadBase<InstARM32::Ldrex>; 3520 template class InstARM32LoadBase<InstARM32::Vldr1d>; 3521 template class InstARM32LoadBase<InstARM32::Vldr1q>; 3522 template class InstARM32ThreeAddrFP<InstARM32::Vzip>; 3523 template class InstARM32TwoAddrGPR<InstARM32::Movt>; 3524 3525 template class InstARM32UnaryopGPR<InstARM32::Movw, false>; 3526 template class InstARM32UnaryopGPR<InstARM32::Clz, false>; 3527 template class InstARM32UnaryopGPR<InstARM32::Mvn, false>; 3528 template class InstARM32UnaryopGPR<InstARM32::Rbit, false>; 3529 template class InstARM32UnaryopGPR<InstARM32::Rev, false>; 3530 template class InstARM32UnaryopGPR<InstARM32::Sxt, true>; 3531 template class InstARM32UnaryopGPR<InstARM32::Uxt, true>; 3532 template class InstARM32UnaryopFP<InstARM32::Vsqrt>; 3533 3534 template class InstARM32FourAddrGPR<InstARM32::Mla>; 3535 template class InstARM32FourAddrGPR<InstARM32::Mls>; 3536 3537 template class InstARM32CmpLike<InstARM32::Cmn>; 3538 template class InstARM32CmpLike<InstARM32::Cmp>; 3539 template class InstARM32CmpLike<InstARM32::Tst>; 3540 3541 } // end of namespace ARM32 3542 } // end of namespace Ice 3543