Index: include/llvm/IR/PassInstrumentation.h =================================================================== --- include/llvm/IR/PassInstrumentation.h +++ include/llvm/IR/PassInstrumentation.h @@ -90,7 +90,7 @@ /// PassInstrumentation to pass control to the registered callbacks. class PassInstrumentationCallbacks { public: - // Before/After Pass callbacks accept IRUnits, so they need to take them + // Before/After callbacks accept IRUnits, so they need to take them // as pointers, wrapped with llvm::Any using BeforePassFunc = bool(StringRef, Any); using AfterPassFunc = void(StringRef, Any); @@ -112,6 +112,16 @@ AfterPassCallbacks.push_back(C); } + void + registerBeforeAnalysisCallback(const std::function &C) { + BeforeAnalysisCallbacks.push_back(C); + } + + void + registerAfterAnalysisCallback(const std::function &C) { + AfterAnalysisCallbacks.push_back(C); + } + private: // Instrumentation calls should not be used as a public interface. // Only for consumption by PassInstrumentation. @@ -130,9 +140,17 @@ template void runAfterPass(StringRef PassID, const IRUnitT &) const; + template + void runBeforeAnalysis(StringRef AnalysisID, const IRUnitT &) const; + + template + void runAfterAnalysis(StringRef AnalysisID, const IRUnitT &) const; + // instrumentation callbacks SmallVector, 4> BeforePassCallbacks; SmallVector, 4> AfterPassCallbacks; + SmallVector, 4> BeforeAnalysisCallbacks; + SmallVector, 4> AfterAnalysisCallbacks; }; /// This class provides instrumentation entry points for the Pass Manager, @@ -162,6 +180,22 @@ Callbacks->runAfterPass(Pass.name(), IR); } + /// BeforeAnalysis instrumentation point - takes \p Analysis instance + /// to be executed and constant reference to IR it operates on. + template + void runBeforeAnalysis(const PassT &Analysis, const IRUnitT &IR) const { + if (Callbacks) + Callbacks->runBeforeAnalysis(Analysis.name(), IR); + } + + /// AfterAnalysis instrumentation point - takes \p Analysis instance + /// that has just been executed and constant reference to IR it operated on. + template + void runAfterAnalysis(const PassT &Analysis, const IRUnitT &IR) const { + if (Callbacks) + Callbacks->runAfterAnalysis(Analysis.name(), IR); + } + /// 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 @@ -943,9 +943,18 @@ if (DebugLogging) dbgs() << "Running analysis: " << P.name() << " on " << IR.getName() << "\n"; + + PassInstrumentation PI; + if (ID != PassInstrumentationAnalysis::ID()) { + PI = getResult(IR, ExtraArgs...); + PI.runBeforeAnalysis(P, IR); + } + AnalysisResultListT &ResultList = AnalysisResultLists[&IR]; ResultList.emplace_back(ID, P.run(IR, *this, ExtraArgs...)); + PI.runAfterAnalysis(P, IR); + // P.run may have inserted elements into AnalysisResults and invalidated // RI. RI = AnalysisResults.find({ID, &IR}); Index: lib/IR/PassInstrumentation.cpp =================================================================== --- lib/IR/PassInstrumentation.cpp +++ lib/IR/PassInstrumentation.cpp @@ -35,6 +35,20 @@ C(PassID, llvm::Any(&IR)); } +template +void PassInstrumentationCallbacks::runBeforeAnalysis(StringRef AnalysisID, + const IRUnitT &IR) const { + for (auto &C : BeforeAnalysisCallbacks) + C(AnalysisID, llvm::Any(&IR)); +} + +template +void PassInstrumentationCallbacks::runAfterAnalysis(StringRef AnalysisID, + const IRUnitT &IR) const { + for (auto &C : AfterAnalysisCallbacks) + C(AnalysisID, llvm::Any(&IR)); +} + template bool PassInstrumentationCallbacks::runBeforePass(StringRef PassID, const Module &IR) const; @@ -57,6 +71,28 @@ template void PassInstrumentationCallbacks::runAfterPass(StringRef PassID, const LazyCallGraph::SCC &IR) const; +template void +PassInstrumentationCallbacks::runBeforeAnalysis(StringRef PassID, + const Module &IR) const; +template void +PassInstrumentationCallbacks::runBeforeAnalysis(StringRef PassID, + const Function &IR) const; +template void +PassInstrumentationCallbacks::runBeforeAnalysis(StringRef PassID, + const Loop &IR) const; +template void PassInstrumentationCallbacks::runBeforeAnalysis( + StringRef PassID, const LazyCallGraph::SCC &IR) const; +template void +PassInstrumentationCallbacks::runAfterAnalysis(StringRef PassID, + const Module &IR) const; +template void +PassInstrumentationCallbacks::runAfterAnalysis(StringRef PassID, + const Function &IR) const; +template void +PassInstrumentationCallbacks::runAfterAnalysis(StringRef PassID, + const Loop &IR) const; +template void PassInstrumentationCallbacks::runAfterAnalysis( + StringRef PassID, const LazyCallGraph::SCC &IR) const; AnalysisKey PassInstrumentationAnalysis::Key; Index: test/Other/new-pm-lto-defaults.ll =================================================================== --- test/Other/new-pm-lto-defaults.ll +++ test/Other/new-pm-lto-defaults.ll @@ -51,8 +51,10 @@ ; CHECK-O1-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Function ; CHECK-O-NEXT: Running analysis: LazyCallGraphAnalysis ; CHECK-O-NEXT: Running analysis: FunctionAnalysisManagerCGSCCProxy +; CHECK-O-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy<{{.*}}LazyCallGraph{{.*}}> ; CHECK-O-NEXT: Running analysis: AAManager +; CHECK-O1-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-O1-NEXT: Running analysis: TargetLibraryAnalysis ; CHECK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running analysis: CallGraphAnalysis Index: test/Other/new-pm-thinlto-defaults.ll =================================================================== --- test/Other/new-pm-thinlto-defaults.ll +++ test/Other/new-pm-thinlto-defaults.ll @@ -59,13 +59,14 @@ ; CHECK-POSTLINK-O-NEXT: Running analysis: ProfileSummaryAnalysis ; CHECK-POSTLINK-O-NEXT: Running analysis: InnerAnalysisManagerProxy ; CHECK-POSTLINK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis +; CHECK-POSTLINK-O-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-O-NEXT: Running pass: PassManager<{{.*}}Module{{.*}}> ; CHECK-O-NEXT: Starting llvm::Module pass manager run. ; CHECK-O-NEXT: Running pass: InferFunctionAttrsPass ; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis ; CHECK-O-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}> ; CHECK-PRELINK-O-NODIS-NEXT: Running analysis: InnerAnalysisManagerProxy -; CHECK-O-NEXT: Running analysis: PassInstrumentationAnalysis +; CHECK-PRELINK-O-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-O-NEXT: Starting llvm::Function pass manager run. ; CHECK-O-NEXT: Running pass: SimplifyCFGPass ; CHECK-O-NEXT: Running analysis: TargetIRAnalysis Index: unittests/IR/PassBuilderCallbacksTest.cpp =================================================================== --- unittests/IR/PassBuilderCallbacksTest.cpp +++ unittests/IR/PassBuilderCallbacksTest.cpp @@ -270,9 +270,13 @@ // by default by PassBuilder - Verifier pass etc). EXPECT_CALL(*this, runBeforePass(_, _)).Times(AnyNumber()); EXPECT_CALL(*this, runAfterPass(_, _)).Times(AnyNumber()); + EXPECT_CALL(*this, runBeforeAnalysis(_, _)).Times(AnyNumber()); + EXPECT_CALL(*this, runAfterAnalysis(_, _)).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)); }; static std::unique_ptr parseIR(LLVMContext &C, const char *IR) { @@ -425,6 +429,12 @@ PIC.registerAfterPassCallback( std::bind(&MockPassInstrumentationCallbacks::runAfterPass, &PICallbacks, _1, _2)); + PIC.registerBeforeAnalysisCallback( + std::bind(&MockPassInstrumentationCallbacks::runBeforeAnalysis, + &PICallbacks, _1, _2)); + PIC.registerAfterAnalysisCallback( + std::bind(&MockPassInstrumentationCallbacks::runAfterAnalysis, + &PICallbacks, _1, _2)); }); /// Register builtin analyses and cross-register the analysis proxies PB.registerModuleAnalyses(AM); @@ -464,6 +474,12 @@ testing::InSequence InstrumentationExpectationsSequenced; EXPECT_CALL(PICallbacks, runBeforePass(HasNameRegex("MockPassHandle"), HasName(""))); + EXPECT_CALL(PICallbacks, + runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), + HasName(""))); + EXPECT_CALL(PICallbacks, + runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), + HasName(""))); EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), HasName(""))); } @@ -484,9 +500,16 @@ EXPECT_CALL(AnalysisHandle, run(HasName(""), _)).Times(0); EXPECT_CALL(PassHandle, run(HasName(""), _)).Times(0); - // As the pass is skipped there is no afterPass as well. + // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis + // as well. EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), _)) .Times(0); + EXPECT_CALL(PICallbacks, + runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _)) + .Times(0); + EXPECT_CALL(PICallbacks, + runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _)) + .Times(0); StringRef PipelineText = "test-transform"; ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) @@ -515,6 +538,12 @@ testing::InSequence InstrumentationExpectationsSequenced; EXPECT_CALL(PICallbacks, runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo"))); + EXPECT_CALL( + PICallbacks, + runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo"))); + EXPECT_CALL( + PICallbacks, + runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo"))); EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo"))); } @@ -534,9 +563,18 @@ EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)).Times(0); EXPECT_CALL(PassHandle, run(HasName("foo"), _)).Times(0); - // As the pass is skipped there is no afterPass as well. + // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis + // as well. + EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), _)) + .Times(0); EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), _)) .Times(0); + EXPECT_CALL(PICallbacks, + runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _)) + .Times(0); + EXPECT_CALL(PICallbacks, + runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _)) + .Times(0); StringRef PipelineText = "test-transform"; ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) @@ -563,6 +601,12 @@ testing::InSequence InstrumentationExpectationsSequenced; EXPECT_CALL(PICallbacks, runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop"))); + EXPECT_CALL( + PICallbacks, + runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop"))); + EXPECT_CALL( + PICallbacks, + runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop"))); EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"))); } @@ -582,9 +626,16 @@ EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)).Times(0); EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)).Times(0); - // As the pass is skipped there is no afterPass as well. + // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis + // as well. EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), _)) .Times(0); + EXPECT_CALL(PICallbacks, + runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _)) + .Times(0); + EXPECT_CALL(PICallbacks, + runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _)) + .Times(0); StringRef PipelineText = "test-transform"; ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) @@ -612,6 +663,12 @@ testing::InSequence InstrumentationExpectationsSequenced; EXPECT_CALL(PICallbacks, runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)"))); + EXPECT_CALL(PICallbacks, + runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), + HasName("(foo)"))); + EXPECT_CALL( + PICallbacks, + runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)"))); EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))); } @@ -632,9 +689,16 @@ EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)).Times(0); EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)).Times(0); - // As the pass is skipped there is no afterPass as well. + // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis + // as well. EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), _)) .Times(0); + EXPECT_CALL(PICallbacks, + runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _)) + .Times(0); + EXPECT_CALL(PICallbacks, + runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _)) + .Times(0); StringRef PipelineText = "test-transform"; ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))