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 /// \file | 10 /// \file |
11 /// This file declares the InstARM32 and OperandARM32 classes and | 11 /// This file declares the InstARM32 and OperandARM32 classes and their |
12 /// their subclasses. This represents the machine instructions and | 12 /// subclasses. This represents the machine instructions and operands used for |
13 /// operands used for ARM32 code selection. | 13 /// ARM32 code selection. |
14 /// | 14 /// |
15 //===----------------------------------------------------------------------===// | 15 //===----------------------------------------------------------------------===// |
16 | 16 |
17 #ifndef SUBZERO_SRC_ICEINSTARM32_H | 17 #ifndef SUBZERO_SRC_ICEINSTARM32_H |
18 #define SUBZERO_SRC_ICEINSTARM32_H | 18 #define SUBZERO_SRC_ICEINSTARM32_H |
19 | 19 |
20 #include "IceConditionCodesARM32.h" | 20 #include "IceConditionCodesARM32.h" |
21 #include "IceDefs.h" | 21 #include "IceDefs.h" |
22 #include "IceInst.h" | 22 #include "IceInst.h" |
23 #include "IceInstARM32.def" | 23 #include "IceInstARM32.def" |
24 #include "IceOperand.h" | 24 #include "IceOperand.h" |
25 | 25 |
26 namespace Ice { | 26 namespace Ice { |
27 | 27 |
28 class TargetARM32; | 28 class TargetARM32; |
29 | 29 |
30 /// OperandARM32 extends the Operand hierarchy. Its subclasses are | 30 /// OperandARM32 extends the Operand hierarchy. Its subclasses are |
31 /// OperandARM32Mem and OperandARM32Flex. | 31 /// OperandARM32Mem and OperandARM32Flex. |
32 class OperandARM32 : public Operand { | 32 class OperandARM32 : public Operand { |
33 OperandARM32() = delete; | 33 OperandARM32() = delete; |
34 OperandARM32(const OperandARM32 &) = delete; | 34 OperandARM32(const OperandARM32 &) = delete; |
35 OperandARM32 &operator=(const OperandARM32 &) = delete; | 35 OperandARM32 &operator=(const OperandARM32 &) = delete; |
36 | 36 |
37 public: | 37 public: |
38 enum OperandKindARM32 { | 38 enum OperandKindARM32 { |
39 k__Start = Operand::kTarget, | 39 k__Start = Operand::kTarget, |
40 kMem, | 40 kMem, |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 PostIndex = (0 | 4 | 0) << 21, // post-indexed addressing with writeback | 80 PostIndex = (0 | 4 | 0) << 21, // post-indexed addressing with writeback |
81 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) |
82 NegPreIndex = (8 | 0 | 1) << 21, // negative pre-indexed with writeback | 82 NegPreIndex = (8 | 0 | 1) << 21, // negative pre-indexed with writeback |
83 NegPostIndex = (0 | 0 | 0) << 21 // negative post-indexed with writeback | 83 NegPostIndex = (0 | 0 | 0) << 21 // negative post-indexed with writeback |
84 }; | 84 }; |
85 | 85 |
86 /// Provide two constructors. | 86 /// Provide two constructors. |
87 /// NOTE: The Variable-typed operands have to be registers. | 87 /// NOTE: The Variable-typed operands have to be registers. |
88 /// | 88 /// |
89 /// (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 |
90 /// for encoding, so check canHoldOffset first. It cannot handle | 90 /// for encoding, so check canHoldOffset first. It cannot handle general |
91 /// general Constant operands like ConstantRelocatable, since a relocatable | 91 /// Constant operands like ConstantRelocatable, since a relocatable can |
92 /// can potentially take up too many bits. | 92 /// potentially take up too many bits. |
93 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, | 93 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, |
94 ConstantInteger32 *ImmOffset, | 94 ConstantInteger32 *ImmOffset, |
95 AddrMode Mode = Offset) { | 95 AddrMode Mode = Offset) { |
96 return new (Func->allocate<OperandARM32Mem>()) | 96 return new (Func->allocate<OperandARM32Mem>()) |
97 OperandARM32Mem(Func, Ty, Base, ImmOffset, Mode); | 97 OperandARM32Mem(Func, Ty, Base, ImmOffset, Mode); |
98 } | 98 } |
99 /// (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. Note that |
100 /// Note that this mode is disallowed in the NaCl sandbox. | 100 /// this mode is disallowed in the NaCl sandbox. |
101 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, | 101 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base, |
102 Variable *Index, ShiftKind ShiftOp = kNoShift, | 102 Variable *Index, ShiftKind ShiftOp = kNoShift, |
103 uint16_t ShiftAmt = 0, | 103 uint16_t ShiftAmt = 0, |
104 AddrMode Mode = Offset) { | 104 AddrMode Mode = Offset) { |
105 return new (Func->allocate<OperandARM32Mem>()) | 105 return new (Func->allocate<OperandARM32Mem>()) |
106 OperandARM32Mem(Func, Ty, Base, Index, ShiftOp, ShiftAmt, Mode); | 106 OperandARM32Mem(Func, Ty, Base, Index, ShiftOp, ShiftAmt, Mode); |
107 } | 107 } |
108 Variable *getBase() const { return Base; } | 108 Variable *getBase() const { return Base; } |
109 ConstantInteger32 *getOffset() const { return ImmOffset; } | 109 ConstantInteger32 *getOffset() const { return ImmOffset; } |
110 Variable *getIndex() const { return Index; } | 110 Variable *getIndex() const { return Index; } |
(...skipping 12 matching lines...) Expand all Loading... |
123 } | 123 } |
124 | 124 |
125 void emit(const Cfg *Func) const override; | 125 void emit(const Cfg *Func) const override; |
126 using OperandARM32::dump; | 126 using OperandARM32::dump; |
127 void dump(const Cfg *Func, Ostream &Str) const override; | 127 void dump(const Cfg *Func, Ostream &Str) const override; |
128 | 128 |
129 static bool classof(const Operand *Operand) { | 129 static bool classof(const Operand *Operand) { |
130 return Operand->getKind() == static_cast<OperandKind>(kMem); | 130 return Operand->getKind() == static_cast<OperandKind>(kMem); |
131 } | 131 } |
132 | 132 |
133 /// 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 can |
134 /// can encode the Offset directly in the immediate field of the 32-bit | 134 /// encode the Offset directly in the immediate field of the 32-bit ARM |
135 /// ARM instruction. For some types, if the load is Sign extending, then | 135 /// instruction. For some types, if the load is Sign extending, then the range |
136 /// the range is reduced. | 136 /// is reduced. |
137 static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset); | 137 static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset); |
138 | 138 |
139 private: | 139 private: |
140 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, | 140 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, |
141 ConstantInteger32 *ImmOffset, AddrMode Mode); | 141 ConstantInteger32 *ImmOffset, AddrMode Mode); |
142 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, Variable *Index, | 142 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, Variable *Index, |
143 ShiftKind ShiftOp, uint16_t ShiftAmt, AddrMode Mode); | 143 ShiftKind ShiftOp, uint16_t ShiftAmt, AddrMode Mode); |
144 | 144 |
145 Variable *Base; | 145 Variable *Base; |
146 ConstantInteger32 *ImmOffset; | 146 ConstantInteger32 *ImmOffset; |
147 Variable *Index; | 147 Variable *Index; |
148 ShiftKind ShiftOp; | 148 ShiftKind ShiftOp; |
149 uint16_t ShiftAmt; | 149 uint16_t ShiftAmt; |
150 AddrMode Mode; | 150 AddrMode Mode; |
151 }; | 151 }; |
152 | 152 |
153 /// OperandARM32Flex represent the "flexible second operand" for | 153 /// OperandARM32Flex represent the "flexible second operand" for data-processing |
154 /// data-processing instructions. It can be a rotatable 8-bit constant, or | 154 /// instructions. It can be a rotatable 8-bit constant, or a register with an |
155 /// a register with an optional shift operand. The shift amount can even be | 155 /// optional shift operand. The shift amount can even be a third register. |
156 /// a third register. | |
157 class OperandARM32Flex : public OperandARM32 { | 156 class OperandARM32Flex : public OperandARM32 { |
158 OperandARM32Flex() = delete; | 157 OperandARM32Flex() = delete; |
159 OperandARM32Flex(const OperandARM32Flex &) = delete; | 158 OperandARM32Flex(const OperandARM32Flex &) = delete; |
160 OperandARM32Flex &operator=(const OperandARM32Flex &) = delete; | 159 OperandARM32Flex &operator=(const OperandARM32Flex &) = delete; |
161 | 160 |
162 public: | 161 public: |
163 static bool classof(const Operand *Operand) { | 162 static bool classof(const Operand *Operand) { |
164 return static_cast<OperandKind>(kFlexStart) <= Operand->getKind() && | 163 return static_cast<OperandKind>(kFlexStart) <= Operand->getKind() && |
165 Operand->getKind() <= static_cast<OperandKind>(kFlexEnd); | 164 Operand->getKind() <= static_cast<OperandKind>(kFlexEnd); |
166 } | 165 } |
(...skipping 17 matching lines...) Expand all Loading... |
184 } | 183 } |
185 | 184 |
186 void emit(const Cfg *Func) const override; | 185 void emit(const Cfg *Func) const override; |
187 using OperandARM32::dump; | 186 using OperandARM32::dump; |
188 void dump(const Cfg *Func, Ostream &Str) const override; | 187 void dump(const Cfg *Func, Ostream &Str) const override; |
189 | 188 |
190 static bool classof(const Operand *Operand) { | 189 static bool classof(const Operand *Operand) { |
191 return Operand->getKind() == static_cast<OperandKind>(kFlexImm); | 190 return Operand->getKind() == static_cast<OperandKind>(kFlexImm); |
192 } | 191 } |
193 | 192 |
194 /// Return true if the Immediate can fit in the ARM flexible operand. | 193 /// Return true if the Immediate can fit in the ARM flexible operand. Fills in |
195 /// Fills in the out-params RotateAmt and Immed_8 if Immediate fits. | 194 /// the out-params RotateAmt and Immed_8 if Immediate fits. |
196 static bool canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, | 195 static bool canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, |
197 uint32_t *Immed_8); | 196 uint32_t *Immed_8); |
198 | 197 |
199 uint32_t getImm() const { return Imm; } | 198 uint32_t getImm() const { return Imm; } |
200 uint32_t getRotateAmt() const { return RotateAmt; } | 199 uint32_t getRotateAmt() const { return RotateAmt; } |
201 | 200 |
202 private: | 201 private: |
203 OperandARM32FlexImm(Cfg *Func, Type Ty, uint32_t Imm, uint32_t RotateAmt); | 202 OperandARM32FlexImm(Cfg *Func, Type Ty, uint32_t Imm, uint32_t RotateAmt); |
204 | 203 |
205 uint32_t Imm; | 204 uint32_t Imm; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, ShiftKind ShiftOp, | 236 OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, ShiftKind ShiftOp, |
238 Operand *ShiftAmt); | 237 Operand *ShiftAmt); |
239 | 238 |
240 Variable *Reg; | 239 Variable *Reg; |
241 ShiftKind ShiftOp; | 240 ShiftKind ShiftOp; |
242 Operand *ShiftAmt; | 241 Operand *ShiftAmt; |
243 }; | 242 }; |
244 | 243 |
245 /// StackVariable represents a Var that isn't assigned a register (stack-only). | 244 /// StackVariable represents a Var that isn't assigned a register (stack-only). |
246 /// It is assigned a stack slot, but the slot's offset may be too large to | 245 /// It is assigned a stack slot, but the slot's offset may be too large to |
247 /// represent in the native addressing mode, and so it has a separate | 246 /// represent in the native addressing mode, and so it has a separate base |
248 /// base register from SP/FP, where the offset from that base register is | 247 /// register from SP/FP, where the offset from that base register is then in |
249 /// then in range. | 248 /// range. |
250 class StackVariable final : public Variable { | 249 class StackVariable final : public Variable { |
251 StackVariable() = delete; | 250 StackVariable() = delete; |
252 StackVariable(const StackVariable &) = delete; | 251 StackVariable(const StackVariable &) = delete; |
253 StackVariable &operator=(const StackVariable &) = delete; | 252 StackVariable &operator=(const StackVariable &) = delete; |
254 | 253 |
255 public: | 254 public: |
256 static StackVariable *create(Cfg *Func, Type Ty, SizeT Index) { | 255 static StackVariable *create(Cfg *Func, Type Ty, SizeT Index) { |
257 return new (Func->allocate<StackVariable>()) StackVariable(Ty, Index); | 256 return new (Func->allocate<StackVariable>()) StackVariable(Ty, Index); |
258 } | 257 } |
259 const static OperandKind StackVariableKind = | 258 const static OperandKind StackVariableKind = |
260 static_cast<OperandKind>(kVariable_Target); | 259 static_cast<OperandKind>(kVariable_Target); |
261 static bool classof(const Operand *Operand) { | 260 static bool classof(const Operand *Operand) { |
262 return Operand->getKind() == StackVariableKind; | 261 return Operand->getKind() == StackVariableKind; |
263 } | 262 } |
264 void setBaseRegNum(int32_t RegNum) { BaseRegNum = RegNum; } | 263 void setBaseRegNum(int32_t RegNum) { BaseRegNum = RegNum; } |
265 int32_t getBaseRegNum() const override { return BaseRegNum; } | 264 int32_t getBaseRegNum() const override { return BaseRegNum; } |
266 // Inherit dump() and emit() from Variable. | 265 // Inherit dump() and emit() from Variable. |
267 | 266 |
268 private: | 267 private: |
269 StackVariable(Type Ty, SizeT Index) | 268 StackVariable(Type Ty, SizeT Index) |
270 : Variable(StackVariableKind, Ty, Index) {} | 269 : Variable(StackVariableKind, Ty, Index) {} |
271 int32_t BaseRegNum = Variable::NoRegister; | 270 int32_t BaseRegNum = Variable::NoRegister; |
272 }; | 271 }; |
273 | 272 |
274 /// Base class for ARM instructions. While most ARM instructions can be | 273 /// Base class for ARM instructions. While most ARM instructions can be |
275 /// conditionally executed, a few of them are not predicable (halt, | 274 /// conditionally executed, a few of them are not predicable (halt, memory |
276 /// memory barriers, etc.). | 275 /// barriers, etc.). |
277 class InstARM32 : public InstTarget { | 276 class InstARM32 : public InstTarget { |
278 InstARM32() = delete; | 277 InstARM32() = delete; |
279 InstARM32(const InstARM32 &) = delete; | 278 InstARM32(const InstARM32 &) = delete; |
280 InstARM32 &operator=(const InstARM32 &) = delete; | 279 InstARM32 &operator=(const InstARM32 &) = delete; |
281 | 280 |
282 public: | 281 public: |
283 enum InstKindARM32 { | 282 enum InstKindARM32 { |
284 k__Start = Inst::Target, | 283 k__Start = Inst::Target, |
285 Adc, | 284 Adc, |
286 Add, | 285 Add, |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
518 InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src, | 517 InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src, |
519 CondARM32::Cond Predicate) | 518 CondARM32::Cond Predicate) |
520 : InstARM32Pred(Func, K, 2, Dest, Predicate) { | 519 : InstARM32Pred(Func, K, 2, Dest, Predicate) { |
521 addSource(Dest); | 520 addSource(Dest); |
522 addSource(Src); | 521 addSource(Src); |
523 } | 522 } |
524 | 523 |
525 static const char *Opcode; | 524 static const char *Opcode; |
526 }; | 525 }; |
527 | 526 |
528 /// Base class for assignment instructions. | 527 /// Base class for assignment instructions. These can be tested for redundancy |
529 /// These can be tested for redundancy (and elided if redundant). | 528 /// (and elided if redundant). |
530 template <InstARM32::InstKindARM32 K> | 529 template <InstARM32::InstKindARM32 K> |
531 class InstARM32Movlike : public InstARM32Pred { | 530 class InstARM32Movlike : public InstARM32Pred { |
532 InstARM32Movlike() = delete; | 531 InstARM32Movlike() = delete; |
533 InstARM32Movlike(const InstARM32Movlike &) = delete; | 532 InstARM32Movlike(const InstARM32Movlike &) = delete; |
534 InstARM32Movlike &operator=(const InstARM32Movlike &) = delete; | 533 InstARM32Movlike &operator=(const InstARM32Movlike &) = delete; |
535 | 534 |
536 public: | 535 public: |
537 static InstARM32Movlike *create(Cfg *Func, Variable *Dest, Operand *Source, | 536 static InstARM32Movlike *create(Cfg *Func, Variable *Dest, Operand *Source, |
538 CondARM32::Cond Predicate) { | 537 CondARM32::Cond Predicate) { |
539 return new (Func->allocate<InstARM32Movlike>()) | 538 return new (Func->allocate<InstARM32Movlike>()) |
(...skipping 29 matching lines...) Expand all Loading... |
569 | 568 |
570 /// Instructions of the form x := y op z. May have the side-effect of setting | 569 /// Instructions of the form x := y op z. May have the side-effect of setting |
571 /// status flags. | 570 /// status flags. |
572 template <InstARM32::InstKindARM32 K> | 571 template <InstARM32::InstKindARM32 K> |
573 class InstARM32ThreeAddrGPR : public InstARM32Pred { | 572 class InstARM32ThreeAddrGPR : public InstARM32Pred { |
574 InstARM32ThreeAddrGPR() = delete; | 573 InstARM32ThreeAddrGPR() = delete; |
575 InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete; | 574 InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete; |
576 InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete; | 575 InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete; |
577 | 576 |
578 public: | 577 public: |
579 /// Create an ordinary binary-op instruction like add, and sub. | 578 /// Create an ordinary binary-op instruction like add, and sub. Dest and Src1 |
580 /// Dest and Src1 must be registers. | 579 /// must be registers. |
581 static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest, | 580 static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest, |
582 Variable *Src0, Operand *Src1, | 581 Variable *Src0, Operand *Src1, |
583 CondARM32::Cond Predicate, | 582 CondARM32::Cond Predicate, |
584 bool SetFlags = false) { | 583 bool SetFlags = false) { |
585 return new (Func->allocate<InstARM32ThreeAddrGPR>()) | 584 return new (Func->allocate<InstARM32ThreeAddrGPR>()) |
586 InstARM32ThreeAddrGPR(Func, Dest, Src0, Src1, Predicate, SetFlags); | 585 InstARM32ThreeAddrGPR(Func, Dest, Src0, Src1, Predicate, SetFlags); |
587 } | 586 } |
588 void emit(const Cfg *Func) const override { | 587 void emit(const Cfg *Func) const override { |
589 if (!BuildDefs::dump()) | 588 if (!BuildDefs::dump()) |
590 return; | 589 return; |
(...skipping 20 matching lines...) Expand all Loading... |
611 Operand *Src1, CondARM32::Cond Predicate, bool SetFlags) | 610 Operand *Src1, CondARM32::Cond Predicate, bool SetFlags) |
612 : InstARM32Pred(Func, K, 2, Dest, Predicate), SetFlags(SetFlags) { | 611 : InstARM32Pred(Func, K, 2, Dest, Predicate), SetFlags(SetFlags) { |
613 addSource(Src0); | 612 addSource(Src0); |
614 addSource(Src1); | 613 addSource(Src1); |
615 } | 614 } |
616 | 615 |
617 static const char *Opcode; | 616 static const char *Opcode; |
618 bool SetFlags; | 617 bool SetFlags; |
619 }; | 618 }; |
620 | 619 |
621 /// Instructions of the form x := y op z, for vector/FP. We leave these as | 620 /// Instructions of the form x := y op z, for vector/FP. We leave these as |
622 /// unconditional: "ARM deprecates the conditional execution of any instruction | 621 /// unconditional: "ARM deprecates the conditional execution of any instruction |
623 /// encoding provided by the Advanced SIMD Extension that is not also provided | 622 /// encoding provided by the Advanced SIMD Extension that is not also provided |
624 /// by the Floating-point (VFP) extension". They do not set flags. | 623 /// by the Floating-point (VFP) extension". They do not set flags. |
625 template <InstARM32::InstKindARM32 K> | 624 template <InstARM32::InstKindARM32 K> |
626 class InstARM32ThreeAddrFP : public InstARM32 { | 625 class InstARM32ThreeAddrFP : public InstARM32 { |
627 InstARM32ThreeAddrFP() = delete; | 626 InstARM32ThreeAddrFP() = delete; |
628 InstARM32ThreeAddrFP(const InstARM32ThreeAddrFP &) = delete; | 627 InstARM32ThreeAddrFP(const InstARM32ThreeAddrFP &) = delete; |
629 InstARM32ThreeAddrFP &operator=(const InstARM32ThreeAddrFP &) = delete; | 628 InstARM32ThreeAddrFP &operator=(const InstARM32ThreeAddrFP &) = delete; |
630 | 629 |
631 public: | 630 public: |
632 /// Create a vector/FP binary-op instruction like vadd, and vsub. | 631 /// Create a vector/FP binary-op instruction like vadd, and vsub. Everything |
633 /// Everything must be a register. | 632 /// must be a register. |
634 static InstARM32ThreeAddrFP *create(Cfg *Func, Variable *Dest, Variable *Src0, | 633 static InstARM32ThreeAddrFP *create(Cfg *Func, Variable *Dest, Variable *Src0, |
635 Variable *Src1) { | 634 Variable *Src1) { |
636 return new (Func->allocate<InstARM32ThreeAddrFP>()) | 635 return new (Func->allocate<InstARM32ThreeAddrFP>()) |
637 InstARM32ThreeAddrFP(Func, Dest, Src0, Src1); | 636 InstARM32ThreeAddrFP(Func, Dest, Src0, Src1); |
638 } | 637 } |
639 void emit(const Cfg *Func) const override { | 638 void emit(const Cfg *Func) const override { |
640 if (!BuildDefs::dump()) | 639 if (!BuildDefs::dump()) |
641 return; | 640 return; |
642 emitThreeAddrFP(Opcode, this, Func); | 641 emitThreeAddrFP(Opcode, this, Func); |
643 } | 642 } |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
772 using InstARM32Rsb = InstARM32ThreeAddrGPR<InstARM32::Rsb>; | 771 using InstARM32Rsb = InstARM32ThreeAddrGPR<InstARM32::Rsb>; |
773 using InstARM32Sbc = InstARM32ThreeAddrGPR<InstARM32::Sbc>; | 772 using InstARM32Sbc = InstARM32ThreeAddrGPR<InstARM32::Sbc>; |
774 using InstARM32Sdiv = InstARM32ThreeAddrGPR<InstARM32::Sdiv>; | 773 using InstARM32Sdiv = InstARM32ThreeAddrGPR<InstARM32::Sdiv>; |
775 using InstARM32Sub = InstARM32ThreeAddrGPR<InstARM32::Sub>; | 774 using InstARM32Sub = InstARM32ThreeAddrGPR<InstARM32::Sub>; |
776 using InstARM32Udiv = InstARM32ThreeAddrGPR<InstARM32::Udiv>; | 775 using InstARM32Udiv = InstARM32ThreeAddrGPR<InstARM32::Udiv>; |
777 using InstARM32Vadd = InstARM32ThreeAddrFP<InstARM32::Vadd>; | 776 using InstARM32Vadd = InstARM32ThreeAddrFP<InstARM32::Vadd>; |
778 using InstARM32Vdiv = InstARM32ThreeAddrFP<InstARM32::Vdiv>; | 777 using InstARM32Vdiv = InstARM32ThreeAddrFP<InstARM32::Vdiv>; |
779 using InstARM32Vmul = InstARM32ThreeAddrFP<InstARM32::Vmul>; | 778 using InstARM32Vmul = InstARM32ThreeAddrFP<InstARM32::Vmul>; |
780 using InstARM32Vsub = InstARM32ThreeAddrFP<InstARM32::Vsub>; | 779 using InstARM32Vsub = InstARM32ThreeAddrFP<InstARM32::Vsub>; |
781 using InstARM32Ldr = InstARM32Movlike<InstARM32::Ldr>; | 780 using InstARM32Ldr = InstARM32Movlike<InstARM32::Ldr>; |
782 /// Move instruction (variable <- flex). This is more of a pseudo-inst. | 781 /// Move instruction (variable <- flex). This is more of a pseudo-inst. If var |
783 /// If var is a register, then we use "mov". If var is stack, then we use | 782 /// is a register, then we use "mov". If var is stack, then we use "str" to |
784 /// "str" to store to the stack. | 783 /// store to the stack. |
785 using InstARM32Mov = InstARM32Movlike<InstARM32::Mov>; | 784 using InstARM32Mov = InstARM32Movlike<InstARM32::Mov>; |
786 /// Represents various vector mov instruction forms (simple single source, | 785 /// Represents various vector mov instruction forms (simple single source, |
787 /// single dest forms only, not the 2 GPR <-> 1 D reg forms, etc.). | 786 /// single dest forms only, not the 2 GPR <-> 1 D reg forms, etc.). |
788 using InstARM32Vmov = InstARM32Movlike<InstARM32::Vmov>; | 787 using InstARM32Vmov = InstARM32Movlike<InstARM32::Vmov>; |
789 using InstARM32Vldr = InstARM32Movlike<InstARM32::Vldr>; | 788 using InstARM32Vldr = InstARM32Movlike<InstARM32::Vldr>; |
790 /// MovT leaves the bottom bits alone so dest is also a source. | 789 /// MovT leaves the bottom bits alone so dest is also a source. This helps |
791 /// This helps indicate that a previous MovW setting dest is not dead code. | 790 /// indicate that a previous MovW setting dest is not dead code. |
792 using InstARM32Movt = InstARM32TwoAddrGPR<InstARM32::Movt>; | 791 using InstARM32Movt = InstARM32TwoAddrGPR<InstARM32::Movt>; |
793 using InstARM32Movw = InstARM32UnaryopGPR<InstARM32::Movw, false>; | 792 using InstARM32Movw = InstARM32UnaryopGPR<InstARM32::Movw, false>; |
794 using InstARM32Clz = InstARM32UnaryopGPR<InstARM32::Clz, false>; | 793 using InstARM32Clz = InstARM32UnaryopGPR<InstARM32::Clz, false>; |
795 using InstARM32Mvn = InstARM32UnaryopGPR<InstARM32::Mvn, false>; | 794 using InstARM32Mvn = InstARM32UnaryopGPR<InstARM32::Mvn, false>; |
796 using InstARM32Rbit = InstARM32UnaryopGPR<InstARM32::Rbit, false>; | 795 using InstARM32Rbit = InstARM32UnaryopGPR<InstARM32::Rbit, false>; |
797 using InstARM32Rev = InstARM32UnaryopGPR<InstARM32::Rev, false>; | 796 using InstARM32Rev = InstARM32UnaryopGPR<InstARM32::Rev, false>; |
798 // Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation | 797 // Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation operand |
799 // operand as well (rotate source by 8, 16, 24 bits prior to extending), | 798 // as well (rotate source by 8, 16, 24 bits prior to extending), but we aren't |
800 // but we aren't using that for now, so just model as a Unaryop. | 799 // using that for now, so just model as a Unaryop. |
801 using InstARM32Sxt = InstARM32UnaryopGPR<InstARM32::Sxt, true>; | 800 using InstARM32Sxt = InstARM32UnaryopGPR<InstARM32::Sxt, true>; |
802 using InstARM32Uxt = InstARM32UnaryopGPR<InstARM32::Uxt, true>; | 801 using InstARM32Uxt = InstARM32UnaryopGPR<InstARM32::Uxt, true>; |
803 using InstARM32Vsqrt = InstARM32UnaryopFP<InstARM32::Vsqrt>; | 802 using InstARM32Vsqrt = InstARM32UnaryopFP<InstARM32::Vsqrt>; |
804 using InstARM32Mla = InstARM32FourAddrGPR<InstARM32::Mla>; | 803 using InstARM32Mla = InstARM32FourAddrGPR<InstARM32::Mla>; |
805 using InstARM32Mls = InstARM32FourAddrGPR<InstARM32::Mls>; | 804 using InstARM32Mls = InstARM32FourAddrGPR<InstARM32::Mls>; |
806 using InstARM32Cmp = InstARM32CmpLike<InstARM32::Cmp>; | 805 using InstARM32Cmp = InstARM32CmpLike<InstARM32::Cmp>; |
807 using InstARM32Tst = InstARM32CmpLike<InstARM32::Tst>; | 806 using InstARM32Tst = InstARM32CmpLike<InstARM32::Tst>; |
808 | 807 |
809 // InstARM32Label represents an intra-block label that is the target | 808 // InstARM32Label represents an intra-block label that is the target of an |
810 // of an intra-block branch. The offset between the label and the | 809 // intra-block branch. The offset between the label and the branch must be fit |
811 // branch must be fit in the instruction immediate (considered "near"). | 810 // in the instruction immediate (considered "near"). |
812 class InstARM32Label : public InstARM32 { | 811 class InstARM32Label : public InstARM32 { |
813 InstARM32Label() = delete; | 812 InstARM32Label() = delete; |
814 InstARM32Label(const InstARM32Label &) = delete; | 813 InstARM32Label(const InstARM32Label &) = delete; |
815 InstARM32Label &operator=(const InstARM32Label &) = delete; | 814 InstARM32Label &operator=(const InstARM32Label &) = delete; |
816 | 815 |
817 public: | 816 public: |
818 static InstARM32Label *create(Cfg *Func, TargetARM32 *Target) { | 817 static InstARM32Label *create(Cfg *Func, TargetARM32 *Target) { |
819 return new (Func->allocate<InstARM32Label>()) InstARM32Label(Func, Target); | 818 return new (Func->allocate<InstARM32Label>()) InstARM32Label(Func, Target); |
820 } | 819 } |
821 uint32_t getEmitInstCount() const override { return 0; } | 820 uint32_t getEmitInstCount() const override { return 0; } |
(...skipping 24 matching lines...) Expand all Loading... |
846 return new (Func->allocate<InstARM32Br>()) | 845 return new (Func->allocate<InstARM32Br>()) |
847 InstARM32Br(Func, TargetTrue, TargetFalse, NoLabel, Predicate); | 846 InstARM32Br(Func, TargetTrue, TargetFalse, NoLabel, Predicate); |
848 } | 847 } |
849 /// Create an unconditional branch to a node. | 848 /// Create an unconditional branch to a node. |
850 static InstARM32Br *create(Cfg *Func, CfgNode *Target) { | 849 static InstARM32Br *create(Cfg *Func, CfgNode *Target) { |
851 constexpr CfgNode *NoCondTarget = nullptr; | 850 constexpr CfgNode *NoCondTarget = nullptr; |
852 constexpr InstARM32Label *NoLabel = nullptr; | 851 constexpr InstARM32Label *NoLabel = nullptr; |
853 return new (Func->allocate<InstARM32Br>()) | 852 return new (Func->allocate<InstARM32Br>()) |
854 InstARM32Br(Func, NoCondTarget, Target, NoLabel, CondARM32::AL); | 853 InstARM32Br(Func, NoCondTarget, Target, NoLabel, CondARM32::AL); |
855 } | 854 } |
856 /// Create a non-terminator conditional branch to a node, with a | 855 /// Create a non-terminator conditional branch to a node, with a fallthrough |
857 /// fallthrough to the next instruction in the current node. This is | 856 /// to the next instruction in the current node. This is used for switch |
858 /// used for switch lowering. | 857 /// lowering. |
859 static InstARM32Br *create(Cfg *Func, CfgNode *Target, | 858 static InstARM32Br *create(Cfg *Func, CfgNode *Target, |
860 CondARM32::Cond Predicate) { | 859 CondARM32::Cond Predicate) { |
861 assert(Predicate != CondARM32::AL); | 860 assert(Predicate != CondARM32::AL); |
862 constexpr CfgNode *NoUncondTarget = nullptr; | 861 constexpr CfgNode *NoUncondTarget = nullptr; |
863 constexpr InstARM32Label *NoLabel = nullptr; | 862 constexpr InstARM32Label *NoLabel = nullptr; |
864 return new (Func->allocate<InstARM32Br>()) | 863 return new (Func->allocate<InstARM32Br>()) |
865 InstARM32Br(Func, Target, NoUncondTarget, NoLabel, Predicate); | 864 InstARM32Br(Func, Target, NoUncondTarget, NoLabel, Predicate); |
866 } | 865 } |
867 // Create a conditional intra-block branch (or unconditional, if | 866 // Create a conditional intra-block branch (or unconditional, if |
868 // Condition==AL) to a label in the current block. | 867 // Condition==AL) to a label in the current block. |
(...skipping 28 matching lines...) Expand all Loading... |
897 | 896 |
898 private: | 897 private: |
899 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, | 898 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, |
900 const InstARM32Label *Label, CondARM32::Cond Predicate); | 899 const InstARM32Label *Label, CondARM32::Cond Predicate); |
901 | 900 |
902 const CfgNode *TargetTrue; | 901 const CfgNode *TargetTrue; |
903 const CfgNode *TargetFalse; | 902 const CfgNode *TargetFalse; |
904 const InstARM32Label *Label; // Intra-block branch target | 903 const InstARM32Label *Label; // Intra-block branch target |
905 }; | 904 }; |
906 | 905 |
907 /// AdjustStack instruction - subtracts SP by the given amount and | 906 /// AdjustStack instruction - subtracts SP by the given amount and updates the |
908 /// updates the stack offset during code emission. | 907 /// stack offset during code emission. |
909 class InstARM32AdjustStack : public InstARM32 { | 908 class InstARM32AdjustStack : public InstARM32 { |
910 InstARM32AdjustStack() = delete; | 909 InstARM32AdjustStack() = delete; |
911 InstARM32AdjustStack(const InstARM32AdjustStack &) = delete; | 910 InstARM32AdjustStack(const InstARM32AdjustStack &) = delete; |
912 InstARM32AdjustStack &operator=(const InstARM32AdjustStack &) = delete; | 911 InstARM32AdjustStack &operator=(const InstARM32AdjustStack &) = delete; |
913 | 912 |
914 public: | 913 public: |
915 /// Note: We need both Amount and SrcAmount. If Amount is too large then | 914 /// Note: We need both Amount and SrcAmount. If Amount is too large then it |
916 /// it needs to be copied to a register (so SrcAmount could be a register). | 915 /// needs to be copied to a register (so SrcAmount could be a register). |
917 /// However, we also need the numeric Amount for bookkeeping, and it's | 916 /// However, we also need the numeric Amount for bookkeeping, and it's hard to |
918 /// hard to pull that from the generic SrcAmount operand. | 917 /// pull that from the generic SrcAmount operand. |
919 static InstARM32AdjustStack *create(Cfg *Func, Variable *SP, SizeT Amount, | 918 static InstARM32AdjustStack *create(Cfg *Func, Variable *SP, SizeT Amount, |
920 Operand *SrcAmount) { | 919 Operand *SrcAmount) { |
921 return new (Func->allocate<InstARM32AdjustStack>()) | 920 return new (Func->allocate<InstARM32AdjustStack>()) |
922 InstARM32AdjustStack(Func, SP, Amount, SrcAmount); | 921 InstARM32AdjustStack(Func, SP, Amount, SrcAmount); |
923 } | 922 } |
924 void emit(const Cfg *Func) const override; | 923 void emit(const Cfg *Func) const override; |
925 void emitIAS(const Cfg *Func) const override; | 924 void emitIAS(const Cfg *Func) const override; |
926 void dump(const Cfg *Func) const override; | 925 void dump(const Cfg *Func) const override; |
927 static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); } | 926 static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); } |
928 SizeT getAmount() const { return Amount; } | 927 SizeT getAmount() const { return Amount; } |
929 | 928 |
930 private: | 929 private: |
931 InstARM32AdjustStack(Cfg *Func, Variable *SP, SizeT Amount, | 930 InstARM32AdjustStack(Cfg *Func, Variable *SP, SizeT Amount, |
932 Operand *SrcAmount); | 931 Operand *SrcAmount); |
933 const SizeT Amount; | 932 const SizeT Amount; |
934 }; | 933 }; |
935 | 934 |
936 /// Call instruction (bl/blx). Arguments should have already been pushed. | 935 /// Call instruction (bl/blx). Arguments should have already been pushed. |
937 /// Technically bl and the register form of blx can be predicated, but we'll | 936 /// Technically bl and the register form of blx can be predicated, but we'll |
938 /// leave that out until needed. | 937 /// leave that out until needed. |
939 class InstARM32Call : public InstARM32 { | 938 class InstARM32Call : public InstARM32 { |
940 InstARM32Call() = delete; | 939 InstARM32Call() = delete; |
941 InstARM32Call(const InstARM32Call &) = delete; | 940 InstARM32Call(const InstARM32Call &) = delete; |
942 InstARM32Call &operator=(const InstARM32Call &) = delete; | 941 InstARM32Call &operator=(const InstARM32Call &) = delete; |
943 | 942 |
944 public: | 943 public: |
945 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { | 944 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { |
946 return new (Func->allocate<InstARM32Call>()) | 945 return new (Func->allocate<InstARM32Call>()) |
(...skipping 24 matching lines...) Expand all Loading... |
971 void emitIAS(const Cfg *Func) const override; | 970 void emitIAS(const Cfg *Func) const override; |
972 void dump(const Cfg *Func) const override; | 971 void dump(const Cfg *Func) const override; |
973 static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } | 972 static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } |
974 | 973 |
975 private: | 974 private: |
976 InstARM32Pop(Cfg *Func, const VarList &Dests); | 975 InstARM32Pop(Cfg *Func, const VarList &Dests); |
977 | 976 |
978 VarList Dests; | 977 VarList Dests; |
979 }; | 978 }; |
980 | 979 |
981 /// Push a list of GPRs. Technically this can be predicated, but we don't | 980 /// Push a list of GPRs. Technically this can be predicated, but we don't need |
982 /// need that functionality. | 981 /// that functionality. |
983 class InstARM32Push : public InstARM32 { | 982 class InstARM32Push : public InstARM32 { |
984 InstARM32Push() = delete; | 983 InstARM32Push() = delete; |
985 InstARM32Push(const InstARM32Push &) = delete; | 984 InstARM32Push(const InstARM32Push &) = delete; |
986 InstARM32Push &operator=(const InstARM32Push &) = delete; | 985 InstARM32Push &operator=(const InstARM32Push &) = delete; |
987 | 986 |
988 public: | 987 public: |
989 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) { | 988 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) { |
990 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); | 989 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); |
991 } | 990 } |
992 void emit(const Cfg *Func) const override; | 991 void emit(const Cfg *Func) const override; |
993 void emitIAS(const Cfg *Func) const override; | 992 void emitIAS(const Cfg *Func) const override; |
994 void dump(const Cfg *Func) const override; | 993 void dump(const Cfg *Func) const override; |
995 static bool classof(const Inst *Inst) { return isClassof(Inst, Push); } | 994 static bool classof(const Inst *Inst) { return isClassof(Inst, Push); } |
996 | 995 |
997 private: | 996 private: |
998 InstARM32Push(Cfg *Func, const VarList &Srcs); | 997 InstARM32Push(Cfg *Func, const VarList &Srcs); |
999 }; | 998 }; |
1000 | 999 |
1001 /// Ret pseudo-instruction. This is actually a "bx" instruction with | 1000 /// Ret pseudo-instruction. This is actually a "bx" instruction with an "lr" |
1002 /// an "lr" register operand, but epilogue lowering will search for a Ret | 1001 /// register operand, but epilogue lowering will search for a Ret instead of a |
1003 /// instead of a generic "bx". This instruction also takes a Source | 1002 /// generic "bx". This instruction also takes a Source operand (for non-void |
1004 /// operand (for non-void returning functions) for liveness analysis, though | 1003 /// returning functions) for liveness analysis, though a FakeUse before the ret |
1005 /// a FakeUse before the ret would do just as well. | 1004 /// would do just as well. |
1006 /// | 1005 /// |
1007 /// NOTE: Even though "bx" can be predicated, for now leave out the predication | 1006 /// NOTE: Even though "bx" can be predicated, for now leave out the predication |
1008 /// since it's not yet known to be useful for Ret. That may complicate finding | 1007 /// since it's not yet known to be useful for Ret. That may complicate finding |
1009 /// the terminator instruction if it's not guaranteed to be executed. | 1008 /// the terminator instruction if it's not guaranteed to be executed. |
1010 class InstARM32Ret : public InstARM32 { | 1009 class InstARM32Ret : public InstARM32 { |
1011 InstARM32Ret() = delete; | 1010 InstARM32Ret() = delete; |
1012 InstARM32Ret(const InstARM32Ret &) = delete; | 1011 InstARM32Ret(const InstARM32Ret &) = delete; |
1013 InstARM32Ret &operator=(const InstARM32Ret &) = delete; | 1012 InstARM32Ret &operator=(const InstARM32Ret &) = delete; |
1014 | 1013 |
1015 public: | 1014 public: |
1016 static InstARM32Ret *create(Cfg *Func, Variable *LR, | 1015 static InstARM32Ret *create(Cfg *Func, Variable *LR, |
1017 Variable *Source = nullptr) { | 1016 Variable *Source = nullptr) { |
1018 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); | 1017 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); |
1019 } | 1018 } |
1020 void emit(const Cfg *Func) const override; | 1019 void emit(const Cfg *Func) const override; |
1021 void emitIAS(const Cfg *Func) const override; | 1020 void emitIAS(const Cfg *Func) const override; |
1022 void dump(const Cfg *Func) const override; | 1021 void dump(const Cfg *Func) const override; |
1023 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } | 1022 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } |
1024 | 1023 |
1025 private: | 1024 private: |
1026 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); | 1025 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); |
1027 }; | 1026 }; |
1028 | 1027 |
1029 /// Store instruction. It's important for liveness that there is no Dest | 1028 /// Store instruction. It's important for liveness that there is no Dest operand |
1030 /// operand (OperandARM32Mem instead of Dest Variable). | 1029 /// (OperandARM32Mem instead of Dest Variable). |
1031 class InstARM32Str : public InstARM32Pred { | 1030 class InstARM32Str : public InstARM32Pred { |
1032 InstARM32Str() = delete; | 1031 InstARM32Str() = delete; |
1033 InstARM32Str(const InstARM32Str &) = delete; | 1032 InstARM32Str(const InstARM32Str &) = delete; |
1034 InstARM32Str &operator=(const InstARM32Str &) = delete; | 1033 InstARM32Str &operator=(const InstARM32Str &) = delete; |
1035 | 1034 |
1036 public: | 1035 public: |
1037 /// Value must be a register. | 1036 /// Value must be a register. |
1038 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, | 1037 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, |
1039 CondARM32::Cond Predicate) { | 1038 CondARM32::Cond Predicate) { |
1040 return new (Func->allocate<InstARM32Str>()) | 1039 return new (Func->allocate<InstARM32Str>()) |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1112 void dump(const Cfg *Func) const override; | 1111 void dump(const Cfg *Func) const override; |
1113 static bool classof(const Inst *Inst) { return isClassof(Inst, Vcvt); } | 1112 static bool classof(const Inst *Inst) { return isClassof(Inst, Vcvt); } |
1114 | 1113 |
1115 private: | 1114 private: |
1116 InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src, VcvtVariant Variant, | 1115 InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src, VcvtVariant Variant, |
1117 CondARM32::Cond Predicate); | 1116 CondARM32::Cond Predicate); |
1118 | 1117 |
1119 const VcvtVariant Variant; | 1118 const VcvtVariant Variant; |
1120 }; | 1119 }; |
1121 | 1120 |
1122 // Declare partial template specializations of emit() methods that | 1121 // Declare partial template specializations of emit() methods that already have |
1123 // already have default implementations. Without this, there is the | 1122 // default implementations. Without this, there is the possibility of ODR |
1124 // possibility of ODR violations and link errors. | 1123 // violations and link errors. |
1125 | 1124 |
1126 template <> void InstARM32Ldr::emit(const Cfg *Func) const; | 1125 template <> void InstARM32Ldr::emit(const Cfg *Func) const; |
1127 template <> void InstARM32Mov::emit(const Cfg *Func) const; | 1126 template <> void InstARM32Mov::emit(const Cfg *Func) const; |
1128 template <> void InstARM32Movw::emit(const Cfg *Func) const; | 1127 template <> void InstARM32Movw::emit(const Cfg *Func) const; |
1129 template <> void InstARM32Movt::emit(const Cfg *Func) const; | 1128 template <> void InstARM32Movt::emit(const Cfg *Func) const; |
1130 template <> void InstARM32Vldr::emit(const Cfg *Func) const; | 1129 template <> void InstARM32Vldr::emit(const Cfg *Func) const; |
1131 template <> void InstARM32Vmov::emit(const Cfg *Func) const; | 1130 template <> void InstARM32Vmov::emit(const Cfg *Func) const; |
1132 | 1131 |
1133 } // end of namespace Ice | 1132 } // end of namespace Ice |
1134 | 1133 |
1135 #endif // SUBZERO_SRC_ICEINSTARM32_H | 1134 #endif // SUBZERO_SRC_ICEINSTARM32_H |
OLD | NEW |