summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiroshi Inoue <inouehrs@jp.ibm.com>2017-12-30 08:09:04 +0000
committerHiroshi Inoue <inouehrs@jp.ibm.com>2017-12-30 08:09:04 +0000
commit727bd578df48604636398fa39631da5ae11505dc (patch)
treebccfb7457562b6a7e37a6ed8b8155eab5f3e809c
parentdaeece147b55978acc04d89c45c697b0d18a66ff (diff)
[PowerPC] fix a bug in TCO eligibility check
If the callee and caller use different calling convensions, we cannot apply TCO if the callee requires arguments on stack; e.g. C calling convention and Fast CC use the same registers for parameter passing, but the stack offset is not necessarily same. This patch also recommit r319218 "[PowerPC] Allow tail calls of fastcc functions from C CallingConv functions." by @sfertile since the problem reported in r320106 should be fixed. Differential Revision: https://reviews.llvm.org/D40893 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@321579 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/PowerPC/PPCISelLowering.cpp35
-rw-r--r--test/CodeGen/PowerPC/duplicate-returns-for-tailcall.ll6
-rw-r--r--test/CodeGen/PowerPC/ppc64-sibcall.ll9
3 files changed, 41 insertions, 9 deletions
diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp
index cea59de3e8a..f9de65fcb1d 100644
--- a/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -4397,13 +4397,18 @@ hasSameArgumentList(const Function *CallerFn, ImmutableCallSite CS) {
static bool
areCallingConvEligibleForTCO_64SVR4(CallingConv::ID CallerCC,
CallingConv::ID CalleeCC) {
- // Tail or Sibling call optimization (TCO/SCO) needs callee and caller to
- // have the same calling convention.
- if (CallerCC != CalleeCC)
+ // Tail calls are possible with fastcc and ccc.
+ auto isTailCallableCC = [] (CallingConv::ID CC){
+ return CC == CallingConv::C || CC == CallingConv::Fast;
+ };
+ if (!isTailCallableCC(CallerCC) || !isTailCallableCC(CalleeCC))
return false;
- // Tail or Sibling calls can be done with fastcc/ccc.
- return (CallerCC == CallingConv::Fast || CallerCC == CallingConv::C);
+ // We can safely tail call both fastcc and ccc callees from a c calling
+ // convention caller. If the caller is fastcc, we may have less stack space
+ // than a non-fastcc caller with the same signature so disable tail-calls in
+ // that case.
+ return CallerCC == CallingConv::C || CallerCC == CalleeCC;
}
bool
@@ -4434,10 +4439,28 @@ PPCTargetLowering::IsEligibleForTailCallOptimization_64SVR4(
// Callee contains any byval parameter is not supported, too.
// Note: This is a quick work around, because in some cases, e.g.
// caller's stack size > callee's stack size, we are still able to apply
- // sibling call optimization. See: https://reviews.llvm.org/D23441#513574
+ // sibling call optimization. For example, gcc is able to do SCO for caller1
+ // in the following example, but not for caller2.
+ // struct test {
+ // long int a;
+ // char ary[56];
+ // } gTest;
+ // __attribute__((noinline)) int callee(struct test v, struct test *b) {
+ // b->a = v.a;
+ // return 0;
+ // }
+ // void caller1(struct test a, struct test c, struct test *b) {
+ // callee(gTest, b); }
+ // void caller2(struct test *b) { callee(gTest, b); }
if (any_of(Outs, [](const ISD::OutputArg& OA) { return OA.Flags.isByVal(); }))
return false;
+ // If callee and caller use different calling conventions, we cannot pass
+ // parameters on stack since offsets for the parameter area may be different.
+ if (Caller.getCallingConv() != CalleeCC &&
+ needStackSlotPassParameters(Subtarget, Outs))
+ return false;
+
// No TCO/SCO on indirect call because Caller have to restore its TOC
if (!isFunctionGlobalAddress(Callee) &&
!isa<ExternalSymbolSDNode>(Callee))
diff --git a/test/CodeGen/PowerPC/duplicate-returns-for-tailcall.ll b/test/CodeGen/PowerPC/duplicate-returns-for-tailcall.ll
index 520efd8106f..9c0e77dafde 100644
--- a/test/CodeGen/PowerPC/duplicate-returns-for-tailcall.ll
+++ b/test/CodeGen/PowerPC/duplicate-returns-for-tailcall.ll
@@ -42,10 +42,10 @@ if.end4: ; preds = %if.end
if.then6: ; preds = %if.end4
%call7 = tail call fastcc signext i32 @call3(i32 signext %a, i32 signext %b, i32 signext %c)
br label %return
-; No duplication here because the calling convention mismatch means we won't tail-call
+; tail calling a fastcc function from a ccc function is supported.
; CHECK_LABEL: if.then13:
-; CHECK: tail call fastcc signext i32 @call3
-; CHECK-NEXT: br
+; CHECK: %[[T2:[a-zA-Z0-9]+]] = tail call fastcc signext i32 @call3
+; CHECK-NEXT: ret i32 %[[T2]]
return: ; preds = %if.end4, %if.then6, %if.then2, %if.then
%retval.0 = phi i32 [ %call, %if.then ], [ %call3, %if.then2 ], [ %call7, %if.then6 ], [ %c, %if.end4 ]
diff --git a/test/CodeGen/PowerPC/ppc64-sibcall.ll b/test/CodeGen/PowerPC/ppc64-sibcall.ll
index 3c08ecb5119..fc0e71f878c 100644
--- a/test/CodeGen/PowerPC/ppc64-sibcall.ll
+++ b/test/CodeGen/PowerPC/ppc64-sibcall.ll
@@ -41,6 +41,15 @@ define void @caller_64_64_copy([8 x i64] %a, [8 x i64] %b) #1 {
; CHECK-SCO: b callee_64_64_copy
}
+define internal fastcc void @callee_64_64_copy_fastcc([8 x i64] %a, [8 x i64] %b) #0 { ret void }
+define void @caller_64_64_copy_ccc([8 x i64] %a, [8 x i64] %b) #1 {
+ tail call fastcc void @callee_64_64_copy_fastcc([8 x i64] %a, [8 x i64] %b)
+ ret void
+; If caller and callee use different calling convensions, we cannot apply TCO.
+; CHECK-SCO-LABEL: caller_64_64_copy_ccc:
+; CHECK-SCO: bl callee_64_64_copy_fastcc
+}
+
define void @caller_64_64_reorder_copy([8 x i64] %a, [8 x i64] %b) #1 {
tail call void @callee_64_64_copy([8 x i64] %b, [8 x i64] %a)
ret void