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, 1, Dest) { |
| 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, 1, Dest), Imm(Imm){ |
| 276 addSource(Source); |
| 277 } |
| 278 |
| 279 InstMIPS32Imm16(Cfg *Func, Variable *Dest, uint32_t Imm) |
| 280 : InstMIPS32(Func, K, 0, Dest), Imm(Imm) { |
| 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::La> InstMIPS32La; |
| 291 typedef InstMIPS32Imm16<InstMIPS32::Ori> InstMIPS32Ori; |
| 292 |
| 293 /// Handles (some of) vmov's various formats. |
| 294 class InstMIPS32Mov final : public InstMIPS32 { |
| 295 InstMIPS32Mov() = delete; |
| 296 InstMIPS32Mov(const InstMIPS32Mov &) = delete; |
| 297 InstMIPS32Mov &operator=(const InstMIPS32Mov &) = delete; |
| 298 |
| 299 public: |
| 300 static InstMIPS32Mov *create(Cfg *Func, Variable *Dest, Operand *Src) { |
| 301 return new (Func->allocate<InstMIPS32Mov>()) InstMIPS32Mov(Func, Dest, Src); |
| 302 } |
| 303 bool isRedundantAssign() const override { |
| 304 return !isMultiDest() && !isMultiSource() && |
| 305 checkForRedundantAssign(getDest(), getSrc(0)); |
| 306 } |
| 307 //bool isSimpleAssign() const override { return true; } |
| 308 void emit(const Cfg *Func) const override; |
| 309 void emitIAS(const Cfg *Func) const override; |
| 310 void dump(const Cfg *Func) const override; |
| 311 static bool classof(const Inst *Inst) { return isClassof(Inst, Mov); } |
| 312 |
| 313 bool isMultiDest() const { return DestHi != nullptr; } |
| 314 |
| 315 bool isMultiSource() const { |
| 316 assert(getSrcSize() == 1 || getSrcSize() == 2); |
| 317 return getSrcSize() == 2; |
| 318 } |
| 319 |
| 320 Variable *getDestHi() const { return DestHi; } |
| 321 |
| 322 private: |
| 323 InstMIPS32Mov(Cfg *Func, Variable *Dest, Operand *Src); |
| 324 |
| 325 void emitMultiDestSingleSource(const Cfg *Func) const; |
| 326 void emitSingleDestMultiSource(const Cfg *Func) const; |
| 327 void emitSingleDestSingleSource(const Cfg *Func) const; |
| 328 |
| 329 Variable *DestHi = nullptr; |
| 330 }; |
| 331 |
78 } // end of namespace Ice | 332 } // end of namespace Ice |
79 | 333 |
80 #endif // SUBZERO_SRC_ICEINSTMIPS32_H | 334 #endif // SUBZERO_SRC_ICEINSTMIPS32_H |
OLD | NEW |