static void createFPFnStub(Function *F, Module *M, FPParamVariant PV, const MipsSubtarget &Subtarget ) { bool PicMode = Subtarget.getRelocationModel() == Reloc::PIC_; bool LE = Subtarget.isLittle(); 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); }
static std::string computeDataLayout(const MipsSubtarget &ST) { std::string Ret = ""; // There are both little and big endian mips. if (ST.isLittle()) Ret += "e"; else Ret += "E"; Ret += "-m:m"; // Pointers are 32 bit on some ABIs. if (!ST.isABI_N64()) Ret += "-p:32:32"; // 8 and 16 bit integers only need no have natural alignment, but try to // align them to 32 bits. 64 bit integers have natural alignment. Ret += "-i8:8:32-i16:16:32-i64:64"; // 32 bit registers are always available and the stack is at least 64 bit // aligned. On N64 64 bit registers are also available and the stack is // 128 bit aligned. if (ST.isABI_N64() || ST.isABI_N32()) Ret += "-n32:64-S128"; else Ret += "-n32-S64"; return Ret; }
void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { MipsTargetStreamer &TS = getTargetStreamer(); // MipsTargetStreamer has an initialization order problem when emitting an // object file directly (see MipsTargetELFStreamer for full details). Work // around it by re-initializing the PIC state here. TS.setPic(OutContext.getObjectFileInfo()->isPositionIndependent()); // Compute MIPS architecture attributes based on the default subtarget // that we'd have constructed. Module level directives aren't LTO // clean anyhow. // FIXME: For ifunc related functions we could iterate over and look // for a feature string that doesn't match the default one. const Triple &TT = TM.getTargetTriple(); StringRef CPU = MIPS_MC::selectMipsCPU(TT, TM.getTargetCPU()); StringRef FS = TM.getTargetFeatureString(); const MipsTargetMachine &MTM = static_cast<const MipsTargetMachine &>(TM); const MipsSubtarget STI(TT, CPU, FS, MTM.isLittleEndian(), MTM, 0); bool IsABICalls = STI.isABICalls(); const MipsABIInfo &ABI = MTM.getABI(); if (IsABICalls) { TS.emitDirectiveAbiCalls(); // FIXME: This condition should be a lot more complicated that it is here. // Ideally it should test for properties of the ABI and not the ABI // itself. // For the moment, I'm only correcting enough to make MIPS-IV work. if (!isPositionIndependent() && STI.hasSym32()) TS.emitDirectiveOptionPic0(); } // Tell the assembler which ABI we are using std::string SectionName = std::string(".mdebug.") + getCurrentABIString(); OutStreamer->SwitchSection( OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, 0)); // NaN: At the moment we only support: // 1. .nan legacy (default) // 2. .nan 2008 STI.isNaN2008() ? TS.emitDirectiveNaN2008() : TS.emitDirectiveNaNLegacy(); // TODO: handle O64 ABI TS.updateABIInfo(STI); // We should always emit a '.module fp=...' but binutils 2.24 does not accept // it. We therefore emit it when it contradicts the ABI defaults (-mfpxx or // -mfp64) and omit it otherwise. if (ABI.IsO32() && (STI.isABI_FPXX() || STI.isFP64bit())) TS.emitDirectiveModuleFP(); // We should always emit a '.module [no]oddspreg' but binutils 2.24 does not // accept it. We therefore emit it when it contradicts the default or an // option has changed the default (i.e. FPXX) and omit it otherwise. if (ABI.IsO32() && (!STI.useOddSPReg() || STI.isABI_FPXX())) TS.emitDirectiveModuleOddSPReg(); }
Mips16TargetLowering::Mips16TargetLowering(const MipsTargetMachine &TM, const MipsSubtarget &STI) : MipsTargetLowering(TM, STI) { // Set up the register classes addRegisterClass(MVT::i32, &Mips::CPU16RegsRegClass); if (!Subtarget.useSoftFloat()) setMips16HardFloatLibCalls(); setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand); setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_ADD, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_SUB, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_AND, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_OR, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_XOR, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_NAND, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_MIN, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_MAX, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_UMIN, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, Expand); setOperationAction(ISD::ROTR, MVT::i32, Expand); setOperationAction(ISD::ROTR, MVT::i64, Expand); setOperationAction(ISD::BSWAP, MVT::i32, Expand); setOperationAction(ISD::BSWAP, MVT::i64, Expand); computeRegisterProperties(STI.getRegisterInfo()); }
// // Returns of float, double and complex need to be handled with a helper // function. // static bool fixupFPReturnAndCall (Function &F, Module *M, const MipsSubtarget &Subtarget) { 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* 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, NULL)); CallInst::Create(F, Params, "", &Inst ); } else if (const CallInst *CI = dyn_cast<CallInst>(I)) { // pic mode calls are handled by already defined // helper functions if (Subtarget.getRelocationModel() != Reloc::PIC_ ) { Function *F_ = CI->getCalledFunction(); if (F_ && !isIntrinsicInline(F_) && needsFPHelperFromSig(*F_)) { assureFPCallStub(*F_, M, Subtarget); Modified=true; } } } } return Modified; }
// Integrated assembler version void MipsReginfo::emitMipsReginfoSectionCG(MCStreamer &OS, const TargetLoweringObjectFile &TLOF, const MipsSubtarget &MST) const { if (OS.hasRawTextSupport()) return; const MipsTargetObjectFile &TLOFELF = static_cast<const MipsTargetObjectFile &>(TLOF); OS.SwitchSection(TLOFELF.getReginfoSection()); // .reginfo if (MST.isABI_O32()) { OS.EmitIntValue(0, 4); // ri_gprmask OS.EmitIntValue(0, 4); // ri_cpr[0]mask OS.EmitIntValue(0, 4); // ri_cpr[1]mask OS.EmitIntValue(0, 4); // ri_cpr[2]mask OS.EmitIntValue(0, 4); // ri_cpr[3]mask OS.EmitIntValue(0, 4); // ri_gp_value } // .MIPS.options else if (MST.isABI_N64()) { OS.EmitIntValue(1, 1); // kind OS.EmitIntValue(40, 1); // size OS.EmitIntValue(0, 2); // section OS.EmitIntValue(0, 4); // info OS.EmitIntValue(0, 4); // ri_gprmask OS.EmitIntValue(0, 4); // pad OS.EmitIntValue(0, 4); // ri_cpr[0]mask OS.EmitIntValue(0, 4); // ri_cpr[1]mask OS.EmitIntValue(0, 4); // ri_cpr[2]mask OS.EmitIntValue(0, 4); // ri_cpr[3]mask OS.EmitIntValue(0, 8); // ri_gp_value } else llvm_unreachable("Unsupported abi for reginfo"); }
MipsCCState::SpecialCallingConvType MipsCCState::getSpecialCallingConvForCallee(const SDNode *Callee, const MipsSubtarget &Subtarget) { MipsCCState::SpecialCallingConvType SpecialCallingConv = NoSpecialCallingConv; if (Subtarget.inMips16HardFloat()) { if (const GlobalAddressSDNode *G = dyn_cast<const GlobalAddressSDNode>(Callee)) { llvm::StringRef Sym = G->getGlobal()->getName(); Function *F = G->getGlobal()->getParent()->getFunction(Sym); if (F && F->hasFnAttribute("__Mips16RetHelper")) { SpecialCallingConv = Mips16RetHelperConv; } } } return SpecialCallingConv; }
// For llc. Set a group of ELF header flags void MipsELFStreamer::emitELFHeaderFlagsCG(const MipsSubtarget &Subtarget) { if (hasRawTextSupport()) return; // Update e_header flags MCAssembler& MCA = getAssembler(); unsigned EFlags = MCA.getELFHeaderEFlags(); // TODO: Need to add -mabicalls and -mno-abicalls flags. // Currently we assume that -mabicalls is the default. EFlags |= ELF::EF_MIPS_CPIC; if (Subtarget.inMips16Mode()) EFlags |= ELF::EF_MIPS_ARCH_ASE_M16; else EFlags |= ELF::EF_MIPS_NOREORDER; // Architecture if (Subtarget.hasMips64r2()) EFlags |= ELF::EF_MIPS_ARCH_64R2; else if (Subtarget.hasMips64()) EFlags |= ELF::EF_MIPS_ARCH_64; else if (Subtarget.hasMips32r2()) EFlags |= ELF::EF_MIPS_ARCH_32R2; else EFlags |= ELF::EF_MIPS_ARCH_32; if (Subtarget.inMicroMipsMode()) EFlags |= ELF::EF_MIPS_MICROMIPS; // ABI if (Subtarget.isABI_O32()) EFlags |= ELF::EF_MIPS_ABI_O32; // Relocation Model Reloc::Model RM = Subtarget.getRelocationModel(); if (RM == Reloc::PIC_ || RM == Reloc::Default) EFlags |= ELF::EF_MIPS_PIC; else if (RM == Reloc::Static) ; // Do nothing for Reloc::Static else llvm_unreachable("Unsupported relocation model for e_flags"); MCA.setELFHeaderEFlags(EFlags); }
MipsSEInstrInfo::MipsSEInstrInfo(const MipsSubtarget &STI) : MipsInstrInfo(STI, STI.getRelocationModel() == Reloc::PIC_ ? Mips::B : Mips::J), RI() {}
// // Make sure that we know we already need a stub for this function. // Having called needsFPHelperFromSig // static void assureFPCallStub(Function &F, Module *M, const MipsSubtarget &Subtarget){ // for now we only need them for static relocation if (Subtarget.getRelocationModel() == Reloc::PIC_) return; LLVMContext &Context = M->getContext(); bool LE = Subtarget.isLittle(); 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); InlineAsmHelper IAH(Context, BB); IAH.Out(".set reorder"); FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType()); FPParamVariant PV = whichFPParamVariantNeeded(F); swapFPIntParams(PV, M, IAH, LE, true); if (RV != NoFPRet) { IAH.Out("move $$18, $$31"); IAH.Out("jal " + Name); } else { IAH.Out("lui $$25,%hi(" + Name + ")"); IAH.Out("addiu $$25,$$25,%lo(" + Name + ")" ); } switch (RV) { case FRet: IAH.Out("mfc1 $$2,$$f0"); break; case DRet: if (LE) { IAH.Out("mfc1 $$2,$$f0"); IAH.Out("mfc1 $$3,$$f1"); } else { IAH.Out("mfc1 $$3,$$f0"); IAH.Out("mfc1 $$2,$$f1"); } break; case CFRet: if (LE) { IAH.Out("mfc1 $$2,$$f0"); IAH.Out("mfc1 $$3,$$f2"); } else { IAH.Out("mfc1 $$3,$$f0"); IAH.Out("mfc1 $$3,$$f2"); } break; case CDRet: if (LE) { IAH.Out("mfc1 $$4,$$f2"); IAH.Out("mfc1 $$5,$$f3"); IAH.Out("mfc1 $$2,$$f0"); IAH.Out("mfc1 $$3,$$f1"); } else { IAH.Out("mfc1 $$5,$$f2"); IAH.Out("mfc1 $$4,$$f3"); IAH.Out("mfc1 $$3,$$f0"); IAH.Out("mfc1 $$2,$$f1"); } break; case NoFPRet: break; } if (RV != NoFPRet) IAH.Out("jr $$18"); else IAH.Out("jr $$25"); new UnreachableInst(Context, BB); }
void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { // Compute MIPS architecture attributes based on the default subtarget // that we'd have constructed. Module level directives aren't LTO // clean anyhow. // FIXME: For ifunc related functions we could iterate over and look // for a feature string that doesn't match the default one. const Triple &TT = TM.getTargetTriple(); StringRef CPU = MIPS_MC::selectMipsCPU(TT, TM.getTargetCPU()); StringRef FS = TM.getTargetFeatureString(); const MipsTargetMachine &MTM = static_cast<const MipsTargetMachine &>(TM); const MipsSubtarget STI(TT, CPU, FS, MTM.isLittleEndian(), MTM); bool IsABICalls = STI.isABICalls(); const MipsABIInfo &ABI = MTM.getABI(); if (IsABICalls) { getTargetStreamer().emitDirectiveAbiCalls(); Reloc::Model RM = TM.getRelocationModel(); // FIXME: This condition should be a lot more complicated that it is here. // Ideally it should test for properties of the ABI and not the ABI // itself. // For the moment, I'm only correcting enough to make MIPS-IV work. if (RM == Reloc::Static && !ABI.IsN64()) getTargetStreamer().emitDirectiveOptionPic0(); } // Tell the assembler which ABI we are using std::string SectionName = std::string(".mdebug.") + getCurrentABIString(); OutStreamer->SwitchSection( OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, 0)); // NaN: At the moment we only support: // 1. .nan legacy (default) // 2. .nan 2008 STI.isNaN2008() ? getTargetStreamer().emitDirectiveNaN2008() : getTargetStreamer().emitDirectiveNaNLegacy(); // TODO: handle O64 ABI if (ABI.IsEABI()) { if (STI.isGP32bit()) OutStreamer->SwitchSection(OutContext.getELFSection(".gcc_compiled_long32", ELF::SHT_PROGBITS, 0)); else OutStreamer->SwitchSection(OutContext.getELFSection(".gcc_compiled_long64", ELF::SHT_PROGBITS, 0)); } getTargetStreamer().updateABIInfo(STI); // We should always emit a '.module fp=...' but binutils 2.24 does not accept // it. We therefore emit it when it contradicts the ABI defaults (-mfpxx or // -mfp64) and omit it otherwise. if (ABI.IsO32() && (STI.isABI_FPXX() || STI.isFP64bit())) getTargetStreamer().emitDirectiveModuleFP(); // We should always emit a '.module [no]oddspreg' but binutils 2.24 does not // accept it. We therefore emit it when it contradicts the default or an // option has changed the default (i.e. FPXX) and omit it otherwise. if (ABI.IsO32() && (!STI.useOddSPReg() || STI.isABI_FPXX())) getTargetStreamer().emitDirectiveModuleOddSPReg(); }
MipsSEFrameLowering::MipsSEFrameLowering(const MipsSubtarget &STI) : MipsFrameLowering(STI, STI.stackAlignment()) {}
MipsSEInstrInfo::MipsSEInstrInfo(const MipsSubtarget &STI) : MipsInstrInfo(STI, STI.isPositionIndependent() ? Mips::B : Mips::J), RI() {}