Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 //===- subzero/src/IceInstARM32.h - ARM32 machine instructions --*- C++ -*-===// | 1 //===- subzero/src/IceInstARM32.h - ARM32 machine instructions --*- C++ -*-===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 // | 9 // |
| 10 // This file declares the InstARM32 and OperandARM32 classes and | 10 // This file declares the InstARM32 and OperandARM32 classes and |
| 11 // their subclasses. This represents the machine instructions and | 11 // their subclasses. This represents the machine instructions and |
| 12 // operands used for ARM32 code selection. | 12 // operands used for ARM32 code selection. |
| 13 // | 13 // |
| 14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
| 15 | 15 |
| 16 #ifndef SUBZERO_SRC_ICEINSTARM32_H | 16 #ifndef SUBZERO_SRC_ICEINSTARM32_H |
| 17 #define SUBZERO_SRC_ICEINSTARM32_H | 17 #define SUBZERO_SRC_ICEINSTARM32_H |
| 18 | 18 |
| 19 #include "IceDefs.h" | 19 #include "IceDefs.h" |
| 20 #include "IceInst.h" | 20 #include "IceInst.h" |
| 21 #include "IceInstARM32.def" | 21 #include "IceInstARM32.def" |
| 22 #include "IceOperand.h" | 22 #include "IceOperand.h" |
| 23 | 23 |
| 24 namespace Ice { | 24 namespace Ice { |
| 25 | 25 |
| 26 class TargetARM32; | 26 class TargetARM32; |
| 27 | 27 |
| 28 // OperandARM32 extends the Operand hierarchy. | 28 // OperandARM32 extends the Operand hierarchy. Its subclasses are |
| 29 // TODO(jvoung): Add the OperandARM32Mem and OperandARM32Flex. | 29 // OperandARM32Mem and OperandARM32Flex. |
| 30 class OperandARM32 : public Operand { | 30 class OperandARM32 : public Operand { |
| 31 OperandARM32() = delete; | 31 OperandARM32() = delete; |
| 32 OperandARM32(const OperandARM32 &) = delete; | 32 OperandARM32(const OperandARM32 &) = delete; |
| 33 OperandARM32 &operator=(const OperandARM32 &) = delete; | 33 OperandARM32 &operator=(const OperandARM32 &) = delete; |
| 34 | 34 |
| 35 public: | 35 public: |
| 36 enum OperandKindARM32 { k__Start = Operand::kTarget }; | 36 enum OperandKindARM32 { |
| 37 k__Start = Operand::kTarget, | |
|
Jim Stichnoth
2015/05/16 00:10:34
It looks like InstKind and OperandKind value space
jvoung (off chromium)
2015/05/17 18:06:30
Done.
| |
| 38 kMem, | |
| 39 kFlexStart, | |
| 40 kFlexImm = kFlexStart, | |
| 41 kFlexReg, | |
| 42 kFlexEnd = kFlexReg | |
| 43 }; | |
| 37 | 44 |
| 38 enum ShiftKind { | 45 enum ShiftKind { |
| 39 kNoShift = -1, | 46 kNoShift = -1, |
| 40 #define X(enum, emit) enum, | 47 #define X(enum, emit) enum, |
| 41 ICEINSTARM32SHIFT_TABLE | 48 ICEINSTARM32SHIFT_TABLE |
| 42 #undef X | 49 #undef X |
| 43 }; | 50 }; |
| 44 | 51 |
| 45 using Operand::dump; | 52 using Operand::dump; |
| 46 void dump(const Cfg *, Ostream &Str) const override { | 53 void dump(const Cfg *, Ostream &Str) const override { |
| 47 if (ALLOW_DUMP) | 54 if (ALLOW_DUMP) |
| 48 Str << "<OperandARM32>"; | 55 Str << "<OperandARM32>"; |
| 49 } | 56 } |
| 50 | 57 |
| 51 protected: | 58 protected: |
| 52 OperandARM32(OperandKindARM32 Kind, Type Ty) | 59 OperandARM32(OperandKindARM32 Kind, Type Ty) |
| 53 : Operand(static_cast<OperandKind>(Kind), Ty) {} | 60 : Operand(static_cast<OperandKind>(Kind), Ty) {} |
| 54 ~OperandARM32() override {} | 61 ~OperandARM32() override {} |
| 55 }; | 62 }; |
| 56 | 63 |
| 57 // OperandARM32Mem represents a memory operand in any of the various ARM32 | 64 // OperandARM32Mem represents a memory operand in any of the various ARM32 |
| 58 // addressing modes. | 65 // addressing modes. |
| 59 // TODO(jvoung): Fill out more. | |
| 60 class OperandARM32Mem : public OperandARM32 { | 66 class OperandARM32Mem : public OperandARM32 { |
| 61 OperandARM32Mem() = delete; | 67 OperandARM32Mem() = delete; |
| 62 OperandARM32Mem(const OperandARM32Mem &) = delete; | 68 OperandARM32Mem(const OperandARM32Mem &) = delete; |
| 63 OperandARM32Mem &operator=(const OperandARM32Mem &) = delete; | 69 OperandARM32Mem &operator=(const OperandARM32Mem &) = delete; |
| 64 | 70 |
| 65 public: | 71 public: |
| 72 // Memory operand addressing mode. | |
| 73 // The enum value also carries the encoding. | |
| 74 // TODO(jvoung): unify with the assembler. | |
| 75 enum AddrMode { | |
| 76 // bit encoding P U W | |
| 77 Offset = (8 | 4 | 0) << 21, // offset (w/o writeback to base) | |
| 78 PreIndex = (8 | 4 | 1) << 21, // pre-indexed addressing with writeback | |
| 79 PostIndex = (0 | 4 | 0) << 21, // post-indexed addressing with writeback | |
| 80 NegOffset = (8 | 0 | 0) << 21, // negative offset (w/o writeback to base) | |
| 81 NegPreIndex = (8 | 0 | 1) << 21, // negative pre-indexed with writeback | |
| 82 NegPostIndex = (0 | 0 | 0) << 21 // negative post-indexed with writeback | |
| 83 }; | |
| 84 | |
| 85 // Provide two constructors. | |
| 86 // NOTE: The Variable-typed operands have to be registers. | |
| 87 // | |
| 88 // (1) Reg + Imm. The Immediate actually has a limited number of bits | |
| 89 // for encoding, so check canHoldOffset first. It cannot handle | |
| 90 // general Constant operands like ConstantRelocatable, since a relocatable | |
| 91 // can potentially take up too many bits. | |
| 92 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, | |
| 93 ConstantInteger32 *ImmOffset = nullptr, | |
| 94 AddrMode Mode = Offset) { | |
| 95 return new (Func->allocate<OperandARM32Mem>()) | |
| 96 OperandARM32Mem(Func, Ty, Base, ImmOffset, Mode); | |
| 97 } | |
| 98 // (2) Reg +/- Reg with an optional shift of some kind and amount. | |
| 99 // Note that this mode is disallowed in the NaCl sandbox. | |
| 100 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, | |
| 101 Variable *Index, ShiftKind ShiftOp = kNoShift, | |
| 102 uint16_t ShiftAmt = 0, | |
| 103 AddrMode Mode = Offset) { | |
| 104 return new (Func->allocate<OperandARM32Mem>()) | |
| 105 OperandARM32Mem(Func, Ty, Base, Index, ShiftOp, ShiftAmt, Mode); | |
| 106 } | |
| 107 Variable *getBase() const { return Base; } | |
| 108 ConstantInteger32 *getOffset() const { return ImmOffset; } | |
| 109 Variable *getIndex() const { return Index; } | |
| 110 ShiftKind getShiftOp() const { return ShiftOp; } | |
| 111 uint16_t getShiftAmt() const { return ShiftAmt; } | |
| 112 AddrMode getAddrMode() const { return Mode; } | |
| 113 | |
| 114 bool isRegReg() const { return Index != nullptr; } | |
| 115 bool isNegAddrMode() const { return Mode >= NegOffset; } | |
| 116 | |
| 117 void emit(const Cfg *Func) const override; | |
| 118 using OperandARM32::dump; | |
| 119 void dump(const Cfg *Func, Ostream &Str) const override; | |
| 120 | |
| 121 static bool classof(const Operand *Operand) { | |
| 122 return Operand->getKind() == static_cast<OperandKind>(kMem); | |
| 123 } | |
| 124 | |
| 66 // Return true if a load/store instruction for an element of type Ty | 125 // Return true if a load/store instruction for an element of type Ty |
| 67 // can encode the Offset directly in the immediate field of the 32-bit | 126 // can encode the Offset directly in the immediate field of the 32-bit |
| 68 // ARM instruction. For some types, if the load is Sign extending, then | 127 // ARM instruction. For some types, if the load is Sign extending, then |
| 69 // the range is reduced. | 128 // the range is reduced. |
| 70 static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset); | 129 static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset); |
| 130 | |
| 131 private: | |
| 132 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, | |
| 133 ConstantInteger32 *ImmOffset, AddrMode Mode); | |
| 134 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, Variable *Index, | |
| 135 ShiftKind ShiftOp, uint16_t ShiftAmt, AddrMode Mode); | |
| 136 ~OperandARM32Mem() override {} | |
| 137 Variable *Base; | |
| 138 ConstantInteger32 *ImmOffset; | |
| 139 Variable *Index; | |
| 140 ShiftKind ShiftOp; | |
| 141 uint16_t ShiftAmt; | |
| 142 AddrMode Mode; | |
| 143 }; | |
| 144 | |
| 145 // OperandARM32Flex represent the "flexible second operand" for | |
| 146 // data-processing instructions. It can be a rotatable 8-bit constant, or | |
| 147 // a register with an optional shift operand. The shift amount can even be | |
| 148 // a third register. | |
| 149 class OperandARM32Flex : public OperandARM32 { | |
| 150 OperandARM32Flex() = delete; | |
| 151 OperandARM32Flex(const OperandARM32Flex &) = delete; | |
| 152 OperandARM32Flex &operator=(const OperandARM32Flex &) = delete; | |
| 153 | |
| 154 public: | |
| 155 static bool classof(const Operand *Operand) { | |
| 156 return static_cast<OperandKind>(kFlexStart) <= Operand->getKind() && | |
| 157 Operand->getKind() <= static_cast<OperandKind>(kFlexEnd); | |
| 158 } | |
| 159 | |
| 160 protected: | |
| 161 OperandARM32Flex(OperandKindARM32 Kind, Type Ty) : OperandARM32(Kind, Ty) {} | |
| 162 ~OperandARM32Flex() override {} | |
| 163 }; | |
| 164 | |
| 165 // Rotated immediate variant. | |
| 166 class OperandARM32FlexImm : public OperandARM32Flex { | |
| 167 OperandARM32FlexImm() = delete; | |
| 168 OperandARM32FlexImm(const OperandARM32FlexImm &) = delete; | |
| 169 OperandARM32FlexImm &operator=(const OperandARM32FlexImm &) = delete; | |
| 170 | |
| 171 public: | |
| 172 // Immed_8 rotated by an even number of bits (2 * RotateAmt). | |
| 173 static OperandARM32FlexImm *create(Cfg *Func, Type Ty, uint32_t Imm, | |
| 174 uint32_t RotateAmt) { | |
| 175 return new (Func->allocate<OperandARM32FlexImm>()) | |
| 176 OperandARM32FlexImm(Func, Ty, Imm, RotateAmt); | |
| 177 } | |
| 178 | |
| 179 void emit(const Cfg *Func) const override; | |
| 180 using OperandARM32::dump; | |
| 181 void dump(const Cfg *Func, Ostream &Str) const override; | |
| 182 | |
| 183 static bool classof(const Operand *Operand) { | |
| 184 return Operand->getKind() == static_cast<OperandKind>(kFlexImm); | |
| 185 } | |
| 186 | |
| 187 // Return true if the Immediate can fit in the ARM flexible operand. | |
| 188 // Fills in the out-params RotateAmt and Immed_8 if Immediate fits. | |
| 189 static bool canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, | |
| 190 uint32_t *Immed_8); | |
| 191 | |
| 192 uint32_t getImm() const { return Imm; } | |
| 193 uint32_t getRotateAmt() const { return RotateAmt; } | |
| 194 | |
| 195 private: | |
| 196 OperandARM32FlexImm(Cfg *Func, Type Ty, uint32_t Imm, uint32_t RotateAmt); | |
| 197 ~OperandARM32FlexImm() override {} | |
| 198 | |
| 199 uint32_t Imm; | |
| 200 uint32_t RotateAmt; | |
| 201 }; | |
| 202 | |
| 203 // Shifted register variant. | |
| 204 class OperandARM32FlexReg : public OperandARM32Flex { | |
| 205 OperandARM32FlexReg() = delete; | |
| 206 OperandARM32FlexReg(const OperandARM32FlexReg &) = delete; | |
| 207 OperandARM32FlexReg &operator=(const OperandARM32FlexReg &) = delete; | |
| 208 | |
| 209 public: | |
| 210 // Register with immediate/reg shift amount and shift operation. | |
| 211 static OperandARM32FlexReg *create(Cfg *Func, Type Ty, Variable *Reg, | |
| 212 ShiftKind ShiftOp, Operand *ShiftAmt) { | |
| 213 return new (Func->allocate<OperandARM32FlexReg>()) | |
| 214 OperandARM32FlexReg(Func, Ty, Reg, ShiftOp, ShiftAmt); | |
| 215 } | |
| 216 | |
| 217 void emit(const Cfg *Func) const override; | |
| 218 using OperandARM32::dump; | |
| 219 void dump(const Cfg *Func, Ostream &Str) const override; | |
| 220 | |
| 221 static bool classof(const Operand *Operand) { | |
| 222 return Operand->getKind() == static_cast<OperandKind>(kFlexReg); | |
| 223 } | |
| 224 | |
| 225 Variable *getReg() const { return Reg; } | |
| 226 ShiftKind getShiftOp() const { return ShiftOp; } | |
| 227 // ShiftAmt can represent an immediate or a register. | |
| 228 Operand *getShiftAmt() const { return ShiftAmt; } | |
| 229 | |
| 230 private: | |
| 231 OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, ShiftKind ShiftOp, | |
| 232 Operand *ShiftAmt); | |
| 233 ~OperandARM32FlexReg() override {} | |
| 234 | |
| 235 Variable *Reg; | |
| 236 ShiftKind ShiftOp; | |
| 237 Operand *ShiftAmt; | |
| 71 }; | 238 }; |
| 72 | 239 |
| 73 class InstARM32 : public InstTarget { | 240 class InstARM32 : public InstTarget { |
| 74 InstARM32() = delete; | 241 InstARM32() = delete; |
| 75 InstARM32(const InstARM32 &) = delete; | 242 InstARM32(const InstARM32 &) = delete; |
| 76 InstARM32 &operator=(const InstARM32 &) = delete; | 243 InstARM32 &operator=(const InstARM32 &) = delete; |
| 77 | 244 |
| 78 public: | 245 public: |
| 79 enum InstKindARM32 { k__Start = Inst::Target, Ret }; | 246 enum InstKindARM32 { |
| 247 k__Start = Inst::Target, | |
| 248 Mov, | |
| 249 Movt, | |
| 250 Movw, | |
| 251 Mvn, | |
| 252 Ret, | |
| 253 Ldr | |
| 254 }; | |
| 80 | 255 |
| 81 static const char *getWidthString(Type Ty); | 256 static const char *getWidthString(Type Ty); |
| 82 | 257 |
| 83 void dump(const Cfg *Func) const override; | 258 void dump(const Cfg *Func) const override; |
| 84 | 259 |
| 85 protected: | 260 protected: |
| 86 InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest) | 261 InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest) |
| 87 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} | 262 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} |
| 88 ~InstARM32() override {} | 263 ~InstARM32() override {} |
| 89 static bool isClassof(const Inst *Inst, InstKindARM32 MyKind) { | 264 static bool isClassof(const Inst *Inst, InstKindARM32 MyKind) { |
| 90 return Inst->getKind() == static_cast<InstKind>(MyKind); | 265 return Inst->getKind() == static_cast<InstKind>(MyKind); |
| 91 } | 266 } |
| 92 }; | 267 }; |
| 93 | 268 |
| 269 void emitTwoAddr(const char *Opcode, const Inst *Inst, const Cfg *Func); | |
| 270 | |
| 271 // TODO(jvoung): add condition codes if instruction can be predicated. | |
| 272 | |
| 273 // Instructions of the form x := op(y). | |
| 274 template <InstARM32::InstKindARM32 K> | |
| 275 class InstARM32UnaryopGPR : public InstARM32 { | |
| 276 InstARM32UnaryopGPR() = delete; | |
| 277 InstARM32UnaryopGPR(const InstARM32UnaryopGPR &) = delete; | |
| 278 InstARM32UnaryopGPR &operator=(const InstARM32UnaryopGPR &) = delete; | |
| 279 | |
| 280 public: | |
| 281 static InstARM32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src) { | |
| 282 return new (Func->allocate<InstARM32UnaryopGPR>()) | |
| 283 InstARM32UnaryopGPR(Func, Dest, Src); | |
| 284 } | |
| 285 void emit(const Cfg *Func) const override { | |
| 286 if (!ALLOW_DUMP) | |
| 287 return; | |
| 288 Ostream &Str = Func->getContext()->getStrEmit(); | |
| 289 assert(getSrcSize() == 1); | |
| 290 Str << "\t" << Opcode << "\t"; | |
| 291 getDest()->emit(Func); | |
| 292 Str << ", "; | |
| 293 getSrc(0)->emit(Func); | |
| 294 } | |
| 295 void emitIAS(const Cfg *Func) const override { | |
| 296 (void)Func; | |
| 297 llvm_unreachable("Not yet implemented"); | |
| 298 } | |
| 299 void dump(const Cfg *Func) const override { | |
| 300 if (!ALLOW_DUMP) | |
| 301 return; | |
| 302 Ostream &Str = Func->getContext()->getStrDump(); | |
| 303 dumpDest(Func); | |
| 304 Str << " = " << Opcode << "." << getDest()->getType() << " "; | |
| 305 dumpSources(Func); | |
| 306 } | |
| 307 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
| 308 | |
| 309 private: | |
| 310 InstARM32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src) | |
| 311 : InstARM32(Func, K, 1, Dest) { | |
| 312 addSource(Src); | |
| 313 } | |
| 314 ~InstARM32UnaryopGPR() override {} | |
| 315 static const char *Opcode; | |
| 316 }; | |
| 317 | |
| 318 // Instructions of the form x := x op y. | |
| 319 template <InstARM32::InstKindARM32 K> | |
| 320 class InstARM32TwoAddrGPR : public InstARM32 { | |
| 321 InstARM32TwoAddrGPR() = delete; | |
| 322 InstARM32TwoAddrGPR(const InstARM32TwoAddrGPR &) = delete; | |
| 323 InstARM32TwoAddrGPR &operator=(const InstARM32TwoAddrGPR &) = delete; | |
| 324 | |
| 325 public: | |
| 326 // Dest must be a register. | |
| 327 static InstARM32TwoAddrGPR *create(Cfg *Func, Variable *Dest, Operand *Src) { | |
| 328 return new (Func->allocate<InstARM32TwoAddrGPR>()) | |
| 329 InstARM32TwoAddrGPR(Func, Dest, Src); | |
| 330 } | |
| 331 void emit(const Cfg *Func) const override { | |
| 332 if (!ALLOW_DUMP) | |
| 333 return; | |
| 334 emitTwoAddr(Opcode, this, Func); | |
| 335 } | |
| 336 void emitIAS(const Cfg *Func) const override { | |
| 337 (void)Func; | |
| 338 llvm::report_fatal_error("Not yet implemented"); | |
| 339 } | |
| 340 void dump(const Cfg *Func) const override { | |
| 341 if (!ALLOW_DUMP) | |
| 342 return; | |
| 343 Ostream &Str = Func->getContext()->getStrDump(); | |
| 344 dumpDest(Func); | |
| 345 Str << " = " << Opcode << "." << getDest()->getType() << " "; | |
| 346 dumpSources(Func); | |
| 347 } | |
| 348 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
| 349 | |
| 350 private: | |
| 351 InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src) | |
| 352 : InstARM32(Func, K, 2, Dest) { | |
| 353 addSource(Dest); | |
| 354 addSource(Src); | |
| 355 } | |
| 356 ~InstARM32TwoAddrGPR() override {} | |
| 357 static const char *Opcode; | |
| 358 }; | |
| 359 | |
| 360 // Base class for assignment instructions. | |
| 361 // These can be tested for redundancy (and elided if redundant). | |
| 362 template <InstARM32::InstKindARM32 K> | |
| 363 class InstARM32Movlike : public InstARM32 { | |
| 364 InstARM32Movlike() = delete; | |
| 365 InstARM32Movlike(const InstARM32Movlike &) = delete; | |
| 366 InstARM32Movlike &operator=(const InstARM32Movlike &) = delete; | |
| 367 | |
| 368 public: | |
| 369 static InstARM32Movlike *create(Cfg *Func, Variable *Dest, Operand *Source) { | |
| 370 return new (Func->allocate<InstARM32Movlike>()) | |
| 371 InstARM32Movlike(Func, Dest, Source); | |
| 372 } | |
| 373 bool isRedundantAssign() const override { | |
| 374 return checkForRedundantAssign(getDest(), getSrc(0)); | |
| 375 } | |
| 376 bool isSimpleAssign() const override { return true; } | |
| 377 void emit(const Cfg *Func) const override; | |
| 378 void emitIAS(const Cfg *Func) const override; | |
| 379 void dump(const Cfg *Func) const override { | |
| 380 if (!ALLOW_DUMP) | |
| 381 return; | |
| 382 Ostream &Str = Func->getContext()->getStrDump(); | |
| 383 Str << Opcode << "." << getDest()->getType() << " "; | |
| 384 dumpDest(Func); | |
| 385 Str << ", "; | |
| 386 dumpSources(Func); | |
| 387 } | |
| 388 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
| 389 | |
| 390 private: | |
| 391 InstARM32Movlike(Cfg *Func, Variable *Dest, Operand *Source) | |
| 392 : InstARM32(Func, K, 1, Dest) { | |
| 393 addSource(Source); | |
| 394 } | |
| 395 ~InstARM32Movlike() override {} | |
| 396 | |
| 397 static const char *Opcode; | |
| 398 }; | |
| 399 | |
| 400 // Move instruction (variable <- flex). This is more of a pseudo-inst. | |
| 401 // If var is a register, then we use "mov". If var is stack, then we use | |
| 402 // "str" to store to the stack. | |
| 403 typedef InstARM32Movlike<InstARM32::Mov> InstARM32Mov; | |
| 404 // MovT leaves the bottom bits alone so dest is also a source. | |
| 405 // This helps indicate that a previous MovW setting dest is not dead code. | |
| 406 typedef InstARM32TwoAddrGPR<InstARM32::Movt> InstARM32Movt; | |
| 407 typedef InstARM32UnaryopGPR<InstARM32::Movw> InstARM32Movw; | |
| 408 typedef InstARM32UnaryopGPR<InstARM32::Mvn> InstARM32Mvn; | |
| 409 | |
| 410 // Load instruction. | |
| 411 class InstARM32Ldr : public InstARM32 { | |
| 412 InstARM32Ldr() = delete; | |
| 413 InstARM32Ldr(const InstARM32Ldr &) = delete; | |
| 414 InstARM32Ldr &operator=(const InstARM32Ldr &) = delete; | |
| 415 | |
| 416 public: | |
| 417 // Dest must be a register. | |
| 418 static InstARM32Ldr *create(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem) { | |
| 419 return new (Func->allocate<InstARM32Ldr>()) InstARM32Ldr(Func, Dest, Mem); | |
| 420 } | |
| 421 void emit(const Cfg *Func) const override; | |
| 422 void emitIAS(const Cfg *Func) const override; | |
| 423 void dump(const Cfg *Func) const override; | |
| 424 static bool classof(const Inst *Inst) { return isClassof(Inst, Ldr); } | |
| 425 | |
| 426 private: | |
| 427 InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem); | |
| 428 ~InstARM32Ldr() override {} | |
| 429 }; | |
| 430 | |
| 94 // Ret pseudo-instruction. This is actually a "bx" instruction with | 431 // Ret pseudo-instruction. This is actually a "bx" instruction with |
| 95 // an "lr" register operand, but epilogue lowering will search for a Ret | 432 // an "lr" register operand, but epilogue lowering will search for a Ret |
| 96 // instead of a generic "bx". This instruction also takes a Source | 433 // instead of a generic "bx". This instruction also takes a Source |
| 97 // operand (for non-void returning functions) for liveness analysis, though | 434 // operand (for non-void returning functions) for liveness analysis, though |
| 98 // a FakeUse before the ret would do just as well. | 435 // a FakeUse before the ret would do just as well. |
| 99 class InstARM32Ret : public InstARM32 { | 436 class InstARM32Ret : public InstARM32 { |
| 100 InstARM32Ret() = delete; | 437 InstARM32Ret() = delete; |
| 101 InstARM32Ret(const InstARM32Ret &) = delete; | 438 InstARM32Ret(const InstARM32Ret &) = delete; |
| 102 InstARM32Ret &operator=(const InstARM32Ret &) = delete; | 439 InstARM32Ret &operator=(const InstARM32Ret &) = delete; |
| 103 | 440 |
| 104 public: | 441 public: |
| 105 static InstARM32Ret *create(Cfg *Func, Variable *LR, | 442 static InstARM32Ret *create(Cfg *Func, Variable *LR, |
| 106 Variable *Source = nullptr) { | 443 Variable *Source = nullptr) { |
| 107 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); | 444 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); |
| 108 } | 445 } |
| 109 void emit(const Cfg *Func) const override; | 446 void emit(const Cfg *Func) const override; |
| 110 void emitIAS(const Cfg *Func) const override; | 447 void emitIAS(const Cfg *Func) const override; |
| 111 void dump(const Cfg *Func) const override; | 448 void dump(const Cfg *Func) const override; |
| 112 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } | 449 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } |
| 113 | 450 |
| 114 private: | 451 private: |
| 115 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); | 452 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); |
| 116 ~InstARM32Ret() override {} | 453 ~InstARM32Ret() override {} |
| 117 }; | 454 }; |
| 118 | 455 |
| 456 // Declare partial template specializations of emit() methods that | |
| 457 // already have default implementations. Without this, there is the | |
| 458 // possibility of ODR violations and link errors. | |
| 459 | |
| 460 template <> void InstARM32Movw::emit(const Cfg *Func) const; | |
| 461 template <> void InstARM32Movt::emit(const Cfg *Func) const; | |
| 462 | |
| 119 } // end of namespace Ice | 463 } // end of namespace Ice |
| 120 | 464 |
| 121 #endif // SUBZERO_SRC_ICEINSTARM32_H | 465 #endif // SUBZERO_SRC_ICEINSTARM32_H |
| OLD | NEW |