diff options
author | Akira Hatanaka <ahatanaka@mips.com> | 2013-03-05 22:13:04 +0000 |
---|---|---|
committer | Akira Hatanaka <ahatanaka@mips.com> | 2013-03-05 22:13:04 +0000 |
commit | 5fdee6d2b5a72a826bf6db47c319ddac08cd9f57 (patch) | |
tree | 8ee76d72d2cef01e08e4e5f97671218db4ba9ef5 | |
parent | f84606732c76899af54c295ec987c96c88452747 (diff) |
[mips] Correct handling of fp128 (long double) formals and read long double
parameters from floating point registers if target is mips64 hard float.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@176520 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Target/Mips/MipsISelLowering.cpp | 76 | ||||
-rw-r--r-- | lib/Target/Mips/MipsISelLowering.h | 12 | ||||
-rw-r--r-- | test/CodeGen/Mips/mips64-call.ll | 13 |
3 files changed, 92 insertions, 9 deletions
diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index cbcc18c7e5..b52bf71655 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -30,7 +30,6 @@ #include "llvm/CodeGen/ValueTypes.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Intrinsics.h" #include "llvm/Support/CommandLine.h" @@ -3647,13 +3646,14 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, *DAG.getContext()); MipsCC MipsCCInfo(CallConv, IsO32, CCInfo); + Function::const_arg_iterator FuncArg = + DAG.getMachineFunction().getFunction()->arg_begin(); + bool UseSoftFloat = getTargetMachine().Options.UseSoftFloat; - MipsCCInfo.analyzeFormalArguments(Ins); + MipsCCInfo.analyzeFormalArguments(Ins, UseSoftFloat, FuncArg); MipsFI->setFormalArgInfo(CCInfo.getNextStackOffset(), MipsCCInfo.hasByValArg()); - Function::const_arg_iterator FuncArg = - DAG.getMachineFunction().getFunction()->arg_begin(); unsigned CurArgIdx = 0; MipsCC::byval_iterator ByValArg = MipsCCInfo.byval_begin(); @@ -3713,9 +3713,11 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, ArgValue = DAG.getNode(ISD::TRUNCATE, dl, ValVT, ArgValue); } - // Handle floating point arguments passed in integer registers. + // Handle floating point arguments passed in integer registers and + // long double arguments passed in floating point registers. if ((RegVT == MVT::i32 && ValVT == MVT::f32) || - (RegVT == MVT::i64 && ValVT == MVT::f64)) + (RegVT == MVT::i64 && ValVT == MVT::f64) || + (RegVT == MVT::f64 && ValVT == MVT::i64)) ArgValue = DAG.getNode(ISD::BITCAST, dl, ValVT, ArgValue); else if (IsO32 && RegVT == MVT::i32 && ValVT == MVT::f64) { unsigned Reg2 = AddLiveIn(DAG.getMachineFunction(), @@ -4175,20 +4177,26 @@ analyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Args, } void MipsTargetLowering::MipsCC:: -analyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Args) { +analyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Args, + bool IsSoftFloat, Function::const_arg_iterator FuncArg) { unsigned NumArgs = Args.size(); llvm::CCAssignFn *FixedFn = fixedArgFn(); + unsigned CurArgIdx = 0; for (unsigned I = 0; I != NumArgs; ++I) { MVT ArgVT = Args[I].VT; ISD::ArgFlagsTy ArgFlags = Args[I].Flags; + std::advance(FuncArg, Args[I].OrigArgIndex - CurArgIdx); + CurArgIdx = Args[I].OrigArgIndex; if (ArgFlags.isByVal()) { handleByValArg(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags); continue; } - if (!FixedFn(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo)) + MVT RegVT = getRegVT(ArgVT, FuncArg->getType(), 0, IsSoftFloat); + + if (!FixedFn(I, ArgVT, RegVT, CCValAssign::Full, ArgFlags, CCInfo)) continue; #ifndef NDEBUG @@ -4273,6 +4281,58 @@ void MipsTargetLowering::MipsCC::allocateRegs(ByValArgInfo &ByVal, CCInfo.AllocateReg(IntArgRegs[I], ShadowRegs[I]); } +/// This function returns true if CallSym is a long double emulation routine. +static bool isF128SoftLibCall(const char *CallSym) { + const char *const LibCalls[] = + {"__addtf3", "__divtf3", "__eqtf2", "__extenddftf2", "__extendsftf2", + "__fixtfdi", "__fixtfsi", "__fixtfti", "__fixunstfdi", "__fixunstfsi", + "__fixunstfti", "__floatditf", "__floatsitf", "__floattitf", + "__floatunditf", "__floatunsitf", "__floatuntitf", "__getf2", "__gttf2", + "__letf2", "__lttf2", "__multf3", "__netf2", "__powitf2", "__subtf3", + "__trunctfdf2", "__trunctfsf2", "__unordtf2", + "ceill", "copysignl", "cosl", "exp2l", "expl", "floorl", "fmal", "fmodl", + "log10l", "log2l", "logl", "nearbyintl", "powl", "rintl", "sinl", "sqrtl", + "truncl"}; + + const char * const *End = LibCalls + array_lengthof(LibCalls); + + // Check that LibCalls is sorted alphabetically. +#ifndef NDEBUG + ltstr Comp; + + for (const char * const *I = LibCalls; I < End - 1; ++I) + assert(Comp(*I, *(I + 1))); +#endif + + return std::binary_search(LibCalls, End, CallSym, ltstr()); +} + + +MVT MipsTargetLowering::MipsCC::getRegVT(MVT VT, const Type *OrigTy, + const SDNode *CallNode, + bool IsSoftFloat) const { + if (IsSoftFloat || IsO32) + return VT; + + // Check if the original type was fp128. + if (OrigTy->isFP128Ty()) { + assert(VT == MVT::i64); + return MVT::f64; + } + + const ExternalSymbolSDNode *ES = + dyn_cast_or_null<const ExternalSymbolSDNode>(CallNode); + + // If the original type was i128 and the function being called is a long + // double emulation routine, the argument must be passed in an f64 register. + if (ES && OrigTy->isIntegerTy(128) && isF128SoftLibCall(ES->getSymbol())) { + assert(VT == MVT::i64); + return MVT::f64; + } + + return VT; +} + void MipsTargetLowering:: copyByValRegs(SDValue Chain, DebugLoc DL, std::vector<SDValue> &OutChains, SelectionDAG &DAG, const ISD::ArgFlagsTy &Flags, diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index 5b2ef08b7b..22751694bb 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -19,6 +19,7 @@ #include "MipsSubtarget.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/IR/Function.h" #include "llvm/Target/TargetLowering.h" #include <deque> #include <string> @@ -205,7 +206,9 @@ namespace llvm { void analyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsVarArg); - void analyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Ins); + void analyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Ins, + bool IsSoftFloat, + Function::const_arg_iterator FuncArg); const CCState &getCCInfo() const { return CCInfo; } /// hasByValArg - Returns true if function has byval arguments. @@ -248,6 +251,13 @@ namespace llvm { void allocateRegs(ByValArgInfo &ByVal, unsigned ByValSize, unsigned Align); + /// Return the type of the register which is used to pass an argument or + /// return a value. This function returns f64 if the argument is an i64 + /// value which has been generated as a result of softening an f128 value. + /// Otherwise, it just returns VT. + MVT getRegVT(MVT VT, const Type *OrigTy, const SDNode *CallNode, + bool IsSoftFloat) const; + CCState &CCInfo; CallingConv::ID CallConv; bool IsO32; diff --git a/test/CodeGen/Mips/mips64-call.ll b/test/CodeGen/Mips/mips64-call.ll new file mode 100644 index 0000000000..7808ac3cc0 --- /dev/null +++ b/test/CodeGen/Mips/mips64-call.ll @@ -0,0 +1,13 @@ +; RUN: llc -march=mips64el -mcpu=mips64r2 < %s | FileCheck %s + +@gld0 = external global fp128 + +; CHECK: foo0 +; CHECK: sdc1 $f13, 8(${{[0-9]+}}) +; CHECK: sdc1 $f12, 0(${{[0-9]+}}) + +define void @foo0(fp128 %a0) { +entry: + store fp128 %a0, fp128* @gld0, align 16 + ret void +} |