Index: include/llvm/Analysis/CGSCCPassManager.h =================================================================== --- include/llvm/Analysis/CGSCCPassManager.h +++ include/llvm/Analysis/CGSCCPassManager.h @@ -340,6 +340,11 @@ /// Runs the CGSCC pass across every SCC in the module. PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) { + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + PassInstrumentation PI = AM.getResult(M); + PI.startPassManager(*this, M); + // Setup the CGSCC analysis manager from its proxy. CGSCCAnalysisManager &CGAM = AM.getResult(M).getManager(); @@ -364,10 +369,6 @@ InvalidSCCSet, nullptr, nullptr, InlinedInternalEdges}; - // Request PassInstrumentation from analysis manager, will use it to run - // instrumenting callbacks for the passes later. - PassInstrumentation PI = AM.getResult(M); - PreservedAnalyses PA = PreservedAnalyses::all(); CG.buildRefSCCs(); for (auto RCI = CG.postorder_ref_scc_begin(), @@ -503,6 +504,8 @@ PA.preserve(); PA.preserve(); PA.preserve(); + + PI.finishPassManager(*this, M); return PA; } @@ -604,6 +607,11 @@ /// Runs the function pass across every function in the module. PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR) { + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + PassInstrumentation PI = AM.getResult(C, CG); + PI.startPassManager(*this, C); + // Setup the function analysis manager from its proxy. FunctionAnalysisManager &FAM = AM.getResult(C, CG).getManager(); @@ -630,7 +638,6 @@ Function &F = N->getFunction(); - PassInstrumentation PI = FAM.getResult(F); if (!PI.runBeforePass(Pass, F)) continue; @@ -670,6 +677,7 @@ // We've also ensured that we updated the call graph along the way. PA.preserve(); + PI.finishPassManager(*this, C); return PA; } @@ -711,8 +719,11 @@ PreservedAnalyses run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR) { PreservedAnalyses PA = PreservedAnalyses::all(); + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. PassInstrumentation PI = AM.getResult(InitialC, CG); + PI.startPassManager(*this, InitialC); // The SCC may be refined while we are running passes over it, so set up // a pointer that we can update. @@ -756,6 +767,7 @@ auto CallCounts = ScanSCC(*C, CallHandles); for (int Iteration = 0;; ++Iteration) { + PI.startIteration(*this, Iteration); if (!PI.runBeforePass(Pass, *C)) continue; @@ -848,6 +860,8 @@ PA.intersect(std::move(PassPA)); } + PI.finishPassManager(*this, InitialC); + // Note that we don't add any preserved entries here unlike a more normal // "pass manager" because we only handle invalidation *between* iterations, // not after the last iteration. Index: include/llvm/IR/PassInstrumentation.h =================================================================== --- include/llvm/IR/PassInstrumentation.h +++ include/llvm/IR/PassInstrumentation.h @@ -96,6 +96,8 @@ using AfterPassFunc = void(StringRef, Any); using BeforeAnalysisFunc = void(StringRef, Any); using AfterAnalysisFunc = void(StringRef, Any); + using PassManagerFunc = void(StringRef, Any); + using PMIterationFunc = void(StringRef, int); public: PassInstrumentationCallbacks() {} @@ -122,6 +124,19 @@ AfterAnalysisCallbacks.push_back(C); } + void + registerStartPassManagerCallback(const std::function &C) { + StartPMCallbacks.push_back(C); + } + void + registerFinishPassManagerCallback(const std::function &C) { + FinishPMCallbacks.push_back(C); + } + + void registerStartIterationCallback(const std::function &C) { + StartIterationCallbacks.push_back(C); + } + private: // Instrumentation calls should not be used as a public interface. // Only for consumption by PassInstrumentation. @@ -146,11 +161,22 @@ template void runAfterAnalysis(StringRef AnalysisID, const IRUnitT &) const; + template + void startPassManager(StringRef PM, const IRUnitT &IR) const; + + template + void finishPassManager(StringRef PM, const IRUnitT &IR) const; + + void startIteration(StringRef PM, int Iteration) const; + // instrumentation callbacks SmallVector, 4> BeforePassCallbacks; SmallVector, 4> AfterPassCallbacks; SmallVector, 4> BeforeAnalysisCallbacks; SmallVector, 4> AfterAnalysisCallbacks; + SmallVector, 2> StartPMCallbacks; + SmallVector, 2> FinishPMCallbacks; + SmallVector, 2> StartIterationCallbacks; }; /// This class provides instrumentation entry points for the Pass Manager, @@ -197,6 +223,33 @@ Callbacks->runAfterAnalysis(Analysis.name(), IR); } + /// startPassManager instrumentation point - takes \p PassManager instance + /// that is about to start its operations and constant reference to IR + /// it operates on. + template + void startPassManager(PassT &PassManager, const IRUnitT &IR) const { + if (Callbacks) + Callbacks->startPassManager(PassManager.name(), IR); + } + + /// finishPassManager instrumentation point - takes \p PassManager instance + /// that is about to finish its operations, as well as constant reference + /// to IR it operates on. + template + void finishPassManager(PassT &PassManager, const IRUnitT &IR) const { + if (Callbacks) + Callbacks->finishPassManager(PassManager.name(), IR); + } + + /// startIteration instrumentation point - takes \p PassManager instance + /// that starts a new iteration through passes and constant reference + /// to IR it operates on. + template + void startIteration(PassT &PassManager, int Iteration) const { + if (Callbacks) + Callbacks->startIteration(PassManager.name(), Iteration); + } + /// Handle invalidation from the pass manager when PassInstrumentation /// is used as the result of PassInstrumentationAnalysis. /// Index: include/llvm/IR/PassManager.h =================================================================== --- include/llvm/IR/PassManager.h +++ include/llvm/IR/PassManager.h @@ -450,7 +450,7 @@ // instrumenting callbacks for the passes later. PassInstrumentation PI = AM.getPassInstrumentation(IR, std::tuple(ExtraArgs...)); - + PI.startPassManager(*this, IR); if (DebugLogging) dbgs() << "Starting " << getTypeName() << " pass manager run.\n"; @@ -493,6 +493,7 @@ // need to inspect each one individually. PA.preserveSet>(); + PI.finishPassManager(*this, IR); if (DebugLogging) dbgs() << "Finished " << getTypeName() << " pass manager run.\n"; @@ -1266,12 +1267,13 @@ /// Runs the function pass across every function in the module. PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) { - FunctionAnalysisManager &FAM = - AM.getResult(M).getManager(); - // Request PassInstrumentation from analysis manager, will use it to run // instrumenting callbacks for the passes later. PassInstrumentation PI = AM.getResult(M); + PI.startPassManager(*this, M); + + FunctionAnalysisManager &FAM = + AM.getResult(M).getManager(); PreservedAnalyses PA = PreservedAnalyses::all(); for (Function &F : M) { @@ -1304,6 +1306,8 @@ // invalidation we needed to do above. PA.preserveSet>(); PA.preserve(); + + PI.finishPassManager(*this, M); return PA; } @@ -1398,9 +1402,12 @@ // to extract AnalysisManager's arguments out of the whole Args set. PassInstrumentation PI = AM.getPassInstrumentation(IR, std::tuple(Args...)); - + PI.startPassManager(*this, IR); 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). @@ -1409,6 +1416,7 @@ PA.intersect(P.run(IR, AM, std::forward(Args)...)); PI.runAfterPass(P, IR); } + PI.finishPassManager(*this, IR); return PA; } Index: include/llvm/Transforms/Scalar/LoopPassManager.h =================================================================== --- include/llvm/Transforms/Scalar/LoopPassManager.h +++ include/llvm/Transforms/Scalar/LoopPassManager.h @@ -277,6 +277,7 @@ // directly build up function analyses after this as the function pass // manager handles all the invalidation at that layer. PassInstrumentation PI = AM.getResult(F); + PI.startPassManager(*this, F); PreservedAnalyses PA = PreservedAnalyses::all(); // Check the PassInstrumentation's BeforePass callbacks before running the @@ -387,6 +388,8 @@ PA.preserve(); PA.preserve(); PA.preserve(); + + PI.finishPassManager(*this, F); return PA; } Index: lib/Analysis/CGSCCPassManager.cpp =================================================================== --- lib/Analysis/CGSCCPassManager.cpp +++ lib/Analysis/CGSCCPassManager.cpp @@ -58,6 +58,7 @@ // instrumenting callbacks for the passes later. PassInstrumentation PI = AM.getResult(InitialC, G); + PI.startPassManager(*this, InitialC); PreservedAnalyses PA = PreservedAnalyses::all(); @@ -114,6 +115,7 @@ // one individually. PA.preserveSet>(); + PI.finishPassManager(*this, InitialC); if (DebugLogging) dbgs() << "Finished CGSCC pass manager run.\n"; Index: lib/IR/PassInstrumentation.cpp =================================================================== --- lib/IR/PassInstrumentation.cpp +++ lib/IR/PassInstrumentation.cpp @@ -49,6 +49,25 @@ C(AnalysisID, llvm::Any(&IR)); } +template +void PassInstrumentationCallbacks::startPassManager(StringRef PM, + const IRUnitT &IR) const { + for (auto &C : StartPMCallbacks) + C(PM, llvm::Any(&IR)); +} +template +void PassInstrumentationCallbacks::finishPassManager(StringRef PM, + const IRUnitT &IR) const { + for (auto &C : FinishPMCallbacks) + C(PM, llvm::Any(&IR)); +} + +void PassInstrumentationCallbacks::startIteration(StringRef PM, + int Iteration) const { + for (auto &C : StartIterationCallbacks) + C(PM, Iteration); +} + template bool PassInstrumentationCallbacks::runBeforePass(StringRef PassID, const Module &IR) const; @@ -93,6 +112,28 @@ const Loop &IR) const; template void PassInstrumentationCallbacks::runAfterAnalysis( StringRef PassID, const LazyCallGraph::SCC &IR) const; +template void +PassInstrumentationCallbacks::startPassManager(StringRef PassID, + const Module &IR) const; +template void +PassInstrumentationCallbacks::startPassManager(StringRef PassID, + const Function &IR) const; +template void +PassInstrumentationCallbacks::startPassManager(StringRef PassID, + const Loop &IR) const; +template void PassInstrumentationCallbacks::startPassManager( + StringRef PassID, const LazyCallGraph::SCC &IR) const; +template void +PassInstrumentationCallbacks::finishPassManager(StringRef PassID, + const Module &IR) const; +template void +PassInstrumentationCallbacks::finishPassManager(StringRef PassID, + const Function &IR) const; +template void +PassInstrumentationCallbacks::finishPassManager(StringRef PassID, + const Loop &IR) const; +template void PassInstrumentationCallbacks::finishPassManager( + StringRef PassID, const LazyCallGraph::SCC &IR) const; AnalysisKey PassInstrumentationAnalysis::Key; Index: lib/Transforms/Scalar/LoopPassManager.cpp =================================================================== --- lib/Transforms/Scalar/LoopPassManager.cpp +++ lib/Transforms/Scalar/LoopPassManager.cpp @@ -33,6 +33,7 @@ // Request PassInstrumentation from analysis manager, will use it to run // instrumenting callbacks for the passes later. PassInstrumentation PI = AM.getResult(L, AR); + PI.startPassManager(*this, L); for (auto &Pass : Passes) { if (DebugLogging) dbgs() << "Running pass: " << Pass->name() << " on " << L; @@ -83,6 +84,8 @@ // be preserved, but unrolling should invalidate the parent loop's analyses. PA.preserveSet>(); + PI.finishPassManager(*this, L); + if (DebugLogging) dbgs() << "Finished Loop pass manager run.\n"; Index: unittests/IR/PassBuilderCallbacksTest.cpp =================================================================== --- unittests/IR/PassBuilderCallbacksTest.cpp +++ unittests/IR/PassBuilderCallbacksTest.cpp @@ -272,11 +272,15 @@ EXPECT_CALL(*this, runAfterPass(_, _)).Times(AnyNumber()); EXPECT_CALL(*this, runBeforeAnalysis(_, _)).Times(AnyNumber()); EXPECT_CALL(*this, runAfterAnalysis(_, _)).Times(AnyNumber()); + EXPECT_CALL(*this, startPassManager(_, _)).Times(AnyNumber()); + EXPECT_CALL(*this, finishPassManager(_, _)).Times(AnyNumber()); } MOCK_METHOD2(runBeforePass, bool(StringRef PassID, llvm::Any)); MOCK_METHOD2(runAfterPass, void(StringRef PassID, llvm::Any)); MOCK_METHOD2(runBeforeAnalysis, void(StringRef PassID, llvm::Any)); MOCK_METHOD2(runAfterAnalysis, void(StringRef PassID, llvm::Any)); + MOCK_METHOD2(startPassManager, void(StringRef PM, llvm::Any)); + MOCK_METHOD2(finishPassManager, void(StringRef PM, llvm::Any)); }; static std::unique_ptr parseIR(LLVMContext &C, const char *IR) { @@ -435,6 +439,12 @@ PIC.registerAfterAnalysisCallback( std::bind(&MockPassInstrumentationCallbacks::runAfterAnalysis, &PICallbacks, _1, _2)); + PIC.registerStartPassManagerCallback( + std::bind(&MockPassInstrumentationCallbacks::startPassManager, + &PICallbacks, _1, _2)); + PIC.registerFinishPassManagerCallback( + std::bind(&MockPassInstrumentationCallbacks::finishPassManager, + &PICallbacks, _1, _2)); }); /// Register builtin analyses and cross-register the analysis proxies PB.registerModuleAnalyses(AM); @@ -472,6 +482,7 @@ { testing::InSequence InstrumentationExpectationsSequenced; + EXPECT_CALL(PICallbacks, startPassManager(_, HasName(""))); EXPECT_CALL(PICallbacks, runBeforePass(HasNameRegex("MockPassHandle"), HasName(""))); EXPECT_CALL(PICallbacks, @@ -482,6 +493,7 @@ HasName(""))); EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), HasName(""))); + EXPECT_CALL(PICallbacks, finishPassManager(_, HasName(""))); } StringRef PipelineText = "test-transform"; @@ -536,6 +548,12 @@ { testing::InSequence InstrumentationExpectationsSequenced; + EXPECT_CALL(PICallbacks, startPassManager(HasNameRegex("PassManager"), + HasName(""))); + EXPECT_CALL(PICallbacks, startPassManager(HasNameRegex("PassAdaptor"), + HasName(""))); + EXPECT_CALL(PICallbacks, + startPassManager(HasNameRegex("PassManager"), HasName("foo"))); EXPECT_CALL(PICallbacks, runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo"))); EXPECT_CALL( @@ -546,6 +564,9 @@ runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo"))); EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo"))); + EXPECT_CALL(PICallbacks, finishPassManager(_, HasName("foo"))); + EXPECT_CALL(PICallbacks, finishPassManager(_, HasName(""))); + EXPECT_CALL(PICallbacks, finishPassManager(_, HasName(""))); } StringRef PipelineText = "test-transform"; @@ -599,6 +620,21 @@ .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); { testing::InSequence InstrumentationExpectationsSequenced; + EXPECT_CALL(PICallbacks, + startPassManager(HasNameRegex("PassManager<.*Module.*>"), + HasName(""))); + EXPECT_CALL(PICallbacks, + startPassManager(HasNameRegex("ModuleToFunctionPassAdaptor"), + HasName(""))); + EXPECT_CALL(PICallbacks, + startPassManager(HasNameRegex("PassManager<.*Function.*>"), + HasName("foo"))); + EXPECT_CALL(PICallbacks, + startPassManager(HasNameRegex("FunctionToLoopPassAdaptor"), + HasName("foo"))); + EXPECT_CALL(PICallbacks, + startPassManager(HasNameRegex("PassManager<.*Loop.*>"), + HasName("loop"))); EXPECT_CALL(PICallbacks, runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop"))); EXPECT_CALL( @@ -609,6 +645,11 @@ runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop"))); EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"))); + EXPECT_CALL(PICallbacks, finishPassManager(_, HasName("loop"))); + EXPECT_CALL(PICallbacks, finishPassManager(_, HasName("foo"))); + EXPECT_CALL(PICallbacks, finishPassManager(_, HasName("foo"))); + EXPECT_CALL(PICallbacks, finishPassManager(_, HasName(""))); + EXPECT_CALL(PICallbacks, finishPassManager(_, HasName(""))); } StringRef PipelineText = "test-transform"; @@ -661,6 +702,17 @@ { testing::InSequence InstrumentationExpectationsSequenced; + EXPECT_CALL(PICallbacks, + startPassManager(HasNameRegex("PassManager<.*Module.*>"), + HasName(""))); + EXPECT_CALL( + PICallbacks, + startPassManager(HasNameRegex("ModuleToPostOrderCGSCCPassAdaptor"), + HasName(""))); + EXPECT_CALL( + PICallbacks, + startPassManager(HasNameRegex("PassManager<.*LazyCallGraph::SCC.*>"), + HasName("(foo)"))); EXPECT_CALL(PICallbacks, runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)"))); EXPECT_CALL(PICallbacks, @@ -671,6 +723,9 @@ runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)"))); EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))); + EXPECT_CALL(PICallbacks, finishPassManager(_, HasName("(foo)"))); + EXPECT_CALL(PICallbacks, finishPassManager(_, HasName(""))); + EXPECT_CALL(PICallbacks, finishPassManager(_, HasName(""))); } StringRef PipelineText = "test-transform";