When a return struct pointer is passed in registers, the called has nothing

to pop.

llvm-svn: 160725
This commit is contained in:
Rafael Espindola 2012-07-25 13:41:10 +00:00
parent 2caee7f4d2
commit 11c38b9657
3 changed files with 71 additions and 25 deletions

View File

@ -1527,6 +1527,8 @@ static unsigned computeBytesPopedByCalle(const X86Subtarget &Subtarget,
return 0;
if (!CS.paramHasAttr(1, Attribute::StructRet))
return 0;
if (CS.paramHasAttr(1, Attribute::InReg))
return 0;
return 4;
}

View File

@ -1717,21 +1717,37 @@ X86TargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag,
/// CallIsStructReturn - Determines whether a call uses struct return
/// semantics.
static bool CallIsStructReturn(const SmallVectorImpl<ISD::OutputArg> &Outs) {
enum StructReturnType {
NotStructReturn,
RegStructReturn,
StackStructReturn
};
static StructReturnType
callIsStructReturn(const SmallVectorImpl<ISD::OutputArg> &Outs) {
if (Outs.empty())
return false;
return NotStructReturn;
return Outs[0].Flags.isSRet();
const ISD::ArgFlagsTy &Flags = Outs[0].Flags;
if (!Flags.isSRet())
return NotStructReturn;
if (Flags.isInReg())
return RegStructReturn;
return StackStructReturn;
}
/// ArgsAreStructReturn - Determines whether a function uses struct
/// return semantics.
static bool
ArgsAreStructReturn(const SmallVectorImpl<ISD::InputArg> &Ins) {
static StructReturnType
argsAreStructReturn(const SmallVectorImpl<ISD::InputArg> &Ins) {
if (Ins.empty())
return false;
return NotStructReturn;
return Ins[0].Flags.isSRet();
const ISD::ArgFlagsTy &Flags = Ins[0].Flags;
if (!Flags.isSRet())
return NotStructReturn;
if (Flags.isInReg())
return RegStructReturn;
return StackStructReturn;
}
/// CreateCopyOfByValArgument - Make a copy of an aggregate at address specified
@ -2072,7 +2088,7 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain,
FuncInfo->setBytesToPopOnReturn(0); // Callee pops nothing.
// If this is an sret function, the return should pop the hidden pointer.
if (!Is64Bit && !IsTailCallConvention(CallConv) && !IsWindows &&
ArgsAreStructReturn(Ins))
argsAreStructReturn(Ins) == StackStructReturn)
FuncInfo->setBytesToPopOnReturn(4);
}
@ -2162,7 +2178,7 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
bool Is64Bit = Subtarget->is64Bit();
bool IsWin64 = Subtarget->isTargetWin64();
bool IsWindows = Subtarget->isTargetWindows();
bool IsStructRet = CallIsStructReturn(Outs);
StructReturnType SR = callIsStructReturn(Outs);
bool IsSibcall = false;
if (MF.getTarget().Options.DisableTailCalls)
@ -2171,8 +2187,9 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
if (isTailCall) {
// Check if it's really possible to do a tail call.
isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv,
isVarArg, IsStructRet, MF.getFunction()->hasStructRetAttr(),
Outs, OutVals, Ins, DAG);
isVarArg, SR != NotStructReturn,
MF.getFunction()->hasStructRetAttr(),
Outs, OutVals, Ins, DAG);
// Sibcalls are automatically detected tailcalls which do not require
// ABI changes.
@ -2548,7 +2565,7 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
getTargetMachine().Options.GuaranteedTailCallOpt))
NumBytesForCalleeToPush = NumBytes; // Callee pops everything
else if (!Is64Bit && !IsTailCallConvention(CallConv) && !IsWindows &&
IsStructRet)
SR == StackStructReturn)
// If this is a call to a struct-return function, the callee
// pops the hidden struct pointer, so we have to push it back.
// This is common for Darwin/X86, Linux & Mingw32 targets.

View File

@ -1,19 +1,46 @@
; RUN: llc < %s -mtriple=i686-pc-linux -mcpu=corei7 | FileCheck %s
; RUN: llc < %s -mtriple=i686-pc-linux -mcpu=corei7 | FileCheck --check-prefix=DAG %s
; RUN: llc < %s -mtriple=i686-pc-linux -mcpu=corei7 -O0 | FileCheck --check-prefix=FAST %s
%struct.s = type { double, float }
%struct.s1 = type { double, float }
define void @g() nounwind {
define void @g1() nounwind {
entry:
%tmp = alloca %struct.s, align 4
call void @f(%struct.s* inreg sret %tmp, i32 inreg 41, i32 inreg 42, i32 43)
%tmp = alloca %struct.s1, align 4
call void @f(%struct.s1* inreg sret %tmp, i32 inreg 41, i32 inreg 42, i32 43)
ret void
; CHECK: g:
; CHECK: subl {{.*}}, %esp
; CHECK-NEXT: $43, (%esp)
; CHECK-NEXT: leal 16(%esp), %eax
; CHECK-NEXT: movl $41, %edx
; CHECK-NEXT: movl $42, %ecx
; CHECK-NEXT: calll f
; DAG: g1:
; DAG: subl $[[AMT:.*]], %esp
; DAG-NEXT: $43, (%esp)
; DAG-NEXT: leal 16(%esp), %eax
; DAG-NEXT: movl $41, %edx
; DAG-NEXT: movl $42, %ecx
; DAG-NEXT: calll f
; DAG-NEXT: addl $[[AMT]], %esp
; DAG-NEXT: ret
; FAST: g1:
; FAST: subl $[[AMT:.*]], %esp
; FAST-NEXT: leal 8(%esp), %eax
; FAST-NEXT: movl $41, %edx
; FAST-NEXT: movl $42, %ecx
; FAST: $43, (%esp)
; FAST: calll f
; FAST-NEXT: addl $[[AMT]], %esp
; FAST: ret
}
declare void @f(%struct.s* inreg sret, i32 inreg, i32 inreg, i32)
declare void @f(%struct.s1* inreg sret, i32 inreg, i32 inreg, i32)
%struct.s2 = type {}
define void @g2(%struct.s2* inreg sret %agg.result) nounwind {
entry:
ret void
; DAG: g2
; DAG-NOT: ret $4
; DAG: .size g2
; FAST: g2
; FAST-NOT: ret $4
; FAST: .size g2
}