diff --git a/llvm/lib/CodeGen/Analysis.cpp b/llvm/lib/CodeGen/Analysis.cpp --- a/llvm/lib/CodeGen/Analysis.cpp +++ b/llvm/lib/CodeGen/Analysis.cpp @@ -503,6 +503,15 @@ return true; } +// This function checks if the result of the given instruction is used by +// a non-return instruction. +static bool hasNonReturnUses(const Value *V) { + assert(V && "Expected non-null input!"); + if ((V->hasOneUse() && !isa(*V->user_begin())) || + V->hasNUsesOrMore(2)) + return true; + return false; +} /// Test if the given instruction is in a position to be optimized /// with a tail-call. This roughly means that it's in a block with @@ -530,8 +539,10 @@ // If I will have a chain, make sure no other instruction that will have a // chain interposes between I and the return. + // If a speculatable call's result is used by a non-return instruction, + // check if it is in a position to be optimized with a tail-call. if (Call.mayHaveSideEffects() || Call.mayReadFromMemory() || - !isSafeToSpeculativelyExecute(&Call)) + !isSafeToSpeculativelyExecute(&Call) || hasNonReturnUses(&Call)) for (BasicBlock::const_iterator BBI = std::prev(ExitBB->end(), 2);; --BBI) { if (&*BBI == &Call) break; diff --git a/llvm/test/CodeGen/PowerPC/tailcall-speculatable-callee.ll b/llvm/test/CodeGen/PowerPC/tailcall-speculatable-callee.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/tailcall-speculatable-callee.ll @@ -0,0 +1,66 @@ +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: -ppc-asm-full-reg-names -ppc-vsr-nums-as-vr < %s | FileCheck %s + +; The tests check the behavior of the tail call decision when the callee is speculatable. + +; Callee should be tail called in this function since its result is only used by a return instruction +define dso_local double @speculatable_callee_return_use_only (double* nocapture %res, double %a) #0 { +; CHECK-LABEL: speculatable_callee_return_use_only: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: b callee +entry: + %value = tail call double @callee(double %a) #2 + ret double %value +} + +; Callee should not be tail called since its result is used by a non-return instruction +define dso_local void @speculatable_callee_non_return_use_only (double* nocapture %res, double %a) #0 { +; CHECK-LABEL: speculatable_callee_non_return_use_only: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mflr r0 +; CHECK-NEXT: std r30, -16(r1) # 8-byte Folded Spill +; CHECK-NEXT: std r0, 16(r1) +; CHECK-NEXT: stdu r1, -48(r1) +; CHECK-NEXT: mr r30, r3 +; CHECK-NEXT: bl callee +; CHECK-NEXT: stfdx f1, 0, r30 +; CHECK-NEXT: addi r1, r1, 48 +; CHECK-NEXT: ld r0, 16(r1) +; CHECK-NEXT: ld r30, -16(r1) # 8-byte Folded Reload +; CHECK-NEXT: mtlr r0 +; CHECK-NEXT: blr +entry: + %call = tail call double @callee(double %a) #2 + store double %call, double* %res, align 8 + ret void +} + +; Callee should not be tail called since its result is used by multiple instructions. +define dso_local double @speculatable_callee_multi_use (double* nocapture %res, double %a) #0 { + ; CHECK-LABEL: speculatable_callee_multi_use: + ; CHECK: # %bb.0: # %entry + ; CHECK-NEXT: mflr r0 + ; CHECK-NEXT: std r30, -16(r1) # 8-byte Folded Spill + ; CHECK-NEXT: std r0, 16(r1) + ; CHECK-NEXT: stdu r1, -48(r1) + ; CHECK-NEXT: mr r30, r3 + ; CHECK-NEXT: bl callee + ; CHECK-NEXT: stfdx f1, 0, r30 + ; CHECK-NEXT: addi r1, r1, 48 + ; CHECK-NEXT: ld r0, 16(r1) + ; CHECK-NEXT: ld r30, -16(r1) # 8-byte Folded Reload + ; CHECK-NEXT: mtlr r0 + ; CHECK-NEXT: blr + entry: + %call = tail call double @callee(double %a) #2 + store double %call, double* %res, align 8 + ret double %call +} + +define double @callee(double) #1 { + ret double 4.5 +} + +attributes #0 = { nounwind } +attributes #1 = { readnone speculatable } +attributes #2 = { nounwind noinline }