| //===- 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 << "<OperandMIPS32>"; |
| } |
| |
| protected: |
| OperandMIPS32(OperandKindMIPS32 Kind, Type Ty) |
| : Operand(static_cast<OperandKind>(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>()) 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<uint16_t>(FpCondCode); |
| } |
| |
| static bool classof(const Operand *Operand) { |
| return Operand->getKind() == static_cast<OperandKind>(kFCC); |
| } |
| |
| void dump(const Cfg *Func, Ostream &Str) const override { |
| if (!BuildDefs::dump()) |
| return; |
| (void)Func; |
| Str << "$fcc" << static_cast<uint16_t>(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>()) |
| 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<OperandKind>(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<InstKind>(Kind), Maxsrcs, Dest) {} |
| static bool isClassof(const Inst *Inst, InstKindMIPS32 MyKind) { |
| return Inst->getKind() == static_cast<InstKind>(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>()) |
| 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 <InstMIPS32::InstKindMIPS32 K> |
| 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>()) |
| 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 <InstMIPS32::InstKindMIPS32 K> |
| 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>()) |
| 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 <InstMIPS32::InstKindMIPS32 K> |
| 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>()) |
| 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 <InstMIPS32::InstKindMIPS32 K> |
| 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>()) |
| 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 <InstMIPS32::InstKindMIPS32 K> |
| 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>()) |
| 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 <InstMIPS32::InstKindMIPS32 K> |
| 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>()) |
| 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<InstKind>(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 <InstMIPS32::InstKindMIPS32 K> |
| 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>()) |
| 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<InstKind>(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>()) |
| 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>()) |
| 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>()) |
| 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>()) |
| 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>()) |
| 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>()) |
| 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>()) |
| 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 <InstMIPS32::InstKindMIPS32 K> |
| 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>()) |
| 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>()) 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 <InstMIPS32::InstKindMIPS32 K> |
| 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>()) |
| 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 <InstMIPS32::InstKindMIPS32 K, bool Signed = false> |
| 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>()) |
| 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>()) |
| InstMIPS32Imm16(Func, Dest, Imm, Reloc); |
| } |
| |
| static InstMIPS32Imm16 *create(Cfg *Func, Variable *Dest, Operand *Src0, |
| Operand *Src1, RelocOp Reloc) { |
| return new (Func->allocate<InstMIPS32Imm16>()) |
| 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<ConstantRelocatable>(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 <InstMIPS32::InstKindMIPS32 K> |
| 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>()) |
| 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<InstMIPS32::Abs_d>; |
| using InstMIPS32Abs_s = InstMIPS32TwoAddrFPR<InstMIPS32::Abs_s>; |
| using InstMIPS32Add = InstMIPS32ThreeAddrGPR<InstMIPS32::Add>; |
| using InstMIPS32Add_d = InstMIPS32ThreeAddrFPR<InstMIPS32::Add_d>; |
| using InstMIPS32Add_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Add_s>; |
| using InstMIPS32Addu = InstMIPS32ThreeAddrGPR<InstMIPS32::Addu>; |
| using InstMIPS32Addi = InstMIPS32Imm16<InstMIPS32::Addi, true>; |
| using InstMIPS32Addiu = InstMIPS32Imm16<InstMIPS32::Addiu, true>; |
| using InstMIPS32And = InstMIPS32ThreeAddrGPR<InstMIPS32::And>; |
| using InstMIPS32Andi = InstMIPS32Imm16<InstMIPS32::Andi>; |
| using InstMIPS32C_eq_d = InstMIPS32FPCmp<InstMIPS32::C_eq_d>; |
| using InstMIPS32C_eq_s = InstMIPS32FPCmp<InstMIPS32::C_eq_s>; |
| using InstMIPS32C_ole_d = InstMIPS32FPCmp<InstMIPS32::C_ole_d>; |
| using InstMIPS32C_ole_s = InstMIPS32FPCmp<InstMIPS32::C_ole_s>; |
| using InstMIPS32C_olt_d = InstMIPS32FPCmp<InstMIPS32::C_olt_d>; |
| using InstMIPS32C_olt_s = InstMIPS32FPCmp<InstMIPS32::C_olt_s>; |
| using InstMIPS32C_ueq_d = InstMIPS32FPCmp<InstMIPS32::C_ueq_d>; |
| using InstMIPS32C_ueq_s = InstMIPS32FPCmp<InstMIPS32::C_ueq_s>; |
| using InstMIPS32C_ule_d = InstMIPS32FPCmp<InstMIPS32::C_ule_d>; |
| using InstMIPS32C_ule_s = InstMIPS32FPCmp<InstMIPS32::C_ule_s>; |
| using InstMIPS32C_ult_d = InstMIPS32FPCmp<InstMIPS32::C_ult_d>; |
| using InstMIPS32C_ult_s = InstMIPS32FPCmp<InstMIPS32::C_ult_s>; |
| using InstMIPS32C_un_d = InstMIPS32FPCmp<InstMIPS32::C_un_d>; |
| using InstMIPS32C_un_s = InstMIPS32FPCmp<InstMIPS32::C_un_s>; |
| using InstMIPS32Clz = InstMIPS32TwoAddrGPR<InstMIPS32::Clz>; |
| using InstMIPS32Cvt_d_s = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_s>; |
| using InstMIPS32Cvt_d_l = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_l>; |
| using InstMIPS32Cvt_d_w = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_w>; |
| using InstMIPS32Cvt_s_d = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_s_d>; |
| using InstMIPS32Cvt_s_l = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_s_l>; |
| using InstMIPS32Cvt_s_w = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_s_w>; |
| using InstMIPS32Div = InstMIPS32ThreeAddrGPR<InstMIPS32::Div>; |
| using InstMIPS32Div_d = InstMIPS32ThreeAddrFPR<InstMIPS32::Div_d>; |
| using InstMIPS32Div_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Div_s>; |
| using InstMIPS32Divu = InstMIPS32ThreeAddrGPR<InstMIPS32::Divu>; |
| using InstMIPS32La = InstMIPS32UnaryopGPR<InstMIPS32::La>; |
| using InstMIPS32Ldc1 = InstMIPS32Load<InstMIPS32::Ldc1>; |
| using InstMIPS32Ll = InstMIPS32Load<InstMIPS32::Ll>; |
| using InstMIPS32Lui = InstMIPS32UnaryopGPR<InstMIPS32::Lui>; |
| using InstMIPS32Lw = InstMIPS32Load<InstMIPS32::Lw>; |
| using InstMIPS32Lwc1 = InstMIPS32Load<InstMIPS32::Lwc1>; |
| using InstMIPS32Mfc1 = InstMIPS32TwoAddrGPR<InstMIPS32::Mfc1>; |
| using InstMIPS32Mfhi = InstMIPS32UnaryopGPR<InstMIPS32::Mfhi>; |
| using InstMIPS32Mflo = InstMIPS32UnaryopGPR<InstMIPS32::Mflo>; |
| using InstMIPS32Mov_d = InstMIPS32TwoAddrFPR<InstMIPS32::Mov_d>; |
| using InstMIPS32Mov_s = InstMIPS32TwoAddrFPR<InstMIPS32::Mov_s>; |
| using InstMIPS32Movf = InstMIPS32MovConditional<InstMIPS32::Movf>; |
| using InstMIPS32Movn = InstMIPS32ThreeAddrGPR<InstMIPS32::Movn>; |
| using InstMIPS32Movn_d = InstMIPS32ThreeAddrGPR<InstMIPS32::Movn_d>; |
| using InstMIPS32Movn_s = InstMIPS32ThreeAddrGPR<InstMIPS32::Movn_s>; |
| using InstMIPS32Movt = InstMIPS32MovConditional<InstMIPS32::Movt>; |
| using InstMIPS32Movz = InstMIPS32ThreeAddrGPR<InstMIPS32::Movz>; |
| using InstMIPS32Movz_d = InstMIPS32ThreeAddrGPR<InstMIPS32::Movz_d>; |
| using InstMIPS32Movz_s = InstMIPS32ThreeAddrGPR<InstMIPS32::Movz_s>; |
| using InstMIPS32Mtc1 = InstMIPS32TwoAddrGPR<InstMIPS32::Mtc1>; |
| using InstMIPS32Mthi = InstMIPS32UnaryopGPR<InstMIPS32::Mthi>; |
| using InstMIPS32Mtlo = InstMIPS32UnaryopGPR<InstMIPS32::Mtlo>; |
| using InstMIPS32Mul = InstMIPS32ThreeAddrGPR<InstMIPS32::Mul>; |
| using InstMIPS32Mul_d = InstMIPS32ThreeAddrFPR<InstMIPS32::Mul_d>; |
| using InstMIPS32Mul_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Mul_s>; |
| using InstMIPS32Mult = InstMIPS32ThreeAddrGPR<InstMIPS32::Mult>; |
| using InstMIPS32Multu = InstMIPS32ThreeAddrGPR<InstMIPS32::Multu>; |
| using InstMIPS32Nor = InstMIPS32ThreeAddrGPR<InstMIPS32::Nor>; |
| using InstMIPS32Or = InstMIPS32ThreeAddrGPR<InstMIPS32::Or>; |
| using InstMIPS32Ori = InstMIPS32Imm16<InstMIPS32::Ori>; |
| using InstMIPS32Sc = InstMIPS32Store<InstMIPS32::Sc>; |
| using InstMIPS32Sdc1 = InstMIPS32Store<InstMIPS32::Sdc1>; |
| using InstMIPS32Sll = InstMIPS32Imm16<InstMIPS32::Sll>; |
| using InstMIPS32Sllv = InstMIPS32ThreeAddrGPR<InstMIPS32::Sllv>; |
| using InstMIPS32Slt = InstMIPS32ThreeAddrGPR<InstMIPS32::Slt>; |
| using InstMIPS32Slti = InstMIPS32Imm16<InstMIPS32::Slti>; |
| using InstMIPS32Sltiu = InstMIPS32Imm16<InstMIPS32::Sltiu>; |
| using InstMIPS32Sltu = InstMIPS32ThreeAddrGPR<InstMIPS32::Sltu>; |
| using InstMIPS32Sqrt_d = InstMIPS32TwoAddrFPR<InstMIPS32::Sqrt_d>; |
| using InstMIPS32Sqrt_s = InstMIPS32TwoAddrFPR<InstMIPS32::Sqrt_s>; |
| using InstMIPS32Sra = InstMIPS32Imm16<InstMIPS32::Sra>; |
| using InstMIPS32Srav = InstMIPS32ThreeAddrGPR<InstMIPS32::Srav>; |
| using InstMIPS32Srl = InstMIPS32Imm16<InstMIPS32::Srl>; |
| using InstMIPS32Srlv = InstMIPS32ThreeAddrGPR<InstMIPS32::Srlv>; |
| using InstMIPS32Sub = InstMIPS32ThreeAddrGPR<InstMIPS32::Sub>; |
| using InstMIPS32Sub_d = InstMIPS32ThreeAddrFPR<InstMIPS32::Sub_d>; |
| using InstMIPS32Sub_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Sub_s>; |
| using InstMIPS32Subu = InstMIPS32ThreeAddrGPR<InstMIPS32::Subu>; |
| using InstMIPS32Sw = InstMIPS32Store<InstMIPS32::Sw>; |
| using InstMIPS32Swc1 = InstMIPS32Store<InstMIPS32::Swc1>; |
| using InstMIPS32Teq = InstMIPS32Trap<InstMIPS32::Teq>; |
| using InstMIPS32Trunc_l_d = InstMIPS32TwoAddrFPR<InstMIPS32::Trunc_l_d>; |
| using InstMIPS32Trunc_l_s = InstMIPS32TwoAddrFPR<InstMIPS32::Trunc_l_s>; |
| using InstMIPS32Trunc_w_d = InstMIPS32TwoAddrFPR<InstMIPS32::Trunc_w_d>; |
| using InstMIPS32Trunc_w_s = InstMIPS32TwoAddrFPR<InstMIPS32::Trunc_w_s>; |
| using InstMIPS32Ori = InstMIPS32Imm16<InstMIPS32::Ori>; |
| using InstMIPS32Xor = InstMIPS32ThreeAddrGPR<InstMIPS32::Xor>; |
| using InstMIPS32Xori = InstMIPS32Imm16<InstMIPS32::Xori>; |
| |
| /// 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>()) |
| 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>()) |
| 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 |