|  | //===- subzero/src/IceInstMips32.cpp - Mips32 instruction implementation --===// | 
|  | // | 
|  | //                        The Subzero Code Generator | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | /// \file | 
|  | /// \brief Implements the InstMips32 and OperandMips32 classes, primarily the | 
|  | /// constructors and the dump()/emit() methods. | 
|  | /// | 
|  | //===----------------------------------------------------------------------===// | 
|  | #include "IceAssemblerMIPS32.h" | 
|  | #include "IceCfg.h" | 
|  | #include "IceCfgNode.h" | 
|  | #include "IceInst.h" | 
|  | #include "IceInstMIPS32.h" | 
|  | #include "IceOperand.h" | 
|  | #include "IceRegistersMIPS32.h" | 
|  | #include "IceTargetLoweringMIPS32.h" | 
|  | #include <limits> | 
|  |  | 
|  | namespace Ice { | 
|  | namespace MIPS32 { | 
|  |  | 
|  | const struct InstMIPS32CondAttributes_ { | 
|  | CondMIPS32::Cond Opposite; | 
|  | const char *EmitString; | 
|  | } InstMIPS32CondAttributes[] = { | 
|  | #define X(tag, opp, emit)                                                      \ | 
|  | { CondMIPS32::opp, emit }                                                    \ | 
|  | , | 
|  | ICEINSTMIPS32COND_TABLE | 
|  | #undef X | 
|  | }; | 
|  |  | 
|  | bool OperandMIPS32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) { | 
|  | (void)SignExt; | 
|  | (void)Ty; | 
|  | if ((std::numeric_limits<int16_t>::min() <= Offset) && | 
|  | (Offset <= std::numeric_limits<int16_t>::max())) | 
|  | return true; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | OperandMIPS32Mem::OperandMIPS32Mem(Cfg *Func, Type Ty, Variable *Base, | 
|  | Operand *ImmOffset, AddrMode Mode) | 
|  | : OperandMIPS32(kMem, Ty), Base(Base), ImmOffset(ImmOffset), Mode(Mode) { | 
|  | // The Neg modes are only needed for Reg +/- Reg. | 
|  | (void)Func; | 
|  | // assert(!isNegAddrMode()); | 
|  | NumVars = 1; | 
|  | Vars = &this->Base; | 
|  | } | 
|  |  | 
|  | const char *InstMIPS32::getWidthString(Type Ty) { | 
|  | (void)Ty; | 
|  | return "TBD"; | 
|  | } | 
|  |  | 
|  | template <> const char *InstMIPS32Abs_d::Opcode = "abs.d"; | 
|  | template <> const char *InstMIPS32Abs_s::Opcode = "abs.s"; | 
|  | template <> const char *InstMIPS32Addi::Opcode = "addi"; | 
|  | template <> const char *InstMIPS32Add::Opcode = "add"; | 
|  | template <> const char *InstMIPS32Add_d::Opcode = "add.d"; | 
|  | template <> const char *InstMIPS32Add_s::Opcode = "add.s"; | 
|  | template <> const char *InstMIPS32Addiu::Opcode = "addiu"; | 
|  | template <> const char *InstMIPS32Addu::Opcode = "addu"; | 
|  | template <> const char *InstMIPS32And::Opcode = "and"; | 
|  | template <> const char *InstMIPS32Andi::Opcode = "andi"; | 
|  | template <> const char *InstMIPS32C_eq_d::Opcode = "c.eq.d"; | 
|  | template <> const char *InstMIPS32C_eq_s::Opcode = "c.eq.s"; | 
|  | template <> const char *InstMIPS32C_ole_d::Opcode = "c.ole.d"; | 
|  | template <> const char *InstMIPS32C_ole_s::Opcode = "c.ole.s"; | 
|  | template <> const char *InstMIPS32C_olt_d::Opcode = "c.olt.d"; | 
|  | template <> const char *InstMIPS32C_olt_s::Opcode = "c.olt.s"; | 
|  | template <> const char *InstMIPS32C_ueq_d::Opcode = "c.ueq.d"; | 
|  | template <> const char *InstMIPS32C_ueq_s::Opcode = "c.ueq.s"; | 
|  | template <> const char *InstMIPS32C_ule_d::Opcode = "c.ule.d"; | 
|  | template <> const char *InstMIPS32C_ule_s::Opcode = "c.ule.s"; | 
|  | template <> const char *InstMIPS32C_ult_d::Opcode = "c.ult.d"; | 
|  | template <> const char *InstMIPS32C_ult_s::Opcode = "c.ult.s"; | 
|  | template <> const char *InstMIPS32C_un_d::Opcode = "c.un.d"; | 
|  | template <> const char *InstMIPS32C_un_s::Opcode = "c.un.s"; | 
|  | template <> const char *InstMIPS32Clz::Opcode = "clz"; | 
|  | template <> const char *InstMIPS32Cvt_d_l::Opcode = "cvt.d.l"; | 
|  | template <> const char *InstMIPS32Cvt_d_s::Opcode = "cvt.d.s"; | 
|  | template <> const char *InstMIPS32Cvt_d_w::Opcode = "cvt.d.w"; | 
|  | template <> const char *InstMIPS32Cvt_s_d::Opcode = "cvt.s.d"; | 
|  | template <> const char *InstMIPS32Cvt_s_l::Opcode = "cvt.s.l"; | 
|  | template <> const char *InstMIPS32Cvt_s_w::Opcode = "cvt.s.w"; | 
|  | template <> const char *InstMIPS32Div::Opcode = "div"; | 
|  | template <> const char *InstMIPS32Div_d::Opcode = "div.d"; | 
|  | template <> const char *InstMIPS32Div_s::Opcode = "div.s"; | 
|  | template <> const char *InstMIPS32Divu::Opcode = "divu"; | 
|  | template <> const char *InstMIPS32La::Opcode = "la"; | 
|  | template <> const char *InstMIPS32Ldc1::Opcode = "ldc1"; | 
|  | template <> const char *InstMIPS32Ll::Opcode = "ll"; | 
|  | template <> const char *InstMIPS32Lui::Opcode = "lui"; | 
|  | template <> const char *InstMIPS32Lw::Opcode = "lw"; | 
|  | template <> const char *InstMIPS32Lwc1::Opcode = "lwc1"; | 
|  | template <> const char *InstMIPS32Mfc1::Opcode = "mfc1"; | 
|  | template <> const char *InstMIPS32Mfhi::Opcode = "mfhi"; | 
|  | template <> const char *InstMIPS32Mflo::Opcode = "mflo"; | 
|  | template <> const char *InstMIPS32Mov_d::Opcode = "mov.d"; | 
|  | template <> const char *InstMIPS32Mov_s::Opcode = "mov.s"; | 
|  | template <> const char *InstMIPS32Movf::Opcode = "movf"; | 
|  | template <> const char *InstMIPS32Movn::Opcode = "movn"; | 
|  | template <> const char *InstMIPS32Movn_d::Opcode = "movn.d"; | 
|  | template <> const char *InstMIPS32Movn_s::Opcode = "movn.s"; | 
|  | template <> const char *InstMIPS32Movt::Opcode = "movt"; | 
|  | template <> const char *InstMIPS32Movz::Opcode = "movz"; | 
|  | template <> const char *InstMIPS32Movz_d::Opcode = "movz.d"; | 
|  | template <> const char *InstMIPS32Movz_s::Opcode = "movz.s"; | 
|  | template <> const char *InstMIPS32Mtc1::Opcode = "mtc1"; | 
|  | template <> const char *InstMIPS32Mthi::Opcode = "mthi"; | 
|  | template <> const char *InstMIPS32Mtlo::Opcode = "mtlo"; | 
|  | template <> const char *InstMIPS32Mul::Opcode = "mul"; | 
|  | template <> const char *InstMIPS32Mul_d::Opcode = "mul.d"; | 
|  | template <> const char *InstMIPS32Mul_s::Opcode = "mul.s"; | 
|  | template <> const char *InstMIPS32Mult::Opcode = "mult"; | 
|  | template <> const char *InstMIPS32Multu::Opcode = "multu"; | 
|  | template <> const char *InstMIPS32Nor::Opcode = "nor"; | 
|  | template <> const char *InstMIPS32Or::Opcode = "or"; | 
|  | template <> const char *InstMIPS32Ori::Opcode = "ori"; | 
|  | template <> const char *InstMIPS32Sc::Opcode = "sc"; | 
|  | template <> const char *InstMIPS32Sdc1::Opcode = "sdc1"; | 
|  | template <> const char *InstMIPS32Sll::Opcode = "sll"; | 
|  | template <> const char *InstMIPS32Sllv::Opcode = "sllv"; | 
|  | template <> const char *InstMIPS32Slt::Opcode = "slt"; | 
|  | template <> const char *InstMIPS32Slti::Opcode = "slti"; | 
|  | template <> const char *InstMIPS32Sltiu::Opcode = "sltiu"; | 
|  | template <> const char *InstMIPS32Sltu::Opcode = "sltu"; | 
|  | template <> const char *InstMIPS32Sqrt_d::Opcode = "sqrt.d"; | 
|  | template <> const char *InstMIPS32Sqrt_s::Opcode = "sqrt.s"; | 
|  | template <> const char *InstMIPS32Sra::Opcode = "sra"; | 
|  | template <> const char *InstMIPS32Srav::Opcode = "srav"; | 
|  | template <> const char *InstMIPS32Srl::Opcode = "srl"; | 
|  | template <> const char *InstMIPS32Srlv::Opcode = "srlv"; | 
|  | template <> const char *InstMIPS32Sub::Opcode = "sub"; | 
|  | template <> const char *InstMIPS32Sub_d::Opcode = "sub.d"; | 
|  | template <> const char *InstMIPS32Sub_s::Opcode = "sub.s"; | 
|  | template <> const char *InstMIPS32Subu::Opcode = "subu"; | 
|  | template <> const char *InstMIPS32Sw::Opcode = "sw"; | 
|  | template <> const char *InstMIPS32Swc1::Opcode = "swc1"; | 
|  | const char *InstMIPS32Sync::Opcode = "sync"; | 
|  | template <> const char *InstMIPS32Teq::Opcode = "teq"; | 
|  | template <> const char *InstMIPS32Trunc_l_d::Opcode = "trunc.l.d"; | 
|  | template <> const char *InstMIPS32Trunc_l_s::Opcode = "trunc.l.s"; | 
|  | template <> const char *InstMIPS32Trunc_w_d::Opcode = "trunc.w.d"; | 
|  | template <> const char *InstMIPS32Trunc_w_s::Opcode = "trunc.w.s"; | 
|  | template <> const char *InstMIPS32Xor::Opcode = "xor"; | 
|  | template <> const char *InstMIPS32Xori::Opcode = "xori"; | 
|  |  | 
|  | template <> void InstMIPS32Lui::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | assert(getSrcSize() == 1); | 
|  | Str << "\t" << Opcode << "\t"; | 
|  | getDest()->emit(Func); | 
|  | Str << ", "; | 
|  | auto *Src0 = llvm::cast<Constant>(getSrc(0)); | 
|  | if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src0)) { | 
|  | emitRelocOp(Str, Reloc); | 
|  | Str << "("; | 
|  | CR->emitWithoutPrefix(Func->getTarget()); | 
|  | Str << ")"; | 
|  | } else { | 
|  | Src0->emit(Func); | 
|  | } | 
|  | } | 
|  |  | 
|  | InstMIPS32Br::InstMIPS32Br(Cfg *Func, const CfgNode *TargetTrue, | 
|  | const CfgNode *TargetFalse, | 
|  | const InstMIPS32Label *Label, CondMIPS32::Cond Cond) | 
|  | : InstMIPS32(Func, InstMIPS32::Br, 0, nullptr), TargetTrue(TargetTrue), | 
|  | TargetFalse(TargetFalse), Label(Label), Predicate(Cond) {} | 
|  |  | 
|  | InstMIPS32Br::InstMIPS32Br(Cfg *Func, const CfgNode *TargetTrue, | 
|  | const CfgNode *TargetFalse, Operand *Src0, | 
|  | const InstMIPS32Label *Label, CondMIPS32::Cond Cond) | 
|  | : InstMIPS32(Func, InstMIPS32::Br, 1, nullptr), TargetTrue(TargetTrue), | 
|  | TargetFalse(TargetFalse), Label(Label), Predicate(Cond) { | 
|  | addSource(Src0); | 
|  | } | 
|  |  | 
|  | InstMIPS32Br::InstMIPS32Br(Cfg *Func, const CfgNode *TargetTrue, | 
|  | const CfgNode *TargetFalse, Operand *Src0, | 
|  | Operand *Src1, const InstMIPS32Label *Label, | 
|  | CondMIPS32::Cond Cond) | 
|  | : InstMIPS32(Func, InstMIPS32::Br, 2, nullptr), TargetTrue(TargetTrue), | 
|  | TargetFalse(TargetFalse), Label(Label), Predicate(Cond) { | 
|  | addSource(Src0); | 
|  | addSource(Src1); | 
|  | } | 
|  |  | 
|  | CondMIPS32::Cond InstMIPS32::getOppositeCondition(CondMIPS32::Cond Cond) { | 
|  | return InstMIPS32CondAttributes[Cond].Opposite; | 
|  | } | 
|  |  | 
|  | bool InstMIPS32Br::optimizeBranch(const CfgNode *NextNode) { | 
|  | // If there is no next block, then there can be no fallthrough to optimize. | 
|  | if (NextNode == nullptr) | 
|  | return false; | 
|  | // Intra-block conditional branches can't be optimized. | 
|  | if (Label != nullptr) | 
|  | return false; | 
|  | // Unconditional branch to the next node can be removed. | 
|  | if (isUnconditionalBranch() && getTargetFalse() == NextNode) { | 
|  | assert(getTargetTrue() == nullptr); | 
|  | setDeleted(); | 
|  | return true; | 
|  | } | 
|  | // If there is no fallthrough node, such as a non-default case label for a | 
|  | // switch instruction, then there is no opportunity to optimize. | 
|  | if (getTargetTrue() == nullptr) | 
|  | return false; | 
|  | // If the fallthrough is to the next node, set fallthrough to nullptr to | 
|  | // indicate. | 
|  | if (getTargetTrue() == NextNode) { | 
|  | TargetTrue = nullptr; | 
|  | return true; | 
|  | } | 
|  | // If TargetFalse is the next node, and TargetTrue is not nullptr | 
|  | // then invert the branch condition, swap the targets, and set new | 
|  | // fallthrough to nullptr. | 
|  | if (getTargetFalse() == NextNode) { | 
|  | assert(Predicate != CondMIPS32::AL); | 
|  | setPredicate(getOppositeCondition(getPredicate())); | 
|  | TargetFalse = getTargetTrue(); | 
|  | TargetTrue = nullptr; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool InstMIPS32Br::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { | 
|  | bool Found = false; | 
|  | if (TargetFalse == OldNode) { | 
|  | TargetFalse = NewNode; | 
|  | Found = true; | 
|  | } | 
|  | if (TargetTrue == OldNode) { | 
|  | TargetTrue = NewNode; | 
|  | Found = true; | 
|  | } | 
|  | return Found; | 
|  | } | 
|  |  | 
|  | InstMIPS32Label::InstMIPS32Label(Cfg *Func, TargetMIPS32 *Target) | 
|  | : InstMIPS32(Func, InstMIPS32::Label, 0, nullptr), | 
|  | Number(Target->makeNextLabelNumber()) { | 
|  | if (BuildDefs::dump()) { | 
|  | Name = GlobalString::createWithString( | 
|  | Func->getContext(), | 
|  | ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number)); | 
|  | } else { | 
|  | Name = GlobalString::createWithoutString(Func->getContext()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void InstMIPS32Label::dump(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrDump(); | 
|  | Str << getLabelName() << ":"; | 
|  | } | 
|  |  | 
|  | void InstMIPS32Label::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | Str << getLabelName() << ":"; | 
|  | } | 
|  |  | 
|  | void InstMIPS32Label::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->bindLocalLabel(this, Number); | 
|  | } | 
|  |  | 
|  | InstMIPS32Call::InstMIPS32Call(Cfg *Func, Variable *Dest, Operand *CallTarget) | 
|  | : InstMIPS32(Func, InstMIPS32::Call, 1, Dest) { | 
|  | HasSideEffects = true; | 
|  | addSource(CallTarget); | 
|  | } | 
|  |  | 
|  | InstMIPS32Mov::InstMIPS32Mov(Cfg *Func, Variable *Dest, Operand *Src, | 
|  | Operand *Src2) | 
|  | : InstMIPS32(Func, InstMIPS32::Mov, 2, Dest) { | 
|  | auto *Dest64 = llvm::dyn_cast<Variable64On32>(Dest); | 
|  | auto *Src64 = llvm::dyn_cast<Variable64On32>(Src); | 
|  |  | 
|  | assert(Dest64 == nullptr || Src64 == nullptr); | 
|  |  | 
|  | if (Dest->getType() == IceType_f64 && Src2 != nullptr) { | 
|  | addSource(Src); | 
|  | addSource(Src2); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (Dest64 != nullptr) { | 
|  | // this-> is needed below because there is a parameter named Dest. | 
|  | this->Dest = Dest64->getLo(); | 
|  | DestHi = Dest64->getHi(); | 
|  | } | 
|  |  | 
|  | if (Src64 == nullptr) { | 
|  | addSource(Src); | 
|  | } else { | 
|  | addSource(Src64->getLo()); | 
|  | addSource(Src64->getHi()); | 
|  | } | 
|  | } | 
|  |  | 
|  | InstMIPS32MovFP64ToI64::InstMIPS32MovFP64ToI64(Cfg *Func, Variable *Dst, | 
|  | Operand *Src, | 
|  | Int64Part Int64HiLo) | 
|  | : InstMIPS32(Func, InstMIPS32::Mov_fp, 1, Dst), Int64HiLo(Int64HiLo) { | 
|  | addSource(Src); | 
|  | } | 
|  |  | 
|  | InstMIPS32Ret::InstMIPS32Ret(Cfg *Func, Variable *RA, Variable *Source) | 
|  | : InstMIPS32(Func, InstMIPS32::Ret, Source ? 2 : 1, nullptr) { | 
|  | addSource(RA); | 
|  | if (Source) | 
|  | addSource(Source); | 
|  | } | 
|  |  | 
|  | // ======================== Dump routines ======================== // | 
|  |  | 
|  | void InstMIPS32::dump(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrDump(); | 
|  | Str << "[MIPS32] "; | 
|  | Inst::dump(Func); | 
|  | } | 
|  |  | 
|  | void OperandMIPS32Mem::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | Operand *Offset = getOffset(); | 
|  | if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Offset)) { | 
|  | Str << "("; | 
|  | CR->emitWithoutPrefix(Func->getTarget()); | 
|  | Str << ")"; | 
|  | } else | 
|  | Offset->emit(Func); | 
|  | Str << "("; | 
|  | getBase()->emit(Func); | 
|  | Str << ")"; | 
|  | } | 
|  |  | 
|  | void InstMIPS32::emitUnaryopGPR(const char *Opcode, const InstMIPS32 *Inst, | 
|  | const Cfg *Func) { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | Str << "\t" << Opcode << "\t"; | 
|  | Inst->getDest()->emit(Func); | 
|  | Str << ", "; | 
|  | Inst->getSrc(0)->emit(Func); | 
|  | } | 
|  | void InstMIPS32::emitUnaryopGPRFLoHi(const char *Opcode, const InstMIPS32 *Inst, | 
|  | const Cfg *Func) { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | Str << "\t" << Opcode << "\t"; | 
|  | Inst->getDest()->emit(Func); | 
|  | } | 
|  |  | 
|  | void InstMIPS32::emitUnaryopGPRTLoHi(const char *Opcode, const InstMIPS32 *Inst, | 
|  | const Cfg *Func) { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | Str << "\t" << Opcode << "\t"; | 
|  | Inst->getSrc(0)->emit(Func); | 
|  | } | 
|  |  | 
|  | void InstMIPS32::emitThreeAddr(const char *Opcode, const InstMIPS32 *Inst, | 
|  | const Cfg *Func) { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | assert(Inst->getSrcSize() == 2); | 
|  | Str << "\t" << Opcode << "\t"; | 
|  | Inst->getDest()->emit(Func); | 
|  | Str << ", "; | 
|  | Inst->getSrc(0)->emit(Func); | 
|  | Str << ", "; | 
|  | Inst->getSrc(1)->emit(Func); | 
|  | } | 
|  |  | 
|  | void InstMIPS32::emitTwoAddr(const char *Opcode, const InstMIPS32 *Inst, | 
|  | const Cfg *Func) { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | assert(Inst->getSrcSize() == 1); | 
|  | Str << "\t" << Opcode << "\t"; | 
|  | Inst->getDest()->emit(Func); | 
|  | Str << ", "; | 
|  | Inst->getSrc(0)->emit(Func); | 
|  | } | 
|  |  | 
|  | void InstMIPS32::emitThreeAddrLoHi(const char *Opcode, const InstMIPS32 *Inst, | 
|  | const Cfg *Func) { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | assert(Inst->getSrcSize() == 2); | 
|  | Str << "\t" << Opcode << "\t"; | 
|  | Inst->getSrc(0)->emit(Func); | 
|  | Str << ", "; | 
|  | Inst->getSrc(1)->emit(Func); | 
|  | } | 
|  |  | 
|  | void InstMIPS32Ret::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | assert(getSrcSize() > 0); | 
|  | auto *RA = llvm::cast<Variable>(getSrc(0)); | 
|  | assert(RA->hasReg()); | 
|  | assert(RA->getRegNum() == RegMIPS32::Reg_RA); | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | Str << "\t" | 
|  | "jr" | 
|  | "\t"; | 
|  | RA->emit(Func); | 
|  | } | 
|  |  | 
|  | void InstMIPS32Br::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | if (Label != nullptr) { | 
|  | // Intra-block branches are of kind bcc | 
|  | if (isUnconditionalBranch()) { | 
|  | Asm->b(Asm->getOrCreateLocalLabel(Label->getNumber())); | 
|  | } else { | 
|  | Asm->bcc(Predicate, getSrc(0), getSrc(1), | 
|  | Asm->getOrCreateLocalLabel(Label->getNumber())); | 
|  | } | 
|  | } else if (isUnconditionalBranch()) { | 
|  | Asm->b(Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex())); | 
|  | } else { | 
|  | switch (Predicate) { | 
|  | default: | 
|  | break; | 
|  | case CondMIPS32::EQ: | 
|  | case CondMIPS32::NE: | 
|  | Asm->bcc(Predicate, getSrc(0), getSrc(1), | 
|  | Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex())); | 
|  | break; | 
|  | case CondMIPS32::EQZ: | 
|  | case CondMIPS32::NEZ: | 
|  | case CondMIPS32::LEZ: | 
|  | case CondMIPS32::LTZ: | 
|  | case CondMIPS32::GEZ: | 
|  | case CondMIPS32::GTZ: | 
|  | Asm->bzc(Predicate, getSrc(0), | 
|  | Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex())); | 
|  | break; | 
|  | } | 
|  | if (getTargetTrue()) { | 
|  | Asm->b(Asm->getOrCreateCfgNodeLabel(getTargetTrue()->getIndex())); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void InstMIPS32Br::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | Str << "\t" | 
|  | "b" << InstMIPS32CondAttributes[Predicate].EmitString << "\t"; | 
|  | if (Label != nullptr) { | 
|  | if (isUnconditionalBranch()) { | 
|  | Str << Label->getLabelName(); | 
|  | } else { | 
|  | getSrc(0)->emit(Func); | 
|  | Str << ", "; | 
|  | getSrc(1)->emit(Func); | 
|  | Str << ", " << Label->getLabelName(); | 
|  | } | 
|  | } else { | 
|  | if (isUnconditionalBranch()) { | 
|  | Str << getTargetFalse()->getAsmName(); | 
|  | } else { | 
|  | switch (Predicate) { | 
|  | default: | 
|  | break; | 
|  | case CondMIPS32::EQ: | 
|  | case CondMIPS32::NE: { | 
|  | getSrc(0)->emit(Func); | 
|  | Str << ", "; | 
|  | getSrc(1)->emit(Func); | 
|  | Str << ", "; | 
|  | break; | 
|  | } | 
|  | case CondMIPS32::EQZ: | 
|  | case CondMIPS32::NEZ: | 
|  | case CondMIPS32::LEZ: | 
|  | case CondMIPS32::LTZ: | 
|  | case CondMIPS32::GEZ: | 
|  | case CondMIPS32::GTZ: { | 
|  | getSrc(0)->emit(Func); | 
|  | Str << ", "; | 
|  | break; | 
|  | } | 
|  | } | 
|  | Str << getTargetFalse()->getAsmName(); | 
|  | if (getTargetTrue()) { | 
|  | Str << "\n\t" | 
|  | << "b" | 
|  | << "\t" << getTargetTrue()->getAsmName(); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void InstMIPS32Br::dump(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrDump(); | 
|  | Str << "\t" | 
|  | "b" << InstMIPS32CondAttributes[Predicate].EmitString << "\t"; | 
|  |  | 
|  | if (Label != nullptr) { | 
|  | if (isUnconditionalBranch()) { | 
|  | Str << Label->getLabelName(); | 
|  | } else { | 
|  | getSrc(0)->dump(Func); | 
|  | Str << ", "; | 
|  | getSrc(1)->dump(Func); | 
|  | Str << ", " << Label->getLabelName(); | 
|  | } | 
|  | } else { | 
|  | if (isUnconditionalBranch()) { | 
|  | Str << getTargetFalse()->getAsmName(); | 
|  | } else { | 
|  | dumpSources(Func); | 
|  | Str << ", "; | 
|  | Str << getTargetFalse()->getAsmName(); | 
|  | if (getTargetTrue()) { | 
|  | Str << "\n\t" | 
|  | << "b" | 
|  | << "\t" << getTargetTrue()->getAsmName(); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void InstMIPS32Call::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | assert(getSrcSize() == 1); | 
|  | if (llvm::isa<ConstantInteger32>(getCallTarget())) { | 
|  | // This shouldn't happen (typically have to copy the full 32-bits to a | 
|  | // register and do an indirect jump). | 
|  | llvm::report_fatal_error("MIPS2Call to ConstantInteger32"); | 
|  | } else if (const auto *CallTarget = | 
|  | llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { | 
|  | // Calls only have 26-bits, but the linker should insert veneers to extend | 
|  | // the range if needed. | 
|  | Str << "\t" | 
|  | "jal" | 
|  | "\t"; | 
|  | CallTarget->emitWithoutPrefix(Func->getTarget()); | 
|  | } else { | 
|  | Str << "\t" | 
|  | "jalr" | 
|  | "\t"; | 
|  | getCallTarget()->emit(Func); | 
|  | } | 
|  | } | 
|  |  | 
|  | void InstMIPS32Call::emitIAS(const Cfg *Func) const { | 
|  | assert(getSrcSize() == 1); | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | if (llvm::isa<ConstantInteger32>(getCallTarget())) { | 
|  | llvm::report_fatal_error("MIPS32Call to ConstantInteger32"); | 
|  | } else if (const auto *CallTarget = | 
|  | llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { | 
|  | Asm->jal(CallTarget); | 
|  | } else { | 
|  | const Operand *ImplicitRA = nullptr; | 
|  | Asm->jalr(getCallTarget(), ImplicitRA); | 
|  | } | 
|  | } | 
|  |  | 
|  | void InstMIPS32Call::dump(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrDump(); | 
|  | if (getDest()) { | 
|  | dumpDest(Func); | 
|  | Str << " = "; | 
|  | } | 
|  | Str << "call "; | 
|  | getCallTarget()->dump(Func); | 
|  | } | 
|  |  | 
|  | void InstMIPS32Ret::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | auto *RA = llvm::cast<Variable>(getSrc(0)); | 
|  | assert(RA->hasReg()); | 
|  | assert(RA->getRegNum() == RegMIPS32::Reg_RA); | 
|  | (void)RA; | 
|  | Asm->ret(); | 
|  | } | 
|  |  | 
|  | void InstMIPS32Ret::dump(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrDump(); | 
|  | Type Ty = (getSrcSize() == 1 ? IceType_void : getSrc(0)->getType()); | 
|  | Str << "ret." << Ty << " "; | 
|  | dumpSources(Func); | 
|  | } | 
|  |  | 
|  | void InstMIPS32Mov::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  |  | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | Variable *Dest = getDest(); | 
|  | Operand *Src = getSrc(0); | 
|  | auto *SrcV = llvm::dyn_cast<Variable>(Src); | 
|  |  | 
|  | assert(!llvm::isa<Constant>(Src)); | 
|  |  | 
|  | const char *ActualOpcode = nullptr; | 
|  | const bool DestIsReg = Dest->hasReg(); | 
|  | const bool SrcIsReg = (SrcV && SrcV->hasReg()); | 
|  |  | 
|  | // reg to reg | 
|  | if (DestIsReg && SrcIsReg) { | 
|  | const Type DstType = Dest->getType(); | 
|  | const Type SrcType = Src->getType(); | 
|  |  | 
|  | // move GP to/from FP | 
|  | if ((isScalarIntegerType(DstType) && isScalarFloatingType(SrcType)) || | 
|  | (isScalarFloatingType(DstType) && isScalarIntegerType(SrcType))) { | 
|  | if (isScalarFloatingType(DstType)) { | 
|  | Str << "\t" | 
|  | "mtc1" | 
|  | "\t"; | 
|  | getSrc(0)->emit(Func); | 
|  | Str << ", "; | 
|  | getDest()->emit(Func); | 
|  | return; | 
|  | } | 
|  | ActualOpcode = "mfc1"; | 
|  | } else { | 
|  | switch (Dest->getType()) { | 
|  | case IceType_f32: | 
|  | ActualOpcode = "mov.s"; | 
|  | break; | 
|  | case IceType_f64: | 
|  | ActualOpcode = "mov.d"; | 
|  | break; | 
|  | case IceType_i1: | 
|  | case IceType_i8: | 
|  | case IceType_i16: | 
|  | case IceType_i32: | 
|  | ActualOpcode = "move"; | 
|  | break; | 
|  | default: | 
|  | UnimplementedError(getFlags()); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | assert(ActualOpcode); | 
|  | Str << "\t" << ActualOpcode << "\t"; | 
|  | getDest()->emit(Func); | 
|  | Str << ", "; | 
|  | getSrc(0)->emit(Func); | 
|  | return; | 
|  | } | 
|  |  | 
|  | llvm::report_fatal_error("Invalid mov instruction. Dest or Src is memory."); | 
|  | } | 
|  |  | 
|  | void InstMIPS32Mov::emitIAS(const Cfg *Func) const { | 
|  | Variable *Dest = getDest(); | 
|  | Operand *Src = getSrc(0); | 
|  | auto *SrcV = llvm::dyn_cast<Variable>(Src); | 
|  | assert(!llvm::isa<Constant>(Src)); | 
|  | const bool DestIsReg = Dest->hasReg(); | 
|  | const bool SrcIsReg = (SrcV && SrcV->hasReg()); | 
|  |  | 
|  | // reg to reg | 
|  | if (DestIsReg && SrcIsReg) { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->move(getDest(), getSrc(0)); | 
|  | return; | 
|  | } | 
|  |  | 
|  | llvm::report_fatal_error("InstMIPS32Mov invalid operands"); | 
|  | } | 
|  |  | 
|  | void InstMIPS32Mov::dump(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | assert(getSrcSize() == 1 || getSrcSize() == 2); | 
|  | Ostream &Str = Func->getContext()->getStrDump(); | 
|  | Variable *Dest = getDest(); | 
|  | Variable *DestHi = getDestHi(); | 
|  | Dest->dump(Func); | 
|  | if (DestHi) { | 
|  | Str << ", "; | 
|  | DestHi->dump(Func); | 
|  | } | 
|  | dumpOpcode(Str, " = mov", getDest()->getType()); | 
|  | Str << " "; | 
|  | dumpSources(Func); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Abs_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->abs_d(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Abs_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->abs_s(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Addi::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->addi(getDest(), getSrc(0), Imm); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Add_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->add_d(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Add_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->add_s(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Addiu::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | if (Reloc == RO_No) { | 
|  | Asm->addiu(getDest(), getSrc(0), Imm); | 
|  | } else { | 
|  | Asm->addiu(getDest(), getSrc(0), getSrc(1), Reloc); | 
|  | } | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Addu::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->addu(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32And::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->and_(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Andi::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->andi(getDest(), getSrc(0), Imm); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_eq_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_eq_d(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_eq_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_eq_s(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_ole_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_ole_d(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_ole_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_ole_s(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_olt_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_olt_d(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_olt_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_olt_s(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_ueq_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_ueq_d(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_ueq_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_ueq_s(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_ule_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_ule_d(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_ule_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_ule_s(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_ult_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_ult_d(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_ult_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_ult_s(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_un_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_un_d(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32C_un_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->c_un_s(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Clz::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->clz(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Cvt_d_l::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->cvt_d_l(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Cvt_d_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->cvt_d_s(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Cvt_d_w::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->cvt_d_w(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Cvt_s_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->cvt_s_d(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Cvt_s_l::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->cvt_s_l(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Cvt_s_w::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->cvt_s_w(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Div::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->div(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Div_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->div_d(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Div_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->div_s(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Divu::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->divu(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Lui::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->lui(getDest(), getSrc(0), Reloc); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Ldc1::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(0)); | 
|  | Asm->ldc1(getDest(), Mem->getBase(), Mem->getOffset(), Reloc); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Ll::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(0)); | 
|  | ConstantInteger32 *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset()); | 
|  | uint32_t Imm = static_cast<uint32_t>(Offset->getValue()); | 
|  | Asm->ll(getDest(), Mem->getBase(), Imm); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Lw::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(0)); | 
|  | ConstantInteger32 *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset()); | 
|  | uint32_t Imm = static_cast<uint32_t>(Offset->getValue()); | 
|  | Asm->lw(getDest(), Mem->getBase(), Imm); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Lwc1::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(0)); | 
|  | Asm->lwc1(getDest(), Mem->getBase(), Mem->getOffset(), Reloc); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mfc1::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->mfc1(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mflo::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | emitUnaryopGPRFLoHi(Opcode, this, Func); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mflo::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->mflo(getDest()); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mfhi::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | emitUnaryopGPRFLoHi(Opcode, this, Func); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mfhi::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->mfhi(getDest()); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mov_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->mov_d(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mov_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->mov_s(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Movf::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->movf(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Movn::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->movn(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Movn_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->movn_d(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Movn_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->movn_s(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Movt::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->movt(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Movz::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->movz(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Movz_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->movz_d(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Movz_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->movz_s(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mtc1::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Func->getContext()->getStrEmit(); | 
|  | assert(getSrcSize() == 1); | 
|  | Str << "\t" << Opcode << "\t"; | 
|  | getSrc(0)->emit(Func); | 
|  | Str << ", "; | 
|  | getDest()->emit(Func); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mtc1::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->mtc1(getSrc(0), getDest()); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mtlo::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | emitUnaryopGPRTLoHi(Opcode, this, Func); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mtlo::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->mtlo(getDest()); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mthi::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | emitUnaryopGPRTLoHi(Opcode, this, Func); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mthi::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->mthi(getDest()); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mul::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->mul(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mul_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->mul_d(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mul_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->mul_s(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mult::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | emitThreeAddrLoHi(Opcode, this, Func); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Mult::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->mult(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Multu::emit(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | emitThreeAddrLoHi(Opcode, this, Func); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Multu::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->multu(getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Nor::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->nor(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Or::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->or_(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Ori::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->ori(getDest(), getSrc(0), Imm); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Sc::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(1)); | 
|  | ConstantInteger32 *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset()); | 
|  | uint32_t Imm = static_cast<uint32_t>(Offset->getValue()); | 
|  | Asm->sc(getSrc(0), Mem->getBase(), Imm); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Sll::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->sll(getDest(), getSrc(0), Imm); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Sllv::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->sllv(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Slt::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->slt(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Slti::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->slti(getDest(), getSrc(0), Imm); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Sltiu::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->sltiu(getDest(), getSrc(0), Imm); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Sltu::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->sltu(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Sqrt_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->sqrt_d(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Sqrt_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->sqrt_s(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Sra::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->sra(getDest(), getSrc(0), Imm); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Srav::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->srav(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Srl::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->srl(getDest(), getSrc(0), Imm); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Srlv::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->srlv(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Sub_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->sub_d(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Sub_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->sub_s(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Subu::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->subu(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Sdc1::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(0)); | 
|  | Asm->sdc1(getSrc(0), Mem->getBase(), Mem->getOffset(), Reloc); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Sw::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(1)); | 
|  | ConstantInteger32 *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset()); | 
|  | uint32_t Imm = static_cast<uint32_t>(Offset->getValue()); | 
|  | Asm->sw(getSrc(0), Mem->getBase(), Imm); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Swc1::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(0)); | 
|  | Asm->swc1(getSrc(0), Mem->getBase(), Mem->getOffset(), Reloc); | 
|  | } | 
|  |  | 
|  | void InstMIPS32Sync::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->sync(); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Teq::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->teq(getSrc(0), getSrc(1), getTrapCode()); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Trunc_l_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->trunc_l_d(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Trunc_l_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->trunc_l_s(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Trunc_w_d::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->trunc_w_d(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Trunc_w_s::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->trunc_w_s(getDest(), getSrc(0)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Xor::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->xor_(getDest(), getSrc(0), getSrc(1)); | 
|  | } | 
|  |  | 
|  | template <> void InstMIPS32Xori::emitIAS(const Cfg *Func) const { | 
|  | auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); | 
|  | Asm->xori(getDest(), getSrc(0), Imm); | 
|  | } | 
|  |  | 
|  | } // end of namespace MIPS32 | 
|  | } // end of namespace Ice |