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 |