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