diff --git a/lib/Target/Mips/CMakeLists.txt b/lib/Target/Mips/CMakeLists.txt index a225a00c023b..c304ee31facc 100644 --- a/lib/Target/Mips/CMakeLists.txt +++ b/lib/Target/Mips/CMakeLists.txt @@ -16,6 +16,7 @@ add_public_tablegen_target(MipsCommonTableGen) add_llvm_target(MipsCodeGen Mips16FrameLowering.cpp Mips16HardFloat.cpp + Mips16HardFloatInfo.cpp Mips16InstrInfo.cpp Mips16ISelDAGToDAG.cpp Mips16ISelLowering.cpp diff --git a/lib/Target/Mips/Mips16HardFloat.cpp b/lib/Target/Mips/Mips16HardFloat.cpp index 3d5781de8cc9..d321e2192ad9 100644 --- a/lib/Target/Mips/Mips16HardFloat.cpp +++ b/lib/Target/Mips/Mips16HardFloat.cpp @@ -245,8 +245,8 @@ static void swapFPIntParams // 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){ +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; @@ -500,8 +500,9 @@ namespace llvm { // declared via attributes as nomips16, we must: // 1) fixup all returns of float, double, single and double complex // by calling a helper function before the actual return. -// 2) generate helper functions (stubs) that can be called by mips32 functions -// that will move parameters passed normally passed in floating point +// 2) generate helper functions (stubs) that can be called by mips32 +// functions that will move parameters passed normally passed in +// floating point // registers the soft float equivalents. // 3) in the case of static relocation, generate helper functions so that // mips16 functions can call extern functions of unknown type (mips16 or diff --git a/lib/Target/Mips/Mips16HardFloatInfo.cpp b/lib/Target/Mips/Mips16HardFloatInfo.cpp new file mode 100644 index 000000000000..294f6c92fc29 --- /dev/null +++ b/lib/Target/Mips/Mips16HardFloatInfo.cpp @@ -0,0 +1,50 @@ +//===---- Mips16HardFloatInfo.cpp for Mips16 Hard Float -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips16 implementation of Mips16HardFloatInfo +// namespace. +// +//===----------------------------------------------------------------------===// + +#include +#include "Mips16HardFloatInfo.h" + +namespace llvm { + +namespace Mips16HardFloatInfo { + +const FuncNameSignature PredefinedFuncs[] = { + { "__floatdidf", { NoSig, DRet } }, + { "__floatdisf", { NoSig, FRet } }, + { "__floatundidf", { NoSig, DRet } }, + { "__fixsfdi", { FSig, NoFPRet } }, + { "__fixunsdfsi", { DSig, NoFPRet } }, + { "__fixunsdfdi", { DSig, NoFPRet } }, + { "__fixdfdi", { DSig, NoFPRet } }, + { "__fixunssfsi", { FSig, NoFPRet } }, + { "__fixunssfdi", { FSig, NoFPRet } }, + { "__floatundisf", { NoSig, FRet } }, + { 0, { NoSig, NoFPRet } } +}; + +// just do a search for now. there are very few of these special cases. +// +extern FuncSignature const *findFuncSignature(const char *name) { + const char *name_; + int i = 0; + while (PredefinedFuncs[i].Name) { + name_ = PredefinedFuncs[i].Name; + if (strcmp(name, name_) == 0) + return &PredefinedFuncs[i].Signature; + i++; + } + return 0; +} +} +} diff --git a/lib/Target/Mips/Mips16HardFloatInfo.h b/lib/Target/Mips/Mips16HardFloatInfo.h new file mode 100644 index 000000000000..02444d98c140 --- /dev/null +++ b/lib/Target/Mips/Mips16HardFloatInfo.h @@ -0,0 +1,50 @@ +//===---- Mips16HardFloatInfo.h for Mips16 Hard Float --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some data structures relevant to the implementation of +// Mips16 hard float. +// +// +//===----------------------------------------------------------------------===// + +#ifndef MIPS16HARDFLOATINFO_H +#define MIPS16HARDFLOATINFO_H + +namespace llvm { + +namespace Mips16HardFloatInfo { + +// Return types that matter for hard float are: +// float, double, complex float, and complex double +// +enum FPReturnVariant { FRet, DRet, CFRet, CDRet, NoFPRet }; + +// +// Parameter type that matter are float, (float, float), (float, double), +// double, (double, double), (double, float) +// +enum FPParamVariant { FSig, FFSig, FDSig, DSig, DDSig, DFSig, NoSig }; + +struct FuncSignature { + FPParamVariant ParamSig; + FPReturnVariant RetSig; +}; + +struct FuncNameSignature { + const char *Name; + FuncSignature Signature; +}; + +extern const FuncNameSignature PredefinedFuncs[]; + +extern FuncSignature const *findFuncSignature(const char *name); +} +} + +#endif diff --git a/lib/Target/Mips/Mips16ISelLowering.cpp b/lib/Target/Mips/Mips16ISelLowering.cpp index 91d18eaa1854..502793df87ae 100644 --- a/lib/Target/Mips/Mips16ISelLowering.cpp +++ b/lib/Target/Mips/Mips16ISelLowering.cpp @@ -11,10 +11,12 @@ // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "mips-lower" +#include #include "Mips16ISelLowering.h" #include "MCTargetDesc/MipsBaseInfo.h" #include "MipsRegisterInfo.h" #include "MipsTargetMachine.h" +#include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetInstrInfo.h" @@ -445,7 +447,29 @@ getOpndList(SmallVectorImpl &Ops, Find)) LookupHelper = false; else { - Mips16IntrinsicHelperType IntrinsicFind = {S->getSymbol(), ""}; + const char *Symbol = S->getSymbol(); + Mips16IntrinsicHelperType IntrinsicFind = { Symbol, "" }; + const Mips16HardFloatInfo::FuncSignature *Signature = + Mips16HardFloatInfo::findFuncSignature(Symbol); + if (!IsPICCall && (Signature && (FuncInfo->StubsNeeded.find(Symbol) == + FuncInfo->StubsNeeded.end()))) { + FuncInfo->StubsNeeded[Symbol] = Signature; + // + // S2 is normally saved if the stub is for a function which + // returns a float or double value and is not otherwise. This is + // because more work is required after the function the stub + // is calling completes, and so the stub cannot directly return + // and the stub has no stack space to store the return address so + // S2 is used for that purpose. + // In order to take advantage of not saving S2, we need to also + // optimize the call in the stub and this requires some further + // functionality in MipsAsmPrinter which we don't have yet. + // So for now we always save S2. The optimization will be done + // in a follow-on patch. + // + if (Signature->RetSig != Mips16HardFloatInfo::NoFPRet || 1) + FuncInfo->setSaveS2(); + } // one more look at list of intrinsics if (std::binary_search(Mips16IntrinsicHelper, array_endof(Mips16IntrinsicHelper), @@ -748,8 +772,8 @@ MachineBasicBlock *Mips16TargetLowering::emitFEXT_CCRX16_ins( unsigned CC = MI->getOperand(0).getReg(); unsigned regX = MI->getOperand(1).getReg(); unsigned regY = MI->getOperand(2).getReg(); - BuildMI(*BB, MI, MI->getDebugLoc(), - TII->get(SltOpc)).addReg(regX).addReg(regY); + BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(SltOpc)).addReg(regX).addReg( + regY); BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(Mips::MoveR3216), CC).addReg(Mips::T8); MI->eraseFromParent(); // The pseudo instruction is gone now. diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index 7757132fc625..67c17a92f0f5 100644 --- a/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -36,7 +36,9 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/ELF.h" @@ -44,6 +46,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetOptions.h" +#include using namespace llvm; @@ -57,6 +60,17 @@ bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { const_cast(getObjFileLowering()) .Initialize(OutContext, TM); MipsFI = MF.getInfo(); + if (Subtarget->inMips16Mode()) + for (std::map< + const char *, + const llvm::Mips16HardFloatInfo::FuncSignature *>::const_iterator + it = MipsFI->StubsNeeded.begin(); + it != MipsFI->StubsNeeded.end(); ++it) { + const char *Symbol = it->first; + const llvm::Mips16HardFloatInfo::FuncSignature *Signature = it->second; + if (StubsNeeded.find(Symbol) == StubsNeeded.end()) + StubsNeeded[Symbol] = Signature; + } MCP = MF.getConstantPool(); AsmPrinter::runOnMachineFunction(MF); return true; @@ -616,7 +630,273 @@ void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { OutContext.getELFSection(".gcc_compiled_long64", ELF::SHT_PROGBITS, 0, SectionKind::getDataRel())); } +} + +void MipsAsmPrinter::EmitJal(MCSymbol *Symbol) { + MCInst I; + I.setOpcode(Mips::JAL); + I.addOperand( + MCOperand::CreateExpr(MCSymbolRefExpr::Create(Symbol, OutContext))); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} + +void MipsAsmPrinter::EmitInstrReg(unsigned Opcode, unsigned Reg) { + MCInst I; + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg)); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} + +void MipsAsmPrinter::EmitInstrRegReg(unsigned Opcode, unsigned Reg1, + unsigned Reg2) { + MCInst I; + // + // Because of the current td files for Mips32, the operands for MTC1 + // appear backwards from their normal assembly order. It's not a trivial + // change to fix this in the td file so we adjust for it here. + // + if (Opcode == Mips::MTC1) { + unsigned Temp = Reg1; + Reg1 = Reg2; + Reg2 = Temp; + } + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg1)); + I.addOperand(MCOperand::CreateReg(Reg2)); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} + +void MipsAsmPrinter::EmitInstrRegRegReg(unsigned Opcode, unsigned Reg1, + unsigned Reg2, unsigned Reg3) { + MCInst I; + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg1)); + I.addOperand(MCOperand::CreateReg(Reg2)); + I.addOperand(MCOperand::CreateReg(Reg3)); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} + +void MipsAsmPrinter::EmitMovFPIntPair(unsigned MovOpc, unsigned Reg1, + unsigned Reg2, unsigned FPReg1, + unsigned FPReg2, bool LE) { + if (!LE) { + unsigned temp = Reg1; + Reg1 = Reg2; + Reg2 = temp; + } + EmitInstrRegReg(MovOpc, Reg1, FPReg1); + EmitInstrRegReg(MovOpc, Reg2, FPReg2); +} + +void MipsAsmPrinter::EmitSwapFPIntParams(Mips16HardFloatInfo::FPParamVariant PV, + bool LE, bool ToFP) { + using namespace Mips16HardFloatInfo; + unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1; + switch (PV) { + case FSig: + EmitInstrRegReg(MovOpc, Mips::A0, Mips::F12); + break; + case FFSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE); + break; + case FDSig: + EmitInstrRegReg(MovOpc, Mips::A0, Mips::F12); + EmitMovFPIntPair(MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); + break; + case DSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + break; + case DDSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + EmitMovFPIntPair(MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); + break; + case DFSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + EmitInstrRegReg(MovOpc, Mips::A2, Mips::F14); + break; + case NoSig: + return; + } +} + +void +MipsAsmPrinter::EmitSwapFPIntRetval(Mips16HardFloatInfo::FPReturnVariant RV, + bool LE) { + using namespace Mips16HardFloatInfo; + unsigned MovOpc = Mips::MFC1; + switch (RV) { + case FRet: + EmitInstrRegReg(MovOpc, Mips::V0, Mips::F0); + break; + case DRet: + EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + break; + case CFRet: + EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + break; + case CDRet: + EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE); + break; + case NoFPRet: + break; + } +} +void MipsAsmPrinter::EmitFPCallStub( + const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) { + MCSymbol *MSymbol = OutContext.GetOrCreateSymbol(StringRef(Symbol)); + using namespace Mips16HardFloatInfo; + bool LE = Subtarget->isLittle(); + // + // .global xxxx + // + OutStreamer.EmitSymbolAttribute(MSymbol, MCSA_Global); + const char *RetType; + // + // make the comment field identifying the return and parameter + // types of the floating point stub + // # Stub function to call rettype xxxx (params) + // + switch (Signature->RetSig) { + case FRet: + RetType = "float"; + break; + case DRet: + RetType = "double"; + break; + case CFRet: + RetType = "complex"; + break; + case CDRet: + RetType = "double complex"; + break; + case NoFPRet: + RetType = ""; + break; + } + const char *Parms; + switch (Signature->ParamSig) { + case FSig: + Parms = "float"; + break; + case FFSig: + Parms = "float, float"; + break; + case FDSig: + Parms = "float, double"; + break; + case DSig: + Parms = "double"; + break; + case DDSig: + Parms = "double, double"; + break; + case DFSig: + Parms = "double, float"; + break; + case NoSig: + Parms = ""; + break; + } + OutStreamer.AddComment("\t# Stub function to call " + Twine(RetType) + " " + + Twine(Symbol) + " (" + Twine(Parms) + ")"); + // + // probably not necessary but we save and restore the current section state + // + OutStreamer.PushSection(); + // + // .section mips16.call.fpxxxx,"ax",@progbits + // + const MCSectionELF *M = OutContext.getELFSection( + ".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_EXECINSTR, SectionKind::getText()); + OutStreamer.SwitchSection(M, 0); + // + // .align 2 + // + OutStreamer.EmitValueToAlignment(4); + MipsTargetStreamer &TS = getTargetStreamer(); + // + // .set nomips16 + // .set nomicromips + // + TS.emitDirectiveSetNoMips16(); + TS.emitDirectiveSetNoMicroMips(); + // + // .ent __call_stub_fp_xxxx + // .type __call_stub_fp_xxxx,@function + // __call_stub_fp_xxxx: + // + std::string x = "__call_stub_fp_" + std::string(Symbol); + MCSymbol *Stub = OutContext.GetOrCreateSymbol(StringRef(x)); + TS.emitDirectiveEnt(*Stub); + MCSymbol *MType = + OutContext.GetOrCreateSymbol("__call_stub_fp_" + Twine(Symbol)); + OutStreamer.EmitSymbolAttribute(MType, MCSA_ELF_TypeFunction); + OutStreamer.EmitLabel(Stub); + // + // we just handle non pic for now. these function will not be + // called otherwise. when the full stub generation is moved here + // we need to deal with pic. + // + if (Subtarget->getRelocationModel() == Reloc::PIC_) + llvm_unreachable("should not be here if we are compiling pic"); + TS.emitDirectiveSetReorder(); + // + // We need to add a MipsMCExpr class to MCTargetDesc to fully implement + // stubs without raw text but this current patch is for compiler generated + // functions and they all return some value. + // The calling sequence for non pic is different in that case and we need + // to implement %lo and %hi in order to handle the case of no return value + // See the corresponding method in Mips16HardFloat for details. + // + // mov the return address to S2. + // we have no stack space to store it and we are about to make another call. + // We need to make sure that the enclosing function knows to save S2 + // This should have already been handled. + // + // Mov $18, $31 + + EmitInstrRegRegReg(Mips::ADDu, Mips::S2, Mips::RA, Mips::ZERO); + + EmitSwapFPIntParams(Signature->ParamSig, LE, true); + + // Jal xxxx + // + EmitJal(MSymbol); + + // fix return values + EmitSwapFPIntRetval(Signature->RetSig, LE); + // + // do the return + // if (Signature->RetSig == NoFPRet) + // llvm_unreachable("should not be any stubs here with no return value"); + // else + EmitInstrReg(Mips::JR, Mips::S2); + + MCSymbol *Tmp = OutContext.CreateTempSymbol(); + OutStreamer.EmitLabel(Tmp); + const MCSymbolRefExpr *E = MCSymbolRefExpr::Create(Stub, OutContext); + const MCSymbolRefExpr *T = MCSymbolRefExpr::Create(Tmp, OutContext); + const MCExpr *T_min_E = MCBinaryExpr::CreateSub(T, E, OutContext); + OutStreamer.EmitELFSize(Stub, T_min_E); + TS.emitDirectiveEnd(x); + OutStreamer.PopSection(); +} + +void MipsAsmPrinter::EmitEndOfAsmFile(Module &M) { + // Emit needed stubs + // + for (std::map< + const char *, + const llvm::Mips16HardFloatInfo::FuncSignature *>::const_iterator + it = StubsNeeded.begin(); + it != StubsNeeded.end(); ++it) { + const char *Symbol = it->first; + const llvm::Mips16HardFloatInfo::FuncSignature *Signature = it->second; + EmitFPCallStub(Symbol, Signature); + } // return to the text section OutStreamer.SwitchSection(OutContext.getObjectFileInfo()->getTextSection()); } diff --git a/lib/Target/Mips/MipsAsmPrinter.h b/lib/Target/Mips/MipsAsmPrinter.h index 1af4ac8b5297..2808b940da44 100644 --- a/lib/Target/Mips/MipsAsmPrinter.h +++ b/lib/Target/Mips/MipsAsmPrinter.h @@ -14,6 +14,7 @@ #ifndef MIPSASMPRINTER_H #define MIPSASMPRINTER_H +#include "Mips16HardFloatInfo.h" #include "MipsMCInstLower.h" #include "MipsMachineFunction.h" #include "MipsSubtarget.h" @@ -50,6 +51,27 @@ class LLVM_LIBRARY_VISIBILITY MipsAsmPrinter : public AsmPrinter { /// pool entries so we can properly mark them as data regions. bool InConstantPool; + std::map + StubsNeeded; + + void EmitJal(MCSymbol *Symbol); + + void EmitInstrReg(unsigned Opcode, unsigned Reg); + + void EmitInstrRegReg(unsigned Opcode, unsigned Reg1, unsigned Reg2); + + void EmitInstrRegRegReg(unsigned Opcode, unsigned Reg1, unsigned Reg2, + unsigned Reg3); + + void EmitMovFPIntPair(unsigned MovOpc, unsigned Reg1, unsigned Reg2, + unsigned FPReg1, unsigned FPReg2, bool LE); + + void EmitSwapFPIntParams(Mips16HardFloatInfo::FPParamVariant, bool LE, + bool ToFP); + + void EmitSwapFPIntRetval(Mips16HardFloatInfo::FPReturnVariant, bool LE); + + void EmitFPCallStub(const char *, const Mips16HardFloatInfo::FuncSignature *); public: @@ -100,6 +122,7 @@ class LLVM_LIBRARY_VISIBILITY MipsAsmPrinter : public AsmPrinter { void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, const char *Modifier = 0); void EmitStartOfAsmFile(Module &M); + void EmitEndOfAsmFile(Module &M); void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); }; } diff --git a/lib/Target/Mips/MipsMachineFunction.h b/lib/Target/Mips/MipsMachineFunction.h index 43bf6827eefb..d54c3606431d 100644 --- a/lib/Target/Mips/MipsMachineFunction.h +++ b/lib/Target/Mips/MipsMachineFunction.h @@ -14,6 +14,7 @@ #ifndef MIPS_MACHINE_FUNCTION_INFO_H #define MIPS_MACHINE_FUNCTION_INFO_H +#include "Mips16HardFloatInfo.h" #include "MipsSubtarget.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/ValueMap.h" @@ -24,6 +25,8 @@ #include "llvm/IR/GlobalValue.h" #include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetMachine.h" +#include +#include #include namespace llvm { @@ -50,10 +53,9 @@ class MipsCallEntry : public PseudoSourceValue { /// Mips target-specific information for each MachineFunction. class MipsFunctionInfo : public MachineFunctionInfo { public: - MipsFunctionInfo(MachineFunction& MF) - : MF(MF), SRetReturnReg(0), GlobalBaseReg(0), Mips16SPAliasReg(0), - VarArgsFrameIndex(0), CallsEhReturn(false) - {} + MipsFunctionInfo(MachineFunction &MF) + : MF(MF), SRetReturnReg(0), GlobalBaseReg(0), Mips16SPAliasReg(0), + VarArgsFrameIndex(0), CallsEhReturn(false), SaveS2(false) {} ~MipsFunctionInfo(); @@ -92,6 +94,12 @@ class MipsFunctionInfo : public MachineFunctionInfo { /// representing a GOT entry for a global function. MachinePointerInfo callPtrInfo(const GlobalValue *Val); + void setSaveS2() { SaveS2 = true; } + bool hasSaveS2() const { return SaveS2; } + + std::map + StubsNeeded; + private: virtual void anchor(); @@ -126,6 +134,9 @@ class MipsFunctionInfo : public MachineFunctionInfo { /// Frame objects for spilling eh data registers. int EhDataRegFI[4]; + // saveS2 + bool SaveS2; + /// MipsCallEntry maps. StringMap ExternalCallEntries; ValueMap GlobalCallEntries; diff --git a/lib/Target/Mips/MipsRegisterInfo.cpp b/lib/Target/Mips/MipsRegisterInfo.cpp index 14c96a069766..c6563708b26c 100644 --- a/lib/Target/Mips/MipsRegisterInfo.cpp +++ b/lib/Target/Mips/MipsRegisterInfo.cpp @@ -187,11 +187,12 @@ getReservedRegs(const MachineFunction &MF) const { // Reserve RA if in mips16 mode. if (Subtarget.inMips16Mode()) { + const MipsFunctionInfo *MipsFI = MF.getInfo(); Reserved.set(Mips::RA); Reserved.set(Mips::RA_64); Reserved.set(Mips::T0); Reserved.set(Mips::T1); - if (MF.getFunction()->hasFnAttribute("saveS2")) + if (MF.getFunction()->hasFnAttribute("saveS2") || MipsFI->hasSaveS2()) Reserved.set(Mips::S2); } diff --git a/test/CodeGen/Mips/l3mc.ll b/test/CodeGen/Mips/l3mc.ll new file mode 100644 index 000000000000..3bfb389ba05d --- /dev/null +++ b/test/CodeGen/Mips/l3mc.ll @@ -0,0 +1,114 @@ +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___fixunsdfsi + +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___floatdidf + +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___floatdisf + +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___floatundidf + +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___fixsfdi + +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___fixunsdfdi + +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___fixdfdi + +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___fixunssfsi + +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___fixunssfdi + +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___floatundisf + +@ll1 = global i64 0, align 8 +@ll2 = global i64 0, align 8 +@ll3 = global i64 0, align 8 +@l1 = global i32 0, align 4 +@l2 = global i32 0, align 4 +@l3 = global i32 0, align 4 +@ull1 = global i64 0, align 8 +@ull2 = global i64 0, align 8 +@ull3 = global i64 0, align 8 +@ul1 = global i32 0, align 4 +@ul2 = global i32 0, align 4 +@ul3 = global i32 0, align 4 +@d1 = global double 0.000000e+00, align 8 +@d2 = global double 0.000000e+00, align 8 +@d3 = global double 0.000000e+00, align 8 +@d4 = global double 0.000000e+00, align 8 +@f1 = global float 0.000000e+00, align 4 +@f2 = global float 0.000000e+00, align 4 +@f3 = global float 0.000000e+00, align 4 +@f4 = global float 0.000000e+00, align 4 + +; Function Attrs: nounwind +define void @_Z3foov() #0 { +entry: + %0 = load double* @d1, align 8 + %conv = fptosi double %0 to i64 + store i64 %conv, i64* @ll1, align 8 + %1 = load double* @d2, align 8 + %conv1 = fptoui double %1 to i64 + store i64 %conv1, i64* @ull1, align 8 + %2 = load float* @f1, align 4 + %conv2 = fptosi float %2 to i64 + store i64 %conv2, i64* @ll2, align 8 + %3 = load float* @f2, align 4 + %conv3 = fptoui float %3 to i64 + store i64 %conv3, i64* @ull2, align 8 + %4 = load double* @d3, align 8 + %conv4 = fptosi double %4 to i32 + store i32 %conv4, i32* @l1, align 4 + %5 = load double* @d4, align 8 + %conv5 = fptoui double %5 to i32 + store i32 %conv5, i32* @ul1, align 4 + %6 = load float* @f3, align 4 + %conv6 = fptosi float %6 to i32 + store i32 %conv6, i32* @l2, align 4 + %7 = load float* @f4, align 4 + %conv7 = fptoui float %7 to i32 + store i32 %conv7, i32* @ul2, align 4 + ret void +} + +; Function Attrs: nounwind +define void @_Z3goov() #0 { +entry: + %0 = load i64* @ll1, align 8 + %conv = sitofp i64 %0 to double + store double %conv, double* @d1, align 8 + %1 = load i64* @ull1, align 8 + %conv1 = uitofp i64 %1 to double + store double %conv1, double* @d2, align 8 + %2 = load i64* @ll2, align 8 + %conv2 = sitofp i64 %2 to float + store float %conv2, float* @f1, align 4 + %3 = load i64* @ull2, align 8 + %conv3 = uitofp i64 %3 to float + store float %conv3, float* @f2, align 4 + %4 = load i32* @l1, align 4 + %conv4 = sitofp i32 %4 to double + store double %conv4, double* @d3, align 8 + %5 = load i32* @ul1, align 4 + %conv5 = uitofp i32 %5 to double + store double %conv5, double* @d4, align 8 + %6 = load i32* @l2, align 4 + %conv6 = sitofp i32 %6 to float + store float %conv6, float* @f3, align 4 + %7 = load i32* @ul2, align 4 + %conv7 = uitofp i32 %7 to float + store float %conv7, float* @f4, align 4 + ret void +} + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +; __call_stub_fp___fixunsdfsi: __call_stub_fp___fixunsdfsi: +; __call_stub_fp___floatdidf: __call_stub_fp___floatdidf: +; __call_stub_fp___floatdisf: __call_stub_fp___floatdisf: +; __call_stub_fp___floatundidf: __call_stub_fp___floatundidf: +; __call_stub_fp___fixsfdi: __call_stub_fp___fixsfdi: +; __call_stub_fp___fixunsdfdi: __call_stub_fp___fixunsdfdi: +; __call_stub_fp___fixdfdi: __call_stub_fp___fixdfdi: +; __call_stub_fp___fixunssfsi: __call_stub_fp___fixunssfsi: +; __call_stub_fp___fixunssfdi: __call_stub_fp___fixunssfdi: +; __call_stub_fp___floatundisf: __call_stub_fp___floatundisf: +