diff --git a/llvm/include/llvm/IR/PassInstrumentation.h b/llvm/include/llvm/IR/PassInstrumentation.h --- a/llvm/include/llvm/IR/PassInstrumentation.h +++ b/llvm/include/llvm/IR/PassInstrumentation.h @@ -74,6 +74,7 @@ // IRUnits in a safe way, and we might pursue that as soon as there is a // useful instrumentation that needs it. using BeforePassFunc = bool(StringRef, Any); + using BeforeSkippedPassFunc = void(StringRef, Any); using BeforeNonSkippedPassFunc = void(StringRef, Any); using AfterPassFunc = void(StringRef, Any); using AfterPassInvalidatedFunc = void(StringRef); @@ -91,6 +92,11 @@ BeforePassCallbacks.emplace_back(std::move(C)); } + template + void registerBeforeSkippedPassCallback(CallableT C) { + BeforeSkippedPassCallbacks.emplace_back(std::move(C)); + } + template void registerBeforeNonSkippedPassCallback(CallableT C) { BeforeNonSkippedPassCallbacks.emplace_back(std::move(C)); @@ -119,6 +125,8 @@ friend class PassInstrumentation; SmallVector, 4> BeforePassCallbacks; + SmallVector, 4> + BeforeSkippedPassCallbacks; SmallVector, 4> BeforeNonSkippedPassCallbacks; SmallVector, 4> AfterPassCallbacks; @@ -179,6 +187,9 @@ if (ShouldRun) { for (auto &C : Callbacks->BeforeNonSkippedPassCallbacks) C(Pass.name(), llvm::Any(&IR)); + } else { + for (auto &C : Callbacks->BeforeSkippedPassCallbacks) + C(Pass.name(), llvm::Any(&IR)); } return ShouldRun; diff --git a/llvm/unittests/IR/PassBuilderCallbacksTest.cpp b/llvm/unittests/IR/PassBuilderCallbacksTest.cpp --- a/llvm/unittests/IR/PassBuilderCallbacksTest.cpp +++ b/llvm/unittests/IR/PassBuilderCallbacksTest.cpp @@ -320,6 +320,7 @@ ON_CALL(*this, runBeforePass(_, _)).WillByDefault(Return(true)); } MOCK_METHOD2(runBeforePass, bool(StringRef PassID, llvm::Any)); + MOCK_METHOD2(runBeforeSkippedPass, void(StringRef PassID, llvm::Any)); MOCK_METHOD2(runBeforeNonSkippedPass, void(StringRef PassID, llvm::Any)); MOCK_METHOD2(runAfterPass, void(StringRef PassID, llvm::Any)); MOCK_METHOD1(runAfterPassInvalidated, void(StringRef PassID)); @@ -330,6 +331,10 @@ Callbacks.registerBeforePassCallback([this](StringRef P, llvm::Any IR) { return this->runBeforePass(P, IR); }); + Callbacks.registerBeforeSkippedPassCallback( + [this](StringRef P, llvm::Any IR) { + this->runBeforeSkippedPass(P, IR); + }); Callbacks.registerBeforeNonSkippedPassCallback( [this](StringRef P, llvm::Any IR) { this->runBeforeNonSkippedPass(P, IR); @@ -354,6 +359,9 @@ EXPECT_CALL(*this, runBeforePass(Not(HasNameRegex("Mock")), HasName(IRName))) .Times(AnyNumber()); + EXPECT_CALL( + *this, runBeforeSkippedPass(Not(HasNameRegex("Mock")), HasName(IRName))) + .Times(AnyNumber()); EXPECT_CALL(*this, runBeforeNonSkippedPass(Not(HasNameRegex("Mock")), HasName(IRName))) .Times(AnyNumber()); @@ -524,6 +532,13 @@ runAfterPass(HasNameRegex("MockPassHandle"), HasName(""))) .InSequence(PISequence); + // No passes are skipped, so there should be no calls to + // runBeforeSkippedPass(). + EXPECT_CALL( + CallbacksHandle, + runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName(""))) + .Times(0); + StringRef PipelineText = "test-transform"; ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; @@ -535,12 +550,17 @@ CallbacksHandle.registerPassInstrumentation(); // Non-mock instrumentation run here can safely be ignored. CallbacksHandle.ignoreNonMockPassInstrumentation(""); + CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); // Skip all passes by returning false. Pass managers and adaptor passes are // also passes that observed by the callbacks. EXPECT_CALL(CallbacksHandle, runBeforePass(_, _)) .WillRepeatedly(Return(false)); + EXPECT_CALL(CallbacksHandle, + runBeforeSkippedPass(HasNameRegex("MockPassHandle"), _)) + .Times(3); + EXPECT_CALL(AnalysisHandle, run(HasName(""), _)).Times(0); EXPECT_CALL(PassHandle, run(HasName(""), _)).Times(0); @@ -684,6 +704,13 @@ runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo"))) .InSequence(PISequence); + // No passes are skipped, so there should be no calls to + // runBeforeSkippedPass(). + EXPECT_CALL( + CallbacksHandle, + runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo"))) + .Times(0); + // Our mock pass does not invalidate IR. EXPECT_CALL(CallbacksHandle, runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) @@ -706,11 +733,19 @@ runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo"))) .WillOnce(Return(false)); + EXPECT_CALL( + CallbacksHandle, + runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo"))) + .Times(1); + 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, beforeAnalysis/afterAnalysis // as well. + EXPECT_CALL(CallbacksHandle, + runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _)) + .Times(0); EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) .Times(0); EXPECT_CALL(CallbacksHandle, @@ -780,6 +815,13 @@ runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) .Times(0); + // No passes are skipped, so there should be no calls to + // runBeforeSkippedPass(). + EXPECT_CALL( + CallbacksHandle, + runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop"))) + .Times(0); + StringRef PipelineText = "test-transform"; ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; @@ -846,11 +888,19 @@ runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop"))) .WillOnce(Return(false)); + EXPECT_CALL( + CallbacksHandle, + runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop"))) + .Times(1); + 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, beforeAnalysis/afterAnalysis // as well. + EXPECT_CALL(CallbacksHandle, + runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _)) + .Times(0); EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) .Times(0); EXPECT_CALL(CallbacksHandle, @@ -918,6 +968,13 @@ runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) .Times(0); + // No passes are skipped, so there should be no calls to + // runBeforeSkippedPass(). + EXPECT_CALL( + CallbacksHandle, + runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) + .Times(0); + StringRef PipelineText = "test-transform"; ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; @@ -984,12 +1041,20 @@ runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) .WillOnce(Return(false)); + EXPECT_CALL( + CallbacksHandle, + runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) + .Times(1); + // neither Analysis nor Pass are called. 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, beforeAnalysis/afterAnalysis // as well. + EXPECT_CALL(CallbacksHandle, + runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _)) + .Times(0); EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) .Times(0); EXPECT_CALL(CallbacksHandle,