diff options
Diffstat (limited to 'contrib/llvm/patches/patch-r262261-llvm-r198145-sparc.diff')
-rw-r--r-- | contrib/llvm/patches/patch-r262261-llvm-r198145-sparc.diff | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198145-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198145-sparc.diff new file mode 100644 index 0000000..2429e52 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198145-sparc.diff @@ -0,0 +1,166 @@ +Pull in r198145 from upstream llvm trunk (by Venkatraman Govindaraju): + + [SparcV9]: Implement lowering of long double (fp128) arguments in Sparc64 ABI. + Also, pass fp128 arguments to varargs through integer registers if necessary. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/CodeGen/SPARC/64abi.ll +=================================================================== +--- test/CodeGen/SPARC/64abi.ll ++++ test/CodeGen/SPARC/64abi.ll +@@ -411,3 +411,33 @@ entry: + } + + declare i32 @use_buf(i32, i8*) ++ ++; CHECK-LABEL: test_fp128_args ++; CHECK-DAG: std %f0, [%fp+{{.+}}] ++; CHECK-DAG: std %f2, [%fp+{{.+}}] ++; CHECK-DAG: std %f6, [%fp+{{.+}}] ++; CHECK-DAG: std %f4, [%fp+{{.+}}] ++; CHECK: add %fp, [[Offset:[0-9]+]], %o0 ++; CHECK: call _Qp_add ++; CHECK: ldd [%fp+[[Offset]]], %f0 ++define fp128 @test_fp128_args(fp128 %a, fp128 %b) { ++entry: ++ %0 = fadd fp128 %a, %b ++ ret fp128 %0 ++} ++ ++declare i64 @receive_fp128(i64 %a, ...) ++ ++; CHECK-LABEL: test_fp128_variable_args ++; CHECK-DAG: std %f4, [%sp+[[Offset0:[0-9]+]]] ++; CHECK-DAG: std %f6, [%sp+[[Offset1:[0-9]+]]] ++; CHECK-DAG: ldx [%sp+[[Offset0]]], %o2 ++; CHECK-DAG: ldx [%sp+[[Offset1]]], %o3 ++; CHECK: call receive_fp128 ++define i64 @test_fp128_variable_args(i64 %a, fp128 %b) { ++entry: ++ %0 = call i64 (i64, ...)* @receive_fp128(i64 %a, fp128 %b) ++ ret i64 %0 ++} ++ ++ +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -80,11 +80,14 @@ static bool CC_Sparc_Assign_f64(unsigned &ValNo, M + static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT, + MVT &LocVT, CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, CCState &State) { +- assert((LocVT == MVT::f32 || LocVT.getSizeInBits() == 64) && ++ assert((LocVT == MVT::f32 || LocVT == MVT::f128 ++ || LocVT.getSizeInBits() == 64) && + "Can't handle non-64 bits locations"); + + // Stack space is allocated for all arguments starting from [%fp+BIAS+128]. +- unsigned Offset = State.AllocateStack(8, 8); ++ unsigned size = (LocVT == MVT::f128) ? 16 : 8; ++ unsigned alignment = (LocVT == MVT::f128) ? 16 : 8; ++ unsigned Offset = State.AllocateStack(size, alignment); + unsigned Reg = 0; + + if (LocVT == MVT::i64 && Offset < 6*8) +@@ -96,6 +99,9 @@ static bool CC_Sparc64_Full(unsigned &ValNo, MVT & + else if (LocVT == MVT::f32 && Offset < 16*8) + // Promote floats to %f1, %f3, ... + Reg = SP::F1 + Offset/4; ++ else if (LocVT == MVT::f128 && Offset < 16*8) ++ // Promote long doubles to %q0-%q28. (Which LLVM calls Q0-Q7). ++ Reg = SP::Q0 + Offset/16; + + // Promote to register when possible, otherwise use the stack slot. + if (Reg) { +@@ -998,9 +1004,10 @@ static void fixupVariableFloatArgs(SmallVectorImpl + ArrayRef<ISD::OutputArg> Outs) { + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + const CCValAssign &VA = ArgLocs[i]; ++ MVT ValTy = VA.getLocVT(); + // FIXME: What about f32 arguments? C promotes them to f64 when calling + // varargs functions. +- if (!VA.isRegLoc() || VA.getLocVT() != MVT::f64) ++ if (!VA.isRegLoc() || (ValTy != MVT::f64 && ValTy != MVT::f128)) + continue; + // The fixed arguments to a varargs function still go in FP registers. + if (Outs[VA.getValNo()].IsFixed) +@@ -1010,15 +1017,25 @@ static void fixupVariableFloatArgs(SmallVectorImpl + CCValAssign NewVA; + + // Determine the offset into the argument array. +- unsigned Offset = 8 * (VA.getLocReg() - SP::D0); ++ unsigned firstReg = (ValTy == MVT::f64) ? SP::D0 : SP::Q0; ++ unsigned argSize = (ValTy == MVT::f64) ? 8 : 16; ++ unsigned Offset = argSize * (VA.getLocReg() - firstReg); + assert(Offset < 16*8 && "Offset out of range, bad register enum?"); + + if (Offset < 6*8) { + // This argument should go in %i0-%i5. + unsigned IReg = SP::I0 + Offset/8; +- // Full register, just bitconvert into i64. +- NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(), +- IReg, MVT::i64, CCValAssign::BCvt); ++ if (ValTy == MVT::f64) ++ // Full register, just bitconvert into i64. ++ NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(), ++ IReg, MVT::i64, CCValAssign::BCvt); ++ else { ++ assert(ValTy == MVT::f128 && "Unexpected type!"); ++ // Full register, just bitconvert into i128 -- We will lower this into ++ // two i64s in LowerCall_64. ++ NewVA = CCValAssign::getCustomReg(VA.getValNo(), VA.getValVT(), ++ IReg, MVT::i128, CCValAssign::BCvt); ++ } + } else { + // This needs to go to memory, we're out of integer registers. + NewVA = CCValAssign::getMem(VA.getValNo(), VA.getValVT(), +@@ -1094,11 +1111,46 @@ SparcTargetLowering::LowerCall_64(TargetLowering:: + Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg); + break; + case CCValAssign::BCvt: +- Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg); ++ // fixupVariableFloatArgs() may create bitcasts from f128 to i128. But ++ // SPARC does not support i128 natively. Lower it into two i64, see below. ++ if (!VA.needsCustom() || VA.getValVT() != MVT::f128 ++ || VA.getLocVT() != MVT::i128) ++ Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg); + break; + } + + if (VA.isRegLoc()) { ++ if (VA.needsCustom() && VA.getValVT() == MVT::f128 ++ && VA.getLocVT() == MVT::i128) { ++ // Store and reload into the interger register reg and reg+1. ++ unsigned Offset = 8 * (VA.getLocReg() - SP::I0); ++ unsigned StackOffset = Offset + Subtarget->getStackPointerBias() + 128; ++ SDValue StackPtr = DAG.getRegister(SP::O6, getPointerTy()); ++ SDValue HiPtrOff = DAG.getIntPtrConstant(StackOffset); ++ HiPtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr, ++ HiPtrOff); ++ SDValue LoPtrOff = DAG.getIntPtrConstant(StackOffset + 8); ++ LoPtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr, ++ LoPtrOff); ++ ++ // Store to %sp+BIAS+128+Offset ++ SDValue Store = DAG.getStore(Chain, DL, Arg, HiPtrOff, ++ MachinePointerInfo(), ++ false, false, 0); ++ // Load into Reg and Reg+1 ++ SDValue Hi64 = DAG.getLoad(MVT::i64, DL, Store, HiPtrOff, ++ MachinePointerInfo(), ++ false, false, false, 0); ++ SDValue Lo64 = DAG.getLoad(MVT::i64, DL, Store, LoPtrOff, ++ MachinePointerInfo(), ++ false, false, false, 0); ++ RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()), ++ Hi64)); ++ RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()+1), ++ Lo64)); ++ continue; ++ } ++ + // The custom bit on an i32 return value indicates that it should be + // passed in the high bits of the register. + if (VA.getValVT() == MVT::i32 && VA.needsCustom()) { |