forked from OSchip/llvm-project
When a return struct pointer is passed in registers, the called has nothing
to pop. llvm-svn: 160725
This commit is contained in:
parent
2caee7f4d2
commit
11c38b9657
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue