| 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 | 298 |
| 298 protected: | 299 protected: |
| 299 InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest) | 300 InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest) |
| 300 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} | 301 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} |
| 301 | 302 |
| 302 static bool isClassof(const Inst *Inst, InstKindARM32 MyKind) { | 303 static bool isClassof(const Inst *Inst, InstKindARM32 MyKind) { |
| 303 return Inst->getKind() == static_cast<InstKind>(MyKind); | 304 return Inst->getKind() == static_cast<InstKind>(MyKind); |
| 304 } | 305 } |
| 305 }; | 306 }; |
| 306 | 307 |
| 307 // A predicable ARM instruction. | 308 /// A predicable ARM instruction. |
| 308 class InstARM32Pred : public InstARM32 { | 309 class InstARM32Pred : public InstARM32 { |
| 309 InstARM32Pred() = delete; | 310 InstARM32Pred() = delete; |
| 310 InstARM32Pred(const InstARM32Pred &) = delete; | 311 InstARM32Pred(const InstARM32Pred &) = delete; |
| 311 InstARM32Pred &operator=(const InstARM32Pred &) = delete; | 312 InstARM32Pred &operator=(const InstARM32Pred &) = delete; |
| 312 | 313 |
| 313 public: | 314 public: |
| 314 InstARM32Pred(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest, | 315 InstARM32Pred(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest, |
| 315 CondARM32::Cond Predicate) | 316 CondARM32::Cond Predicate) |
| 316 : InstARM32(Func, Kind, Maxsrcs, Dest), Predicate(Predicate) {} | 317 : InstARM32(Func, Kind, Maxsrcs, Dest), Predicate(Predicate) {} |
| 317 | 318 |
| 318 CondARM32::Cond getPredicate() const { return Predicate; } | 319 CondARM32::Cond getPredicate() const { return Predicate; } |
| 319 void setPredicate(CondARM32::Cond Pred) { Predicate = Pred; } | 320 void setPredicate(CondARM32::Cond Pred) { Predicate = Pred; } |
| 320 | 321 |
| 321 static const char *predString(CondARM32::Cond Predicate); | 322 static const char *predString(CondARM32::Cond Predicate); |
| 322 void dumpOpcodePred(Ostream &Str, const char *Opcode, Type Ty) const; | 323 void dumpOpcodePred(Ostream &Str, const char *Opcode, Type Ty) const; |
| 323 | 324 |
| 324 // Shared emit routines for common forms of instructions. | 325 /// Shared emit routines for common forms of instructions. |
| 325 static void emitUnaryopGPR(const char *Opcode, const InstARM32Pred *Inst, | 326 static void emitUnaryopGPR(const char *Opcode, const InstARM32Pred *Inst, |
| 326 const Cfg *Func); | 327 const Cfg *Func); |
| 327 static void emitTwoAddr(const char *Opcode, const InstARM32Pred *Inst, | 328 static void emitTwoAddr(const char *Opcode, const InstARM32Pred *Inst, |
| 328 const Cfg *Func); | 329 const Cfg *Func); |
| 329 static void emitThreeAddr(const char *Opcode, const InstARM32Pred *Inst, | 330 static void emitThreeAddr(const char *Opcode, const InstARM32Pred *Inst, |
| 330 const Cfg *Func, bool SetFlags); | 331 const Cfg *Func, bool SetFlags); |
| 331 static void emitFourAddr(const char *Opcode, const InstARM32Pred *Inst, | 332 static void emitFourAddr(const char *Opcode, const InstARM32Pred *Inst, |
| 332 const Cfg *Func); | 333 const Cfg *Func); |
| 333 static void emitCmpLike(const char *Opcode, const InstARM32Pred *Inst, | 334 static void emitCmpLike(const char *Opcode, const InstARM32Pred *Inst, |
| 334 const Cfg *Func); | 335 const Cfg *Func); |
| 335 | 336 |
| 336 protected: | 337 protected: |
| 337 CondARM32::Cond Predicate; | 338 CondARM32::Cond Predicate; |
| 338 }; | 339 }; |
| 339 | 340 |
| 340 template <typename StreamType> | 341 template <typename StreamType> |
| 341 inline StreamType &operator<<(StreamType &Stream, CondARM32::Cond Predicate) { | 342 inline StreamType &operator<<(StreamType &Stream, CondARM32::Cond Predicate) { |
| 342 Stream << InstARM32Pred::predString(Predicate); | 343 Stream << InstARM32Pred::predString(Predicate); |
| 343 return Stream; | 344 return Stream; |
| 344 } | 345 } |
| 345 | 346 |
| 346 // Instructions of the form x := op(y). | 347 /// Instructions of the form x := op(y). |
| 347 template <InstARM32::InstKindARM32 K> | 348 template <InstARM32::InstKindARM32 K> |
| 348 class InstARM32UnaryopGPR : public InstARM32Pred { | 349 class InstARM32UnaryopGPR : public InstARM32Pred { |
| 349 InstARM32UnaryopGPR() = delete; | 350 InstARM32UnaryopGPR() = delete; |
| 350 InstARM32UnaryopGPR(const InstARM32UnaryopGPR &) = delete; | 351 InstARM32UnaryopGPR(const InstARM32UnaryopGPR &) = delete; |
| 351 InstARM32UnaryopGPR &operator=(const InstARM32UnaryopGPR &) = delete; | 352 InstARM32UnaryopGPR &operator=(const InstARM32UnaryopGPR &) = delete; |
| 352 | 353 |
| 353 public: | 354 public: |
| 354 static InstARM32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src, | 355 static InstARM32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src, |
| 355 CondARM32::Cond Predicate) { | 356 CondARM32::Cond Predicate) { |
| 356 return new (Func->allocate<InstARM32UnaryopGPR>()) | 357 return new (Func->allocate<InstARM32UnaryopGPR>()) |
| (...skipping 23 matching lines...) Expand all Loading... |
| 380 private: | 381 private: |
| 381 InstARM32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src, | 382 InstARM32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src, |
| 382 CondARM32::Cond Predicate) | 383 CondARM32::Cond Predicate) |
| 383 : InstARM32Pred(Func, K, 1, Dest, Predicate) { | 384 : InstARM32Pred(Func, K, 1, Dest, Predicate) { |
| 384 addSource(Src); | 385 addSource(Src); |
| 385 } | 386 } |
| 386 | 387 |
| 387 static const char *Opcode; | 388 static const char *Opcode; |
| 388 }; | 389 }; |
| 389 | 390 |
| 390 // Instructions of the form x := x op y. | 391 /// Instructions of the form x := x op y. |
| 391 template <InstARM32::InstKindARM32 K> | 392 template <InstARM32::InstKindARM32 K> |
| 392 class InstARM32TwoAddrGPR : public InstARM32Pred { | 393 class InstARM32TwoAddrGPR : public InstARM32Pred { |
| 393 InstARM32TwoAddrGPR() = delete; | 394 InstARM32TwoAddrGPR() = delete; |
| 394 InstARM32TwoAddrGPR(const InstARM32TwoAddrGPR &) = delete; | 395 InstARM32TwoAddrGPR(const InstARM32TwoAddrGPR &) = delete; |
| 395 InstARM32TwoAddrGPR &operator=(const InstARM32TwoAddrGPR &) = delete; | 396 InstARM32TwoAddrGPR &operator=(const InstARM32TwoAddrGPR &) = delete; |
| 396 | 397 |
| 397 public: | 398 public: |
| 398 // Dest must be a register. | 399 /// Dest must be a register. |
| 399 static InstARM32TwoAddrGPR *create(Cfg *Func, Variable *Dest, Operand *Src, | 400 static InstARM32TwoAddrGPR *create(Cfg *Func, Variable *Dest, Operand *Src, |
| 400 CondARM32::Cond Predicate) { | 401 CondARM32::Cond Predicate) { |
| 401 return new (Func->allocate<InstARM32TwoAddrGPR>()) | 402 return new (Func->allocate<InstARM32TwoAddrGPR>()) |
| 402 InstARM32TwoAddrGPR(Func, Dest, Src, Predicate); | 403 InstARM32TwoAddrGPR(Func, Dest, Src, Predicate); |
| 403 } | 404 } |
| 404 void emit(const Cfg *Func) const override { | 405 void emit(const Cfg *Func) const override { |
| 405 if (!BuildDefs::dump()) | 406 if (!BuildDefs::dump()) |
| 406 return; | 407 return; |
| 407 emitTwoAddr(Opcode, this, Func); | 408 emitTwoAddr(Opcode, this, Func); |
| 408 } | 409 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 426 InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src, | 427 InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src, |
| 427 CondARM32::Cond Predicate) | 428 CondARM32::Cond Predicate) |
| 428 : InstARM32Pred(Func, K, 2, Dest, Predicate) { | 429 : InstARM32Pred(Func, K, 2, Dest, Predicate) { |
| 429 addSource(Dest); | 430 addSource(Dest); |
| 430 addSource(Src); | 431 addSource(Src); |
| 431 } | 432 } |
| 432 | 433 |
| 433 static const char *Opcode; | 434 static const char *Opcode; |
| 434 }; | 435 }; |
| 435 | 436 |
| 436 // Base class for assignment instructions. | 437 /// Base class for assignment instructions. |
| 437 // These can be tested for redundancy (and elided if redundant). | 438 /// These can be tested for redundancy (and elided if redundant). |
| 438 template <InstARM32::InstKindARM32 K> | 439 template <InstARM32::InstKindARM32 K> |
| 439 class InstARM32Movlike : public InstARM32Pred { | 440 class InstARM32Movlike : public InstARM32Pred { |
| 440 InstARM32Movlike() = delete; | 441 InstARM32Movlike() = delete; |
| 441 InstARM32Movlike(const InstARM32Movlike &) = delete; | 442 InstARM32Movlike(const InstARM32Movlike &) = delete; |
| 442 InstARM32Movlike &operator=(const InstARM32Movlike &) = delete; | 443 InstARM32Movlike &operator=(const InstARM32Movlike &) = delete; |
| 443 | 444 |
| 444 public: | 445 public: |
| 445 static InstARM32Movlike *create(Cfg *Func, Variable *Dest, Operand *Source, | 446 static InstARM32Movlike *create(Cfg *Func, Variable *Dest, Operand *Source, |
| 446 CondARM32::Cond Predicate) { | 447 CondARM32::Cond Predicate) { |
| 447 return new (Func->allocate<InstARM32Movlike>()) | 448 return new (Func->allocate<InstARM32Movlike>()) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 468 private: | 469 private: |
| 469 InstARM32Movlike(Cfg *Func, Variable *Dest, Operand *Source, | 470 InstARM32Movlike(Cfg *Func, Variable *Dest, Operand *Source, |
| 470 CondARM32::Cond Predicate) | 471 CondARM32::Cond Predicate) |
| 471 : InstARM32Pred(Func, K, 1, Dest, Predicate) { | 472 : InstARM32Pred(Func, K, 1, Dest, Predicate) { |
| 472 addSource(Source); | 473 addSource(Source); |
| 473 } | 474 } |
| 474 | 475 |
| 475 static const char *Opcode; | 476 static const char *Opcode; |
| 476 }; | 477 }; |
| 477 | 478 |
| 478 // Instructions of the form x := y op z. May have the side-effect of setting | 479 /// Instructions of the form x := y op z. May have the side-effect of setting |
| 479 // status flags. | 480 /// status flags. |
| 480 template <InstARM32::InstKindARM32 K> | 481 template <InstARM32::InstKindARM32 K> |
| 481 class InstARM32ThreeAddrGPR : public InstARM32Pred { | 482 class InstARM32ThreeAddrGPR : public InstARM32Pred { |
| 482 InstARM32ThreeAddrGPR() = delete; | 483 InstARM32ThreeAddrGPR() = delete; |
| 483 InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete; | 484 InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete; |
| 484 InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete; | 485 InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete; |
| 485 | 486 |
| 486 public: | 487 public: |
| 487 // Create an ordinary binary-op instruction like add, and sub. | 488 /// Create an ordinary binary-op instruction like add, and sub. |
| 488 // Dest and Src1 must be registers. | 489 /// Dest and Src1 must be registers. |
| 489 static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest, | 490 static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest, |
| 490 Variable *Src0, Operand *Src1, | 491 Variable *Src0, Operand *Src1, |
| 491 CondARM32::Cond Predicate, | 492 CondARM32::Cond Predicate, |
| 492 bool SetFlags = false) { | 493 bool SetFlags = false) { |
| 493 return new (Func->allocate<InstARM32ThreeAddrGPR>()) | 494 return new (Func->allocate<InstARM32ThreeAddrGPR>()) |
| 494 InstARM32ThreeAddrGPR(Func, Dest, Src0, Src1, Predicate, SetFlags); | 495 InstARM32ThreeAddrGPR(Func, Dest, Src0, Src1, Predicate, SetFlags); |
| 495 } | 496 } |
| 496 void emit(const Cfg *Func) const override { | 497 void emit(const Cfg *Func) const override { |
| 497 if (!BuildDefs::dump()) | 498 if (!BuildDefs::dump()) |
| 498 return; | 499 return; |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 626 typedef InstARM32ThreeAddrGPR<InstARM32::Eor> InstARM32Eor; | 627 typedef InstARM32ThreeAddrGPR<InstARM32::Eor> InstARM32Eor; |
| 627 typedef InstARM32ThreeAddrGPR<InstARM32::Lsl> InstARM32Lsl; | 628 typedef InstARM32ThreeAddrGPR<InstARM32::Lsl> InstARM32Lsl; |
| 628 typedef InstARM32ThreeAddrGPR<InstARM32::Lsr> InstARM32Lsr; | 629 typedef InstARM32ThreeAddrGPR<InstARM32::Lsr> InstARM32Lsr; |
| 629 typedef InstARM32ThreeAddrGPR<InstARM32::Mul> InstARM32Mul; | 630 typedef InstARM32ThreeAddrGPR<InstARM32::Mul> InstARM32Mul; |
| 630 typedef InstARM32ThreeAddrGPR<InstARM32::Orr> InstARM32Orr; | 631 typedef InstARM32ThreeAddrGPR<InstARM32::Orr> InstARM32Orr; |
| 631 typedef InstARM32ThreeAddrGPR<InstARM32::Rsb> InstARM32Rsb; | 632 typedef InstARM32ThreeAddrGPR<InstARM32::Rsb> InstARM32Rsb; |
| 632 typedef InstARM32ThreeAddrGPR<InstARM32::Sbc> InstARM32Sbc; | 633 typedef InstARM32ThreeAddrGPR<InstARM32::Sbc> InstARM32Sbc; |
| 633 typedef InstARM32ThreeAddrGPR<InstARM32::Sdiv> InstARM32Sdiv; | 634 typedef InstARM32ThreeAddrGPR<InstARM32::Sdiv> InstARM32Sdiv; |
| 634 typedef InstARM32ThreeAddrGPR<InstARM32::Sub> InstARM32Sub; | 635 typedef InstARM32ThreeAddrGPR<InstARM32::Sub> InstARM32Sub; |
| 635 typedef InstARM32ThreeAddrGPR<InstARM32::Udiv> InstARM32Udiv; | 636 typedef InstARM32ThreeAddrGPR<InstARM32::Udiv> InstARM32Udiv; |
| 636 // Move instruction (variable <- flex). This is more of a pseudo-inst. | 637 /// Move instruction (variable <- flex). This is more of a pseudo-inst. |
| 637 // If var is a register, then we use "mov". If var is stack, then we use | 638 /// If var is a register, then we use "mov". If var is stack, then we use |
| 638 // "str" to store to the stack. | 639 /// "str" to store to the stack. |
| 639 typedef InstARM32Movlike<InstARM32::Mov> InstARM32Mov; | 640 typedef InstARM32Movlike<InstARM32::Mov> InstARM32Mov; |
| 640 // MovT leaves the bottom bits alone so dest is also a source. | 641 /// MovT leaves the bottom bits alone so dest is also a source. |
| 641 // This helps indicate that a previous MovW setting dest is not dead code. | 642 /// This helps indicate that a previous MovW setting dest is not dead code. |
| 642 typedef InstARM32TwoAddrGPR<InstARM32::Movt> InstARM32Movt; | 643 typedef InstARM32TwoAddrGPR<InstARM32::Movt> InstARM32Movt; |
| 643 typedef InstARM32UnaryopGPR<InstARM32::Movw> InstARM32Movw; | 644 typedef InstARM32UnaryopGPR<InstARM32::Movw> InstARM32Movw; |
| 644 typedef InstARM32UnaryopGPR<InstARM32::Mvn> InstARM32Mvn; | 645 typedef InstARM32UnaryopGPR<InstARM32::Mvn> InstARM32Mvn; |
| 645 // Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation | 646 // Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation |
| 646 // operand as well (rotate source by 8, 16, 24 bits prior to extending), | 647 // operand as well (rotate source by 8, 16, 24 bits prior to extending), |
| 647 // but we aren't using that for now, so just model as a Unaryop. | 648 // but we aren't using that for now, so just model as a Unaryop. |
| 648 typedef InstARM32UnaryopGPR<InstARM32::Sxt> InstARM32Sxt; | 649 typedef InstARM32UnaryopGPR<InstARM32::Sxt> InstARM32Sxt; |
| 649 typedef InstARM32UnaryopGPR<InstARM32::Uxt> InstARM32Uxt; | 650 typedef InstARM32UnaryopGPR<InstARM32::Uxt> InstARM32Uxt; |
| 650 typedef InstARM32FourAddrGPR<InstARM32::Mla> InstARM32Mla; | 651 typedef InstARM32FourAddrGPR<InstARM32::Mla> InstARM32Mla; |
| 651 typedef InstARM32FourAddrGPR<InstARM32::Mls> InstARM32Mls; | 652 typedef InstARM32FourAddrGPR<InstARM32::Mls> InstARM32Mls; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 670 void emit(const Cfg *Func) const override; | 671 void emit(const Cfg *Func) const override; |
| 671 void emitIAS(const Cfg *Func) const override; | 672 void emitIAS(const Cfg *Func) const override; |
| 672 void dump(const Cfg *Func) const override; | 673 void dump(const Cfg *Func) const override; |
| 673 | 674 |
| 674 private: | 675 private: |
| 675 InstARM32Label(Cfg *Func, TargetARM32 *Target); | 676 InstARM32Label(Cfg *Func, TargetARM32 *Target); |
| 676 | 677 |
| 677 SizeT Number; // used for unique label generation. | 678 SizeT Number; // used for unique label generation. |
| 678 }; | 679 }; |
| 679 | 680 |
| 680 // Direct branch instruction. | 681 /// Direct branch instruction. |
| 681 class InstARM32Br : public InstARM32Pred { | 682 class InstARM32Br : public InstARM32Pred { |
| 682 InstARM32Br() = delete; | 683 InstARM32Br() = delete; |
| 683 InstARM32Br(const InstARM32Br &) = delete; | 684 InstARM32Br(const InstARM32Br &) = delete; |
| 684 InstARM32Br &operator=(const InstARM32Br &) = delete; | 685 InstARM32Br &operator=(const InstARM32Br &) = delete; |
| 685 | 686 |
| 686 public: | 687 public: |
| 687 // Create a conditional branch to one of two nodes. | 688 /// Create a conditional branch to one of two nodes. |
| 688 static InstARM32Br *create(Cfg *Func, CfgNode *TargetTrue, | 689 static InstARM32Br *create(Cfg *Func, CfgNode *TargetTrue, |
| 689 CfgNode *TargetFalse, CondARM32::Cond Predicate) { | 690 CfgNode *TargetFalse, CondARM32::Cond Predicate) { |
| 690 assert(Predicate != CondARM32::AL); | 691 assert(Predicate != CondARM32::AL); |
| 691 constexpr InstARM32Label *NoLabel = nullptr; | 692 constexpr InstARM32Label *NoLabel = nullptr; |
| 692 return new (Func->allocate<InstARM32Br>()) | 693 return new (Func->allocate<InstARM32Br>()) |
| 693 InstARM32Br(Func, TargetTrue, TargetFalse, NoLabel, Predicate); | 694 InstARM32Br(Func, TargetTrue, TargetFalse, NoLabel, Predicate); |
| 694 } | 695 } |
| 695 // Create an unconditional branch to a node. | 696 /// Create an unconditional branch to a node. |
| 696 static InstARM32Br *create(Cfg *Func, CfgNode *Target) { | 697 static InstARM32Br *create(Cfg *Func, CfgNode *Target) { |
| 697 constexpr CfgNode *NoCondTarget = nullptr; | 698 constexpr CfgNode *NoCondTarget = nullptr; |
| 698 constexpr InstARM32Label *NoLabel = nullptr; | 699 constexpr InstARM32Label *NoLabel = nullptr; |
| 699 return new (Func->allocate<InstARM32Br>()) | 700 return new (Func->allocate<InstARM32Br>()) |
| 700 InstARM32Br(Func, NoCondTarget, Target, NoLabel, CondARM32::AL); | 701 InstARM32Br(Func, NoCondTarget, Target, NoLabel, CondARM32::AL); |
| 701 } | 702 } |
| 702 // Create a non-terminator conditional branch to a node, with a | 703 /// Create a non-terminator conditional branch to a node, with a |
| 703 // fallthrough to the next instruction in the current node. This is | 704 /// fallthrough to the next instruction in the current node. This is |
| 704 // used for switch lowering. | 705 /// used for switch lowering. |
| 705 static InstARM32Br *create(Cfg *Func, CfgNode *Target, | 706 static InstARM32Br *create(Cfg *Func, CfgNode *Target, |
| 706 CondARM32::Cond Predicate) { | 707 CondARM32::Cond Predicate) { |
| 707 assert(Predicate != CondARM32::AL); | 708 assert(Predicate != CondARM32::AL); |
| 708 constexpr CfgNode *NoUncondTarget = nullptr; | 709 constexpr CfgNode *NoUncondTarget = nullptr; |
| 709 constexpr InstARM32Label *NoLabel = nullptr; | 710 constexpr InstARM32Label *NoLabel = nullptr; |
| 710 return new (Func->allocate<InstARM32Br>()) | 711 return new (Func->allocate<InstARM32Br>()) |
| 711 InstARM32Br(Func, Target, NoUncondTarget, NoLabel, Predicate); | 712 InstARM32Br(Func, Target, NoUncondTarget, NoLabel, Predicate); |
| 712 } | 713 } |
| 713 // Create a conditional intra-block branch (or unconditional, if | 714 // Create a conditional intra-block branch (or unconditional, if |
| 714 // Condition==AL) to a label in the current block. | 715 // Condition==AL) to a label in the current block. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 743 | 744 |
| 744 private: | 745 private: |
| 745 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, | 746 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, |
| 746 const InstARM32Label *Label, CondARM32::Cond Predicate); | 747 const InstARM32Label *Label, CondARM32::Cond Predicate); |
| 747 | 748 |
| 748 const CfgNode *TargetTrue; | 749 const CfgNode *TargetTrue; |
| 749 const CfgNode *TargetFalse; | 750 const CfgNode *TargetFalse; |
| 750 const InstARM32Label *Label; // Intra-block branch target | 751 const InstARM32Label *Label; // Intra-block branch target |
| 751 }; | 752 }; |
| 752 | 753 |
| 753 // AdjustStack instruction - subtracts SP by the given amount and | 754 /// AdjustStack instruction - subtracts SP by the given amount and |
| 754 // updates the stack offset during code emission. | 755 /// updates the stack offset during code emission. |
| 755 class InstARM32AdjustStack : public InstARM32 { | 756 class InstARM32AdjustStack : public InstARM32 { |
| 756 InstARM32AdjustStack() = delete; | 757 InstARM32AdjustStack() = delete; |
| 757 InstARM32AdjustStack(const InstARM32AdjustStack &) = delete; | 758 InstARM32AdjustStack(const InstARM32AdjustStack &) = delete; |
| 758 InstARM32AdjustStack &operator=(const InstARM32AdjustStack &) = delete; | 759 InstARM32AdjustStack &operator=(const InstARM32AdjustStack &) = delete; |
| 759 | 760 |
| 760 public: | 761 public: |
| 761 // Note: We need both Amount and SrcAmount. If Amount is too large then | 762 /// Note: We need both Amount and SrcAmount. If Amount is too large then |
| 762 // it needs to be copied to a register (so SrcAmount could be a register). | 763 /// it needs to be copied to a register (so SrcAmount could be a register). |
| 763 // However, we also need the numeric Amount for bookkeeping, and it's | 764 /// However, we also need the numeric Amount for bookkeeping, and it's |
| 764 // hard to pull that from the generic SrcAmount operand. | 765 /// hard to pull that from the generic SrcAmount operand. |
| 765 static InstARM32AdjustStack *create(Cfg *Func, Variable *SP, SizeT Amount, | 766 static InstARM32AdjustStack *create(Cfg *Func, Variable *SP, SizeT Amount, |
| 766 Operand *SrcAmount) { | 767 Operand *SrcAmount) { |
| 767 return new (Func->allocate<InstARM32AdjustStack>()) | 768 return new (Func->allocate<InstARM32AdjustStack>()) |
| 768 InstARM32AdjustStack(Func, SP, Amount, SrcAmount); | 769 InstARM32AdjustStack(Func, SP, Amount, SrcAmount); |
| 769 } | 770 } |
| 770 void emit(const Cfg *Func) const override; | 771 void emit(const Cfg *Func) const override; |
| 771 void emitIAS(const Cfg *Func) const override; | 772 void emitIAS(const Cfg *Func) const override; |
| 772 void dump(const Cfg *Func) const override; | 773 void dump(const Cfg *Func) const override; |
| 773 static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); } | 774 static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); } |
| 774 | 775 |
| 775 private: | 776 private: |
| 776 InstARM32AdjustStack(Cfg *Func, Variable *SP, SizeT Amount, | 777 InstARM32AdjustStack(Cfg *Func, Variable *SP, SizeT Amount, |
| 777 Operand *SrcAmount); | 778 Operand *SrcAmount); |
| 778 const SizeT Amount; | 779 const SizeT Amount; |
| 779 }; | 780 }; |
| 780 | 781 |
| 781 // Call instruction (bl/blx). Arguments should have already been pushed. | 782 /// Call instruction (bl/blx). Arguments should have already been pushed. |
| 782 // Technically bl and the register form of blx can be predicated, but we'll | 783 /// Technically bl and the register form of blx can be predicated, but we'll |
| 783 // leave that out until needed. | 784 /// leave that out until needed. |
| 784 class InstARM32Call : public InstARM32 { | 785 class InstARM32Call : public InstARM32 { |
| 785 InstARM32Call() = delete; | 786 InstARM32Call() = delete; |
| 786 InstARM32Call(const InstARM32Call &) = delete; | 787 InstARM32Call(const InstARM32Call &) = delete; |
| 787 InstARM32Call &operator=(const InstARM32Call &) = delete; | 788 InstARM32Call &operator=(const InstARM32Call &) = delete; |
| 788 | 789 |
| 789 public: | 790 public: |
| 790 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { | 791 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { |
| 791 return new (Func->allocate<InstARM32Call>()) | 792 return new (Func->allocate<InstARM32Call>()) |
| 792 InstARM32Call(Func, Dest, CallTarget); | 793 InstARM32Call(Func, Dest, CallTarget); |
| 793 } | 794 } |
| 794 Operand *getCallTarget() const { return getSrc(0); } | 795 Operand *getCallTarget() const { return getSrc(0); } |
| 795 void emit(const Cfg *Func) const override; | 796 void emit(const Cfg *Func) const override; |
| 796 void emitIAS(const Cfg *Func) const override; | 797 void emitIAS(const Cfg *Func) const override; |
| 797 void dump(const Cfg *Func) const override; | 798 void dump(const Cfg *Func) const override; |
| 798 static bool classof(const Inst *Inst) { return isClassof(Inst, Call); } | 799 static bool classof(const Inst *Inst) { return isClassof(Inst, Call); } |
| 799 | 800 |
| 800 private: | 801 private: |
| 801 InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget); | 802 InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget); |
| 802 }; | 803 }; |
| 803 | 804 |
| 804 // Load instruction. | 805 /// Load instruction. |
| 805 class InstARM32Ldr : public InstARM32Pred { | 806 class InstARM32Ldr : public InstARM32Pred { |
| 806 InstARM32Ldr() = delete; | 807 InstARM32Ldr() = delete; |
| 807 InstARM32Ldr(const InstARM32Ldr &) = delete; | 808 InstARM32Ldr(const InstARM32Ldr &) = delete; |
| 808 InstARM32Ldr &operator=(const InstARM32Ldr &) = delete; | 809 InstARM32Ldr &operator=(const InstARM32Ldr &) = delete; |
| 809 | 810 |
| 810 public: | 811 public: |
| 811 // Dest must be a register. | 812 /// Dest must be a register. |
| 812 static InstARM32Ldr *create(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem, | 813 static InstARM32Ldr *create(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem, |
| 813 CondARM32::Cond Predicate) { | 814 CondARM32::Cond Predicate) { |
| 814 return new (Func->allocate<InstARM32Ldr>()) | 815 return new (Func->allocate<InstARM32Ldr>()) |
| 815 InstARM32Ldr(Func, Dest, Mem, Predicate); | 816 InstARM32Ldr(Func, Dest, Mem, Predicate); |
| 816 } | 817 } |
| 817 void emit(const Cfg *Func) const override; | 818 void emit(const Cfg *Func) const override; |
| 818 void emitIAS(const Cfg *Func) const override; | 819 void emitIAS(const Cfg *Func) const override; |
| 819 void dump(const Cfg *Func) const override; | 820 void dump(const Cfg *Func) const override; |
| 820 static bool classof(const Inst *Inst) { return isClassof(Inst, Ldr); } | 821 static bool classof(const Inst *Inst) { return isClassof(Inst, Ldr); } |
| 821 | 822 |
| 822 private: | 823 private: |
| 823 InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem, | 824 InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem, |
| 824 CondARM32::Cond Predicate); | 825 CondARM32::Cond Predicate); |
| 825 }; | 826 }; |
| 826 | 827 |
| 827 // Pop into a list of GPRs. Technically this can be predicated, but we don't | 828 /// Pop into a list of GPRs. Technically this can be predicated, but we don't |
| 828 // need that functionality. | 829 /// need that functionality. |
| 829 class InstARM32Pop : public InstARM32 { | 830 class InstARM32Pop : public InstARM32 { |
| 830 InstARM32Pop() = delete; | 831 InstARM32Pop() = delete; |
| 831 InstARM32Pop(const InstARM32Pop &) = delete; | 832 InstARM32Pop(const InstARM32Pop &) = delete; |
| 832 InstARM32Pop &operator=(const InstARM32Pop &) = delete; | 833 InstARM32Pop &operator=(const InstARM32Pop &) = delete; |
| 833 | 834 |
| 834 public: | 835 public: |
| 835 static InstARM32Pop *create(Cfg *Func, const VarList &Dests) { | 836 static InstARM32Pop *create(Cfg *Func, const VarList &Dests) { |
| 836 return new (Func->allocate<InstARM32Pop>()) InstARM32Pop(Func, Dests); | 837 return new (Func->allocate<InstARM32Pop>()) InstARM32Pop(Func, Dests); |
| 837 } | 838 } |
| 838 void emit(const Cfg *Func) const override; | 839 void emit(const Cfg *Func) const override; |
| 839 void emitIAS(const Cfg *Func) const override; | 840 void emitIAS(const Cfg *Func) const override; |
| 840 void dump(const Cfg *Func) const override; | 841 void dump(const Cfg *Func) const override; |
| 841 static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } | 842 static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } |
| 842 | 843 |
| 843 private: | 844 private: |
| 844 InstARM32Pop(Cfg *Func, const VarList &Dests); | 845 InstARM32Pop(Cfg *Func, const VarList &Dests); |
| 845 | 846 |
| 846 VarList Dests; | 847 VarList Dests; |
| 847 }; | 848 }; |
| 848 | 849 |
| 849 // Push a list of GPRs. Technically this can be predicated, but we don't | 850 /// Push a list of GPRs. Technically this can be predicated, but we don't |
| 850 // need that functionality. | 851 /// need that functionality. |
| 851 class InstARM32Push : public InstARM32 { | 852 class InstARM32Push : public InstARM32 { |
| 852 InstARM32Push() = delete; | 853 InstARM32Push() = delete; |
| 853 InstARM32Push(const InstARM32Push &) = delete; | 854 InstARM32Push(const InstARM32Push &) = delete; |
| 854 InstARM32Push &operator=(const InstARM32Push &) = delete; | 855 InstARM32Push &operator=(const InstARM32Push &) = delete; |
| 855 | 856 |
| 856 public: | 857 public: |
| 857 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) { | 858 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) { |
| 858 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); | 859 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); |
| 859 } | 860 } |
| 860 void emit(const Cfg *Func) const override; | 861 void emit(const Cfg *Func) const override; |
| 861 void emitIAS(const Cfg *Func) const override; | 862 void emitIAS(const Cfg *Func) const override; |
| 862 void dump(const Cfg *Func) const override; | 863 void dump(const Cfg *Func) const override; |
| 863 static bool classof(const Inst *Inst) { return isClassof(Inst, Push); } | 864 static bool classof(const Inst *Inst) { return isClassof(Inst, Push); } |
| 864 | 865 |
| 865 private: | 866 private: |
| 866 InstARM32Push(Cfg *Func, const VarList &Srcs); | 867 InstARM32Push(Cfg *Func, const VarList &Srcs); |
| 867 }; | 868 }; |
| 868 | 869 |
| 869 // Ret pseudo-instruction. This is actually a "bx" instruction with | 870 /// Ret pseudo-instruction. This is actually a "bx" instruction with |
| 870 // an "lr" register operand, but epilogue lowering will search for a Ret | 871 /// an "lr" register operand, but epilogue lowering will search for a Ret |
| 871 // instead of a generic "bx". This instruction also takes a Source | 872 /// instead of a generic "bx". This instruction also takes a Source |
| 872 // operand (for non-void returning functions) for liveness analysis, though | 873 /// operand (for non-void returning functions) for liveness analysis, though |
| 873 // a FakeUse before the ret would do just as well. | 874 /// a FakeUse before the ret would do just as well. |
| 874 // | 875 /// |
| 875 // NOTE: Even though "bx" can be predicated, for now leave out the predication | 876 /// NOTE: Even though "bx" can be predicated, for now leave out the predication |
| 876 // since it's not yet known to be useful for Ret. That may complicate finding | 877 /// since it's not yet known to be useful for Ret. That may complicate finding |
| 877 // the terminator instruction if it's not guaranteed to be executed. | 878 /// the terminator instruction if it's not guaranteed to be executed. |
| 878 class InstARM32Ret : public InstARM32 { | 879 class InstARM32Ret : public InstARM32 { |
| 879 InstARM32Ret() = delete; | 880 InstARM32Ret() = delete; |
| 880 InstARM32Ret(const InstARM32Ret &) = delete; | 881 InstARM32Ret(const InstARM32Ret &) = delete; |
| 881 InstARM32Ret &operator=(const InstARM32Ret &) = delete; | 882 InstARM32Ret &operator=(const InstARM32Ret &) = delete; |
| 882 | 883 |
| 883 public: | 884 public: |
| 884 static InstARM32Ret *create(Cfg *Func, Variable *LR, | 885 static InstARM32Ret *create(Cfg *Func, Variable *LR, |
| 885 Variable *Source = nullptr) { | 886 Variable *Source = nullptr) { |
| 886 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); | 887 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); |
| 887 } | 888 } |
| 888 void emit(const Cfg *Func) const override; | 889 void emit(const Cfg *Func) const override; |
| 889 void emitIAS(const Cfg *Func) const override; | 890 void emitIAS(const Cfg *Func) const override; |
| 890 void dump(const Cfg *Func) const override; | 891 void dump(const Cfg *Func) const override; |
| 891 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } | 892 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } |
| 892 | 893 |
| 893 private: | 894 private: |
| 894 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); | 895 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); |
| 895 }; | 896 }; |
| 896 | 897 |
| 897 // Store instruction. It's important for liveness that there is no Dest | 898 /// Store instruction. It's important for liveness that there is no Dest |
| 898 // operand (OperandARM32Mem instead of Dest Variable). | 899 /// operand (OperandARM32Mem instead of Dest Variable). |
| 899 class InstARM32Str : public InstARM32Pred { | 900 class InstARM32Str : public InstARM32Pred { |
| 900 InstARM32Str() = delete; | 901 InstARM32Str() = delete; |
| 901 InstARM32Str(const InstARM32Str &) = delete; | 902 InstARM32Str(const InstARM32Str &) = delete; |
| 902 InstARM32Str &operator=(const InstARM32Str &) = delete; | 903 InstARM32Str &operator=(const InstARM32Str &) = delete; |
| 903 | 904 |
| 904 public: | 905 public: |
| 905 // Value must be a register. | 906 /// Value must be a register. |
| 906 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, | 907 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, |
| 907 CondARM32::Cond Predicate) { | 908 CondARM32::Cond Predicate) { |
| 908 return new (Func->allocate<InstARM32Str>()) | 909 return new (Func->allocate<InstARM32Str>()) |
| 909 InstARM32Str(Func, Value, Mem, Predicate); | 910 InstARM32Str(Func, Value, Mem, Predicate); |
| 910 } | 911 } |
| 911 void emit(const Cfg *Func) const override; | 912 void emit(const Cfg *Func) const override; |
| 912 void emitIAS(const Cfg *Func) const override; | 913 void emitIAS(const Cfg *Func) const override; |
| 913 void dump(const Cfg *Func) const override; | 914 void dump(const Cfg *Func) const override; |
| 914 static bool classof(const Inst *Inst) { return isClassof(Inst, Str); } | 915 static bool classof(const Inst *Inst) { return isClassof(Inst, Str); } |
| 915 | 916 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 929 } | 930 } |
| 930 void emit(const Cfg *Func) const override; | 931 void emit(const Cfg *Func) const override; |
| 931 void emitIAS(const Cfg *Func) const override; | 932 void emitIAS(const Cfg *Func) const override; |
| 932 void dump(const Cfg *Func) const override; | 933 void dump(const Cfg *Func) const override; |
| 933 static bool classof(const Inst *Inst) { return isClassof(Inst, Trap); } | 934 static bool classof(const Inst *Inst) { return isClassof(Inst, Trap); } |
| 934 | 935 |
| 935 private: | 936 private: |
| 936 explicit InstARM32Trap(Cfg *Func); | 937 explicit InstARM32Trap(Cfg *Func); |
| 937 }; | 938 }; |
| 938 | 939 |
| 939 // Unsigned Multiply Long: d.lo, d.hi := x * y | 940 /// Unsigned Multiply Long: d.lo, d.hi := x * y |
| 940 class InstARM32Umull : public InstARM32Pred { | 941 class InstARM32Umull : public InstARM32Pred { |
| 941 InstARM32Umull() = delete; | 942 InstARM32Umull() = delete; |
| 942 InstARM32Umull(const InstARM32Umull &) = delete; | 943 InstARM32Umull(const InstARM32Umull &) = delete; |
| 943 InstARM32Umull &operator=(const InstARM32Umull &) = delete; | 944 InstARM32Umull &operator=(const InstARM32Umull &) = delete; |
| 944 | 945 |
| 945 public: | 946 public: |
| 946 // Everything must be a register. | 947 /// Everything must be a register. |
| 947 static InstARM32Umull *create(Cfg *Func, Variable *DestLo, Variable *DestHi, | 948 static InstARM32Umull *create(Cfg *Func, Variable *DestLo, Variable *DestHi, |
| 948 Variable *Src0, Variable *Src1, | 949 Variable *Src0, Variable *Src1, |
| 949 CondARM32::Cond Predicate) { | 950 CondARM32::Cond Predicate) { |
| 950 return new (Func->allocate<InstARM32Umull>()) | 951 return new (Func->allocate<InstARM32Umull>()) |
| 951 InstARM32Umull(Func, DestLo, DestHi, Src0, Src1, Predicate); | 952 InstARM32Umull(Func, DestLo, DestHi, Src0, Src1, Predicate); |
| 952 } | 953 } |
| 953 void emit(const Cfg *Func) const override; | 954 void emit(const Cfg *Func) const override; |
| 954 void emitIAS(const Cfg *Func) const override; | 955 void emitIAS(const Cfg *Func) const override; |
| 955 void dump(const Cfg *Func) const override; | 956 void dump(const Cfg *Func) const override; |
| 956 static bool classof(const Inst *Inst) { return isClassof(Inst, Umull); } | 957 static bool classof(const Inst *Inst) { return isClassof(Inst, Umull); } |
| 957 | 958 |
| 958 private: | 959 private: |
| 959 InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, Variable *Src0, | 960 InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, Variable *Src0, |
| 960 Variable *Src1, CondARM32::Cond Predicate); | 961 Variable *Src1, CondARM32::Cond Predicate); |
| 961 | 962 |
| 962 Variable *DestHi; | 963 Variable *DestHi; |
| 963 }; | 964 }; |
| 964 | 965 |
| 965 // Declare partial template specializations of emit() methods that | 966 // Declare partial template specializations of emit() methods that |
| 966 // already have default implementations. Without this, there is the | 967 // already have default implementations. Without this, there is the |
| 967 // possibility of ODR violations and link errors. | 968 // possibility of ODR violations and link errors. |
| 968 | 969 |
| 969 template <> void InstARM32Movw::emit(const Cfg *Func) const; | 970 template <> void InstARM32Movw::emit(const Cfg *Func) const; |
| 970 template <> void InstARM32Movt::emit(const Cfg *Func) const; | 971 template <> void InstARM32Movt::emit(const Cfg *Func) const; |
| 971 | 972 |
| 972 } // end of namespace Ice | 973 } // end of namespace Ice |
| 973 | 974 |
| 974 #endif // SUBZERO_SRC_ICEINSTARM32_H | 975 #endif // SUBZERO_SRC_ICEINSTARM32_H |
| OLD | NEW |