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