| 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 // This file declares the InstARM32 and OperandARM32 classes and | 10 // This file declares the InstARM32 and OperandARM32 classes and |
| 11 // their subclasses. This represents the machine instructions and | 11 // their subclasses. This represents the machine instructions and |
| 12 // operands used for ARM32 code selection. | 12 // operands used for ARM32 code selection. |
| 13 // | 13 // |
| 14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
| 15 | 15 |
| 16 #ifndef SUBZERO_SRC_ICEINSTARM32_H | 16 #ifndef SUBZERO_SRC_ICEINSTARM32_H |
| 17 #define SUBZERO_SRC_ICEINSTARM32_H | 17 #define SUBZERO_SRC_ICEINSTARM32_H |
| 18 | 18 |
| 19 #include "IceConditionCodesARM32.h" | 19 #include "IceConditionCodesARM32.h" |
| 20 #include "IceDefs.h" | 20 #include "IceDefs.h" |
| 21 #include "IceInst.h" | 21 #include "IceInst.h" |
| 22 #include "IceInstARM32.def" | 22 #include "IceInstARM32.def" |
| 23 #include "IceOperand.h" | 23 #include "IceOperand.h" |
| 24 | 24 |
| 25 namespace Ice { | 25 namespace Ice { |
| 26 | 26 |
| 27 class TargetARM32; | 27 class TargetARM32; |
| 28 | 28 |
| 29 // OperandARM32 extends the Operand hierarchy. Its subclasses are | 29 /// OperandARM32 extends the Operand hierarchy. Its subclasses are |
| 30 // OperandARM32Mem and OperandARM32Flex. | 30 /// OperandARM32Mem and OperandARM32Flex. |
| 31 class OperandARM32 : public Operand { | 31 class OperandARM32 : public Operand { |
| 32 OperandARM32() = delete; | 32 OperandARM32() = delete; |
| 33 OperandARM32(const OperandARM32 &) = delete; | 33 OperandARM32(const OperandARM32 &) = delete; |
| 34 OperandARM32 &operator=(const OperandARM32 &) = delete; | 34 OperandARM32 &operator=(const OperandARM32 &) = delete; |
| 35 | 35 |
| 36 public: | 36 public: |
| 37 enum OperandKindARM32 { | 37 enum OperandKindARM32 { |
| 38 k__Start = Operand::kTarget, | 38 k__Start = Operand::kTarget, |
| 39 kMem, | 39 kMem, |
| 40 kFlexStart, | 40 kFlexStart, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 54 void dump(const Cfg *, Ostream &Str) const override { | 54 void dump(const Cfg *, Ostream &Str) const override { |
| 55 if (BuildDefs::dump()) | 55 if (BuildDefs::dump()) |
| 56 Str << "<OperandARM32>"; | 56 Str << "<OperandARM32>"; |
| 57 } | 57 } |
| 58 | 58 |
| 59 protected: | 59 protected: |
| 60 OperandARM32(OperandKindARM32 Kind, Type Ty) | 60 OperandARM32(OperandKindARM32 Kind, Type Ty) |
| 61 : Operand(static_cast<OperandKind>(Kind), Ty) {} | 61 : Operand(static_cast<OperandKind>(Kind), Ty) {} |
| 62 }; | 62 }; |
| 63 | 63 |
| 64 // OperandARM32Mem represents a memory operand in any of the various ARM32 | 64 /// OperandARM32Mem represents a memory operand in any of the various ARM32 |
| 65 // addressing modes. | 65 /// addressing modes. |
| 66 class OperandARM32Mem : public OperandARM32 { | 66 class OperandARM32Mem : public OperandARM32 { |
| 67 OperandARM32Mem() = delete; | 67 OperandARM32Mem() = delete; |
| 68 OperandARM32Mem(const OperandARM32Mem &) = delete; | 68 OperandARM32Mem(const OperandARM32Mem &) = delete; |
| 69 OperandARM32Mem &operator=(const OperandARM32Mem &) = delete; | 69 OperandARM32Mem &operator=(const OperandARM32Mem &) = delete; |
| 70 | 70 |
| 71 public: | 71 public: |
| 72 // Memory operand addressing mode. | 72 /// Memory operand addressing mode. |
| 73 // The enum value also carries the encoding. | 73 /// The enum value also carries the encoding. |
| 74 // TODO(jvoung): unify with the assembler. | 74 // TODO(jvoung): unify with the assembler. |
| 75 enum AddrMode { | 75 enum AddrMode { |
| 76 // bit encoding P U W | 76 // bit encoding P U W |
| 77 Offset = (8 | 4 | 0) << 21, // offset (w/o writeback to base) | 77 Offset = (8 | 4 | 0) << 21, // offset (w/o writeback to base) |
| 78 PreIndex = (8 | 4 | 1) << 21, // pre-indexed addressing with writeback | 78 PreIndex = (8 | 4 | 1) << 21, // pre-indexed addressing with writeback |
| 79 PostIndex = (0 | 4 | 0) << 21, // post-indexed addressing with writeback | 79 PostIndex = (0 | 4 | 0) << 21, // post-indexed addressing with writeback |
| 80 NegOffset = (8 | 0 | 0) << 21, // negative offset (w/o writeback to base) | 80 NegOffset = (8 | 0 | 0) << 21, // negative offset (w/o writeback to base) |
| 81 NegPreIndex = (8 | 0 | 1) << 21, // negative pre-indexed with writeback | 81 NegPreIndex = (8 | 0 | 1) << 21, // negative pre-indexed with writeback |
| 82 NegPostIndex = (0 | 0 | 0) << 21 // negative post-indexed with writeback | 82 NegPostIndex = (0 | 0 | 0) << 21 // negative post-indexed with writeback |
| 83 }; | 83 }; |
| 84 | 84 |
| 85 // Provide two constructors. | 85 /// Provide two constructors. |
| 86 // NOTE: The Variable-typed operands have to be registers. | 86 /// NOTE: The Variable-typed operands have to be registers. |
| 87 // | 87 /// |
| 88 // (1) Reg + Imm. The Immediate actually has a limited number of bits | 88 /// (1) Reg + Imm. The Immediate actually has a limited number of bits |
| 89 // for encoding, so check canHoldOffset first. It cannot handle | 89 /// for encoding, so check canHoldOffset first. It cannot handle |
| 90 // general Constant operands like ConstantRelocatable, since a relocatable | 90 /// general Constant operands like ConstantRelocatable, since a relocatable |
| 91 // can potentially take up too many bits. | 91 /// can potentially take up too many bits. |
| 92 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, | 92 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, |
| 93 ConstantInteger32 *ImmOffset, | 93 ConstantInteger32 *ImmOffset, |
| 94 AddrMode Mode = Offset) { | 94 AddrMode Mode = Offset) { |
| 95 return new (Func->allocate<OperandARM32Mem>()) | 95 return new (Func->allocate<OperandARM32Mem>()) |
| 96 OperandARM32Mem(Func, Ty, Base, ImmOffset, Mode); | 96 OperandARM32Mem(Func, Ty, Base, ImmOffset, Mode); |
| 97 } | 97 } |
| 98 // (2) Reg +/- Reg with an optional shift of some kind and amount. | 98 /// (2) Reg +/- Reg with an optional shift of some kind and amount. |
| 99 // Note that this mode is disallowed in the NaCl sandbox. | 99 /// Note that this mode is disallowed in the NaCl sandbox. |
| 100 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, | 100 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, |
| 101 Variable *Index, ShiftKind ShiftOp = kNoShift, | 101 Variable *Index, ShiftKind ShiftOp = kNoShift, |
| 102 uint16_t ShiftAmt = 0, | 102 uint16_t ShiftAmt = 0, |
| 103 AddrMode Mode = Offset) { | 103 AddrMode Mode = Offset) { |
| 104 return new (Func->allocate<OperandARM32Mem>()) | 104 return new (Func->allocate<OperandARM32Mem>()) |
| 105 OperandARM32Mem(Func, Ty, Base, Index, ShiftOp, ShiftAmt, Mode); | 105 OperandARM32Mem(Func, Ty, Base, Index, ShiftOp, ShiftAmt, Mode); |
| 106 } | 106 } |
| 107 Variable *getBase() const { return Base; } | 107 Variable *getBase() const { return Base; } |
| 108 ConstantInteger32 *getOffset() const { return ImmOffset; } | 108 ConstantInteger32 *getOffset() const { return ImmOffset; } |
| 109 Variable *getIndex() const { return Index; } | 109 Variable *getIndex() const { return Index; } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 122 } | 122 } |
| 123 | 123 |
| 124 void emit(const Cfg *Func) const override; | 124 void emit(const Cfg *Func) const override; |
| 125 using OperandARM32::dump; | 125 using OperandARM32::dump; |
| 126 void dump(const Cfg *Func, Ostream &Str) const override; | 126 void dump(const Cfg *Func, Ostream &Str) const override; |
| 127 | 127 |
| 128 static bool classof(const Operand *Operand) { | 128 static bool classof(const Operand *Operand) { |
| 129 return Operand->getKind() == static_cast<OperandKind>(kMem); | 129 return Operand->getKind() == static_cast<OperandKind>(kMem); |
| 130 } | 130 } |
| 131 | 131 |
| 132 // Return true if a load/store instruction for an element of type Ty | 132 /// Return true if a load/store instruction for an element of type Ty |
| 133 // can encode the Offset directly in the immediate field of the 32-bit | 133 /// can encode the Offset directly in the immediate field of the 32-bit |
| 134 // ARM instruction. For some types, if the load is Sign extending, then | 134 /// ARM instruction. For some types, if the load is Sign extending, then |
| 135 // the range is reduced. | 135 /// the range is reduced. |
| 136 static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset); | 136 static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset); |
| 137 | 137 |
| 138 private: | 138 private: |
| 139 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, | 139 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, |
| 140 ConstantInteger32 *ImmOffset, AddrMode Mode); | 140 ConstantInteger32 *ImmOffset, AddrMode Mode); |
| 141 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, Variable *Index, | 141 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, Variable *Index, |
| 142 ShiftKind ShiftOp, uint16_t ShiftAmt, AddrMode Mode); | 142 ShiftKind ShiftOp, uint16_t ShiftAmt, AddrMode Mode); |
| 143 | 143 |
| 144 Variable *Base; | 144 Variable *Base; |
| 145 ConstantInteger32 *ImmOffset; | 145 ConstantInteger32 *ImmOffset; |
| 146 Variable *Index; | 146 Variable *Index; |
| 147 ShiftKind ShiftOp; | 147 ShiftKind ShiftOp; |
| 148 uint16_t ShiftAmt; | 148 uint16_t ShiftAmt; |
| 149 AddrMode Mode; | 149 AddrMode Mode; |
| 150 }; | 150 }; |
| 151 | 151 |
| 152 // OperandARM32Flex represent the "flexible second operand" for | 152 /// OperandARM32Flex represent the "flexible second operand" for |
| 153 // data-processing instructions. It can be a rotatable 8-bit constant, or | 153 /// data-processing instructions. It can be a rotatable 8-bit constant, or |
| 154 // a register with an optional shift operand. The shift amount can even be | 154 /// a register with an optional shift operand. The shift amount can even be |
| 155 // a third register. | 155 /// a third register. |
| 156 class OperandARM32Flex : public OperandARM32 { | 156 class OperandARM32Flex : public OperandARM32 { |
| 157 OperandARM32Flex() = delete; | 157 OperandARM32Flex() = delete; |
| 158 OperandARM32Flex(const OperandARM32Flex &) = delete; | 158 OperandARM32Flex(const OperandARM32Flex &) = delete; |
| 159 OperandARM32Flex &operator=(const OperandARM32Flex &) = delete; | 159 OperandARM32Flex &operator=(const OperandARM32Flex &) = delete; |
| 160 | 160 |
| 161 public: | 161 public: |
| 162 static bool classof(const Operand *Operand) { | 162 static bool classof(const Operand *Operand) { |
| 163 return static_cast<OperandKind>(kFlexStart) <= Operand->getKind() && | 163 return static_cast<OperandKind>(kFlexStart) <= Operand->getKind() && |
| 164 Operand->getKind() <= static_cast<OperandKind>(kFlexEnd); | 164 Operand->getKind() <= static_cast<OperandKind>(kFlexEnd); |
| 165 } | 165 } |
| 166 | 166 |
| 167 protected: | 167 protected: |
| 168 OperandARM32Flex(OperandKindARM32 Kind, Type Ty) : OperandARM32(Kind, Ty) {} | 168 OperandARM32Flex(OperandKindARM32 Kind, Type Ty) : OperandARM32(Kind, Ty) {} |
| 169 }; | 169 }; |
| 170 | 170 |
| 171 // Rotated immediate variant. | 171 /// Rotated immediate variant. |
| 172 class OperandARM32FlexImm : public OperandARM32Flex { | 172 class OperandARM32FlexImm : public OperandARM32Flex { |
| 173 OperandARM32FlexImm() = delete; | 173 OperandARM32FlexImm() = delete; |
| 174 OperandARM32FlexImm(const OperandARM32FlexImm &) = delete; | 174 OperandARM32FlexImm(const OperandARM32FlexImm &) = delete; |
| 175 OperandARM32FlexImm &operator=(const OperandARM32FlexImm &) = delete; | 175 OperandARM32FlexImm &operator=(const OperandARM32FlexImm &) = delete; |
| 176 | 176 |
| 177 public: | 177 public: |
| 178 // Immed_8 rotated by an even number of bits (2 * RotateAmt). | 178 /// Immed_8 rotated by an even number of bits (2 * RotateAmt). |
| 179 static OperandARM32FlexImm *create(Cfg *Func, Type Ty, uint32_t Imm, | 179 static OperandARM32FlexImm *create(Cfg *Func, Type Ty, uint32_t Imm, |
| 180 uint32_t RotateAmt) { | 180 uint32_t RotateAmt) { |
| 181 return new (Func->allocate<OperandARM32FlexImm>()) | 181 return new (Func->allocate<OperandARM32FlexImm>()) |
| 182 OperandARM32FlexImm(Func, Ty, Imm, RotateAmt); | 182 OperandARM32FlexImm(Func, Ty, Imm, RotateAmt); |
| 183 } | 183 } |
| 184 | 184 |
| 185 void emit(const Cfg *Func) const override; | 185 void emit(const Cfg *Func) const override; |
| 186 using OperandARM32::dump; | 186 using OperandARM32::dump; |
| 187 void dump(const Cfg *Func, Ostream &Str) const override; | 187 void dump(const Cfg *Func, Ostream &Str) const override; |
| 188 | 188 |
| 189 static bool classof(const Operand *Operand) { | 189 static bool classof(const Operand *Operand) { |
| 190 return Operand->getKind() == static_cast<OperandKind>(kFlexImm); | 190 return Operand->getKind() == static_cast<OperandKind>(kFlexImm); |
| 191 } | 191 } |
| 192 | 192 |
| 193 // 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. |
| 194 // Fills in the out-params RotateAmt and Immed_8 if Immediate fits. | 194 /// Fills in the out-params RotateAmt and Immed_8 if Immediate fits. |
| 195 static bool canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, | 195 static bool canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, |
| 196 uint32_t *Immed_8); | 196 uint32_t *Immed_8); |
| 197 | 197 |
| 198 uint32_t getImm() const { return Imm; } | 198 uint32_t getImm() const { return Imm; } |
| 199 uint32_t getRotateAmt() const { return RotateAmt; } | 199 uint32_t getRotateAmt() const { return RotateAmt; } |
| 200 | 200 |
| 201 private: | 201 private: |
| 202 OperandARM32FlexImm(Cfg *Func, Type Ty, uint32_t Imm, uint32_t RotateAmt); | 202 OperandARM32FlexImm(Cfg *Func, Type Ty, uint32_t Imm, uint32_t RotateAmt); |
| 203 | 203 |
| 204 uint32_t Imm; | 204 uint32_t Imm; |
| 205 uint32_t RotateAmt; | 205 uint32_t RotateAmt; |
| 206 }; | 206 }; |
| 207 | 207 |
| 208 // Shifted register variant. | 208 /// Shifted register variant. |
| 209 class OperandARM32FlexReg : public OperandARM32Flex { | 209 class OperandARM32FlexReg : public OperandARM32Flex { |
| 210 OperandARM32FlexReg() = delete; | 210 OperandARM32FlexReg() = delete; |
| 211 OperandARM32FlexReg(const OperandARM32FlexReg &) = delete; | 211 OperandARM32FlexReg(const OperandARM32FlexReg &) = delete; |
| 212 OperandARM32FlexReg &operator=(const OperandARM32FlexReg &) = delete; | 212 OperandARM32FlexReg &operator=(const OperandARM32FlexReg &) = delete; |
| 213 | 213 |
| 214 public: | 214 public: |
| 215 // Register with immediate/reg shift amount and shift operation. | 215 /// Register with immediate/reg shift amount and shift operation. |
| 216 static OperandARM32FlexReg *create(Cfg *Func, Type Ty, Variable *Reg, | 216 static OperandARM32FlexReg *create(Cfg *Func, Type Ty, Variable *Reg, |
| 217 ShiftKind ShiftOp, Operand *ShiftAmt) { | 217 ShiftKind ShiftOp, Operand *ShiftAmt) { |
| 218 return new (Func->allocate<OperandARM32FlexReg>()) | 218 return new (Func->allocate<OperandARM32FlexReg>()) |
| 219 OperandARM32FlexReg(Func, Ty, Reg, ShiftOp, ShiftAmt); | 219 OperandARM32FlexReg(Func, Ty, Reg, ShiftOp, ShiftAmt); |
| 220 } | 220 } |
| 221 | 221 |
| 222 void emit(const Cfg *Func) const override; | 222 void emit(const Cfg *Func) const override; |
| 223 using OperandARM32::dump; | 223 using OperandARM32::dump; |
| 224 void dump(const Cfg *Func, Ostream &Str) const override; | 224 void dump(const Cfg *Func, Ostream &Str) const override; |
| 225 | 225 |
| 226 static bool classof(const Operand *Operand) { | 226 static bool classof(const Operand *Operand) { |
| 227 return Operand->getKind() == static_cast<OperandKind>(kFlexReg); | 227 return Operand->getKind() == static_cast<OperandKind>(kFlexReg); |
| 228 } | 228 } |
| 229 | 229 |
| 230 Variable *getReg() const { return Reg; } | 230 Variable *getReg() const { return Reg; } |
| 231 ShiftKind getShiftOp() const { return ShiftOp; } | 231 ShiftKind getShiftOp() const { return ShiftOp; } |
| 232 // ShiftAmt can represent an immediate or a register. | 232 /// ShiftAmt can represent an immediate or a register. |
| 233 Operand *getShiftAmt() const { return ShiftAmt; } | 233 Operand *getShiftAmt() const { return ShiftAmt; } |
| 234 | 234 |
| 235 private: | 235 private: |
| 236 OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, ShiftKind ShiftOp, | 236 OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, ShiftKind ShiftOp, |
| 237 Operand *ShiftAmt); | 237 Operand *ShiftAmt); |
| 238 | 238 |
| 239 Variable *Reg; | 239 Variable *Reg; |
| 240 ShiftKind ShiftOp; | 240 ShiftKind ShiftOp; |
| 241 Operand *ShiftAmt; | 241 Operand *ShiftAmt; |
| 242 }; | 242 }; |
| 243 | 243 |
| 244 // Base class for ARM instructions. While most ARM instructions can be | 244 /// Base class for ARM instructions. While most ARM instructions can be |
| 245 // conditionally executed, a few of them are not predicable (halt, | 245 /// conditionally executed, a few of them are not predicable (halt, |
| 246 // memory barriers, etc.). | 246 /// memory barriers, etc.). |
| 247 class InstARM32 : public InstTarget { | 247 class InstARM32 : public InstTarget { |
| 248 InstARM32() = delete; | 248 InstARM32() = delete; |
| 249 InstARM32(const InstARM32 &) = delete; | 249 InstARM32(const InstARM32 &) = delete; |
| 250 InstARM32 &operator=(const InstARM32 &) = delete; | 250 InstARM32 &operator=(const InstARM32 &) = delete; |
| 251 | 251 |
| 252 public: | 252 public: |
| 253 enum InstKindARM32 { | 253 enum InstKindARM32 { |
| 254 k__Start = Inst::Target, | 254 k__Start = Inst::Target, |
| 255 Adc, | 255 Adc, |
| 256 Add, | 256 Add, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 | 291 |
| 292 protected: | 292 protected: |
| 293 InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest) | 293 InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest) |
| 294 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} | 294 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} |
| 295 | 295 |
| 296 static bool isClassof(const Inst *Inst, InstKindARM32 MyKind) { | 296 static bool isClassof(const Inst *Inst, InstKindARM32 MyKind) { |
| 297 return Inst->getKind() == static_cast<InstKind>(MyKind); | 297 return Inst->getKind() == static_cast<InstKind>(MyKind); |
| 298 } | 298 } |
| 299 }; | 299 }; |
| 300 | 300 |
| 301 // A predicable ARM instruction. | 301 /// A predicable ARM instruction. |
| 302 class InstARM32Pred : public InstARM32 { | 302 class InstARM32Pred : public InstARM32 { |
| 303 InstARM32Pred() = delete; | 303 InstARM32Pred() = delete; |
| 304 InstARM32Pred(const InstARM32Pred &) = delete; | 304 InstARM32Pred(const InstARM32Pred &) = delete; |
| 305 InstARM32Pred &operator=(const InstARM32Pred &) = delete; | 305 InstARM32Pred &operator=(const InstARM32Pred &) = delete; |
| 306 | 306 |
| 307 public: | 307 public: |
| 308 InstARM32Pred(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest, | 308 InstARM32Pred(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest, |
| 309 CondARM32::Cond Predicate) | 309 CondARM32::Cond Predicate) |
| 310 : InstARM32(Func, Kind, Maxsrcs, Dest), Predicate(Predicate) {} | 310 : InstARM32(Func, Kind, Maxsrcs, Dest), Predicate(Predicate) {} |
| 311 | 311 |
| 312 CondARM32::Cond getPredicate() const { return Predicate; } | 312 CondARM32::Cond getPredicate() const { return Predicate; } |
| 313 void setPredicate(CondARM32::Cond Pred) { Predicate = Pred; } | 313 void setPredicate(CondARM32::Cond Pred) { Predicate = Pred; } |
| 314 | 314 |
| 315 static const char *predString(CondARM32::Cond Predicate); | 315 static const char *predString(CondARM32::Cond Predicate); |
| 316 void dumpOpcodePred(Ostream &Str, const char *Opcode, Type Ty) const; | 316 void dumpOpcodePred(Ostream &Str, const char *Opcode, Type Ty) const; |
| 317 | 317 |
| 318 // Shared emit routines for common forms of instructions. | 318 /// Shared emit routines for common forms of instructions. |
| 319 static void emitUnaryopGPR(const char *Opcode, const InstARM32Pred *Inst, | 319 static void emitUnaryopGPR(const char *Opcode, const InstARM32Pred *Inst, |
| 320 const Cfg *Func); | 320 const Cfg *Func); |
| 321 static void emitTwoAddr(const char *Opcode, const InstARM32Pred *Inst, | 321 static void emitTwoAddr(const char *Opcode, const InstARM32Pred *Inst, |
| 322 const Cfg *Func); | 322 const Cfg *Func); |
| 323 static void emitThreeAddr(const char *Opcode, const InstARM32Pred *Inst, | 323 static void emitThreeAddr(const char *Opcode, const InstARM32Pred *Inst, |
| 324 const Cfg *Func, bool SetFlags); | 324 const Cfg *Func, bool SetFlags); |
| 325 | 325 |
| 326 protected: | 326 protected: |
| 327 CondARM32::Cond Predicate; | 327 CondARM32::Cond Predicate; |
| 328 }; | 328 }; |
| 329 | 329 |
| 330 template <typename StreamType> | 330 template <typename StreamType> |
| 331 inline StreamType &operator<<(StreamType &Stream, CondARM32::Cond Predicate) { | 331 inline StreamType &operator<<(StreamType &Stream, CondARM32::Cond Predicate) { |
| 332 Stream << InstARM32Pred::predString(Predicate); | 332 Stream << InstARM32Pred::predString(Predicate); |
| 333 return Stream; | 333 return Stream; |
| 334 } | 334 } |
| 335 | 335 |
| 336 // Instructions of the form x := op(y). | 336 /// Instructions of the form x := op(y). |
| 337 template <InstARM32::InstKindARM32 K> | 337 template <InstARM32::InstKindARM32 K> |
| 338 class InstARM32UnaryopGPR : public InstARM32Pred { | 338 class InstARM32UnaryopGPR : public InstARM32Pred { |
| 339 InstARM32UnaryopGPR() = delete; | 339 InstARM32UnaryopGPR() = delete; |
| 340 InstARM32UnaryopGPR(const InstARM32UnaryopGPR &) = delete; | 340 InstARM32UnaryopGPR(const InstARM32UnaryopGPR &) = delete; |
| 341 InstARM32UnaryopGPR &operator=(const InstARM32UnaryopGPR &) = delete; | 341 InstARM32UnaryopGPR &operator=(const InstARM32UnaryopGPR &) = delete; |
| 342 | 342 |
| 343 public: | 343 public: |
| 344 static InstARM32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src, | 344 static InstARM32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src, |
| 345 CondARM32::Cond Predicate) { | 345 CondARM32::Cond Predicate) { |
| 346 return new (Func->allocate<InstARM32UnaryopGPR>()) | 346 return new (Func->allocate<InstARM32UnaryopGPR>()) |
| (...skipping 23 matching lines...) Expand all Loading... |
| 370 private: | 370 private: |
| 371 InstARM32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src, | 371 InstARM32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src, |
| 372 CondARM32::Cond Predicate) | 372 CondARM32::Cond Predicate) |
| 373 : InstARM32Pred(Func, K, 1, Dest, Predicate) { | 373 : InstARM32Pred(Func, K, 1, Dest, Predicate) { |
| 374 addSource(Src); | 374 addSource(Src); |
| 375 } | 375 } |
| 376 | 376 |
| 377 static const char *Opcode; | 377 static const char *Opcode; |
| 378 }; | 378 }; |
| 379 | 379 |
| 380 // Instructions of the form x := x op y. | 380 /// Instructions of the form x := x op y. |
| 381 template <InstARM32::InstKindARM32 K> | 381 template <InstARM32::InstKindARM32 K> |
| 382 class InstARM32TwoAddrGPR : public InstARM32Pred { | 382 class InstARM32TwoAddrGPR : public InstARM32Pred { |
| 383 InstARM32TwoAddrGPR() = delete; | 383 InstARM32TwoAddrGPR() = delete; |
| 384 InstARM32TwoAddrGPR(const InstARM32TwoAddrGPR &) = delete; | 384 InstARM32TwoAddrGPR(const InstARM32TwoAddrGPR &) = delete; |
| 385 InstARM32TwoAddrGPR &operator=(const InstARM32TwoAddrGPR &) = delete; | 385 InstARM32TwoAddrGPR &operator=(const InstARM32TwoAddrGPR &) = delete; |
| 386 | 386 |
| 387 public: | 387 public: |
| 388 // Dest must be a register. | 388 /// Dest must be a register. |
| 389 static InstARM32TwoAddrGPR *create(Cfg *Func, Variable *Dest, Operand *Src, | 389 static InstARM32TwoAddrGPR *create(Cfg *Func, Variable *Dest, Operand *Src, |
| 390 CondARM32::Cond Predicate) { | 390 CondARM32::Cond Predicate) { |
| 391 return new (Func->allocate<InstARM32TwoAddrGPR>()) | 391 return new (Func->allocate<InstARM32TwoAddrGPR>()) |
| 392 InstARM32TwoAddrGPR(Func, Dest, Src, Predicate); | 392 InstARM32TwoAddrGPR(Func, Dest, Src, Predicate); |
| 393 } | 393 } |
| 394 void emit(const Cfg *Func) const override { | 394 void emit(const Cfg *Func) const override { |
| 395 if (!BuildDefs::dump()) | 395 if (!BuildDefs::dump()) |
| 396 return; | 396 return; |
| 397 emitTwoAddr(Opcode, this, Func); | 397 emitTwoAddr(Opcode, this, Func); |
| 398 } | 398 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 416 InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src, | 416 InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src, |
| 417 CondARM32::Cond Predicate) | 417 CondARM32::Cond Predicate) |
| 418 : InstARM32Pred(Func, K, 2, Dest, Predicate) { | 418 : InstARM32Pred(Func, K, 2, Dest, Predicate) { |
| 419 addSource(Dest); | 419 addSource(Dest); |
| 420 addSource(Src); | 420 addSource(Src); |
| 421 } | 421 } |
| 422 | 422 |
| 423 static const char *Opcode; | 423 static const char *Opcode; |
| 424 }; | 424 }; |
| 425 | 425 |
| 426 // Base class for assignment instructions. | 426 /// Base class for assignment instructions. |
| 427 // These can be tested for redundancy (and elided if redundant). | 427 /// These can be tested for redundancy (and elided if redundant). |
| 428 template <InstARM32::InstKindARM32 K> | 428 template <InstARM32::InstKindARM32 K> |
| 429 class InstARM32Movlike : public InstARM32Pred { | 429 class InstARM32Movlike : public InstARM32Pred { |
| 430 InstARM32Movlike() = delete; | 430 InstARM32Movlike() = delete; |
| 431 InstARM32Movlike(const InstARM32Movlike &) = delete; | 431 InstARM32Movlike(const InstARM32Movlike &) = delete; |
| 432 InstARM32Movlike &operator=(const InstARM32Movlike &) = delete; | 432 InstARM32Movlike &operator=(const InstARM32Movlike &) = delete; |
| 433 | 433 |
| 434 public: | 434 public: |
| 435 static InstARM32Movlike *create(Cfg *Func, Variable *Dest, Operand *Source, | 435 static InstARM32Movlike *create(Cfg *Func, Variable *Dest, Operand *Source, |
| 436 CondARM32::Cond Predicate) { | 436 CondARM32::Cond Predicate) { |
| 437 return new (Func->allocate<InstARM32Movlike>()) | 437 return new (Func->allocate<InstARM32Movlike>()) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 458 private: | 458 private: |
| 459 InstARM32Movlike(Cfg *Func, Variable *Dest, Operand *Source, | 459 InstARM32Movlike(Cfg *Func, Variable *Dest, Operand *Source, |
| 460 CondARM32::Cond Predicate) | 460 CondARM32::Cond Predicate) |
| 461 : InstARM32Pred(Func, K, 1, Dest, Predicate) { | 461 : InstARM32Pred(Func, K, 1, Dest, Predicate) { |
| 462 addSource(Source); | 462 addSource(Source); |
| 463 } | 463 } |
| 464 | 464 |
| 465 static const char *Opcode; | 465 static const char *Opcode; |
| 466 }; | 466 }; |
| 467 | 467 |
| 468 // Instructions of the form x := y op z. May have the side-effect of setting | 468 /// Instructions of the form x := y op z. May have the side-effect of setting |
| 469 // status flags. | 469 /// status flags. |
| 470 template <InstARM32::InstKindARM32 K> | 470 template <InstARM32::InstKindARM32 K> |
| 471 class InstARM32ThreeAddrGPR : public InstARM32Pred { | 471 class InstARM32ThreeAddrGPR : public InstARM32Pred { |
| 472 InstARM32ThreeAddrGPR() = delete; | 472 InstARM32ThreeAddrGPR() = delete; |
| 473 InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete; | 473 InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete; |
| 474 InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete; | 474 InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete; |
| 475 | 475 |
| 476 public: | 476 public: |
| 477 // Create an ordinary binary-op instruction like add, and sub. | 477 /// Create an ordinary binary-op instruction like add, and sub. |
| 478 // Dest and Src1 must be registers. | 478 /// Dest and Src1 must be registers. |
| 479 static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest, | 479 static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest, |
| 480 Variable *Src1, Operand *Src2, | 480 Variable *Src1, Operand *Src2, |
| 481 CondARM32::Cond Predicate, | 481 CondARM32::Cond Predicate, |
| 482 bool SetFlags = false) { | 482 bool SetFlags = false) { |
| 483 return new (Func->allocate<InstARM32ThreeAddrGPR>()) | 483 return new (Func->allocate<InstARM32ThreeAddrGPR>()) |
| 484 InstARM32ThreeAddrGPR(Func, Dest, Src1, Src2, Predicate, SetFlags); | 484 InstARM32ThreeAddrGPR(Func, Dest, Src1, Src2, Predicate, SetFlags); |
| 485 } | 485 } |
| 486 void emit(const Cfg *Func) const override { | 486 void emit(const Cfg *Func) const override { |
| 487 if (!BuildDefs::dump()) | 487 if (!BuildDefs::dump()) |
| 488 return; | 488 return; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 typedef InstARM32ThreeAddrGPR<InstARM32::Asr> InstARM32Asr; | 522 typedef InstARM32ThreeAddrGPR<InstARM32::Asr> InstARM32Asr; |
| 523 typedef InstARM32ThreeAddrGPR<InstARM32::Bic> InstARM32Bic; | 523 typedef InstARM32ThreeAddrGPR<InstARM32::Bic> InstARM32Bic; |
| 524 typedef InstARM32ThreeAddrGPR<InstARM32::Eor> InstARM32Eor; | 524 typedef InstARM32ThreeAddrGPR<InstARM32::Eor> InstARM32Eor; |
| 525 typedef InstARM32ThreeAddrGPR<InstARM32::Lsl> InstARM32Lsl; | 525 typedef InstARM32ThreeAddrGPR<InstARM32::Lsl> InstARM32Lsl; |
| 526 typedef InstARM32ThreeAddrGPR<InstARM32::Lsr> InstARM32Lsr; | 526 typedef InstARM32ThreeAddrGPR<InstARM32::Lsr> InstARM32Lsr; |
| 527 typedef InstARM32ThreeAddrGPR<InstARM32::Mul> InstARM32Mul; | 527 typedef InstARM32ThreeAddrGPR<InstARM32::Mul> InstARM32Mul; |
| 528 typedef InstARM32ThreeAddrGPR<InstARM32::Orr> InstARM32Orr; | 528 typedef InstARM32ThreeAddrGPR<InstARM32::Orr> InstARM32Orr; |
| 529 typedef InstARM32ThreeAddrGPR<InstARM32::Rsb> InstARM32Rsb; | 529 typedef InstARM32ThreeAddrGPR<InstARM32::Rsb> InstARM32Rsb; |
| 530 typedef InstARM32ThreeAddrGPR<InstARM32::Sbc> InstARM32Sbc; | 530 typedef InstARM32ThreeAddrGPR<InstARM32::Sbc> InstARM32Sbc; |
| 531 typedef InstARM32ThreeAddrGPR<InstARM32::Sub> InstARM32Sub; | 531 typedef InstARM32ThreeAddrGPR<InstARM32::Sub> InstARM32Sub; |
| 532 // Move instruction (variable <- flex). This is more of a pseudo-inst. | 532 /// Move instruction (variable <- flex). This is more of a pseudo-inst. |
| 533 // If var is a register, then we use "mov". If var is stack, then we use | 533 /// If var is a register, then we use "mov". If var is stack, then we use |
| 534 // "str" to store to the stack. | 534 /// "str" to store to the stack. |
| 535 typedef InstARM32Movlike<InstARM32::Mov> InstARM32Mov; | 535 typedef InstARM32Movlike<InstARM32::Mov> InstARM32Mov; |
| 536 // MovT leaves the bottom bits alone so dest is also a source. | 536 /// MovT leaves the bottom bits alone so dest is also a source. |
| 537 // This helps indicate that a previous MovW setting dest is not dead code. | 537 /// This helps indicate that a previous MovW setting dest is not dead code. |
| 538 typedef InstARM32TwoAddrGPR<InstARM32::Movt> InstARM32Movt; | 538 typedef InstARM32TwoAddrGPR<InstARM32::Movt> InstARM32Movt; |
| 539 typedef InstARM32UnaryopGPR<InstARM32::Movw> InstARM32Movw; | 539 typedef InstARM32UnaryopGPR<InstARM32::Movw> InstARM32Movw; |
| 540 typedef InstARM32UnaryopGPR<InstARM32::Mvn> InstARM32Mvn; | 540 typedef InstARM32UnaryopGPR<InstARM32::Mvn> InstARM32Mvn; |
| 541 // Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation | 541 // Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation |
| 542 // operand as well (rotate source by 8, 16, 24 bits prior to extending), | 542 // operand as well (rotate source by 8, 16, 24 bits prior to extending), |
| 543 // but we aren't using that for now, so just model as a Unaryop. | 543 // but we aren't using that for now, so just model as a Unaryop. |
| 544 typedef InstARM32UnaryopGPR<InstARM32::Sxt> InstARM32Sxt; | 544 typedef InstARM32UnaryopGPR<InstARM32::Sxt> InstARM32Sxt; |
| 545 typedef InstARM32UnaryopGPR<InstARM32::Uxt> InstARM32Uxt; | 545 typedef InstARM32UnaryopGPR<InstARM32::Uxt> InstARM32Uxt; |
| 546 | 546 |
| 547 // Direct branch instruction. | 547 /// Direct branch instruction. |
| 548 class InstARM32Br : public InstARM32Pred { | 548 class InstARM32Br : public InstARM32Pred { |
| 549 InstARM32Br() = delete; | 549 InstARM32Br() = delete; |
| 550 InstARM32Br(const InstARM32Br &) = delete; | 550 InstARM32Br(const InstARM32Br &) = delete; |
| 551 InstARM32Br &operator=(const InstARM32Br &) = delete; | 551 InstARM32Br &operator=(const InstARM32Br &) = delete; |
| 552 | 552 |
| 553 public: | 553 public: |
| 554 // Create a conditional branch to one of two nodes. | 554 /// Create a conditional branch to one of two nodes. |
| 555 static InstARM32Br *create(Cfg *Func, CfgNode *TargetTrue, | 555 static InstARM32Br *create(Cfg *Func, CfgNode *TargetTrue, |
| 556 CfgNode *TargetFalse, CondARM32::Cond Predicate) { | 556 CfgNode *TargetFalse, CondARM32::Cond Predicate) { |
| 557 assert(Predicate != CondARM32::AL); | 557 assert(Predicate != CondARM32::AL); |
| 558 return new (Func->allocate<InstARM32Br>()) | 558 return new (Func->allocate<InstARM32Br>()) |
| 559 InstARM32Br(Func, TargetTrue, TargetFalse, Predicate); | 559 InstARM32Br(Func, TargetTrue, TargetFalse, Predicate); |
| 560 } | 560 } |
| 561 // Create an unconditional branch to a node. | 561 /// Create an unconditional branch to a node. |
| 562 static InstARM32Br *create(Cfg *Func, CfgNode *Target) { | 562 static InstARM32Br *create(Cfg *Func, CfgNode *Target) { |
| 563 const CfgNode *NoCondTarget = nullptr; | 563 const CfgNode *NoCondTarget = nullptr; |
| 564 return new (Func->allocate<InstARM32Br>()) | 564 return new (Func->allocate<InstARM32Br>()) |
| 565 InstARM32Br(Func, NoCondTarget, Target, CondARM32::AL); | 565 InstARM32Br(Func, NoCondTarget, Target, CondARM32::AL); |
| 566 } | 566 } |
| 567 // Create a non-terminator conditional branch to a node, with a | 567 /// Create a non-terminator conditional branch to a node, with a |
| 568 // fallthrough to the next instruction in the current node. This is | 568 /// fallthrough to the next instruction in the current node. This is |
| 569 // used for switch lowering. | 569 /// used for switch lowering. |
| 570 static InstARM32Br *create(Cfg *Func, CfgNode *Target, | 570 static InstARM32Br *create(Cfg *Func, CfgNode *Target, |
| 571 CondARM32::Cond Predicate) { | 571 CondARM32::Cond Predicate) { |
| 572 assert(Predicate != CondARM32::AL); | 572 assert(Predicate != CondARM32::AL); |
| 573 const CfgNode *NoUncondTarget = nullptr; | 573 const CfgNode *NoUncondTarget = nullptr; |
| 574 return new (Func->allocate<InstARM32Br>()) | 574 return new (Func->allocate<InstARM32Br>()) |
| 575 InstARM32Br(Func, Target, NoUncondTarget, Predicate); | 575 InstARM32Br(Func, Target, NoUncondTarget, Predicate); |
| 576 } | 576 } |
| 577 const CfgNode *getTargetTrue() const { return TargetTrue; } | 577 const CfgNode *getTargetTrue() const { return TargetTrue; } |
| 578 const CfgNode *getTargetFalse() const { return TargetFalse; } | 578 const CfgNode *getTargetFalse() const { return TargetFalse; } |
| 579 bool optimizeBranch(const CfgNode *NextNode); | 579 bool optimizeBranch(const CfgNode *NextNode); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 595 static bool classof(const Inst *Inst) { return isClassof(Inst, Br); } | 595 static bool classof(const Inst *Inst) { return isClassof(Inst, Br); } |
| 596 | 596 |
| 597 private: | 597 private: |
| 598 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, | 598 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, |
| 599 CondARM32::Cond Predicate); | 599 CondARM32::Cond Predicate); |
| 600 | 600 |
| 601 const CfgNode *TargetTrue; | 601 const CfgNode *TargetTrue; |
| 602 const CfgNode *TargetFalse; | 602 const CfgNode *TargetFalse; |
| 603 }; | 603 }; |
| 604 | 604 |
| 605 // AdjustStack instruction - subtracts SP by the given amount and | 605 /// AdjustStack instruction - subtracts SP by the given amount and |
| 606 // updates the stack offset during code emission. | 606 /// updates the stack offset during code emission. |
| 607 class InstARM32AdjustStack : public InstARM32 { | 607 class InstARM32AdjustStack : public InstARM32 { |
| 608 InstARM32AdjustStack() = delete; | 608 InstARM32AdjustStack() = delete; |
| 609 InstARM32AdjustStack(const InstARM32AdjustStack &) = delete; | 609 InstARM32AdjustStack(const InstARM32AdjustStack &) = delete; |
| 610 InstARM32AdjustStack &operator=(const InstARM32AdjustStack &) = delete; | 610 InstARM32AdjustStack &operator=(const InstARM32AdjustStack &) = delete; |
| 611 | 611 |
| 612 public: | 612 public: |
| 613 // Note: We need both Amount and SrcAmount. If Amount is too large then | 613 /// Note: We need both Amount and SrcAmount. If Amount is too large then |
| 614 // it needs to be copied to a register (so SrcAmount could be a register). | 614 /// it needs to be copied to a register (so SrcAmount could be a register). |
| 615 // However, we also need the numeric Amount for bookkeeping, and it's | 615 /// However, we also need the numeric Amount for bookkeeping, and it's |
| 616 // hard to pull that from the generic SrcAmount operand. | 616 /// hard to pull that from the generic SrcAmount operand. |
| 617 static InstARM32AdjustStack *create(Cfg *Func, Variable *SP, SizeT Amount, | 617 static InstARM32AdjustStack *create(Cfg *Func, Variable *SP, SizeT Amount, |
| 618 Operand *SrcAmount) { | 618 Operand *SrcAmount) { |
| 619 return new (Func->allocate<InstARM32AdjustStack>()) | 619 return new (Func->allocate<InstARM32AdjustStack>()) |
| 620 InstARM32AdjustStack(Func, SP, Amount, SrcAmount); | 620 InstARM32AdjustStack(Func, SP, Amount, SrcAmount); |
| 621 } | 621 } |
| 622 void emit(const Cfg *Func) const override; | 622 void emit(const Cfg *Func) const override; |
| 623 void emitIAS(const Cfg *Func) const override; | 623 void emitIAS(const Cfg *Func) const override; |
| 624 void dump(const Cfg *Func) const override; | 624 void dump(const Cfg *Func) const override; |
| 625 static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); } | 625 static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); } |
| 626 | 626 |
| 627 private: | 627 private: |
| 628 InstARM32AdjustStack(Cfg *Func, Variable *SP, SizeT Amount, | 628 InstARM32AdjustStack(Cfg *Func, Variable *SP, SizeT Amount, |
| 629 Operand *SrcAmount); | 629 Operand *SrcAmount); |
| 630 const SizeT Amount; | 630 const SizeT Amount; |
| 631 }; | 631 }; |
| 632 | 632 |
| 633 // Call instruction (bl/blx). Arguments should have already been pushed. | 633 /// Call instruction (bl/blx). Arguments should have already been pushed. |
| 634 // Technically bl and the register form of blx can be predicated, but we'll | 634 /// Technically bl and the register form of blx can be predicated, but we'll |
| 635 // leave that out until needed. | 635 /// leave that out until needed. |
| 636 class InstARM32Call : public InstARM32 { | 636 class InstARM32Call : public InstARM32 { |
| 637 InstARM32Call() = delete; | 637 InstARM32Call() = delete; |
| 638 InstARM32Call(const InstARM32Call &) = delete; | 638 InstARM32Call(const InstARM32Call &) = delete; |
| 639 InstARM32Call &operator=(const InstARM32Call &) = delete; | 639 InstARM32Call &operator=(const InstARM32Call &) = delete; |
| 640 | 640 |
| 641 public: | 641 public: |
| 642 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { | 642 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { |
| 643 return new (Func->allocate<InstARM32Call>()) | 643 return new (Func->allocate<InstARM32Call>()) |
| 644 InstARM32Call(Func, Dest, CallTarget); | 644 InstARM32Call(Func, Dest, CallTarget); |
| 645 } | 645 } |
| 646 Operand *getCallTarget() const { return getSrc(0); } | 646 Operand *getCallTarget() const { return getSrc(0); } |
| 647 void emit(const Cfg *Func) const override; | 647 void emit(const Cfg *Func) const override; |
| 648 void emitIAS(const Cfg *Func) const override; | 648 void emitIAS(const Cfg *Func) const override; |
| 649 void dump(const Cfg *Func) const override; | 649 void dump(const Cfg *Func) const override; |
| 650 static bool classof(const Inst *Inst) { return isClassof(Inst, Call); } | 650 static bool classof(const Inst *Inst) { return isClassof(Inst, Call); } |
| 651 | 651 |
| 652 private: | 652 private: |
| 653 InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget); | 653 InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget); |
| 654 }; | 654 }; |
| 655 | 655 |
| 656 // Integer compare instruction. | 656 /// Integer compare instruction. |
| 657 class InstARM32Cmp : public InstARM32Pred { | 657 class InstARM32Cmp : public InstARM32Pred { |
| 658 InstARM32Cmp() = delete; | 658 InstARM32Cmp() = delete; |
| 659 InstARM32Cmp(const InstARM32Cmp &) = delete; | 659 InstARM32Cmp(const InstARM32Cmp &) = delete; |
| 660 InstARM32Cmp &operator=(const InstARM32Cmp &) = delete; | 660 InstARM32Cmp &operator=(const InstARM32Cmp &) = delete; |
| 661 | 661 |
| 662 public: | 662 public: |
| 663 static InstARM32Cmp *create(Cfg *Func, Variable *Src1, Operand *Src2, | 663 static InstARM32Cmp *create(Cfg *Func, Variable *Src1, Operand *Src2, |
| 664 CondARM32::Cond Predicate) { | 664 CondARM32::Cond Predicate) { |
| 665 return new (Func->allocate<InstARM32Cmp>()) | 665 return new (Func->allocate<InstARM32Cmp>()) |
| 666 InstARM32Cmp(Func, Src1, Src2, Predicate); | 666 InstARM32Cmp(Func, Src1, Src2, Predicate); |
| 667 } | 667 } |
| 668 void emit(const Cfg *Func) const override; | 668 void emit(const Cfg *Func) const override; |
| 669 void emitIAS(const Cfg *Func) const override; | 669 void emitIAS(const Cfg *Func) const override; |
| 670 void dump(const Cfg *Func) const override; | 670 void dump(const Cfg *Func) const override; |
| 671 static bool classof(const Inst *Inst) { return isClassof(Inst, Cmp); } | 671 static bool classof(const Inst *Inst) { return isClassof(Inst, Cmp); } |
| 672 | 672 |
| 673 private: | 673 private: |
| 674 InstARM32Cmp(Cfg *Func, Variable *Src1, Operand *Src2, | 674 InstARM32Cmp(Cfg *Func, Variable *Src1, Operand *Src2, |
| 675 CondARM32::Cond Predicate); | 675 CondARM32::Cond Predicate); |
| 676 }; | 676 }; |
| 677 | 677 |
| 678 // Load instruction. | 678 /// Load instruction. |
| 679 class InstARM32Ldr : public InstARM32Pred { | 679 class InstARM32Ldr : public InstARM32Pred { |
| 680 InstARM32Ldr() = delete; | 680 InstARM32Ldr() = delete; |
| 681 InstARM32Ldr(const InstARM32Ldr &) = delete; | 681 InstARM32Ldr(const InstARM32Ldr &) = delete; |
| 682 InstARM32Ldr &operator=(const InstARM32Ldr &) = delete; | 682 InstARM32Ldr &operator=(const InstARM32Ldr &) = delete; |
| 683 | 683 |
| 684 public: | 684 public: |
| 685 // Dest must be a register. | 685 /// Dest must be a register. |
| 686 static InstARM32Ldr *create(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem, | 686 static InstARM32Ldr *create(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem, |
| 687 CondARM32::Cond Predicate) { | 687 CondARM32::Cond Predicate) { |
| 688 return new (Func->allocate<InstARM32Ldr>()) | 688 return new (Func->allocate<InstARM32Ldr>()) |
| 689 InstARM32Ldr(Func, Dest, Mem, Predicate); | 689 InstARM32Ldr(Func, Dest, Mem, Predicate); |
| 690 } | 690 } |
| 691 void emit(const Cfg *Func) const override; | 691 void emit(const Cfg *Func) const override; |
| 692 void emitIAS(const Cfg *Func) const override; | 692 void emitIAS(const Cfg *Func) const override; |
| 693 void dump(const Cfg *Func) const override; | 693 void dump(const Cfg *Func) const override; |
| 694 static bool classof(const Inst *Inst) { return isClassof(Inst, Ldr); } | 694 static bool classof(const Inst *Inst) { return isClassof(Inst, Ldr); } |
| 695 | 695 |
| 696 private: | 696 private: |
| 697 InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem, | 697 InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem, |
| 698 CondARM32::Cond Predicate); | 698 CondARM32::Cond Predicate); |
| 699 }; | 699 }; |
| 700 | 700 |
| 701 // Multiply Accumulate: d := x * y + a | 701 /// Multiply Accumulate: d := x * y + a |
| 702 class InstARM32Mla : public InstARM32Pred { | 702 class InstARM32Mla : public InstARM32Pred { |
| 703 InstARM32Mla() = delete; | 703 InstARM32Mla() = delete; |
| 704 InstARM32Mla(const InstARM32Mla &) = delete; | 704 InstARM32Mla(const InstARM32Mla &) = delete; |
| 705 InstARM32Mla &operator=(const InstARM32Mla &) = delete; | 705 InstARM32Mla &operator=(const InstARM32Mla &) = delete; |
| 706 | 706 |
| 707 public: | 707 public: |
| 708 // Everything must be a register. | 708 /// Everything must be a register. |
| 709 static InstARM32Mla *create(Cfg *Func, Variable *Dest, Variable *Src0, | 709 static InstARM32Mla *create(Cfg *Func, Variable *Dest, Variable *Src0, |
| 710 Variable *Src1, Variable *Acc, | 710 Variable *Src1, Variable *Acc, |
| 711 CondARM32::Cond Predicate) { | 711 CondARM32::Cond Predicate) { |
| 712 return new (Func->allocate<InstARM32Mla>()) | 712 return new (Func->allocate<InstARM32Mla>()) |
| 713 InstARM32Mla(Func, Dest, Src0, Src1, Acc, Predicate); | 713 InstARM32Mla(Func, Dest, Src0, Src1, Acc, Predicate); |
| 714 } | 714 } |
| 715 void emit(const Cfg *Func) const override; | 715 void emit(const Cfg *Func) const override; |
| 716 void emitIAS(const Cfg *Func) const override; | 716 void emitIAS(const Cfg *Func) const override; |
| 717 void dump(const Cfg *Func) const override; | 717 void dump(const Cfg *Func) const override; |
| 718 static bool classof(const Inst *Inst) { return isClassof(Inst, Mla); } | 718 static bool classof(const Inst *Inst) { return isClassof(Inst, Mla); } |
| 719 | 719 |
| 720 private: | 720 private: |
| 721 InstARM32Mla(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1, | 721 InstARM32Mla(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1, |
| 722 Variable *Acc, CondARM32::Cond Predicate); | 722 Variable *Acc, CondARM32::Cond Predicate); |
| 723 }; | 723 }; |
| 724 | 724 |
| 725 // Pop into a list of GPRs. Technically this can be predicated, but we don't | 725 /// Pop into a list of GPRs. Technically this can be predicated, but we don't |
| 726 // need that functionality. | 726 /// need that functionality. |
| 727 class InstARM32Pop : public InstARM32 { | 727 class InstARM32Pop : public InstARM32 { |
| 728 InstARM32Pop() = delete; | 728 InstARM32Pop() = delete; |
| 729 InstARM32Pop(const InstARM32Pop &) = delete; | 729 InstARM32Pop(const InstARM32Pop &) = delete; |
| 730 InstARM32Pop &operator=(const InstARM32Pop &) = delete; | 730 InstARM32Pop &operator=(const InstARM32Pop &) = delete; |
| 731 | 731 |
| 732 public: | 732 public: |
| 733 static InstARM32Pop *create(Cfg *Func, const VarList &Dests) { | 733 static InstARM32Pop *create(Cfg *Func, const VarList &Dests) { |
| 734 return new (Func->allocate<InstARM32Pop>()) InstARM32Pop(Func, Dests); | 734 return new (Func->allocate<InstARM32Pop>()) InstARM32Pop(Func, Dests); |
| 735 } | 735 } |
| 736 void emit(const Cfg *Func) const override; | 736 void emit(const Cfg *Func) const override; |
| 737 void emitIAS(const Cfg *Func) const override; | 737 void emitIAS(const Cfg *Func) const override; |
| 738 void dump(const Cfg *Func) const override; | 738 void dump(const Cfg *Func) const override; |
| 739 static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } | 739 static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } |
| 740 | 740 |
| 741 private: | 741 private: |
| 742 InstARM32Pop(Cfg *Func, const VarList &Dests); | 742 InstARM32Pop(Cfg *Func, const VarList &Dests); |
| 743 | 743 |
| 744 VarList Dests; | 744 VarList Dests; |
| 745 }; | 745 }; |
| 746 | 746 |
| 747 // Push a list of GPRs. Technically this can be predicated, but we don't | 747 /// Push a list of GPRs. Technically this can be predicated, but we don't |
| 748 // need that functionality. | 748 /// need that functionality. |
| 749 class InstARM32Push : public InstARM32 { | 749 class InstARM32Push : public InstARM32 { |
| 750 InstARM32Push() = delete; | 750 InstARM32Push() = delete; |
| 751 InstARM32Push(const InstARM32Push &) = delete; | 751 InstARM32Push(const InstARM32Push &) = delete; |
| 752 InstARM32Push &operator=(const InstARM32Push &) = delete; | 752 InstARM32Push &operator=(const InstARM32Push &) = delete; |
| 753 | 753 |
| 754 public: | 754 public: |
| 755 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) { | 755 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) { |
| 756 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); | 756 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); |
| 757 } | 757 } |
| 758 void emit(const Cfg *Func) const override; | 758 void emit(const Cfg *Func) const override; |
| 759 void emitIAS(const Cfg *Func) const override; | 759 void emitIAS(const Cfg *Func) const override; |
| 760 void dump(const Cfg *Func) const override; | 760 void dump(const Cfg *Func) const override; |
| 761 static bool classof(const Inst *Inst) { return isClassof(Inst, Push); } | 761 static bool classof(const Inst *Inst) { return isClassof(Inst, Push); } |
| 762 | 762 |
| 763 private: | 763 private: |
| 764 InstARM32Push(Cfg *Func, const VarList &Srcs); | 764 InstARM32Push(Cfg *Func, const VarList &Srcs); |
| 765 }; | 765 }; |
| 766 | 766 |
| 767 // Ret pseudo-instruction. This is actually a "bx" instruction with | 767 /// Ret pseudo-instruction. This is actually a "bx" instruction with |
| 768 // an "lr" register operand, but epilogue lowering will search for a Ret | 768 /// an "lr" register operand, but epilogue lowering will search for a Ret |
| 769 // instead of a generic "bx". This instruction also takes a Source | 769 /// instead of a generic "bx". This instruction also takes a Source |
| 770 // operand (for non-void returning functions) for liveness analysis, though | 770 /// operand (for non-void returning functions) for liveness analysis, though |
| 771 // a FakeUse before the ret would do just as well. | 771 /// a FakeUse before the ret would do just as well. |
| 772 // | 772 /// |
| 773 // NOTE: Even though "bx" can be predicated, for now leave out the predication | 773 /// NOTE: Even though "bx" can be predicated, for now leave out the predication |
| 774 // since it's not yet known to be useful for Ret. That may complicate finding | 774 /// since it's not yet known to be useful for Ret. That may complicate finding |
| 775 // the terminator instruction if it's not guaranteed to be executed. | 775 /// the terminator instruction if it's not guaranteed to be executed. |
| 776 class InstARM32Ret : public InstARM32 { | 776 class InstARM32Ret : public InstARM32 { |
| 777 InstARM32Ret() = delete; | 777 InstARM32Ret() = delete; |
| 778 InstARM32Ret(const InstARM32Ret &) = delete; | 778 InstARM32Ret(const InstARM32Ret &) = delete; |
| 779 InstARM32Ret &operator=(const InstARM32Ret &) = delete; | 779 InstARM32Ret &operator=(const InstARM32Ret &) = delete; |
| 780 | 780 |
| 781 public: | 781 public: |
| 782 static InstARM32Ret *create(Cfg *Func, Variable *LR, | 782 static InstARM32Ret *create(Cfg *Func, Variable *LR, |
| 783 Variable *Source = nullptr) { | 783 Variable *Source = nullptr) { |
| 784 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); | 784 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); |
| 785 } | 785 } |
| 786 void emit(const Cfg *Func) const override; | 786 void emit(const Cfg *Func) const override; |
| 787 void emitIAS(const Cfg *Func) const override; | 787 void emitIAS(const Cfg *Func) const override; |
| 788 void dump(const Cfg *Func) const override; | 788 void dump(const Cfg *Func) const override; |
| 789 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } | 789 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } |
| 790 | 790 |
| 791 private: | 791 private: |
| 792 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); | 792 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); |
| 793 }; | 793 }; |
| 794 | 794 |
| 795 // Store instruction. It's important for liveness that there is no Dest | 795 /// Store instruction. It's important for liveness that there is no Dest |
| 796 // operand (OperandARM32Mem instead of Dest Variable). | 796 /// operand (OperandARM32Mem instead of Dest Variable). |
| 797 class InstARM32Str : public InstARM32Pred { | 797 class InstARM32Str : public InstARM32Pred { |
| 798 InstARM32Str() = delete; | 798 InstARM32Str() = delete; |
| 799 InstARM32Str(const InstARM32Str &) = delete; | 799 InstARM32Str(const InstARM32Str &) = delete; |
| 800 InstARM32Str &operator=(const InstARM32Str &) = delete; | 800 InstARM32Str &operator=(const InstARM32Str &) = delete; |
| 801 | 801 |
| 802 public: | 802 public: |
| 803 // Value must be a register. | 803 /// Value must be a register. |
| 804 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, | 804 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, |
| 805 CondARM32::Cond Predicate) { | 805 CondARM32::Cond Predicate) { |
| 806 return new (Func->allocate<InstARM32Str>()) | 806 return new (Func->allocate<InstARM32Str>()) |
| 807 InstARM32Str(Func, Value, Mem, Predicate); | 807 InstARM32Str(Func, Value, Mem, Predicate); |
| 808 } | 808 } |
| 809 void emit(const Cfg *Func) const override; | 809 void emit(const Cfg *Func) const override; |
| 810 void emitIAS(const Cfg *Func) const override; | 810 void emitIAS(const Cfg *Func) const override; |
| 811 void dump(const Cfg *Func) const override; | 811 void dump(const Cfg *Func) const override; |
| 812 static bool classof(const Inst *Inst) { return isClassof(Inst, Str); } | 812 static bool classof(const Inst *Inst) { return isClassof(Inst, Str); } |
| 813 | 813 |
| 814 private: | 814 private: |
| 815 InstARM32Str(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, | 815 InstARM32Str(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, |
| 816 CondARM32::Cond Predicate); | 816 CondARM32::Cond Predicate); |
| 817 }; | 817 }; |
| 818 | 818 |
| 819 // Unsigned Multiply Long: d.lo, d.hi := x * y | 819 /// Unsigned Multiply Long: d.lo, d.hi := x * y |
| 820 class InstARM32Umull : public InstARM32Pred { | 820 class InstARM32Umull : public InstARM32Pred { |
| 821 InstARM32Umull() = delete; | 821 InstARM32Umull() = delete; |
| 822 InstARM32Umull(const InstARM32Umull &) = delete; | 822 InstARM32Umull(const InstARM32Umull &) = delete; |
| 823 InstARM32Umull &operator=(const InstARM32Umull &) = delete; | 823 InstARM32Umull &operator=(const InstARM32Umull &) = delete; |
| 824 | 824 |
| 825 public: | 825 public: |
| 826 // Everything must be a register. | 826 /// Everything must be a register. |
| 827 static InstARM32Umull *create(Cfg *Func, Variable *DestLo, Variable *DestHi, | 827 static InstARM32Umull *create(Cfg *Func, Variable *DestLo, Variable *DestHi, |
| 828 Variable *Src0, Variable *Src1, | 828 Variable *Src0, Variable *Src1, |
| 829 CondARM32::Cond Predicate) { | 829 CondARM32::Cond Predicate) { |
| 830 return new (Func->allocate<InstARM32Umull>()) | 830 return new (Func->allocate<InstARM32Umull>()) |
| 831 InstARM32Umull(Func, DestLo, DestHi, Src0, Src1, Predicate); | 831 InstARM32Umull(Func, DestLo, DestHi, Src0, Src1, Predicate); |
| 832 } | 832 } |
| 833 void emit(const Cfg *Func) const override; | 833 void emit(const Cfg *Func) const override; |
| 834 void emitIAS(const Cfg *Func) const override; | 834 void emitIAS(const Cfg *Func) const override; |
| 835 void dump(const Cfg *Func) const override; | 835 void dump(const Cfg *Func) const override; |
| 836 static bool classof(const Inst *Inst) { return isClassof(Inst, Umull); } | 836 static bool classof(const Inst *Inst) { return isClassof(Inst, Umull); } |
| 837 | 837 |
| 838 private: | 838 private: |
| 839 InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, Variable *Src0, | 839 InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, Variable *Src0, |
| 840 Variable *Src1, CondARM32::Cond Predicate); | 840 Variable *Src1, CondARM32::Cond Predicate); |
| 841 | 841 |
| 842 Variable *DestHi; | 842 Variable *DestHi; |
| 843 }; | 843 }; |
| 844 | 844 |
| 845 // Declare partial template specializations of emit() methods that | 845 // Declare partial template specializations of emit() methods that |
| 846 // already have default implementations. Without this, there is the | 846 // already have default implementations. Without this, there is the |
| 847 // possibility of ODR violations and link errors. | 847 // possibility of ODR violations and link errors. |
| 848 | 848 |
| 849 template <> void InstARM32Movw::emit(const Cfg *Func) const; | 849 template <> void InstARM32Movw::emit(const Cfg *Func) const; |
| 850 template <> void InstARM32Movt::emit(const Cfg *Func) const; | 850 template <> void InstARM32Movt::emit(const Cfg *Func) const; |
| 851 | 851 |
| 852 } // end of namespace Ice | 852 } // end of namespace Ice |
| 853 | 853 |
| 854 #endif // SUBZERO_SRC_ICEINSTARM32_H | 854 #endif // SUBZERO_SRC_ICEINSTARM32_H |
| OLD | NEW |