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)); } + void + registerStartPassManagerCallback(llvm::unique_function &&C) { + StartPMCallbacks.emplace_back(std::move(C)); + } + + void registerFinishPassManagerCallback( + llvm::unique_function &&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 @@ -488,7 +488,7 @@ PassInstrumentation PI = detail::getAnalysisResult( AM, IR, std::tuple(ExtraArgs...)); - + PI.startPassManager(*this, IR); if (DebugLogging) dbgs() << "Starting " << getTypeName() << " pass manager run.\n"; @@ -531,6 +531,7 @@ // need to inspect each one individually. PA.preserveSet>(); + PI.finishPassManager(*this, IR); if (DebugLogging) dbgs() << "Finished " << getTypeName() << " pass manager run.\n"; @@ -1277,12 +1278,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) { @@ -1315,6 +1317,8 @@ // invalidation we needed to do above. PA.preserveSet>(); PA.preserve(); + + PI.finishPassManager(*this, M); return PA; } @@ -1411,8 +1415,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). @@ -1421,6 +1429,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 @@ -274,11 +274,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)); void registerPassInstrumentation() { Callbacks.registerBeforePassCallback([this](StringRef P, llvm::Any IR) { @@ -291,6 +295,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); }); } }; @@ -474,6 +482,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); @@ -488,6 +498,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)) @@ -546,6 +558,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); @@ -560,6 +581,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)) @@ -618,6 +645,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); @@ -632,6 +679,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)) @@ -688,6 +745,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)"))) @@ -699,6 +773,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))