diff --git a/llvm/include/llvm/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h --- a/llvm/include/llvm/Analysis/CGSCCPassManager.h +++ b/llvm/include/llvm/Analysis/CGSCCPassManager.h @@ -487,6 +487,33 @@ std::unique_ptr Pass; }; +class FunctionStatusAnalysis + : public AnalysisInfoMixin { +public: + static AnalysisKey Key; + class Result { + SmallPtrSet WasOptimized; + + public: + Result(const Result &) = delete; + Result(Result &&) = default; + Result() = default; + + void registerPassCompleted(const CGSCCToFunctionPassAdaptor &P) { + WasOptimized.insert(&P); + } + bool passHadRun(const CGSCCToFunctionPassAdaptor &P) const { + return WasOptimized.contains(&P); + } + bool invalidate(Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &Inv) { + return false; + } + }; + + Result run(Function &F, FunctionAnalysisManager &FAM) { return Result(); } +}; + /// A function to deduce a function pass type and wrap it in the /// templated adaptor. template diff --git a/llvm/lib/Analysis/CGSCCPassManager.cpp b/llvm/lib/Analysis/CGSCCPassManager.cpp --- a/llvm/lib/Analysis/CGSCCPassManager.cpp +++ b/llvm/lib/Analysis/CGSCCPassManager.cpp @@ -43,6 +43,9 @@ "abort-on-max-devirt-iterations-reached", cl::desc("Abort when the max iterations for devirtualization CGSCC repeat " "pass is reached")); +static cl::opt NoReruns("no-reruns", cl::init(true), cl::desc("")); + +AnalysisKey FunctionStatusAnalysis::Key; // Explicit instantiations for the core proxy templates. template class AllAnalysesOn; @@ -547,6 +550,9 @@ continue; Function &F = N->getFunction(); + auto *FS = FAM.getCachedResult(F); + if (NoReruns && FS && FS->passHadRun(*this)) + continue; PassInstrumentation PI = FAM.getResult(F); if (!PI.runBeforePass(*Pass, F)) @@ -564,6 +570,8 @@ // function's analyses (that's the contract of a function pass), so // directly handle the function analysis manager's invalidation here. FAM.invalidate(F, PassPA); + if (!PassPA.areAllPreserved()) + FAM.invalidate(F); // Then intersect the preserved set so that invalidation of module // analyses will eventually occur when the module pass completes. @@ -579,6 +587,7 @@ assert(CG.lookupSCC(*N) == CurrentC && "Current SCC not updated to the SCC containing the current node!"); } + FAM.getResult(F).registerPassCompleted(*this); } // By definition we preserve the proxy. And we preserve all analyses on @@ -720,7 +729,8 @@ auto PAC = PA.getChecker(); if (!PAC.preserved() && !PAC.preservedSet>()) { for (LazyCallGraph::Node &N : C) - FAM->clear(N.getFunction(), N.getFunction().getName()); + if (!FAM->getCachedResult(N.getFunction())) + FAM->clear(N.getFunction(), N.getFunction().getName()); return false; } @@ -893,6 +903,9 @@ LazyCallGraph &G, LazyCallGraph::SCC &InitialC, LazyCallGraph::Node &N, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, FunctionAnalysisManager &FAM, bool FunctionPass) { + + FAM.invalidate(N.getFunction()); + using Node = LazyCallGraph::Node; using Edge = LazyCallGraph::Edge; using SCC = LazyCallGraph::SCC; diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -173,6 +173,7 @@ FUNCTION_ANALYSIS("verify", VerifierAnalysis()) FUNCTION_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis(PIC)) FUNCTION_ANALYSIS("divergence", DivergenceAnalysis()) +FUNCTION_ANALYSIS("func-status", FunctionStatusAnalysis()) #ifndef FUNCTION_ALIAS_ANALYSIS #define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) \