forked from OSchip/llvm-project
[mips] Fix MipsCC::analyzeReturn so that, in soft-float mode, fp128 gets
returned in registers $2 and $4. llvm-svn: 176527
This commit is contained in:
parent
864b810739
commit
e092f72956
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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<const ExternalSymbolSDNode>(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<typename Ty>
|
|||
void MipsTargetLowering::MipsCC::
|
||||
analyzeReturn(const SmallVectorImpl<Ty> &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<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())) {
|
||||
if (originalTypeIsF128(OrigTy, CallNode)) {
|
||||
assert(VT == MVT::i64);
|
||||
return MVT::f64;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue