| OLD | NEW |
| 1 //===- subzero/src/IceInstARM32.h - ARM32 machine instructions --*- C++ -*-===// | 1 //===- subzero/src/IceInstARM32.h - ARM32 machine instructions --*- C++ -*-===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| 11 /// This file declares the InstARM32 and OperandARM32 classes and | 11 /// This file declares the InstARM32 and OperandARM32 classes and their |
| 12 /// their subclasses. This represents the machine instructions and | 12 /// subclasses. This represents the machine instructions and operands used for |
| 13 /// operands used for ARM32 code selection. | 13 /// ARM32 code selection. |
| 14 /// | 14 /// |
| 15 //===----------------------------------------------------------------------===// | 15 //===----------------------------------------------------------------------===// |
| 16 | 16 |
| 17 #ifndef SUBZERO_SRC_ICEINSTARM32_H | 17 #ifndef SUBZERO_SRC_ICEINSTARM32_H |
| 18 #define SUBZERO_SRC_ICEINSTARM32_H | 18 #define SUBZERO_SRC_ICEINSTARM32_H |
| 19 | 19 |
| 20 #include "IceConditionCodesARM32.h" | 20 #include "IceConditionCodesARM32.h" |
| 21 #include "IceDefs.h" | 21 #include "IceDefs.h" |
| 22 #include "IceInst.h" | 22 #include "IceInst.h" |
| 23 #include "IceInstARM32.def" | 23 #include "IceInstARM32.def" |
| 24 #include "IceOperand.h" | 24 #include "IceOperand.h" |
| 25 | 25 |
| 26 namespace Ice { | 26 namespace Ice { |
| 27 | 27 |
| 28 class TargetARM32; | 28 class TargetARM32; |
| 29 | 29 |
| 30 /// OperandARM32 extends the Operand hierarchy. Its subclasses are | 30 /// OperandARM32 extends the Operand hierarchy. Its subclasses are |
| 31 /// OperandARM32Mem and OperandARM32Flex. | 31 /// OperandARM32Mem and OperandARM32Flex. |
| 32 class OperandARM32 : public Operand { | 32 class OperandARM32 : public Operand { |
| 33 OperandARM32() = delete; | 33 OperandARM32() = delete; |
| 34 OperandARM32(const OperandARM32 &) = delete; | 34 OperandARM32(const OperandARM32 &) = delete; |
| 35 OperandARM32 &operator=(const OperandARM32 &) = delete; | 35 OperandARM32 &operator=(const OperandARM32 &) = delete; |
| 36 | 36 |
| 37 public: | 37 public: |
| 38 enum OperandKindARM32 { | 38 enum OperandKindARM32 { |
| 39 k__Start = Operand::kTarget, | 39 k__Start = Operand::kTarget, |
| 40 kMem, | 40 kMem, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 PostIndex = (0 | 4 | 0) << 21, // post-indexed addressing with writeback | 80 PostIndex = (0 | 4 | 0) << 21, // post-indexed addressing with writeback |
| 81 NegOffset = (8 | 0 | 0) << 21, // negative offset (w/o writeback to base) | 81 NegOffset = (8 | 0 | 0) << 21, // negative offset (w/o writeback to base) |
| 82 NegPreIndex = (8 | 0 | 1) << 21, // negative pre-indexed with writeback | 82 NegPreIndex = (8 | 0 | 1) << 21, // negative pre-indexed with writeback |
| 83 NegPostIndex = (0 | 0 | 0) << 21 // negative post-indexed with writeback | 83 NegPostIndex = (0 | 0 | 0) << 21 // negative post-indexed with writeback |
| 84 }; | 84 }; |
| 85 | 85 |
| 86 /// Provide two constructors. | 86 /// Provide two constructors. |
| 87 /// NOTE: The Variable-typed operands have to be registers. | 87 /// NOTE: The Variable-typed operands have to be registers. |
| 88 /// | 88 /// |
| 89 /// (1) Reg + Imm. The Immediate actually has a limited number of bits | 89 /// (1) Reg + Imm. The Immediate actually has a limited number of bits |
| 90 /// for encoding, so check canHoldOffset first. It cannot handle | 90 /// for encoding, so check canHoldOffset first. It cannot handle general |
| 91 /// general Constant operands like ConstantRelocatable, since a relocatable | 91 /// Constant operands like ConstantRelocatable, since a relocatable can |
| 92 /// can potentially take up too many bits. | 92 /// potentially take up too many bits. |
| 93 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, | 93 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, |
| 94 ConstantInteger32 *ImmOffset, | 94 ConstantInteger32 *ImmOffset, |
| 95 AddrMode Mode = Offset) { | 95 AddrMode Mode = Offset) { |
| 96 return new (Func->allocate<OperandARM32Mem>()) | 96 return new (Func->allocate<OperandARM32Mem>()) |
| 97 OperandARM32Mem(Func, Ty, Base, ImmOffset, Mode); | 97 OperandARM32Mem(Func, Ty, Base, ImmOffset, Mode); |
| 98 } | 98 } |
| 99 /// (2) Reg +/- Reg with an optional shift of some kind and amount. | 99 /// (2) Reg +/- Reg with an optional shift of some kind and amount. Note that |
| 100 /// Note that this mode is disallowed in the NaCl sandbox. | 100 /// this mode is disallowed in the NaCl sandbox. |
| 101 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, | 101 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, |
| 102 Variable *Index, ShiftKind ShiftOp = kNoShift, | 102 Variable *Index, ShiftKind ShiftOp = kNoShift, |
| 103 uint16_t ShiftAmt = 0, | 103 uint16_t ShiftAmt = 0, |
| 104 AddrMode Mode = Offset) { | 104 AddrMode Mode = Offset) { |
| 105 return new (Func->allocate<OperandARM32Mem>()) | 105 return new (Func->allocate<OperandARM32Mem>()) |
| 106 OperandARM32Mem(Func, Ty, Base, Index, ShiftOp, ShiftAmt, Mode); | 106 OperandARM32Mem(Func, Ty, Base, Index, ShiftOp, ShiftAmt, Mode); |
| 107 } | 107 } |
| 108 Variable *getBase() const { return Base; } | 108 Variable *getBase() const { return Base; } |
| 109 ConstantInteger32 *getOffset() const { return ImmOffset; } | 109 ConstantInteger32 *getOffset() const { return ImmOffset; } |
| 110 Variable *getIndex() const { return Index; } | 110 Variable *getIndex() const { return Index; } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 123 } | 123 } |
| 124 | 124 |
| 125 void emit(const Cfg *Func) const override; | 125 void emit(const Cfg *Func) const override; |
| 126 using OperandARM32::dump; | 126 using OperandARM32::dump; |
| 127 void dump(const Cfg *Func, Ostream &Str) const override; | 127 void dump(const Cfg *Func, Ostream &Str) const override; |
| 128 | 128 |
| 129 static bool classof(const Operand *Operand) { | 129 static bool classof(const Operand *Operand) { |
| 130 return Operand->getKind() == static_cast<OperandKind>(kMem); | 130 return Operand->getKind() == static_cast<OperandKind>(kMem); |
| 131 } | 131 } |
| 132 | 132 |
| 133 /// Return true if a load/store instruction for an element of type Ty | 133 /// Return true if a load/store instruction for an element of type Ty can |
| 134 /// can encode the Offset directly in the immediate field of the 32-bit | 134 /// encode the Offset directly in the immediate field of the 32-bit ARM |
| 135 /// ARM instruction. For some types, if the load is Sign extending, then | 135 /// instruction. For some types, if the load is Sign extending, then the range |
| 136 /// the range is reduced. | 136 /// is reduced. |
| 137 static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset); | 137 static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset); |
| 138 | 138 |
| 139 private: | 139 private: |
| 140 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, | 140 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, |
| 141 ConstantInteger32 *ImmOffset, AddrMode Mode); | 141 ConstantInteger32 *ImmOffset, AddrMode Mode); |
| 142 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, Variable *Index, | 142 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, Variable *Index, |
| 143 ShiftKind ShiftOp, uint16_t ShiftAmt, AddrMode Mode); | 143 ShiftKind ShiftOp, uint16_t ShiftAmt, AddrMode Mode); |
| 144 | 144 |
| 145 Variable *Base; | 145 Variable *Base; |
| 146 ConstantInteger32 *ImmOffset; | 146 ConstantInteger32 *ImmOffset; |
| 147 Variable *Index; | 147 Variable *Index; |
| 148 ShiftKind ShiftOp; | 148 ShiftKind ShiftOp; |
| 149 uint16_t ShiftAmt; | 149 uint16_t ShiftAmt; |
| 150 AddrMode Mode; | 150 AddrMode Mode; |
| 151 }; | 151 }; |
| 152 | 152 |
| 153 /// OperandARM32Flex represent the "flexible second operand" for | 153 /// OperandARM32Flex represent the "flexible second operand" for data-processing |
| 154 /// data-processing instructions. It can be a rotatable 8-bit constant, or | 154 /// instructions. It can be a rotatable 8-bit constant, or a register with an |
| 155 /// a register with an optional shift operand. The shift amount can even be | 155 /// optional shift operand. The shift amount can even be a third register. |
| 156 /// a third register. | |
| 157 class OperandARM32Flex : public OperandARM32 { | 156 class OperandARM32Flex : public OperandARM32 { |
| 158 OperandARM32Flex() = delete; | 157 OperandARM32Flex() = delete; |
| 159 OperandARM32Flex(const OperandARM32Flex &) = delete; | 158 OperandARM32Flex(const OperandARM32Flex &) = delete; |
| 160 OperandARM32Flex &operator=(const OperandARM32Flex &) = delete; | 159 OperandARM32Flex &operator=(const OperandARM32Flex &) = delete; |
| 161 | 160 |
| 162 public: | 161 public: |
| 163 static bool classof(const Operand *Operand) { | 162 static bool classof(const Operand *Operand) { |
| 164 return static_cast<OperandKind>(kFlexStart) <= Operand->getKind() && | 163 return static_cast<OperandKind>(kFlexStart) <= Operand->getKind() && |
| 165 Operand->getKind() <= static_cast<OperandKind>(kFlexEnd); | 164 Operand->getKind() <= static_cast<OperandKind>(kFlexEnd); |
| 166 } | 165 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 184 } | 183 } |
| 185 | 184 |
| 186 void emit(const Cfg *Func) const override; | 185 void emit(const Cfg *Func) const override; |
| 187 using OperandARM32::dump; | 186 using OperandARM32::dump; |
| 188 void dump(const Cfg *Func, Ostream &Str) const override; | 187 void dump(const Cfg *Func, Ostream &Str) const override; |
| 189 | 188 |
| 190 static bool classof(const Operand *Operand) { | 189 static bool classof(const Operand *Operand) { |
| 191 return Operand->getKind() == static_cast<OperandKind>(kFlexImm); | 190 return Operand->getKind() == static_cast<OperandKind>(kFlexImm); |
| 192 } | 191 } |
| 193 | 192 |
| 194 /// Return true if the Immediate can fit in the ARM flexible operand. | 193 /// Return true if the Immediate can fit in the ARM flexible operand. Fills in |
| 195 /// Fills in the out-params RotateAmt and Immed_8 if Immediate fits. | 194 /// the out-params RotateAmt and Immed_8 if Immediate fits. |
| 196 static bool canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, | 195 static bool canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, |
| 197 uint32_t *Immed_8); | 196 uint32_t *Immed_8); |
| 198 | 197 |
| 199 uint32_t getImm() const { return Imm; } | 198 uint32_t getImm() const { return Imm; } |
| 200 uint32_t getRotateAmt() const { return RotateAmt; } | 199 uint32_t getRotateAmt() const { return RotateAmt; } |
| 201 | 200 |
| 202 private: | 201 private: |
| 203 OperandARM32FlexImm(Cfg *Func, Type Ty, uint32_t Imm, uint32_t RotateAmt); | 202 OperandARM32FlexImm(Cfg *Func, Type Ty, uint32_t Imm, uint32_t RotateAmt); |
| 204 | 203 |
| 205 uint32_t Imm; | 204 uint32_t Imm; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, ShiftKind ShiftOp, | 236 OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, ShiftKind ShiftOp, |
| 238 Operand *ShiftAmt); | 237 Operand *ShiftAmt); |
| 239 | 238 |
| 240 Variable *Reg; | 239 Variable *Reg; |
| 241 ShiftKind ShiftOp; | 240 ShiftKind ShiftOp; |
| 242 Operand *ShiftAmt; | 241 Operand *ShiftAmt; |
| 243 }; | 242 }; |
| 244 | 243 |
| 245 /// StackVariable represents a Var that isn't assigned a register (stack-only). | 244 /// StackVariable represents a Var that isn't assigned a register (stack-only). |
| 246 /// It is assigned a stack slot, but the slot's offset may be too large to | 245 /// It is assigned a stack slot, but the slot's offset may be too large to |
| 247 /// represent in the native addressing mode, and so it has a separate | 246 /// represent in the native addressing mode, and so it has a separate base |
| 248 /// base register from SP/FP, where the offset from that base register is | 247 /// register from SP/FP, where the offset from that base register is then in |
| 249 /// then in range. | 248 /// range. |
| 250 class StackVariable final : public Variable { | 249 class StackVariable final : public Variable { |
| 251 StackVariable() = delete; | 250 StackVariable() = delete; |
| 252 StackVariable(const StackVariable &) = delete; | 251 StackVariable(const StackVariable &) = delete; |
| 253 StackVariable &operator=(const StackVariable &) = delete; | 252 StackVariable &operator=(const StackVariable &) = delete; |
| 254 | 253 |
| 255 public: | 254 public: |
| 256 static StackVariable *create(Cfg *Func, Type Ty, SizeT Index) { | 255 static StackVariable *create(Cfg *Func, Type Ty, SizeT Index) { |
| 257 return new (Func->allocate<StackVariable>()) StackVariable(Ty, Index); | 256 return new (Func->allocate<StackVariable>()) StackVariable(Ty, Index); |
| 258 } | 257 } |
| 259 const static OperandKind StackVariableKind = | 258 const static OperandKind StackVariableKind = |
| 260 static_cast<OperandKind>(kVariable_Target); | 259 static_cast<OperandKind>(kVariable_Target); |
| 261 static bool classof(const Operand *Operand) { | 260 static bool classof(const Operand *Operand) { |
| 262 return Operand->getKind() == StackVariableKind; | 261 return Operand->getKind() == StackVariableKind; |
| 263 } | 262 } |
| 264 void setBaseRegNum(int32_t RegNum) { BaseRegNum = RegNum; } | 263 void setBaseRegNum(int32_t RegNum) { BaseRegNum = RegNum; } |
| 265 int32_t getBaseRegNum() const override { return BaseRegNum; } | 264 int32_t getBaseRegNum() const override { return BaseRegNum; } |
| 266 // Inherit dump() and emit() from Variable. | 265 // Inherit dump() and emit() from Variable. |
| 267 | 266 |
| 268 private: | 267 private: |
| 269 StackVariable(Type Ty, SizeT Index) | 268 StackVariable(Type Ty, SizeT Index) |
| 270 : Variable(StackVariableKind, Ty, Index) {} | 269 : Variable(StackVariableKind, Ty, Index) {} |
| 271 int32_t BaseRegNum = Variable::NoRegister; | 270 int32_t BaseRegNum = Variable::NoRegister; |
| 272 }; | 271 }; |
| 273 | 272 |
| 274 /// Base class for ARM instructions. While most ARM instructions can be | 273 /// Base class for ARM instructions. While most ARM instructions can be |
| 275 /// conditionally executed, a few of them are not predicable (halt, | 274 /// conditionally executed, a few of them are not predicable (halt, memory |
| 276 /// memory barriers, etc.). | 275 /// barriers, etc.). |
| 277 class InstARM32 : public InstTarget { | 276 class InstARM32 : public InstTarget { |
| 278 InstARM32() = delete; | 277 InstARM32() = delete; |
| 279 InstARM32(const InstARM32 &) = delete; | 278 InstARM32(const InstARM32 &) = delete; |
| 280 InstARM32 &operator=(const InstARM32 &) = delete; | 279 InstARM32 &operator=(const InstARM32 &) = delete; |
| 281 | 280 |
| 282 public: | 281 public: |
| 283 enum InstKindARM32 { | 282 enum InstKindARM32 { |
| 284 k__Start = Inst::Target, | 283 k__Start = Inst::Target, |
| 285 Adc, | 284 Adc, |
| 286 Add, | 285 Add, |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src, | 517 InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src, |
| 519 CondARM32::Cond Predicate) | 518 CondARM32::Cond Predicate) |
| 520 : InstARM32Pred(Func, K, 2, Dest, Predicate) { | 519 : InstARM32Pred(Func, K, 2, Dest, Predicate) { |
| 521 addSource(Dest); | 520 addSource(Dest); |
| 522 addSource(Src); | 521 addSource(Src); |
| 523 } | 522 } |
| 524 | 523 |
| 525 static const char *Opcode; | 524 static const char *Opcode; |
| 526 }; | 525 }; |
| 527 | 526 |
| 528 /// Base class for assignment instructions. | 527 /// Base class for assignment instructions. These can be tested for redundancy |
| 529 /// These can be tested for redundancy (and elided if redundant). | 528 /// (and elided if redundant). |
| 530 template <InstARM32::InstKindARM32 K> | 529 template <InstARM32::InstKindARM32 K> |
| 531 class InstARM32Movlike : public InstARM32Pred { | 530 class InstARM32Movlike : public InstARM32Pred { |
| 532 InstARM32Movlike() = delete; | 531 InstARM32Movlike() = delete; |
| 533 InstARM32Movlike(const InstARM32Movlike &) = delete; | 532 InstARM32Movlike(const InstARM32Movlike &) = delete; |
| 534 InstARM32Movlike &operator=(const InstARM32Movlike &) = delete; | 533 InstARM32Movlike &operator=(const InstARM32Movlike &) = delete; |
| 535 | 534 |
| 536 public: | 535 public: |
| 537 static InstARM32Movlike *create(Cfg *Func, Variable *Dest, Operand *Source, | 536 static InstARM32Movlike *create(Cfg *Func, Variable *Dest, Operand *Source, |
| 538 CondARM32::Cond Predicate) { | 537 CondARM32::Cond Predicate) { |
| 539 return new (Func->allocate<InstARM32Movlike>()) | 538 return new (Func->allocate<InstARM32Movlike>()) |
| (...skipping 29 matching lines...) Expand all Loading... |
| 569 | 568 |
| 570 /// Instructions of the form x := y op z. May have the side-effect of setting | 569 /// Instructions of the form x := y op z. May have the side-effect of setting |
| 571 /// status flags. | 570 /// status flags. |
| 572 template <InstARM32::InstKindARM32 K> | 571 template <InstARM32::InstKindARM32 K> |
| 573 class InstARM32ThreeAddrGPR : public InstARM32Pred { | 572 class InstARM32ThreeAddrGPR : public InstARM32Pred { |
| 574 InstARM32ThreeAddrGPR() = delete; | 573 InstARM32ThreeAddrGPR() = delete; |
| 575 InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete; | 574 InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete; |
| 576 InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete; | 575 InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete; |
| 577 | 576 |
| 578 public: | 577 public: |
| 579 /// Create an ordinary binary-op instruction like add, and sub. | 578 /// Create an ordinary binary-op instruction like add, and sub. Dest and Src1 |
| 580 /// Dest and Src1 must be registers. | 579 /// must be registers. |
| 581 static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest, | 580 static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest, |
| 582 Variable *Src0, Operand *Src1, | 581 Variable *Src0, Operand *Src1, |
| 583 CondARM32::Cond Predicate, | 582 CondARM32::Cond Predicate, |
| 584 bool SetFlags = false) { | 583 bool SetFlags = false) { |
| 585 return new (Func->allocate<InstARM32ThreeAddrGPR>()) | 584 return new (Func->allocate<InstARM32ThreeAddrGPR>()) |
| 586 InstARM32ThreeAddrGPR(Func, Dest, Src0, Src1, Predicate, SetFlags); | 585 InstARM32ThreeAddrGPR(Func, Dest, Src0, Src1, Predicate, SetFlags); |
| 587 } | 586 } |
| 588 void emit(const Cfg *Func) const override { | 587 void emit(const Cfg *Func) const override { |
| 589 if (!BuildDefs::dump()) | 588 if (!BuildDefs::dump()) |
| 590 return; | 589 return; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 611 Operand *Src1, CondARM32::Cond Predicate, bool SetFlags) | 610 Operand *Src1, CondARM32::Cond Predicate, bool SetFlags) |
| 612 : InstARM32Pred(Func, K, 2, Dest, Predicate), SetFlags(SetFlags) { | 611 : InstARM32Pred(Func, K, 2, Dest, Predicate), SetFlags(SetFlags) { |
| 613 addSource(Src0); | 612 addSource(Src0); |
| 614 addSource(Src1); | 613 addSource(Src1); |
| 615 } | 614 } |
| 616 | 615 |
| 617 static const char *Opcode; | 616 static const char *Opcode; |
| 618 bool SetFlags; | 617 bool SetFlags; |
| 619 }; | 618 }; |
| 620 | 619 |
| 621 /// Instructions of the form x := y op z, for vector/FP. We leave these as | 620 /// Instructions of the form x := y op z, for vector/FP. We leave these as |
| 622 /// unconditional: "ARM deprecates the conditional execution of any instruction | 621 /// unconditional: "ARM deprecates the conditional execution of any instruction |
| 623 /// encoding provided by the Advanced SIMD Extension that is not also provided | 622 /// encoding provided by the Advanced SIMD Extension that is not also provided |
| 624 /// by the Floating-point (VFP) extension". They do not set flags. | 623 /// by the Floating-point (VFP) extension". They do not set flags. |
| 625 template <InstARM32::InstKindARM32 K> | 624 template <InstARM32::InstKindARM32 K> |
| 626 class InstARM32ThreeAddrFP : public InstARM32 { | 625 class InstARM32ThreeAddrFP : public InstARM32 { |
| 627 InstARM32ThreeAddrFP() = delete; | 626 InstARM32ThreeAddrFP() = delete; |
| 628 InstARM32ThreeAddrFP(const InstARM32ThreeAddrFP &) = delete; | 627 InstARM32ThreeAddrFP(const InstARM32ThreeAddrFP &) = delete; |
| 629 InstARM32ThreeAddrFP &operator=(const InstARM32ThreeAddrFP &) = delete; | 628 InstARM32ThreeAddrFP &operator=(const InstARM32ThreeAddrFP &) = delete; |
| 630 | 629 |
| 631 public: | 630 public: |
| 632 /// Create a vector/FP binary-op instruction like vadd, and vsub. | 631 /// Create a vector/FP binary-op instruction like vadd, and vsub. Everything |
| 633 /// Everything must be a register. | 632 /// must be a register. |
| 634 static InstARM32ThreeAddrFP *create(Cfg *Func, Variable *Dest, Variable *Src0, | 633 static InstARM32ThreeAddrFP *create(Cfg *Func, Variable *Dest, Variable *Src0, |
| 635 Variable *Src1) { | 634 Variable *Src1) { |
| 636 return new (Func->allocate<InstARM32ThreeAddrFP>()) | 635 return new (Func->allocate<InstARM32ThreeAddrFP>()) |
| 637 InstARM32ThreeAddrFP(Func, Dest, Src0, Src1); | 636 InstARM32ThreeAddrFP(Func, Dest, Src0, Src1); |
| 638 } | 637 } |
| 639 void emit(const Cfg *Func) const override { | 638 void emit(const Cfg *Func) const override { |
| 640 if (!BuildDefs::dump()) | 639 if (!BuildDefs::dump()) |
| 641 return; | 640 return; |
| 642 emitThreeAddrFP(Opcode, this, Func); | 641 emitThreeAddrFP(Opcode, this, Func); |
| 643 } | 642 } |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 772 using InstARM32Rsb = InstARM32ThreeAddrGPR<InstARM32::Rsb>; | 771 using InstARM32Rsb = InstARM32ThreeAddrGPR<InstARM32::Rsb>; |
| 773 using InstARM32Sbc = InstARM32ThreeAddrGPR<InstARM32::Sbc>; | 772 using InstARM32Sbc = InstARM32ThreeAddrGPR<InstARM32::Sbc>; |
| 774 using InstARM32Sdiv = InstARM32ThreeAddrGPR<InstARM32::Sdiv>; | 773 using InstARM32Sdiv = InstARM32ThreeAddrGPR<InstARM32::Sdiv>; |
| 775 using InstARM32Sub = InstARM32ThreeAddrGPR<InstARM32::Sub>; | 774 using InstARM32Sub = InstARM32ThreeAddrGPR<InstARM32::Sub>; |
| 776 using InstARM32Udiv = InstARM32ThreeAddrGPR<InstARM32::Udiv>; | 775 using InstARM32Udiv = InstARM32ThreeAddrGPR<InstARM32::Udiv>; |
| 777 using InstARM32Vadd = InstARM32ThreeAddrFP<InstARM32::Vadd>; | 776 using InstARM32Vadd = InstARM32ThreeAddrFP<InstARM32::Vadd>; |
| 778 using InstARM32Vdiv = InstARM32ThreeAddrFP<InstARM32::Vdiv>; | 777 using InstARM32Vdiv = InstARM32ThreeAddrFP<InstARM32::Vdiv>; |
| 779 using InstARM32Vmul = InstARM32ThreeAddrFP<InstARM32::Vmul>; | 778 using InstARM32Vmul = InstARM32ThreeAddrFP<InstARM32::Vmul>; |
| 780 using InstARM32Vsub = InstARM32ThreeAddrFP<InstARM32::Vsub>; | 779 using InstARM32Vsub = InstARM32ThreeAddrFP<InstARM32::Vsub>; |
| 781 using InstARM32Ldr = InstARM32Movlike<InstARM32::Ldr>; | 780 using InstARM32Ldr = InstARM32Movlike<InstARM32::Ldr>; |
| 782 /// Move instruction (variable <- flex). This is more of a pseudo-inst. | 781 /// Move instruction (variable <- flex). This is more of a pseudo-inst. If var |
| 783 /// If var is a register, then we use "mov". If var is stack, then we use | 782 /// is a register, then we use "mov". If var is stack, then we use "str" to |
| 784 /// "str" to store to the stack. | 783 /// store to the stack. |
| 785 using InstARM32Mov = InstARM32Movlike<InstARM32::Mov>; | 784 using InstARM32Mov = InstARM32Movlike<InstARM32::Mov>; |
| 786 /// Represents various vector mov instruction forms (simple single source, | 785 /// Represents various vector mov instruction forms (simple single source, |
| 787 /// single dest forms only, not the 2 GPR <-> 1 D reg forms, etc.). | 786 /// single dest forms only, not the 2 GPR <-> 1 D reg forms, etc.). |
| 788 using InstARM32Vmov = InstARM32Movlike<InstARM32::Vmov>; | 787 using InstARM32Vmov = InstARM32Movlike<InstARM32::Vmov>; |
| 789 using InstARM32Vldr = InstARM32Movlike<InstARM32::Vldr>; | 788 using InstARM32Vldr = InstARM32Movlike<InstARM32::Vldr>; |
| 790 /// MovT leaves the bottom bits alone so dest is also a source. | 789 /// MovT leaves the bottom bits alone so dest is also a source. This helps |
| 791 /// This helps indicate that a previous MovW setting dest is not dead code. | 790 /// indicate that a previous MovW setting dest is not dead code. |
| 792 using InstARM32Movt = InstARM32TwoAddrGPR<InstARM32::Movt>; | 791 using InstARM32Movt = InstARM32TwoAddrGPR<InstARM32::Movt>; |
| 793 using InstARM32Movw = InstARM32UnaryopGPR<InstARM32::Movw, false>; | 792 using InstARM32Movw = InstARM32UnaryopGPR<InstARM32::Movw, false>; |
| 794 using InstARM32Clz = InstARM32UnaryopGPR<InstARM32::Clz, false>; | 793 using InstARM32Clz = InstARM32UnaryopGPR<InstARM32::Clz, false>; |
| 795 using InstARM32Mvn = InstARM32UnaryopGPR<InstARM32::Mvn, false>; | 794 using InstARM32Mvn = InstARM32UnaryopGPR<InstARM32::Mvn, false>; |
| 796 using InstARM32Rbit = InstARM32UnaryopGPR<InstARM32::Rbit, false>; | 795 using InstARM32Rbit = InstARM32UnaryopGPR<InstARM32::Rbit, false>; |
| 797 using InstARM32Rev = InstARM32UnaryopGPR<InstARM32::Rev, false>; | 796 using InstARM32Rev = InstARM32UnaryopGPR<InstARM32::Rev, false>; |
| 798 // Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation | 797 // Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation operand |
| 799 // operand as well (rotate source by 8, 16, 24 bits prior to extending), | 798 // as well (rotate source by 8, 16, 24 bits prior to extending), but we aren't |
| 800 // but we aren't using that for now, so just model as a Unaryop. | 799 // using that for now, so just model as a Unaryop. |
| 801 using InstARM32Sxt = InstARM32UnaryopGPR<InstARM32::Sxt, true>; | 800 using InstARM32Sxt = InstARM32UnaryopGPR<InstARM32::Sxt, true>; |
| 802 using InstARM32Uxt = InstARM32UnaryopGPR<InstARM32::Uxt, true>; | 801 using InstARM32Uxt = InstARM32UnaryopGPR<InstARM32::Uxt, true>; |
| 803 using InstARM32Vsqrt = InstARM32UnaryopFP<InstARM32::Vsqrt>; | 802 using InstARM32Vsqrt = InstARM32UnaryopFP<InstARM32::Vsqrt>; |
| 804 using InstARM32Mla = InstARM32FourAddrGPR<InstARM32::Mla>; | 803 using InstARM32Mla = InstARM32FourAddrGPR<InstARM32::Mla>; |
| 805 using InstARM32Mls = InstARM32FourAddrGPR<InstARM32::Mls>; | 804 using InstARM32Mls = InstARM32FourAddrGPR<InstARM32::Mls>; |
| 806 using InstARM32Cmp = InstARM32CmpLike<InstARM32::Cmp>; | 805 using InstARM32Cmp = InstARM32CmpLike<InstARM32::Cmp>; |
| 807 using InstARM32Tst = InstARM32CmpLike<InstARM32::Tst>; | 806 using InstARM32Tst = InstARM32CmpLike<InstARM32::Tst>; |
| 808 | 807 |
| 809 // InstARM32Label represents an intra-block label that is the target | 808 // InstARM32Label represents an intra-block label that is the target of an |
| 810 // of an intra-block branch. The offset between the label and the | 809 // intra-block branch. The offset between the label and the branch must be fit |
| 811 // branch must be fit in the instruction immediate (considered "near"). | 810 // in the instruction immediate (considered "near"). |
| 812 class InstARM32Label : public InstARM32 { | 811 class InstARM32Label : public InstARM32 { |
| 813 InstARM32Label() = delete; | 812 InstARM32Label() = delete; |
| 814 InstARM32Label(const InstARM32Label &) = delete; | 813 InstARM32Label(const InstARM32Label &) = delete; |
| 815 InstARM32Label &operator=(const InstARM32Label &) = delete; | 814 InstARM32Label &operator=(const InstARM32Label &) = delete; |
| 816 | 815 |
| 817 public: | 816 public: |
| 818 static InstARM32Label *create(Cfg *Func, TargetARM32 *Target) { | 817 static InstARM32Label *create(Cfg *Func, TargetARM32 *Target) { |
| 819 return new (Func->allocate<InstARM32Label>()) InstARM32Label(Func, Target); | 818 return new (Func->allocate<InstARM32Label>()) InstARM32Label(Func, Target); |
| 820 } | 819 } |
| 821 uint32_t getEmitInstCount() const override { return 0; } | 820 uint32_t getEmitInstCount() const override { return 0; } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 846 return new (Func->allocate<InstARM32Br>()) | 845 return new (Func->allocate<InstARM32Br>()) |
| 847 InstARM32Br(Func, TargetTrue, TargetFalse, NoLabel, Predicate); | 846 InstARM32Br(Func, TargetTrue, TargetFalse, NoLabel, Predicate); |
| 848 } | 847 } |
| 849 /// Create an unconditional branch to a node. | 848 /// Create an unconditional branch to a node. |
| 850 static InstARM32Br *create(Cfg *Func, CfgNode *Target) { | 849 static InstARM32Br *create(Cfg *Func, CfgNode *Target) { |
| 851 constexpr CfgNode *NoCondTarget = nullptr; | 850 constexpr CfgNode *NoCondTarget = nullptr; |
| 852 constexpr InstARM32Label *NoLabel = nullptr; | 851 constexpr InstARM32Label *NoLabel = nullptr; |
| 853 return new (Func->allocate<InstARM32Br>()) | 852 return new (Func->allocate<InstARM32Br>()) |
| 854 InstARM32Br(Func, NoCondTarget, Target, NoLabel, CondARM32::AL); | 853 InstARM32Br(Func, NoCondTarget, Target, NoLabel, CondARM32::AL); |
| 855 } | 854 } |
| 856 /// Create a non-terminator conditional branch to a node, with a | 855 /// Create a non-terminator conditional branch to a node, with a fallthrough |
| 857 /// fallthrough to the next instruction in the current node. This is | 856 /// to the next instruction in the current node. This is used for switch |
| 858 /// used for switch lowering. | 857 /// lowering. |
| 859 static InstARM32Br *create(Cfg *Func, CfgNode *Target, | 858 static InstARM32Br *create(Cfg *Func, CfgNode *Target, |
| 860 CondARM32::Cond Predicate) { | 859 CondARM32::Cond Predicate) { |
| 861 assert(Predicate != CondARM32::AL); | 860 assert(Predicate != CondARM32::AL); |
| 862 constexpr CfgNode *NoUncondTarget = nullptr; | 861 constexpr CfgNode *NoUncondTarget = nullptr; |
| 863 constexpr InstARM32Label *NoLabel = nullptr; | 862 constexpr InstARM32Label *NoLabel = nullptr; |
| 864 return new (Func->allocate<InstARM32Br>()) | 863 return new (Func->allocate<InstARM32Br>()) |
| 865 InstARM32Br(Func, Target, NoUncondTarget, NoLabel, Predicate); | 864 InstARM32Br(Func, Target, NoUncondTarget, NoLabel, Predicate); |
| 866 } | 865 } |
| 867 // Create a conditional intra-block branch (or unconditional, if | 866 // Create a conditional intra-block branch (or unconditional, if |
| 868 // Condition==AL) to a label in the current block. | 867 // Condition==AL) to a label in the current block. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 897 | 896 |
| 898 private: | 897 private: |
| 899 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, | 898 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, |
| 900 const InstARM32Label *Label, CondARM32::Cond Predicate); | 899 const InstARM32Label *Label, CondARM32::Cond Predicate); |
| 901 | 900 |
| 902 const CfgNode *TargetTrue; | 901 const CfgNode *TargetTrue; |
| 903 const CfgNode *TargetFalse; | 902 const CfgNode *TargetFalse; |
| 904 const InstARM32Label *Label; // Intra-block branch target | 903 const InstARM32Label *Label; // Intra-block branch target |
| 905 }; | 904 }; |
| 906 | 905 |
| 907 /// AdjustStack instruction - subtracts SP by the given amount and | 906 /// AdjustStack instruction - subtracts SP by the given amount and updates the |
| 908 /// updates the stack offset during code emission. | 907 /// stack offset during code emission. |
| 909 class InstARM32AdjustStack : public InstARM32 { | 908 class InstARM32AdjustStack : public InstARM32 { |
| 910 InstARM32AdjustStack() = delete; | 909 InstARM32AdjustStack() = delete; |
| 911 InstARM32AdjustStack(const InstARM32AdjustStack &) = delete; | 910 InstARM32AdjustStack(const InstARM32AdjustStack &) = delete; |
| 912 InstARM32AdjustStack &operator=(const InstARM32AdjustStack &) = delete; | 911 InstARM32AdjustStack &operator=(const InstARM32AdjustStack &) = delete; |
| 913 | 912 |
| 914 public: | 913 public: |
| 915 /// Note: We need both Amount and SrcAmount. If Amount is too large then | 914 /// Note: We need both Amount and SrcAmount. If Amount is too large then it |
| 916 /// it needs to be copied to a register (so SrcAmount could be a register). | 915 /// needs to be copied to a register (so SrcAmount could be a register). |
| 917 /// However, we also need the numeric Amount for bookkeeping, and it's | 916 /// However, we also need the numeric Amount for bookkeeping, and it's hard to |
| 918 /// hard to pull that from the generic SrcAmount operand. | 917 /// pull that from the generic SrcAmount operand. |
| 919 static InstARM32AdjustStack *create(Cfg *Func, Variable *SP, SizeT Amount, | 918 static InstARM32AdjustStack *create(Cfg *Func, Variable *SP, SizeT Amount, |
| 920 Operand *SrcAmount) { | 919 Operand *SrcAmount) { |
| 921 return new (Func->allocate<InstARM32AdjustStack>()) | 920 return new (Func->allocate<InstARM32AdjustStack>()) |
| 922 InstARM32AdjustStack(Func, SP, Amount, SrcAmount); | 921 InstARM32AdjustStack(Func, SP, Amount, SrcAmount); |
| 923 } | 922 } |
| 924 void emit(const Cfg *Func) const override; | 923 void emit(const Cfg *Func) const override; |
| 925 void emitIAS(const Cfg *Func) const override; | 924 void emitIAS(const Cfg *Func) const override; |
| 926 void dump(const Cfg *Func) const override; | 925 void dump(const Cfg *Func) const override; |
| 927 static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); } | 926 static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); } |
| 928 SizeT getAmount() const { return Amount; } | 927 SizeT getAmount() const { return Amount; } |
| 929 | 928 |
| 930 private: | 929 private: |
| 931 InstARM32AdjustStack(Cfg *Func, Variable *SP, SizeT Amount, | 930 InstARM32AdjustStack(Cfg *Func, Variable *SP, SizeT Amount, |
| 932 Operand *SrcAmount); | 931 Operand *SrcAmount); |
| 933 const SizeT Amount; | 932 const SizeT Amount; |
| 934 }; | 933 }; |
| 935 | 934 |
| 936 /// Call instruction (bl/blx). Arguments should have already been pushed. | 935 /// Call instruction (bl/blx). Arguments should have already been pushed. |
| 937 /// Technically bl and the register form of blx can be predicated, but we'll | 936 /// Technically bl and the register form of blx can be predicated, but we'll |
| 938 /// leave that out until needed. | 937 /// leave that out until needed. |
| 939 class InstARM32Call : public InstARM32 { | 938 class InstARM32Call : public InstARM32 { |
| 940 InstARM32Call() = delete; | 939 InstARM32Call() = delete; |
| 941 InstARM32Call(const InstARM32Call &) = delete; | 940 InstARM32Call(const InstARM32Call &) = delete; |
| 942 InstARM32Call &operator=(const InstARM32Call &) = delete; | 941 InstARM32Call &operator=(const InstARM32Call &) = delete; |
| 943 | 942 |
| 944 public: | 943 public: |
| 945 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { | 944 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { |
| 946 return new (Func->allocate<InstARM32Call>()) | 945 return new (Func->allocate<InstARM32Call>()) |
| (...skipping 24 matching lines...) Expand all Loading... |
| 971 void emitIAS(const Cfg *Func) const override; | 970 void emitIAS(const Cfg *Func) const override; |
| 972 void dump(const Cfg *Func) const override; | 971 void dump(const Cfg *Func) const override; |
| 973 static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } | 972 static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } |
| 974 | 973 |
| 975 private: | 974 private: |
| 976 InstARM32Pop(Cfg *Func, const VarList &Dests); | 975 InstARM32Pop(Cfg *Func, const VarList &Dests); |
| 977 | 976 |
| 978 VarList Dests; | 977 VarList Dests; |
| 979 }; | 978 }; |
| 980 | 979 |
| 981 /// Push a list of GPRs. Technically this can be predicated, but we don't | 980 /// Push a list of GPRs. Technically this can be predicated, but we don't need |
| 982 /// need that functionality. | 981 /// that functionality. |
| 983 class InstARM32Push : public InstARM32 { | 982 class InstARM32Push : public InstARM32 { |
| 984 InstARM32Push() = delete; | 983 InstARM32Push() = delete; |
| 985 InstARM32Push(const InstARM32Push &) = delete; | 984 InstARM32Push(const InstARM32Push &) = delete; |
| 986 InstARM32Push &operator=(const InstARM32Push &) = delete; | 985 InstARM32Push &operator=(const InstARM32Push &) = delete; |
| 987 | 986 |
| 988 public: | 987 public: |
| 989 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) { | 988 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) { |
| 990 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); | 989 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); |
| 991 } | 990 } |
| 992 void emit(const Cfg *Func) const override; | 991 void emit(const Cfg *Func) const override; |
| 993 void emitIAS(const Cfg *Func) const override; | 992 void emitIAS(const Cfg *Func) const override; |
| 994 void dump(const Cfg *Func) const override; | 993 void dump(const Cfg *Func) const override; |
| 995 static bool classof(const Inst *Inst) { return isClassof(Inst, Push); } | 994 static bool classof(const Inst *Inst) { return isClassof(Inst, Push); } |
| 996 | 995 |
| 997 private: | 996 private: |
| 998 InstARM32Push(Cfg *Func, const VarList &Srcs); | 997 InstARM32Push(Cfg *Func, const VarList &Srcs); |
| 999 }; | 998 }; |
| 1000 | 999 |
| 1001 /// Ret pseudo-instruction. This is actually a "bx" instruction with | 1000 /// Ret pseudo-instruction. This is actually a "bx" instruction with an "lr" |
| 1002 /// an "lr" register operand, but epilogue lowering will search for a Ret | 1001 /// register operand, but epilogue lowering will search for a Ret instead of a |
| 1003 /// instead of a generic "bx". This instruction also takes a Source | 1002 /// generic "bx". This instruction also takes a Source operand (for non-void |
| 1004 /// operand (for non-void returning functions) for liveness analysis, though | 1003 /// returning functions) for liveness analysis, though a FakeUse before the ret |
| 1005 /// a FakeUse before the ret would do just as well. | 1004 /// would do just as well. |
| 1006 /// | 1005 /// |
| 1007 /// NOTE: Even though "bx" can be predicated, for now leave out the predication | 1006 /// NOTE: Even though "bx" can be predicated, for now leave out the predication |
| 1008 /// since it's not yet known to be useful for Ret. That may complicate finding | 1007 /// since it's not yet known to be useful for Ret. That may complicate finding |
| 1009 /// the terminator instruction if it's not guaranteed to be executed. | 1008 /// the terminator instruction if it's not guaranteed to be executed. |
| 1010 class InstARM32Ret : public InstARM32 { | 1009 class InstARM32Ret : public InstARM32 { |
| 1011 InstARM32Ret() = delete; | 1010 InstARM32Ret() = delete; |
| 1012 InstARM32Ret(const InstARM32Ret &) = delete; | 1011 InstARM32Ret(const InstARM32Ret &) = delete; |
| 1013 InstARM32Ret &operator=(const InstARM32Ret &) = delete; | 1012 InstARM32Ret &operator=(const InstARM32Ret &) = delete; |
| 1014 | 1013 |
| 1015 public: | 1014 public: |
| 1016 static InstARM32Ret *create(Cfg *Func, Variable *LR, | 1015 static InstARM32Ret *create(Cfg *Func, Variable *LR, |
| 1017 Variable *Source = nullptr) { | 1016 Variable *Source = nullptr) { |
| 1018 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); | 1017 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); |
| 1019 } | 1018 } |
| 1020 void emit(const Cfg *Func) const override; | 1019 void emit(const Cfg *Func) const override; |
| 1021 void emitIAS(const Cfg *Func) const override; | 1020 void emitIAS(const Cfg *Func) const override; |
| 1022 void dump(const Cfg *Func) const override; | 1021 void dump(const Cfg *Func) const override; |
| 1023 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } | 1022 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } |
| 1024 | 1023 |
| 1025 private: | 1024 private: |
| 1026 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); | 1025 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); |
| 1027 }; | 1026 }; |
| 1028 | 1027 |
| 1029 /// Store instruction. It's important for liveness that there is no Dest | 1028 /// Store instruction. It's important for liveness that there is no Dest operand |
| 1030 /// operand (OperandARM32Mem instead of Dest Variable). | 1029 /// (OperandARM32Mem instead of Dest Variable). |
| 1031 class InstARM32Str : public InstARM32Pred { | 1030 class InstARM32Str : public InstARM32Pred { |
| 1032 InstARM32Str() = delete; | 1031 InstARM32Str() = delete; |
| 1033 InstARM32Str(const InstARM32Str &) = delete; | 1032 InstARM32Str(const InstARM32Str &) = delete; |
| 1034 InstARM32Str &operator=(const InstARM32Str &) = delete; | 1033 InstARM32Str &operator=(const InstARM32Str &) = delete; |
| 1035 | 1034 |
| 1036 public: | 1035 public: |
| 1037 /// Value must be a register. | 1036 /// Value must be a register. |
| 1038 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, | 1037 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, |
| 1039 CondARM32::Cond Predicate) { | 1038 CondARM32::Cond Predicate) { |
| 1040 return new (Func->allocate<InstARM32Str>()) | 1039 return new (Func->allocate<InstARM32Str>()) |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1112 void dump(const Cfg *Func) const override; | 1111 void dump(const Cfg *Func) const override; |
| 1113 static bool classof(const Inst *Inst) { return isClassof(Inst, Vcvt); } | 1112 static bool classof(const Inst *Inst) { return isClassof(Inst, Vcvt); } |
| 1114 | 1113 |
| 1115 private: | 1114 private: |
| 1116 InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src, VcvtVariant Variant, | 1115 InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src, VcvtVariant Variant, |
| 1117 CondARM32::Cond Predicate); | 1116 CondARM32::Cond Predicate); |
| 1118 | 1117 |
| 1119 const VcvtVariant Variant; | 1118 const VcvtVariant Variant; |
| 1120 }; | 1119 }; |
| 1121 | 1120 |
| 1122 // Declare partial template specializations of emit() methods that | 1121 // Declare partial template specializations of emit() methods that already have |
| 1123 // already have default implementations. Without this, there is the | 1122 // default implementations. Without this, there is the possibility of ODR |
| 1124 // possibility of ODR violations and link errors. | 1123 // violations and link errors. |
| 1125 | 1124 |
| 1126 template <> void InstARM32Ldr::emit(const Cfg *Func) const; | 1125 template <> void InstARM32Ldr::emit(const Cfg *Func) const; |
| 1127 template <> void InstARM32Mov::emit(const Cfg *Func) const; | 1126 template <> void InstARM32Mov::emit(const Cfg *Func) const; |
| 1128 template <> void InstARM32Movw::emit(const Cfg *Func) const; | 1127 template <> void InstARM32Movw::emit(const Cfg *Func) const; |
| 1129 template <> void InstARM32Movt::emit(const Cfg *Func) const; | 1128 template <> void InstARM32Movt::emit(const Cfg *Func) const; |
| 1130 template <> void InstARM32Vldr::emit(const Cfg *Func) const; | 1129 template <> void InstARM32Vldr::emit(const Cfg *Func) const; |
| 1131 template <> void InstARM32Vmov::emit(const Cfg *Func) const; | 1130 template <> void InstARM32Vmov::emit(const Cfg *Func) const; |
| 1132 | 1131 |
| 1133 } // end of namespace Ice | 1132 } // end of namespace Ice |
| 1134 | 1133 |
| 1135 #endif // SUBZERO_SRC_ICEINSTARM32_H | 1134 #endif // SUBZERO_SRC_ICEINSTARM32_H |
| OLD | NEW |