static void createFPFnStub(Function *F, Module *M, FPParamVariant PV, const MipsTargetMachine &TM) { bool PicMode = TM.getRelocationModel() == Reloc::PIC_; bool LE = TM.isLittleEndian(); LLVMContext &Context = M->getContext(); std::string Name = F->getName(); std::string SectionName = ".mips16.fn." + Name; std::string StubName = "__fn_stub_" + Name; std::string LocalName = "$$__fn_local_" + Name; Function *FStub = Function::Create (F->getFunctionType(), Function::InternalLinkage, StubName, M); FStub->addFnAttr("mips16_fp_stub"); FStub->addFnAttr(llvm::Attribute::Naked); FStub->addFnAttr(llvm::Attribute::NoUnwind); FStub->addFnAttr(llvm::Attribute::NoInline); FStub->addFnAttr("nomips16"); FStub->setSection(SectionName); BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub); InlineAsmHelper IAH(Context, BB); if (PicMode) { IAH.Out(".set noreorder"); IAH.Out(".cpload $$25"); IAH.Out(".set reorder"); IAH.Out(".reloc 0,R_MIPS_NONE," + Name); IAH.Out("la $$25," + LocalName); } else { IAH.Out("la $$25," + Name); } swapFPIntParams(PV, M, IAH, LE, false); IAH.Out("jr $$25"); IAH.Out(LocalName + " = " + Name); new UnreachableInst(FStub->getContext(), BB); }
MipsTargetAsmInfo::MipsTargetAsmInfo(const MipsTargetMachine &TM) { AlignmentIsInBytes = false; Data16bitsDirective = "\t.half\t"; Data32bitsDirective = "\t.word\t"; PrivateGlobalPrefix = "$"; JumpTableDataSection = "\t.rdata"; CommentString = "#"; ReadOnlySection = "\t.rdata"; ZeroDirective = "\t.space\t"; BSSSection = "\t.section\t.bss"; LCOMMDirective = "\t.lcomm\t"; if (TM.getRelocationModel() == Reloc::Static) JumpTableDirective = "\t.word\t"; else JumpTableDirective = "\t.gpword\t"; COMMDirectiveTakesAlignment = true; }
MipsSEInstrInfo::MipsSEInstrInfo(MipsTargetMachine &tm) : MipsInstrInfo(tm, tm.getRelocationModel() == Reloc::PIC_ ? Mips::B : Mips::J), RI(*tm.getSubtargetImpl()), IsN64(tm.getSubtarget<MipsSubtarget>().isABI_N64()) {}
// // Returns of float, double and complex need to be handled with a helper // function. // static bool fixupFPReturnAndCall(Function &F, Module *M, const MipsTargetMachine &TM) { bool Modified = false; LLVMContext &C = M->getContext(); Type *MyVoid = Type::getVoidTy(C); for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { Instruction &Inst = *I; if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) { Value *RVal = RI->getReturnValue(); if (!RVal) continue; // // If there is a return value and it needs a helper function, // figure out which one and add a call before the actual // return to this helper. The purpose of the helper is to move // floating point values from their soft float return mapping to // where they would have been mapped to in floating point registers. // Type *T = RVal->getType(); FPReturnVariant RV = whichFPReturnVariant(T); if (RV == NoFPRet) continue; static const char *const Helper[NoFPRet] = { "__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc", "__mips16_ret_dc" }; const char *Name = Helper[RV]; AttributeSet A; Value *Params[] = {RVal}; Modified = true; // // These helper functions have a different calling ABI so // this __Mips16RetHelper indicates that so that later // during call setup, the proper call lowering to the helper // functions will take place. // A = A.addAttribute(C, AttributeSet::FunctionIndex, "__Mips16RetHelper"); A = A.addAttribute(C, AttributeSet::FunctionIndex, Attribute::ReadNone); A = A.addAttribute(C, AttributeSet::FunctionIndex, Attribute::NoInline); Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, nullptr)); CallInst::Create(F, Params, "", &Inst ); } else if (const CallInst *CI = dyn_cast<CallInst>(I)) { const Value* V = CI->getCalledValue(); Type* T = nullptr; if (V) T = V->getType(); PointerType *PFT = nullptr; if (T) PFT = dyn_cast<PointerType>(T); FunctionType *FT = nullptr; if (PFT) FT = dyn_cast<FunctionType>(PFT->getElementType()); Function *F_ = CI->getCalledFunction(); if (FT && needsFPReturnHelper(*FT) && !(F_ && isIntrinsicInline(F_))) { Modified=true; F.addFnAttr("saveS2"); } if (F_ && !isIntrinsicInline(F_)) { // pic mode calls are handled by already defined // helper functions if (needsFPReturnHelper(*F_)) { Modified=true; F.addFnAttr("saveS2"); } if (TM.getRelocationModel() != Reloc::PIC_ ) { if (needsFPHelperFromSig(*F_)) { assureFPCallStub(*F_, M, TM); Modified=true; } } } } } return Modified; }
// // Make sure that we know we already need a stub for this function. // Having called needsFPHelperFromSig // static void assureFPCallStub(Function &F, Module *M, const MipsTargetMachine &TM) { // for now we only need them for static relocation if (TM.getRelocationModel() == Reloc::PIC_) return; LLVMContext &Context = M->getContext(); bool LE = TM.isLittleEndian(); std::string Name = F.getName(); std::string SectionName = ".mips16.call.fp." + Name; std::string StubName = "__call_stub_fp_" + Name; // // see if we already have the stub // Function *FStub = M->getFunction(StubName); if (FStub && !FStub->isDeclaration()) return; FStub = Function::Create(F.getFunctionType(), Function::InternalLinkage, StubName, M); FStub->addFnAttr("mips16_fp_stub"); FStub->addFnAttr(llvm::Attribute::Naked); FStub->addFnAttr(llvm::Attribute::NoInline); FStub->addFnAttr(llvm::Attribute::NoUnwind); FStub->addFnAttr("nomips16"); FStub->setSection(SectionName); BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub); FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType()); FPParamVariant PV = whichFPParamVariantNeeded(F); std::string AsmText; AsmText += ".set reorder\n"; AsmText += swapFPIntParams(PV, M, LE, true); if (RV != NoFPRet) { AsmText += "move $$18, $$31\n"; AsmText += "jal " + Name + "\n"; } else { AsmText += "lui $$25, %hi(" + Name + ")\n"; AsmText += "addiu $$25, $$25, %lo(" + Name + ")\n"; } switch (RV) { case FRet: AsmText += "mfc1 $$2, $$f0\n"; break; case DRet: if (LE) { AsmText += "mfc1 $$2, $$f0\n"; AsmText += "mfc1 $$3, $$f1\n"; } else { AsmText += "mfc1 $$3, $$f0\n"; AsmText += "mfc1 $$2, $$f1\n"; } break; case CFRet: if (LE) { AsmText += "mfc1 $$2, $$f0\n"; AsmText += "mfc1 $$3, $$f2\n"; } else { AsmText += "mfc1 $$3, $$f0\n"; AsmText += "mfc1 $$3, $$f2\n"; } break; case CDRet: if (LE) { AsmText += "mfc1 $$4, $$f2\n"; AsmText += "mfc1 $$5, $$f3\n"; AsmText += "mfc1 $$2, $$f0\n"; AsmText += "mfc1 $$3, $$f1\n"; } else { AsmText += "mfc1 $$5, $$f2\n"; AsmText += "mfc1 $$4, $$f3\n"; AsmText += "mfc1 $$3, $$f0\n"; AsmText += "mfc1 $$2, $$f1\n"; } break; case NoFPRet: break; } if (RV != NoFPRet) AsmText += "jr $$18\n"; else AsmText += "jr $$25\n"; EmitInlineAsm(Context, BB, AsmText); new UnreachableInst(Context, BB); }
MipsSubtarget::MipsSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS, bool little, const MipsTargetMachine &TM) : MipsGenSubtargetInfo(TT, CPU, FS), MipsArchVersion(MipsDefault), IsLittle(little), IsSoftFloat(false), IsSingleFloat(false), IsFPXX(false), NoABICalls(false), IsFP64bit(false), UseOddSPReg(true), IsNaN2008bit(false), IsGP64bit(false), HasVFPU(false), HasCnMips(false), HasMips3_32(false), HasMips3_32r2(false), HasMips4_32(false), HasMips4_32r2(false), HasMips5_32r2(false), InMips16Mode(false), InMips16HardFloat(Mips16HardFloat), InMicroMipsMode(false), HasDSP(false), HasDSPR2(false), AllowMixed16_32(Mixed16_32 | Mips_Os16), Os16(Mips_Os16), HasMSA(false), UseTCCInDIV(false), TM(TM), TargetTriple(TT), TSInfo(), InstrInfo( MipsInstrInfo::create(initializeSubtargetDependencies(CPU, FS, TM))), FrameLowering(MipsFrameLowering::create(*this)), TLInfo(MipsTargetLowering::create(TM, *this)) { PreviousInMips16Mode = InMips16Mode; if (MipsArchVersion == MipsDefault) MipsArchVersion = Mips32; // Don't even attempt to generate code for MIPS-I and MIPS-V. They have not // been tested and currently exist for the integrated assembler only. if (MipsArchVersion == Mips1) report_fatal_error("Code generation for MIPS-I is not implemented", false); if (MipsArchVersion == Mips5) report_fatal_error("Code generation for MIPS-V is not implemented", false); // Check if Architecture and ABI are compatible. assert(((!isGP64bit() && (isABI_O32() || isABI_EABI())) || (isGP64bit() && (isABI_N32() || isABI_N64()))) && "Invalid Arch & ABI pair."); if (hasMSA() && !isFP64bit()) report_fatal_error("MSA requires a 64-bit FPU register file (FR=1 mode). " "See -mattr=+fp64.", false); if (!isABI_O32() && !useOddSPReg()) report_fatal_error("-mattr=+nooddspreg requires the O32 ABI.", false); if (IsFPXX && (isABI_N32() || isABI_N64())) report_fatal_error("FPXX is not permitted for the N32/N64 ABI's.", false); if (hasMips32r6()) { StringRef ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6"; assert(isFP64bit()); assert(isNaN2008()); if (hasDSP()) report_fatal_error(ISA + " is not compatible with the DSP ASE", false); } if (NoABICalls && TM.getRelocationModel() == Reloc::PIC_) report_fatal_error("position-independent code requires '-mabicalls'"); // Set UseSmallSection. UseSmallSection = GPOpt; if (!NoABICalls && GPOpt) { errs() << "warning: cannot use small-data accesses for '-mabicalls'" << "\n"; UseSmallSection = false; } }