123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985 |
- //===- unittests/IR/PassBuilderCallbacksTest.cpp - PB Callback Tests --===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/Testing/Support/Error.h"
- #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>
- using namespace llvm;
- namespace {
- using testing::AnyNumber;
- using testing::AtLeast;
- using testing::DoDefault;
- using testing::Not;
- using testing::Return;
- using testing::Expectation;
- using testing::Invoke;
- using testing::WithArgs;
- using testing::_;
- /// A CRTP base for analysis mock handles
- ///
- /// This class reconciles mocking with the value semantics implementation of the
- /// AnalysisManager. Analysis mock handles should derive from this class and
- /// call \c setDefault() in their constroctur for wiring up the defaults defined
- /// by this base with their mock run() and invalidate() implementations.
- template <typename DerivedT, typename IRUnitT,
- typename AnalysisManagerT = AnalysisManager<IRUnitT>,
- typename... ExtraArgTs>
- class MockAnalysisHandleBase {
- public:
- class Analysis : public AnalysisInfoMixin<Analysis> {
- friend AnalysisInfoMixin<Analysis>;
- friend MockAnalysisHandleBase;
- static AnalysisKey Key;
- DerivedT *Handle;
- Analysis(DerivedT &Handle) : Handle(&Handle) {
- static_assert(std::is_base_of<MockAnalysisHandleBase, DerivedT>::value,
- "Must pass the derived type to this template!");
- }
- public:
- class Result {
- friend MockAnalysisHandleBase;
- DerivedT *Handle;
- Result(DerivedT &Handle) : Handle(&Handle) {}
- public:
- // Forward invalidation events to the mock handle.
- bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,
- typename AnalysisManagerT::Invalidator &Inv) {
- return Handle->invalidate(IR, PA, Inv);
- }
- };
- Result run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs) {
- return Handle->run(IR, AM, ExtraArgs...);
- }
- };
- Analysis getAnalysis() { return Analysis(static_cast<DerivedT &>(*this)); }
- 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
- // the template, so we use a boring static function.
- static bool invalidateCallback(IRUnitT &IR, const PreservedAnalyses &PA,
- typename AnalysisManagerT::Invalidator &Inv) {
- auto PAC = PA.template getChecker<Analysis>();
- return !PAC.preserved() &&
- !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>();
- }
- /// Derived classes should call this in their constructor to set up default
- /// mock actions. (We can't do this in our constructor because this has to
- /// run after the DerivedT is constructed.)
- void setDefaults() {
- ON_CALL(static_cast<DerivedT &>(*this),
- run(_, _, testing::Matcher<ExtraArgTs>(_)...))
- .WillByDefault(Return(this->getResult()));
- ON_CALL(static_cast<DerivedT &>(*this), invalidate(_, _, _))
- .WillByDefault(Invoke(&invalidateCallback));
- }
- };
- /// A CRTP base for pass mock handles
- ///
- /// This class reconciles mocking with the value semantics implementation of the
- /// PassManager. Pass mock handles should derive from this class and
- /// call \c setDefault() in their constroctur for wiring up the defaults defined
- /// by this base with their mock run() and invalidate() implementations.
- template <typename DerivedT, typename IRUnitT, typename AnalysisManagerT,
- typename... ExtraArgTs>
- AnalysisKey MockAnalysisHandleBase<DerivedT, IRUnitT, AnalysisManagerT,
- ExtraArgTs...>::Analysis::Key;
- template <typename DerivedT, typename IRUnitT,
- typename AnalysisManagerT = AnalysisManager<IRUnitT>,
- typename... ExtraArgTs>
- class MockPassHandleBase {
- public:
- class Pass : public PassInfoMixin<Pass> {
- friend MockPassHandleBase;
- DerivedT *Handle;
- Pass(DerivedT &Handle) : Handle(&Handle) {
- static_assert(std::is_base_of<MockPassHandleBase, DerivedT>::value,
- "Must pass the derived type to this template!");
- }
- public:
- PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
- ExtraArgTs... ExtraArgs) {
- return Handle->run(IR, AM, ExtraArgs...);
- }
- };
- static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
- Pass getPass() { return Pass(static_cast<DerivedT &>(*this)); }
- protected:
- /// Derived classes should call this in their constructor to set up default
- /// mock actions. (We can't do this in our constructor because this has to
- /// run after the DerivedT is constructed.)
- void setDefaults() {
- ON_CALL(static_cast<DerivedT &>(*this),
- run(_, _, testing::Matcher<ExtraArgTs>(_)...))
- .WillByDefault(Return(PreservedAnalyses::all()));
- }
- };
- /// Mock handles for passes for the IRUnits Module, CGSCC, Function, Loop.
- /// These handles define the appropriate run() mock interface for the respective
- /// IRUnit type.
- template <typename IRUnitT> struct MockPassHandle;
- template <>
- struct MockPassHandle<Loop>
- : MockPassHandleBase<MockPassHandle<Loop>, Loop, LoopAnalysisManager,
- LoopStandardAnalysisResults &, LPMUpdater &> {
- MOCK_METHOD4(run,
- PreservedAnalyses(Loop &, LoopAnalysisManager &,
- LoopStandardAnalysisResults &, LPMUpdater &));
- static void invalidateLoop(Loop &L, LoopAnalysisManager &,
- LoopStandardAnalysisResults &,
- LPMUpdater &Updater) {
- Updater.markLoopAsDeleted(L, L.getName());
- }
- MockPassHandle() { setDefaults(); }
- };
- template <>
- struct MockPassHandle<Function>
- : MockPassHandleBase<MockPassHandle<Function>, Function> {
- MOCK_METHOD2(run, PreservedAnalyses(Function &, FunctionAnalysisManager &));
- MockPassHandle() { setDefaults(); }
- };
- template <>
- struct MockPassHandle<LazyCallGraph::SCC>
- : MockPassHandleBase<MockPassHandle<LazyCallGraph::SCC>, LazyCallGraph::SCC,
- CGSCCAnalysisManager, LazyCallGraph &,
- CGSCCUpdateResult &> {
- MOCK_METHOD4(run,
- PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &,
- LazyCallGraph &G, CGSCCUpdateResult &UR));
- static void invalidateSCC(LazyCallGraph::SCC &C, CGSCCAnalysisManager &,
- LazyCallGraph &, CGSCCUpdateResult &UR) {
- UR.InvalidatedSCCs.insert(&C);
- }
- MockPassHandle() { setDefaults(); }
- };
- template <>
- struct MockPassHandle<Module>
- : MockPassHandleBase<MockPassHandle<Module>, Module> {
- MOCK_METHOD2(run, PreservedAnalyses(Module &, ModuleAnalysisManager &));
- MockPassHandle() { setDefaults(); }
- };
- /// Mock handles for analyses for the IRUnits Module, CGSCC, Function, Loop.
- /// These handles define the appropriate run() and invalidate() mock interfaces
- /// for the respective IRUnit type.
- template <typename IRUnitT> struct MockAnalysisHandle;
- template <>
- struct MockAnalysisHandle<Loop>
- : MockAnalysisHandleBase<MockAnalysisHandle<Loop>, Loop,
- LoopAnalysisManager,
- LoopStandardAnalysisResults &> {
- MOCK_METHOD3_T(run, typename Analysis::Result(Loop &, LoopAnalysisManager &,
- LoopStandardAnalysisResults &));
- MOCK_METHOD3_T(invalidate, bool(Loop &, const PreservedAnalyses &,
- LoopAnalysisManager::Invalidator &));
- MockAnalysisHandle<Loop>() { this->setDefaults(); }
- };
- template <>
- struct MockAnalysisHandle<Function>
- : MockAnalysisHandleBase<MockAnalysisHandle<Function>, Function> {
- MOCK_METHOD2(run, Analysis::Result(Function &, FunctionAnalysisManager &));
- MOCK_METHOD3(invalidate, bool(Function &, const PreservedAnalyses &,
- FunctionAnalysisManager::Invalidator &));
- MockAnalysisHandle<Function>() { setDefaults(); }
- };
- template <>
- struct MockAnalysisHandle<LazyCallGraph::SCC>
- : MockAnalysisHandleBase<MockAnalysisHandle<LazyCallGraph::SCC>,
- LazyCallGraph::SCC, CGSCCAnalysisManager,
- LazyCallGraph &> {
- MOCK_METHOD3(run, Analysis::Result(LazyCallGraph::SCC &,
- CGSCCAnalysisManager &, LazyCallGraph &));
- MOCK_METHOD3(invalidate, bool(LazyCallGraph::SCC &, const PreservedAnalyses &,
- CGSCCAnalysisManager::Invalidator &));
- MockAnalysisHandle<LazyCallGraph::SCC>() { setDefaults(); }
- };
- template <>
- struct MockAnalysisHandle<Module>
- : MockAnalysisHandleBase<MockAnalysisHandle<Module>, Module> {
- MOCK_METHOD2(run, Analysis::Result(Module &, ModuleAnalysisManager &));
- MOCK_METHOD3(invalidate, bool(Module &, const PreservedAnalyses &,
- ModuleAnalysisManager::Invalidator &));
- MockAnalysisHandle<Module>() { setDefaults(); }
- };
- static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
- SMDiagnostic Err;
- 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));
- MOCK_METHOD1(runAfterPassInvalidated, void(StringRef PassID));
- MOCK_METHOD2(runBeforeAnalysis, void(StringRef PassID, llvm::Any));
- MOCK_METHOD2(runAfterAnalysis, 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); });
- Callbacks.registerAfterPassInvalidatedCallback(
- [this](StringRef P) { this->runAfterPassInvalidated(P); });
- Callbacks.registerBeforeAnalysisCallback([this](StringRef P, llvm::Any IR) {
- return this->runBeforeAnalysis(P, IR);
- });
- Callbacks.registerAfterAnalysisCallback(
- [this](StringRef P, llvm::Any IR) { this->runAfterAnalysis(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());
- EXPECT_CALL(*this,
- runBeforeAnalysis(Not(HasNameRegex("Mock")), HasName(IRName)))
- .Times(AnyNumber());
- EXPECT_CALL(*this,
- runAfterAnalysis(Not(HasNameRegex("Mock")), HasName(IRName)))
- .Times(AnyNumber());
- }
- };
- template <typename PassManagerT> class PassBuilderCallbacksTest;
- /// This test fixture is shared between all the actual tests below and
- /// takes care of setting up appropriate defaults.
- ///
- /// The template specialization serves to extract the IRUnit and AM types from
- /// the given PassManagerT.
- template <typename TestIRUnitT, typename... ExtraPassArgTs,
- typename... ExtraAnalysisArgTs>
- class PassBuilderCallbacksTest<PassManager<
- TestIRUnitT, AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>,
- ExtraPassArgTs...>> : public testing::Test {
- protected:
- using IRUnitT = TestIRUnitT;
- using AnalysisManagerT = AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>;
- using PassManagerT =
- PassManager<TestIRUnitT, AnalysisManagerT, ExtraPassArgTs...>;
- using AnalysisT = typename MockAnalysisHandle<IRUnitT>::Analysis;
- LLVMContext Context;
- std::unique_ptr<Module> M;
- MockPassInstrumentationCallbacks CallbacksHandle;
- PassBuilder PB;
- ModulePassManager PM;
- LoopAnalysisManager LAM;
- FunctionAnalysisManager FAM;
- CGSCCAnalysisManager CGAM;
- ModuleAnalysisManager AM;
- MockPassHandle<IRUnitT> PassHandle;
- MockAnalysisHandle<IRUnitT> AnalysisHandle;
- static PreservedAnalyses getAnalysisResult(IRUnitT &U, AnalysisManagerT &AM,
- ExtraAnalysisArgTs &&... Args) {
- (void)AM.template getResult<AnalysisT>(
- U, std::forward<ExtraAnalysisArgTs>(Args)...);
- return PreservedAnalyses::all();
- }
- PassBuilderCallbacksTest()
- : M(parseIR(Context,
- "declare void @bar()\n"
- "define void @foo(i32 %n) {\n"
- "entry:\n"
- " br label %loop\n"
- "loop:\n"
- " %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]\n"
- " %iv.next = add i32 %iv, 1\n"
- " tail call void @bar()\n"
- " %cmp = icmp eq i32 %iv, %n\n"
- " br i1 %cmp, label %exit, label %loop\n"
- "exit:\n"
- " ret void\n"
- "}\n")),
- CallbacksHandle(),
- PB(nullptr, PipelineTuningOptions(), None, &CallbacksHandle.Callbacks),
- PM(true), LAM(true), FAM(true), CGAM(true), AM(true) {
- /// Register a callback for analysis registration.
- ///
- /// The callback is a function taking a reference to an AnalyisManager
- /// object. When called, the callee gets to register its own analyses with
- /// this PassBuilder instance.
- PB.registerAnalysisRegistrationCallback([this](AnalysisManagerT &AM) {
- // Register our mock analysis
- AM.registerPass([this] { return AnalysisHandle.getAnalysis(); });
- });
- /// Register a callback for pipeline parsing.
- ///
- /// During parsing of a textual pipeline, the PassBuilder will call these
- /// callbacks for each encountered pass name that it does not know. This
- /// includes both simple pass names as well as names of sub-pipelines. In
- /// the latter case, the InnerPipeline is not empty.
- PB.registerPipelineParsingCallback(
- [this](StringRef Name, PassManagerT &PM,
- ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {
- /// Handle parsing of the names of analysis utilities such as
- /// require<test-analysis> and invalidate<test-analysis> for our
- /// analysis mock handle
- if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", Name, PM))
- return true;
- /// Parse the name of our pass mock handle
- if (Name == "test-transform") {
- PM.addPass(PassHandle.getPass());
- return true;
- }
- return false;
- });
- /// Register builtin analyses and cross-register the analysis proxies
- PB.registerModuleAnalyses(AM);
- PB.registerCGSCCAnalyses(CGAM);
- PB.registerFunctionAnalyses(FAM);
- PB.registerLoopAnalyses(LAM);
- PB.crossRegisterProxies(LAM, FAM, CGAM, AM);
- }
- };
- using ModuleCallbacksTest = PassBuilderCallbacksTest<ModulePassManager>;
- using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCCPassManager>;
- using FunctionCallbacksTest = PassBuilderCallbacksTest<FunctionPassManager>;
- using LoopCallbacksTest = PassBuilderCallbacksTest<LoopPassManager>;
- /// Test parsing of the name of our mock pass for all IRUnits.
- ///
- /// The pass should by default run our mock analysis and then preserve it.
- TEST_F(ModuleCallbacksTest, Passes) {
- EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
- EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
- .WillOnce(Invoke(getAnalysisResult));
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "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,
- runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"),
- HasName("<string>")))
- .InSequence(PISequence);
- EXPECT_CALL(
- CallbacksHandle,
- runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("<string>")))
- .InSequence(PISequence);
- EXPECT_CALL(CallbacksHandle,
- runAfterPass(HasNameRegex("MockPassHandle"), HasName("<string>")))
- .InSequence(PISequence);
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "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, beforeAnalysis/afterAnalysis
- // as well.
- EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
- .Times(0);
- EXPECT_CALL(CallbacksHandle,
- runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
- .Times(0);
- EXPECT_CALL(CallbacksHandle,
- runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
- .Times(0);
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- PM.run(*M, AM);
- }
- TEST_F(FunctionCallbacksTest, Passes) {
- EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
- EXPECT_CALL(PassHandle, run(HasName("foo"), _))
- .WillOnce(Invoke(getAnalysisResult));
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- 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,
- runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))
- .InSequence(PISequence);
- EXPECT_CALL(
- CallbacksHandle,
- runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))
- .InSequence(PISequence);
- EXPECT_CALL(CallbacksHandle,
- runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo")))
- .InSequence(PISequence);
- // Our mock pass does not invalidate IR.
- EXPECT_CALL(CallbacksHandle,
- runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
- .Times(0);
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "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, beforeAnalysis/afterAnalysis
- // as well.
- EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
- .Times(0);
- EXPECT_CALL(CallbacksHandle,
- runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
- .Times(0);
- EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
- .Times(0);
- EXPECT_CALL(CallbacksHandle,
- runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
- .Times(0);
- EXPECT_CALL(CallbacksHandle,
- runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
- .Times(0);
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- PM.run(*M, AM);
- }
- TEST_F(LoopCallbacksTest, Passes) {
- EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
- EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
- .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- 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,
- runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
- .InSequence(PISequence);
- EXPECT_CALL(
- CallbacksHandle,
- runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
- .InSequence(PISequence);
- EXPECT_CALL(CallbacksHandle,
- runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop")))
- .InSequence(PISequence);
- // Our mock pass does not invalidate IR.
- EXPECT_CALL(CallbacksHandle,
- runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
- .Times(0);
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- PM.run(*M, AM);
- }
- TEST_F(LoopCallbacksTest, InstrumentedInvalidatingPasses) {
- 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(DoAll(WithArgs<0, 1, 2, 3>(Invoke(PassHandle.invalidateLoop)),
- 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,
- runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
- .InSequence(PISequence);
- EXPECT_CALL(
- CallbacksHandle,
- runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
- .InSequence(PISequence);
- EXPECT_CALL(CallbacksHandle,
- runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
- .InSequence(PISequence);
- EXPECT_CALL(CallbacksHandle,
- runAfterPassInvalidated(HasNameRegex("^PassManager")))
- .InSequence(PISequence);
- // Our mock pass invalidates IR, thus normal runAfterPass is never called.
- EXPECT_CALL(CallbacksHandle,
- runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop")))
- .Times(0);
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "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, beforeAnalysis/afterAnalysis
- // as well.
- EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
- .Times(0);
- EXPECT_CALL(CallbacksHandle,
- runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
- .Times(0);
- EXPECT_CALL(CallbacksHandle,
- runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
- .Times(0);
- EXPECT_CALL(CallbacksHandle,
- runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
- .Times(0);
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- PM.run(*M, AM);
- }
- TEST_F(CGSCCCallbacksTest, Passes) {
- EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
- EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
- .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- 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");
- 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,
- runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
- .InSequence(PISequence);
- EXPECT_CALL(
- CallbacksHandle,
- runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
- .InSequence(PISequence);
- EXPECT_CALL(CallbacksHandle,
- runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
- .InSequence(PISequence);
- // Our mock pass does not invalidate IR.
- EXPECT_CALL(CallbacksHandle,
- runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
- .Times(0);
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- PM.run(*M, AM);
- }
- TEST_F(CGSCCCallbacksTest, InstrumentedInvalidatingPasses) {
- CallbacksHandle.registerPassInstrumentation();
- // Non-mock instrumentation not specifically mentioned below can be ignored.
- CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
- CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
- CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
- EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
- EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
- .WillOnce(DoAll(WithArgs<0, 1, 2, 3>(Invoke(PassHandle.invalidateSCC)),
- 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,
- runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
- .InSequence(PISequence);
- EXPECT_CALL(
- CallbacksHandle,
- runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
- .InSequence(PISequence);
- EXPECT_CALL(CallbacksHandle,
- runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
- .InSequence(PISequence);
- EXPECT_CALL(CallbacksHandle,
- runAfterPassInvalidated(HasNameRegex("^PassManager")))
- .InSequence(PISequence);
- // Our mock pass does invalidate IR, thus normal runAfterPass is never called.
- EXPECT_CALL(CallbacksHandle,
- runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
- .Times(0);
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "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");
- 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, beforeAnalysis/afterAnalysis
- // as well.
- EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
- .Times(0);
- EXPECT_CALL(CallbacksHandle,
- runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
- .Times(0);
- EXPECT_CALL(CallbacksHandle,
- runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
- .Times(0);
- EXPECT_CALL(CallbacksHandle,
- runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
- .Times(0);
- StringRef PipelineText = "test-transform";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- PM.run(*M, AM);
- }
- /// Test parsing of the names of analysis utilities for our mock analysis
- /// for all IRUnits.
- ///
- /// We first require<>, then invalidate<> it, expecting the analysis to be run
- /// once and subsequently invalidated.
- TEST_F(ModuleCallbacksTest, AnalysisUtilities) {
- EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
- EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));
- StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- PM.run(*M, AM);
- }
- TEST_F(CGSCCCallbacksTest, PassUtilities) {
- EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
- EXPECT_CALL(AnalysisHandle, invalidate(HasName("(foo)"), _, _));
- StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- PM.run(*M, AM);
- }
- TEST_F(FunctionCallbacksTest, AnalysisUtilities) {
- EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
- EXPECT_CALL(AnalysisHandle, invalidate(HasName("foo"), _, _));
- StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- PM.run(*M, AM);
- }
- TEST_F(LoopCallbacksTest, PassUtilities) {
- EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
- EXPECT_CALL(AnalysisHandle, invalidate(HasName("loop"), _, _));
- StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- PM.run(*M, AM);
- }
- /// Test parsing of the top-level pipeline.
- ///
- /// The ParseTopLevelPipeline callback takes over parsing of the entire pipeline
- /// from PassBuilder if it encounters an unknown pipeline entry at the top level
- /// (i.e., the first entry on the pipeline).
- /// This test parses a pipeline named 'another-pipeline', whose only elements
- /// may be the test-transform pass or the analysis utilities
- TEST_F(ModuleCallbacksTest, ParseTopLevelPipeline) {
- PB.registerParseTopLevelPipelineCallback([this](
- ModulePassManager &MPM, ArrayRef<PassBuilder::PipelineElement> Pipeline,
- bool VerifyEachPass, bool DebugLogging) {
- auto &FirstName = Pipeline.front().Name;
- auto &InnerPipeline = Pipeline.front().InnerPipeline;
- if (FirstName == "another-pipeline") {
- for (auto &E : InnerPipeline) {
- if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", E.Name, PM))
- continue;
- if (E.Name == "test-transform") {
- PM.addPass(PassHandle.getPass());
- continue;
- }
- return false;
- }
- }
- return true;
- });
- EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
- EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
- .WillOnce(Invoke(getAnalysisResult));
- EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));
- StringRef PipelineText =
- "another-pipeline(test-transform,invalidate<test-analysis>)";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
- << "Pipeline was: " << PipelineText;
- PM.run(*M, AM);
- /// Test the negative case
- PipelineText = "another-pipeline(instcombine)";
- ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Failed())
- << "Pipeline was: " << PipelineText;
- }
- } // end anonymous namespace
|