Index: llvm/trunk/include/llvm/Transforms/Utils/Local.h =================================================================== --- llvm/trunk/include/llvm/Transforms/Utils/Local.h +++ llvm/trunk/include/llvm/Transforms/Utils/Local.h @@ -378,7 +378,7 @@ /// /// Most passes can and should ignore this information, and it is only used /// during lowering by the GC infrastructure. -bool callsGCLeafFunction(ImmutableCallSite CS); +bool callsGCLeafFunction(ImmutableCallSite CS, const TargetLibraryInfo &TLI); /// Copy a nonnull metadata node to a new load instruction. /// Index: llvm/trunk/lib/Transforms/Scalar/PlaceSafepoints.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/PlaceSafepoints.cpp +++ llvm/trunk/lib/Transforms/Scalar/PlaceSafepoints.cpp @@ -54,6 +54,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/CFG.h" #include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IntrinsicInst.h" @@ -113,6 +114,7 @@ ScalarEvolution *SE = nullptr; DominatorTree *DT = nullptr; LoopInfo *LI = nullptr; + TargetLibraryInfo *TLI = nullptr; PlaceBackedgeSafepointsImpl(bool CallSafepoints = false) : FunctionPass(ID), CallSafepointsEnabled(CallSafepoints) { @@ -131,6 +133,7 @@ SE = &getAnalysis().getSE(); DT = &getAnalysis().getDomTree(); LI = &getAnalysis().getLoopInfo(); + TLI = &getAnalysis().getTLI(); for (Loop *I : *LI) { runOnLoopAndSubLoops(I); } @@ -141,6 +144,7 @@ AU.addRequired(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); // We no longer modify the IR at all in this pass. Thus all // analysis are preserved. AU.setPreservesAll(); @@ -165,6 +169,7 @@ // We modify the graph wholesale (inlining, block insertion, etc). We // preserve nothing at the moment. We could potentially preserve dom tree // if that was worth doing + AU.addRequired(); } }; } @@ -174,10 +179,11 @@ // callers job. static void InsertSafepointPoll(Instruction *InsertBefore, - std::vector &ParsePointsNeeded /*rval*/); + std::vector &ParsePointsNeeded /*rval*/, + const TargetLibraryInfo &TLI); -static bool needsStatepoint(const CallSite &CS) { - if (callsGCLeafFunction(CS)) +static bool needsStatepoint(const CallSite &CS, const TargetLibraryInfo &TLI) { + if (callsGCLeafFunction(CS, TLI)) return false; if (CS.isCall()) { CallInst *call = cast(CS.getInstruction()); @@ -194,7 +200,8 @@ /// answer; i.e. false is always valid. static bool containsUnconditionalCallSafepoint(Loop *L, BasicBlock *Header, BasicBlock *Pred, - DominatorTree &DT) { + DominatorTree &DT, + const TargetLibraryInfo &TLI) { // In general, we're looking for any cut of the graph which ensures // there's a call safepoint along every edge between Header and Pred. // For the moment, we look only for the 'cuts' that consist of a single call @@ -217,7 +224,7 @@ // unconditional poll. In practice, this is only a theoretical concern // since we don't have any methods with conditional-only safepoint // polls. - if (needsStatepoint(CS)) + if (needsStatepoint(CS, TLI)) return true; } @@ -321,7 +328,7 @@ continue; } if (CallSafepointsEnabled && - containsUnconditionalCallSafepoint(L, Header, Pred, *DT)) { + containsUnconditionalCallSafepoint(L, Header, Pred, *DT, *TLI)) { // Note: This is only semantically legal since we won't do any further // IPO or inlining before the actual call insertion.. If we hadn't, we // might latter loose this call safepoint. @@ -472,6 +479,9 @@ if (!shouldRewriteFunction(F)) return false; + const TargetLibraryInfo &TLI = + getAnalysis().getTLI(); + bool Modified = false; // In various bits below, we rely on the fact that uses are reachable from @@ -578,7 +588,7 @@ // safepoint polls themselves. for (Instruction *PollLocation : PollsNeeded) { std::vector RuntimeCalls; - InsertSafepointPoll(PollLocation, RuntimeCalls); + InsertSafepointPoll(PollLocation, RuntimeCalls, TLI); ParsePointNeeded.insert(ParsePointNeeded.end(), RuntimeCalls.begin(), RuntimeCalls.end()); } @@ -610,7 +620,8 @@ static void InsertSafepointPoll(Instruction *InsertBefore, - std::vector &ParsePointsNeeded /*rval*/) { + std::vector &ParsePointsNeeded /*rval*/, + const TargetLibraryInfo &TLI) { BasicBlock *OrigBB = InsertBefore->getParent(); Module *M = InsertBefore->getModule(); assert(M && "must be part of a module"); @@ -669,7 +680,7 @@ assert(ParsePointsNeeded.empty()); for (auto *CI : Calls) { // No safepoint needed or wanted - if (!needsStatepoint(CI)) + if (!needsStatepoint(CI, TLI)) continue; // These are likely runtime calls. Should we assert that via calling Index: llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" #include "llvm/Analysis/CFG.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" @@ -103,6 +104,7 @@ // else. We could in theory preserve a lot more analyses here. AU.addRequired(); AU.addRequired(); + AU.addRequired(); } /// The IR fed into RewriteStatepointsForGC may have had attributes and @@ -2419,10 +2421,12 @@ DominatorTree &DT = getAnalysis(F).getDomTree(); TargetTransformInfo &TTI = getAnalysis().getTTI(F); + const TargetLibraryInfo &TLI = + getAnalysis().getTLI(); - auto NeedsRewrite = [](Instruction &I) { + auto NeedsRewrite = [&TLI](Instruction &I) { if (ImmutableCallSite CS = ImmutableCallSite(&I)) - return !callsGCLeafFunction(CS) && !isStatepoint(CS); + return !callsGCLeafFunction(CS, TLI) && !isStatepoint(CS); return false; }; Index: llvm/trunk/lib/Transforms/Utils/Local.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/Local.cpp +++ llvm/trunk/lib/Transforms/Utils/Local.cpp @@ -1832,7 +1832,8 @@ return ::replaceDominatedUsesWith(From, To, BB, ProperlyDominates); } -bool llvm::callsGCLeafFunction(ImmutableCallSite CS) { +bool llvm::callsGCLeafFunction(ImmutableCallSite CS, + const TargetLibraryInfo &TLI) { // Check if the function is specifically marked as a gc leaf function. if (CS.hasFnAttr("gc-leaf-function")) return true; @@ -1846,6 +1847,14 @@ IID != Intrinsic::experimental_deoptimize; } + // Lib calls can be materialized by some passes, and won't be + // marked as 'gc-leaf-function.' All available Libcalls are + // GC-leaf. + LibFunc LF; + if (TLI.getLibFunc(CS, LF)) { + return TLI.has(LF); + } + return false; } Index: llvm/trunk/test/Transforms/PlaceSafepoints/libcall.ll =================================================================== --- llvm/trunk/test/Transforms/PlaceSafepoints/libcall.ll +++ llvm/trunk/test/Transforms/PlaceSafepoints/libcall.ll @@ -0,0 +1,37 @@ +; RUN: opt -S -place-safepoints < %s | FileCheck %s + +; Libcalls will not contain a safepoint poll, so check that we insert +; a safepoint in a loop containing a libcall. +declare double @ldexp(double %x, i32 %n) nounwind readnone +define double @test_libcall(double %x) gc "statepoint-example" { +; CHECK-LABEL: test_libcall + +entry: +; CHECK: entry +; CHECK-NEXT: call void @do_safepoint +; CHECK-NEXT: br label %loop + br label %loop + +loop: +; CHECK: loop +; CHECK-NEXT: %x_loop = phi double [ %x, %entry ], [ %x_exp, %loop ] +; CHECK-NEXT: %x_exp = call double @ldexp(double %x_loop, i32 5) +; CHECK-NEXT: %done = fcmp ogt double %x_exp, 1.5 +; CHECK-NEXT: call void @do_safepoint + %x_loop = phi double [ %x, %entry ], [ %x_exp, %loop ] + %x_exp = call double @ldexp(double %x_loop, i32 5) nounwind readnone + %done = fcmp ogt double %x_exp, 1.5 + br i1 %done, label %end, label %loop +end: + %x_end = phi double [%x_exp, %loop] + ret double %x_end +} + +; This function is inlined when inserting a poll. +declare void @do_safepoint() +define void @gc.safepoint_poll() { +; CHECK-LABEL: gc.safepoint_poll +entry: + call void @do_safepoint() + ret void +} Index: llvm/trunk/test/Transforms/RewriteStatepointsForGC/libcall.ll =================================================================== --- llvm/trunk/test/Transforms/RewriteStatepointsForGC/libcall.ll +++ llvm/trunk/test/Transforms/RewriteStatepointsForGC/libcall.ll @@ -0,0 +1,14 @@ +; A call to a libcall function is not a statepoint. +; This test verifies that calls to libcalls functions do not get converted to +; statepoint calls. +; RUN: opt -S -rewrite-statepoints-for-gc < %s | FileCheck %s + +declare double @ldexp(double %x, i32 %n) nounwind readnone + +define double @test_libcall(double %x) gc "statepoint-example" { +; CHECK-LABEL: test_libcall +; CHECK-NEXT: %res = call double @ldexp(double %x, i32 5) +; CHECK-NEXT: ret double %res + %res = call double @ldexp(double %x, i32 5) nounwind readnone + ret double %res +}