|  | //===- subzero/src/IceTargetLoweringMIPS32.h - MIPS32 lowering ---*- 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 TargetLoweringMIPS32 class, which implements the | 
|  | /// TargetLowering interface for the MIPS 32-bit architecture. | 
|  | /// | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef SUBZERO_SRC_ICETARGETLOWERINGMIPS32_H | 
|  | #define SUBZERO_SRC_ICETARGETLOWERINGMIPS32_H | 
|  |  | 
|  | #include "IceAssemblerMIPS32.h" | 
|  | #include "IceDefs.h" | 
|  | #include "IceInstMIPS32.h" | 
|  | #include "IceRegistersMIPS32.h" | 
|  | #include "IceTargetLowering.h" | 
|  |  | 
|  | namespace Ice { | 
|  | namespace MIPS32 { | 
|  |  | 
|  | class TargetMIPS32 : public TargetLowering { | 
|  | TargetMIPS32() = delete; | 
|  | TargetMIPS32(const TargetMIPS32 &) = delete; | 
|  | TargetMIPS32 &operator=(const TargetMIPS32 &) = delete; | 
|  |  | 
|  | public: | 
|  | ~TargetMIPS32() override = default; | 
|  |  | 
|  | static void staticInit(GlobalContext *Ctx); | 
|  | static bool shouldBePooled(const Constant *C) { | 
|  | (void)C; | 
|  | return false; | 
|  | } | 
|  | static std::unique_ptr<::Ice::TargetLowering> create(Cfg *Func) { | 
|  | return makeUnique<TargetMIPS32>(Func); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<::Ice::Assembler> createAssembler() const override { | 
|  | return makeUnique<MIPS32::AssemblerMIPS32>(); | 
|  | } | 
|  |  | 
|  | void initNodeForLowering(CfgNode *Node) override { | 
|  | Computations.forgetProducers(); | 
|  | Computations.recordProducers(Node); | 
|  | Computations.dump(Func); | 
|  | } | 
|  |  | 
|  | void translateOm1() override; | 
|  | void translateO2() override; | 
|  | bool doBranchOpt(Inst *Instr, const CfgNode *NextNode) override; | 
|  |  | 
|  | SizeT getNumRegisters() const override { return RegMIPS32::Reg_NUM; } | 
|  | Variable *getPhysicalRegister(RegNumT RegNum, | 
|  | Type Ty = IceType_void) override; | 
|  | const char *getRegName(RegNumT RegNum, Type Ty) const override; | 
|  | SmallBitVector getRegisterSet(RegSetMask Include, | 
|  | RegSetMask Exclude) const override; | 
|  | const SmallBitVector & | 
|  | getRegistersForVariable(const Variable *Var) const override { | 
|  | RegClass RC = Var->getRegClass(); | 
|  | assert(RC < RC_Target); | 
|  | return TypeToRegisterSet[RC]; | 
|  | } | 
|  | const SmallBitVector & | 
|  | getAllRegistersForVariable(const Variable *Var) const override { | 
|  | RegClass RC = Var->getRegClass(); | 
|  | assert(RC < RC_Target); | 
|  | return TypeToRegisterSetUnfiltered[RC]; | 
|  | } | 
|  | const SmallBitVector &getAliasesForRegister(RegNumT Reg) const override { | 
|  | return RegisterAliases[Reg]; | 
|  | } | 
|  | bool hasFramePointer() const override { return UsesFramePointer; } | 
|  | void setHasFramePointer() override { UsesFramePointer = true; } | 
|  | RegNumT getStackReg() const override { return RegMIPS32::Reg_SP; } | 
|  | RegNumT getFrameReg() const override { return RegMIPS32::Reg_FP; } | 
|  | RegNumT getFrameOrStackReg() const override { | 
|  | return UsesFramePointer ? getFrameReg() : getStackReg(); | 
|  | } | 
|  | size_t typeWidthInBytesOnStack(Type Ty) const override { | 
|  | // Round up to the next multiple of 4 bytes. In particular, i1, i8, and i16 | 
|  | // are rounded up to 4 bytes. | 
|  | return (typeWidthInBytes(Ty) + 3) & ~3; | 
|  | } | 
|  | uint32_t getStackAlignment() const override; | 
|  | void reserveFixedAllocaArea(size_t Size, size_t Align) override { | 
|  | FixedAllocaSizeBytes = Size; | 
|  | assert(llvm::isPowerOf2_32(Align)); | 
|  | FixedAllocaAlignBytes = Align; | 
|  | PrologEmitsFixedAllocas = true; | 
|  | } | 
|  | int32_t getFrameFixedAllocaOffset() const override { | 
|  | // TODO(sehr): Implement fixed stack layout. | 
|  | llvm::report_fatal_error("Not yet implemented"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | uint32_t maxOutArgsSizeBytes() const override { return MaxOutArgsSizeBytes; } | 
|  |  | 
|  | bool shouldSplitToVariable64On32(Type Ty) const override { | 
|  | return Ty == IceType_i64; | 
|  | } | 
|  |  | 
|  | // TODO(ascull): what is the best size of MIPS? | 
|  | SizeT getMinJumpTableSize() const override { return 3; } | 
|  | void emitJumpTable(const Cfg *Func, | 
|  | const InstJumpTable *JumpTable) const override; | 
|  |  | 
|  | void emitVariable(const Variable *Var) const override; | 
|  |  | 
|  | void emit(const ConstantInteger32 *C) const final { | 
|  | if (!BuildDefs::dump()) | 
|  | return; | 
|  | Ostream &Str = Ctx->getStrEmit(); | 
|  | Str << C->getValue(); | 
|  | } | 
|  | void emit(const ConstantInteger64 *C) const final { | 
|  | (void)C; | 
|  | llvm::report_fatal_error("Not yet implemented"); | 
|  | } | 
|  | void emit(const ConstantFloat *C) const final { | 
|  | (void)C; | 
|  | llvm::report_fatal_error("Not yet implemented"); | 
|  | } | 
|  | void emit(const ConstantDouble *C) const final { | 
|  | (void)C; | 
|  | llvm::report_fatal_error("Not yet implemented"); | 
|  | } | 
|  | void emit(const ConstantUndef *C) const final { | 
|  | (void)C; | 
|  | llvm::report_fatal_error("Not yet implemented"); | 
|  | } | 
|  | void emit(const ConstantRelocatable *C) const final { | 
|  | (void)C; | 
|  | llvm::report_fatal_error("Not yet implemented"); | 
|  | } | 
|  |  | 
|  | // The following are helpers that insert lowered MIPS32 instructions with | 
|  | // minimal syntactic overhead, so that the lowering code can look as close to | 
|  | // assembly as practical. | 
|  | void _add(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Add>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _addu(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Addu>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _and(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32And>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _andi(Variable *Dest, Variable *Src, uint32_t Imm) { | 
|  | Context.insert<InstMIPS32Andi>(Dest, Src, Imm); | 
|  | } | 
|  |  | 
|  | void _br(CfgNode *Target) { Context.insert<InstMIPS32Br>(Target); } | 
|  |  | 
|  | void _br(CfgNode *TargetTrue, CfgNode *TargetFalse, Operand *Src0, | 
|  | Operand *Src1, CondMIPS32::Cond Condition) { | 
|  | Context.insert<InstMIPS32Br>(TargetTrue, TargetFalse, Src0, Src1, | 
|  | Condition); | 
|  | } | 
|  |  | 
|  | void _br(CfgNode *TargetTrue, CfgNode *TargetFalse, Operand *Src0, | 
|  | CondMIPS32::Cond Condition) { | 
|  | Context.insert<InstMIPS32Br>(TargetTrue, TargetFalse, Src0, Condition); | 
|  | } | 
|  |  | 
|  | void _ret(Variable *RA, Variable *Src0 = nullptr) { | 
|  | Context.insert<InstMIPS32Ret>(RA, Src0); | 
|  | } | 
|  |  | 
|  | void _add_d(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Add_d>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _add_s(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Add_s>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _addiu(Variable *Dest, Variable *Src, uint32_t Imm) { | 
|  | Context.insert<InstMIPS32Addiu>(Dest, Src, Imm); | 
|  | } | 
|  |  | 
|  | void _cvt_d_l(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Cvt_d_l>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _cvt_d_s(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Cvt_d_s>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _cvt_d_w(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Cvt_d_w>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _cvt_s_d(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Cvt_s_d>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _cvt_s_l(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Cvt_s_l>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _cvt_s_w(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Cvt_s_w>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _div(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Div>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _div_d(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Div_d>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _div_s(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Div_s>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _divu(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Divu>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _ldc1(Variable *Value, OperandMIPS32Mem *Mem) { | 
|  | Context.insert<InstMIPS32Ldc1>(Value, Mem); | 
|  | } | 
|  |  | 
|  | void _lw(Variable *Value, OperandMIPS32Mem *Mem) { | 
|  | Context.insert<InstMIPS32Lw>(Value, Mem); | 
|  | } | 
|  |  | 
|  | void _lwc1(Variable *Value, OperandMIPS32Mem *Mem) { | 
|  | Context.insert<InstMIPS32Lwc1>(Value, Mem); | 
|  | } | 
|  |  | 
|  | void _lui(Variable *Dest, uint32_t Imm) { | 
|  | Context.insert<InstMIPS32Lui>(Dest, Imm); | 
|  | } | 
|  |  | 
|  | void _mov(Variable *Dest, Operand *Src0) { | 
|  | assert(Dest != nullptr); | 
|  | // Variable* Src0_ = llvm::dyn_cast<Variable>(Src0); | 
|  | if (llvm::isa<ConstantRelocatable>(Src0)) { | 
|  | Context.insert<InstMIPS32La>(Dest, Src0); | 
|  | } else { | 
|  | auto *Instr = Context.insert<InstMIPS32Mov>(Dest, Src0); | 
|  | if (Instr->isMultiDest()) { | 
|  | // If Instr is multi-dest, then Dest must be a Variable64On32. We add a | 
|  | // fake-def for Instr.DestHi here. | 
|  | assert(llvm::isa<Variable64On32>(Dest)); | 
|  | Context.insert<InstFakeDef>(Instr->getDestHi()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void _mov_d(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Mov_d>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _mov_s(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Mov_s>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _mfc1(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Mfc1>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _mfhi(Variable *Dest, Operand *Src) { | 
|  | Context.insert<InstMIPS32Mfhi>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _mflo(Variable *Dest, Operand *Src) { | 
|  | Context.insert<InstMIPS32Mflo>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _mtc1(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Mtc1>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _mthi(Variable *Dest, Operand *Src) { | 
|  | Context.insert<InstMIPS32Mthi>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _mtlo(Variable *Dest, Operand *Src) { | 
|  | Context.insert<InstMIPS32Mtlo>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _mul(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Mul>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _mul_d(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Mul_d>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _mul_s(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Mul_s>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _mult(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Mult>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _multu(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Multu>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _or(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Or>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _ori(Variable *Dest, Variable *Src, uint32_t Imm) { | 
|  | Context.insert<InstMIPS32Ori>(Dest, Src, Imm); | 
|  | } | 
|  |  | 
|  | void _sdc1(Variable *Value, OperandMIPS32Mem *Mem) { | 
|  | Context.insert<InstMIPS32Sdc1>(Value, Mem); | 
|  | } | 
|  |  | 
|  | void _sll(Variable *Dest, Variable *Src, uint32_t Imm) { | 
|  | Context.insert<InstMIPS32Sll>(Dest, Src, Imm); | 
|  | } | 
|  |  | 
|  | void _sllv(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Sllv>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _slt(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Slt>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _slti(Variable *Dest, Variable *Src, uint32_t Imm) { | 
|  | Context.insert<InstMIPS32Slti>(Dest, Src, Imm); | 
|  | } | 
|  |  | 
|  | void _sltiu(Variable *Dest, Variable *Src, uint32_t Imm) { | 
|  | Context.insert<InstMIPS32Sltiu>(Dest, Src, Imm); | 
|  | } | 
|  |  | 
|  | void _sltu(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Sltu>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _sra(Variable *Dest, Variable *Src, uint32_t Imm) { | 
|  | Context.insert<InstMIPS32Sra>(Dest, Src, Imm); | 
|  | } | 
|  |  | 
|  | void _srav(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Srav>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _srl(Variable *Dest, Variable *Src, uint32_t Imm) { | 
|  | Context.insert<InstMIPS32Srl>(Dest, Src, Imm); | 
|  | } | 
|  |  | 
|  | void _srlv(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Srlv>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _sub(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Sub>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _sub_d(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Sub_d>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _sub_s(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Sub_s>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _subu(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Subu>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _sw(Variable *Value, OperandMIPS32Mem *Mem) { | 
|  | Context.insert<InstMIPS32Sw>(Value, Mem); | 
|  | } | 
|  |  | 
|  | void _swc1(Variable *Value, OperandMIPS32Mem *Mem) { | 
|  | Context.insert<InstMIPS32Swc1>(Value, Mem); | 
|  | } | 
|  |  | 
|  | void _trunc_l_d(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Trunc_l_d>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _trunc_l_s(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Trunc_l_s>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _trunc_w_d(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Trunc_w_d>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _trunc_w_s(Variable *Dest, Variable *Src) { | 
|  | Context.insert<InstMIPS32Trunc_w_s>(Dest, Src); | 
|  | } | 
|  |  | 
|  | void _xor(Variable *Dest, Variable *Src0, Variable *Src1) { | 
|  | Context.insert<InstMIPS32Xor>(Dest, Src0, Src1); | 
|  | } | 
|  |  | 
|  | void _xori(Variable *Dest, Variable *Src, uint32_t Imm) { | 
|  | Context.insert<InstMIPS32Xori>(Dest, Src, Imm); | 
|  | } | 
|  |  | 
|  | void lowerArguments() override; | 
|  |  | 
|  | /// Operand legalization helpers.  To deal with address mode constraints, | 
|  | /// the helpers will create a new Operand and emit instructions that | 
|  | /// guarantee that the Operand kind is one of those indicated by the | 
|  | /// LegalMask (a bitmask of allowed kinds).  If the input Operand is known | 
|  | /// to already meet the constraints, it may be simply returned as the result, | 
|  | /// without creating any new instructions or operands. | 
|  | enum OperandLegalization { | 
|  | Legal_None = 0, | 
|  | Legal_Reg = 1 << 0, // physical register, not stack location | 
|  | Legal_Imm = 1 << 1, | 
|  | Legal_Mem = 1 << 2, | 
|  | Legal_Default = ~Legal_None | 
|  | }; | 
|  | typedef uint32_t LegalMask; | 
|  | Operand *legalize(Operand *From, LegalMask Allowed = Legal_Default, | 
|  | RegNumT RegNum = RegNumT()); | 
|  |  | 
|  | Variable *legalizeToVar(Operand *From, RegNumT RegNum = RegNumT()); | 
|  |  | 
|  | Variable *legalizeToReg(Operand *From, RegNumT RegNum = RegNumT()); | 
|  |  | 
|  | Variable *makeReg(Type Ty, RegNumT RegNum = RegNumT()); | 
|  |  | 
|  | Variable *getZero() { | 
|  | return getPhysicalRegister(RegMIPS32::Reg_ZERO, IceType_i32); | 
|  | } | 
|  |  | 
|  | Variable *I32Reg(RegNumT RegNum = RegNumT()) { | 
|  | return makeReg(IceType_i32, RegNum); | 
|  | } | 
|  |  | 
|  | static Type stackSlotType(); | 
|  | Variable *copyToReg(Operand *Src, RegNumT RegNum = RegNumT()); | 
|  |  | 
|  | void unsetIfNonLeafFunc(); | 
|  |  | 
|  | // Iterates over the CFG and determines the maximum outgoing stack arguments | 
|  | // bytes. This information is later used during addProlog() to pre-allocate | 
|  | // the outargs area | 
|  | void findMaxStackOutArgsSize(); | 
|  |  | 
|  | void addProlog(CfgNode *Node) override; | 
|  | void addEpilog(CfgNode *Node) override; | 
|  |  | 
|  | // Ensure that a 64-bit Variable has been split into 2 32-bit | 
|  | // Variables, creating them if necessary.  This is needed for all | 
|  | // I64 operations. | 
|  | void split64(Variable *Var); | 
|  | Operand *loOperand(Operand *Operand); | 
|  | Operand *hiOperand(Operand *Operand); | 
|  |  | 
|  | void finishArgumentLowering(Variable *Arg, Variable *FramePtr, | 
|  | size_t BasicFrameOffset, size_t *InArgsSizeBytes); | 
|  |  | 
|  | Operand *legalizeUndef(Operand *From, RegNumT RegNum = RegNumT()); | 
|  |  | 
|  | /// Helper class that understands the Calling Convention and register | 
|  | /// assignments as per MIPS O32 abi. | 
|  | class CallingConv { | 
|  | CallingConv(const CallingConv &) = delete; | 
|  | CallingConv &operator=(const CallingConv &) = delete; | 
|  |  | 
|  | public: | 
|  | CallingConv(); | 
|  | ~CallingConv() = default; | 
|  |  | 
|  | /// argInReg returns true if there is a Register available for the requested | 
|  | /// type, and false otherwise. If it returns true, Reg is set to the | 
|  | /// appropriate register number. Note that, when Ty == IceType_i64, Reg will | 
|  | /// be an I64 register pair. | 
|  | bool argInReg(Type Ty, uint32_t ArgNo, RegNumT *Reg); | 
|  |  | 
|  | private: | 
|  | // argInGPR is used to find if any GPR register is available for argument of | 
|  | // type Ty | 
|  | bool argInGPR(Type Ty, RegNumT *Reg); | 
|  | /// argInVFP is to floating-point/vector types what argInGPR is for integer | 
|  | /// types. | 
|  | bool argInVFP(Type Ty, RegNumT *Reg); | 
|  | inline void discardNextGPRAndItsAliases(CfgVector<RegNumT> *Regs); | 
|  | void discardUnavailableGPRsAndTheirAliases(CfgVector<RegNumT> *Regs); | 
|  | SmallBitVector GPRegsUsed; | 
|  | CfgVector<RegNumT> GPRArgs; | 
|  | CfgVector<RegNumT> I64Args; | 
|  |  | 
|  | void discardUnavailableVFPRegsAndTheirAliases(CfgVector<RegNumT> *Regs); | 
|  | SmallBitVector VFPRegsUsed; | 
|  | CfgVector<RegNumT> FP32Args; | 
|  | CfgVector<RegNumT> FP64Args; | 
|  | // UseFPRegs is a flag indicating if FP registers can be used | 
|  | bool UseFPRegs = false; | 
|  | }; | 
|  |  | 
|  | protected: | 
|  | explicit TargetMIPS32(Cfg *Func); | 
|  |  | 
|  | void postLower() override; | 
|  |  | 
|  | void lowerAlloca(const InstAlloca *Instr) override; | 
|  | void lowerArithmetic(const InstArithmetic *Instr) override; | 
|  | void lowerInt64Arithmetic(const InstArithmetic *Instr, Variable *Dest, | 
|  | Operand *Src0, Operand *Src1); | 
|  | void lowerAssign(const InstAssign *Instr) override; | 
|  | void lowerBr(const InstBr *Instr) override; | 
|  | void lowerBreakpoint(const InstBreakpoint *Instr) override; | 
|  | void lowerCall(const InstCall *Instr) override; | 
|  | void lowerCast(const InstCast *Instr) override; | 
|  | void lowerExtractElement(const InstExtractElement *Instr) override; | 
|  | void lowerFcmp(const InstFcmp *Instr) override; | 
|  | void lowerIcmp(const InstIcmp *Instr) override; | 
|  | void lower64Icmp(const InstIcmp *Instr); | 
|  | void lowerIntrinsicCall(const InstIntrinsicCall *Instr) override; | 
|  | void lowerInsertElement(const InstInsertElement *Instr) override; | 
|  | void lowerLoad(const InstLoad *Instr) override; | 
|  | void lowerPhi(const InstPhi *Instr) override; | 
|  | void lowerRet(const InstRet *Instr) override; | 
|  | void lowerSelect(const InstSelect *Instr) override; | 
|  | void lowerShuffleVector(const InstShuffleVector *Instr) override; | 
|  | void lowerStore(const InstStore *Instr) override; | 
|  | void lowerSwitch(const InstSwitch *Instr) override; | 
|  | void lowerUnreachable(const InstUnreachable *Instr) override; | 
|  | void prelowerPhis() override; | 
|  | uint32_t getCallStackArgumentsSizeBytes(const InstCall *Instr) override { | 
|  | (void)Instr; | 
|  | return 0; | 
|  | } | 
|  | void genTargetHelperCallFor(Inst *Instr) override { (void)Instr; } | 
|  | void doAddressOptLoad() override; | 
|  | void doAddressOptStore() override; | 
|  | void randomlyInsertNop(float Probability, | 
|  | RandomNumberGenerator &RNG) override; | 
|  | void | 
|  | makeRandomRegisterPermutation(llvm::SmallVectorImpl<RegNumT> &Permutation, | 
|  | const SmallBitVector &ExcludeRegisters, | 
|  | uint64_t Salt) const override; | 
|  |  | 
|  | OperandMIPS32Mem *formMemoryOperand(Operand *Ptr, Type Ty); | 
|  |  | 
|  | bool UsesFramePointer = false; | 
|  | bool NeedsStackAlignment = false; | 
|  | bool MaybeLeafFunc = true; | 
|  | bool PrologEmitsFixedAllocas = false; | 
|  | uint32_t MaxOutArgsSizeBytes = 0; | 
|  | uint32_t TotalStackSizeBytes = 0; | 
|  | static SmallBitVector TypeToRegisterSet[RCMIPS32_NUM]; | 
|  | static SmallBitVector TypeToRegisterSetUnfiltered[RCMIPS32_NUM]; | 
|  | static SmallBitVector RegisterAliases[RegMIPS32::Reg_NUM]; | 
|  | SmallBitVector RegsUsed; | 
|  | VarList PhysicalRegisters[IceType_NUM]; | 
|  | VarList PreservedGPRs; | 
|  | static constexpr uint32_t CHAR_BITS = 8; | 
|  | static constexpr uint32_t INT32_BITS = 32; | 
|  | size_t SpillAreaSizeBytes = 0; | 
|  | size_t FixedAllocaSizeBytes = 0; | 
|  | size_t FixedAllocaAlignBytes = 0; | 
|  | size_t PreservedRegsSizeBytes = 0; | 
|  |  | 
|  | private: | 
|  | ENABLE_MAKE_UNIQUE; | 
|  |  | 
|  | class ComputationTracker { | 
|  | public: | 
|  | ComputationTracker() = default; | 
|  | ~ComputationTracker() = default; | 
|  |  | 
|  | void forgetProducers() { KnownComputations.clear(); } | 
|  | void recordProducers(CfgNode *Node); | 
|  |  | 
|  | const Inst *getProducerOf(const Operand *Opnd) const { | 
|  | auto *Var = llvm::dyn_cast<Variable>(Opnd); | 
|  | if (Var == nullptr) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | auto Iter = KnownComputations.find(Var->getIndex()); | 
|  | if (Iter == KnownComputations.end()) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | return Iter->second.Instr; | 
|  | } | 
|  |  | 
|  | void dump(const Cfg *Func) const { | 
|  | if (!BuildDefs::dump() || !Func->isVerbose(IceV_Folding)) | 
|  | return; | 
|  | OstreamLocker L(Func->getContext()); | 
|  | Ostream &Str = Func->getContext()->getStrDump(); | 
|  | Str << "foldable producer:\n"; | 
|  | for (const auto &Computation : KnownComputations) { | 
|  | Str << "    "; | 
|  | Computation.second.Instr->dump(Func); | 
|  | Str << "\n"; | 
|  | } | 
|  | Str << "\n"; | 
|  | } | 
|  |  | 
|  | private: | 
|  | class ComputationEntry { | 
|  | public: | 
|  | ComputationEntry(Inst *I, Type Ty) : Instr(I), ComputationType(Ty) {} | 
|  | Inst *const Instr; | 
|  | // Boolean folding is disabled for variables whose live range is multi | 
|  | // block. We conservatively initialize IsLiveOut to true, and set it to | 
|  | // false once we find the end of the live range for the variable defined | 
|  | // by this instruction. If liveness analysis is not performed (e.g., in | 
|  | // Om1 mode) IsLiveOut will never be set to false, and folding will be | 
|  | // disabled. | 
|  | bool IsLiveOut = true; | 
|  | int32_t NumUses = 0; | 
|  | Type ComputationType; | 
|  | }; | 
|  |  | 
|  | // ComputationMap maps a Variable number to a payload identifying which | 
|  | // instruction defined it. | 
|  | using ComputationMap = CfgUnorderedMap<SizeT, ComputationEntry>; | 
|  | ComputationMap KnownComputations; | 
|  | }; | 
|  |  | 
|  | ComputationTracker Computations; | 
|  | }; | 
|  |  | 
|  | class TargetDataMIPS32 final : public TargetDataLowering { | 
|  | TargetDataMIPS32() = delete; | 
|  | TargetDataMIPS32(const TargetDataMIPS32 &) = delete; | 
|  | TargetDataMIPS32 &operator=(const TargetDataMIPS32 &) = delete; | 
|  |  | 
|  | public: | 
|  | static std::unique_ptr<TargetDataLowering> create(GlobalContext *Ctx) { | 
|  | return std::unique_ptr<TargetDataLowering>(new TargetDataMIPS32(Ctx)); | 
|  | } | 
|  |  | 
|  | void lowerGlobals(const VariableDeclarationList &Vars, | 
|  | const std::string &SectionSuffix) override; | 
|  | void lowerConstants() override; | 
|  | void lowerJumpTables() override; | 
|  |  | 
|  | protected: | 
|  | explicit TargetDataMIPS32(GlobalContext *Ctx); | 
|  |  | 
|  | private: | 
|  | ~TargetDataMIPS32() override = default; | 
|  | template <typename T> static void emitConstantPool(GlobalContext *Ctx); | 
|  | }; | 
|  |  | 
|  | class TargetHeaderMIPS32 final : public TargetHeaderLowering { | 
|  | TargetHeaderMIPS32() = delete; | 
|  | TargetHeaderMIPS32(const TargetHeaderMIPS32 &) = delete; | 
|  | TargetHeaderMIPS32 &operator=(const TargetHeaderMIPS32 &) = delete; | 
|  |  | 
|  | public: | 
|  | static std::unique_ptr<TargetHeaderLowering> create(GlobalContext *Ctx) { | 
|  | return std::unique_ptr<TargetHeaderLowering>(new TargetHeaderMIPS32(Ctx)); | 
|  | } | 
|  |  | 
|  | void lower() override; | 
|  |  | 
|  | protected: | 
|  | explicit TargetHeaderMIPS32(GlobalContext *Ctx); | 
|  |  | 
|  | private: | 
|  | ~TargetHeaderMIPS32() = default; | 
|  | }; | 
|  |  | 
|  | } // end of namespace MIPS32 | 
|  | } // end of namespace Ice | 
|  |  | 
|  | #endif // SUBZERO_SRC_ICETARGETLOWERINGMIPS32_H |