diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -321,7 +321,8 @@ /// This method will evaluate \p Pred on call sites and return /// true if \p Pred holds in every call sites. However, this is only possible /// all call sites are known, hence the function has internal linkage. - bool checkForAllCallSites(Function &F, std::function &Pred, + bool checkForAllCallSites(Function &F, + const function_ref &Pred, const AbstractAttribute &QueryingAA, bool RequireAllCallSites); diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -1043,7 +1043,7 @@ unsigned ArgNo = getArgNo(); // Callback function - std::function CallSiteCheck = [&](CallSite CS) { + auto CallSiteCheck = [&](CallSite CS) { assert(CS && "Sanity check: Call site was not initialized properly!"); auto *NonNullAA = @@ -1245,8 +1245,16 @@ void initialize(Attributor &A) override { const Function &F = getAnchorScope(); + if (F.hasInternalLinkage()) + return; + + exploreFromEntry(A, F); + } + + void exploreFromEntry(Attributor &A, const Function &F) { ToBeExploredPaths.insert(&(F.getEntryBlock().front())); AssumedLiveBlocks.insert(&(F.getEntryBlock())); + for (size_t i = 0; i < ToBeExploredPaths.size(); ++i) if (const Instruction *NextNoReturnI = findNextNoReturn(A, ToBeExploredPaths[i])) @@ -1276,7 +1284,12 @@ "Attempted to manifest an invalid state!"); ChangeStatus HasChanged = ChangeStatus::UNCHANGED; - const Function &F = getAnchorScope(); + Function &F = getAnchorScope(); + + if (AssumedLiveBlocks.size() == 0) { + F.replaceAllUsesWith(UndefValue::get(F.getType())); + return ChangeStatus::CHANGED; + } // Flag to determine if we can change an invoke to a call assuming the // callee is nounwind. This is not possible if the personality of the @@ -1467,10 +1480,25 @@ } ChangeStatus AAIsDeadImpl::updateImpl(Attributor &A) { + Function &F = getAnchorScope(); + ChangeStatus Status = ChangeStatus::UNCHANGED; + + if (F.hasInternalLinkage()) { + auto CallSiteCheck = [&](CallSite) { return false; }; + + // All callsites of F are dead. + if (A.checkForAllCallSites(F, CallSiteCheck, *this, true)) + return ChangeStatus::UNCHANGED; + + // There exists at least one live call site, so we explore the function. + Status = ChangeStatus::CHANGED; + + exploreFromEntry(A, F); + } + // Temporary collection to iterate over existing noreturn instructions. This // will alow easier modification of NoReturnCalls collection SmallVector NoReturnChanged; - ChangeStatus Status = ChangeStatus::UNCHANGED; for (const Instruction *I : NoReturnCalls) NoReturnChanged.push_back(I); @@ -1774,7 +1802,7 @@ bool IsGlobal = isAssumedGlobal(); // Callback function - std::function CallSiteCheck = [&](CallSite CS) -> bool { + auto CallSiteCheck = [&](CallSite CS) { assert(CS && "Sanity check: Call site was not initialized properly!"); // Check that DereferenceableAA is AADereferenceableCallSiteArgument. @@ -1950,7 +1978,7 @@ auto BeforeState = getAssumed(); // Callback function - std::function CallSiteCheck = [&](CallSite CS) { + auto CallSiteCheck = [&](CallSite CS) { assert(CS && "Sanity check: Call site was not initialized properly!"); auto *AlignAA = A.getAAFor(*this, *CS.getInstruction(), ArgNo); @@ -2056,7 +2084,7 @@ /// ---------------------------------------------------------------------------- bool Attributor::checkForAllCallSites(Function &F, - std::function &Pred, + const function_ref &Pred, const AbstractAttribute &QueryingAA, bool RequireAllCallSites) { // We can try to determine information from diff --git a/llvm/test/Transforms/FunctionAttrs/align.ll b/llvm/test/Transforms/FunctionAttrs/align.ll --- a/llvm/test/Transforms/FunctionAttrs/align.ll +++ b/llvm/test/Transforms/FunctionAttrs/align.ll @@ -138,7 +138,8 @@ ; TEST 7 ; Better than IR information ; ATTRIBUTOR: define align 32 i32* @test7(i32* returned align 32 %p) -define align 4 i32* @test7(i32* align 32 %p) #0 { +define align 4 i32* @test7(i32* align 32 %p, i8* readnone %c) #0 { + tail call i8* @f1(i8* nonnull %c) ret i32* %p } diff --git a/llvm/test/Transforms/FunctionAttrs/liveness.ll b/llvm/test/Transforms/FunctionAttrs/liveness.ll --- a/llvm/test/Transforms/FunctionAttrs/liveness.ll +++ b/llvm/test/Transforms/FunctionAttrs/liveness.ll @@ -12,6 +12,28 @@ declare i32 @bar() nosync readnone +; This internal function has no live call sites, so all its BBs are considered dead, +; and nothing should be deduced for it. + +; CHECK: Function Attrs: nofree noreturn nosync nounwind +; CHECK-NEXT: define internal i32 @dead_internal_func(i32 %0) +define internal i32 @dead_internal_func(i32 %0) { + %2 = icmp slt i32 %0, 1 + br i1 %2, label %3, label %5 + +;