OLD | NEW |
---|---|
1 //===- subzero/src/IceInstMIPS32.h - MIPS32 machine instrs --*- C++ -*-=== // | 1 //===- subzero/src/IceInstMIPS32.h - MIPS32 machine instrs --*- 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 InstMIPS32 and OperandMIPS32 classes and their | 11 /// This file declares the InstMIPS32 and OperandMIPS32 classes and their |
12 /// subclasses. This represents the machine instructions and operands used for | 12 /// subclasses. This represents the machine instructions and operands used for |
13 /// MIPS32 code selection. | 13 /// MIPS32 code selection. |
14 /// | 14 /// |
15 //===----------------------------------------------------------------------===// | 15 //===----------------------------------------------------------------------===// |
16 | 16 |
17 #ifndef SUBZERO_SRC_ICEINSTMIPS32_H | 17 #ifndef SUBZERO_SRC_ICEINSTMIPS32_H |
18 #define SUBZERO_SRC_ICEINSTMIPS32_H | 18 #define SUBZERO_SRC_ICEINSTMIPS32_H |
19 | 19 |
20 #include "IceDefs.h" | 20 #include "IceDefs.h" |
21 #include "IceInst.h" | 21 #include "IceInst.h" |
22 #include "IceInstMIPS32.def" | 22 #include "IceInstMIPS32.def" |
23 #include "IceOperand.h" | 23 #include "IceOperand.h" |
24 | 24 |
25 namespace Ice { | 25 namespace Ice { |
26 | 26 |
27 class TargetMIPS32; | 27 class TargetMIPS32; |
28 | 28 |
29 /// OperandMips32 extends the Operand hierarchy. | |
30 // | |
31 class OperandMIPS32 : public Operand { | |
32 OperandMIPS32() = delete; | |
33 OperandMIPS32(const OperandMIPS32 &) = delete; | |
34 OperandMIPS32 &operator=(const OperandMIPS32 &) = delete; | |
35 | |
36 public: | |
37 enum OperandKindMIPS32 { | |
38 k__Start = Operand::kTarget, | |
39 kMem, | |
40 }; | |
41 | |
42 using Operand::dump; | |
43 void dump(const Cfg *, Ostream &Str) const override { | |
44 if (BuildDefs::dump()) | |
45 Str << "<OperandMIPS32>"; | |
46 } | |
47 protected: | |
48 OperandMIPS32(OperandKindMIPS32 Kind, Type Ty) | |
49 : Operand(static_cast<OperandKind>(Kind), Ty) {} | |
50 }; | |
51 | |
52 class OperandMIPS32Mem : public OperandMIPS32 { | |
53 OperandMIPS32Mem() = delete; | |
54 OperandMIPS32Mem(const OperandMIPS32Mem &) = delete; | |
55 OperandMIPS32Mem &operator=(const OperandMIPS32Mem &) = delete; | |
56 | |
57 public: | |
58 /// Memory operand addressing mode. | |
59 /// The enum value also carries the encoding. | |
60 // TODO(jvoung): unify with the assembler. | |
61 enum AddrMode { Offset }; | |
62 | |
63 /// NOTE: The Variable-typed operands have to be registers. | |
64 /// | |
65 /// Reg + Imm. The Immediate actually has a limited number of bits | |
66 /// for encoding, so check canHoldOffset first. It cannot handle | |
67 /// general Constant operands like ConstantRelocatable, since a relocatable | |
68 /// can potentially take up too many bits. | |
69 static OperandMIPS32Mem *create(Cfg *Func, Type Ty, Variable *Base, | |
70 ConstantInteger32 *ImmOffset, | |
71 AddrMode Mode = Offset) { | |
72 return new (Func->allocate<OperandMIPS32Mem>()) | |
73 OperandMIPS32Mem(Func, Ty, Base, ImmOffset, Mode); | |
74 } | |
75 | |
76 Variable *getBase() const { return Base; } | |
77 ConstantInteger32 *getOffset() const { return ImmOffset; } | |
78 AddrMode getAddrMode() const { return Mode; } | |
79 | |
80 void emit(const Cfg *Func) const override; | |
81 using OperandMIPS32::dump; | |
82 | |
83 static bool classof(const Operand *Operand) { | |
84 return Operand->getKind() == static_cast<OperandKind>(kMem); | |
85 } | |
86 | |
87 /// Return true if a load/store instruction for an element of type Ty | |
88 /// can encode the Offset directly in the immediate field of the 32-bit | |
89 /// MIPS instruction. For some types, if the load is Sign extending, then | |
90 /// the range is reduced. | |
91 static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset); | |
92 | |
93 void dump(const Cfg *Func, Ostream &Str) const override { | |
94 (void)Func; | |
95 (void)Str; | |
96 } | |
97 | |
98 private: | |
99 OperandMIPS32Mem(Cfg *Func, Type Ty, Variable *Base, | |
100 ConstantInteger32 *ImmOffset, AddrMode Mode); | |
101 | |
102 Variable *Base; | |
103 ConstantInteger32 *ImmOffset; | |
104 AddrMode Mode; | |
105 }; | |
106 | |
29 /// Base class for Mips instructions. | 107 /// Base class for Mips instructions. |
30 class InstMIPS32 : public InstTarget { | 108 class InstMIPS32 : public InstTarget { |
31 InstMIPS32() = delete; | 109 InstMIPS32() = delete; |
32 InstMIPS32(const InstMIPS32 &) = delete; | 110 InstMIPS32(const InstMIPS32 &) = delete; |
33 InstMIPS32 &operator=(const InstMIPS32 &) = delete; | 111 InstMIPS32 &operator=(const InstMIPS32 &) = delete; |
34 | 112 |
35 public: | 113 public: |
36 enum InstKindMIPS32 { k__Start = Inst::Target, Ret }; | 114 enum InstKindMIPS32 { |
115 k__Start = Inst::Target, | |
116 Addiu, | |
117 La, | |
118 Lui, | |
119 Mov, // actually a pseudo op for addi rd, rs, 0 | |
120 Ori, | |
121 Ret | |
122 }; | |
37 | 123 |
38 static const char *getWidthString(Type Ty); | 124 static const char *getWidthString(Type Ty); |
39 | 125 |
40 void dump(const Cfg *Func) const override; | 126 void dump(const Cfg *Func) const override; |
41 | 127 |
128 void dumpOpcode(Ostream &Str, const char *Opcode, Type Ty) const { | |
129 Str << Opcode << "." << Ty; | |
130 } | |
131 | |
132 /// Shared emit routines for common forms of instructions. | |
133 static void emitUnaryopGPR(const char *Opcode, const InstMIPS32 *Inst, | |
134 const Cfg *Func); | |
135 | |
42 protected: | 136 protected: |
43 InstMIPS32(Cfg *Func, InstKindMIPS32 Kind, SizeT Maxsrcs, Variable *Dest) | 137 InstMIPS32(Cfg *Func, InstKindMIPS32 Kind, SizeT Maxsrcs, Variable *Dest) |
44 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} | 138 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} |
45 static bool isClassof(const Inst *Inst, InstKindMIPS32 MyKind) { | 139 static bool isClassof(const Inst *Inst, InstKindMIPS32 MyKind) { |
46 return Inst->getKind() == static_cast<InstKind>(MyKind); | 140 return Inst->getKind() == static_cast<InstKind>(MyKind); |
47 } | 141 } |
48 }; | 142 }; |
49 | 143 |
50 /// Ret pseudo-instruction. This is actually a "jr" instruction with an "ra" | 144 /// Ret pseudo-instruction. This is actually a "jr" instruction with an "ra" |
51 /// register operand, but epilogue lowering will search for a Ret instead of a | 145 /// register operand, but epilogue lowering will search for a Ret instead of a |
(...skipping 16 matching lines...) Expand all Loading... | |
68 } | 162 } |
69 void emit(const Cfg *Func) const override; | 163 void emit(const Cfg *Func) const override; |
70 void emitIAS(const Cfg *Func) const override; | 164 void emitIAS(const Cfg *Func) const override; |
71 void dump(const Cfg *Func) const override; | 165 void dump(const Cfg *Func) const override; |
72 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } | 166 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } |
73 | 167 |
74 private: | 168 private: |
75 InstMIPS32Ret(Cfg *Func, Variable *RA, Variable *Source); | 169 InstMIPS32Ret(Cfg *Func, Variable *RA, Variable *Source); |
76 }; | 170 }; |
77 | 171 |
172 /// Instructions of the form x := op(y). | |
173 template <InstMIPS32::InstKindMIPS32 K> | |
174 class InstMIPS32UnaryopGPR : public InstMIPS32 { | |
175 InstMIPS32UnaryopGPR() = delete; | |
176 InstMIPS32UnaryopGPR(const InstMIPS32UnaryopGPR &) = delete; | |
177 InstMIPS32UnaryopGPR &operator=(const InstMIPS32UnaryopGPR &) = delete; | |
178 | |
179 public: | |
180 static InstMIPS32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src) { | |
181 return new (Func->allocate<InstMIPS32UnaryopGPR>()) | |
182 InstMIPS32UnaryopGPR(Func, Dest, Src); | |
183 } | |
184 void emit(const Cfg *Func) const override { | |
185 if (!BuildDefs::dump()) | |
186 return; | |
187 emitUnaryopGPR(Opcode, this, Func); | |
188 } | |
189 void emitIAS(const Cfg *Func) const override { | |
190 (void)Func; | |
191 llvm_unreachable("Not yet implemented"); | |
192 } | |
193 void dump(const Cfg *Func) const override { | |
194 if (!BuildDefs::dump()) | |
195 return; | |
196 Ostream &Str = Func->getContext()->getStrDump(); | |
197 dumpOpcode(Str, Opcode, getDest()->getType()); | |
198 Str << " "; | |
199 dumpDest(Func); | |
200 Str << ", "; | |
201 dumpSources(Func); | |
202 } | |
203 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
204 | |
205 protected: | |
206 InstMIPS32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src) | |
207 : InstMIPS32(Func, K, 2, Dest) { | |
Jim Stichnoth
2015/10/20 04:41:00
I think the "2" should be a "1".
This argument te
rkotlerimgtec
2015/10/21 00:30:54
Done.
| |
208 addSource(Src); | |
209 } | |
210 | |
211 private: | |
212 static const char *Opcode; | |
213 }; | |
214 | |
215 template <InstMIPS32::InstKindMIPS32 K, bool Signed = false> | |
216 class InstMIPS32Imm16 : public InstMIPS32 { | |
217 InstMIPS32Imm16() = delete; | |
218 InstMIPS32Imm16(const InstMIPS32Imm16 &) = delete; | |
219 InstMIPS32Imm16 &operator=(const InstMIPS32Imm16 &) = delete; | |
220 | |
221 public: | |
222 static InstMIPS32Imm16 *create(Cfg *Func, Variable *Dest, Operand *Source, | |
223 uint32_t Imm) { | |
224 return new (Func->allocate<InstMIPS32Imm16>()) | |
225 InstMIPS32Imm16(Func, Dest, Source, Imm); | |
226 } | |
227 | |
228 static InstMIPS32Imm16 *create(Cfg *Func, Variable *Dest, uint32_t Imm) { | |
229 return new (Func->allocate<InstMIPS32Imm16>()) | |
230 InstMIPS32Imm16(Func, Dest, Imm); | |
231 } | |
232 | |
233 void emit(const Cfg *Func) const override { | |
234 if (!BuildDefs::dump()) | |
235 return; | |
236 Ostream &Str = Func->getContext()->getStrEmit(); | |
237 Str << "\t" << Opcode << "\t"; | |
238 getDest()->emit(Func); | |
239 if (getSrcSize() > 0) { | |
240 Str << ", "; | |
241 getSrc(0)->emit(Func); | |
242 } | |
243 Str << ", "; | |
244 if (Signed) | |
245 Str << (int32_t)Imm; | |
246 else | |
247 Str << Imm; | |
248 Str << "\n"; | |
249 } | |
250 | |
251 void emitIAS(const Cfg *Func) const override { | |
252 (void)Func; | |
253 llvm_unreachable("Not yet implemented"); | |
254 } | |
255 void dump(const Cfg *Func) const override { | |
256 if (!BuildDefs::dump()) | |
257 return; | |
258 Ostream &Str = Func->getContext()->getStrDump(); | |
259 Str << " "; | |
260 Str << "\t" << Opcode << "\t"; | |
261 dumpDest(Func); | |
262 Str << ", "; | |
263 dumpSources(Func); | |
264 if (Signed) | |
265 Str << (int32_t)Imm; | |
266 else | |
267 Str << Imm; | |
268 Str << "\n"; | |
269 } | |
270 | |
271 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
272 | |
273 private: | |
274 InstMIPS32Imm16(Cfg *Func, Variable *Dest, Operand *Source, uint32_t Imm) | |
275 : InstMIPS32(Func, K, 2, Dest), Imm(Imm){ | |
Jim Stichnoth
2015/10/20 04:41:00
As above, the "2" should be a "1".
rkotlerimgtec
2015/10/21 00:30:54
Done.
| |
276 addSource(Source); | |
277 } | |
278 | |
279 InstMIPS32Imm16(Cfg *Func, Variable *Dest, uint32_t Imm) | |
280 : InstMIPS32(Func, K, 1, Dest), Imm(Imm) { | |
Jim Stichnoth
2015/10/20 04:41:00
Similarly, the "1" would be "0".
rkotlerimgtec
2015/10/21 00:30:54
Done.
| |
281 } | |
282 | |
283 static const char *Opcode; | |
284 | |
285 const uint32_t Imm; | |
286 }; | |
287 | |
288 typedef InstMIPS32Imm16<InstMIPS32::Addiu, true> InstMIPS32Addiu; | |
289 typedef InstMIPS32Imm16<InstMIPS32::Lui> InstMIPS32Lui; | |
290 typedef InstMIPS32UnaryopGPR<InstMIPS32::Mov> InstMIPS32MovBase; | |
291 typedef InstMIPS32UnaryopGPR<InstMIPS32::La> InstMIPS32La; | |
292 typedef InstMIPS32Imm16<InstMIPS32::Ori> InstMIPS32Ori; | |
293 | |
294 /// Handles (some of) vmov's various formats. | |
295 class InstMIPS32Mov final : public InstMIPS32 { | |
296 InstMIPS32Mov() = delete; | |
297 InstMIPS32Mov(const InstMIPS32Mov &) = delete; | |
298 InstMIPS32Mov &operator=(const InstMIPS32Mov &) = delete; | |
299 | |
300 public: | |
301 static InstMIPS32Mov *create(Cfg *Func, Variable *Dest, Operand *Src) { | |
302 return new (Func->allocate<InstMIPS32Mov>()) InstMIPS32Mov(Func, Dest, Src); | |
303 } | |
304 bool isRedundantAssign() const override { | |
305 return !isMultiDest() && !isMultiSource() && | |
306 checkForRedundantAssign(getDest(), getSrc(0)); | |
307 } | |
308 //bool isSimpleAssign() const override { return true; } | |
309 void emit(const Cfg *Func) const override; | |
310 void emitIAS(const Cfg *Func) const override; | |
311 void dump(const Cfg *Func) const override; | |
312 static bool classof(const Inst *Inst) { return isClassof(Inst, Mov); } | |
313 | |
314 bool isMultiDest() const { return DestHi != nullptr; } | |
315 | |
316 bool isMultiSource() const { | |
317 assert(getSrcSize() == 1 || getSrcSize() == 2); | |
318 return getSrcSize() == 2; | |
319 } | |
320 | |
321 Variable *getDestHi() const { return DestHi; } | |
322 | |
323 private: | |
324 InstMIPS32Mov(Cfg *Func, Variable *Dest, Operand *Src); | |
325 | |
326 void emitMultiDestSingleSource(const Cfg *Func) const; | |
327 void emitSingleDestMultiSource(const Cfg *Func) const; | |
328 void emitSingleDestSingleSource(const Cfg *Func) const; | |
329 | |
330 Variable *DestHi = nullptr; | |
331 }; | |
332 | |
78 } // end of namespace Ice | 333 } // end of namespace Ice |
79 | 334 |
80 #endif // SUBZERO_SRC_ICEINSTMIPS32_H | 335 #endif // SUBZERO_SRC_ICEINSTMIPS32_H |
OLD | NEW |