forked from OSchip/llvm-project
[SparcV9]: Implement lowering of long double (fp128) arguments in Sparc64 ABI.
Also, pass fp128 arguments to varargs through integer registers if necessary. llvm-svn: 198145
This commit is contained in:
parent
059e8e0da1
commit
0776cc0acd
|
@ -80,11 +80,14 @@ static bool CC_Sparc_Assign_f64(unsigned &ValNo, MVT &ValVT,
|
||||||
static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT,
|
static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT,
|
||||||
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
||||||
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
|
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");
|
"Can't handle non-64 bits locations");
|
||||||
|
|
||||||
// Stack space is allocated for all arguments starting from [%fp+BIAS+128].
|
// 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;
|
unsigned Reg = 0;
|
||||||
|
|
||||||
if (LocVT == MVT::i64 && Offset < 6*8)
|
if (LocVT == MVT::i64 && Offset < 6*8)
|
||||||
|
@ -96,6 +99,9 @@ static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT,
|
||||||
else if (LocVT == MVT::f32 && Offset < 16*8)
|
else if (LocVT == MVT::f32 && Offset < 16*8)
|
||||||
// Promote floats to %f1, %f3, ...
|
// Promote floats to %f1, %f3, ...
|
||||||
Reg = SP::F1 + Offset/4;
|
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.
|
// Promote to register when possible, otherwise use the stack slot.
|
||||||
if (Reg) {
|
if (Reg) {
|
||||||
|
@ -998,9 +1004,10 @@ static void fixupVariableFloatArgs(SmallVectorImpl<CCValAssign> &ArgLocs,
|
||||||
ArrayRef<ISD::OutputArg> Outs) {
|
ArrayRef<ISD::OutputArg> Outs) {
|
||||||
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
||||||
const CCValAssign &VA = ArgLocs[i];
|
const CCValAssign &VA = ArgLocs[i];
|
||||||
|
MVT ValTy = VA.getLocVT();
|
||||||
// FIXME: What about f32 arguments? C promotes them to f64 when calling
|
// FIXME: What about f32 arguments? C promotes them to f64 when calling
|
||||||
// varargs functions.
|
// varargs functions.
|
||||||
if (!VA.isRegLoc() || VA.getLocVT() != MVT::f64)
|
if (!VA.isRegLoc() || (ValTy != MVT::f64 && ValTy != MVT::f128))
|
||||||
continue;
|
continue;
|
||||||
// The fixed arguments to a varargs function still go in FP registers.
|
// The fixed arguments to a varargs function still go in FP registers.
|
||||||
if (Outs[VA.getValNo()].IsFixed)
|
if (Outs[VA.getValNo()].IsFixed)
|
||||||
|
@ -1010,15 +1017,25 @@ static void fixupVariableFloatArgs(SmallVectorImpl<CCValAssign> &ArgLocs,
|
||||||
CCValAssign NewVA;
|
CCValAssign NewVA;
|
||||||
|
|
||||||
// Determine the offset into the argument array.
|
// 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?");
|
assert(Offset < 16*8 && "Offset out of range, bad register enum?");
|
||||||
|
|
||||||
if (Offset < 6*8) {
|
if (Offset < 6*8) {
|
||||||
// This argument should go in %i0-%i5.
|
// This argument should go in %i0-%i5.
|
||||||
unsigned IReg = SP::I0 + Offset/8;
|
unsigned IReg = SP::I0 + Offset/8;
|
||||||
// Full register, just bitconvert into i64.
|
if (ValTy == MVT::f64)
|
||||||
NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(),
|
// Full register, just bitconvert into i64.
|
||||||
IReg, MVT::i64, CCValAssign::BCvt);
|
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 {
|
} else {
|
||||||
// This needs to go to memory, we're out of integer registers.
|
// This needs to go to memory, we're out of integer registers.
|
||||||
NewVA = CCValAssign::getMem(VA.getValNo(), VA.getValVT(),
|
NewVA = CCValAssign::getMem(VA.getValNo(), VA.getValVT(),
|
||||||
|
@ -1094,11 +1111,46 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
|
||||||
Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg);
|
Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg);
|
||||||
break;
|
break;
|
||||||
case CCValAssign::BCvt:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VA.isRegLoc()) {
|
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
|
// The custom bit on an i32 return value indicates that it should be
|
||||||
// passed in the high bits of the register.
|
// passed in the high bits of the register.
|
||||||
if (VA.getValVT() == MVT::i32 && VA.needsCustom()) {
|
if (VA.getValVT() == MVT::i32 && VA.needsCustom()) {
|
||||||
|
|
|
@ -411,3 +411,33 @@ entry:
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i32 @use_buf(i32, i8*)
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue