diff options
author | Fedor Sergeev <fedor.sergeev@azul.com> | 2018-09-20 17:08:45 +0000 |
---|---|---|
committer | Fedor Sergeev <fedor.sergeev@azul.com> | 2018-09-20 17:08:45 +0000 |
commit | ee8d31c49e12a4d1fc10940a8fa644e5351239ed (patch) | |
tree | 25f4ccfea83d1279d2e543a6349a4cea2e309015 /llvm/unittests | |
parent | e23d0b636ca317347e84b3006a89eb185a130983 (diff) | |
download | llvm-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.cpp | 7 | ||||
-rw-r--r-- | llvm/unittests/IR/PassBuilderCallbacksTest.cpp | 311 | ||||
-rw-r--r-- | llvm/unittests/IR/PassManagerTest.cpp | 9 | ||||
-rw-r--r-- | llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp | 5 |
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); }); |