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

to pop.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@160725 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Rafael Espindola 2012-07-25 13:41:10 +00:00
parent 742f2c9a43
commit 1cee71099c
3 changed files with 71 additions and 25 deletions

View File

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

View File

@ -1717,21 +1717,37 @@ X86TargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag,
/// CallIsStructReturn - Determines whether a call uses struct return /// CallIsStructReturn - Determines whether a call uses struct return
/// semantics. /// 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()) 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 /// ArgsAreStructReturn - Determines whether a function uses struct
/// return semantics. /// return semantics.
static bool static StructReturnType
ArgsAreStructReturn(const SmallVectorImpl<ISD::InputArg> &Ins) { argsAreStructReturn(const SmallVectorImpl<ISD::InputArg> &Ins) {
if (Ins.empty()) 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 /// CreateCopyOfByValArgument - Make a copy of an aggregate at address specified
@ -2072,7 +2088,7 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain,
FuncInfo->setBytesToPopOnReturn(0); // Callee pops nothing. FuncInfo->setBytesToPopOnReturn(0); // Callee pops nothing.
// If this is an sret function, the return should pop the hidden pointer. // If this is an sret function, the return should pop the hidden pointer.
if (!Is64Bit && !IsTailCallConvention(CallConv) && !IsWindows && if (!Is64Bit && !IsTailCallConvention(CallConv) && !IsWindows &&
ArgsAreStructReturn(Ins)) argsAreStructReturn(Ins) == StackStructReturn)
FuncInfo->setBytesToPopOnReturn(4); FuncInfo->setBytesToPopOnReturn(4);
} }
@ -2162,7 +2178,7 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
bool Is64Bit = Subtarget->is64Bit(); bool Is64Bit = Subtarget->is64Bit();
bool IsWin64 = Subtarget->isTargetWin64(); bool IsWin64 = Subtarget->isTargetWin64();
bool IsWindows = Subtarget->isTargetWindows(); bool IsWindows = Subtarget->isTargetWindows();
bool IsStructRet = CallIsStructReturn(Outs); StructReturnType SR = callIsStructReturn(Outs);
bool IsSibcall = false; bool IsSibcall = false;
if (MF.getTarget().Options.DisableTailCalls) if (MF.getTarget().Options.DisableTailCalls)
@ -2171,8 +2187,9 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
if (isTailCall) { if (isTailCall) {
// Check if it's really possible to do a tail call. // Check if it's really possible to do a tail call.
isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv,
isVarArg, IsStructRet, MF.getFunction()->hasStructRetAttr(), isVarArg, SR != NotStructReturn,
Outs, OutVals, Ins, DAG); MF.getFunction()->hasStructRetAttr(),
Outs, OutVals, Ins, DAG);
// Sibcalls are automatically detected tailcalls which do not require // Sibcalls are automatically detected tailcalls which do not require
// ABI changes. // ABI changes.
@ -2548,7 +2565,7 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
getTargetMachine().Options.GuaranteedTailCallOpt)) getTargetMachine().Options.GuaranteedTailCallOpt))
NumBytesForCalleeToPush = NumBytes; // Callee pops everything NumBytesForCalleeToPush = NumBytes; // Callee pops everything
else if (!Is64Bit && !IsTailCallConvention(CallConv) && !IsWindows && else if (!Is64Bit && !IsTailCallConvention(CallConv) && !IsWindows &&
IsStructRet) SR == StackStructReturn)
// If this is a call to a struct-return function, the callee // If this is a call to a struct-return function, the callee
// pops the hidden struct pointer, so we have to push it back. // pops the hidden struct pointer, so we have to push it back.
// This is common for Darwin/X86, Linux & Mingw32 targets. // 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: entry:
%tmp = alloca %struct.s, align 4 %tmp = alloca %struct.s1, align 4
call void @f(%struct.s* inreg sret %tmp, i32 inreg 41, i32 inreg 42, i32 43) call void @f(%struct.s1* inreg sret %tmp, i32 inreg 41, i32 inreg 42, i32 43)
ret void ret void
; CHECK: g: ; DAG: g1:
; CHECK: subl {{.*}}, %esp ; DAG: subl $[[AMT:.*]], %esp
; CHECK-NEXT: $43, (%esp) ; DAG-NEXT: $43, (%esp)
; CHECK-NEXT: leal 16(%esp), %eax ; DAG-NEXT: leal 16(%esp), %eax
; CHECK-NEXT: movl $41, %edx ; DAG-NEXT: movl $41, %edx
; CHECK-NEXT: movl $42, %ecx ; DAG-NEXT: movl $42, %ecx
; CHECK-NEXT: calll f ; 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
}