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 @@ -74,6 +74,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() {} @@ -100,6 +102,21 @@ AfterAnalysisCallbacks.emplace_back(std::move(C)); } + template + void registerStartPassManagerCallback(CallableT C) { + StartPMCallbacks.emplace_back(std::move(C)); + } + + template + void registerFinishPassManagerCallback(CallableT C) { + FinishPMCallbacks.emplace_back(std::move(C)); + } + + void + registerStartIterationCallback(llvm::unique_function &&C) { + StartIterationCallbacks.emplace_back(std::move(C)); + } + private: friend class PassInstrumentation; @@ -109,6 +126,10 @@ BeforeAnalysisCallbacks; SmallVector, 4> AfterAnalysisCallbacks; + SmallVector, 2> StartPMCallbacks; + SmallVector, 2> FinishPMCallbacks; + SmallVector, 2> + StartIterationCallbacks; }; /// This class provides instrumentation entry points for the Pass Manager, @@ -165,6 +186,36 @@ C(Analysis.name(), llvm::Any(&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(const PassT &PassManager, const IRUnitT &IR) const { + if (Callbacks) + for (auto &C : Callbacks->StartPMCallbacks) + C(PassManager.name(), llvm::Any(&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(const PassT &PassManager, const IRUnitT &IR) const { + if (Callbacks) + for (auto &C : Callbacks->FinishPMCallbacks) + C(PassManager.name(), llvm::Any(&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(const PassT &PassManager, int Iteration) const { + if (Callbacks) + for (auto &C : Callbacks->StartIterationCallbacks) + C(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 @@ -490,7 +490,7 @@ PassInstrumentation PI = detail::getAnalysisResult( AM, IR, std::tuple(ExtraArgs...)); - + PI.startPassManager(*this, IR); if (DebugLogging) dbgs() << "Starting " << getTypeName() << " pass manager run.\n"; @@ -533,6 +533,7 @@ // need to inspect each one individually. PA.preserveSet>(); + PI.finishPassManager(*this, IR); if (DebugLogging) dbgs() << "Finished " << getTypeName() << " pass manager run.\n"; @@ -1279,12 +1280,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) { @@ -1317,6 +1319,8 @@ // invalidation we needed to do above. PA.preserveSet>(); PA.preserve(); + + PI.finishPassManager(*this, M); return PA; } @@ -1413,8 +1417,12 @@ detail::getAnalysisResult( AM, 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). @@ -1423,6 +1431,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/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 @@ -318,10 +318,13 @@ MockPassInstrumentationCallbacks() { ON_CALL(*this, runBeforePass(_, _)).WillByDefault(Return(true)); } + 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)); void registerPassInstrumentation() { Callbacks.registerBeforePassCallback([this](StringRef P, llvm::Any IR) { @@ -334,6 +337,10 @@ }); Callbacks.registerAfterAnalysisCallback( [this](StringRef P, llvm::Any IR) { this->runAfterAnalysis(P, IR); }); + Callbacks.registerStartPassManagerCallback( + [this](StringRef P, llvm::Any IR) { this->startPassManager(P, IR); }); + Callbacks.registerFinishPassManagerCallback( + [this](StringRef P, llvm::Any IR) { this->finishPassManager(P, IR); }); } void ignoreNonMockPassInstrumentation(StringRef IRName) { @@ -353,6 +360,12 @@ EXPECT_CALL(*this, runAfterAnalysis(Not(HasNameRegex("Mock")), HasName(IRName))) .Times(AnyNumber()); + EXPECT_CALL(*this, + startPassManager(Not(HasNameRegex("Mock")), HasName(IRName))) + .Times(AnyNumber()); + EXPECT_CALL(*this, + finishPassManager(Not(HasNameRegex("Mock")), HasName(IRName))) + .Times(AnyNumber()); } }; @@ -489,6 +502,8 @@ // PassInstrumentation calls should happen in-sequence, in the same order // as passes/analyses are scheduled. ::testing::Sequence PISequence; + EXPECT_CALL(CallbacksHandle, startPassManager(_, HasName(""))) + .InSequence(PISequence); EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"), HasName(""))) .InSequence(PISequence); @@ -503,6 +518,8 @@ EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), HasName(""))) .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, finishPassManager(_, HasName(""))) + .InSequence(PISequence); StringRef PipelineText = "test-transform"; ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) @@ -566,6 +583,15 @@ // PassInstrumentation calls should happen in-sequence, in the same order // as passes/analyses are scheduled. ::testing::Sequence PISequence; + EXPECT_CALL(CallbacksHandle, startPassManager(HasNameRegex("PassManager"), + HasName(""))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, startPassManager(HasNameRegex("PassAdaptor"), + HasName(""))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, + startPassManager(HasNameRegex("PassManager"), HasName("foo"))) + .InSequence(PISequence); EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo"))) .InSequence(PISequence); @@ -580,6 +606,12 @@ EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo"))) .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, finishPassManager(_, HasName("foo"))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, finishPassManager(_, HasName(""))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, finishPassManager(_, HasName(""))) + .InSequence(PISequence); StringRef PipelineText = "test-transform"; ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) @@ -645,6 +677,26 @@ // PassInstrumentation calls should happen in-sequence, in the same order // as passes/analyses are scheduled. ::testing::Sequence PISequence; + EXPECT_CALL(CallbacksHandle, + startPassManager(HasNameRegex("PassManager<.*Module.*>"), + HasName(""))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, + startPassManager(HasNameRegex("ModuleToFunctionPassAdaptor"), + HasName(""))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, + startPassManager(HasNameRegex("PassManager<.*Function.*>"), + HasName("foo"))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, + startPassManager(HasNameRegex("FunctionToLoopPassAdaptor"), + HasName("foo"))) + .InSequence(PISequence); + EXPECT_CALL( + CallbacksHandle, + startPassManager(HasNameRegex("PassManager<.*Loop.*>"), HasName("loop"))) + .InSequence(PISequence); EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop"))) .InSequence(PISequence); @@ -659,6 +711,16 @@ EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"))) .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, finishPassManager(_, HasName("loop"))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, finishPassManager(_, HasName("foo"))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, finishPassManager(_, HasName("foo"))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, finishPassManager(_, HasName(""))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, finishPassManager(_, HasName(""))) + .InSequence(PISequence); StringRef PipelineText = "test-transform"; ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) @@ -722,6 +784,23 @@ // PassInstrumentation calls should happen in-sequence, in the same order // as passes/analyses are scheduled. ::testing::Sequence PISequence; + EXPECT_CALL(CallbacksHandle, + startPassManager(HasNameRegex("PassManager<.*Module.*>"), + HasName(""))) + .InSequence(PISequence); + EXPECT_CALL( + CallbacksHandle, + startPassManager(HasNameRegex("ModuleToPostOrderCGSCCPassAdaptor"), + HasName(""))) + .InSequence(PISequence); + EXPECT_CALL( + CallbacksHandle, + startPassManager(HasNameRegex("PassManager<.*LazyCallGraph::SCC.*>"), + HasName("(foo)"))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, + runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) + .InSequence(PISequence); EXPECT_CALL( CallbacksHandle, runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)"))) @@ -733,6 +812,12 @@ EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, finishPassManager(_, HasName("(foo)"))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, finishPassManager(_, HasName(""))) + .InSequence(PISequence); + EXPECT_CALL(CallbacksHandle, finishPassManager(_, HasName(""))) + .InSequence(PISequence); StringRef PipelineText = "test-transform"; ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))