From 1e3e869899468de2210f9777905340d907c814c6 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Tue, 5 Mar 2013 22:54:59 +0000 Subject: [PATCH] [mips] Fix MipsCC::analyzeReturn so that, in soft-float mode, fp128 gets returned in registers $2 and $4. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@176527 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Mips/MipsCallingConv.td | 6 ++ lib/Target/Mips/MipsISelLowering.cpp | 89 +++++++++++++++------------- test/CodeGen/Mips/mips64-f128.ll | 10 ++-- 3 files changed, 60 insertions(+), 45 deletions(-) diff --git a/lib/Target/Mips/MipsCallingConv.td b/lib/Target/Mips/MipsCallingConv.td index 78cf140def6..8e9e4c726fa 100644 --- a/lib/Target/Mips/MipsCallingConv.td +++ b/lib/Target/Mips/MipsCallingConv.td @@ -96,6 +96,12 @@ def RetCC_MipsN : CallingConv<[ CCIfType<[f64], CCAssignToReg<[D0_64, D2_64]>> ]>; +// In soft-mode, register A0_64, instead of V1_64, is used to return a long +// double value. +def RetCC_F128Soft : CallingConv<[ + CCIfType<[i64], CCAssignToReg<[V0_64, A0_64]>> +]>; + //===----------------------------------------------------------------------===// // Mips EABI Calling Convention //===----------------------------------------------------------------------===// diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index 4cdca16e9e5..dd569f65a36 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -4152,6 +4152,46 @@ unsigned MipsTargetLowering::getJumpTableEncoding() const { return TargetLowering::getJumpTableEncoding(); } +/// 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()); +} + +/// This function returns true if Ty is fp128 or i128 which was originally a +/// fp128. +static bool originalTypeIsF128(const Type *Ty, const SDNode *CallNode) { + if (Ty->isFP128Ty()) + return true; + + const ExternalSymbolSDNode *ES = + dyn_cast_or_null(CallNode); + + // If the Ty is i128 and the function being called is a long double emulation + // routine, then the original type is f128. + return (ES && Ty->isIntegerTy(128) && isF128SoftLibCall(ES->getSymbol())); +} + MipsTargetLowering::MipsCC::MipsCC(CallingConv::ID CC, bool IsO32_, CCState &Info) : CCInfo(Info), CallConv(CC), IsO32(IsO32_) { @@ -4232,13 +4272,19 @@ template void MipsTargetLowering::MipsCC:: analyzeReturn(const SmallVectorImpl &RetVals, bool IsSoftFloat, const SDNode *CallNode, const Type *RetTy) const { + CCAssignFn *Fn; + + if (IsSoftFloat && originalTypeIsF128(RetTy, CallNode)) + Fn = RetCC_F128Soft; + else + Fn = RetCC_Mips; + for (unsigned I = 0, E = RetVals.size(); I < E; ++I) { MVT VT = RetVals[I].VT; ISD::ArgFlagsTy Flags = RetVals[I].Flags; MVT RegVT = this->getRegVT(VT, RetTy, CallNode, IsSoftFloat); - if (RetCC_Mips(I, VT, RegVT, CCValAssign::Full, Flags, - this->CCInfo)) { + if (Fn(I, VT, RegVT, CCValAssign::Full, Flags, this->CCInfo)) { #ifndef NDEBUG dbgs() << "Call result #" << I << " has unhandled type " << EVT(VT).getEVTString() << '\n'; @@ -4334,33 +4380,6 @@ 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 { @@ -4368,17 +4387,7 @@ MVT MipsTargetLowering::MipsCC::getRegVT(MVT VT, const Type *OrigTy, 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(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())) { + if (originalTypeIsF128(OrigTy, CallNode)) { assert(VT == MVT::i64); return MVT::f64; } diff --git a/test/CodeGen/Mips/mips64-f128.ll b/test/CodeGen/Mips/mips64-f128.ll index 2a84c84bb49..5892cab4f8e 100644 --- a/test/CodeGen/Mips/mips64-f128.ll +++ b/test/CodeGen/Mips/mips64-f128.ll @@ -236,7 +236,7 @@ entry: ; CHECK: daddiu $[[R1:[0-9]+]], $zero, 1 ; CHECK: dsll $[[R2:[0-9]+]], $[[R1]], 63 ; CHECK: daddiu $[[R3:[0-9]+]], $[[R2]], -1 -; CHECK: and $3, $[[R0]], $[[R3]] +; CHECK: and $4, $[[R0]], $[[R3]] ; CHECK: ld $2, 0($[[R4]]) define fp128 @libcall1_fabsl() { @@ -413,7 +413,7 @@ declare fp128 @llvm.powi.f128(fp128, i32) #3 ; CHECK: ld $[[R6:[0-9]+]], 8($[[R5]]) ; CHECK: daddiu $[[R7:[0-9]+]], $[[R3]], -1 ; CHECK: and $[[R8:[0-9]+]], $[[R6]], $[[R7]] -; CHECK: or $3, $[[R8]], $[[R4]] +; CHECK: or $4, $[[R8]], $[[R4]] ; CHECK: ld $2, 0($[[R5]]) define fp128 @libcall2_copysignl() { @@ -529,7 +529,7 @@ entry: ; CHECK: load_LD_LD: ; CHECK: ld $[[R0:[0-9]+]], %got_disp(gld1) ; CHECK: ld $2, 0($[[R0]]) -; CHECK: ld $3, 8($[[R0]]) +; CHECK: ld $4, 8($[[R0]]) define fp128 @load_LD_LD() { entry: @@ -616,7 +616,7 @@ entry: ; CHECK: movn $8, $6, $4 ; CHECK: movn $9, $7, $4 ; CHECK: move $2, $8 -; CHECK: move $3, $9 +; CHECK: move $4, $9 define fp128 @select_LD(i32 %a, i64, fp128 %b, fp128 %c) { entry: @@ -636,7 +636,7 @@ entry: ; CHECK: movz $[[R1]], $[[R3]], $1 ; CHECK: movz $[[R0]], $[[R2]], $1 ; CHECK: move $2, $[[R1]] -; CHECK: move $3, $[[R0]] +; CHECK: move $4, $[[R0]] define fp128 @selectCC_LD(fp128 %a, fp128 %b, fp128 %c, fp128 %d) { entry: