Skip to content

Commit 08bd84e

Browse files
koachantru
authored andcommitted
[SPARC] Make calls to function with big return values work
Implement CanLowerReturn and associated CallingConv changes for SPARC/SPARC64. In particular, for SPARC64 there's new `RetCC_Sparc64_*` functions that handles the return case of the calling convention. It uses the same analysis as `CC_Sparc64_*` family of funtions, but fails if the return value doesn't fit into the return registers. This makes calls to functions with big return values converted to an sret function as expected, instead of crashing LLVM. Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D132465 (cherry picked from commit d3fcbee)
1 parent 9d46557 commit 08bd84e

File tree

6 files changed

+322
-36
lines changed

6 files changed

+322
-36
lines changed

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9693,6 +9693,7 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const {
96939693
Entry.Alignment = Alignment;
96949694
CLI.getArgs().insert(CLI.getArgs().begin(), Entry);
96959695
CLI.NumFixedArgs += 1;
9696+
CLI.getArgs()[0].IndirectType = CLI.RetTy;
96969697
CLI.RetTy = Type::getVoidTy(CLI.RetTy->getContext());
96979698

96989699
// sret demotion isn't compatible with tail-calls, since the sret argument

llvm/lib/Target/Sparc/SparcCallingConv.td

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,14 @@ def CC_Sparc64 : CallingConv<[
125125
def RetCC_Sparc64 : CallingConv<[
126126
// A single f32 return value always goes in %f0. The ABI doesn't specify what
127127
// happens to multiple f32 return values outside a struct.
128-
CCIfType<[f32], CCCustom<"CC_Sparc64_Half">>,
128+
CCIfType<[f32], CCCustom<"RetCC_Sparc64_Half">>,
129129

130-
// Otherwise, return values are passed exactly like arguments.
131-
CCDelegateTo<CC_Sparc64>
130+
// Otherwise, return values are passed exactly like arguments, except that
131+
// returns that are too big to fit into the registers is passed as an sret
132+
// instead.
133+
CCIfInReg<CCIfType<[i32, f32], CCCustom<"RetCC_Sparc64_Half">>>,
134+
CCIfType<[i32], CCPromoteToType<i64>>,
135+
CCCustom<"RetCC_Sparc64_Full">
132136
]>;
133137

134138
// Callee-saved registers are handled by the register window mechanism.

llvm/lib/Target/Sparc/SparcISelLowering.cpp

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,9 @@ static bool CC_Sparc_Assign_Ret_Split_64(unsigned &ValNo, MVT &ValVT,
101101
}
102102

103103
// Allocate a full-sized argument for the 64-bit ABI.
104-
static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT,
105-
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
106-
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
104+
static bool Analyze_CC_Sparc64_Full(bool IsReturn, unsigned &ValNo, MVT &ValVT,
105+
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
106+
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
107107
assert((LocVT == MVT::f32 || LocVT == MVT::f128
108108
|| LocVT.getSizeInBits() == 64) &&
109109
"Can't handle non-64 bits locations");
@@ -133,6 +133,11 @@ static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT,
133133
return true;
134134
}
135135

136+
// Bail out if this is a return CC and we run out of registers to place
137+
// values into.
138+
if (IsReturn)
139+
return false;
140+
136141
// This argument goes on the stack in an 8-byte slot.
137142
// When passing floats, LocVT is smaller than 8 bytes. Adjust the offset to
138143
// the right-aligned float. The first 4 bytes of the stack slot are undefined.
@@ -146,9 +151,9 @@ static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT,
146151
// Allocate a half-sized argument for the 64-bit ABI.
147152
//
148153
// This is used when passing { float, int } structs by value in registers.
149-
static bool CC_Sparc64_Half(unsigned &ValNo, MVT &ValVT,
150-
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
151-
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
154+
static bool Analyze_CC_Sparc64_Half(bool IsReturn, unsigned &ValNo, MVT &ValVT,
155+
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
156+
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
152157
assert(LocVT.getSizeInBits() == 32 && "Can't handle non-32 bits locations");
153158
unsigned Offset = State.AllocateStack(4, Align(4));
154159

@@ -174,10 +179,43 @@ static bool CC_Sparc64_Half(unsigned &ValNo, MVT &ValVT,
174179
return true;
175180
}
176181

182+
// Bail out if this is a return CC and we run out of registers to place
183+
// values into.
184+
if (IsReturn)
185+
return false;
186+
177187
State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
178188
return true;
179189
}
180190

191+
static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
192+
CCValAssign::LocInfo &LocInfo,
193+
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
194+
return Analyze_CC_Sparc64_Full(false, ValNo, ValVT, LocVT, LocInfo, ArgFlags,
195+
State);
196+
}
197+
198+
static bool CC_Sparc64_Half(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
199+
CCValAssign::LocInfo &LocInfo,
200+
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
201+
return Analyze_CC_Sparc64_Half(false, ValNo, ValVT, LocVT, LocInfo, ArgFlags,
202+
State);
203+
}
204+
205+
static bool RetCC_Sparc64_Full(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
206+
CCValAssign::LocInfo &LocInfo,
207+
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
208+
return Analyze_CC_Sparc64_Full(true, ValNo, ValVT, LocVT, LocInfo, ArgFlags,
209+
State);
210+
}
211+
212+
static bool RetCC_Sparc64_Half(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
213+
CCValAssign::LocInfo &LocInfo,
214+
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
215+
return Analyze_CC_Sparc64_Half(true, ValNo, ValVT, LocVT, LocInfo, ArgFlags,
216+
State);
217+
}
218+
181219
#include "SparcGenCallingConv.inc"
182220

183221
// The calling conventions in SparcCallingConv.td are described in terms of the
@@ -191,6 +229,15 @@ static unsigned toCallerWindow(unsigned Reg) {
191229
return Reg;
192230
}
193231

232+
bool SparcTargetLowering::CanLowerReturn(
233+
CallingConv::ID CallConv, MachineFunction &MF, bool isVarArg,
234+
const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
235+
SmallVector<CCValAssign, 16> RVLocs;
236+
CCState CCInfo(CallConv, isVarArg, MF, RVLocs, Context);
237+
return CCInfo.CheckReturn(Outs, Subtarget->is64Bit() ? RetCC_Sparc64
238+
: RetCC_Sparc32);
239+
}
240+
194241
SDValue
195242
SparcTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
196243
bool IsVarArg,
@@ -1031,6 +1078,7 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
10311078

10321079
// Copy all of the result registers out of their specified physreg.
10331080
for (unsigned i = 0; i != RVLocs.size(); ++i) {
1081+
assert(RVLocs[i].isRegLoc() && "Can only return in registers!");
10341082
if (RVLocs[i].getLocVT() == MVT::v2i32) {
10351083
SDValue Vec = DAG.getNode(ISD::UNDEF, dl, MVT::v2i32);
10361084
SDValue Lo = DAG.getCopyFromReg(
@@ -1346,6 +1394,7 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
13461394
// Copy all of the result registers out of their specified physreg.
13471395
for (unsigned i = 0; i != RVLocs.size(); ++i) {
13481396
CCValAssign &VA = RVLocs[i];
1397+
assert(VA.isRegLoc() && "Can only return in registers!");
13491398
unsigned Reg = toCallerWindow(VA.getLocReg());
13501399

13511400
// When returning 'inreg {i32, i32 }', two consecutive i32 arguments can

llvm/lib/Target/Sparc/SparcISelLowering.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ namespace llvm {
144144
SDValue LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
145145
SmallVectorImpl<SDValue> &InVals) const;
146146

147+
bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF,
148+
bool isVarArg,
149+
const SmallVectorImpl<ISD::OutputArg> &Outs,
150+
LLVMContext &Context) const override;
151+
147152
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
148153
const SmallVectorImpl<ISD::OutputArg> &Outs,
149154
const SmallVectorImpl<SDValue> &OutVals,

llvm/test/CodeGen/SPARC/64abi.ll

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -293,33 +293,6 @@ define void @call_inreg_ii(i32* %p, i32 %i1, i32 %i2) {
293293
ret void
294294
}
295295

296-
; Structs up to 32 bytes in size can be returned in registers.
297-
; CHECK-LABEL: ret_i64_pair:
298-
; CHECK: ldx [%i2], %i0
299-
; CHECK: ldx [%i3], %i1
300-
define { i64, i64 } @ret_i64_pair(i32 %a0, i32 %a1, i64* %p, i64* %q) {
301-
%r1 = load i64, i64* %p
302-
%rv1 = insertvalue { i64, i64 } undef, i64 %r1, 0
303-
store i64 0, i64* %p
304-
%r2 = load i64, i64* %q
305-
%rv2 = insertvalue { i64, i64 } %rv1, i64 %r2, 1
306-
ret { i64, i64 } %rv2
307-
}
308-
309-
; CHECK-LABEL: call_ret_i64_pair:
310-
; CHECK: call ret_i64_pair
311-
; CHECK: stx %o0, [%i0]
312-
; CHECK: stx %o1, [%i0]
313-
define void @call_ret_i64_pair(i64* %i0) {
314-
%rv = call { i64, i64 } @ret_i64_pair(i32 undef, i32 undef,
315-
i64* undef, i64* undef)
316-
%e0 = extractvalue { i64, i64 } %rv, 0
317-
store volatile i64 %e0, i64* %i0
318-
%e1 = extractvalue { i64, i64 } %rv, 1
319-
store i64 %e1, i64* %i0
320-
ret void
321-
}
322-
323296
; This is not a C struct, the i32 member uses 8 bytes, but the float only 4.
324297
; CHECK-LABEL: ret_i32_float_pair:
325298
; CHECK: ld [%i2], %i0

0 commit comments

Comments
 (0)