static void createFPFnStub(Function *F, Module *M, FPParamVariant PV, const MipsTargetMachine &TM) { bool PicMode = TM.isPositionIndependent(); 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); std::string AsmText; if (PicMode) { AsmText += ".set noreorder\n"; AsmText += ".cpload $$25\n"; AsmText += ".set reorder\n"; AsmText += ".reloc 0, R_MIPS_NONE, " + Name + "\n"; AsmText += "la $$25, " + LocalName + "\n"; } else AsmText += "la $$25, " + Name + "\n"; AsmText += swapFPIntParams(PV, M, LE, false); AsmText += "jr $$25\n"; AsmText += LocalName + " = " + Name + "\n"; EmitInlineAsm(Context, BB, AsmText); new UnreachableInst(FStub->getContext(), BB); }
// // 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.isPositionIndependent()) 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); }
// // 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 (auto &BB: F) for (auto &I: BB) { 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]; AttributeList 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, AttributeList::FunctionIndex, "__Mips16RetHelper"); A = A.addAttribute(C, AttributeList::FunctionIndex, Attribute::ReadNone); A = A.addAttribute(C, AttributeList::FunctionIndex, Attribute::NoInline); Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T)); CallInst::Create(F, Params, "", &I); } else if (const CallInst *CI = dyn_cast<CallInst>(&I)) { FunctionType *FT = CI->getFunctionType(); Function *F_ = CI->getCalledFunction(); if (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.isPositionIndependent()) { if (needsFPHelperFromSig(*F_)) { assureFPCallStub(*F_, M, TM); Modified=true; } } } } } return Modified; }
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), HasDSPR3(false), AllowMixed16_32(Mixed16_32 | Mips_Os16), Os16(Mips_Os16), HasMSA(false), UseTCCInDIV(false), HasSym32(false), HasEVA(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()) || (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.isPositionIndependent()) report_fatal_error("position-independent code requires '-mabicalls'"); if (isABI_N64() && !TM.isPositionIndependent() && !hasSym32()) NoABICalls = true; // Set UseSmallSection. UseSmallSection = GPOpt; if (!NoABICalls && GPOpt) { errs() << "warning: cannot use small-data accesses for '-mabicalls'" << "\n"; UseSmallSection = false; } }