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 InstARM32Vldr = InstARM32Movlike<InstARM32::Vldr>; | 787 using InstARM32Vldr = InstARM32Movlike<InstARM32::Vldr>; |
789 /// MovT leaves the bottom bits alone so dest is also a source. | 788 /// MovT leaves the bottom bits alone so dest is also a source. This helps |
790 /// This helps indicate that a previous MovW setting dest is not dead code. | 789 /// indicate that a previous MovW setting dest is not dead code. |
791 using InstARM32Movt = InstARM32TwoAddrGPR<InstARM32::Movt>; | 790 using InstARM32Movt = InstARM32TwoAddrGPR<InstARM32::Movt>; |
792 using InstARM32Movw = InstARM32UnaryopGPR<InstARM32::Movw, false>; | 791 using InstARM32Movw = InstARM32UnaryopGPR<InstARM32::Movw, false>; |
793 using InstARM32Clz = InstARM32UnaryopGPR<InstARM32::Clz, false>; | 792 using InstARM32Clz = InstARM32UnaryopGPR<InstARM32::Clz, false>; |
794 using InstARM32Mvn = InstARM32UnaryopGPR<InstARM32::Mvn, false>; | 793 using InstARM32Mvn = InstARM32UnaryopGPR<InstARM32::Mvn, false>; |
795 using InstARM32Rbit = InstARM32UnaryopGPR<InstARM32::Rbit, false>; | 794 using InstARM32Rbit = InstARM32UnaryopGPR<InstARM32::Rbit, false>; |
796 using InstARM32Rev = InstARM32UnaryopGPR<InstARM32::Rev, false>; | 795 using InstARM32Rev = InstARM32UnaryopGPR<InstARM32::Rev, false>; |
797 // Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation | 796 // Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation operand |
798 // operand as well (rotate source by 8, 16, 24 bits prior to extending), | 797 // as well (rotate source by 8, 16, 24 bits prior to extending), but we aren't |
799 // but we aren't using that for now, so just model as a Unaryop. | 798 // using that for now, so just model as a Unaryop. |
800 using InstARM32Sxt = InstARM32UnaryopGPR<InstARM32::Sxt, true>; | 799 using InstARM32Sxt = InstARM32UnaryopGPR<InstARM32::Sxt, true>; |
801 using InstARM32Uxt = InstARM32UnaryopGPR<InstARM32::Uxt, true>; | 800 using InstARM32Uxt = InstARM32UnaryopGPR<InstARM32::Uxt, true>; |
802 using InstARM32Vsqrt = InstARM32UnaryopFP<InstARM32::Vsqrt>; | 801 using InstARM32Vsqrt = InstARM32UnaryopFP<InstARM32::Vsqrt>; |
803 using InstARM32Mla = InstARM32FourAddrGPR<InstARM32::Mla>; | 802 using InstARM32Mla = InstARM32FourAddrGPR<InstARM32::Mla>; |
804 using InstARM32Mls = InstARM32FourAddrGPR<InstARM32::Mls>; | 803 using InstARM32Mls = InstARM32FourAddrGPR<InstARM32::Mls>; |
805 using InstARM32Cmp = InstARM32CmpLike<InstARM32::Cmp>; | 804 using InstARM32Cmp = InstARM32CmpLike<InstARM32::Cmp>; |
806 using InstARM32Tst = InstARM32CmpLike<InstARM32::Tst>; | 805 using InstARM32Tst = InstARM32CmpLike<InstARM32::Tst>; |
807 | 806 |
808 // InstARM32Label represents an intra-block label that is the target | 807 // InstARM32Label represents an intra-block label that is the target of an |
809 // of an intra-block branch. The offset between the label and the | 808 // intra-block branch. The offset between the label and the branch must be fit |
810 // branch must be fit in the instruction immediate (considered "near"). | 809 // in the instruction immediate (considered "near"). |
811 class InstARM32Label : public InstARM32 { | 810 class InstARM32Label : public InstARM32 { |
812 InstARM32Label() = delete; | 811 InstARM32Label() = delete; |
813 InstARM32Label(const InstARM32Label &) = delete; | 812 InstARM32Label(const InstARM32Label &) = delete; |
814 InstARM32Label &operator=(const InstARM32Label &) = delete; | 813 InstARM32Label &operator=(const InstARM32Label &) = delete; |
815 | 814 |
816 public: | 815 public: |
817 static InstARM32Label *create(Cfg *Func, TargetARM32 *Target) { | 816 static InstARM32Label *create(Cfg *Func, TargetARM32 *Target) { |
818 return new (Func->allocate<InstARM32Label>()) InstARM32Label(Func, Target); | 817 return new (Func->allocate<InstARM32Label>()) InstARM32Label(Func, Target); |
819 } | 818 } |
820 uint32_t getEmitInstCount() const override { return 0; } | 819 uint32_t getEmitInstCount() const override { return 0; } |
(...skipping 24 matching lines...) Expand all Loading... |
845 return new (Func->allocate<InstARM32Br>()) | 844 return new (Func->allocate<InstARM32Br>()) |
846 InstARM32Br(Func, TargetTrue, TargetFalse, NoLabel, Predicate); | 845 InstARM32Br(Func, TargetTrue, TargetFalse, NoLabel, Predicate); |
847 } | 846 } |
848 /// Create an unconditional branch to a node. | 847 /// Create an unconditional branch to a node. |
849 static InstARM32Br *create(Cfg *Func, CfgNode *Target) { | 848 static InstARM32Br *create(Cfg *Func, CfgNode *Target) { |
850 constexpr CfgNode *NoCondTarget = nullptr; | 849 constexpr CfgNode *NoCondTarget = nullptr; |
851 constexpr InstARM32Label *NoLabel = nullptr; | 850 constexpr InstARM32Label *NoLabel = nullptr; |
852 return new (Func->allocate<InstARM32Br>()) | 851 return new (Func->allocate<InstARM32Br>()) |
853 InstARM32Br(Func, NoCondTarget, Target, NoLabel, CondARM32::AL); | 852 InstARM32Br(Func, NoCondTarget, Target, NoLabel, CondARM32::AL); |
854 } | 853 } |
855 /// Create a non-terminator conditional branch to a node, with a | 854 /// Create a non-terminator conditional branch to a node, with a fallthrough |
856 /// fallthrough to the next instruction in the current node. This is | 855 /// to the next instruction in the current node. This is used for switch |
857 /// used for switch lowering. | 856 /// lowering. |
858 static InstARM32Br *create(Cfg *Func, CfgNode *Target, | 857 static InstARM32Br *create(Cfg *Func, CfgNode *Target, |
859 CondARM32::Cond Predicate) { | 858 CondARM32::Cond Predicate) { |
860 assert(Predicate != CondARM32::AL); | 859 assert(Predicate != CondARM32::AL); |
861 constexpr CfgNode *NoUncondTarget = nullptr; | 860 constexpr CfgNode *NoUncondTarget = nullptr; |
862 constexpr InstARM32Label *NoLabel = nullptr; | 861 constexpr InstARM32Label *NoLabel = nullptr; |
863 return new (Func->allocate<InstARM32Br>()) | 862 return new (Func->allocate<InstARM32Br>()) |
864 InstARM32Br(Func, Target, NoUncondTarget, NoLabel, Predicate); | 863 InstARM32Br(Func, Target, NoUncondTarget, NoLabel, Predicate); |
865 } | 864 } |
866 // Create a conditional intra-block branch (or unconditional, if | 865 // Create a conditional intra-block branch (or unconditional, if |
867 // Condition==AL) to a label in the current block. | 866 // Condition==AL) to a label in the current block. |
(...skipping 28 matching lines...) Expand all Loading... |
896 | 895 |
897 private: | 896 private: |
898 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, | 897 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, |
899 const InstARM32Label *Label, CondARM32::Cond Predicate); | 898 const InstARM32Label *Label, CondARM32::Cond Predicate); |
900 | 899 |
901 const CfgNode *TargetTrue; | 900 const CfgNode *TargetTrue; |
902 const CfgNode *TargetFalse; | 901 const CfgNode *TargetFalse; |
903 const InstARM32Label *Label; // Intra-block branch target | 902 const InstARM32Label *Label; // Intra-block branch target |
904 }; | 903 }; |
905 | 904 |
906 /// AdjustStack instruction - subtracts SP by the given amount and | 905 /// AdjustStack instruction - subtracts SP by the given amount and updates the |
907 /// updates the stack offset during code emission. | 906 /// stack offset during code emission. |
908 class InstARM32AdjustStack : public InstARM32 { | 907 class InstARM32AdjustStack : public InstARM32 { |
909 InstARM32AdjustStack() = delete; | 908 InstARM32AdjustStack() = delete; |
910 InstARM32AdjustStack(const InstARM32AdjustStack &) = delete; | 909 InstARM32AdjustStack(const InstARM32AdjustStack &) = delete; |
911 InstARM32AdjustStack &operator=(const InstARM32AdjustStack &) = delete; | 910 InstARM32AdjustStack &operator=(const InstARM32AdjustStack &) = delete; |
912 | 911 |
913 public: | 912 public: |
914 /// Note: We need both Amount and SrcAmount. If Amount is too large then | 913 /// Note: We need both Amount and SrcAmount. If Amount is too large then it |
915 /// it needs to be copied to a register (so SrcAmount could be a register). | 914 /// needs to be copied to a register (so SrcAmount could be a register). |
916 /// However, we also need the numeric Amount for bookkeeping, and it's | 915 /// However, we also need the numeric Amount for bookkeeping, and it's hard to |
917 /// hard to pull that from the generic SrcAmount operand. | 916 /// pull that from the generic SrcAmount operand. |
918 static InstARM32AdjustStack *create(Cfg *Func, Variable *SP, SizeT Amount, | 917 static InstARM32AdjustStack *create(Cfg *Func, Variable *SP, SizeT Amount, |
919 Operand *SrcAmount) { | 918 Operand *SrcAmount) { |
920 return new (Func->allocate<InstARM32AdjustStack>()) | 919 return new (Func->allocate<InstARM32AdjustStack>()) |
921 InstARM32AdjustStack(Func, SP, Amount, SrcAmount); | 920 InstARM32AdjustStack(Func, SP, Amount, SrcAmount); |
922 } | 921 } |
923 void emit(const Cfg *Func) const override; | 922 void emit(const Cfg *Func) const override; |
924 void emitIAS(const Cfg *Func) const override; | 923 void emitIAS(const Cfg *Func) const override; |
925 void dump(const Cfg *Func) const override; | 924 void dump(const Cfg *Func) const override; |
926 static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); } | 925 static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); } |
927 SizeT getAmount() const { return Amount; } | 926 SizeT getAmount() const { return Amount; } |
928 | 927 |
929 private: | 928 private: |
930 InstARM32AdjustStack(Cfg *Func, Variable *SP, SizeT Amount, | 929 InstARM32AdjustStack(Cfg *Func, Variable *SP, SizeT Amount, |
931 Operand *SrcAmount); | 930 Operand *SrcAmount); |
932 const SizeT Amount; | 931 const SizeT Amount; |
933 }; | 932 }; |
934 | 933 |
935 /// Call instruction (bl/blx). Arguments should have already been pushed. | 934 /// Call instruction (bl/blx). Arguments should have already been pushed. |
936 /// Technically bl and the register form of blx can be predicated, but we'll | 935 /// Technically bl and the register form of blx can be predicated, but we'll |
937 /// leave that out until needed. | 936 /// leave that out until needed. |
938 class InstARM32Call : public InstARM32 { | 937 class InstARM32Call : public InstARM32 { |
939 InstARM32Call() = delete; | 938 InstARM32Call() = delete; |
940 InstARM32Call(const InstARM32Call &) = delete; | 939 InstARM32Call(const InstARM32Call &) = delete; |
941 InstARM32Call &operator=(const InstARM32Call &) = delete; | 940 InstARM32Call &operator=(const InstARM32Call &) = delete; |
942 | 941 |
943 public: | 942 public: |
944 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { | 943 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { |
945 return new (Func->allocate<InstARM32Call>()) | 944 return new (Func->allocate<InstARM32Call>()) |
(...skipping 24 matching lines...) Expand all Loading... |
970 void emitIAS(const Cfg *Func) const override; | 969 void emitIAS(const Cfg *Func) const override; |
971 void dump(const Cfg *Func) const override; | 970 void dump(const Cfg *Func) const override; |
972 static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } | 971 static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } |
973 | 972 |
974 private: | 973 private: |
975 InstARM32Pop(Cfg *Func, const VarList &Dests); | 974 InstARM32Pop(Cfg *Func, const VarList &Dests); |
976 | 975 |
977 VarList Dests; | 976 VarList Dests; |
978 }; | 977 }; |
979 | 978 |
980 /// Push a list of GPRs. Technically this can be predicated, but we don't | 979 /// Push a list of GPRs. Technically this can be predicated, but we don't need |
981 /// need that functionality. | 980 /// that functionality. |
982 class InstARM32Push : public InstARM32 { | 981 class InstARM32Push : public InstARM32 { |
983 InstARM32Push() = delete; | 982 InstARM32Push() = delete; |
984 InstARM32Push(const InstARM32Push &) = delete; | 983 InstARM32Push(const InstARM32Push &) = delete; |
985 InstARM32Push &operator=(const InstARM32Push &) = delete; | 984 InstARM32Push &operator=(const InstARM32Push &) = delete; |
986 | 985 |
987 public: | 986 public: |
988 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) { | 987 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) { |
989 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); | 988 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); |
990 } | 989 } |
991 void emit(const Cfg *Func) const override; | 990 void emit(const Cfg *Func) const override; |
992 void emitIAS(const Cfg *Func) const override; | 991 void emitIAS(const Cfg *Func) const override; |
993 void dump(const Cfg *Func) const override; | 992 void dump(const Cfg *Func) const override; |
994 static bool classof(const Inst *Inst) { return isClassof(Inst, Push); } | 993 static bool classof(const Inst *Inst) { return isClassof(Inst, Push); } |
995 | 994 |
996 private: | 995 private: |
997 InstARM32Push(Cfg *Func, const VarList &Srcs); | 996 InstARM32Push(Cfg *Func, const VarList &Srcs); |
998 }; | 997 }; |
999 | 998 |
1000 /// Ret pseudo-instruction. This is actually a "bx" instruction with | 999 /// Ret pseudo-instruction. This is actually a "bx" instruction with an "lr" |
1001 /// an "lr" register operand, but epilogue lowering will search for a Ret | 1000 /// register operand, but epilogue lowering will search for a Ret instead of a |
1002 /// instead of a generic "bx". This instruction also takes a Source | 1001 /// generic "bx". This instruction also takes a Source operand (for non-void |
1003 /// operand (for non-void returning functions) for liveness analysis, though | 1002 /// returning functions) for liveness analysis, though a FakeUse before the ret |
1004 /// a FakeUse before the ret would do just as well. | 1003 /// would do just as well. |
1005 /// | 1004 /// |
1006 /// NOTE: Even though "bx" can be predicated, for now leave out the predication | 1005 /// NOTE: Even though "bx" can be predicated, for now leave out the predication |
1007 /// since it's not yet known to be useful for Ret. That may complicate finding | 1006 /// since it's not yet known to be useful for Ret. That may complicate finding |
1008 /// the terminator instruction if it's not guaranteed to be executed. | 1007 /// the terminator instruction if it's not guaranteed to be executed. |
1009 class InstARM32Ret : public InstARM32 { | 1008 class InstARM32Ret : public InstARM32 { |
1010 InstARM32Ret() = delete; | 1009 InstARM32Ret() = delete; |
1011 InstARM32Ret(const InstARM32Ret &) = delete; | 1010 InstARM32Ret(const InstARM32Ret &) = delete; |
1012 InstARM32Ret &operator=(const InstARM32Ret &) = delete; | 1011 InstARM32Ret &operator=(const InstARM32Ret &) = delete; |
1013 | 1012 |
1014 public: | 1013 public: |
1015 static InstARM32Ret *create(Cfg *Func, Variable *LR, | 1014 static InstARM32Ret *create(Cfg *Func, Variable *LR, |
1016 Variable *Source = nullptr) { | 1015 Variable *Source = nullptr) { |
1017 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); | 1016 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); |
1018 } | 1017 } |
1019 void emit(const Cfg *Func) const override; | 1018 void emit(const Cfg *Func) const override; |
1020 void emitIAS(const Cfg *Func) const override; | 1019 void emitIAS(const Cfg *Func) const override; |
1021 void dump(const Cfg *Func) const override; | 1020 void dump(const Cfg *Func) const override; |
1022 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } | 1021 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } |
1023 | 1022 |
1024 private: | 1023 private: |
1025 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); | 1024 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); |
1026 }; | 1025 }; |
1027 | 1026 |
1028 /// Store instruction. It's important for liveness that there is no Dest | 1027 /// Store instruction. It's important for liveness that there is no Dest operand |
1029 /// operand (OperandARM32Mem instead of Dest Variable). | 1028 /// (OperandARM32Mem instead of Dest Variable). |
1030 class InstARM32Str : public InstARM32Pred { | 1029 class InstARM32Str : public InstARM32Pred { |
1031 InstARM32Str() = delete; | 1030 InstARM32Str() = delete; |
1032 InstARM32Str(const InstARM32Str &) = delete; | 1031 InstARM32Str(const InstARM32Str &) = delete; |
1033 InstARM32Str &operator=(const InstARM32Str &) = delete; | 1032 InstARM32Str &operator=(const InstARM32Str &) = delete; |
1034 | 1033 |
1035 public: | 1034 public: |
1036 /// Value must be a register. | 1035 /// Value must be a register. |
1037 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, | 1036 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, |
1038 CondARM32::Cond Predicate) { | 1037 CondARM32::Cond Predicate) { |
1039 return new (Func->allocate<InstARM32Str>()) | 1038 return new (Func->allocate<InstARM32Str>()) |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1198 return getSrcSize() > 1; | 1197 return getSrcSize() > 1; |
1199 } | 1198 } |
1200 | 1199 |
1201 void emitMultiDestSingleSource(const Cfg *Func) const; | 1200 void emitMultiDestSingleSource(const Cfg *Func) const; |
1202 void emitSingleDestMultiSource(const Cfg *Func) const; | 1201 void emitSingleDestMultiSource(const Cfg *Func) const; |
1203 void emitSingleDestSingleSource(const Cfg *Func) const; | 1202 void emitSingleDestSingleSource(const Cfg *Func) const; |
1204 | 1203 |
1205 Variable *Dest1 = nullptr; | 1204 Variable *Dest1 = nullptr; |
1206 }; | 1205 }; |
1207 | 1206 |
1208 // Declare partial template specializations of emit() methods that | 1207 // Declare partial template specializations of emit() methods that already have |
1209 // already have default implementations. Without this, there is the | 1208 // default implementations. Without this, there is the possibility of ODR |
1210 // possibility of ODR violations and link errors. | 1209 // violations and link errors. |
1211 | 1210 |
1212 template <> void InstARM32Ldr::emit(const Cfg *Func) const; | 1211 template <> void InstARM32Ldr::emit(const Cfg *Func) const; |
1213 template <> void InstARM32Mov::emit(const Cfg *Func) const; | 1212 template <> void InstARM32Mov::emit(const Cfg *Func) const; |
1214 template <> void InstARM32Movw::emit(const Cfg *Func) const; | 1213 template <> void InstARM32Movw::emit(const Cfg *Func) const; |
1215 template <> void InstARM32Movt::emit(const Cfg *Func) const; | 1214 template <> void InstARM32Movt::emit(const Cfg *Func) const; |
1216 template <> void InstARM32Vldr::emit(const Cfg *Func) const; | 1215 template <> void InstARM32Vldr::emit(const Cfg *Func) const; |
1217 | 1216 |
1218 } // end of namespace Ice | 1217 } // end of namespace Ice |
1219 | 1218 |
1220 #endif // SUBZERO_SRC_ICEINSTARM32_H | 1219 #endif // SUBZERO_SRC_ICEINSTARM32_H |
OLD | NEW |