Index: include/llvm/Analysis/CGSCCPassManager.h =================================================================== --- include/llvm/Analysis/CGSCCPassManager.h +++ include/llvm/Analysis/CGSCCPassManager.h @@ -881,6 +881,45 @@ return DevirtSCCRepeatedPass(std::move(Pass), MaxIterations); } +/// A specialized version of RepeatedPass that handles CGSCCAnalysisManager +/// interface. +template +class RepeatedPass + : public PassInfoMixin> { +public: + RepeatedPass(int Count, PassT P) : Count(Count), P(std::move(P)) {} + + PreservedAnalyses run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM, + LazyCallGraph &G, CGSCCUpdateResult &UR) { + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + // Passing all the Args into AM's getResult since here we know that they do + // match. + PassInstrumentation PI = + AM.template getResult(InitialC, G); + PI.startPassManager(*this, InitialC); + auto PA = PreservedAnalyses::all(); + for (int i = 0; i < Count; ++i) { + // Tell PassInstrumentation that we started a new iteration. + PI.startIteration(*this, i); + + // Check the PassInstrumentation's BeforePass callbacks before running the + // pass, skip its execution completely if asked to (callback returns + // false). + if (!PI.runBeforePass(P, InitialC)) + continue; + PA.intersect(P.run(InitialC, AM, G, UR)); + PI.runAfterPass(P, InitialC); + } + PI.finishPassManager(*this, InitialC); + return PA; + } + +private: + int Count; + PassT P; +}; + // Clear out the debug logging macro. #undef DEBUG_TYPE Index: include/llvm/IR/PassManager.h =================================================================== --- include/llvm/IR/PassManager.h +++ include/llvm/IR/PassManager.h @@ -483,11 +483,8 @@ // Request PassInstrumentation from analysis manager, will use it to run // instrumenting callbacks for the passes later. - // Here we use std::tuple wrapper over getResult which helps to extract - // AnalysisManager's arguments out of the whole ExtraArgs set. PassInstrumentation PI = - detail::getAnalysisResult( - AM, IR, std::tuple(ExtraArgs...)); + AM.template getResult(IR, ExtraArgs...); PI.startPassManager(*this, IR); if (DebugLogging) dbgs() << "Starting " << getTypeName() << " pass manager run.\n"; @@ -1403,22 +1400,30 @@ /// /// This can be useful when debugging or testing passes. It also serves as an /// example of how to extend the pass manager in ways beyond composition. -template -class RepeatedPass : public PassInfoMixin> { + +template +class RepeatedPass + : public PassInfoMixin> { public: RepeatedPass(int Count, PassT P) : Count(Count), P(std::move(P)) {} - template - PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM, Ts &&... Args) { + template + PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM, + ExtraArgTs &&... Args) { + // This implementation assumes that arguments of the pass and analysis + // manager do match fully. You will have to partially specialize + // RepeatedPass for your own AnalysisManager if this assumption is broken. + static_assert(std::is_same>::value, + "generic RepeatedPass::run assumes AnalysisManager takes the " + "same Args"); // Request PassInstrumentation from analysis manager, will use it to run // instrumenting callbacks for the passes later. - // Here we use std::tuple wrapper over getResult which helps to extract - // AnalysisManager's arguments out of the whole Args set. + // Passing all the Args into AM's getResult since here we know that they do + // match. PassInstrumentation PI = - detail::getAnalysisResult( - AM, IR, std::tuple(Args...)); - + AM.template getResult(IR, Args...); PI.startPassManager(*this, IR); auto PA = PreservedAnalyses::all(); for (int i = 0; i < Count; ++i) { @@ -1430,7 +1435,7 @@ // false). if (!PI.runBeforePass(P, IR)) continue; - PA.intersect(P.run(IR, AM, std::forward(Args)...)); + PA.intersect(P.run(IR, AM, Args...)); PI.runAfterPass(P, IR); } PI.finishPassManager(*this, IR); @@ -1442,9 +1447,9 @@ PassT P; }; -template -RepeatedPass createRepeatedPass(int Count, PassT P) { - return RepeatedPass(Count, std::move(P)); +template +RepeatedPass createRepeatedPass(int Count, PassT P) { + return RepeatedPass(Count, std::move(P)); } } // end namespace llvm Index: include/llvm/Transforms/Scalar/LoopPassManager.h =================================================================== --- include/llvm/Transforms/Scalar/LoopPassManager.h +++ include/llvm/Transforms/Scalar/LoopPassManager.h @@ -419,6 +419,45 @@ PreservedAnalyses run(Loop &L, LoopAnalysisManager &, LoopStandardAnalysisResults &, LPMUpdater &); }; + +/// A specialized version of RepeatedPass that handles LoopAnalysisManager +/// interface. +template +class RepeatedPass + : public PassInfoMixin> { +public: + RepeatedPass(int Count, PassT P) : Count(Count), P(std::move(P)) {} + + PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR, LPMUpdater &LU) { + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + // Passing all the Args into AM's getResult since here we know that they do + // match. + PassInstrumentation PI = + AM.template getResult(L, AR); + PI.startPassManager(*this, L); + auto PA = PreservedAnalyses::all(); + for (int i = 0; i < Count; ++i) { + // Tell PassInstrumentation that we started a new iteration. + PI.startIteration(*this, i); + + // Check the PassInstrumentation's BeforePass callbacks before running the + // pass, skip its execution completely if asked to (callback returns + // false). + if (!PI.runBeforePass(P, L)) + continue; + PA.intersect(P.run(L, AM, AR, LU)); + PI.runAfterPass(P, L); + } + PI.finishPassManager(*this, L); + return PA; + } + +private: + int Count; + PassT P; +}; } #endif // LLVM_TRANSFORMS_SCALAR_LOOPPASSMANAGER_H Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -1447,7 +1447,8 @@ if (!parseModulePassPipeline(NestedMPM, InnerPipeline, VerifyEachPass, DebugLogging)) return false; - MPM.addPass(createRepeatedPass(*Count, std::move(NestedMPM))); + MPM.addPass(createRepeatedPass( + *Count, std::move(NestedMPM))); return true; } @@ -1549,7 +1550,8 @@ if (!parseCGSCCPassPipeline(NestedCGPM, InnerPipeline, VerifyEachPass, DebugLogging)) return false; - CGPM.addPass(createRepeatedPass(*Count, std::move(NestedCGPM))); + CGPM.addPass(createRepeatedPass( + *Count, std::move(NestedCGPM))); return true; } if (auto MaxRepetitions = parseDevirtPassName(Name)) { @@ -1629,7 +1631,8 @@ if (!parseFunctionPassPipeline(NestedFPM, InnerPipeline, VerifyEachPass, DebugLogging)) return false; - FPM.addPass(createRepeatedPass(*Count, std::move(NestedFPM))); + FPM.addPass(createRepeatedPass( + *Count, std::move(NestedFPM))); return true; } @@ -1688,7 +1691,8 @@ if (!parseLoopPassPipeline(NestedLPM, InnerPipeline, VerifyEachPass, DebugLogging)) return false; - LPM.addPass(createRepeatedPass(*Count, std::move(NestedLPM))); + LPM.addPass(createRepeatedPass( + *Count, std::move(NestedLPM))); return true; } Index: unittests/IR/PassManagerTest.cpp =================================================================== --- unittests/IR/PassManagerTest.cpp +++ unittests/IR/PassManagerTest.cpp @@ -543,6 +543,71 @@ AnalysisKey CustomizedAnalysis::Key; +} // namespace + +namespace llvm { +template <> +PreservedAnalyses +PassManager::run( + Function &IR, CustomizedAnalysisManager &AM, int I, int &O) { + PreservedAnalyses PA = PreservedAnalyses::all(); + + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + PassInstrumentation PI = + AM.template getResult(IR, I); + PI.startPassManager(*this, IR); + if (DebugLogging) + dbgs() << "Starting " << getTypeName() << " pass manager run.\n"; + + for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) { + auto *P = Passes[Idx].get(); + if (DebugLogging) + dbgs() << "Running pass: " << P->name() << " on " << IR.getName() << "\n"; + + // Check the PassInstrumentation's BeforePass callbacks before running the + // pass, skip its execution completely if asked to (callback returns + // false). + if (!PI.runBeforePass(*P, IR)) + continue; + + PreservedAnalyses PassPA = P->run(IR, AM, I, O); + + // Call onto PassInstrumentation's AfterPass callbacks immediately after + // running the pass. + PI.runAfterPass(*P, IR); + + // Update the analysis manager as each pass runs and potentially + // invalidates analyses. + AM.invalidate(IR, PassPA); + + // Finally, intersect the preserved analyses to compute the aggregate + // preserved set for this pass manager. + PA.intersect(std::move(PassPA)); + + // FIXME: Historically, the pass managers all called the LLVM context's + // yield function here. We don't have a generic way to acquire the + // context and it isn't yet clear what the right pattern is for yielding + // in the new pass manager so it is currently omitted. + // IR.getContext().yield(); + } + + // Invalidation was handled after each pass in the above loop for the + // current unit of IR. Therefore, the remaining analysis results in the + // AnalysisManager are preserved. We mark this with a set so that we don't + // need to inspect each one individually. + PA.preserveSet>(); + + PI.finishPassManager(*this, IR); + if (DebugLogging) + dbgs() << "Finished " << getTypeName() << " pass manager run.\n"; + + return PA; +} + +} // namespace llvm + +namespace { struct CustomizedPass : PassInfoMixin { std::function Callback;