mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-09 05:13:01 +00:00
Pass sret arguments through the stack instead of through registers in Sparc backend. It makes the code generated more compliant with the sparc32 ABI.
llvm-svn: 124030
This commit is contained in:
parent
beeff6bcf0
commit
66369057ae
@ -24,6 +24,8 @@ def RetCC_Sparc32 : CallingConv<[
|
|||||||
|
|
||||||
// Sparc 32-bit C Calling convention.
|
// Sparc 32-bit C Calling convention.
|
||||||
def CC_Sparc32 : CallingConv<[
|
def CC_Sparc32 : CallingConv<[
|
||||||
|
//Custom assign SRet to [sp+64].
|
||||||
|
CCIfSRet<CCCustom<"CC_Sparc_Assign_SRet">>,
|
||||||
// i32 f32 arguments get passed in integer registers if there is space.
|
// i32 f32 arguments get passed in integer registers if there is space.
|
||||||
CCIfType<[i32, f32], CCAssignToReg<[I0, I1, I2, I3, I4, I5]>>,
|
CCIfType<[i32, f32], CCAssignToReg<[I0, I1, I2, I3, I4, I5]>>,
|
||||||
// f64 arguments are split and passed through registers or through stack.
|
// f64 arguments are split and passed through registers or through stack.
|
||||||
|
@ -33,6 +33,19 @@ using namespace llvm;
|
|||||||
// Calling Convention Implementation
|
// Calling Convention Implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
static bool CC_Sparc_Assign_SRet(unsigned &ValNo, MVT &ValVT,
|
||||||
|
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
||||||
|
ISD::ArgFlagsTy &ArgFlags, CCState &State)
|
||||||
|
{
|
||||||
|
assert (ArgFlags.isSRet());
|
||||||
|
|
||||||
|
//Assign SRet argument
|
||||||
|
State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
|
||||||
|
0,
|
||||||
|
LocVT, LocInfo));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool CC_Sparc_Assign_f64(unsigned &ValNo, MVT &ValVT,
|
static bool CC_Sparc_Assign_f64(unsigned &ValNo, MVT &ValVT,
|
||||||
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
||||||
ISD::ArgFlagsTy &ArgFlags, CCState &State)
|
ISD::ArgFlagsTy &ArgFlags, CCState &State)
|
||||||
@ -70,6 +83,8 @@ SparcTargetLowering::LowerReturn(SDValue Chain,
|
|||||||
const SmallVectorImpl<SDValue> &OutVals,
|
const SmallVectorImpl<SDValue> &OutVals,
|
||||||
DebugLoc dl, SelectionDAG &DAG) const {
|
DebugLoc dl, SelectionDAG &DAG) const {
|
||||||
|
|
||||||
|
MachineFunction &MF = DAG.getMachineFunction();
|
||||||
|
|
||||||
// CCValAssign - represent the assignment of the return value to locations.
|
// CCValAssign - represent the assignment of the return value to locations.
|
||||||
SmallVector<CCValAssign, 16> RVLocs;
|
SmallVector<CCValAssign, 16> RVLocs;
|
||||||
|
|
||||||
@ -82,10 +97,10 @@ SparcTargetLowering::LowerReturn(SDValue Chain,
|
|||||||
|
|
||||||
// If this is the first return lowered for this function, add the regs to the
|
// If this is the first return lowered for this function, add the regs to the
|
||||||
// liveout set for the function.
|
// liveout set for the function.
|
||||||
if (DAG.getMachineFunction().getRegInfo().liveout_empty()) {
|
if (MF.getRegInfo().liveout_empty()) {
|
||||||
for (unsigned i = 0; i != RVLocs.size(); ++i)
|
for (unsigned i = 0; i != RVLocs.size(); ++i)
|
||||||
if (RVLocs[i].isRegLoc())
|
if (RVLocs[i].isRegLoc())
|
||||||
DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg());
|
MF.getRegInfo().addLiveOut(RVLocs[i].getLocReg());
|
||||||
}
|
}
|
||||||
|
|
||||||
SDValue Flag;
|
SDValue Flag;
|
||||||
@ -101,6 +116,18 @@ SparcTargetLowering::LowerReturn(SDValue Chain,
|
|||||||
// Guarantee that all emitted copies are stuck together with flags.
|
// Guarantee that all emitted copies are stuck together with flags.
|
||||||
Flag = Chain.getValue(1);
|
Flag = Chain.getValue(1);
|
||||||
}
|
}
|
||||||
|
// If the function returns a struct, copy the SRetReturnReg to I0
|
||||||
|
if (MF.getFunction()->hasStructRetAttr()) {
|
||||||
|
SparcMachineFunctionInfo *SFI = MF.getInfo<SparcMachineFunctionInfo>();
|
||||||
|
unsigned Reg = SFI->getSRetReturnReg();
|
||||||
|
if (!Reg)
|
||||||
|
llvm_unreachable("sret virtual register not created in the entry block");
|
||||||
|
SDValue Val = DAG.getCopyFromReg(Chain, dl, Reg, getPointerTy());
|
||||||
|
Chain = DAG.getCopyToReg(Chain, dl, SP::I0, Val, Flag);
|
||||||
|
Flag = Chain.getValue(1);
|
||||||
|
if (MF.getRegInfo().liveout_empty())
|
||||||
|
MF.getRegInfo().addLiveOut(SP::I0);
|
||||||
|
}
|
||||||
|
|
||||||
if (Flag.getNode())
|
if (Flag.getNode())
|
||||||
return DAG.getNode(SPISD::RET_FLAG, dl, MVT::Other, Chain, Flag);
|
return DAG.getNode(SPISD::RET_FLAG, dl, MVT::Other, Chain, Flag);
|
||||||
@ -134,6 +161,17 @@ SparcTargetLowering::LowerFormalArguments(SDValue Chain,
|
|||||||
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
||||||
CCValAssign &VA = ArgLocs[i];
|
CCValAssign &VA = ArgLocs[i];
|
||||||
|
|
||||||
|
if (i == 0 && Ins[i].Flags.isSRet()) {
|
||||||
|
//Get SRet from [%fp+64]
|
||||||
|
int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, 64, true);
|
||||||
|
SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
|
||||||
|
SDValue Arg = DAG.getLoad(MVT::i32, dl, Chain, FIPtr,
|
||||||
|
MachinePointerInfo(),
|
||||||
|
false, false, 0);
|
||||||
|
InVals.push_back(Arg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (VA.isRegLoc()) {
|
if (VA.isRegLoc()) {
|
||||||
EVT RegVT = VA.getLocVT();
|
EVT RegVT = VA.getLocVT();
|
||||||
|
|
||||||
@ -244,6 +282,18 @@ SparcTargetLowering::LowerFormalArguments(SDValue Chain,
|
|||||||
InVals.push_back(Load);
|
InVals.push_back(Load);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (MF.getFunction()->hasStructRetAttr()) {
|
||||||
|
//Copy the SRet Argument to SRetReturnReg
|
||||||
|
SparcMachineFunctionInfo *SFI = MF.getInfo<SparcMachineFunctionInfo>();
|
||||||
|
unsigned Reg = SFI->getSRetReturnReg();
|
||||||
|
if (!Reg) {
|
||||||
|
Reg = MF.getRegInfo().createVirtualRegister(&SP::IntRegsRegClass);
|
||||||
|
SFI->setSRetReturnReg(Reg);
|
||||||
|
}
|
||||||
|
SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), dl, Reg, InVals[0]);
|
||||||
|
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Copy, Chain);
|
||||||
|
}
|
||||||
|
|
||||||
// Store remaining ArgRegs to the stack if this is a varargs function.
|
// Store remaining ArgRegs to the stack if this is a varargs function.
|
||||||
if (isVarArg) {
|
if (isVarArg) {
|
||||||
static const unsigned ArgRegs[] = {
|
static const unsigned ArgRegs[] = {
|
||||||
@ -374,6 +424,18 @@ SparcTargetLowering::LowerCall(SDValue Chain, SDValue Callee,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Flags.isSRet()) {
|
||||||
|
assert(VA.needsCustom());
|
||||||
|
// store SRet argument in %sp+64
|
||||||
|
SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32);
|
||||||
|
SDValue PtrOff = DAG.getIntPtrConstant(64);
|
||||||
|
PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff);
|
||||||
|
MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff,
|
||||||
|
MachinePointerInfo(),
|
||||||
|
false, false, 0));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (VA.needsCustom()) {
|
if (VA.needsCustom()) {
|
||||||
assert(VA.getLocVT() == MVT::f64);
|
assert(VA.getLocVT() == MVT::f64);
|
||||||
|
|
||||||
|
@ -24,16 +24,23 @@ namespace llvm {
|
|||||||
/// VarArgsFrameOffset - Frame offset to start of varargs area.
|
/// VarArgsFrameOffset - Frame offset to start of varargs area.
|
||||||
int VarArgsFrameOffset;
|
int VarArgsFrameOffset;
|
||||||
|
|
||||||
|
/// SRetReturnReg - Holds the virtual register into which the sret
|
||||||
|
/// argument is passed.
|
||||||
|
unsigned SRetReturnReg;
|
||||||
public:
|
public:
|
||||||
SparcMachineFunctionInfo() : GlobalBaseReg(0), VarArgsFrameOffset(0) {}
|
SparcMachineFunctionInfo()
|
||||||
|
: GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0) {}
|
||||||
explicit SparcMachineFunctionInfo(MachineFunction &MF)
|
explicit SparcMachineFunctionInfo(MachineFunction &MF)
|
||||||
: GlobalBaseReg(0), VarArgsFrameOffset(0) {}
|
: GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0) {}
|
||||||
|
|
||||||
unsigned getGlobalBaseReg() const { return GlobalBaseReg; }
|
unsigned getGlobalBaseReg() const { return GlobalBaseReg; }
|
||||||
void setGlobalBaseReg(unsigned Reg) { GlobalBaseReg = Reg; }
|
void setGlobalBaseReg(unsigned Reg) { GlobalBaseReg = Reg; }
|
||||||
|
|
||||||
int getVarArgsFrameOffset() const { return VarArgsFrameOffset; }
|
int getVarArgsFrameOffset() const { return VarArgsFrameOffset; }
|
||||||
void setVarArgsFrameOffset(int Offset) { VarArgsFrameOffset = Offset; }
|
void setVarArgsFrameOffset(int Offset) { VarArgsFrameOffset = Offset; }
|
||||||
|
|
||||||
|
unsigned getSRetReturnReg() const { return SRetReturnReg; }
|
||||||
|
void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
36
test/CodeGen/SPARC/2011-01-22-SRet.ll
Normal file
36
test/CodeGen/SPARC/2011-01-22-SRet.ll
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
;RUN: llc -march=sparc < %s | FileCheck %s
|
||||||
|
|
||||||
|
%struct.foo_t = type { i32, i32, i32 }
|
||||||
|
|
||||||
|
define weak void @make_foo(%struct.foo_t* noalias sret %agg.result, i32 %a, i32 %b, i32 %c) nounwind {
|
||||||
|
entry:
|
||||||
|
;CHECK: make_foo
|
||||||
|
;CHECK: ld [%fp+64], {{.+}}
|
||||||
|
;CHECK: or {{.+}}, {{.+}}, %i0
|
||||||
|
;CHECK: ret
|
||||||
|
%0 = getelementptr inbounds %struct.foo_t* %agg.result, i32 0, i32 0
|
||||||
|
store i32 %a, i32* %0, align 4
|
||||||
|
%1 = getelementptr inbounds %struct.foo_t* %agg.result, i32 0, i32 1
|
||||||
|
store i32 %b, i32* %1, align 4
|
||||||
|
%2 = getelementptr inbounds %struct.foo_t* %agg.result, i32 0, i32 2
|
||||||
|
store i32 %c, i32* %2, align 4
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test() nounwind {
|
||||||
|
entry:
|
||||||
|
;CHECK: test
|
||||||
|
;CHECK: st {{.+}}, [%sp+64]
|
||||||
|
;CHECK: make_foo
|
||||||
|
%f = alloca %struct.foo_t, align 8
|
||||||
|
call void @make_foo(%struct.foo_t* noalias sret %f, i32 10, i32 20, i32 30) nounwind
|
||||||
|
%0 = getelementptr inbounds %struct.foo_t* %f, i32 0, i32 0
|
||||||
|
%1 = load i32* %0, align 8
|
||||||
|
%2 = getelementptr inbounds %struct.foo_t* %f, i32 0, i32 1
|
||||||
|
%3 = load i32* %2, align 4
|
||||||
|
%4 = getelementptr inbounds %struct.foo_t* %f, i32 0, i32 2
|
||||||
|
%5 = load i32* %4, align 8
|
||||||
|
%6 = add nsw i32 %3, %1
|
||||||
|
%7 = add nsw i32 %6, %5
|
||||||
|
ret i32 %7
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user