aboutsummaryrefslogtreecommitdiff
path: root/llvm/unittests
diff options
context:
space:
mode:
authorFedor Sergeev <fedor.sergeev@azul.com>2018-09-20 17:08:45 +0000
committerFedor Sergeev <fedor.sergeev@azul.com>2018-09-20 17:08:45 +0000
commitee8d31c49e12a4d1fc10940a8fa644e5351239ed (patch)
tree25f4ccfea83d1279d2e543a6349a4cea2e309015 /llvm/unittests
parente23d0b636ca317347e84b3006a89eb185a130983 (diff)
downloadllvm-ee8d31c49e12a4d1fc10940a8fa644e5351239ed.zip
llvm-ee8d31c49e12a4d1fc10940a8fa644e5351239ed.tar.gz
llvm-ee8d31c49e12a4d1fc10940a8fa644e5351239ed.tar.bz2
[New PM] Introducing PassInstrumentation framework
Pass Execution Instrumentation interface enables customizable instrumentation of pass execution, as per "RFC: Pass Execution Instrumentation interface" posted 06/07/2018 on llvm-dev@ The intent is to provide a common machinery to implement all the pass-execution-debugging features like print-before/after, opt-bisect, time-passes etc. Here we get a basic implementation consisting of: * PassInstrumentationCallbacks class that handles registration of callbacks and access to them. * PassInstrumentation class that handles instrumentation-point interfaces that call into PassInstrumentationCallbacks. * Callbacks accept StringRef which is just a name of the Pass right now. There were some ideas to pass an opaque wrapper for the pointer to pass instance, however it appears that pointer does not actually identify the instance (adaptors and managers might have the same address with the pass they govern). Hence it was decided to go simple for now and then later decide on what the proper mental model of identifying a "pass in a phase of pipeline" is. * Callbacks accept llvm::Any serving as a wrapper for const IRUnit*, to remove direct dependencies on different IRUnits (e.g. Analyses). * PassInstrumentationAnalysis analysis is explicitly requested from PassManager through usual AnalysisManager::getResult. All pass managers were updated to run that to get PassInstrumentation object for instrumentation calls. * Using tuples/index_sequence getAnalysisResult helper to extract generic AnalysisManager's extra args out of a generic PassManager's extra args. This is the only way I was able to explicitly run getResult for PassInstrumentationAnalysis out of a generic code like PassManager::run or RepeatedPass::run. TODO: Upon lengthy discussions we agreed to accept this as an initial implementation and then get rid of getAnalysisResult by improving RepeatedPass implementation. * PassBuilder takes PassInstrumentationCallbacks object to pass it further into PassInstrumentationAnalysis. Callbacks registration should be performed directly through PassInstrumentationCallbacks. * new-pm tests updated to account for PassInstrumentationAnalysis being run * Added PassInstrumentation tests to PassBuilderCallbacks unit tests. Other unit tests updated with registration of the now-required PassInstrumentationAnalysis. Made getName helper to return std::string (instead of StringRef initially) to fix asan builtbot failures on CGSCC tests. Reviewers: chandlerc, philip.pfaffe Differential Revision: https://reviews.llvm.org/D47858 llvm-svn: 342664
Diffstat (limited to 'llvm/unittests')
-rw-r--r--llvm/unittests/Analysis/CGSCCPassManagerTest.cpp7
-rw-r--r--llvm/unittests/IR/PassBuilderCallbacksTest.cpp311
-rw-r--r--llvm/unittests/IR/PassManagerTest.cpp9
-rw-r--r--llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp5
4 files changed, 313 insertions, 19 deletions
diff --git a/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp b/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp
index aa0be73..60da2bb 100644
--- a/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp
+++ b/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp
@@ -231,6 +231,13 @@ public:
MAM.registerPass([&] { return TargetLibraryAnalysis(); });
MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
+
+ // Register required pass instrumentation analysis.
+ MAM.registerPass([&] { return PassInstrumentationAnalysis(); });
+ CGAM.registerPass([&] { return PassInstrumentationAnalysis(); });
+ FAM.registerPass([&] { return PassInstrumentationAnalysis(); });
+
+ // Cross-register proxies.
MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(); });
CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
diff --git a/llvm/unittests/IR/PassBuilderCallbacksTest.cpp b/llvm/unittests/IR/PassBuilderCallbacksTest.cpp
index e46fc17..024e7d6 100644
--- a/llvm/unittests/IR/PassBuilderCallbacksTest.cpp
+++ b/llvm/unittests/IR/PassBuilderCallbacksTest.cpp
@@ -7,14 +7,18 @@
//
//===----------------------------------------------------------------------===//
+#include <functional>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <llvm/ADT/Any.h>
#include <llvm/Analysis/CGSCCPassManager.h>
#include <llvm/Analysis/LoopAnalysisManager.h>
#include <llvm/AsmParser/Parser.h>
#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/PassInstrumentation.h>
#include <llvm/IR/PassManager.h>
#include <llvm/Passes/PassBuilder.h>
+#include <llvm/Support/Regex.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Transforms/Scalar/LoopPassManager.h>
@@ -32,7 +36,10 @@ static std::ostream &operator<<(std::ostream &O, StringRef S) {
}
namespace {
+using testing::AnyNumber;
+using testing::AtLeast;
using testing::DoDefault;
+using testing::Not;
using testing::Return;
using testing::Expectation;
using testing::Invoke;
@@ -87,6 +94,7 @@ public:
typename Analysis::Result getResult() {
return typename Analysis::Result(static_cast<DerivedT &>(*this));
}
+ static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
protected:
// FIXME: MSVC seems unable to handle a lambda argument to Invoke from within
@@ -143,6 +151,8 @@ public:
}
};
+ static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
+
Pass getPass() { return Pass(static_cast<DerivedT &>(*this)); }
protected:
@@ -258,6 +268,81 @@ static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
return parseAssemblyString(IR, Err, C);
}
+/// Helper for HasName matcher that returns getName both for IRUnit and
+/// for IRUnit pointer wrapper into llvm::Any (wrapped by PassInstrumentation).
+template <typename IRUnitT> std::string getName(const IRUnitT &IR) {
+ return IR.getName();
+}
+
+template <> std::string getName(const StringRef &name) { return name; }
+
+template <> std::string getName(const llvm::Any &WrappedIR) {
+ if (any_isa<const Module *>(WrappedIR))
+ return any_cast<const Module *>(WrappedIR)->getName().str();
+ if (any_isa<const Function *>(WrappedIR))
+ return any_cast<const Function *>(WrappedIR)->getName().str();
+ if (any_isa<const Loop *>(WrappedIR))
+ return any_cast<const Loop *>(WrappedIR)->getName().str();
+ if (any_isa<const LazyCallGraph::SCC *>(WrappedIR))
+ return any_cast<const LazyCallGraph::SCC *>(WrappedIR)->getName();
+ return "<UNKNOWN>";
+}
+/// Define a custom matcher for objects which support a 'getName' method.
+///
+/// LLVM often has IR objects or analysis objects which expose a name
+/// and in tests it is convenient to match these by name for readability.
+/// Usually, this name is either a StringRef or a plain std::string. This
+/// matcher supports any type exposing a getName() method of this form whose
+/// return value is compatible with an std::ostream. For StringRef, this uses
+/// the shift operator defined above.
+///
+/// It should be used as:
+///
+/// HasName("my_function")
+///
+/// No namespace or other qualification is required.
+MATCHER_P(HasName, Name, "") {
+ *result_listener << "has name '" << getName(arg) << "'";
+ return Name == getName(arg);
+}
+
+MATCHER_P(HasNameRegex, Name, "") {
+ *result_listener << "has name '" << getName(arg) << "'";
+ llvm::Regex r(Name);
+ return r.match(getName(arg));
+}
+
+struct MockPassInstrumentationCallbacks {
+ PassInstrumentationCallbacks Callbacks;
+
+ MockPassInstrumentationCallbacks() {
+ ON_CALL(*this, runBeforePass(_, _)).WillByDefault(Return(true));
+ }
+ MOCK_METHOD2(runBeforePass, bool(StringRef PassID, llvm::Any));
+ MOCK_METHOD2(runAfterPass, void(StringRef PassID, llvm::Any));
+
+ void registerPassInstrumentation() {
+ Callbacks.registerBeforePassCallback([this](StringRef P, llvm::Any IR) {
+ return this->runBeforePass(P, IR);
+ });
+ Callbacks.registerAfterPassCallback(
+ [this](StringRef P, llvm::Any IR) { this->runAfterPass(P, IR); });
+ }
+
+ void ignoreNonMockPassInstrumentation(StringRef IRName) {
+ // Generic EXPECT_CALLs are needed to match instrumentation on unimportant
+ // parts of a pipeline that we do not care about (e.g. various passes added
+ // by default by PassBuilder - Verifier pass etc).
+ // Make sure to avoid ignoring Mock passes/analysis, we definitely want
+ // to check these explicitly.
+ EXPECT_CALL(*this,
+ runBeforePass(Not(HasNameRegex("Mock")), HasName(IRName)))
+ .Times(AnyNumber());
+ EXPECT_CALL(*this, runAfterPass(Not(HasNameRegex("Mock")), HasName(IRName)))
+ .Times(AnyNumber());
+ }
+};
+
template <typename PassManagerT> class PassBuilderCallbacksTest;
/// This test fixture is shared between all the actual tests below and
@@ -280,6 +365,8 @@ protected:
LLVMContext Context;
std::unique_ptr<Module> M;
+ MockPassInstrumentationCallbacks CallbacksHandle;
+
PassBuilder PB;
ModulePassManager PM;
LoopAnalysisManager LAM;
@@ -312,6 +399,7 @@ protected:
"exit:\n"
" ret void\n"
"}\n")),
+ CallbacksHandle(), PB(nullptr, None, &CallbacksHandle.Callbacks),
PM(true), LAM(true), FAM(true), CGAM(true), AM(true) {
/// Register a callback for analysis registration.
@@ -356,25 +444,6 @@ protected:
}
};
-/// Define a custom matcher for objects which support a 'getName' method.
-///
-/// LLVM often has IR objects or analysis objects which expose a name
-/// and in tests it is convenient to match these by name for readability.
-/// Usually, this name is either a StringRef or a plain std::string. This
-/// matcher supports any type exposing a getName() method of this form whose
-/// return value is compatible with an std::ostream. For StringRef, this uses
-/// the shift operator defined above.
-///
-/// It should be used as:
-///
-/// HasName("my_function")
-///
-/// No namespace or other qualification is required.
-MATCHER_P(HasName, Name, "") {
- *result_listener << "has name '" << arg.getName() << "'";
- return Name == arg.getName();
-}
-
using ModuleCallbacksTest = PassBuilderCallbacksTest<ModulePassManager>;
using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCCPassManager>;
using FunctionCallbacksTest = PassBuilderCallbacksTest<FunctionPassManager>;
@@ -391,6 +460,57 @@ TEST_F(ModuleCallbacksTest, Passes) {
StringRef PipelineText = "test-transform";
ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
<< "Pipeline was: " << PipelineText;
+
+ PM.run(*M, AM);
+}
+
+TEST_F(ModuleCallbacksTest, InstrumentedPasses) {
+ EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
+ EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
+ .WillOnce(Invoke(getAnalysisResult));
+
+ CallbacksHandle.registerPassInstrumentation();
+ // Non-mock instrumentation not specifically mentioned below can be ignored.
+ CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+
+ // PassInstrumentation calls should happen in-sequence, in the same order
+ // as passes/analyses are scheduled.
+ ::testing::Sequence PISequence;
+ EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"),
+ HasName("<string>")))
+ .InSequence(PISequence);
+ EXPECT_CALL(CallbacksHandle,
+ runAfterPass(HasNameRegex("MockPassHandle"), HasName("<string>")))
+ .InSequence(PISequence);
+
+ StringRef PipelineText = "test-transform";
+ ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
+ << "Pipeline was: " << PipelineText;
+
+ PM.run(*M, AM);
+}
+
+TEST_F(ModuleCallbacksTest, InstrumentedSkippedPasses) {
+ CallbacksHandle.registerPassInstrumentation();
+ // Non-mock instrumentation run here can safely be ignored.
+ CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+
+ // Skip the pass by returning false.
+ EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"),
+ HasName("<string>")))
+ .WillOnce(Return(false));
+
+ EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)).Times(0);
+ EXPECT_CALL(PassHandle, run(HasName("<string>"), _)).Times(0);
+
+ // As the pass is skipped there is no afterPass as well.
+ EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
+ .Times(0);
+
+ StringRef PipelineText = "test-transform";
+ ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
+ << "Pipeline was: " << PipelineText;
+
PM.run(*M, AM);
}
@@ -405,6 +525,56 @@ TEST_F(FunctionCallbacksTest, Passes) {
PM.run(*M, AM);
}
+TEST_F(FunctionCallbacksTest, InstrumentedPasses) {
+ CallbacksHandle.registerPassInstrumentation();
+ // Non-mock instrumentation not specifically mentioned below can be ignored.
+ CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+ CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
+
+ EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
+ EXPECT_CALL(PassHandle, run(HasName("foo"), _))
+ .WillOnce(Invoke(getAnalysisResult));
+
+ // PassInstrumentation calls should happen in-sequence, in the same order
+ // as passes/analyses are scheduled.
+ ::testing::Sequence PISequence;
+ EXPECT_CALL(CallbacksHandle,
+ runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
+ .InSequence(PISequence);
+ EXPECT_CALL(CallbacksHandle,
+ runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo")))
+ .InSequence(PISequence);
+
+ StringRef PipelineText = "test-transform";
+ ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
+ << "Pipeline was: " << PipelineText;
+ PM.run(*M, AM);
+}
+
+TEST_F(FunctionCallbacksTest, InstrumentedSkippedPasses) {
+ CallbacksHandle.registerPassInstrumentation();
+ // Non-mock instrumentation run here can safely be ignored.
+ CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+ CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
+
+ // Skip the pass by returning false.
+ EXPECT_CALL(CallbacksHandle,
+ runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
+ .WillOnce(Return(false));
+
+ 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.
+ EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
+ .Times(0);
+
+ StringRef PipelineText = "test-transform";
+ ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
+ << "Pipeline was: " << PipelineText;
+ PM.run(*M, AM);
+}
+
TEST_F(LoopCallbacksTest, Passes) {
EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
@@ -416,6 +586,58 @@ TEST_F(LoopCallbacksTest, Passes) {
PM.run(*M, AM);
}
+TEST_F(LoopCallbacksTest, InstrumentedPasses) {
+ CallbacksHandle.registerPassInstrumentation();
+ // Non-mock instrumentation not specifically mentioned below can be ignored.
+ CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+ CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
+ CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
+
+ EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
+ EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
+ .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
+
+ // PassInstrumentation calls should happen in-sequence, in the same order
+ // as passes/analyses are scheduled.
+ ::testing::Sequence PISequence;
+ EXPECT_CALL(CallbacksHandle,
+ runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
+ .InSequence(PISequence);
+ EXPECT_CALL(CallbacksHandle,
+ runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop")))
+ .InSequence(PISequence);
+
+ StringRef PipelineText = "test-transform";
+ ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
+ << "Pipeline was: " << PipelineText;
+ PM.run(*M, AM);
+}
+
+TEST_F(LoopCallbacksTest, InstrumentedSkippedPasses) {
+ CallbacksHandle.registerPassInstrumentation();
+ // Non-mock instrumentation run here can safely be ignored.
+ CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+ CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
+ CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
+
+ // Skip the pass by returning false.
+ EXPECT_CALL(CallbacksHandle,
+ runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
+ .WillOnce(Return(false));
+
+ 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.
+ EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
+ .Times(0);
+
+ StringRef PipelineText = "test-transform";
+ ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
+ << "Pipeline was: " << PipelineText;
+ PM.run(*M, AM);
+}
+
TEST_F(CGSCCCallbacksTest, Passes) {
EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
@@ -427,6 +649,57 @@ TEST_F(CGSCCCallbacksTest, Passes) {
PM.run(*M, AM);
}
+TEST_F(CGSCCCallbacksTest, InstrumentedPasses) {
+ CallbacksHandle.registerPassInstrumentation();
+ // Non-mock instrumentation not specifically mentioned below can be ignored.
+ CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+ CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
+
+ EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
+ EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
+ .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
+
+ // PassInstrumentation calls should happen in-sequence, in the same order
+ // as passes/analyses are scheduled.
+ ::testing::Sequence PISequence;
+ EXPECT_CALL(CallbacksHandle,
+ runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
+ .InSequence(PISequence);
+ EXPECT_CALL(CallbacksHandle,
+ runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
+ .InSequence(PISequence);
+
+ StringRef PipelineText = "test-transform";
+ ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
+ << "Pipeline was: " << PipelineText;
+ PM.run(*M, AM);
+}
+
+TEST_F(CGSCCCallbacksTest, InstrumentedSkippedPasses) {
+ CallbacksHandle.registerPassInstrumentation();
+ // Non-mock instrumentation run here can safely be ignored.
+ CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+ CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
+
+ // Skip the pass by returning false.
+ EXPECT_CALL(CallbacksHandle,
+ runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
+ .WillOnce(Return(false));
+
+ // 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 as well.
+ EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
+ .Times(0);
+
+ StringRef PipelineText = "test-transform";
+ ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
+ << "Pipeline was: " << PipelineText;
+ PM.run(*M, AM);
+}
+
/// Test parsing of the names of analysis utilities for our mock analysis
/// for all IRUnits.
///
diff --git a/llvm/unittests/IR/PassManagerTest.cpp b/llvm/unittests/IR/PassManagerTest.cpp
index 7709453..13b87f1 100644
--- a/llvm/unittests/IR/PassManagerTest.cpp
+++ b/llvm/unittests/IR/PassManagerTest.cpp
@@ -406,6 +406,9 @@ TEST_F(PassManagerTest, Basic) {
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
+ MAM.registerPass([&] { return PassInstrumentationAnalysis(); });
+ FAM.registerPass([&] { return PassInstrumentationAnalysis(); });
+
ModulePassManager MPM;
// Count the runs over a Function.
@@ -556,6 +559,8 @@ struct CustomizedPass : PassInfoMixin<CustomizedPass> {
TEST_F(PassManagerTest, CustomizedPassManagerArgs) {
CustomizedAnalysisManager AM;
AM.registerPass([&] { return CustomizedAnalysis(); });
+ PassInstrumentationCallbacks PIC;
+ AM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
CustomizedPassManager PM;
@@ -688,6 +693,10 @@ TEST_F(PassManagerTest, IndirectAnalysisInvalidation) {
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
+ PassInstrumentationCallbacks PIC;
+ MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
+ FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
+
int InstrCount = 0, FunctionCount = 0;
ModulePassManager MPM(/*DebugLogging*/ true);
FunctionPassManager FPM(/*DebugLogging*/ true);
diff --git a/llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp b/llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
index 57fb57e..9f0b6f0 100644
--- a/llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
+++ b/llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
@@ -308,6 +308,11 @@ public:
FAM.registerPass([&] { return TargetLibraryAnalysis(); });
FAM.registerPass([&] { return TargetIRAnalysis(); });
+ // Register required pass instrumentation analysis.
+ LAM.registerPass([&] { return PassInstrumentationAnalysis(); });
+ FAM.registerPass([&] { return PassInstrumentationAnalysis(); });
+ MAM.registerPass([&] { return PassInstrumentationAnalysis(); });
+
// Cross-register proxies.
LAM.registerPass([&] { return FunctionAnalysisManagerLoopProxy(FAM); });
FAM.registerPass([&] { return LoopAnalysisManagerFunctionProxy(LAM); });