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 @@ -530,24 +530,23 @@ // If I will have a chain, make sure no other instruction that will have a // chain interposes between I and the return. - if (Call.mayHaveSideEffects() || Call.mayReadFromMemory() || - !isSafeToSpeculativelyExecute(&Call)) - for (BasicBlock::const_iterator BBI = std::prev(ExitBB->end(), 2);; --BBI) { - if (&*BBI == &Call) - break; - // Debug info intrinsics do not get in the way of tail call optimization. - if (isa(BBI)) + // Check for all calls including speculatable functions. + for (BasicBlock::const_iterator BBI = std::prev(ExitBB->end(), 2);; --BBI) { + if (&*BBI == &Call) + break; + // Debug info intrinsics do not get in the way of tail call optimization. + if (isa(BBI)) + continue; + // A lifetime end or assume intrinsic should not stop tail call + // optimization. + if (const IntrinsicInst *II = dyn_cast(BBI)) + if (II->getIntrinsicID() == Intrinsic::lifetime_end || + II->getIntrinsicID() == Intrinsic::assume) continue; - // A lifetime end or assume intrinsic should not stop tail call - // optimization. - if (const IntrinsicInst *II = dyn_cast(BBI)) - if (II->getIntrinsicID() == Intrinsic::lifetime_end || - II->getIntrinsicID() == Intrinsic::assume) - continue; - if (BBI->mayHaveSideEffects() || BBI->mayReadFromMemory() || - !isSafeToSpeculativelyExecute(&*BBI)) - return false; - } + if (BBI->mayHaveSideEffects() || BBI->mayReadFromMemory() || + !isSafeToSpeculativelyExecute(&*BBI)) + return false; + } const Function *F = ExitBB->getParent(); return returnTypeIsEligibleForTailCall( 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,96 @@ +; 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 it is at a tail call position. +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 it is not at a tail call position. +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 it is not at a tail call position. +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 +} + +; Callee should not be tail called since it is not at a tail call position. +; FIXME: A speculatable callee can be tail called if it is moved into a valid tail call position. +define dso_local double @speculatable_callee_intermediate_instructions (double* nocapture %res, double %a) #0 { + ; CHECK-LABEL: speculatable_callee_intermediate_instructions: + ; 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: lis r3, 16404 + ; CHECK-NEXT: ori r3, r3, 52428 + ; CHECK-NEXT: sldi r3, r3, 32 + ; CHECK-NEXT: oris r3, r3, 52428 + ; CHECK-NEXT: ori r3, r3, 52429 + ; CHECK-NEXT: std r3, 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 5.2, 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 }