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 @@ -899,9 +899,11 @@ /// 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. + /// If true is returned, \p AllCallSitesKnown is set if all possible call + /// sites of the function have been visited. bool checkForAllCallSites(const function_ref &Pred, const AbstractAttribute &QueryingAA, - bool RequireAllCallSites); + bool RequireAllCallSites, bool &AllCallSitesKnown); /// Check \p Pred on all values potentially returned by \p F. /// @@ -959,9 +961,12 @@ /// 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. + /// If true is returned, \p AllCallSitesKnown is set if all possible call + /// sites of the function have been visited. bool checkForAllCallSites(const function_ref &Pred, const Function &Fn, bool RequireAllCallSites, - const AbstractAttribute *QueryingAA); + const AbstractAttribute *QueryingAA, + bool &AllCallSitesKnown); /// The private version of getAAFor that allows to omit a querying abstract /// attribute. See also the public getAAFor method. @@ -1862,6 +1867,9 @@ /// Returns true if the underlying value is assumed dead. virtual bool isAssumedDead() const = 0; + /// Returns true if the underlying value is known dead. + virtual bool isKnownDead() const = 0; + /// Returns true if \p BB is assumed dead. virtual bool isAssumedDead(const BasicBlock *BB) const = 0; 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 @@ -682,7 +682,9 @@ return T->isValidState(); }; - if (!A.checkForAllCallSites(CallSiteCheck, QueryingAA, true)) + bool AllCallSitesKnown; + if (!A.checkForAllCallSites(CallSiteCheck, QueryingAA, true, + AllCallSitesKnown)) S.indicatePessimisticFixpoint(); else if (T.hasValue()) S ^= *T; @@ -2501,6 +2503,9 @@ /// See AAIsDead::isAssumedDead(). bool isAssumedDead() const override { return getAssumed(); } + /// See AAIsDead::isKnownDead(). + bool isKnownDead() const override { return getKnown(); } + /// See AAIsDead::isAssumedDead(BasicBlock *). bool isAssumedDead(const BasicBlock *BB) const override { return false; } @@ -2643,18 +2648,25 @@ /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { + bool AllKnownDead = true; auto PredForCallSite = [&](AbstractCallSite ACS) { if (ACS.isCallbackCall()) return false; const IRPosition &CSRetPos = IRPosition::callsite_returned(ACS.getCallSite()); const auto &RetIsDeadAA = A.getAAFor(*this, CSRetPos); + AllKnownDead &= RetIsDeadAA.isKnownDead(); return RetIsDeadAA.isAssumedDead(); }; - if (!A.checkForAllCallSites(PredForCallSite, *this, true)) + bool AllCallSitesKnown; + if (!A.checkForAllCallSites(PredForCallSite, *this, true, + AllCallSitesKnown)) return indicatePessimisticFixpoint(); + if (AllCallSitesKnown && AllKnownDead) + indicateOptimisticFixpoint(); + return ChangeStatus::UNCHANGED; } @@ -2838,6 +2850,9 @@ /// Returns true if the function is assumed dead. bool isAssumedDead() const override { return false; } + /// See AAIsDead::isKnownDead(). + bool isKnownDead() const override { return false; } + /// See AAIsDead::isAssumedDead(BasicBlock *). bool isAssumedDead(const BasicBlock *BB) const override { assert(BB->getParent() == getAssociatedFunction() && @@ -4214,7 +4229,9 @@ return checkAndUpdate(A, *this, *ArgOp, SimplifiedAssociatedValue); }; - if (!A.checkForAllCallSites(PredForCallSite, *this, true)) + bool AllCallSitesKnown; + if (!A.checkForAllCallSites(PredForCallSite, *this, true, + AllCallSitesKnown)) return indicatePessimisticFixpoint(); // If a candicate was found in this update, return CHANGED. @@ -5140,7 +5157,8 @@ bool Attributor::checkForAllCallSites( const function_ref &Pred, - const AbstractAttribute &QueryingAA, bool RequireAllCallSites) { + const AbstractAttribute &QueryingAA, bool RequireAllCallSites, + bool &AllCallSitesKnown) { // We can try to determine information from // the call sites. However, this is only possible all call sites are known, // hence the function has internal linkage. @@ -5149,24 +5167,30 @@ if (!AssociatedFunction) { LLVM_DEBUG(dbgs() << "[Attributor] No function associated with " << IRP << "\n"); + AllCallSitesKnown = false; return false; } return checkForAllCallSites(Pred, *AssociatedFunction, RequireAllCallSites, - &QueryingAA); + &QueryingAA, AllCallSitesKnown); } bool Attributor::checkForAllCallSites( const function_ref &Pred, const Function &Fn, - bool RequireAllCallSites, const AbstractAttribute *QueryingAA) { + bool RequireAllCallSites, const AbstractAttribute *QueryingAA, + bool &AllCallSitesKnown) { if (RequireAllCallSites && !Fn.hasLocalLinkage()) { LLVM_DEBUG( dbgs() << "[Attributor] Function " << Fn.getName() << " has no internal linkage, hence not all call sites are known\n"); + AllCallSitesKnown = false; return false; } + // If we do not require all call sites we might not see all. + AllCallSitesKnown = RequireAllCallSites; + for (const Use &U : Fn.uses()) { AbstractCallSite ACS(&U); if (!ACS) { @@ -5192,6 +5216,7 @@ // dependence. if (QueryingAA) recordDependence(*LivenessAA, *QueryingAA, DepClassTy::OPTIONAL); + AllCallSitesKnown = false; continue; } @@ -5615,8 +5640,9 @@ if (!F) continue; + bool AllCallSitesKnown; if (!checkForAllCallSites([](AbstractCallSite ACS) { return false; }, - *F, true, nullptr)) + *F, true, nullptr, AllCallSitesKnown)) continue; STATS_TRACK(AAIsDead, Function);