Skip to content

Commit 9f34406

Browse files
committed
x86 users can now return arbitrary sized structs. Structs too large to fit in return registers will be returned through a hidden sret parameter introduced during SelectionDAG construction.
llvm-svn: 86876
1 parent 71782d5 commit 9f34406

3 files changed

Lines changed: 228 additions & 67 deletions

File tree

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp

Lines changed: 203 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -951,50 +951,49 @@ SDValue SelectionDAGLowering::getValue(const Value *V) {
951951
/// Get the EVTs and ArgFlags collections that represent the return type
952952
/// of the given function. This does not require a DAG or a return value, and
953953
/// is suitable for use before any DAGs for the function are constructed.
954-
static void getReturnInfo(const Function* F, SmallVectorImpl<EVT> &OutVTs,
954+
static void getReturnInfo(const Type* ReturnType,
955+
Attributes attr, SmallVectorImpl<EVT> &OutVTs,
955956
SmallVectorImpl<ISD::ArgFlagsTy> &OutFlags,
956-
TargetLowering &TLI) {
957-
const Type* ReturnType = F->getReturnType();
958-
957+
TargetLowering &TLI,
958+
SmallVectorImpl<uint64_t> *Offsets = 0) {
959959
SmallVector<EVT, 4> ValueVTs;
960-
ComputeValueVTs(TLI, ReturnType, ValueVTs);
960+
ComputeValueVTs(TLI, ReturnType, ValueVTs, Offsets);
961961
unsigned NumValues = ValueVTs.size();
962962
if ( NumValues == 0 ) return;
963963

964964
for (unsigned j = 0, f = NumValues; j != f; ++j) {
965965
EVT VT = ValueVTs[j];
966966
ISD::NodeType ExtendKind = ISD::ANY_EXTEND;
967-
968-
if (F->paramHasAttr(0, Attribute::SExt))
967+
968+
if (attr & Attribute::SExt)
969969
ExtendKind = ISD::SIGN_EXTEND;
970-
else if (F->paramHasAttr(0, Attribute::ZExt))
970+
else if (attr & Attribute::ZExt)
971971
ExtendKind = ISD::ZERO_EXTEND;
972972

973973
// FIXME: C calling convention requires the return type to be promoted to
974974
// at least 32-bit. But this is not necessary for non-C calling
975975
// conventions. The frontend should mark functions whose return values
976976
// require promoting with signext or zeroext attributes.
977977
if (ExtendKind != ISD::ANY_EXTEND && VT.isInteger()) {
978-
EVT MinVT = TLI.getRegisterType(F->getContext(), MVT::i32);
978+
EVT MinVT = TLI.getRegisterType(ReturnType->getContext(), MVT::i32);
979979
if (VT.bitsLT(MinVT))
980980
VT = MinVT;
981981
}
982982

983-
unsigned NumParts = TLI.getNumRegisters(F->getContext(), VT);
984-
EVT PartVT = TLI.getRegisterType(F->getContext(), VT);
983+
unsigned NumParts = TLI.getNumRegisters(ReturnType->getContext(), VT);
984+
EVT PartVT = TLI.getRegisterType(ReturnType->getContext(), VT);
985985
// 'inreg' on function refers to return value
986986
ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy();
987-
if (F->paramHasAttr(0, Attribute::InReg))
987+
if (attr & Attribute::InReg)
988988
Flags.setInReg();
989989

990990
// Propagate extension type if any
991-
if (F->paramHasAttr(0, Attribute::SExt))
991+
if (attr & Attribute::SExt)
992992
Flags.setSExt();
993-
else if (F->paramHasAttr(0, Attribute::ZExt))
993+
else if (attr & Attribute::ZExt)
994994
Flags.setZExt();
995995

996-
for (unsigned i = 0; i < NumParts; ++i)
997-
{
996+
for (unsigned i = 0; i < NumParts; ++i) {
998997
OutVTs.push_back(PartVT);
999998
OutFlags.push_back(Flags);
1000999
}
@@ -1004,54 +1003,88 @@ static void getReturnInfo(const Function* F, SmallVectorImpl<EVT> &OutVTs,
10041003
void SelectionDAGLowering::visitRet(ReturnInst &I) {
10051004
SDValue Chain = getControlRoot();
10061005
SmallVector<ISD::OutputArg, 8> Outs;
1007-
for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) {
1006+
FunctionLoweringInfo &FLI = DAG.getFunctionLoweringInfo();
1007+
1008+
if (!FLI.CanLowerReturn) {
1009+
unsigned DemoteReg = FLI.DemoteRegister;
1010+
const Function *F = I.getParent()->getParent();
1011+
1012+
// Emit a store of the return value through the virtual register.
1013+
// Leave Outs empty so that LowerReturn won't try to load return
1014+
// registers the usual way.
1015+
SmallVector<EVT, 1> PtrValueVTs;
1016+
ComputeValueVTs(TLI, PointerType::getUnqual(F->getReturnType()),
1017+
PtrValueVTs);
1018+
1019+
SDValue RetPtr = DAG.getRegister(DemoteReg, PtrValueVTs[0]);
1020+
SDValue RetOp = getValue(I.getOperand(0));
1021+
10081022
SmallVector<EVT, 4> ValueVTs;
1009-
ComputeValueVTs(TLI, I.getOperand(i)->getType(), ValueVTs);
1023+
SmallVector<uint64_t, 4> Offsets;
1024+
ComputeValueVTs(TLI, I.getOperand(0)->getType(), ValueVTs, &Offsets);
10101025
unsigned NumValues = ValueVTs.size();
1011-
if (NumValues == 0) continue;
1012-
1013-
SDValue RetOp = getValue(I.getOperand(i));
1014-
for (unsigned j = 0, f = NumValues; j != f; ++j) {
1015-
EVT VT = ValueVTs[j];
10161026

1017-
ISD::NodeType ExtendKind = ISD::ANY_EXTEND;
1018-
1019-
const Function *F = I.getParent()->getParent();
1020-
if (F->paramHasAttr(0, Attribute::SExt))
1021-
ExtendKind = ISD::SIGN_EXTEND;
1022-
else if (F->paramHasAttr(0, Attribute::ZExt))
1023-
ExtendKind = ISD::ZERO_EXTEND;
1027+
SmallVector<SDValue, 4> Chains(NumValues);
1028+
EVT PtrVT = PtrValueVTs[0];
1029+
for (unsigned i = 0; i != NumValues; ++i)
1030+
Chains[i] = DAG.getStore(Chain, getCurDebugLoc(),
1031+
SDValue(RetOp.getNode(), RetOp.getResNo() + i),
1032+
DAG.getNode(ISD::ADD, getCurDebugLoc(), PtrVT, RetPtr,
1033+
DAG.getConstant(Offsets[i], PtrVT)),
1034+
NULL, Offsets[i], false, 0);
1035+
Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(),
1036+
MVT::Other, &Chains[0], NumValues);
1037+
}
1038+
else {
1039+
for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) {
1040+
SmallVector<EVT, 4> ValueVTs;
1041+
ComputeValueVTs(TLI, I.getOperand(i)->getType(), ValueVTs);
1042+
unsigned NumValues = ValueVTs.size();
1043+
if (NumValues == 0) continue;
1044+
1045+
SDValue RetOp = getValue(I.getOperand(i));
1046+
for (unsigned j = 0, f = NumValues; j != f; ++j) {
1047+
EVT VT = ValueVTs[j];
1048+
1049+
ISD::NodeType ExtendKind = ISD::ANY_EXTEND;
1050+
1051+
const Function *F = I.getParent()->getParent();
1052+
if (F->paramHasAttr(0, Attribute::SExt))
1053+
ExtendKind = ISD::SIGN_EXTEND;
1054+
else if (F->paramHasAttr(0, Attribute::ZExt))
1055+
ExtendKind = ISD::ZERO_EXTEND;
1056+
1057+
// FIXME: C calling convention requires the return type to be promoted to
1058+
// at least 32-bit. But this is not necessary for non-C calling
1059+
// conventions. The frontend should mark functions whose return values
1060+
// require promoting with signext or zeroext attributes.
1061+
if (ExtendKind != ISD::ANY_EXTEND && VT.isInteger()) {
1062+
EVT MinVT = TLI.getRegisterType(*DAG.getContext(), MVT::i32);
1063+
if (VT.bitsLT(MinVT))
1064+
VT = MinVT;
1065+
}
10241066

1025-
// FIXME: C calling convention requires the return type to be promoted to
1026-
// at least 32-bit. But this is not necessary for non-C calling
1027-
// conventions. The frontend should mark functions whose return values
1028-
// require promoting with signext or zeroext attributes.
1029-
if (ExtendKind != ISD::ANY_EXTEND && VT.isInteger()) {
1030-
EVT MinVT = TLI.getRegisterType(*DAG.getContext(), MVT::i32);
1031-
if (VT.bitsLT(MinVT))
1032-
VT = MinVT;
1067+
unsigned NumParts = TLI.getNumRegisters(*DAG.getContext(), VT);
1068+
EVT PartVT = TLI.getRegisterType(*DAG.getContext(), VT);
1069+
SmallVector<SDValue, 4> Parts(NumParts);
1070+
getCopyToParts(DAG, getCurDebugLoc(),
1071+
SDValue(RetOp.getNode(), RetOp.getResNo() + j),
1072+
&Parts[0], NumParts, PartVT, ExtendKind);
1073+
1074+
// 'inreg' on function refers to return value
1075+
ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy();
1076+
if (F->paramHasAttr(0, Attribute::InReg))
1077+
Flags.setInReg();
1078+
1079+
// Propagate extension type if any
1080+
if (F->paramHasAttr(0, Attribute::SExt))
1081+
Flags.setSExt();
1082+
else if (F->paramHasAttr(0, Attribute::ZExt))
1083+
Flags.setZExt();
1084+
1085+
for (unsigned i = 0; i < NumParts; ++i)
1086+
Outs.push_back(ISD::OutputArg(Flags, Parts[i], /*isfixed=*/true));
10331087
}
1034-
1035-
unsigned NumParts = TLI.getNumRegisters(*DAG.getContext(), VT);
1036-
EVT PartVT = TLI.getRegisterType(*DAG.getContext(), VT);
1037-
SmallVector<SDValue, 4> Parts(NumParts);
1038-
getCopyToParts(DAG, getCurDebugLoc(),
1039-
SDValue(RetOp.getNode(), RetOp.getResNo() + j),
1040-
&Parts[0], NumParts, PartVT, ExtendKind);
1041-
1042-
// 'inreg' on function refers to return value
1043-
ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy();
1044-
if (F->paramHasAttr(0, Attribute::InReg))
1045-
Flags.setInReg();
1046-
1047-
// Propagate extension type if any
1048-
if (F->paramHasAttr(0, Attribute::SExt))
1049-
Flags.setSExt();
1050-
else if (F->paramHasAttr(0, Attribute::ZExt))
1051-
Flags.setZExt();
1052-
1053-
for (unsigned i = 0; i < NumParts; ++i)
1054-
Outs.push_back(ISD::OutputArg(Flags, Parts[i], /*isfixed=*/true));
10551088
}
10561089
}
10571090

@@ -4453,15 +4486,52 @@ void SelectionDAGLowering::LowerCallTo(CallSite CS, SDValue Callee,
44534486
MachineBasicBlock *LandingPad) {
44544487
const PointerType *PT = cast<PointerType>(CS.getCalledValue()->getType());
44554488
const FunctionType *FTy = cast<FunctionType>(PT->getElementType());
4489+
const Type *RetTy = FTy->getReturnType();
44564490
MachineModuleInfo *MMI = DAG.getMachineModuleInfo();
44574491
unsigned BeginLabel = 0, EndLabel = 0;
44584492

44594493
TargetLowering::ArgListTy Args;
44604494
TargetLowering::ArgListEntry Entry;
44614495
Args.reserve(CS.arg_size());
4462-
unsigned j = 1;
4496+
4497+
// Check whether the function can return without sret-demotion.
4498+
SmallVector<EVT, 4> OutVTs;
4499+
SmallVector<ISD::ArgFlagsTy, 4> OutsFlags;
4500+
SmallVector<uint64_t, 4> Offsets;
4501+
getReturnInfo(RetTy, CS.getAttributes().getRetAttributes(),
4502+
OutVTs, OutsFlags, TLI, &Offsets);
4503+
4504+
4505+
bool CanLowerReturn = TLI.CanLowerReturn(CS.getCallingConv(),
4506+
FTy->isVarArg(), OutVTs, OutsFlags, DAG);
4507+
4508+
SDValue DemoteStackSlot;
4509+
4510+
if (!CanLowerReturn) {
4511+
uint64_t TySize = TLI.getTargetData()->getTypeAllocSize(
4512+
FTy->getReturnType());
4513+
unsigned Align = TLI.getTargetData()->getPrefTypeAlignment(
4514+
FTy->getReturnType());
4515+
MachineFunction &MF = DAG.getMachineFunction();
4516+
int SSFI = MF.getFrameInfo()->CreateStackObject(TySize, Align);
4517+
const Type *StackSlotPtrType = PointerType::getUnqual(FTy->getReturnType());
4518+
4519+
DemoteStackSlot = DAG.getFrameIndex(SSFI, TLI.getPointerTy());
4520+
Entry.Node = DemoteStackSlot;
4521+
Entry.Ty = StackSlotPtrType;
4522+
Entry.isSExt = false;
4523+
Entry.isZExt = false;
4524+
Entry.isInReg = false;
4525+
Entry.isSRet = true;
4526+
Entry.isNest = false;
4527+
Entry.isByVal = false;
4528+
Entry.Alignment = Align;
4529+
Args.push_back(Entry);
4530+
RetTy = Type::getVoidTy(FTy->getContext());
4531+
}
4532+
44634533
for (CallSite::arg_iterator i = CS.arg_begin(), e = CS.arg_end();
4464-
i != e; ++i, ++j) {
4534+
i != e; ++i) {
44654535
SDValue ArgNode = getValue(*i);
44664536
Entry.Node = ArgNode; Entry.Ty = (*i)->getType();
44674537

@@ -4497,7 +4567,7 @@ void SelectionDAGLowering::LowerCallTo(CallSite CS, SDValue Callee,
44974567
isTailCall = false;
44984568

44994569
std::pair<SDValue,SDValue> Result =
4500-
TLI.LowerCallTo(getRoot(), CS.getType(),
4570+
TLI.LowerCallTo(getRoot(), RetTy,
45014571
CS.paramHasAttr(0, Attribute::SExt),
45024572
CS.paramHasAttr(0, Attribute::ZExt), FTy->isVarArg(),
45034573
CS.paramHasAttr(0, Attribute::InReg), FTy->getNumParams(),
@@ -4511,6 +4581,35 @@ void SelectionDAGLowering::LowerCallTo(CallSite CS, SDValue Callee,
45114581
"Null value expected with tail call!");
45124582
if (Result.first.getNode())
45134583
setValue(CS.getInstruction(), Result.first);
4584+
else if (!CanLowerReturn && Result.second.getNode()) {
4585+
// The instruction result is the result of loading from the
4586+
// hidden sret parameter.
4587+
SmallVector<EVT, 1> PVTs;
4588+
const Type *PtrRetTy = PointerType::getUnqual(FTy->getReturnType());
4589+
4590+
ComputeValueVTs(TLI, PtrRetTy, PVTs);
4591+
assert(PVTs.size() == 1 && "Pointers should fit in one register");
4592+
EVT PtrVT = PVTs[0];
4593+
unsigned NumValues = OutVTs.size();
4594+
SmallVector<SDValue, 4> Values(NumValues);
4595+
SmallVector<SDValue, 4> Chains(NumValues);
4596+
4597+
for (unsigned i = 0; i < NumValues; ++i) {
4598+
SDValue L = DAG.getLoad(OutVTs[i], getCurDebugLoc(), Result.second,
4599+
DAG.getNode(ISD::ADD, getCurDebugLoc(), PtrVT, DemoteStackSlot,
4600+
DAG.getConstant(Offsets[i], PtrVT)),
4601+
NULL, Offsets[i], false, 1);
4602+
Values[i] = L;
4603+
Chains[i] = L.getValue(1);
4604+
}
4605+
SDValue Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(),
4606+
MVT::Other, &Chains[0], NumValues);
4607+
PendingLoads.push_back(Chain);
4608+
4609+
setValue(CS.getInstruction(), DAG.getNode(ISD::MERGE_VALUES,
4610+
getCurDebugLoc(), DAG.getVTList(&OutVTs[0], NumValues),
4611+
&Values[0], NumValues));
4612+
}
45144613
// As a special case, a null chain means that a tail call has
45154614
// been emitted and the DAG root is already updated.
45164615
if (Result.second.getNode())
@@ -5779,17 +5878,32 @@ void SelectionDAGISel::LowerArguments(BasicBlock *LLVMBB) {
57795878
SDValue OldRoot = DAG.getRoot();
57805879
DebugLoc dl = SDL->getCurDebugLoc();
57815880
const TargetData *TD = TLI.getTargetData();
5881+
SmallVector<ISD::InputArg, 16> Ins;
57825882

57835883
// Check whether the function can return without sret-demotion.
57845884
SmallVector<EVT, 4> OutVTs;
57855885
SmallVector<ISD::ArgFlagsTy, 4> OutsFlags;
5786-
getReturnInfo(&F, OutVTs, OutsFlags, TLI);
5787-
// For now, assert and bail out if it can't.
5788-
assert(TLI.CanLowerReturn(F.getCallingConv(), F.isVarArg(), OutVTs, OutsFlags,
5789-
DAG) && "Cannot fit return value in registers!");
5886+
getReturnInfo(F.getReturnType(), F.getAttributes().getRetAttributes(),
5887+
OutVTs, OutsFlags, TLI);
5888+
FunctionLoweringInfo &FLI = DAG.getFunctionLoweringInfo();
5889+
5890+
FLI.CanLowerReturn = TLI.CanLowerReturn(F.getCallingConv(), F.isVarArg(),
5891+
OutVTs, OutsFlags, DAG);
5892+
if (!FLI.CanLowerReturn) {
5893+
// Put in an sret pointer parameter before all the other parameters.
5894+
SmallVector<EVT, 1> ValueVTs;
5895+
ComputeValueVTs(TLI, PointerType::getUnqual(F.getReturnType()), ValueVTs);
5896+
5897+
// NOTE: Assuming that a pointer will never break down to more than one VT
5898+
// or one register.
5899+
ISD::ArgFlagsTy Flags;
5900+
Flags.setSRet();
5901+
EVT RegisterVT = TLI.getRegisterType(*CurDAG->getContext(), ValueVTs[0]);
5902+
ISD::InputArg RetArg(Flags, RegisterVT, true);
5903+
Ins.push_back(RetArg);
5904+
}
57905905

57915906
// Set up the incoming argument description vector.
5792-
SmallVector<ISD::InputArg, 16> Ins;
57935907
unsigned Idx = 1;
57945908
for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end();
57955909
I != E; ++I, ++Idx) {
@@ -5867,6 +5981,28 @@ void SelectionDAGISel::LowerArguments(BasicBlock *LLVMBB) {
58675981
// Set up the argument values.
58685982
unsigned i = 0;
58695983
Idx = 1;
5984+
if (!FLI.CanLowerReturn) {
5985+
// Create a virtual register for the sret pointer, and put in a copy
5986+
// from the sret argument into it.
5987+
SmallVector<EVT, 1> ValueVTs;
5988+
ComputeValueVTs(TLI, PointerType::getUnqual(F.getReturnType()), ValueVTs);
5989+
EVT VT = ValueVTs[0];
5990+
EVT RegVT = TLI.getRegisterType(*CurDAG->getContext(), VT);
5991+
ISD::NodeType AssertOp = ISD::DELETED_NODE;
5992+
SDValue ArgValue = getCopyFromParts(DAG, dl, &InVals[0], 1, RegVT,
5993+
VT, AssertOp);
5994+
5995+
MachineFunction& MF = SDL->DAG.getMachineFunction();
5996+
MachineRegisterInfo& RegInfo = MF.getRegInfo();
5997+
unsigned SRetReg = RegInfo.createVirtualRegister(TLI.getRegClassFor(RegVT));
5998+
FLI.DemoteRegister = SRetReg;
5999+
NewRoot = SDL->DAG.getCopyToReg(NewRoot, SDL->getCurDebugLoc(), SRetReg, ArgValue);
6000+
DAG.setRoot(NewRoot);
6001+
6002+
// i indexes lowered arguments. Bump it past the hidden sret argument.
6003+
// Idx indexes LLVM arguments. Don't touch it.
6004+
++i;
6005+
}
58706006
for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E;
58716007
++I, ++Idx) {
58726008
SmallVector<SDValue, 4> ArgValues;

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ class FunctionLoweringInfo {
9090
MachineFunction *MF;
9191
MachineRegisterInfo *RegInfo;
9292

93+
/// CanLowerReturn - true iff the function's return value can be lowered to
94+
/// registers.
95+
bool CanLowerReturn;
96+
97+
/// DemoteRegister - if CanLowerReturn is false, DemoteRegister is a vreg
98+
/// allocated to hold a pointer to the hidden sret parameter.
99+
unsigned DemoteRegister;
100+
93101
explicit FunctionLoweringInfo(TargetLowering &TLI);
94102

95103
/// set - Initialize this FunctionLoweringInfo with the given Function
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
; RUN: llc < %s -march=x86 -o %t
2+
; RUN: grep "movl .24601, 12(%ecx)" %t
3+
; RUN: grep "movl .48, 8(%ecx)" %t
4+
; RUN: grep "movl .24, 4(%ecx)" %t
5+
; RUN: grep "movl .12, (%ecx)" %t
6+
7+
%0 = type { i32, i32, i32, i32 }
8+
9+
define internal fastcc %0 @ReturnBigStruct() nounwind readnone {
10+
entry:
11+
%0 = insertvalue %0 zeroinitializer, i32 12, 0
12+
%1 = insertvalue %0 %0, i32 24, 1
13+
%2 = insertvalue %0 %1, i32 48, 2
14+
%3 = insertvalue %0 %2, i32 24601, 3
15+
ret %0 %3
16+
}
17+

0 commit comments

Comments
 (0)