1 //===- subzero/src/IceInstARM32.h - ARM32 machine instructions --*- C++ -*-===// 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 Declares the InstARM32 and OperandARM32 classes and their subclasses. 12 /// 13 /// This represents the machine instructions and operands used for ARM32 code 14 /// selection. 15 /// 16 //===----------------------------------------------------------------------===// 17 18 #ifndef SUBZERO_SRC_ICEINSTARM32_H 19 #define SUBZERO_SRC_ICEINSTARM32_H 20 21 #include "IceConditionCodesARM32.h" 22 #include "IceDefs.h" 23 #include "IceInst.h" 24 #include "IceInstARM32.def" 25 #include "IceOperand.h" 26 #include "IceRegistersARM32.h" 27 28 namespace Ice { 29 namespace ARM32 { 30 31 /// Encoding of an ARM 32-bit instruction. 32 using IValueT = uint32_t; 33 34 /// An Offset value (+/-) used in an ARM 32-bit instruction. 35 using IOffsetT = int32_t; 36 37 class TargetARM32; 38 39 /// OperandARM32 extends the Operand hierarchy. Its subclasses are 40 /// OperandARM32Mem and OperandARM32Flex. 41 class OperandARM32 : public Operand { 42 OperandARM32() = delete; 43 OperandARM32(const OperandARM32 &) = delete; 44 OperandARM32 &operator=(const OperandARM32 &) = delete; 45 46 public: 47 enum OperandKindARM32 { 48 k__Start = Operand::kTarget, 49 kMem, 50 kShAmtImm, 51 kFlexStart, 52 kFlexImm = kFlexStart, 53 kFlexFpImm, 54 kFlexFpZero, 55 kFlexReg, 56 kFlexEnd = kFlexReg 57 }; 58 59 enum ShiftKind { 60 kNoShift = -1, 61 #define X(enum, emit) enum, 62 ICEINSTARM32SHIFT_TABLE 63 #undef X 64 }; 65 66 using Operand::dump; dump(const Cfg *,Ostream & Str)67 void dump(const Cfg *, Ostream &Str) const override { 68 if (BuildDefs::dump()) 69 Str << "<OperandARM32>"; 70 } 71 72 protected: OperandARM32(OperandKindARM32 Kind,Type Ty)73 OperandARM32(OperandKindARM32 Kind, Type Ty) 74 : Operand(static_cast<OperandKind>(Kind), Ty) {} 75 }; 76 77 /// OperandARM32Mem represents a memory operand in any of the various ARM32 78 /// addressing modes. 79 class OperandARM32Mem : public OperandARM32 { 80 OperandARM32Mem() = delete; 81 OperandARM32Mem(const OperandARM32Mem &) = delete; 82 OperandARM32Mem &operator=(const OperandARM32Mem &) = delete; 83 84 public: 85 /// Memory operand addressing mode. 86 /// The enum value also carries the encoding. 87 // TODO(jvoung): unify with the assembler. 88 enum AddrMode { 89 // bit encoding P U 0 W 90 Offset = (8 | 4 | 0) << 21, // offset (w/o writeback to base) 91 PreIndex = (8 | 4 | 1) << 21, // pre-indexed addressing with writeback 92 PostIndex = (0 | 4 | 0) << 21, // post-indexed addressing with writeback 93 NegOffset = (8 | 0 | 0) << 21, // negative offset (w/o writeback to base) 94 NegPreIndex = (8 | 0 | 1) << 21, // negative pre-indexed with writeback 95 NegPostIndex = (0 | 0 | 0) << 21 // negative post-indexed with writeback 96 }; 97 98 /// Provide two constructors. 99 /// NOTE: The Variable-typed operands have to be registers. 100 /// 101 /// (1) Reg + Imm. The Immediate actually has a limited number of bits 102 /// for encoding, so check canHoldOffset first. It cannot handle general 103 /// Constant operands like ConstantRelocatable, since a relocatable can 104 /// potentially take up too many bits. 105 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, 106 ConstantInteger32 *ImmOffset, 107 AddrMode Mode = Offset) { 108 return new (Func->allocate<OperandARM32Mem>()) 109 OperandARM32Mem(Func, Ty, Base, ImmOffset, Mode); 110 } 111 /// (2) Reg +/- Reg with an optional shift of some kind and amount. Note that 112 /// this mode is disallowed in the NaCl sandbox. 113 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, 114 Variable *Index, ShiftKind ShiftOp = kNoShift, 115 uint16_t ShiftAmt = 0, 116 AddrMode Mode = Offset) { 117 return new (Func->allocate<OperandARM32Mem>()) 118 OperandARM32Mem(Func, Ty, Base, Index, ShiftOp, ShiftAmt, Mode); 119 } getBase()120 Variable *getBase() const { return Base; } getOffset()121 ConstantInteger32 *getOffset() const { return ImmOffset; } getIndex()122 Variable *getIndex() const { return Index; } getShiftOp()123 ShiftKind getShiftOp() const { return ShiftOp; } getShiftAmt()124 uint16_t getShiftAmt() const { return ShiftAmt; } getAddrMode()125 AddrMode getAddrMode() const { return Mode; } 126 isRegReg()127 bool isRegReg() const { return Index != nullptr; } isNegAddrMode()128 bool isNegAddrMode() const { 129 // Positive address modes have the "U" bit set, and negative modes don't. 130 static_assert((PreIndex & (4 << 21)) != 0, 131 "Positive addr modes should have U bit set."); 132 static_assert((NegPreIndex & (4 << 21)) == 0, 133 "Negative addr modes should have U bit clear."); 134 return (Mode & (4 << 21)) == 0; 135 } 136 137 void emit(const Cfg *Func) const override; 138 using OperandARM32::dump; 139 void dump(const Cfg *Func, Ostream &Str) const override; 140 classof(const Operand * Operand)141 static bool classof(const Operand *Operand) { 142 return Operand->getKind() == static_cast<OperandKind>(kMem); 143 } 144 145 /// Return true if a load/store instruction for an element of type Ty can 146 /// encode the Offset directly in the immediate field of the 32-bit ARM 147 /// instruction. For some types, if the load is Sign extending, then the range 148 /// is reduced. 149 static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset); 150 151 private: 152 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, 153 ConstantInteger32 *ImmOffset, AddrMode Mode); 154 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, Variable *Index, 155 ShiftKind ShiftOp, uint16_t ShiftAmt, AddrMode Mode); 156 157 Variable *Base; 158 ConstantInteger32 *ImmOffset; 159 Variable *Index; 160 ShiftKind ShiftOp; 161 uint16_t ShiftAmt; 162 AddrMode Mode; 163 }; 164 165 /// OperandARM32ShAmtImm represents an Immediate that is used in one of the 166 /// shift-by-immediate instructions (lsl, lsr, and asr), and shift-by-immediate 167 /// shifted registers. 168 class OperandARM32ShAmtImm : public OperandARM32 { 169 OperandARM32ShAmtImm() = delete; 170 OperandARM32ShAmtImm(const OperandARM32ShAmtImm &) = delete; 171 OperandARM32ShAmtImm &operator=(const OperandARM32ShAmtImm &) = delete; 172 173 public: create(Cfg * Func,ConstantInteger32 * ShAmt)174 static OperandARM32ShAmtImm *create(Cfg *Func, ConstantInteger32 *ShAmt) { 175 return new (Func->allocate<OperandARM32ShAmtImm>()) 176 OperandARM32ShAmtImm(ShAmt); 177 } 178 classof(const Operand * Operand)179 static bool classof(const Operand *Operand) { 180 return Operand->getKind() == static_cast<OperandKind>(kShAmtImm); 181 } 182 183 void emit(const Cfg *Func) const override; 184 using OperandARM32::dump; 185 void dump(const Cfg *Func, Ostream &Str) const override; 186 getShAmtImm()187 uint32_t getShAmtImm() const { return ShAmt->getValue(); } 188 189 private: 190 explicit OperandARM32ShAmtImm(ConstantInteger32 *SA); 191 192 const ConstantInteger32 *const ShAmt; 193 }; 194 195 /// OperandARM32Flex represent the "flexible second operand" for data-processing 196 /// instructions. It can be a rotatable 8-bit constant, or a register with an 197 /// optional shift operand. The shift amount can even be a third register. 198 class OperandARM32Flex : public OperandARM32 { 199 OperandARM32Flex() = delete; 200 OperandARM32Flex(const OperandARM32Flex &) = delete; 201 OperandARM32Flex &operator=(const OperandARM32Flex &) = delete; 202 203 public: classof(const Operand * Operand)204 static bool classof(const Operand *Operand) { 205 return static_cast<OperandKind>(kFlexStart) <= Operand->getKind() && 206 Operand->getKind() <= static_cast<OperandKind>(kFlexEnd); 207 } 208 209 protected: OperandARM32Flex(OperandKindARM32 Kind,Type Ty)210 OperandARM32Flex(OperandKindARM32 Kind, Type Ty) : OperandARM32(Kind, Ty) {} 211 }; 212 213 /// Rotated immediate variant. 214 class OperandARM32FlexImm : public OperandARM32Flex { 215 OperandARM32FlexImm() = delete; 216 OperandARM32FlexImm(const OperandARM32FlexImm &) = delete; 217 OperandARM32FlexImm &operator=(const OperandARM32FlexImm &) = delete; 218 219 public: 220 /// Immed_8 rotated by an even number of bits (2 * RotateAmt). 221 static OperandARM32FlexImm *create(Cfg *Func, Type Ty, uint32_t Imm, 222 uint32_t RotateAmt); 223 224 void emit(const Cfg *Func) const override; 225 using OperandARM32::dump; 226 void dump(const Cfg *Func, Ostream &Str) const override; 227 classof(const Operand * Operand)228 static bool classof(const Operand *Operand) { 229 return Operand->getKind() == static_cast<OperandKind>(kFlexImm); 230 } 231 232 /// Return true if the Immediate can fit in the ARM flexible operand. Fills in 233 /// the out-params RotateAmt and Immed_8 if Immediate fits. 234 static bool canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, 235 uint32_t *Immed_8); 236 getImm()237 uint32_t getImm() const { return Imm; } getRotateAmt()238 uint32_t getRotateAmt() const { return RotateAmt; } 239 240 private: 241 OperandARM32FlexImm(Cfg *Func, Type Ty, uint32_t Imm, uint32_t RotateAmt); 242 243 uint32_t Imm; 244 uint32_t RotateAmt; 245 }; 246 247 /// Modified Floating-point constant. 248 class OperandARM32FlexFpImm : public OperandARM32Flex { 249 OperandARM32FlexFpImm() = delete; 250 OperandARM32FlexFpImm(const OperandARM32FlexFpImm &) = delete; 251 OperandARM32FlexFpImm &operator=(const OperandARM32FlexFpImm &) = delete; 252 253 public: create(Cfg * Func,Type Ty,uint32_t ModifiedImm)254 static OperandARM32FlexFpImm *create(Cfg *Func, Type Ty, 255 uint32_t ModifiedImm) { 256 return new (Func->allocate<OperandARM32FlexFpImm>()) 257 OperandARM32FlexFpImm(Func, Ty, ModifiedImm); 258 } 259 260 void emit(const Cfg *Func) const override; 261 using OperandARM32::dump; 262 void dump(const Cfg *Func, Ostream &Str) const override; 263 classof(const Operand * Operand)264 static bool classof(const Operand *Operand) { 265 return Operand->getKind() == static_cast<OperandKind>(kFlexFpImm); 266 } 267 268 static bool canHoldImm(const Operand *C, uint32_t *ModifiedImm); 269 getModifiedImm()270 uint32_t getModifiedImm() const { return ModifiedImm; } 271 272 private: 273 OperandARM32FlexFpImm(Cfg *Func, Type Ty, uint32_t ModifiedImm); 274 275 const uint32_t ModifiedImm; 276 }; 277 278 /// An operand for representing the 0.0 immediate in vcmp. 279 class OperandARM32FlexFpZero : public OperandARM32Flex { 280 OperandARM32FlexFpZero() = delete; 281 OperandARM32FlexFpZero(const OperandARM32FlexFpZero &) = delete; 282 OperandARM32FlexFpZero &operator=(const OperandARM32FlexFpZero &) = delete; 283 284 public: create(Cfg * Func,Type Ty)285 static OperandARM32FlexFpZero *create(Cfg *Func, Type Ty) { 286 return new (Func->allocate<OperandARM32FlexFpZero>()) 287 OperandARM32FlexFpZero(Func, Ty); 288 } 289 290 void emit(const Cfg *Func) const override; 291 using OperandARM32::dump; 292 void dump(const Cfg *Func, Ostream &Str) const override; 293 classof(const Operand * Operand)294 static bool classof(const Operand *Operand) { 295 return Operand->getKind() == static_cast<OperandKind>(kFlexFpZero); 296 } 297 298 private: 299 OperandARM32FlexFpZero(Cfg *Func, Type Ty); 300 }; 301 302 /// Shifted register variant. 303 class OperandARM32FlexReg : public OperandARM32Flex { 304 OperandARM32FlexReg() = delete; 305 OperandARM32FlexReg(const OperandARM32FlexReg &) = delete; 306 OperandARM32FlexReg &operator=(const OperandARM32FlexReg &) = delete; 307 308 public: 309 /// Register with immediate/reg shift amount and shift operation. create(Cfg * Func,Type Ty,Variable * Reg,ShiftKind ShiftOp,Operand * ShiftAmt)310 static OperandARM32FlexReg *create(Cfg *Func, Type Ty, Variable *Reg, 311 ShiftKind ShiftOp, Operand *ShiftAmt) { 312 return new (Func->allocate<OperandARM32FlexReg>()) 313 OperandARM32FlexReg(Func, Ty, Reg, ShiftOp, ShiftAmt); 314 } 315 316 void emit(const Cfg *Func) const override; 317 using OperandARM32::dump; 318 void dump(const Cfg *Func, Ostream &Str) const override; 319 classof(const Operand * Operand)320 static bool classof(const Operand *Operand) { 321 return Operand->getKind() == static_cast<OperandKind>(kFlexReg); 322 } 323 getReg()324 Variable *getReg() const { return Reg; } getShiftOp()325 ShiftKind getShiftOp() const { return ShiftOp; } 326 /// ShiftAmt can represent an immediate or a register. getShiftAmt()327 Operand *getShiftAmt() const { return ShiftAmt; } 328 329 private: 330 OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, ShiftKind ShiftOp, 331 Operand *ShiftAmt); 332 333 Variable *Reg; 334 ShiftKind ShiftOp; 335 Operand *ShiftAmt; 336 }; 337 338 /// StackVariable represents a Var that isn't assigned a register (stack-only). 339 /// It is assigned a stack slot, but the slot's offset may be too large to 340 /// represent in the native addressing mode, and so it has a separate base 341 /// register from SP/FP, where the offset from that base register is then in 342 /// range. 343 class StackVariable final : public Variable { 344 StackVariable() = delete; 345 StackVariable(const StackVariable &) = delete; 346 StackVariable &operator=(const StackVariable &) = delete; 347 348 public: create(Cfg * Func,Type Ty,SizeT Index)349 static StackVariable *create(Cfg *Func, Type Ty, SizeT Index) { 350 return new (Func->allocate<StackVariable>()) StackVariable(Func, Ty, Index); 351 } 352 constexpr static auto StackVariableKind = 353 static_cast<OperandKind>(kVariable_Target); classof(const Operand * Operand)354 static bool classof(const Operand *Operand) { 355 return Operand->getKind() == StackVariableKind; 356 } setBaseRegNum(RegNumT RegNum)357 void setBaseRegNum(RegNumT RegNum) { BaseRegNum = RegNum; } getBaseRegNum()358 RegNumT getBaseRegNum() const override { return BaseRegNum; } 359 // Inherit dump() and emit() from Variable. 360 361 private: StackVariable(const Cfg * Func,Type Ty,SizeT Index)362 StackVariable(const Cfg *Func, Type Ty, SizeT Index) 363 : Variable(Func, StackVariableKind, Ty, Index) {} 364 RegNumT BaseRegNum; 365 }; 366 367 /// Base class for ARM instructions. While most ARM instructions can be 368 /// conditionally executed, a few of them are not predicable (halt, memory 369 /// barriers, etc.). 370 class InstARM32 : public InstTarget { 371 InstARM32() = delete; 372 InstARM32(const InstARM32 &) = delete; 373 InstARM32 &operator=(const InstARM32 &) = delete; 374 375 public: 376 // Defines form that assembly instruction should be synthesized. 377 enum EmitForm { Emit_Text, Emit_Binary }; 378 379 enum InstKindARM32 { 380 k__Start = Inst::Target, 381 Adc, 382 Add, 383 And, 384 Asr, 385 Bic, 386 Br, 387 Call, 388 Clz, 389 Cmn, 390 Cmp, 391 Dmb, 392 Eor, 393 Extract, 394 Insert, 395 Label, 396 Ldr, 397 Ldrex, 398 Lsl, 399 Lsr, 400 Nop, 401 Mla, 402 Mls, 403 Mov, 404 Movt, 405 Movw, 406 Mul, 407 Mvn, 408 Orr, 409 Pop, 410 Push, 411 Rbit, 412 Ret, 413 Rev, 414 Rsb, 415 Rsc, 416 Sbc, 417 Sdiv, 418 Str, 419 Strex, 420 Sub, 421 Sxt, 422 Trap, 423 Tst, 424 Udiv, 425 Umull, 426 Uxt, 427 Vabs, 428 Vadd, 429 Vand, 430 Vbsl, 431 Vceq, 432 Vcge, 433 Vcgt, 434 Vcmp, 435 Vcvt, 436 Vdiv, 437 Veor, 438 Vmla, 439 Vmls, 440 Vmrs, 441 Vmul, 442 Vmvn, 443 Vneg, 444 Vorr, 445 Vshl, 446 Vshr, 447 Vsqrt, 448 Vsub 449 }; 450 451 static constexpr size_t InstSize = sizeof(uint32_t); 452 453 static CondARM32::Cond getOppositeCondition(CondARM32::Cond Cond); 454 455 /// Called inside derived methods emit() to communicate that multiple 456 /// instructions are being generated. Used by emitIAS() methods to 457 /// generate textual fixups for instructions that are not yet 458 /// implemented. 459 void startNextInst(const Cfg *Func) const; 460 461 /// FPSign is used for certain vector instructions (particularly, right 462 /// shifts) that require an operand sign specification. 463 enum FPSign { 464 FS_None, 465 FS_Signed, 466 FS_Unsigned, 467 }; 468 /// Shared emit routines for common forms of instructions. 469 /// @{ 470 static void emitThreeAddrFP(const char *Opcode, FPSign Sign, 471 const InstARM32 *Instr, const Cfg *Func, 472 Type OpType); 473 static void emitFourAddrFP(const char *Opcode, FPSign Sign, 474 const InstARM32 *Instr, const Cfg *Func); 475 /// @} 476 477 void dump(const Cfg *Func) const override; 478 479 void emitIAS(const Cfg *Func) const override; 480 481 protected: InstARM32(Cfg * Func,InstKindARM32 Kind,SizeT Maxsrcs,Variable * Dest)482 InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest) 483 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} 484 isClassof(const Inst * Instr,InstKindARM32 MyKind)485 static bool isClassof(const Inst *Instr, InstKindARM32 MyKind) { 486 return Instr->getKind() == static_cast<InstKind>(MyKind); 487 } 488 489 // Generates text of assembly instruction using method emit(), and then adds 490 // to the assembly buffer as a Fixup. 491 void emitUsingTextFixup(const Cfg *Func) const; 492 }; 493 494 /// A predicable ARM instruction. 495 class InstARM32Pred : public InstARM32 { 496 InstARM32Pred() = delete; 497 InstARM32Pred(const InstARM32Pred &) = delete; 498 InstARM32Pred &operator=(const InstARM32Pred &) = delete; 499 500 public: InstARM32Pred(Cfg * Func,InstKindARM32 Kind,SizeT Maxsrcs,Variable * Dest,CondARM32::Cond Predicate)501 InstARM32Pred(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest, 502 CondARM32::Cond Predicate) 503 : InstARM32(Func, Kind, Maxsrcs, Dest), Predicate(Predicate) {} 504 getPredicate()505 CondARM32::Cond getPredicate() const { return Predicate; } setPredicate(CondARM32::Cond Pred)506 void setPredicate(CondARM32::Cond Pred) { Predicate = Pred; } 507 508 static const char *predString(CondARM32::Cond Predicate); 509 void dumpOpcodePred(Ostream &Str, const char *Opcode, Type Ty) const; 510 511 /// Shared emit routines for common forms of instructions. 512 static void emitUnaryopGPR(const char *Opcode, const InstARM32Pred *Instr, 513 const Cfg *Func, bool NeedsWidthSuffix); 514 static void emitUnaryopFP(const char *Opcode, FPSign Sign, 515 const InstARM32Pred *Instr, const Cfg *Func); 516 static void emitTwoAddr(const char *Opcode, const InstARM32Pred *Instr, 517 const Cfg *Func); 518 static void emitThreeAddr(const char *Opcode, const InstARM32Pred *Instr, 519 const Cfg *Func, bool SetFlags); 520 static void emitFourAddr(const char *Opcode, const InstARM32Pred *Instr, 521 const Cfg *Func); 522 static void emitCmpLike(const char *Opcode, const InstARM32Pred *Instr, 523 const Cfg *Func); 524 525 protected: 526 CondARM32::Cond Predicate; 527 }; 528 529 template <typename StreamType> 530 inline StreamType &operator<<(StreamType &Stream, CondARM32::Cond Predicate) { 531 Stream << InstARM32Pred::predString(Predicate); 532 return Stream; 533 } 534 535 /// Instructions of the form x := op(y). 536 template <InstARM32::InstKindARM32 K, bool NeedsWidthSuffix> 537 class InstARM32UnaryopGPR : public InstARM32Pred { 538 InstARM32UnaryopGPR() = delete; 539 InstARM32UnaryopGPR(const InstARM32UnaryopGPR &) = delete; 540 InstARM32UnaryopGPR &operator=(const InstARM32UnaryopGPR &) = delete; 541 542 public: create(Cfg * Func,Variable * Dest,Operand * Src,CondARM32::Cond Predicate)543 static InstARM32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src, 544 CondARM32::Cond Predicate) { 545 return new (Func->allocate<InstARM32UnaryopGPR>()) 546 InstARM32UnaryopGPR(Func, Dest, Src, Predicate); 547 } emit(const Cfg * Func)548 void emit(const Cfg *Func) const override { 549 if (!BuildDefs::dump()) 550 return; 551 emitUnaryopGPR(Opcode, this, Func, NeedsWidthSuffix); 552 } 553 void emitIAS(const Cfg *Func) const override; dump(const Cfg * Func)554 void dump(const Cfg *Func) const override { 555 if (!BuildDefs::dump()) 556 return; 557 Ostream &Str = Func->getContext()->getStrDump(); 558 dumpDest(Func); 559 Str << " = "; 560 dumpOpcodePred(Str, Opcode, getDest()->getType()); 561 Str << " "; 562 dumpSources(Func); 563 } classof(const Inst * Instr)564 static bool classof(const Inst *Instr) { return isClassof(Instr, K); } 565 566 private: InstARM32UnaryopGPR(Cfg * Func,Variable * Dest,Operand * Src,CondARM32::Cond Predicate)567 InstARM32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src, 568 CondARM32::Cond Predicate) 569 : InstARM32Pred(Func, K, 1, Dest, Predicate) { 570 addSource(Src); 571 } 572 573 static const char *Opcode; 574 }; 575 576 /// Instructions of the form x := op(y), for vector/FP. 577 template <InstARM32::InstKindARM32 K> 578 class InstARM32UnaryopFP : public InstARM32Pred { 579 InstARM32UnaryopFP() = delete; 580 InstARM32UnaryopFP(const InstARM32UnaryopFP &) = delete; 581 InstARM32UnaryopFP &operator=(const InstARM32UnaryopFP &) = delete; 582 583 public: create(Cfg * Func,Variable * Dest,Variable * Src,CondARM32::Cond Predicate)584 static InstARM32UnaryopFP *create(Cfg *Func, Variable *Dest, Variable *Src, 585 CondARM32::Cond Predicate) { 586 return new (Func->allocate<InstARM32UnaryopFP>()) 587 InstARM32UnaryopFP(Func, Dest, Src, Predicate); 588 } emit(const Cfg * Func)589 void emit(const Cfg *Func) const override { 590 if (!BuildDefs::dump()) 591 return; 592 emitUnaryopFP(Opcode, Sign, this, Func); 593 } 594 void emitIAS(const Cfg *Func) const override; dump(const Cfg * Func)595 void dump(const Cfg *Func) const override { 596 if (!BuildDefs::dump()) 597 return; 598 Ostream &Str = Func->getContext()->getStrDump(); 599 dumpDest(Func); 600 Str << " = "; 601 dumpOpcodePred(Str, Opcode, getDest()->getType()); 602 Str << " "; 603 dumpSources(Func); 604 } classof(const Inst * Instr)605 static bool classof(const Inst *Instr) { return isClassof(Instr, K); } 606 607 protected: InstARM32UnaryopFP(Cfg * Func,Variable * Dest,Operand * Src,CondARM32::Cond Predicate)608 InstARM32UnaryopFP(Cfg *Func, Variable *Dest, Operand *Src, 609 CondARM32::Cond Predicate) 610 : InstARM32Pred(Func, K, 1, Dest, Predicate) { 611 addSource(Src); 612 } 613 614 FPSign Sign = FS_None; 615 static const char *Opcode; 616 }; 617 618 template <InstARM32::InstKindARM32 K> 619 class InstARM32UnaryopSignAwareFP : public InstARM32UnaryopFP<K> { 620 InstARM32UnaryopSignAwareFP() = delete; 621 InstARM32UnaryopSignAwareFP(const InstARM32UnaryopSignAwareFP &) = delete; 622 InstARM32UnaryopSignAwareFP & 623 operator=(const InstARM32UnaryopSignAwareFP &) = delete; 624 625 public: 626 static InstARM32UnaryopSignAwareFP * create(Cfg * Func,Variable * Dest,Variable * Src,CondARM32::Cond Predicate)627 create(Cfg *Func, Variable *Dest, Variable *Src, CondARM32::Cond Predicate) { 628 return new (Func->allocate<InstARM32UnaryopSignAwareFP>()) 629 InstARM32UnaryopSignAwareFP(Func, Dest, Src, Predicate); 630 } 631 void emitIAS(const Cfg *Func) const override; setSignType(InstARM32::FPSign SignType)632 void setSignType(InstARM32::FPSign SignType) { this->Sign = SignType; } 633 634 private: InstARM32UnaryopSignAwareFP(Cfg * Func,Variable * Dest,Operand * Src,CondARM32::Cond Predicate)635 InstARM32UnaryopSignAwareFP(Cfg *Func, Variable *Dest, Operand *Src, 636 CondARM32::Cond Predicate) 637 : InstARM32UnaryopFP<K>(Func, Dest, Src, Predicate) {} 638 }; 639 640 /// Instructions of the form x := x op y. 641 template <InstARM32::InstKindARM32 K> 642 class InstARM32TwoAddrGPR : public InstARM32Pred { 643 InstARM32TwoAddrGPR() = delete; 644 InstARM32TwoAddrGPR(const InstARM32TwoAddrGPR &) = delete; 645 InstARM32TwoAddrGPR &operator=(const InstARM32TwoAddrGPR &) = delete; 646 647 public: 648 /// Dest must be a register. create(Cfg * Func,Variable * Dest,Operand * Src,CondARM32::Cond Predicate)649 static InstARM32TwoAddrGPR *create(Cfg *Func, Variable *Dest, Operand *Src, 650 CondARM32::Cond Predicate) { 651 return new (Func->allocate<InstARM32TwoAddrGPR>()) 652 InstARM32TwoAddrGPR(Func, Dest, Src, Predicate); 653 } emit(const Cfg * Func)654 void emit(const Cfg *Func) const override { 655 if (!BuildDefs::dump()) 656 return; 657 emitTwoAddr(Opcode, this, Func); 658 } 659 void emitIAS(const Cfg *Func) const override; dump(const Cfg * Func)660 void dump(const Cfg *Func) const override { 661 if (!BuildDefs::dump()) 662 return; 663 Ostream &Str = Func->getContext()->getStrDump(); 664 dumpDest(Func); 665 Str << " = "; 666 dumpOpcodePred(Str, Opcode, getDest()->getType()); 667 Str << " "; 668 dumpSources(Func); 669 } classof(const Inst * Instr)670 static bool classof(const Inst *Instr) { return isClassof(Instr, K); } 671 672 private: InstARM32TwoAddrGPR(Cfg * Func,Variable * Dest,Operand * Src,CondARM32::Cond Predicate)673 InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src, 674 CondARM32::Cond Predicate) 675 : InstARM32Pred(Func, K, 2, Dest, Predicate) { 676 addSource(Dest); 677 addSource(Src); 678 } 679 680 static const char *Opcode; 681 }; 682 683 /// Base class for load instructions. 684 template <InstARM32::InstKindARM32 K> 685 class InstARM32LoadBase : public InstARM32Pred { 686 InstARM32LoadBase() = delete; 687 InstARM32LoadBase(const InstARM32LoadBase &) = delete; 688 InstARM32LoadBase &operator=(const InstARM32LoadBase &) = delete; 689 690 public: create(Cfg * Func,Variable * Dest,Operand * Source,CondARM32::Cond Predicate)691 static InstARM32LoadBase *create(Cfg *Func, Variable *Dest, Operand *Source, 692 CondARM32::Cond Predicate) { 693 return new (Func->allocate<InstARM32LoadBase>()) 694 InstARM32LoadBase(Func, Dest, Source, Predicate); 695 } 696 void emit(const Cfg *Func) const override; 697 void emitIAS(const Cfg *Func) const override; dump(const Cfg * Func)698 void dump(const Cfg *Func) const override { 699 if (!BuildDefs::dump()) 700 return; 701 Ostream &Str = Func->getContext()->getStrDump(); 702 dumpOpcodePred(Str, Opcode, getDest()->getType()); 703 Str << " "; 704 dumpDest(Func); 705 Str << ", "; 706 dumpSources(Func); 707 } classof(const Inst * Instr)708 static bool classof(const Inst *Instr) { return isClassof(Instr, K); } 709 710 private: InstARM32LoadBase(Cfg * Func,Variable * Dest,Operand * Source,CondARM32::Cond Predicate)711 InstARM32LoadBase(Cfg *Func, Variable *Dest, Operand *Source, 712 CondARM32::Cond Predicate) 713 : InstARM32Pred(Func, K, 1, Dest, Predicate) { 714 addSource(Source); 715 } 716 717 static const char *Opcode; 718 }; 719 720 /// Instructions of the form x := y op z. May have the side-effect of setting 721 /// status flags. 722 template <InstARM32::InstKindARM32 K> 723 class InstARM32ThreeAddrGPR : public InstARM32Pred { 724 InstARM32ThreeAddrGPR() = delete; 725 InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete; 726 InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete; 727 728 public: 729 /// Create an ordinary binary-op instruction like add, and sub. Dest and Src1 730 /// must be registers. 731 static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest, 732 Variable *Src0, Operand *Src1, 733 CondARM32::Cond Predicate, 734 bool SetFlags = false) { 735 return new (Func->allocate<InstARM32ThreeAddrGPR>()) 736 InstARM32ThreeAddrGPR(Func, Dest, Src0, Src1, Predicate, SetFlags); 737 } emit(const Cfg * Func)738 void emit(const Cfg *Func) const override { 739 if (!BuildDefs::dump()) 740 return; 741 emitThreeAddr(Opcode, this, Func, SetFlags); 742 } 743 void emitIAS(const Cfg *Func) const override; dump(const Cfg * Func)744 void dump(const Cfg *Func) const override { 745 if (!BuildDefs::dump()) 746 return; 747 Ostream &Str = Func->getContext()->getStrDump(); 748 dumpDest(Func); 749 Str << " = "; 750 dumpOpcodePred(Str, Opcode, getDest()->getType()); 751 Str << (SetFlags ? ".s " : " "); 752 dumpSources(Func); 753 } classof(const Inst * Instr)754 static bool classof(const Inst *Instr) { return isClassof(Instr, K); } 755 756 private: InstARM32ThreeAddrGPR(Cfg * Func,Variable * Dest,Variable * Src0,Operand * Src1,CondARM32::Cond Predicate,bool SetFlags)757 InstARM32ThreeAddrGPR(Cfg *Func, Variable *Dest, Variable *Src0, 758 Operand *Src1, CondARM32::Cond Predicate, bool SetFlags) 759 : InstARM32Pred(Func, K, 2, Dest, Predicate), SetFlags(SetFlags) { 760 HasSideEffects = SetFlags; 761 addSource(Src0); 762 addSource(Src1); 763 } 764 765 static const char *Opcode; 766 bool SetFlags; 767 }; 768 769 /// Instructions of the form x := y op z, for vector/FP. We leave these as 770 /// unconditional: "ARM deprecates the conditional execution of any instruction 771 /// encoding provided by the Advanced SIMD Extension that is not also provided 772 /// by the floating-point (VFP) extension". They do not set flags. 773 template <InstARM32::InstKindARM32 K> 774 class InstARM32ThreeAddrFP : public InstARM32 { 775 InstARM32ThreeAddrFP() = delete; 776 InstARM32ThreeAddrFP(const InstARM32ThreeAddrFP &) = delete; 777 InstARM32ThreeAddrFP &operator=(const InstARM32ThreeAddrFP &) = delete; 778 779 public: 780 /// Create a vector/FP binary-op instruction like vadd, and vsub. Everything 781 /// must be a register. create(Cfg * Func,Variable * Dest,Variable * Src0,Variable * Src1)782 static InstARM32ThreeAddrFP *create(Cfg *Func, Variable *Dest, Variable *Src0, 783 Variable *Src1) { 784 return new (Func->allocate<InstARM32ThreeAddrFP>()) 785 InstARM32ThreeAddrFP(Func, Dest, Src0, Src1); 786 } emit(const Cfg * Func)787 void emit(const Cfg *Func) const override { 788 if (!BuildDefs::dump()) 789 return; 790 const Type OpType = (isVectorCompare() ? getSrc(0) : getDest())->getType(); 791 emitThreeAddrFP(Opcode, Sign, this, Func, OpType); 792 } 793 void emitIAS(const Cfg *Func) const override; dump(const Cfg * Func)794 void dump(const Cfg *Func) const override { 795 if (!BuildDefs::dump()) 796 return; 797 Ostream &Str = Func->getContext()->getStrDump(); 798 dumpDest(Func); 799 const Type OpType = (isVectorCompare() ? getSrc(0) : getDest())->getType(); 800 Str << " = " << Opcode << "." << OpType << " "; 801 dumpSources(Func); 802 } classof(const Inst * Instr)803 static bool classof(const Inst *Instr) { return isClassof(Instr, K); } 804 805 protected: 806 FPSign Sign = FS_None; 807 InstARM32ThreeAddrFP(Cfg * Func,Variable * Dest,Variable * Src0,Operand * Src1)808 InstARM32ThreeAddrFP(Cfg *Func, Variable *Dest, Variable *Src0, Operand *Src1) 809 : InstARM32(Func, K, 2, Dest) { 810 addSource(Src0); 811 addSource(Src1); 812 } 813 814 static const char *Opcode; 815 816 private: isVectorCompare()817 static constexpr bool isVectorCompare() { 818 return K == InstARM32::Vceq || K == InstARM32::Vcgt || K == InstARM32::Vcge; 819 } 820 }; 821 822 template <InstARM32::InstKindARM32 K> 823 class InstARM32ThreeAddrSignAwareFP : public InstARM32ThreeAddrFP<K> { 824 InstARM32ThreeAddrSignAwareFP() = delete; 825 InstARM32ThreeAddrSignAwareFP(const InstARM32ThreeAddrSignAwareFP &) = delete; 826 InstARM32ThreeAddrSignAwareFP & 827 operator=(const InstARM32ThreeAddrSignAwareFP &) = delete; 828 829 public: 830 /// Create a vector/FP binary-op instruction like vadd, and vsub. Everything 831 /// must be a register. create(Cfg * Func,Variable * Dest,Variable * Src0,Variable * Src1)832 static InstARM32ThreeAddrSignAwareFP *create(Cfg *Func, Variable *Dest, 833 Variable *Src0, Variable *Src1) { 834 return new (Func->allocate<InstARM32ThreeAddrSignAwareFP>()) 835 InstARM32ThreeAddrSignAwareFP(Func, Dest, Src0, Src1); 836 } 837 838 static InstARM32ThreeAddrSignAwareFP * create(Cfg * Func,Variable * Dest,Variable * Src0,ConstantInteger32 * Src1)839 create(Cfg *Func, Variable *Dest, Variable *Src0, ConstantInteger32 *Src1) { 840 return new (Func->allocate<InstARM32ThreeAddrSignAwareFP>()) 841 InstARM32ThreeAddrSignAwareFP(Func, Dest, Src0, Src1); 842 } 843 844 void emitIAS(const Cfg *Func) const override; setSignType(InstARM32::FPSign SignType)845 void setSignType(InstARM32::FPSign SignType) { this->Sign = SignType; } 846 847 private: InstARM32ThreeAddrSignAwareFP(Cfg * Func,Variable * Dest,Variable * Src0,Operand * Src1)848 InstARM32ThreeAddrSignAwareFP(Cfg *Func, Variable *Dest, Variable *Src0, 849 Operand *Src1) 850 : InstARM32ThreeAddrFP<K>(Func, Dest, Src0, Src1) {} 851 }; 852 853 /// Instructions of the form x := a op1 (y op2 z). E.g., multiply accumulate. 854 template <InstARM32::InstKindARM32 K> 855 class InstARM32FourAddrGPR : public InstARM32Pred { 856 InstARM32FourAddrGPR() = delete; 857 InstARM32FourAddrGPR(const InstARM32FourAddrGPR &) = delete; 858 InstARM32FourAddrGPR &operator=(const InstARM32FourAddrGPR &) = delete; 859 860 public: 861 // Every operand must be a register. create(Cfg * Func,Variable * Dest,Variable * Src0,Variable * Src1,Variable * Src2,CondARM32::Cond Predicate)862 static InstARM32FourAddrGPR *create(Cfg *Func, Variable *Dest, Variable *Src0, 863 Variable *Src1, Variable *Src2, 864 CondARM32::Cond Predicate) { 865 return new (Func->allocate<InstARM32FourAddrGPR>()) 866 InstARM32FourAddrGPR(Func, Dest, Src0, Src1, Src2, Predicate); 867 } emit(const Cfg * Func)868 void emit(const Cfg *Func) const override { 869 if (!BuildDefs::dump()) 870 return; 871 emitFourAddr(Opcode, this, Func); 872 } 873 void emitIAS(const Cfg *Func) const override; dump(const Cfg * Func)874 void dump(const Cfg *Func) const override { 875 if (!BuildDefs::dump()) 876 return; 877 Ostream &Str = Func->getContext()->getStrDump(); 878 dumpDest(Func); 879 Str << " = "; 880 dumpOpcodePred(Str, Opcode, getDest()->getType()); 881 Str << " "; 882 dumpSources(Func); 883 } classof(const Inst * Instr)884 static bool classof(const Inst *Instr) { return isClassof(Instr, K); } 885 886 private: InstARM32FourAddrGPR(Cfg * Func,Variable * Dest,Variable * Src0,Variable * Src1,Variable * Src2,CondARM32::Cond Predicate)887 InstARM32FourAddrGPR(Cfg *Func, Variable *Dest, Variable *Src0, 888 Variable *Src1, Variable *Src2, 889 CondARM32::Cond Predicate) 890 : InstARM32Pred(Func, K, 3, Dest, Predicate) { 891 addSource(Src0); 892 addSource(Src1); 893 addSource(Src2); 894 } 895 896 static const char *Opcode; 897 }; 898 899 /// Instructions of the form x := x op1 (y op2 z). E.g., multiply accumulate. 900 /// We leave these as unconditional: "ARM deprecates the conditional execution 901 /// of any instruction encoding provided by the Advanced SIMD Extension that is 902 /// not also provided by the floating-point (VFP) extension". They do not set 903 /// flags. 904 template <InstARM32::InstKindARM32 K> 905 class InstARM32FourAddrFP : public InstARM32 { 906 InstARM32FourAddrFP() = delete; 907 InstARM32FourAddrFP(const InstARM32FourAddrFP &) = delete; 908 InstARM32FourAddrFP &operator=(const InstARM32FourAddrFP &) = delete; 909 910 public: 911 // Every operand must be a register. create(Cfg * Func,Variable * Dest,Variable * Src0,Variable * Src1)912 static InstARM32FourAddrFP *create(Cfg *Func, Variable *Dest, Variable *Src0, 913 Variable *Src1) { 914 return new (Func->allocate<InstARM32FourAddrFP>()) 915 InstARM32FourAddrFP(Func, Dest, Src0, Src1); 916 } emit(const Cfg * Func)917 void emit(const Cfg *Func) const override { 918 if (!BuildDefs::dump()) 919 return; 920 emitFourAddrFP(Opcode, Sign, this, Func); 921 } 922 void emitIAS(const Cfg *Func) const override; dump(const Cfg * Func)923 void dump(const Cfg *Func) const override { 924 if (!BuildDefs::dump()) 925 return; 926 Ostream &Str = Func->getContext()->getStrDump(); 927 dumpDest(Func); 928 Str << " = "; 929 Str << Opcode << "." << getDest()->getType() << " "; 930 dumpDest(Func); 931 Str << ", "; 932 dumpSources(Func); 933 } classof(const Inst * Instr)934 static bool classof(const Inst *Instr) { return isClassof(Instr, K); } 935 936 private: InstARM32FourAddrFP(Cfg * Func,Variable * Dest,Variable * Src0,Variable * Src1)937 InstARM32FourAddrFP(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1) 938 : InstARM32(Func, K, 3, Dest) { 939 addSource(Dest); 940 addSource(Src0); 941 addSource(Src1); 942 } 943 944 FPSign Sign = FS_None; 945 static const char *Opcode; 946 }; 947 948 /// Instructions of the form x cmpop y (setting flags). 949 template <InstARM32::InstKindARM32 K> 950 class InstARM32CmpLike : public InstARM32Pred { 951 InstARM32CmpLike() = delete; 952 InstARM32CmpLike(const InstARM32CmpLike &) = delete; 953 InstARM32CmpLike &operator=(const InstARM32CmpLike &) = delete; 954 955 public: create(Cfg * Func,Variable * Src0,Operand * Src1,CondARM32::Cond Predicate)956 static InstARM32CmpLike *create(Cfg *Func, Variable *Src0, Operand *Src1, 957 CondARM32::Cond Predicate) { 958 return new (Func->allocate<InstARM32CmpLike>()) 959 InstARM32CmpLike(Func, Src0, Src1, Predicate); 960 } emit(const Cfg * Func)961 void emit(const Cfg *Func) const override { 962 if (!BuildDefs::dump()) 963 return; 964 emitCmpLike(Opcode, this, Func); 965 } 966 void emitIAS(const Cfg *Func) const override; dump(const Cfg * Func)967 void dump(const Cfg *Func) const override { 968 if (!BuildDefs::dump()) 969 return; 970 Ostream &Str = Func->getContext()->getStrDump(); 971 dumpOpcodePred(Str, Opcode, getSrc(0)->getType()); 972 Str << " "; 973 dumpSources(Func); 974 } classof(const Inst * Instr)975 static bool classof(const Inst *Instr) { return isClassof(Instr, K); } 976 977 private: InstARM32CmpLike(Cfg * Func,Variable * Src0,Operand * Src1,CondARM32::Cond Predicate)978 InstARM32CmpLike(Cfg *Func, Variable *Src0, Operand *Src1, 979 CondARM32::Cond Predicate) 980 : InstARM32Pred(Func, K, 2, nullptr, Predicate) { 981 HasSideEffects = true; 982 addSource(Src0); 983 addSource(Src1); 984 } 985 986 static const char *Opcode; 987 }; 988 989 using InstARM32Adc = InstARM32ThreeAddrGPR<InstARM32::Adc>; 990 using InstARM32Add = InstARM32ThreeAddrGPR<InstARM32::Add>; 991 using InstARM32And = InstARM32ThreeAddrGPR<InstARM32::And>; 992 using InstARM32Asr = InstARM32ThreeAddrGPR<InstARM32::Asr>; 993 using InstARM32Bic = InstARM32ThreeAddrGPR<InstARM32::Bic>; 994 using InstARM32Eor = InstARM32ThreeAddrGPR<InstARM32::Eor>; 995 using InstARM32Lsl = InstARM32ThreeAddrGPR<InstARM32::Lsl>; 996 using InstARM32Lsr = InstARM32ThreeAddrGPR<InstARM32::Lsr>; 997 using InstARM32Mul = InstARM32ThreeAddrGPR<InstARM32::Mul>; 998 using InstARM32Orr = InstARM32ThreeAddrGPR<InstARM32::Orr>; 999 using InstARM32Rsb = InstARM32ThreeAddrGPR<InstARM32::Rsb>; 1000 using InstARM32Rsc = InstARM32ThreeAddrGPR<InstARM32::Rsc>; 1001 using InstARM32Sbc = InstARM32ThreeAddrGPR<InstARM32::Sbc>; 1002 using InstARM32Sdiv = InstARM32ThreeAddrGPR<InstARM32::Sdiv>; 1003 using InstARM32Sub = InstARM32ThreeAddrGPR<InstARM32::Sub>; 1004 using InstARM32Udiv = InstARM32ThreeAddrGPR<InstARM32::Udiv>; 1005 using InstARM32Vadd = InstARM32ThreeAddrFP<InstARM32::Vadd>; 1006 using InstARM32Vand = InstARM32ThreeAddrFP<InstARM32::Vand>; 1007 using InstARM32Vbsl = InstARM32ThreeAddrFP<InstARM32::Vbsl>; 1008 using InstARM32Vceq = InstARM32ThreeAddrFP<InstARM32::Vceq>; 1009 using InstARM32Vcge = InstARM32ThreeAddrSignAwareFP<InstARM32::Vcge>; 1010 using InstARM32Vcgt = InstARM32ThreeAddrSignAwareFP<InstARM32::Vcgt>; 1011 using InstARM32Vdiv = InstARM32ThreeAddrFP<InstARM32::Vdiv>; 1012 using InstARM32Veor = InstARM32ThreeAddrFP<InstARM32::Veor>; 1013 using InstARM32Vmla = InstARM32FourAddrFP<InstARM32::Vmla>; 1014 using InstARM32Vmls = InstARM32FourAddrFP<InstARM32::Vmls>; 1015 using InstARM32Vmul = InstARM32ThreeAddrFP<InstARM32::Vmul>; 1016 using InstARM32Vmvn = InstARM32UnaryopFP<InstARM32::Vmvn>; 1017 using InstARM32Vneg = InstARM32UnaryopSignAwareFP<InstARM32::Vneg>; 1018 using InstARM32Vorr = InstARM32ThreeAddrFP<InstARM32::Vorr>; 1019 using InstARM32Vshl = InstARM32ThreeAddrSignAwareFP<InstARM32::Vshl>; 1020 using InstARM32Vshr = InstARM32ThreeAddrSignAwareFP<InstARM32::Vshr>; 1021 using InstARM32Vsub = InstARM32ThreeAddrFP<InstARM32::Vsub>; 1022 using InstARM32Ldr = InstARM32LoadBase<InstARM32::Ldr>; 1023 using InstARM32Ldrex = InstARM32LoadBase<InstARM32::Ldrex>; 1024 /// MovT leaves the bottom bits alone so dest is also a source. This helps 1025 /// indicate that a previous MovW setting dest is not dead code. 1026 using InstARM32Movt = InstARM32TwoAddrGPR<InstARM32::Movt>; 1027 using InstARM32Movw = InstARM32UnaryopGPR<InstARM32::Movw, false>; 1028 using InstARM32Clz = InstARM32UnaryopGPR<InstARM32::Clz, false>; 1029 using InstARM32Mvn = InstARM32UnaryopGPR<InstARM32::Mvn, false>; 1030 using InstARM32Rbit = InstARM32UnaryopGPR<InstARM32::Rbit, false>; 1031 using InstARM32Rev = InstARM32UnaryopGPR<InstARM32::Rev, false>; 1032 // Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation operand 1033 // as well (rotate source by 8, 16, 24 bits prior to extending), but we aren't 1034 // using that for now, so just model as a Unaryop. 1035 using InstARM32Sxt = InstARM32UnaryopGPR<InstARM32::Sxt, true>; 1036 using InstARM32Uxt = InstARM32UnaryopGPR<InstARM32::Uxt, true>; 1037 using InstARM32Vsqrt = InstARM32UnaryopFP<InstARM32::Vsqrt>; 1038 using InstARM32Mla = InstARM32FourAddrGPR<InstARM32::Mla>; 1039 using InstARM32Mls = InstARM32FourAddrGPR<InstARM32::Mls>; 1040 using InstARM32Cmn = InstARM32CmpLike<InstARM32::Cmn>; 1041 using InstARM32Cmp = InstARM32CmpLike<InstARM32::Cmp>; 1042 using InstARM32Tst = InstARM32CmpLike<InstARM32::Tst>; 1043 1044 // InstARM32Label represents an intra-block label that is the target of an 1045 // intra-block branch. The offset between the label and the branch must be fit 1046 // in the instruction immediate (considered "near"). 1047 class InstARM32Label : public InstARM32 { 1048 InstARM32Label() = delete; 1049 InstARM32Label(const InstARM32Label &) = delete; 1050 InstARM32Label &operator=(const InstARM32Label &) = delete; 1051 1052 public: create(Cfg * Func,TargetARM32 * Target)1053 static InstARM32Label *create(Cfg *Func, TargetARM32 *Target) { 1054 return new (Func->allocate<InstARM32Label>()) InstARM32Label(Func, Target); 1055 } getEmitInstCount()1056 uint32_t getEmitInstCount() const override { return 0; } getLabelName()1057 GlobalString getLabelName() const { return Name; } getNumber()1058 SizeT getNumber() const { return Number; } 1059 void emit(const Cfg *Func) const override; 1060 void emitIAS(const Cfg *Func) const override; 1061 void dump(const Cfg *Func) const override; setRelocOffset(RelocOffset * Value)1062 void setRelocOffset(RelocOffset *Value) { OffsetReloc = Value; } 1063 1064 private: 1065 InstARM32Label(Cfg *Func, TargetARM32 *Target); 1066 1067 RelocOffset *OffsetReloc = nullptr; 1068 SizeT Number; // used for unique label generation. 1069 GlobalString Name; 1070 }; 1071 1072 /// Direct branch instruction. 1073 class InstARM32Br : public InstARM32Pred { 1074 InstARM32Br() = delete; 1075 InstARM32Br(const InstARM32Br &) = delete; 1076 InstARM32Br &operator=(const InstARM32Br &) = delete; 1077 1078 public: 1079 /// Create a conditional branch to one of two nodes. create(Cfg * Func,CfgNode * TargetTrue,CfgNode * TargetFalse,CondARM32::Cond Predicate)1080 static InstARM32Br *create(Cfg *Func, CfgNode *TargetTrue, 1081 CfgNode *TargetFalse, CondARM32::Cond Predicate) { 1082 assert(Predicate != CondARM32::AL); 1083 constexpr InstARM32Label *NoLabel = nullptr; 1084 return new (Func->allocate<InstARM32Br>()) 1085 InstARM32Br(Func, TargetTrue, TargetFalse, NoLabel, Predicate); 1086 } 1087 /// Create an unconditional branch to a node. create(Cfg * Func,CfgNode * Target)1088 static InstARM32Br *create(Cfg *Func, CfgNode *Target) { 1089 constexpr CfgNode *NoCondTarget = nullptr; 1090 constexpr InstARM32Label *NoLabel = nullptr; 1091 return new (Func->allocate<InstARM32Br>()) 1092 InstARM32Br(Func, NoCondTarget, Target, NoLabel, CondARM32::AL); 1093 } 1094 /// Create a non-terminator conditional branch to a node, with a fallthrough 1095 /// to the next instruction in the current node. This is used for switch 1096 /// lowering. create(Cfg * Func,CfgNode * Target,CondARM32::Cond Predicate)1097 static InstARM32Br *create(Cfg *Func, CfgNode *Target, 1098 CondARM32::Cond Predicate) { 1099 assert(Predicate != CondARM32::AL); 1100 constexpr CfgNode *NoUncondTarget = nullptr; 1101 constexpr InstARM32Label *NoLabel = nullptr; 1102 return new (Func->allocate<InstARM32Br>()) 1103 InstARM32Br(Func, Target, NoUncondTarget, NoLabel, Predicate); 1104 } 1105 // Create a conditional intra-block branch (or unconditional, if 1106 // Condition==AL) to a label in the current block. create(Cfg * Func,InstARM32Label * Label,CondARM32::Cond Predicate)1107 static InstARM32Br *create(Cfg *Func, InstARM32Label *Label, 1108 CondARM32::Cond Predicate) { 1109 constexpr CfgNode *NoCondTarget = nullptr; 1110 constexpr CfgNode *NoUncondTarget = nullptr; 1111 return new (Func->allocate<InstARM32Br>()) 1112 InstARM32Br(Func, NoCondTarget, NoUncondTarget, Label, Predicate); 1113 } getTargetTrue()1114 const CfgNode *getTargetTrue() const { return TargetTrue; } getTargetFalse()1115 const CfgNode *getTargetFalse() const { return TargetFalse; } 1116 bool optimizeBranch(const CfgNode *NextNode); getEmitInstCount()1117 uint32_t getEmitInstCount() const override { 1118 uint32_t Sum = 0; 1119 if (Label) 1120 ++Sum; 1121 if (getTargetTrue()) 1122 ++Sum; 1123 if (getTargetFalse()) 1124 ++Sum; 1125 return Sum; 1126 } isUnconditionalBranch()1127 bool isUnconditionalBranch() const override { 1128 return getPredicate() == CondARM32::AL; 1129 } 1130 bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override; 1131 void emit(const Cfg *Func) const override; 1132 void emitIAS(const Cfg *Func) const override; 1133 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1134 static bool classof(const Inst *Instr) { return isClassof(Instr, Br); } 1135 1136 private: 1137 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, 1138 const InstARM32Label *Label, CondARM32::Cond Predicate); 1139 1140 const CfgNode *TargetTrue; 1141 const CfgNode *TargetFalse; 1142 const InstARM32Label *Label; // Intra-block branch target 1143 }; 1144 1145 /// Call instruction (bl/blx). Arguments should have already been pushed. 1146 /// Technically bl and the register form of blx can be predicated, but we'll 1147 /// leave that out until needed. 1148 class InstARM32Call : public InstARM32 { 1149 InstARM32Call() = delete; 1150 InstARM32Call(const InstARM32Call &) = delete; 1151 InstARM32Call &operator=(const InstARM32Call &) = delete; 1152 1153 public: create(Cfg * Func,Variable * Dest,Operand * CallTarget)1154 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { 1155 return new (Func->allocate<InstARM32Call>()) 1156 InstARM32Call(Func, Dest, CallTarget); 1157 } getCallTarget()1158 Operand *getCallTarget() const { return getSrc(0); } 1159 void emit(const Cfg *Func) const override; 1160 void emitIAS(const Cfg *Func) const override; 1161 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1162 static bool classof(const Inst *Instr) { return isClassof(Instr, Call); } 1163 1164 private: 1165 InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget); 1166 }; 1167 1168 class InstARM32RegisterStackOp : public InstARM32 { 1169 InstARM32RegisterStackOp() = delete; 1170 InstARM32RegisterStackOp(const InstARM32RegisterStackOp &) = delete; 1171 InstARM32RegisterStackOp & 1172 operator=(const InstARM32RegisterStackOp &) = delete; 1173 1174 public: 1175 void emit(const Cfg *Func) const override; 1176 void emitIAS(const Cfg *Func) const override; 1177 void dump(const Cfg *Func) const override; 1178 1179 protected: InstARM32RegisterStackOp(Cfg * Func,InstKindARM32 Kind,SizeT Maxsrcs,Variable * Dest)1180 InstARM32RegisterStackOp(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, 1181 Variable *Dest) 1182 : InstARM32(Func, Kind, Maxsrcs, Dest) {} 1183 void emitUsingForm(const Cfg *Func, const EmitForm Form) const; 1184 void emitGPRsAsText(const Cfg *Func) const; 1185 void emitSRegsAsText(const Cfg *Func, const Variable *BaseReg, 1186 SizeT Regcount) const; 1187 void emitSRegsOp(const Cfg *Func, const EmitForm, const Variable *BaseReg, 1188 SizeT RegCount, SizeT InstIndex) const; getDumpOpcode()1189 virtual const char *getDumpOpcode() const { return getGPROpcode(); } 1190 virtual const char *getGPROpcode() const = 0; 1191 virtual const char *getSRegOpcode() const = 0; 1192 virtual Variable *getStackReg(SizeT Index) const = 0; 1193 virtual SizeT getNumStackRegs() const = 0; 1194 virtual void emitSingleGPR(const Cfg *Func, const EmitForm Form, 1195 const Variable *Reg) const = 0; 1196 virtual void emitMultipleGPRs(const Cfg *Func, const EmitForm Form, 1197 IValueT Registers) const = 0; 1198 virtual void emitSRegs(const Cfg *Func, const EmitForm Form, 1199 const Variable *BaseReg, SizeT RegCount) const = 0; 1200 }; 1201 1202 /// Pops a list of registers. It may be a list of GPRs, or a list of VFP "s" 1203 /// regs, but not both. In any case, the list must be sorted. 1204 class InstARM32Pop final : public InstARM32RegisterStackOp { 1205 InstARM32Pop() = delete; 1206 InstARM32Pop(const InstARM32Pop &) = delete; 1207 InstARM32Pop &operator=(const InstARM32Pop &) = delete; 1208 1209 public: create(Cfg * Func,const VarList & Dests)1210 static InstARM32Pop *create(Cfg *Func, const VarList &Dests) { 1211 return new (Func->allocate<InstARM32Pop>()) InstARM32Pop(Func, Dests); 1212 } classof(const Inst * Instr)1213 static bool classof(const Inst *Instr) { return isClassof(Instr, Pop); } 1214 1215 private: 1216 InstARM32Pop(Cfg *Func, const VarList &Dests); 1217 virtual const char *getGPROpcode() const final; 1218 virtual const char *getSRegOpcode() const final; 1219 Variable *getStackReg(SizeT Index) const final; 1220 SizeT getNumStackRegs() const final; 1221 void emitSingleGPR(const Cfg *Func, const EmitForm Form, 1222 const Variable *Reg) const final; 1223 void emitMultipleGPRs(const Cfg *Func, const EmitForm Form, 1224 IValueT Registers) const final; 1225 void emitSRegs(const Cfg *Func, const EmitForm Form, const Variable *BaseReg, 1226 SizeT RegCount) const final; 1227 VarList Dests; 1228 }; 1229 1230 /// Pushes a list of registers. Just like Pop (see above), the list may be of 1231 /// GPRs, or VFP "s" registers, but not both. 1232 class InstARM32Push final : public InstARM32RegisterStackOp { 1233 InstARM32Push() = delete; 1234 InstARM32Push(const InstARM32Push &) = delete; 1235 InstARM32Push &operator=(const InstARM32Push &) = delete; 1236 1237 public: create(Cfg * Func,const VarList & Srcs)1238 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) { 1239 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); 1240 } classof(const Inst * Instr)1241 static bool classof(const Inst *Instr) { return isClassof(Instr, Push); } 1242 1243 private: 1244 InstARM32Push(Cfg *Func, const VarList &Srcs); 1245 const char *getGPROpcode() const final; 1246 const char *getSRegOpcode() const final; 1247 Variable *getStackReg(SizeT Index) const final; 1248 SizeT getNumStackRegs() const final; 1249 void emitSingleGPR(const Cfg *Func, const EmitForm Form, 1250 const Variable *Reg) const final; 1251 void emitMultipleGPRs(const Cfg *Func, const EmitForm Form, 1252 IValueT Registers) const final; 1253 void emitSRegs(const Cfg *Func, const EmitForm Form, const Variable *BaseReg, 1254 SizeT RegCount) const final; 1255 }; 1256 1257 /// Ret pseudo-instruction. This is actually a "bx" instruction with an "lr" 1258 /// register operand, but epilogue lowering will search for a Ret instead of a 1259 /// generic "bx". This instruction also takes a Source operand (for non-void 1260 /// returning functions) for liveness analysis, though a FakeUse before the ret 1261 /// would do just as well. 1262 /// 1263 /// NOTE: Even though "bx" can be predicated, for now leave out the predication 1264 /// since it's not yet known to be useful for Ret. That may complicate finding 1265 /// the terminator instruction if it's not guaranteed to be executed. 1266 class InstARM32Ret : public InstARM32 { 1267 InstARM32Ret() = delete; 1268 InstARM32Ret(const InstARM32Ret &) = delete; 1269 InstARM32Ret &operator=(const InstARM32Ret &) = delete; 1270 1271 public: 1272 static InstARM32Ret *create(Cfg *Func, Variable *LR, 1273 Variable *Source = nullptr) { 1274 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); 1275 } 1276 void emit(const Cfg *Func) const override; 1277 void emitIAS(const Cfg *Func) const override; 1278 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1279 static bool classof(const Inst *Instr) { return isClassof(Instr, Ret); } 1280 1281 private: 1282 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); 1283 }; 1284 1285 /// Store instruction. It's important for liveness that there is no Dest operand 1286 /// (OperandARM32Mem instead of Dest Variable). 1287 class InstARM32Str final : public InstARM32Pred { 1288 InstARM32Str() = delete; 1289 InstARM32Str(const InstARM32Str &) = delete; 1290 InstARM32Str &operator=(const InstARM32Str &) = delete; 1291 1292 public: 1293 /// Value must be a register. create(Cfg * Func,Variable * Value,OperandARM32Mem * Mem,CondARM32::Cond Predicate)1294 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, 1295 CondARM32::Cond Predicate) { 1296 return new (Func->allocate<InstARM32Str>()) 1297 InstARM32Str(Func, Value, Mem, Predicate); 1298 } 1299 void emit(const Cfg *Func) const override; 1300 void emitIAS(const Cfg *Func) const override; 1301 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1302 static bool classof(const Inst *Instr) { return isClassof(Instr, Str); } 1303 1304 private: 1305 InstARM32Str(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, 1306 CondARM32::Cond Predicate); 1307 }; 1308 1309 /// Exclusive Store instruction. Like its non-exclusive sibling, it's important 1310 /// for liveness that there is no Dest operand (OperandARM32Mem instead of Dest 1311 /// Variable). 1312 class InstARM32Strex final : public InstARM32Pred { 1313 InstARM32Strex() = delete; 1314 InstARM32Strex(const InstARM32Strex &) = delete; 1315 InstARM32Strex &operator=(const InstARM32Strex &) = delete; 1316 1317 public: 1318 /// Value must be a register. create(Cfg * Func,Variable * Dest,Variable * Value,OperandARM32Mem * Mem,CondARM32::Cond Predicate)1319 static InstARM32Strex *create(Cfg *Func, Variable *Dest, Variable *Value, 1320 OperandARM32Mem *Mem, 1321 CondARM32::Cond Predicate) { 1322 return new (Func->allocate<InstARM32Strex>()) 1323 InstARM32Strex(Func, Dest, Value, Mem, Predicate); 1324 } 1325 void emit(const Cfg *Func) const override; 1326 void emitIAS(const Cfg *Func) const override; 1327 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1328 static bool classof(const Inst *Instr) { return isClassof(Instr, Strex); } 1329 1330 private: 1331 InstARM32Strex(Cfg *Func, Variable *Dest, Variable *Value, 1332 OperandARM32Mem *Mem, CondARM32::Cond Predicate); 1333 }; 1334 1335 class InstARM32Trap : public InstARM32 { 1336 InstARM32Trap() = delete; 1337 InstARM32Trap(const InstARM32Trap &) = delete; 1338 InstARM32Trap &operator=(const InstARM32Trap &) = delete; 1339 1340 public: create(Cfg * Func)1341 static InstARM32Trap *create(Cfg *Func) { 1342 return new (Func->allocate<InstARM32Trap>()) InstARM32Trap(Func); 1343 } 1344 void emit(const Cfg *Func) const override; 1345 void emitIAS(const Cfg *Func) const override; 1346 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1347 static bool classof(const Inst *Instr) { return isClassof(Instr, Trap); } 1348 1349 private: 1350 explicit InstARM32Trap(Cfg *Func); 1351 }; 1352 1353 /// Unsigned Multiply Long: d.lo, d.hi := x * y 1354 class InstARM32Umull : public InstARM32Pred { 1355 InstARM32Umull() = delete; 1356 InstARM32Umull(const InstARM32Umull &) = delete; 1357 InstARM32Umull &operator=(const InstARM32Umull &) = delete; 1358 1359 public: 1360 /// Everything must be a register. create(Cfg * Func,Variable * DestLo,Variable * DestHi,Variable * Src0,Variable * Src1,CondARM32::Cond Predicate)1361 static InstARM32Umull *create(Cfg *Func, Variable *DestLo, Variable *DestHi, 1362 Variable *Src0, Variable *Src1, 1363 CondARM32::Cond Predicate) { 1364 return new (Func->allocate<InstARM32Umull>()) 1365 InstARM32Umull(Func, DestLo, DestHi, Src0, Src1, Predicate); 1366 } 1367 void emit(const Cfg *Func) const override; 1368 void emitIAS(const Cfg *Func) const override; 1369 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1370 static bool classof(const Inst *Instr) { return isClassof(Instr, Umull); } 1371 1372 private: 1373 InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, Variable *Src0, 1374 Variable *Src1, CondARM32::Cond Predicate); 1375 1376 Variable *DestHi; 1377 }; 1378 1379 /// Handles fp2int, int2fp, and fp2fp conversions. 1380 class InstARM32Vcvt final : public InstARM32Pred { 1381 InstARM32Vcvt() = delete; 1382 InstARM32Vcvt(const InstARM32Vcvt &) = delete; 1383 InstARM32Vcvt &operator=(const InstARM32Vcvt &) = delete; 1384 1385 public: 1386 enum VcvtVariant { 1387 S2si, 1388 S2ui, 1389 Si2s, 1390 Ui2s, 1391 D2si, 1392 D2ui, 1393 Si2d, 1394 Ui2d, 1395 S2d, 1396 D2s, 1397 Vs2si, 1398 Vs2ui, 1399 Vsi2s, 1400 Vui2s, 1401 }; create(Cfg * Func,Variable * Dest,Variable * Src,VcvtVariant Variant,CondARM32::Cond Predicate)1402 static InstARM32Vcvt *create(Cfg *Func, Variable *Dest, Variable *Src, 1403 VcvtVariant Variant, CondARM32::Cond Predicate) { 1404 return new (Func->allocate<InstARM32Vcvt>()) 1405 InstARM32Vcvt(Func, Dest, Src, Variant, Predicate); 1406 } 1407 void emit(const Cfg *Func) const override; 1408 void emitIAS(const Cfg *Func) const override; 1409 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1410 static bool classof(const Inst *Instr) { return isClassof(Instr, Vcvt); } 1411 1412 private: 1413 InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src, VcvtVariant Variant, 1414 CondARM32::Cond Predicate); 1415 1416 const VcvtVariant Variant; 1417 }; 1418 1419 /// Handles (some of) vmov's various formats. 1420 class InstARM32Mov final : public InstARM32Pred { 1421 InstARM32Mov() = delete; 1422 InstARM32Mov(const InstARM32Mov &) = delete; 1423 InstARM32Mov &operator=(const InstARM32Mov &) = delete; 1424 1425 public: create(Cfg * Func,Variable * Dest,Operand * Src,CondARM32::Cond Predicate)1426 static InstARM32Mov *create(Cfg *Func, Variable *Dest, Operand *Src, 1427 CondARM32::Cond Predicate) { 1428 return new (Func->allocate<InstARM32Mov>()) 1429 InstARM32Mov(Func, Dest, Src, Predicate); 1430 } isRedundantAssign()1431 bool isRedundantAssign() const override { 1432 return !isMultiDest() && !isMultiSource() && 1433 getPredicate() == CondARM32::AL && 1434 checkForRedundantAssign(getDest(), getSrc(0)); 1435 } isVarAssign()1436 bool isVarAssign() const override { return llvm::isa<Variable>(getSrc(0)); } 1437 void emit(const Cfg *Func) const override; 1438 void emitIAS(const Cfg *Func) const override; 1439 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1440 static bool classof(const Inst *Instr) { return isClassof(Instr, Mov); } 1441 isMultiDest()1442 bool isMultiDest() const { return DestHi != nullptr; } 1443 isMultiSource()1444 bool isMultiSource() const { 1445 assert(getSrcSize() == 1 || getSrcSize() == 2); 1446 return getSrcSize() == 2; 1447 } 1448 getDestHi()1449 Variable *getDestHi() const { return DestHi; } 1450 1451 private: 1452 InstARM32Mov(Cfg *Func, Variable *Dest, Operand *Src, 1453 CondARM32::Cond Predicate); 1454 void emitMultiDestSingleSource(const Cfg *Func) const; 1455 void emitSingleDestMultiSource(const Cfg *Func) const; 1456 void emitSingleDestSingleSource(const Cfg *Func) const; 1457 1458 Variable *DestHi = nullptr; 1459 }; 1460 1461 /// Generates vmov Rd, Dn[x] instructions, and their related floating point 1462 /// versions. 1463 class InstARM32Extract final : public InstARM32Pred { 1464 InstARM32Extract() = delete; 1465 InstARM32Extract(const InstARM32Extract &) = delete; 1466 InstARM32Extract &operator=(const InstARM32Extract &) = delete; 1467 1468 public: create(Cfg * Func,Variable * Dest,Variable * Src0,uint32_t Index,CondARM32::Cond Predicate)1469 static InstARM32Extract *create(Cfg *Func, Variable *Dest, Variable *Src0, 1470 uint32_t Index, CondARM32::Cond Predicate) { 1471 return new (Func->allocate<InstARM32Extract>()) 1472 InstARM32Extract(Func, Dest, Src0, Index, Predicate); 1473 } 1474 void emit(const Cfg *Func) const override; 1475 void emitIAS(const Cfg *Func) const override; classof(const Inst * Inst)1476 static bool classof(const Inst *Inst) { return isClassof(Inst, Extract); } 1477 1478 private: InstARM32Extract(Cfg * Func,Variable * Dest,Variable * Src0,uint32_t Index,CondARM32::Cond Predicate)1479 InstARM32Extract(Cfg *Func, Variable *Dest, Variable *Src0, uint32_t Index, 1480 CondARM32::Cond Predicate) 1481 : InstARM32Pred(Func, InstARM32::Extract, 1, Dest, Predicate), 1482 Index(Index) { 1483 assert(Index < typeNumElements(Src0->getType())); 1484 addSource(Src0); 1485 } 1486 1487 const uint32_t Index; 1488 }; 1489 1490 /// Generates vmov Dn[x], Rd instructions, and their related floating point 1491 /// versions. 1492 class InstARM32Insert final : public InstARM32Pred { 1493 InstARM32Insert() = delete; 1494 InstARM32Insert(const InstARM32Insert &) = delete; 1495 InstARM32Insert &operator=(const InstARM32Insert &) = delete; 1496 1497 public: create(Cfg * Func,Variable * Dest,Variable * Src0,uint32_t Index,CondARM32::Cond Predicate)1498 static InstARM32Insert *create(Cfg *Func, Variable *Dest, Variable *Src0, 1499 uint32_t Index, CondARM32::Cond Predicate) { 1500 return new (Func->allocate<InstARM32Insert>()) 1501 InstARM32Insert(Func, Dest, Src0, Index, Predicate); 1502 } 1503 void emit(const Cfg *Func) const override; 1504 void emitIAS(const Cfg *Func) const override; classof(const Inst * Inst)1505 static bool classof(const Inst *Inst) { return isClassof(Inst, Insert); } 1506 1507 private: InstARM32Insert(Cfg * Func,Variable * Dest,Variable * Src0,uint32_t Index,CondARM32::Cond Predicate)1508 InstARM32Insert(Cfg *Func, Variable *Dest, Variable *Src0, uint32_t Index, 1509 CondARM32::Cond Predicate) 1510 : InstARM32Pred(Func, InstARM32::Insert, 1, Dest, Predicate), 1511 Index(Index) { 1512 assert(Index < typeNumElements(Dest->getType())); 1513 addSource(Src0); 1514 } 1515 1516 const uint32_t Index; 1517 }; 1518 1519 class InstARM32Vcmp final : public InstARM32Pred { 1520 InstARM32Vcmp() = delete; 1521 InstARM32Vcmp(const InstARM32Vcmp &) = delete; 1522 InstARM32Vcmp &operator=(const InstARM32Vcmp &) = delete; 1523 1524 public: create(Cfg * Func,Variable * Src0,Variable * Src1,CondARM32::Cond Predicate)1525 static InstARM32Vcmp *create(Cfg *Func, Variable *Src0, Variable *Src1, 1526 CondARM32::Cond Predicate) { 1527 return new (Func->allocate<InstARM32Vcmp>()) 1528 InstARM32Vcmp(Func, Src0, Src1, Predicate); 1529 } create(Cfg * Func,Variable * Src0,OperandARM32FlexFpZero * Src1,CondARM32::Cond Predicate)1530 static InstARM32Vcmp *create(Cfg *Func, Variable *Src0, 1531 OperandARM32FlexFpZero *Src1, 1532 CondARM32::Cond Predicate) { 1533 return new (Func->allocate<InstARM32Vcmp>()) 1534 InstARM32Vcmp(Func, Src0, Src1, Predicate); 1535 } 1536 void emit(const Cfg *Func) const override; 1537 void emitIAS(const Cfg *Func) const override; 1538 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1539 static bool classof(const Inst *Instr) { return isClassof(Instr, Vcmp); } 1540 1541 private: 1542 InstARM32Vcmp(Cfg *Func, Variable *Src0, Operand *Src1, 1543 CondARM32::Cond Predicate); 1544 }; 1545 1546 /// Copies the FP Status and Control Register the core flags. 1547 class InstARM32Vmrs final : public InstARM32Pred { 1548 InstARM32Vmrs() = delete; 1549 InstARM32Vmrs(const InstARM32Vmrs &) = delete; 1550 InstARM32Vmrs &operator=(const InstARM32Vmrs &) = delete; 1551 1552 public: create(Cfg * Func,CondARM32::Cond Predicate)1553 static InstARM32Vmrs *create(Cfg *Func, CondARM32::Cond Predicate) { 1554 return new (Func->allocate<InstARM32Vmrs>()) InstARM32Vmrs(Func, Predicate); 1555 } 1556 void emit(const Cfg *Func) const override; 1557 void emitIAS(const Cfg *Func) const override; 1558 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1559 static bool classof(const Inst *Instr) { return isClassof(Instr, Vmrs); } 1560 1561 private: 1562 InstARM32Vmrs(Cfg *Func, CondARM32::Cond Predicate); 1563 }; 1564 1565 class InstARM32Vabs final : public InstARM32Pred { 1566 InstARM32Vabs() = delete; 1567 InstARM32Vabs(const InstARM32Vabs &) = delete; 1568 InstARM32Vabs &operator=(const InstARM32Vabs &) = delete; 1569 1570 public: create(Cfg * Func,Variable * Dest,Variable * Src,CondARM32::Cond Predicate)1571 static InstARM32Vabs *create(Cfg *Func, Variable *Dest, Variable *Src, 1572 CondARM32::Cond Predicate) { 1573 return new (Func->allocate<InstARM32Vabs>()) 1574 InstARM32Vabs(Func, Dest, Src, Predicate); 1575 } 1576 void emit(const Cfg *Func) const override; 1577 void emitIAS(const Cfg *Func) const override; 1578 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1579 static bool classof(const Inst *Instr) { return isClassof(Instr, Vabs); } 1580 1581 private: 1582 InstARM32Vabs(Cfg *Func, Variable *Dest, Variable *Src, 1583 CondARM32::Cond Predicate); 1584 }; 1585 1586 class InstARM32Dmb final : public InstARM32Pred { 1587 InstARM32Dmb() = delete; 1588 InstARM32Dmb(const InstARM32Dmb &) = delete; 1589 InstARM32Dmb &operator=(const InstARM32Dmb &) = delete; 1590 1591 public: create(Cfg * Func)1592 static InstARM32Dmb *create(Cfg *Func) { 1593 return new (Func->allocate<InstARM32Dmb>()) InstARM32Dmb(Func); 1594 } 1595 void emit(const Cfg *Func) const override; 1596 void emitIAS(const Cfg *Func) const override; 1597 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1598 static bool classof(const Inst *Instr) { return isClassof(Instr, Dmb); } 1599 1600 private: 1601 explicit InstARM32Dmb(Cfg *Func); 1602 }; 1603 1604 class InstARM32Nop final : public InstARM32Pred { 1605 InstARM32Nop() = delete; 1606 InstARM32Nop(const InstARM32Nop &) = delete; 1607 InstARM32Nop &operator=(const InstARM32Nop &) = delete; 1608 1609 public: create(Cfg * Func)1610 static InstARM32Nop *create(Cfg *Func) { 1611 return new (Func->allocate<InstARM32Nop>()) InstARM32Nop(Func); 1612 } 1613 void emit(const Cfg *Func) const override; 1614 void emitIAS(const Cfg *Func) const override; 1615 void dump(const Cfg *Func) const override; classof(const Inst * Instr)1616 static bool classof(const Inst *Instr) { return isClassof(Instr, Nop); } 1617 1618 private: 1619 explicit InstARM32Nop(Cfg *Func); 1620 }; 1621 1622 // Declare partial template specializations of emit() methods that already have 1623 // default implementations. Without this, there is the possibility of ODR 1624 // violations and link errors. 1625 1626 template <> void InstARM32Ldr::emit(const Cfg *Func) const; 1627 template <> void InstARM32Movw::emit(const Cfg *Func) const; 1628 template <> void InstARM32Movt::emit(const Cfg *Func) const; 1629 1630 } // end of namespace ARM32 1631 } // end of namespace Ice 1632 1633 #endif // SUBZERO_SRC_ICEINSTARM32_H 1634