1 //===- subzero/src/IceInstARM32.h - ARM32 machine instructions --*- C++ -*-===//
3 // The Subzero Code Generator
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief Declares the InstARM32 and OperandARM32 classes and their subclasses.
13 /// This represents the machine instructions and operands used for ARM32 code
16 //===----------------------------------------------------------------------===//
18 #ifndef SUBZERO_SRC_ICEINSTARM32_H
19 #define SUBZERO_SRC_ICEINSTARM32_H
21 #include "IceConditionCodesARM32.h"
24 #include "IceInstARM32.def"
25 #include "IceOperand.h"
30 /// Encoding of an ARM 32-bit instruction.
31 using IValueT = uint32_t;
33 /// An Offset value (+/-) used in an ARM 32-bit instruction.
34 using IOffsetT = int32_t;
38 /// OperandARM32 extends the Operand hierarchy. Its subclasses are
39 /// OperandARM32Mem and OperandARM32Flex.
40 class OperandARM32 : public Operand {
41 OperandARM32() = delete;
42 OperandARM32(const OperandARM32 &) = delete;
43 OperandARM32 &operator=(const OperandARM32 &) = delete;
46 enum OperandKindARM32 {
47 k__Start = Operand::kTarget,
51 kFlexImm = kFlexStart,
60 #define X(enum, emit) enum,
61 ICEINSTARM32SHIFT_TABLE
66 void dump(const Cfg *, Ostream &Str) const override {
67 if (BuildDefs::dump())
68 Str << "<OperandARM32>";
72 OperandARM32(OperandKindARM32 Kind, Type Ty)
73 : Operand(static_cast<OperandKind>(Kind), Ty) {}
76 /// OperandARM32Mem represents a memory operand in any of the various ARM32
78 class OperandARM32Mem : public OperandARM32 {
79 OperandARM32Mem() = delete;
80 OperandARM32Mem(const OperandARM32Mem &) = delete;
81 OperandARM32Mem &operator=(const OperandARM32Mem &) = delete;
84 /// Memory operand addressing mode.
85 /// The enum value also carries the encoding.
86 // TODO(jvoung): unify with the assembler.
88 // bit encoding P U 0 W
89 Offset = (8 | 4 | 0) << 21, // offset (w/o writeback to base)
90 PreIndex = (8 | 4 | 1) << 21, // pre-indexed addressing with writeback
91 PostIndex = (0 | 4 | 0) << 21, // post-indexed addressing with writeback
92 NegOffset = (8 | 0 | 0) << 21, // negative offset (w/o writeback to base)
93 NegPreIndex = (8 | 0 | 1) << 21, // negative pre-indexed with writeback
94 NegPostIndex = (0 | 0 | 0) << 21 // negative post-indexed with writeback
97 /// Provide two constructors.
98 /// NOTE: The Variable-typed operands have to be registers.
100 /// (1) Reg + Imm. The Immediate actually has a limited number of bits
101 /// for encoding, so check canHoldOffset first. It cannot handle general
102 /// Constant operands like ConstantRelocatable, since a relocatable can
103 /// potentially take up too many bits.
104 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base,
105 ConstantInteger32 *ImmOffset,
106 AddrMode Mode = Offset) {
107 return new (Func->allocate<OperandARM32Mem>())
108 OperandARM32Mem(Func, Ty, Base, ImmOffset, Mode);
110 /// (2) Reg +/- Reg with an optional shift of some kind and amount. Note that
111 /// this mode is disallowed in the NaCl sandbox.
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);
119 Variable *getBase() const { return Base; }
120 ConstantInteger32 *getOffset() const { return ImmOffset; }
121 Variable *getIndex() const { return Index; }
122 ShiftKind getShiftOp() const { return ShiftOp; }
123 uint16_t getShiftAmt() const { return ShiftAmt; }
124 AddrMode getAddrMode() const { return Mode; }
126 bool isRegReg() const { return Index != nullptr; }
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;
136 void emit(const Cfg *Func) const override;
137 using OperandARM32::dump;
138 void dump(const Cfg *Func, Ostream &Str) const override;
140 static bool classof(const Operand *Operand) {
141 return Operand->getKind() == static_cast<OperandKind>(kMem);
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
148 static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset);
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);
157 ConstantInteger32 *ImmOffset;
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;
173 static OperandARM32ShAmtImm *create(Cfg *Func, ConstantInteger32 *ShAmt) {
174 return new (Func->allocate<OperandARM32ShAmtImm>())
175 OperandARM32ShAmtImm(ShAmt);
178 static bool classof(const Operand *Operand) {
179 return Operand->getKind() == static_cast<OperandKind>(kShAmtImm);
182 void emit(const Cfg *Func) const override;
183 using OperandARM32::dump;
184 void dump(const Cfg *Func, Ostream &Str) const override;
186 uint32_t getShAmtImm() const { return ShAmt->getValue(); }
189 explicit OperandARM32ShAmtImm(ConstantInteger32 *SA);
191 const ConstantInteger32 *const ShAmt;
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;
203 static bool classof(const Operand *Operand) {
204 return static_cast<OperandKind>(kFlexStart) <= Operand->getKind() &&
205 Operand->getKind() <= static_cast<OperandKind>(kFlexEnd);
209 OperandARM32Flex(OperandKindARM32 Kind, Type Ty) : OperandARM32(Kind, Ty) {}
212 /// Rotated immediate variant.
213 class OperandARM32FlexImm : public OperandARM32Flex {
214 OperandARM32FlexImm() = delete;
215 OperandARM32FlexImm(const OperandARM32FlexImm &) = delete;
216 OperandARM32FlexImm &operator=(const OperandARM32FlexImm &) = delete;
219 /// Immed_8 rotated by an even number of bits (2 * RotateAmt).
220 static OperandARM32FlexImm *create(Cfg *Func, Type Ty, uint32_t Imm,
223 void emit(const Cfg *Func) const override;
224 using OperandARM32::dump;
225 void dump(const Cfg *Func, Ostream &Str) const override;
227 static bool classof(const Operand *Operand) {
228 return Operand->getKind() == static_cast<OperandKind>(kFlexImm);
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,
236 uint32_t getImm() const { return Imm; }
237 uint32_t getRotateAmt() const { return RotateAmt; }
240 OperandARM32FlexImm(Cfg *Func, Type Ty, uint32_t Imm, uint32_t RotateAmt);
246 /// Modified Floating-point constant.
247 class OperandARM32FlexFpImm : public OperandARM32Flex {
248 OperandARM32FlexFpImm() = delete;
249 OperandARM32FlexFpImm(const OperandARM32FlexFpImm &) = delete;
250 OperandARM32FlexFpImm &operator=(const OperandARM32FlexFpImm &) = delete;
253 static OperandARM32FlexFpImm *create(Cfg *Func, Type Ty,
254 uint32_t ModifiedImm) {
255 return new (Func->allocate<OperandARM32FlexFpImm>())
256 OperandARM32FlexFpImm(Func, Ty, ModifiedImm);
259 void emit(const Cfg *Func) const override;
260 using OperandARM32::dump;
261 void dump(const Cfg *Func, Ostream &Str) const override;
263 static bool classof(const Operand *Operand) {
264 return Operand->getKind() == static_cast<OperandKind>(kFlexFpImm);
267 static bool canHoldImm(Operand *C, uint32_t *ModifiedImm);
269 uint32_t getModifiedImm() const { return ModifiedImm; }
272 OperandARM32FlexFpImm(Cfg *Func, Type Ty, uint32_t ModifiedImm);
274 const uint32_t ModifiedImm;
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;
284 static OperandARM32FlexFpZero *create(Cfg *Func, Type Ty) {
285 return new (Func->allocate<OperandARM32FlexFpZero>())
286 OperandARM32FlexFpZero(Func, Ty);
289 void emit(const Cfg *Func) const override;
290 using OperandARM32::dump;
291 void dump(const Cfg *Func, Ostream &Str) const override;
293 static bool classof(const Operand *Operand) {
294 return Operand->getKind() == static_cast<OperandKind>(kFlexFpZero);
298 OperandARM32FlexFpZero(Cfg *Func, Type Ty);
301 /// Shifted register variant.
302 class OperandARM32FlexReg : public OperandARM32Flex {
303 OperandARM32FlexReg() = delete;
304 OperandARM32FlexReg(const OperandARM32FlexReg &) = delete;
305 OperandARM32FlexReg &operator=(const OperandARM32FlexReg &) = delete;
308 /// Register with immediate/reg shift amount and shift operation.
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);
315 void emit(const Cfg *Func) const override;
316 using OperandARM32::dump;
317 void dump(const Cfg *Func, Ostream &Str) const override;
319 static bool classof(const Operand *Operand) {
320 return Operand->getKind() == static_cast<OperandKind>(kFlexReg);
323 Variable *getReg() const { return Reg; }
324 ShiftKind getShiftOp() const { return ShiftOp; }
325 /// ShiftAmt can represent an immediate or a register.
326 Operand *getShiftAmt() const { return ShiftAmt; }
329 OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, ShiftKind ShiftOp,
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
342 class StackVariable final : public Variable {
343 StackVariable() = delete;
344 StackVariable(const StackVariable &) = delete;
345 StackVariable &operator=(const StackVariable &) = delete;
348 static StackVariable *create(Cfg *Func, Type Ty, SizeT Index) {
349 return new (Func->allocate<StackVariable>()) StackVariable(Ty, Index);
351 const static OperandKind StackVariableKind =
352 static_cast<OperandKind>(kVariable_Target);
353 static bool classof(const Operand *Operand) {
354 return Operand->getKind() == StackVariableKind;
356 void setBaseRegNum(int32_t RegNum) { BaseRegNum = RegNum; }
357 int32_t getBaseRegNum() const override { return BaseRegNum; }
358 // Inherit dump() and emit() from Variable.
361 StackVariable(Type Ty, SizeT Index)
362 : Variable(StackVariableKind, Ty, Index) {}
363 int32_t BaseRegNum = Variable::NoRegister;
366 /// Base class for ARM instructions. While most ARM instructions can be
367 /// conditionally executed, a few of them are not predicable (halt, memory
369 class InstARM32 : public InstTarget {
370 InstARM32() = delete;
371 InstARM32(const InstARM32 &) = delete;
372 InstARM32 &operator=(const InstARM32 &) = delete;
375 // Defines form that assembly instruction should be synthesized.
376 enum EmitForm { Emit_Text, Emit_Binary };
379 k__Start = Inst::Target,
439 static constexpr size_t InstSize = sizeof(uint32_t);
441 static const char *getWidthString(Type Ty);
442 static const char *getVecWidthString(Type Ty);
443 static CondARM32::Cond getOppositeCondition(CondARM32::Cond Cond);
445 /// Called inside derived methods emit() to communicate that multiple
446 /// instructions are being generated. Used by emitIAS() methods to
447 /// generate textual fixups for instructions that are not yet
449 void startNextInst(const Cfg *Func) const;
451 /// Shared emit routines for common forms of instructions.
452 static void emitThreeAddrFP(const char *Opcode, const InstARM32 *Instr,
454 static void emitFourAddrFP(const char *Opcode, const InstARM32 *Instr,
457 void dump(const Cfg *Func) const override;
459 void emitIAS(const Cfg *Func) const override;
462 InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest)
463 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {}
465 static bool isClassof(const Inst *Instr, InstKindARM32 MyKind) {
466 return Instr->getKind() == static_cast<InstKind>(MyKind);
469 // Generates text of assembly instruction using method emit(), and then adds
470 // to the assembly buffer as a Fixup.
471 void emitUsingTextFixup(const Cfg *Func) const;
474 /// A predicable ARM instruction.
475 class InstARM32Pred : public InstARM32 {
476 InstARM32Pred() = delete;
477 InstARM32Pred(const InstARM32Pred &) = delete;
478 InstARM32Pred &operator=(const InstARM32Pred &) = delete;
481 InstARM32Pred(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest,
482 CondARM32::Cond Predicate)
483 : InstARM32(Func, Kind, Maxsrcs, Dest), Predicate(Predicate) {}
485 CondARM32::Cond getPredicate() const { return Predicate; }
486 void setPredicate(CondARM32::Cond Pred) { Predicate = Pred; }
488 static const char *predString(CondARM32::Cond Predicate);
489 void dumpOpcodePred(Ostream &Str, const char *Opcode, Type Ty) const;
491 /// Shared emit routines for common forms of instructions.
492 static void emitUnaryopGPR(const char *Opcode, const InstARM32Pred *Instr,
493 const Cfg *Func, bool NeedsWidthSuffix);
494 static void emitUnaryopFP(const char *Opcode, const InstARM32Pred *Instr,
496 static void emitTwoAddr(const char *Opcode, const InstARM32Pred *Instr,
498 static void emitThreeAddr(const char *Opcode, const InstARM32Pred *Instr,
499 const Cfg *Func, bool SetFlags);
500 static void emitFourAddr(const char *Opcode, const InstARM32Pred *Instr,
502 static void emitCmpLike(const char *Opcode, const InstARM32Pred *Instr,
506 CondARM32::Cond Predicate;
509 template <typename StreamType>
510 inline StreamType &operator<<(StreamType &Stream, CondARM32::Cond Predicate) {
511 Stream << InstARM32Pred::predString(Predicate);
515 /// Instructions of the form x := op(y).
516 template <InstARM32::InstKindARM32 K, bool NeedsWidthSuffix>
517 class InstARM32UnaryopGPR : public InstARM32Pred {
518 InstARM32UnaryopGPR() = delete;
519 InstARM32UnaryopGPR(const InstARM32UnaryopGPR &) = delete;
520 InstARM32UnaryopGPR &operator=(const InstARM32UnaryopGPR &) = delete;
523 static InstARM32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src,
524 CondARM32::Cond Predicate) {
525 return new (Func->allocate<InstARM32UnaryopGPR>())
526 InstARM32UnaryopGPR(Func, Dest, Src, Predicate);
528 void emit(const Cfg *Func) const override {
529 if (!BuildDefs::dump())
531 emitUnaryopGPR(Opcode, this, Func, NeedsWidthSuffix);
533 void emitIAS(const Cfg *Func) const override;
534 void dump(const Cfg *Func) const override {
535 if (!BuildDefs::dump())
537 Ostream &Str = Func->getContext()->getStrDump();
540 dumpOpcodePred(Str, Opcode, getDest()->getType());
544 static bool classof(const Inst *Instr) { return isClassof(Instr, K); }
547 InstARM32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src,
548 CondARM32::Cond Predicate)
549 : InstARM32Pred(Func, K, 1, Dest, Predicate) {
553 static const char *Opcode;
556 /// Instructions of the form x := op(y), for vector/FP.
557 template <InstARM32::InstKindARM32 K>
558 class InstARM32UnaryopFP : public InstARM32Pred {
559 InstARM32UnaryopFP() = delete;
560 InstARM32UnaryopFP(const InstARM32UnaryopFP &) = delete;
561 InstARM32UnaryopFP &operator=(const InstARM32UnaryopFP &) = delete;
564 static InstARM32UnaryopFP *create(Cfg *Func, Variable *Dest, Variable *Src,
565 CondARM32::Cond Predicate) {
566 return new (Func->allocate<InstARM32UnaryopFP>())
567 InstARM32UnaryopFP(Func, Dest, Src, Predicate);
569 void emit(const Cfg *Func) const override {
570 if (!BuildDefs::dump())
572 emitUnaryopFP(Opcode, this, Func);
574 void emitIAS(const Cfg *Func) const override;
575 void dump(const Cfg *Func) const override {
576 if (!BuildDefs::dump())
578 Ostream &Str = Func->getContext()->getStrDump();
581 dumpOpcodePred(Str, Opcode, getDest()->getType());
585 static bool classof(const Inst *Instr) { return isClassof(Instr, K); }
588 InstARM32UnaryopFP(Cfg *Func, Variable *Dest, Operand *Src,
589 CondARM32::Cond Predicate)
590 : InstARM32Pred(Func, K, 1, Dest, Predicate) {
594 static const char *Opcode;
597 /// Instructions of the form x := x op y.
598 template <InstARM32::InstKindARM32 K>
599 class InstARM32TwoAddrGPR : public InstARM32Pred {
600 InstARM32TwoAddrGPR() = delete;
601 InstARM32TwoAddrGPR(const InstARM32TwoAddrGPR &) = delete;
602 InstARM32TwoAddrGPR &operator=(const InstARM32TwoAddrGPR &) = delete;
605 /// Dest must be a register.
606 static InstARM32TwoAddrGPR *create(Cfg *Func, Variable *Dest, Operand *Src,
607 CondARM32::Cond Predicate) {
608 return new (Func->allocate<InstARM32TwoAddrGPR>())
609 InstARM32TwoAddrGPR(Func, Dest, Src, Predicate);
611 void emit(const Cfg *Func) const override {
612 if (!BuildDefs::dump())
614 emitTwoAddr(Opcode, this, Func);
616 void emitIAS(const Cfg *Func) const override;
617 void dump(const Cfg *Func) const override {
618 if (!BuildDefs::dump())
620 Ostream &Str = Func->getContext()->getStrDump();
623 dumpOpcodePred(Str, Opcode, getDest()->getType());
627 static bool classof(const Inst *Instr) { return isClassof(Instr, K); }
630 InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src,
631 CondARM32::Cond Predicate)
632 : InstARM32Pred(Func, K, 2, Dest, Predicate) {
637 static const char *Opcode;
640 /// Base class for load instructions.
641 template <InstARM32::InstKindARM32 K>
642 class InstARM32LoadBase : public InstARM32Pred {
643 InstARM32LoadBase() = delete;
644 InstARM32LoadBase(const InstARM32LoadBase &) = delete;
645 InstARM32LoadBase &operator=(const InstARM32LoadBase &) = delete;
648 static InstARM32LoadBase *create(Cfg *Func, Variable *Dest, Operand *Source,
649 CondARM32::Cond Predicate) {
650 return new (Func->allocate<InstARM32LoadBase>())
651 InstARM32LoadBase(Func, Dest, Source, Predicate);
653 void emit(const Cfg *Func) const override;
654 void emitIAS(const Cfg *Func) const override;
655 void dump(const Cfg *Func) const override {
656 if (!BuildDefs::dump())
658 Ostream &Str = Func->getContext()->getStrDump();
659 dumpOpcodePred(Str, Opcode, getDest()->getType());
665 static bool classof(const Inst *Instr) { return isClassof(Instr, K); }
668 InstARM32LoadBase(Cfg *Func, Variable *Dest, Operand *Source,
669 CondARM32::Cond Predicate)
670 : InstARM32Pred(Func, K, 1, Dest, Predicate) {
674 static const char *Opcode;
677 /// Instructions of the form x := y op z. May have the side-effect of setting
679 template <InstARM32::InstKindARM32 K>
680 class InstARM32ThreeAddrGPR : public InstARM32Pred {
681 InstARM32ThreeAddrGPR() = delete;
682 InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete;
683 InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete;
686 /// Create an ordinary binary-op instruction like add, and sub. Dest and Src1
687 /// must be registers.
688 static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest,
689 Variable *Src0, Operand *Src1,
690 CondARM32::Cond Predicate,
691 bool SetFlags = false) {
692 return new (Func->allocate<InstARM32ThreeAddrGPR>())
693 InstARM32ThreeAddrGPR(Func, Dest, Src0, Src1, Predicate, SetFlags);
695 void emit(const Cfg *Func) const override {
696 if (!BuildDefs::dump())
698 emitThreeAddr(Opcode, this, Func, SetFlags);
700 void emitIAS(const Cfg *Func) const override;
701 void dump(const Cfg *Func) const override {
702 if (!BuildDefs::dump())
704 Ostream &Str = Func->getContext()->getStrDump();
707 dumpOpcodePred(Str, Opcode, getDest()->getType());
708 Str << (SetFlags ? ".s " : " ");
711 static bool classof(const Inst *Instr) { return isClassof(Instr, K); }
714 InstARM32ThreeAddrGPR(Cfg *Func, Variable *Dest, Variable *Src0,
715 Operand *Src1, CondARM32::Cond Predicate, bool SetFlags)
716 : InstARM32Pred(Func, K, 2, Dest, Predicate), SetFlags(SetFlags) {
717 HasSideEffects = SetFlags;
722 static const char *Opcode;
726 /// Instructions of the form x := y op z, for vector/FP. We leave these as
727 /// unconditional: "ARM deprecates the conditional execution of any instruction
728 /// encoding provided by the Advanced SIMD Extension that is not also provided
729 /// by the floating-point (VFP) extension". They do not set flags.
730 template <InstARM32::InstKindARM32 K>
731 class InstARM32ThreeAddrFP : public InstARM32 {
732 InstARM32ThreeAddrFP() = delete;
733 InstARM32ThreeAddrFP(const InstARM32ThreeAddrFP &) = delete;
734 InstARM32ThreeAddrFP &operator=(const InstARM32ThreeAddrFP &) = delete;
737 /// Create a vector/FP binary-op instruction like vadd, and vsub. Everything
738 /// must be a register.
739 static InstARM32ThreeAddrFP *create(Cfg *Func, Variable *Dest, Variable *Src0,
741 return new (Func->allocate<InstARM32ThreeAddrFP>())
742 InstARM32ThreeAddrFP(Func, Dest, Src0, Src1);
744 void emit(const Cfg *Func) const override {
745 if (!BuildDefs::dump())
747 emitThreeAddrFP(Opcode, this, Func);
749 void emitIAS(const Cfg *Func) const override;
750 void dump(const Cfg *Func) const override {
751 if (!BuildDefs::dump())
753 Ostream &Str = Func->getContext()->getStrDump();
756 Str << Opcode << "." << getDest()->getType() << " ";
759 static bool classof(const Inst *Instr) { return isClassof(Instr, K); }
762 InstARM32ThreeAddrFP(Cfg *Func, Variable *Dest, Variable *Src0,
764 : InstARM32(Func, K, 2, Dest) {
769 static const char *Opcode;
772 /// Instructions of the form x := a op1 (y op2 z). E.g., multiply accumulate.
773 template <InstARM32::InstKindARM32 K>
774 class InstARM32FourAddrGPR : public InstARM32Pred {
775 InstARM32FourAddrGPR() = delete;
776 InstARM32FourAddrGPR(const InstARM32FourAddrGPR &) = delete;
777 InstARM32FourAddrGPR &operator=(const InstARM32FourAddrGPR &) = delete;
780 // Every operand must be a register.
781 static InstARM32FourAddrGPR *create(Cfg *Func, Variable *Dest, Variable *Src0,
782 Variable *Src1, Variable *Src2,
783 CondARM32::Cond Predicate) {
784 return new (Func->allocate<InstARM32FourAddrGPR>())
785 InstARM32FourAddrGPR(Func, Dest, Src0, Src1, Src2, Predicate);
787 void emit(const Cfg *Func) const override {
788 if (!BuildDefs::dump())
790 emitFourAddr(Opcode, this, Func);
792 void emitIAS(const Cfg *Func) const override;
793 void dump(const Cfg *Func) const override {
794 if (!BuildDefs::dump())
796 Ostream &Str = Func->getContext()->getStrDump();
799 dumpOpcodePred(Str, Opcode, getDest()->getType());
803 static bool classof(const Inst *Instr) { return isClassof(Instr, K); }
806 InstARM32FourAddrGPR(Cfg *Func, Variable *Dest, Variable *Src0,
807 Variable *Src1, Variable *Src2,
808 CondARM32::Cond Predicate)
809 : InstARM32Pred(Func, K, 3, Dest, Predicate) {
815 static const char *Opcode;
818 /// Instructions of the form x := x op1 (y op2 z). E.g., multiply accumulate.
819 /// We leave these as unconditional: "ARM deprecates the conditional execution
820 /// of any instruction encoding provided by the Advanced SIMD Extension that is
821 /// not also provided by the floating-point (VFP) extension". They do not set
823 template <InstARM32::InstKindARM32 K>
824 class InstARM32FourAddrFP : public InstARM32 {
825 InstARM32FourAddrFP() = delete;
826 InstARM32FourAddrFP(const InstARM32FourAddrFP &) = delete;
827 InstARM32FourAddrFP &operator=(const InstARM32FourAddrFP &) = delete;
830 // Every operand must be a register.
831 static InstARM32FourAddrFP *create(Cfg *Func, Variable *Dest, Variable *Src0,
833 return new (Func->allocate<InstARM32FourAddrFP>())
834 InstARM32FourAddrFP(Func, Dest, Src0, Src1);
836 void emit(const Cfg *Func) const override {
837 if (!BuildDefs::dump())
839 emitFourAddrFP(Opcode, this, Func);
841 void emitIAS(const Cfg *Func) const override;
842 void dump(const Cfg *Func) const override {
843 if (!BuildDefs::dump())
845 Ostream &Str = Func->getContext()->getStrDump();
848 Str << Opcode << "." << getDest()->getType() << " ";
853 static bool classof(const Inst *Instr) { return isClassof(Instr, K); }
856 InstARM32FourAddrFP(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1)
857 : InstARM32(Func, K, 3, Dest) {
863 static const char *Opcode;
866 /// Instructions of the form x cmpop y (setting flags).
867 template <InstARM32::InstKindARM32 K>
868 class InstARM32CmpLike : public InstARM32Pred {
869 InstARM32CmpLike() = delete;
870 InstARM32CmpLike(const InstARM32CmpLike &) = delete;
871 InstARM32CmpLike &operator=(const InstARM32CmpLike &) = delete;
874 static InstARM32CmpLike *create(Cfg *Func, Variable *Src0, Operand *Src1,
875 CondARM32::Cond Predicate) {
876 return new (Func->allocate<InstARM32CmpLike>())
877 InstARM32CmpLike(Func, Src0, Src1, Predicate);
879 void emit(const Cfg *Func) const override {
880 if (!BuildDefs::dump())
882 emitCmpLike(Opcode, this, Func);
884 void emitIAS(const Cfg *Func) const override;
885 void dump(const Cfg *Func) const override {
886 if (!BuildDefs::dump())
888 Ostream &Str = Func->getContext()->getStrDump();
889 dumpOpcodePred(Str, Opcode, getSrc(0)->getType());
893 static bool classof(const Inst *Instr) { return isClassof(Instr, K); }
896 InstARM32CmpLike(Cfg *Func, Variable *Src0, Operand *Src1,
897 CondARM32::Cond Predicate)
898 : InstARM32Pred(Func, K, 2, nullptr, Predicate) {
899 HasSideEffects = true;
904 static const char *Opcode;
907 using InstARM32Adc = InstARM32ThreeAddrGPR<InstARM32::Adc>;
908 using InstARM32Add = InstARM32ThreeAddrGPR<InstARM32::Add>;
909 using InstARM32And = InstARM32ThreeAddrGPR<InstARM32::And>;
910 using InstARM32Asr = InstARM32ThreeAddrGPR<InstARM32::Asr>;
911 using InstARM32Bic = InstARM32ThreeAddrGPR<InstARM32::Bic>;
912 using InstARM32Eor = InstARM32ThreeAddrGPR<InstARM32::Eor>;
913 using InstARM32Lsl = InstARM32ThreeAddrGPR<InstARM32::Lsl>;
914 using InstARM32Lsr = InstARM32ThreeAddrGPR<InstARM32::Lsr>;
915 using InstARM32Mul = InstARM32ThreeAddrGPR<InstARM32::Mul>;
916 using InstARM32Orr = InstARM32ThreeAddrGPR<InstARM32::Orr>;
917 using InstARM32Rsb = InstARM32ThreeAddrGPR<InstARM32::Rsb>;
918 using InstARM32Rsc = InstARM32ThreeAddrGPR<InstARM32::Rsc>;
919 using InstARM32Sbc = InstARM32ThreeAddrGPR<InstARM32::Sbc>;
920 using InstARM32Sdiv = InstARM32ThreeAddrGPR<InstARM32::Sdiv>;
921 using InstARM32Sub = InstARM32ThreeAddrGPR<InstARM32::Sub>;
922 using InstARM32Udiv = InstARM32ThreeAddrGPR<InstARM32::Udiv>;
923 using InstARM32Vadd = InstARM32ThreeAddrFP<InstARM32::Vadd>;
924 using InstARM32Vand = InstARM32ThreeAddrFP<InstARM32::Vand>;
925 using InstARM32Vdiv = InstARM32ThreeAddrFP<InstARM32::Vdiv>;
926 using InstARM32Veor = InstARM32ThreeAddrFP<InstARM32::Veor>;
927 using InstARM32Vmla = InstARM32FourAddrFP<InstARM32::Vmla>;
928 using InstARM32Vmls = InstARM32FourAddrFP<InstARM32::Vmls>;
929 using InstARM32Vmul = InstARM32ThreeAddrFP<InstARM32::Vmul>;
930 using InstARM32Vorr = InstARM32ThreeAddrFP<InstARM32::Vorr>;
931 using InstARM32Vsub = InstARM32ThreeAddrFP<InstARM32::Vsub>;
932 using InstARM32Ldr = InstARM32LoadBase<InstARM32::Ldr>;
933 using InstARM32Ldrex = InstARM32LoadBase<InstARM32::Ldrex>;
934 /// MovT leaves the bottom bits alone so dest is also a source. This helps
935 /// indicate that a previous MovW setting dest is not dead code.
936 using InstARM32Movt = InstARM32TwoAddrGPR<InstARM32::Movt>;
937 using InstARM32Movw = InstARM32UnaryopGPR<InstARM32::Movw, false>;
938 using InstARM32Clz = InstARM32UnaryopGPR<InstARM32::Clz, false>;
939 using InstARM32Mvn = InstARM32UnaryopGPR<InstARM32::Mvn, false>;
940 using InstARM32Rbit = InstARM32UnaryopGPR<InstARM32::Rbit, false>;
941 using InstARM32Rev = InstARM32UnaryopGPR<InstARM32::Rev, false>;
942 // Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation operand
943 // as well (rotate source by 8, 16, 24 bits prior to extending), but we aren't
944 // using that for now, so just model as a Unaryop.
945 using InstARM32Sxt = InstARM32UnaryopGPR<InstARM32::Sxt, true>;
946 using InstARM32Uxt = InstARM32UnaryopGPR<InstARM32::Uxt, true>;
947 using InstARM32Vsqrt = InstARM32UnaryopFP<InstARM32::Vsqrt>;
948 using InstARM32Mla = InstARM32FourAddrGPR<InstARM32::Mla>;
949 using InstARM32Mls = InstARM32FourAddrGPR<InstARM32::Mls>;
950 using InstARM32Cmn = InstARM32CmpLike<InstARM32::Cmn>;
951 using InstARM32Cmp = InstARM32CmpLike<InstARM32::Cmp>;
952 using InstARM32Tst = InstARM32CmpLike<InstARM32::Tst>;
954 // InstARM32Label represents an intra-block label that is the target of an
955 // intra-block branch. The offset between the label and the branch must be fit
956 // in the instruction immediate (considered "near").
957 class InstARM32Label : public InstARM32 {
958 InstARM32Label() = delete;
959 InstARM32Label(const InstARM32Label &) = delete;
960 InstARM32Label &operator=(const InstARM32Label &) = delete;
963 static InstARM32Label *create(Cfg *Func, TargetARM32 *Target) {
964 return new (Func->allocate<InstARM32Label>()) InstARM32Label(Func, Target);
966 uint32_t getEmitInstCount() const override { return 0; }
967 IceString getName(const Cfg *Func) const;
968 SizeT getNumber() const { return Number; }
969 void emit(const Cfg *Func) const override;
970 void emitIAS(const Cfg *Func) const override;
971 void dump(const Cfg *Func) const override;
974 InstARM32Label(Cfg *Func, TargetARM32 *Target);
976 SizeT Number; // used for unique label generation.
979 /// Direct branch instruction.
980 class InstARM32Br : public InstARM32Pred {
981 InstARM32Br() = delete;
982 InstARM32Br(const InstARM32Br &) = delete;
983 InstARM32Br &operator=(const InstARM32Br &) = delete;
986 /// Create a conditional branch to one of two nodes.
987 static InstARM32Br *create(Cfg *Func, CfgNode *TargetTrue,
988 CfgNode *TargetFalse, CondARM32::Cond Predicate) {
989 assert(Predicate != CondARM32::AL);
990 constexpr InstARM32Label *NoLabel = nullptr;
991 return new (Func->allocate<InstARM32Br>())
992 InstARM32Br(Func, TargetTrue, TargetFalse, NoLabel, Predicate);
994 /// Create an unconditional branch to a node.
995 static InstARM32Br *create(Cfg *Func, CfgNode *Target) {
996 constexpr CfgNode *NoCondTarget = nullptr;
997 constexpr InstARM32Label *NoLabel = nullptr;
998 return new (Func->allocate<InstARM32Br>())
999 InstARM32Br(Func, NoCondTarget, Target, NoLabel, CondARM32::AL);
1001 /// Create a non-terminator conditional branch to a node, with a fallthrough
1002 /// to the next instruction in the current node. This is used for switch
1004 static InstARM32Br *create(Cfg *Func, CfgNode *Target,
1005 CondARM32::Cond Predicate) {
1006 assert(Predicate != CondARM32::AL);
1007 constexpr CfgNode *NoUncondTarget = nullptr;
1008 constexpr InstARM32Label *NoLabel = nullptr;
1009 return new (Func->allocate<InstARM32Br>())
1010 InstARM32Br(Func, Target, NoUncondTarget, NoLabel, Predicate);
1012 // Create a conditional intra-block branch (or unconditional, if
1013 // Condition==AL) to a label in the current block.
1014 static InstARM32Br *create(Cfg *Func, InstARM32Label *Label,
1015 CondARM32::Cond Predicate) {
1016 constexpr CfgNode *NoCondTarget = nullptr;
1017 constexpr CfgNode *NoUncondTarget = nullptr;
1018 return new (Func->allocate<InstARM32Br>())
1019 InstARM32Br(Func, NoCondTarget, NoUncondTarget, Label, Predicate);
1021 const CfgNode *getTargetTrue() const { return TargetTrue; }
1022 const CfgNode *getTargetFalse() const { return TargetFalse; }
1023 bool optimizeBranch(const CfgNode *NextNode);
1024 uint32_t getEmitInstCount() const override {
1028 if (getTargetTrue())
1030 if (getTargetFalse())
1034 bool isUnconditionalBranch() const override {
1035 return getPredicate() == CondARM32::AL;
1037 bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override;
1038 void emit(const Cfg *Func) const override;
1039 void emitIAS(const Cfg *Func) const override;
1040 void dump(const Cfg *Func) const override;
1041 static bool classof(const Inst *Instr) { return isClassof(Instr, Br); }
1044 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse,
1045 const InstARM32Label *Label, CondARM32::Cond Predicate);
1047 const CfgNode *TargetTrue;
1048 const CfgNode *TargetFalse;
1049 const InstARM32Label *Label; // Intra-block branch target
1052 /// Call instruction (bl/blx). Arguments should have already been pushed.
1053 /// Technically bl and the register form of blx can be predicated, but we'll
1054 /// leave that out until needed.
1055 class InstARM32Call : public InstARM32 {
1056 InstARM32Call() = delete;
1057 InstARM32Call(const InstARM32Call &) = delete;
1058 InstARM32Call &operator=(const InstARM32Call &) = delete;
1061 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) {
1062 return new (Func->allocate<InstARM32Call>())
1063 InstARM32Call(Func, Dest, CallTarget);
1065 Operand *getCallTarget() const { return getSrc(0); }
1066 void emit(const Cfg *Func) const override;
1067 void emitIAS(const Cfg *Func) const override;
1068 void dump(const Cfg *Func) const override;
1069 static bool classof(const Inst *Instr) { return isClassof(Instr, Call); }
1072 InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget);
1075 class InstARM32RegisterStackOp : public InstARM32 {
1076 InstARM32RegisterStackOp() = delete;
1077 InstARM32RegisterStackOp(const InstARM32RegisterStackOp &) = delete;
1078 InstARM32RegisterStackOp &
1079 operator=(const InstARM32RegisterStackOp &) = delete;
1082 void emit(const Cfg *Func) const override;
1083 void emitIAS(const Cfg *Func) const override;
1084 void dump(const Cfg *Func) const override;
1087 InstARM32RegisterStackOp(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs,
1089 : InstARM32(Func, Kind, Maxsrcs, Dest) {}
1090 void emitUsingForm(const Cfg *Func, const EmitForm Form) const;
1091 void emitGPRsAsText(const Cfg *Func) const;
1092 void emitSRegsAsText(const Cfg *Func, const Variable *BaseReg,
1093 SizeT Regcount) const;
1094 virtual const char *getDumpOpcode() const { return getGPROpcode(); }
1095 virtual const char *getGPROpcode() const = 0;
1096 virtual const char *getSRegOpcode() const = 0;
1097 virtual Variable *getStackReg(SizeT Index) const = 0;
1098 virtual SizeT getNumStackRegs() const = 0;
1099 virtual void emitSingleGPR(const Cfg *Func, const EmitForm Form,
1100 const Variable *Reg) const = 0;
1101 virtual void emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
1102 IValueT Registers) const = 0;
1103 virtual void emitSRegs(const Cfg *Func, const EmitForm Form,
1104 const Variable *BaseReg, SizeT RegCount) const = 0;
1107 /// Pops a list of registers. It may be a list of GPRs, or a list of VFP "s"
1108 /// regs, but not both. In any case, the list must be sorted.
1109 class InstARM32Pop : public InstARM32RegisterStackOp {
1110 InstARM32Pop() = delete;
1111 InstARM32Pop(const InstARM32Pop &) = delete;
1112 InstARM32Pop &operator=(const InstARM32Pop &) = delete;
1115 static InstARM32Pop *create(Cfg *Func, const VarList &Dests) {
1116 return new (Func->allocate<InstARM32Pop>()) InstARM32Pop(Func, Dests);
1118 static bool classof(const Inst *Instr) { return isClassof(Instr, Pop); }
1121 InstARM32Pop(Cfg *Func, const VarList &Dests);
1122 virtual const char *getGPROpcode() const final;
1123 virtual const char *getSRegOpcode() const final;
1124 Variable *getStackReg(SizeT Index) const final;
1125 SizeT getNumStackRegs() const final;
1126 void emitSingleGPR(const Cfg *Func, const EmitForm Form,
1127 const Variable *Reg) const final;
1128 void emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
1129 IValueT Registers) const final;
1130 void emitSRegs(const Cfg *Func, const EmitForm Form, const Variable *BaseReg,
1131 SizeT RegCount) const final;
1136 /// Pushes a list of registers. Just like Pop (see above), the list may be of
1137 /// GPRs, or VFP "s" registers, but not both.
1138 class InstARM32Push : public InstARM32RegisterStackOp {
1139 InstARM32Push() = delete;
1140 InstARM32Push(const InstARM32Push &) = delete;
1141 InstARM32Push &operator=(const InstARM32Push &) = delete;
1144 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) {
1145 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs);
1147 static bool classof(const Inst *Instr) { return isClassof(Instr, Push); }
1150 InstARM32Push(Cfg *Func, const VarList &Srcs);
1151 const char *getGPROpcode() const final;
1152 const char *getSRegOpcode() const final;
1153 Variable *getStackReg(SizeT Index) const final;
1154 SizeT getNumStackRegs() const final;
1155 void emitSingleGPR(const Cfg *Func, const EmitForm Form,
1156 const Variable *Reg) const final;
1157 void emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
1158 IValueT Registers) const final;
1159 void emitSRegs(const Cfg *Func, const EmitForm Form, const Variable *BaseReg,
1160 SizeT RegCount) const final;
1163 /// Ret pseudo-instruction. This is actually a "bx" instruction with an "lr"
1164 /// register operand, but epilogue lowering will search for a Ret instead of a
1165 /// generic "bx". This instruction also takes a Source operand (for non-void
1166 /// returning functions) for liveness analysis, though a FakeUse before the ret
1167 /// would do just as well.
1169 /// NOTE: Even though "bx" can be predicated, for now leave out the predication
1170 /// since it's not yet known to be useful for Ret. That may complicate finding
1171 /// the terminator instruction if it's not guaranteed to be executed.
1172 class InstARM32Ret : public InstARM32 {
1173 InstARM32Ret() = delete;
1174 InstARM32Ret(const InstARM32Ret &) = delete;
1175 InstARM32Ret &operator=(const InstARM32Ret &) = delete;
1178 static InstARM32Ret *create(Cfg *Func, Variable *LR,
1179 Variable *Source = nullptr) {
1180 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source);
1182 void emit(const Cfg *Func) const override;
1183 void emitIAS(const Cfg *Func) const override;
1184 void dump(const Cfg *Func) const override;
1185 static bool classof(const Inst *Instr) { return isClassof(Instr, Ret); }
1188 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source);
1191 /// Store instruction. It's important for liveness that there is no Dest operand
1192 /// (OperandARM32Mem instead of Dest Variable).
1193 class InstARM32Str final : public InstARM32Pred {
1194 InstARM32Str() = delete;
1195 InstARM32Str(const InstARM32Str &) = delete;
1196 InstARM32Str &operator=(const InstARM32Str &) = delete;
1199 /// Value must be a register.
1200 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem,
1201 CondARM32::Cond Predicate) {
1202 return new (Func->allocate<InstARM32Str>())
1203 InstARM32Str(Func, Value, Mem, Predicate);
1205 void emit(const Cfg *Func) const override;
1206 void emitIAS(const Cfg *Func) const override;
1207 void dump(const Cfg *Func) const override;
1208 static bool classof(const Inst *Instr) { return isClassof(Instr, Str); }
1211 InstARM32Str(Cfg *Func, Variable *Value, OperandARM32Mem *Mem,
1212 CondARM32::Cond Predicate);
1215 /// Exclusive Store instruction. Like its non-exclusive sibling, it's important
1216 /// for liveness that there is no Dest operand (OperandARM32Mem instead of Dest
1218 class InstARM32Strex final : public InstARM32Pred {
1219 InstARM32Strex() = delete;
1220 InstARM32Strex(const InstARM32Strex &) = delete;
1221 InstARM32Strex &operator=(const InstARM32Strex &) = delete;
1224 /// Value must be a register.
1225 static InstARM32Strex *create(Cfg *Func, Variable *Dest, Variable *Value,
1226 OperandARM32Mem *Mem,
1227 CondARM32::Cond Predicate) {
1228 return new (Func->allocate<InstARM32Strex>())
1229 InstARM32Strex(Func, Dest, Value, Mem, Predicate);
1231 void emit(const Cfg *Func) const override;
1232 void emitIAS(const Cfg *Func) const override;
1233 void dump(const Cfg *Func) const override;
1234 static bool classof(const Inst *Instr) { return isClassof(Instr, Strex); }
1237 InstARM32Strex(Cfg *Func, Variable *Dest, Variable *Value,
1238 OperandARM32Mem *Mem, CondARM32::Cond Predicate);
1241 class InstARM32Trap : public InstARM32 {
1242 InstARM32Trap() = delete;
1243 InstARM32Trap(const InstARM32Trap &) = delete;
1244 InstARM32Trap &operator=(const InstARM32Trap &) = delete;
1247 static InstARM32Trap *create(Cfg *Func) {
1248 return new (Func->allocate<InstARM32Trap>()) InstARM32Trap(Func);
1250 void emit(const Cfg *Func) const override;
1251 void emitIAS(const Cfg *Func) const override;
1252 void dump(const Cfg *Func) const override;
1253 static bool classof(const Inst *Instr) { return isClassof(Instr, Trap); }
1256 explicit InstARM32Trap(Cfg *Func);
1259 /// Unsigned Multiply Long: d.lo, d.hi := x * y
1260 class InstARM32Umull : public InstARM32Pred {
1261 InstARM32Umull() = delete;
1262 InstARM32Umull(const InstARM32Umull &) = delete;
1263 InstARM32Umull &operator=(const InstARM32Umull &) = delete;
1266 /// Everything must be a register.
1267 static InstARM32Umull *create(Cfg *Func, Variable *DestLo, Variable *DestHi,
1268 Variable *Src0, Variable *Src1,
1269 CondARM32::Cond Predicate) {
1270 return new (Func->allocate<InstARM32Umull>())
1271 InstARM32Umull(Func, DestLo, DestHi, Src0, Src1, Predicate);
1273 void emit(const Cfg *Func) const override;
1274 void emitIAS(const Cfg *Func) const override;
1275 void dump(const Cfg *Func) const override;
1276 static bool classof(const Inst *Instr) { return isClassof(Instr, Umull); }
1279 InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, Variable *Src0,
1280 Variable *Src1, CondARM32::Cond Predicate);
1285 /// Handles fp2int, int2fp, and fp2fp conversions.
1286 class InstARM32Vcvt final : public InstARM32Pred {
1287 InstARM32Vcvt() = delete;
1288 InstARM32Vcvt(const InstARM32Vcvt &) = delete;
1289 InstARM32Vcvt &operator=(const InstARM32Vcvt &) = delete;
1292 enum VcvtVariant { S2si, S2ui, Si2s, Ui2s, D2si, D2ui, Si2d, Ui2d, S2d, D2s };
1293 static InstARM32Vcvt *create(Cfg *Func, Variable *Dest, Variable *Src,
1294 VcvtVariant Variant, CondARM32::Cond Predicate) {
1295 return new (Func->allocate<InstARM32Vcvt>())
1296 InstARM32Vcvt(Func, Dest, Src, Variant, Predicate);
1298 void emit(const Cfg *Func) const override;
1299 void emitIAS(const Cfg *Func) const override;
1300 void dump(const Cfg *Func) const override;
1301 static bool classof(const Inst *Instr) { return isClassof(Instr, Vcvt); }
1304 InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src, VcvtVariant Variant,
1305 CondARM32::Cond Predicate);
1307 const VcvtVariant Variant;
1310 /// Handles (some of) vmov's various formats.
1311 class InstARM32Mov final : public InstARM32Pred {
1312 InstARM32Mov() = delete;
1313 InstARM32Mov(const InstARM32Mov &) = delete;
1314 InstARM32Mov &operator=(const InstARM32Mov &) = delete;
1317 static InstARM32Mov *create(Cfg *Func, Variable *Dest, Operand *Src,
1318 CondARM32::Cond Predicate) {
1319 return new (Func->allocate<InstARM32Mov>())
1320 InstARM32Mov(Func, Dest, Src, Predicate);
1322 bool isRedundantAssign() const override {
1323 return !isMultiDest() && !isMultiSource() &&
1324 getPredicate() == CondARM32::AL &&
1325 checkForRedundantAssign(getDest(), getSrc(0));
1327 bool isVarAssign() const override { return llvm::isa<Variable>(getSrc(0)); }
1328 void emit(const Cfg *Func) const override;
1329 void emitIAS(const Cfg *Func) const override;
1330 void dump(const Cfg *Func) const override;
1331 static bool classof(const Inst *Instr) { return isClassof(Instr, Mov); }
1333 bool isMultiDest() const { return DestHi != nullptr; }
1335 bool isMultiSource() const {
1336 assert(getSrcSize() == 1 || getSrcSize() == 2);
1337 return getSrcSize() == 2;
1340 Variable *getDestHi() const { return DestHi; }
1343 InstARM32Mov(Cfg *Func, Variable *Dest, Operand *Src,
1344 CondARM32::Cond Predicate);
1345 void emitMultiDestSingleSource(const Cfg *Func) const;
1346 void emitSingleDestMultiSource(const Cfg *Func) const;
1347 void emitSingleDestSingleSource(const Cfg *Func) const;
1349 Variable *DestHi = nullptr;
1352 class InstARM32Vcmp final : public InstARM32Pred {
1353 InstARM32Vcmp() = delete;
1354 InstARM32Vcmp(const InstARM32Vcmp &) = delete;
1355 InstARM32Vcmp &operator=(const InstARM32Vcmp &) = delete;
1358 static InstARM32Vcmp *create(Cfg *Func, Variable *Src0, Variable *Src1,
1359 CondARM32::Cond Predicate) {
1360 return new (Func->allocate<InstARM32Vcmp>())
1361 InstARM32Vcmp(Func, Src0, Src1, Predicate);
1363 static InstARM32Vcmp *create(Cfg *Func, Variable *Src0,
1364 OperandARM32FlexFpZero *Src1,
1365 CondARM32::Cond Predicate) {
1366 return new (Func->allocate<InstARM32Vcmp>())
1367 InstARM32Vcmp(Func, Src0, Src1, Predicate);
1369 void emit(const Cfg *Func) const override;
1370 void emitIAS(const Cfg *Func) const override;
1371 void dump(const Cfg *Func) const override;
1372 static bool classof(const Inst *Instr) { return isClassof(Instr, Vcmp); }
1375 InstARM32Vcmp(Cfg *Func, Variable *Src0, Operand *Src1,
1376 CondARM32::Cond Predicate);
1379 /// Copies the FP Status and Control Register the core flags.
1380 class InstARM32Vmrs final : public InstARM32Pred {
1381 InstARM32Vmrs() = delete;
1382 InstARM32Vmrs(const InstARM32Vmrs &) = delete;
1383 InstARM32Vmrs &operator=(const InstARM32Vmrs &) = delete;
1386 static InstARM32Vmrs *create(Cfg *Func, CondARM32::Cond Predicate) {
1387 return new (Func->allocate<InstARM32Vmrs>()) InstARM32Vmrs(Func, Predicate);
1389 void emit(const Cfg *Func) const override;
1390 void emitIAS(const Cfg *Func) const override;
1391 void dump(const Cfg *Func) const override;
1392 static bool classof(const Inst *Instr) { return isClassof(Instr, Vmrs); }
1395 InstARM32Vmrs(Cfg *Func, CondARM32::Cond Predicate);
1398 class InstARM32Vabs final : public InstARM32Pred {
1399 InstARM32Vabs() = delete;
1400 InstARM32Vabs(const InstARM32Vabs &) = delete;
1401 InstARM32Vabs &operator=(const InstARM32Vabs &) = delete;
1404 static InstARM32Vabs *create(Cfg *Func, Variable *Dest, Variable *Src,
1405 CondARM32::Cond Predicate) {
1406 return new (Func->allocate<InstARM32Vabs>())
1407 InstARM32Vabs(Func, Dest, Src, Predicate);
1409 void emit(const Cfg *Func) const override;
1410 void emitIAS(const Cfg *Func) const override;
1411 void dump(const Cfg *Func) const override;
1412 static bool classof(const Inst *Instr) { return isClassof(Instr, Vabs); }
1415 InstARM32Vabs(Cfg *Func, Variable *Dest, Variable *Src,
1416 CondARM32::Cond Predicate);
1419 class InstARM32Dmb final : public InstARM32Pred {
1420 InstARM32Dmb() = delete;
1421 InstARM32Dmb(const InstARM32Dmb &) = delete;
1422 InstARM32Dmb &operator=(const InstARM32Dmb &) = delete;
1425 static InstARM32Dmb *create(Cfg *Func) {
1426 return new (Func->allocate<InstARM32Dmb>()) InstARM32Dmb(Func);
1428 void emit(const Cfg *Func) const override;
1429 void emitIAS(const Cfg *Func) const override;
1430 void dump(const Cfg *Func) const override;
1431 static bool classof(const Inst *Instr) { return isClassof(Instr, Dmb); }
1434 explicit InstARM32Dmb(Cfg *Func);
1437 // Declare partial template specializations of emit() methods that already have
1438 // default implementations. Without this, there is the possibility of ODR
1439 // violations and link errors.
1441 template <> void InstARM32Ldr::emit(const Cfg *Func) const;
1442 template <> void InstARM32Movw::emit(const Cfg *Func) const;
1443 template <> void InstARM32Movt::emit(const Cfg *Func) const;
1445 } // end of namespace ARM32
1446 } // end of namespace Ice
1448 #endif // SUBZERO_SRC_ICEINSTARM32_H