//===- subzero/src/IceInstMIPS32.h - MIPS32 machine instrs --*- C++ -*-----===// // // The Subzero Code Generator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief Declares the InstMIPS32 and OperandMIPS32 classes and their /// subclasses. /// /// This represents the machine instructions and operands used for MIPS32 code /// selection. /// //===----------------------------------------------------------------------===// #ifndef SUBZERO_SRC_ICEINSTMIPS32_H #define SUBZERO_SRC_ICEINSTMIPS32_H #include "IceConditionCodesMIPS32.h" #include "IceDefs.h" #include "IceInst.h" #include "IceInstMIPS32.def" #include "IceOperand.h" namespace Ice { namespace MIPS32 { enum RelocOp { RO_No, RO_Hi, RO_Lo, RO_Jal }; enum Int64Part { Int64_Hi, Int64_Lo }; inline void emitRelocOp(Ostream &Str, RelocOp Reloc) { switch (Reloc) { default: break; case RO_Hi: Str << "%hi"; break; case RO_Lo: Str << "%lo"; break; } } class TargetMIPS32; /// OperandMips32 extends the Operand hierarchy. // class OperandMIPS32 : public Operand { OperandMIPS32() = delete; OperandMIPS32(const OperandMIPS32 &) = delete; OperandMIPS32 &operator=(const OperandMIPS32 &) = delete; public: enum OperandKindMIPS32 { k__Start = Operand::kTarget, kFCC, kMem, }; using Operand::dump; void dump(const Cfg *, Ostream &Str) const override { if (BuildDefs::dump()) Str << ""; } protected: OperandMIPS32(OperandKindMIPS32 Kind, Type Ty) : Operand(static_cast(Kind), Ty) {} }; class OperandMIPS32FCC : public OperandMIPS32 { OperandMIPS32FCC() = delete; OperandMIPS32FCC(const OperandMIPS32FCC &) = delete; OperandMIPS32FCC &operator=(const OperandMIPS32FCC &) = delete; public: using FCC = enum { FCC0 = 0, FCC1, FCC2, FCC3, FCC4, FCC5, FCC6, FCC7 }; static OperandMIPS32FCC *create(Cfg *Func, OperandMIPS32FCC::FCC FCC) { return new (Func->allocate()) OperandMIPS32FCC(FCC); } OperandMIPS32FCC::FCC getFCC() const { return FpCondCode; } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); Str << "$fcc" << static_cast(FpCondCode); } static bool classof(const Operand *Operand) { return Operand->getKind() == static_cast(kFCC); } void dump(const Cfg *Func, Ostream &Str) const override { if (!BuildDefs::dump()) return; (void)Func; Str << "$fcc" << static_cast(FpCondCode); } private: OperandMIPS32FCC(OperandMIPS32FCC::FCC CC) : OperandMIPS32(kFCC, IceType_i32), FpCondCode(CC){}; const OperandMIPS32FCC::FCC FpCondCode; }; class OperandMIPS32Mem : public OperandMIPS32 { OperandMIPS32Mem() = delete; OperandMIPS32Mem(const OperandMIPS32Mem &) = delete; OperandMIPS32Mem &operator=(const OperandMIPS32Mem &) = delete; public: /// Memory operand addressing mode. /// The enum value also carries the encoding. // TODO(jvoung): unify with the assembler. enum AddrMode { Offset }; /// NOTE: The Variable-typed operands have to be registers. /// /// Reg + Imm. The Immediate actually has a limited number of bits /// for encoding, so check canHoldOffset first. It cannot handle /// general Constant operands like ConstantRelocatable, since a relocatable /// can potentially take up too many bits. static OperandMIPS32Mem *create(Cfg *Func, Type Ty, Variable *Base, Operand *ImmOffset, AddrMode Mode = Offset) { return new (Func->allocate()) OperandMIPS32Mem(Func, Ty, Base, ImmOffset, Mode); } Variable *getBase() const { return Base; } Operand *getOffset() const { return ImmOffset; } AddrMode getAddrMode() const { return Mode; } void emit(const Cfg *Func) const override; using OperandMIPS32::dump; static bool classof(const Operand *Operand) { return Operand->getKind() == static_cast(kMem); } /// Return true if a load/store instruction for an element of type Ty /// can encode the Offset directly in the immediate field of the 32-bit /// MIPS instruction. For some types, if the load is Sign extending, then /// the range is reduced. static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset); void dump(const Cfg *Func, Ostream &Str) const override { if (!BuildDefs::dump()) return; Str << "["; if (Func) getBase()->dump(Func); else getBase()->dump(Str); Str << ", "; getOffset()->dump(Func, Str); Str << "] AddrMode=="; if (getAddrMode() == Offset) { Str << "Offset"; } else { Str << "Unknown"; } } private: OperandMIPS32Mem(Cfg *Func, Type Ty, Variable *Base, Operand *ImmOffset, AddrMode Mode); Variable *Base; Operand *const ImmOffset; const AddrMode Mode; }; /// Base class for Mips instructions. class InstMIPS32 : public InstTarget { InstMIPS32() = delete; InstMIPS32(const InstMIPS32 &) = delete; InstMIPS32 &operator=(const InstMIPS32 &) = delete; public: enum InstKindMIPS32 { k__Start = Inst::Target, Abs_d, Abs_s, Add, Add_d, Add_s, Addi, Addiu, Addu, And, Andi, Br, C_eq_d, C_eq_s, C_ole_d, C_ole_s, C_olt_d, C_olt_s, C_ueq_d, C_ueq_s, C_ule_d, C_ule_s, C_ult_d, C_ult_s, C_un_d, C_un_s, Call, Clz, Cvt_d_l, Cvt_d_s, Cvt_d_w, Cvt_s_d, Cvt_s_l, Cvt_s_w, Div, Div_d, Div_s, Divu, La, Label, Ldc1, Ll, Lui, Lw, Lwc1, Mfc1, Mfhi, Mflo, Mov, // actually a pseudo op for addi rd, rs, 0 Mov_fp, Mov_d, Mov_s, Movf, Movn, Movn_d, Movn_s, Movt, Movz, Movz_d, Movz_s, Mtc1, Mthi, Mtlo, Mul, Mul_d, Mul_s, Mult, Multu, Nor, Or, Ori, Ret, Sc, Sdc1, Sll, Sllv, Slt, Slti, Sltiu, Sltu, Sra, Srav, Srl, Srlv, Sqrt_d, Sqrt_s, Sub, Sub_d, Sub_s, Subu, Sw, Swc1, Sync, Teq, Trunc_l_d, Trunc_l_s, Trunc_w_d, Trunc_w_s, Xor, Xori }; static constexpr size_t InstSize = sizeof(uint32_t); static const char *getWidthString(Type Ty); CondMIPS32::Cond getOppositeCondition(CondMIPS32::Cond Cond); void dump(const Cfg *Func) const override; void dumpOpcode(Ostream &Str, const char *Opcode, Type Ty) const { Str << Opcode << "." << Ty; } // TODO(rkotler): while branching is not implemented bool repointEdges(CfgNode *, CfgNode *) override { return true; } /// Shared emit routines for common forms of instructions. static void emitUnaryopGPR(const char *Opcode, const InstMIPS32 *Inst, const Cfg *Func); static void emitUnaryopGPRFLoHi(const char *Opcode, const InstMIPS32 *Inst, const Cfg *Func); static void emitUnaryopGPRTLoHi(const char *Opcode, const InstMIPS32 *Inst, const Cfg *Func); static void emitTwoAddr(const char *Opcode, const InstMIPS32 *Inst, const Cfg *Func); static void emitThreeAddr(const char *Opcode, const InstMIPS32 *Inst, const Cfg *Func); static void emitThreeAddrLoHi(const char *Opcode, const InstMIPS32 *Inst, const Cfg *Func); protected: InstMIPS32(Cfg *Func, InstKindMIPS32 Kind, SizeT Maxsrcs, Variable *Dest) : InstTarget(Func, static_cast(Kind), Maxsrcs, Dest) {} static bool isClassof(const Inst *Inst, InstKindMIPS32 MyKind) { return Inst->getKind() == static_cast(MyKind); } }; /// Ret pseudo-instruction. This is actually a "jr" instruction with an "ra" /// register operand, but epilogue lowering will search for a Ret instead of a /// generic "jr". This instruction also takes a Source operand (for non-void /// returning functions) for liveness analysis, though a FakeUse before the ret /// would do just as well. // TODO(reed kotler): This needs was take from the ARM port and needs to be // scrubbed in the future. class InstMIPS32Ret : public InstMIPS32 { InstMIPS32Ret() = delete; InstMIPS32Ret(const InstMIPS32Ret &) = delete; InstMIPS32Ret &operator=(const InstMIPS32Ret &) = delete; public: static InstMIPS32Ret *create(Cfg *Func, Variable *RA, Variable *Source = nullptr) { return new (Func->allocate()) InstMIPS32Ret(Func, RA, Source); } void emit(const Cfg *Func) const override; void emitIAS(const Cfg *Func) const override; void dump(const Cfg *Func) const override; static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } private: InstMIPS32Ret(Cfg *Func, Variable *RA, Variable *Source); }; /// Instructions of the form x := op(y). template class InstMIPS32UnaryopGPR : public InstMIPS32 { InstMIPS32UnaryopGPR() = delete; InstMIPS32UnaryopGPR(const InstMIPS32UnaryopGPR &) = delete; InstMIPS32UnaryopGPR &operator=(const InstMIPS32UnaryopGPR &) = delete; public: static InstMIPS32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src, RelocOp Reloc = RO_No) { return new (Func->allocate()) InstMIPS32UnaryopGPR(Func, Dest, Src, Reloc); } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; emitUnaryopGPR(Opcode, this, Func); } void emitIAS(const Cfg *Func) const override { (void)Func; llvm_unreachable("Not yet implemented"); } void dump(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); dumpOpcode(Str, Opcode, getDest()->getType()); Str << " "; dumpDest(Func); Str << ", "; dumpSources(Func); } static bool classof(const Inst *Inst) { return isClassof(Inst, K); } protected: InstMIPS32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src, RelocOp Reloc = RO_No) : InstMIPS32(Func, K, 1, Dest), Reloc(Reloc) { addSource(Src); } private: static const char *Opcode; const RelocOp Reloc; }; /// Instructions of the form opcode reg, reg. template class InstMIPS32TwoAddrFPR : public InstMIPS32 { InstMIPS32TwoAddrFPR() = delete; InstMIPS32TwoAddrFPR(const InstMIPS32TwoAddrFPR &) = delete; InstMIPS32TwoAddrFPR &operator=(const InstMIPS32TwoAddrFPR &) = delete; public: static InstMIPS32TwoAddrFPR *create(Cfg *Func, Variable *Dest, Variable *Src0) { return new (Func->allocate()) InstMIPS32TwoAddrFPR(Func, Dest, Src0); } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; emitTwoAddr(Opcode, this, Func); } void emitIAS(const Cfg *Func) const override { (void)Func; llvm_unreachable("Not yet implemented"); } void dump(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); dumpDest(Func); Str << " = "; dumpOpcode(Str, Opcode, getDest()->getType()); Str << " "; dumpSources(Func); } static bool classof(const Inst *Inst) { return isClassof(Inst, K); } private: InstMIPS32TwoAddrFPR(Cfg *Func, Variable *Dest, Variable *Src0) : InstMIPS32(Func, K, 1, Dest) { addSource(Src0); } static const char *Opcode; }; /// Instructions of the form opcode reg, reg. template class InstMIPS32TwoAddrGPR : public InstMIPS32 { InstMIPS32TwoAddrGPR() = delete; InstMIPS32TwoAddrGPR(const InstMIPS32TwoAddrGPR &) = delete; InstMIPS32TwoAddrGPR &operator=(const InstMIPS32TwoAddrGPR &) = delete; public: static InstMIPS32TwoAddrGPR *create(Cfg *Func, Variable *Dest, Variable *Src0) { return new (Func->allocate()) InstMIPS32TwoAddrGPR(Func, Dest, Src0); } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; emitTwoAddr(Opcode, this, Func); } void emitIAS(const Cfg *Func) const override { (void)Func; llvm_unreachable("Not yet implemented"); } void dump(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); dumpDest(Func); Str << " = "; dumpOpcode(Str, Opcode, getDest()->getType()); Str << " "; dumpSources(Func); } static bool classof(const Inst *Inst) { return isClassof(Inst, K); } private: InstMIPS32TwoAddrGPR(Cfg *Func, Variable *Dest, Variable *Src0) : InstMIPS32(Func, K, 1, Dest) { addSource(Src0); } static const char *Opcode; }; /// Instructions of the form x := y op z. May have the side-effect of setting /// status flags. template class InstMIPS32ThreeAddrFPR : public InstMIPS32 { InstMIPS32ThreeAddrFPR() = delete; InstMIPS32ThreeAddrFPR(const InstMIPS32ThreeAddrFPR &) = delete; InstMIPS32ThreeAddrFPR &operator=(const InstMIPS32ThreeAddrFPR &) = delete; public: /// Create an ordinary binary-op instruction like add, and sub. Dest and Src1 /// must be registers. static InstMIPS32ThreeAddrFPR *create(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1) { return new (Func->allocate()) InstMIPS32ThreeAddrFPR(Func, Dest, Src0, Src1); } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; emitThreeAddr(Opcode, this, Func); } void emitIAS(const Cfg *Func) const override { (void)Func; llvm_unreachable("Not yet implemented"); } void dump(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); dumpDest(Func); Str << " = "; dumpOpcode(Str, Opcode, getDest()->getType()); Str << " "; dumpSources(Func); } static bool classof(const Inst *Inst) { return isClassof(Inst, K); } private: InstMIPS32ThreeAddrFPR(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1) : InstMIPS32(Func, K, 2, Dest) { addSource(Src0); addSource(Src1); } static const char *Opcode; }; /// Instructions of the form x := y op z. May have the side-effect of setting /// status flags. template class InstMIPS32ThreeAddrGPR : public InstMIPS32 { InstMIPS32ThreeAddrGPR() = delete; InstMIPS32ThreeAddrGPR(const InstMIPS32ThreeAddrGPR &) = delete; InstMIPS32ThreeAddrGPR &operator=(const InstMIPS32ThreeAddrGPR &) = delete; public: /// Create an ordinary binary-op instruction like add, and sub. Dest and Src1 /// must be registers. static InstMIPS32ThreeAddrGPR *create(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1) { return new (Func->allocate()) InstMIPS32ThreeAddrGPR(Func, Dest, Src0, Src1); } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; emitThreeAddr(Opcode, this, Func); } void emitIAS(const Cfg *Func) const override { (void)Func; llvm_unreachable("Not yet implemented"); } void dump(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); dumpDest(Func); Str << " = "; dumpOpcode(Str, Opcode, getDest()->getType()); Str << " "; dumpSources(Func); } static bool classof(const Inst *Inst) { return isClassof(Inst, K); } private: InstMIPS32ThreeAddrGPR(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1) : InstMIPS32(Func, K, 2, Dest) { addSource(Src0); addSource(Src1); } static const char *Opcode; }; // InstMIPS32Load represents instructions which loads data from memory // Its format is "OPCODE GPR, OFFSET(BASE GPR)" template class InstMIPS32Load : public InstMIPS32 { InstMIPS32Load() = delete; InstMIPS32Load(const InstMIPS32Load &) = delete; InstMIPS32Load &operator=(const InstMIPS32Load &) = delete; public: static InstMIPS32Load *create(Cfg *Func, Variable *Value, OperandMIPS32Mem *Mem, RelocOp Reloc = RO_No) { return new (Func->allocate()) InstMIPS32Load(Func, Value, Mem, Reloc); } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); const Type Ty = getDest()->getType(); if (getKind() == static_cast(Ll)) { Str << "\t" << Opcode << "\t"; } else { switch (Ty) { case IceType_i1: case IceType_i8: Str << "\t" "lb" "\t"; break; case IceType_i16: Str << "\t" "lh" "\t"; break; case IceType_i32: Str << "\t" "lw" "\t"; break; case IceType_f32: Str << "\t" "lwc1" "\t"; break; case IceType_f64: Str << "\t" "ldc1" "\t"; break; default: llvm_unreachable("InstMIPS32Load unknown type"); } } getDest()->emit(Func); Str << ", "; emitRelocOp(Str, Reloc); getSrc(0)->emit(Func); } void emitIAS(const Cfg *Func) const override { (void)Func; llvm_unreachable("Not yet implemented"); } void dump(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); dumpOpcode(Str, Opcode, getDest()->getType()); Str << " "; getDest()->dump(Func); Str << ", "; emitRelocOp(Str, Reloc); getSrc(0)->dump(Func); } static bool classof(const Inst *Inst) { return isClassof(Inst, K); } private: InstMIPS32Load(Cfg *Func, Variable *Value, OperandMIPS32Mem *Mem, RelocOp Reloc = RO_No) : InstMIPS32(Func, K, 2, Value), Reloc(Reloc) { addSource(Mem); } static const char *Opcode; const RelocOp Reloc; }; // InstMIPS32Store represents instructions which stores data to memory // Its format is "OPCODE GPR, OFFSET(BASE GPR)" template class InstMIPS32Store : public InstMIPS32 { InstMIPS32Store() = delete; InstMIPS32Store(const InstMIPS32Store &) = delete; InstMIPS32Store &operator=(const InstMIPS32Store &) = delete; public: static InstMIPS32Store *create(Cfg *Func, Variable *Value, OperandMIPS32Mem *Mem, RelocOp Reloc = RO_No) { return new (Func->allocate()) InstMIPS32Store(Func, Value, Mem, Reloc); } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); assert(getSrcSize() == 2); const Type Ty = getSrc(0)->getType(); if (getKind() == static_cast(Sc)) { Str << "\t" << Opcode << "\t"; } else { switch (Ty) { case IceType_i1: case IceType_i8: Str << "\t" "sb" "\t"; break; case IceType_i16: Str << "\t" "sh" "\t"; break; case IceType_i32: Str << "\t" "sw" "\t"; break; case IceType_f32: Str << "\t" "swc1" "\t"; break; case IceType_f64: Str << "\t" "sdc1" "\t"; break; default: llvm_unreachable("InstMIPS32Store unknown type"); } } getSrc(0)->emit(Func); Str << ", "; emitRelocOp(Str, Reloc); getSrc(1)->emit(Func); } void emitIAS(const Cfg *Func) const override { (void)Func; llvm_unreachable("InstMIPS32Store: Not yet implemented"); } void dump(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); dumpOpcode(Str, Opcode, getSrc(0)->getType()); Str << " "; getSrc(0)->dump(Func); Str << ", "; emitRelocOp(Str, Reloc); getSrc(1)->dump(Func); } static bool classof(const Inst *Inst) { return isClassof(Inst, K); } private: InstMIPS32Store(Cfg *Func, Variable *Value, OperandMIPS32Mem *Mem, RelocOp Reloc = RO_No) : InstMIPS32(Func, K, 2, nullptr), Reloc(Reloc) { addSource(Value); addSource(Mem); } static const char *Opcode; const RelocOp Reloc; }; // InstMIPS32Label represents an intra-block label that is the target of an // intra-block branch. The offset between the label and the branch must be fit // in the instruction immediate (considered "near"). class InstMIPS32Label : public InstMIPS32 { InstMIPS32Label() = delete; InstMIPS32Label(const InstMIPS32Label &) = delete; InstMIPS32Label &operator=(const InstMIPS32Label &) = delete; public: static InstMIPS32Label *create(Cfg *Func, TargetMIPS32 *Target) { return new (Func->allocate()) InstMIPS32Label(Func, Target); } uint32_t getEmitInstCount() const override { return 0; } GlobalString getLabelName() const { return Name; } SizeT getNumber() const { return Number; } void emit(const Cfg *Func) const override; void emitIAS(const Cfg *Func) const override; void dump(const Cfg *Func) const override; static bool classof(const Inst *Instr) { return isClassof(Instr, Label); } private: InstMIPS32Label(Cfg *Func, TargetMIPS32 *Target); // RelocOffset *OffsetReloc = nullptr; SizeT Number; // used for unique label generation. GlobalString Name; }; /// Direct branch instruction. class InstMIPS32Br : public InstMIPS32 { InstMIPS32Br() = delete; InstMIPS32Br(const InstMIPS32Br &) = delete; InstMIPS32Br &operator=(const InstMIPS32Br &) = delete; public: /// Create an unconditional branch to a node. static InstMIPS32Br *create(Cfg *Func, CfgNode *Target) { constexpr CfgNode *NoCondTarget = nullptr; constexpr InstMIPS32Label *NoLabel = nullptr; return new (Func->allocate()) InstMIPS32Br(Func, NoCondTarget, Target, NoLabel, CondMIPS32::AL); } static InstMIPS32Br *create(Cfg *Func, CfgNode *Target, const InstMIPS32Label *Label) { constexpr CfgNode *NoCondTarget = nullptr; return new (Func->allocate()) InstMIPS32Br(Func, NoCondTarget, Target, Label, CondMIPS32::AL); } /// Create a conditional branch to the false node. static InstMIPS32Br *create(Cfg *Func, CfgNode *TargetTrue, CfgNode *TargetFalse, Operand *Src0, Operand *Src1, CondMIPS32::Cond Cond) { constexpr InstMIPS32Label *NoLabel = nullptr; return new (Func->allocate()) InstMIPS32Br(Func, TargetTrue, TargetFalse, Src0, Src1, NoLabel, Cond); } static InstMIPS32Br *create(Cfg *Func, CfgNode *TargetTrue, CfgNode *TargetFalse, Operand *Src0, CondMIPS32::Cond Cond) { constexpr InstMIPS32Label *NoLabel = nullptr; return new (Func->allocate()) InstMIPS32Br(Func, TargetTrue, TargetFalse, Src0, NoLabel, Cond); } static InstMIPS32Br *create(Cfg *Func, CfgNode *TargetTrue, CfgNode *TargetFalse, Operand *Src0, Operand *Src1, const InstMIPS32Label *Label, CondMIPS32::Cond Cond) { return new (Func->allocate()) InstMIPS32Br(Func, TargetTrue, TargetFalse, Src0, Src1, Label, Cond); } const CfgNode *getTargetTrue() const { return TargetTrue; } const CfgNode *getTargetFalse() const { return TargetFalse; } CondMIPS32::Cond getPredicate() const { return Predicate; } void setPredicate(CondMIPS32::Cond Pred) { Predicate = Pred; } bool optimizeBranch(const CfgNode *NextNode); bool isUnconditionalBranch() const override { return Predicate == CondMIPS32::AL; } bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override; void emit(const Cfg *Func) const override; void emitIAS(const Cfg *Func) const override; void dump(const Cfg *Func) const override; static bool classof(const Inst *Instr) { return isClassof(Instr, Br); } private: InstMIPS32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, const InstMIPS32Label *Label, const CondMIPS32::Cond Cond); InstMIPS32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, Operand *Src0, const InstMIPS32Label *Label, const CondMIPS32::Cond Cond); InstMIPS32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, Operand *Src0, Operand *Src1, const InstMIPS32Label *Label, const CondMIPS32::Cond Cond); const CfgNode *TargetTrue; const CfgNode *TargetFalse; const InstMIPS32Label *Label; // Intra-block branch target CondMIPS32::Cond Predicate; }; class InstMIPS32Call : public InstMIPS32 { InstMIPS32Call() = delete; InstMIPS32Call(const InstMIPS32Call &) = delete; InstMIPS32Call &operator=(const InstMIPS32Call &) = delete; public: static InstMIPS32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { return new (Func->allocate()) InstMIPS32Call(Func, Dest, CallTarget); } Operand *getCallTarget() const { return getSrc(0); } void emit(const Cfg *Func) const override; void emitIAS(const Cfg *Func) const override; void dump(const Cfg *Func) const override; static bool classof(const Inst *Inst) { return isClassof(Inst, Call); } private: InstMIPS32Call(Cfg *Func, Variable *Dest, Operand *CallTarget); }; template class InstMIPS32FPCmp : public InstMIPS32 { InstMIPS32FPCmp() = delete; InstMIPS32FPCmp(const InstMIPS32FPCmp &) = delete; InstMIPS32Call &operator=(const InstMIPS32FPCmp &) = delete; public: static InstMIPS32FPCmp *create(Cfg *Func, Variable *Src0, Variable *Src1) { return new (Func->allocate()) InstMIPS32FPCmp(Func, Src0, Src1); } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); assert(getSrcSize() == 2); Str << "\t" << Opcode << "\t"; getSrc(0)->emit(Func); Str << ", "; getSrc(1)->emit(Func); } void emitIAS(const Cfg *Func) const override { (void)Func; llvm_unreachable("Not yet implemented"); } void dump(const Cfg *Func) const override { (void)Func; if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); dumpOpcode(Str, Opcode, getSrc(0)->getType()); Str << " "; dumpSources(Func); } static bool classof(const Inst *Inst) { return isClassof(Inst, Call); } private: InstMIPS32FPCmp(Cfg *Func, Variable *Src0, Variable *Src1) : InstMIPS32(Func, K, 2, nullptr) { addSource(Src0); addSource(Src1); }; static const char *Opcode; }; class InstMIPS32Sync : public InstMIPS32 { InstMIPS32Sync() = delete; InstMIPS32Sync(const InstMIPS32Sync &) = delete; InstMIPS32Sync &operator=(const InstMIPS32Sync &) = delete; public: static InstMIPS32Sync *create(Cfg *Func) { return new (Func->allocate()) InstMIPS32Sync(Func); } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); Str << "\t" << Opcode << "\t"; } void dump(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Func->getContext()->getStrDump() << Opcode << "\t"; } static bool classof(const Inst *Inst) { return isClassof(Inst, InstMIPS32::Sync); } void emitIAS(const Cfg *Func) const override; private: InstMIPS32Sync(Cfg *Func) : InstMIPS32(Func, InstMIPS32::Sync, 0, nullptr) {} static const char *Opcode; }; // Trap template class InstMIPS32Trap : public InstMIPS32 { InstMIPS32Trap() = delete; InstMIPS32Trap(const InstMIPS32Trap &) = delete; InstMIPS32Trap &operator=(const InstMIPS32Trap &) = delete; public: static InstMIPS32Trap *create(Cfg *Func, Operand *Src0, Operand *Src1, uint32_t Tcode) { return new (Func->allocate()) InstMIPS32Trap(Func, Src0, Src1, Tcode); } uint32_t getTrapCode() const { return TrapCode; } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); Str << "\t" << Opcode << "\t"; getSrc(0)->emit(Func); Str << ", "; getSrc(1)->emit(Func); Str << ", " << TrapCode; } void emitIAS(const Cfg *Func) const override { (void)Func; llvm_unreachable("Not yet implemented"); } void dump(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); dumpOpcode(Str, Opcode, getSrc(0)->getType()); Str << " "; dumpSources(Func); Str << ", " << TrapCode; } static bool classof(const Inst *Inst) { return isClassof(Inst, K); } private: InstMIPS32Trap(Cfg *Func, Operand *Src0, Operand *Src1, const uint32_t Tcode) : InstMIPS32(Func, K, 2, nullptr), TrapCode(Tcode) { addSource(Src0); addSource(Src1); } static const char *Opcode; const uint32_t TrapCode; }; template class InstMIPS32Imm16 : public InstMIPS32 { InstMIPS32Imm16() = delete; InstMIPS32Imm16(const InstMIPS32Imm16 &) = delete; InstMIPS32Imm16 &operator=(const InstMIPS32Imm16 &) = delete; public: static InstMIPS32Imm16 *create(Cfg *Func, Variable *Dest, Operand *Source, uint32_t Imm, RelocOp Reloc = RO_No) { return new (Func->allocate()) InstMIPS32Imm16(Func, Dest, Source, Imm, Reloc); } static InstMIPS32Imm16 *create(Cfg *Func, Variable *Dest, uint32_t Imm, RelocOp Reloc = RO_No) { return new (Func->allocate()) InstMIPS32Imm16(Func, Dest, Imm, Reloc); } static InstMIPS32Imm16 *create(Cfg *Func, Variable *Dest, Operand *Src0, Operand *Src1, RelocOp Reloc) { return new (Func->allocate()) InstMIPS32Imm16(Func, Dest, Src0, Src1, Reloc); } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); Str << "\t" << Opcode << "\t"; getDest()->emit(Func); if (getSrcSize() > 0) { Str << ", "; getSrc(0)->emit(Func); } Str << ", "; if (Reloc == RO_No) { if (Signed) Str << (int32_t)Imm; else Str << Imm; } else { auto *CR = llvm::dyn_cast(getSrc(1)); emitRelocOp(Str, Reloc); Str << "("; CR->emitWithoutPrefix(Func->getTarget()); Str << ")"; } } void emitIAS(const Cfg *Func) const override { (void)Func; llvm_unreachable("Not yet implemented"); } void dump(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); dumpOpcode(Str, Opcode, getDest()->getType()); Str << " "; dumpDest(Func); Str << ", "; if (Reloc == RO_No) { dumpSources(Func); Str << ", "; if (Signed) Str << (int32_t)Imm; else Str << Imm; } else { getSrc(0)->dump(Func); Str << ","; emitRelocOp(Str, Reloc); Str << "("; getSrc(1)->dump(Func); Str << ")"; } } uint32_t getImmediateValue() const { return Imm; } static bool classof(const Inst *Inst) { return isClassof(Inst, K); } private: InstMIPS32Imm16(Cfg *Func, Variable *Dest, Operand *Source, uint32_t Imm, RelocOp Reloc = RO_No) : InstMIPS32(Func, K, 1, Dest), Reloc(Reloc), Imm(Imm) { addSource(Source); } InstMIPS32Imm16(Cfg *Func, Variable *Dest, uint32_t Imm, RelocOp Reloc = RO_No) : InstMIPS32(Func, K, 0, Dest), Reloc(Reloc), Imm(Imm) {} InstMIPS32Imm16(Cfg *Func, Variable *Dest, Operand *Src0, Operand *Src1, RelocOp Reloc = RO_No) : InstMIPS32(Func, K, 1, Dest), Reloc(Reloc), Imm(0) { addSource(Src0); addSource(Src1); } static const char *Opcode; const RelocOp Reloc; const uint32_t Imm; }; /// Conditional mov template class InstMIPS32MovConditional : public InstMIPS32 { InstMIPS32MovConditional() = delete; InstMIPS32MovConditional(const InstMIPS32MovConditional &) = delete; InstMIPS32MovConditional & operator=(const InstMIPS32MovConditional &) = delete; public: static InstMIPS32MovConditional *create(Cfg *Func, Variable *Dest, Variable *Src, Operand *FCC) { return new (Func->allocate()) InstMIPS32MovConditional(Func, Dest, Src, FCC); } void emit(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); assert(getSrcSize() == 2); Str << "\t" << Opcode << "\t"; getDest()->emit(Func); Str << ", "; getSrc(0)->emit(Func); Str << ", "; getSrc(1)->emit(Func); } void emitIAS(const Cfg *Func) const override { (void)Func; llvm_unreachable("Not yet implemented"); } void dump(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); dumpDest(Func); Str << " = "; dumpOpcode(Str, Opcode, getDest()->getType()); Str << " "; dumpSources(Func); } static bool classof(const Inst *Inst) { return isClassof(Inst, K); } private: InstMIPS32MovConditional(Cfg *Func, Variable *Dest, Variable *Src, Operand *FCC) : InstMIPS32(Func, K, 2, Dest) { addSource(Src); addSource(FCC); } static const char *Opcode; }; using InstMIPS32Abs_d = InstMIPS32TwoAddrFPR; using InstMIPS32Abs_s = InstMIPS32TwoAddrFPR; using InstMIPS32Add = InstMIPS32ThreeAddrGPR; using InstMIPS32Add_d = InstMIPS32ThreeAddrFPR; using InstMIPS32Add_s = InstMIPS32ThreeAddrFPR; using InstMIPS32Addu = InstMIPS32ThreeAddrGPR; using InstMIPS32Addi = InstMIPS32Imm16; using InstMIPS32Addiu = InstMIPS32Imm16; using InstMIPS32And = InstMIPS32ThreeAddrGPR; using InstMIPS32Andi = InstMIPS32Imm16; using InstMIPS32C_eq_d = InstMIPS32FPCmp; using InstMIPS32C_eq_s = InstMIPS32FPCmp; using InstMIPS32C_ole_d = InstMIPS32FPCmp; using InstMIPS32C_ole_s = InstMIPS32FPCmp; using InstMIPS32C_olt_d = InstMIPS32FPCmp; using InstMIPS32C_olt_s = InstMIPS32FPCmp; using InstMIPS32C_ueq_d = InstMIPS32FPCmp; using InstMIPS32C_ueq_s = InstMIPS32FPCmp; using InstMIPS32C_ule_d = InstMIPS32FPCmp; using InstMIPS32C_ule_s = InstMIPS32FPCmp; using InstMIPS32C_ult_d = InstMIPS32FPCmp; using InstMIPS32C_ult_s = InstMIPS32FPCmp; using InstMIPS32C_un_d = InstMIPS32FPCmp; using InstMIPS32C_un_s = InstMIPS32FPCmp; using InstMIPS32Clz = InstMIPS32TwoAddrGPR; using InstMIPS32Cvt_d_s = InstMIPS32TwoAddrFPR; using InstMIPS32Cvt_d_l = InstMIPS32TwoAddrFPR; using InstMIPS32Cvt_d_w = InstMIPS32TwoAddrFPR; using InstMIPS32Cvt_s_d = InstMIPS32TwoAddrFPR; using InstMIPS32Cvt_s_l = InstMIPS32TwoAddrFPR; using InstMIPS32Cvt_s_w = InstMIPS32TwoAddrFPR; using InstMIPS32Div = InstMIPS32ThreeAddrGPR; using InstMIPS32Div_d = InstMIPS32ThreeAddrFPR; using InstMIPS32Div_s = InstMIPS32ThreeAddrFPR; using InstMIPS32Divu = InstMIPS32ThreeAddrGPR; using InstMIPS32La = InstMIPS32UnaryopGPR; using InstMIPS32Ldc1 = InstMIPS32Load; using InstMIPS32Ll = InstMIPS32Load; using InstMIPS32Lui = InstMIPS32UnaryopGPR; using InstMIPS32Lw = InstMIPS32Load; using InstMIPS32Lwc1 = InstMIPS32Load; using InstMIPS32Mfc1 = InstMIPS32TwoAddrGPR; using InstMIPS32Mfhi = InstMIPS32UnaryopGPR; using InstMIPS32Mflo = InstMIPS32UnaryopGPR; using InstMIPS32Mov_d = InstMIPS32TwoAddrFPR; using InstMIPS32Mov_s = InstMIPS32TwoAddrFPR; using InstMIPS32Movf = InstMIPS32MovConditional; using InstMIPS32Movn = InstMIPS32ThreeAddrGPR; using InstMIPS32Movn_d = InstMIPS32ThreeAddrGPR; using InstMIPS32Movn_s = InstMIPS32ThreeAddrGPR; using InstMIPS32Movt = InstMIPS32MovConditional; using InstMIPS32Movz = InstMIPS32ThreeAddrGPR; using InstMIPS32Movz_d = InstMIPS32ThreeAddrGPR; using InstMIPS32Movz_s = InstMIPS32ThreeAddrGPR; using InstMIPS32Mtc1 = InstMIPS32TwoAddrGPR; using InstMIPS32Mthi = InstMIPS32UnaryopGPR; using InstMIPS32Mtlo = InstMIPS32UnaryopGPR; using InstMIPS32Mul = InstMIPS32ThreeAddrGPR; using InstMIPS32Mul_d = InstMIPS32ThreeAddrFPR; using InstMIPS32Mul_s = InstMIPS32ThreeAddrFPR; using InstMIPS32Mult = InstMIPS32ThreeAddrGPR; using InstMIPS32Multu = InstMIPS32ThreeAddrGPR; using InstMIPS32Nor = InstMIPS32ThreeAddrGPR; using InstMIPS32Or = InstMIPS32ThreeAddrGPR; using InstMIPS32Ori = InstMIPS32Imm16; using InstMIPS32Sc = InstMIPS32Store; using InstMIPS32Sdc1 = InstMIPS32Store; using InstMIPS32Sll = InstMIPS32Imm16; using InstMIPS32Sllv = InstMIPS32ThreeAddrGPR; using InstMIPS32Slt = InstMIPS32ThreeAddrGPR; using InstMIPS32Slti = InstMIPS32Imm16; using InstMIPS32Sltiu = InstMIPS32Imm16; using InstMIPS32Sltu = InstMIPS32ThreeAddrGPR; using InstMIPS32Sqrt_d = InstMIPS32TwoAddrFPR; using InstMIPS32Sqrt_s = InstMIPS32TwoAddrFPR; using InstMIPS32Sra = InstMIPS32Imm16; using InstMIPS32Srav = InstMIPS32ThreeAddrGPR; using InstMIPS32Srl = InstMIPS32Imm16; using InstMIPS32Srlv = InstMIPS32ThreeAddrGPR; using InstMIPS32Sub = InstMIPS32ThreeAddrGPR; using InstMIPS32Sub_d = InstMIPS32ThreeAddrFPR; using InstMIPS32Sub_s = InstMIPS32ThreeAddrFPR; using InstMIPS32Subu = InstMIPS32ThreeAddrGPR; using InstMIPS32Sw = InstMIPS32Store; using InstMIPS32Swc1 = InstMIPS32Store; using InstMIPS32Teq = InstMIPS32Trap; using InstMIPS32Trunc_l_d = InstMIPS32TwoAddrFPR; using InstMIPS32Trunc_l_s = InstMIPS32TwoAddrFPR; using InstMIPS32Trunc_w_d = InstMIPS32TwoAddrFPR; using InstMIPS32Trunc_w_s = InstMIPS32TwoAddrFPR; using InstMIPS32Ori = InstMIPS32Imm16; using InstMIPS32Xor = InstMIPS32ThreeAddrGPR; using InstMIPS32Xori = InstMIPS32Imm16; /// Handles (some of) vmov's various formats. class InstMIPS32Mov final : public InstMIPS32 { InstMIPS32Mov() = delete; InstMIPS32Mov(const InstMIPS32Mov &) = delete; InstMIPS32Mov &operator=(const InstMIPS32Mov &) = delete; public: static InstMIPS32Mov *create(Cfg *Func, Variable *Dest, Operand *Src, Operand *Src2) { return new (Func->allocate()) InstMIPS32Mov(Func, Dest, Src, Src2); } bool isRedundantAssign() const override { return checkForRedundantAssign(getDest(), getSrc(0)); } // bool isSimpleAssign() const override { return true; } void emit(const Cfg *Func) const override; void emitIAS(const Cfg *Func) const override; void dump(const Cfg *Func) const override; static bool classof(const Inst *Inst) { return isClassof(Inst, Mov); } Variable *getDestHi() const { return DestHi; } private: InstMIPS32Mov(Cfg *Func, Variable *Dest, Operand *Src, Operand *Src2); void emitMultiDestSingleSource(const Cfg *Func) const; void emitSingleDestMultiSource(const Cfg *Func) const; void emitSingleDestSingleSource(const Cfg *Func) const; Variable *DestHi = nullptr; }; /// Handle double to i64 move class InstMIPS32MovFP64ToI64 final : public InstMIPS32 { InstMIPS32MovFP64ToI64() = delete; InstMIPS32MovFP64ToI64(const InstMIPS32MovFP64ToI64 &) = delete; InstMIPS32MovFP64ToI64 &operator=(const InstMIPS32MovFP64ToI64 &) = delete; public: static InstMIPS32MovFP64ToI64 *create(Cfg *Func, Variable *Dest, Operand *Src, Int64Part Int64HiLo) { return new (Func->allocate()) InstMIPS32MovFP64ToI64(Func, Dest, Src, Int64HiLo); } bool isRedundantAssign() const override { return checkForRedundantAssign(getDest(), getSrc(0)); } void dump(const Cfg *Func) const override { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); getDest()->dump(Func); Str << " = "; dumpOpcode(Str, "mov_fp", getDest()->getType()); Str << " "; getSrc(0)->dump(Func); } Int64Part getInt64Part() const { return Int64HiLo; } static bool classof(const Inst *Inst) { return isClassof(Inst, Mov_fp); } private: InstMIPS32MovFP64ToI64(Cfg *Func, Variable *Dest, Operand *Src, Int64Part Int64HiLo); const Int64Part Int64HiLo; }; // Declare partial template specializations of emit() methods that already have // default implementations. Without this, there is the possibility of ODR // violations and link errors. template <> void InstMIPS32Abs_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Abs_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Add_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Add_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Addi::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Addiu::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Addu::emitIAS(const Cfg *Func) const; template <> void InstMIPS32And::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Andi::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_eq_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_eq_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_ole_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_ole_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_olt_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_olt_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_ueq_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_ueq_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_ule_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_ule_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_ult_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_ult_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_un_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32C_un_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Clz::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Cvt_d_l::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Cvt_d_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Cvt_d_w::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Cvt_s_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Cvt_s_l::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Cvt_s_w::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Div::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Div_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Div_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Divu::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Ldc1::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Ll::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Lui::emit(const Cfg *Func) const; template <> void InstMIPS32Lui::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Lw::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Lwc1::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mfc1::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mflo::emit(const Cfg *Func) const; template <> void InstMIPS32Mflo::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mfhi::emit(const Cfg *Func) const; template <> void InstMIPS32Mfhi::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mov_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mov_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Movf::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Movn::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Movn_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Movn_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Movt::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Movz::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Movz_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Movz_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mtc1::emit(const Cfg *Func) const; template <> void InstMIPS32Mtc1::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mtlo::emit(const Cfg *Func) const; template <> void InstMIPS32Mtlo::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mthi::emit(const Cfg *Func) const; template <> void InstMIPS32Mthi::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mul::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mul_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mul_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mult::emit(const Cfg *Func) const; template <> void InstMIPS32Multu::emit(const Cfg *Func) const; template <> void InstMIPS32Multu::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Nor::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Or::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Ori::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sc::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sdc1::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sll::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sllv::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Slt::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Slti::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sltiu::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sltu::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sqrt_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sqrt_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sw::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Swc1::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sra::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Srav::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Srl::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Srlv::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sub_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sub_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Subu::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Teq::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Trunc_l_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Trunc_l_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Trunc_w_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Trunc_w_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Xor::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Xori::emitIAS(const Cfg *Func) const; } // end of namespace MIPS32 } // end of namespace Ice #endif // SUBZERO_SRC_ICEINSTMIPS32_H