1311 lines · cpp
1//===- unittests/IR/PassBuilderCallbacksTest.cpp - PB Callback Tests --===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Testing/Support/Error.h"10#include <functional>11#include <gmock/gmock.h>12#include <gtest/gtest.h>13#include <llvm/ADT/Any.h>14#include <llvm/Analysis/CGSCCPassManager.h>15#include <llvm/Analysis/LoopAnalysisManager.h>16#include <llvm/AsmParser/Parser.h>17#include <llvm/IR/LLVMContext.h>18#include <llvm/IR/Module.h>19#include <llvm/IR/PassInstrumentation.h>20#include <llvm/IR/PassManager.h>21#include <llvm/Passes/PassBuilder.h>22#include <llvm/Support/Regex.h>23#include <llvm/Support/SourceMgr.h>24#include <llvm/Transforms/Scalar/LoopPassManager.h>25 26using namespace llvm;27 28namespace {29using testing::AnyNumber;30using testing::DoAll;31using testing::Not;32using testing::Return;33using testing::WithArgs;34using testing::_;35 36/// A CRTP base for analysis mock handles37///38/// This class reconciles mocking with the value semantics implementation of the39/// AnalysisManager. Analysis mock handles should derive from this class and40/// call \c setDefault() in their constroctur for wiring up the defaults defined41/// by this base with their mock run() and invalidate() implementations.42template <typename DerivedT, typename IRUnitT,43 typename AnalysisManagerT = AnalysisManager<IRUnitT>,44 typename... ExtraArgTs>45class MockAnalysisHandleBase {46public:47 class Analysis : public AnalysisInfoMixin<Analysis> {48 friend AnalysisInfoMixin<Analysis>;49 friend MockAnalysisHandleBase;50 static AnalysisKey Key;51 52 DerivedT *Handle;53 54 Analysis(DerivedT &Handle) : Handle(&Handle) {55 static_assert(std::is_base_of<MockAnalysisHandleBase, DerivedT>::value,56 "Must pass the derived type to this template!");57 }58 59 public:60 class Result {61 friend MockAnalysisHandleBase;62 63 DerivedT *Handle;64 65 Result(DerivedT &Handle) : Handle(&Handle) {}66 67 public:68 // Forward invalidation events to the mock handle.69 bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,70 typename AnalysisManagerT::Invalidator &Inv) {71 return Handle->invalidate(IR, PA, Inv);72 }73 };74 75 Result run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs) {76 return Handle->run(IR, AM, ExtraArgs...);77 }78 };79 80 Analysis getAnalysis() { return Analysis(static_cast<DerivedT &>(*this)); }81 typename Analysis::Result getResult() {82 return typename Analysis::Result(static_cast<DerivedT &>(*this));83 }84 static StringRef getName() { return llvm::getTypeName<DerivedT>(); }85 86protected:87 // FIXME: MSVC seems unable to handle a lambda argument to Invoke from within88 // the template, so we use a boring static function.89 static bool invalidateCallback(IRUnitT &IR, const PreservedAnalyses &PA,90 typename AnalysisManagerT::Invalidator &Inv) {91 auto PAC = PA.template getChecker<Analysis>();92 return !PAC.preserved() &&93 !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>();94 }95 96 /// Derived classes should call this in their constructor to set up default97 /// mock actions. (We can't do this in our constructor because this has to98 /// run after the DerivedT is constructed.)99 void setDefaults() {100 ON_CALL(static_cast<DerivedT &>(*this),101 run(_, _, testing::Matcher<ExtraArgTs>(_)...))102 .WillByDefault(Return(this->getResult()));103 ON_CALL(static_cast<DerivedT &>(*this), invalidate(_, _, _))104 .WillByDefault(&invalidateCallback);105 }106};107 108/// A CRTP base for pass mock handles109///110/// This class reconciles mocking with the value semantics implementation of the111/// PassManager. Pass mock handles should derive from this class and112/// call \c setDefault() in their constroctur for wiring up the defaults defined113/// by this base with their mock run() and invalidate() implementations.114template <typename DerivedT, typename IRUnitT, typename AnalysisManagerT,115 typename... ExtraArgTs>116AnalysisKey MockAnalysisHandleBase<DerivedT, IRUnitT, AnalysisManagerT,117 ExtraArgTs...>::Analysis::Key;118 119template <typename DerivedT, typename IRUnitT,120 typename AnalysisManagerT = AnalysisManager<IRUnitT>,121 typename... ExtraArgTs>122class MockPassHandleBase {123public:124 class Pass : public PassInfoMixin<Pass> {125 friend MockPassHandleBase;126 127 DerivedT *Handle;128 129 Pass(DerivedT &Handle) : Handle(&Handle) {130 static_assert(std::is_base_of<MockPassHandleBase, DerivedT>::value,131 "Must pass the derived type to this template!");132 }133 134 public:135 PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,136 ExtraArgTs... ExtraArgs) {137 return Handle->run(IR, AM, ExtraArgs...);138 }139 };140 141 static StringRef getName() { return llvm::getTypeName<DerivedT>(); }142 143 Pass getPass() { return Pass(static_cast<DerivedT &>(*this)); }144 145protected:146 /// Derived classes should call this in their constructor to set up default147 /// mock actions. (We can't do this in our constructor because this has to148 /// run after the DerivedT is constructed.)149 void setDefaults() {150 ON_CALL(static_cast<DerivedT &>(*this),151 run(_, _, testing::Matcher<ExtraArgTs>(_)...))152 .WillByDefault(Return(PreservedAnalyses::all()));153 }154};155 156/// Mock handles for passes for the IRUnits Module, CGSCC, Function, Loop.157/// These handles define the appropriate run() mock interface for the respective158/// IRUnit type.159template <typename IRUnitT> struct MockPassHandle;160template <>161struct MockPassHandle<Loop>162 : MockPassHandleBase<MockPassHandle<Loop>, Loop, LoopAnalysisManager,163 LoopStandardAnalysisResults &, LPMUpdater &> {164 MOCK_METHOD4(run,165 PreservedAnalyses(Loop &, LoopAnalysisManager &,166 LoopStandardAnalysisResults &, LPMUpdater &));167 static void invalidateLoop(Loop &L, LoopAnalysisManager &,168 LoopStandardAnalysisResults &,169 LPMUpdater &Updater) {170 Updater.markLoopAsDeleted(L, L.getName());171 }172 MockPassHandle() { setDefaults(); }173};174 175template <>176struct MockPassHandle<LoopNest>177 : MockPassHandleBase<MockPassHandle<LoopNest>, LoopNest,178 LoopAnalysisManager, LoopStandardAnalysisResults &,179 LPMUpdater &> {180 MOCK_METHOD4(run,181 PreservedAnalyses(LoopNest &, LoopAnalysisManager &,182 LoopStandardAnalysisResults &, LPMUpdater &));183 static void invalidateLoopNest(LoopNest &L, LoopAnalysisManager &,184 LoopStandardAnalysisResults &,185 LPMUpdater &Updater) {186 Updater.markLoopAsDeleted(L.getOutermostLoop(), L.getName());187 }188 MockPassHandle() { setDefaults(); }189};190 191template <>192struct MockPassHandle<Function>193 : MockPassHandleBase<MockPassHandle<Function>, Function> {194 MOCK_METHOD2(run, PreservedAnalyses(Function &, FunctionAnalysisManager &));195 196 MockPassHandle() { setDefaults(); }197};198 199template <>200struct MockPassHandle<LazyCallGraph::SCC>201 : MockPassHandleBase<MockPassHandle<LazyCallGraph::SCC>, LazyCallGraph::SCC,202 CGSCCAnalysisManager, LazyCallGraph &,203 CGSCCUpdateResult &> {204 MOCK_METHOD4(run,205 PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &,206 LazyCallGraph &G, CGSCCUpdateResult &UR));207 208 static void invalidateSCC(LazyCallGraph::SCC &C, CGSCCAnalysisManager &,209 LazyCallGraph &, CGSCCUpdateResult &UR) {210 UR.InvalidatedSCCs.insert(&C);211 }212 213 MockPassHandle() { setDefaults(); }214};215 216template <>217struct MockPassHandle<Module>218 : MockPassHandleBase<MockPassHandle<Module>, Module> {219 MOCK_METHOD2(run, PreservedAnalyses(Module &, ModuleAnalysisManager &));220 221 MockPassHandle() { setDefaults(); }222};223 224/// Mock handles for analyses for the IRUnits Module, CGSCC, Function, Loop.225/// These handles define the appropriate run() and invalidate() mock interfaces226/// for the respective IRUnit type.227template <typename IRUnitT> struct MockAnalysisHandle;228template <>229struct MockAnalysisHandle<Loop>230 : MockAnalysisHandleBase<MockAnalysisHandle<Loop>, Loop,231 LoopAnalysisManager,232 LoopStandardAnalysisResults &> {233 234 MOCK_METHOD3_T(run, typename Analysis::Result(Loop &, LoopAnalysisManager &,235 LoopStandardAnalysisResults &));236 237 MOCK_METHOD3_T(invalidate, bool(Loop &, const PreservedAnalyses &,238 LoopAnalysisManager::Invalidator &));239 240 MockAnalysisHandle() { this->setDefaults(); }241};242 243template <>244struct MockAnalysisHandle<Function>245 : MockAnalysisHandleBase<MockAnalysisHandle<Function>, Function> {246 MOCK_METHOD2(run, Analysis::Result(Function &, FunctionAnalysisManager &));247 248 MOCK_METHOD3(invalidate, bool(Function &, const PreservedAnalyses &,249 FunctionAnalysisManager::Invalidator &));250 251 MockAnalysisHandle() { setDefaults(); }252};253 254template <>255struct MockAnalysisHandle<LazyCallGraph::SCC>256 : MockAnalysisHandleBase<MockAnalysisHandle<LazyCallGraph::SCC>,257 LazyCallGraph::SCC, CGSCCAnalysisManager,258 LazyCallGraph &> {259 MOCK_METHOD3(run, Analysis::Result(LazyCallGraph::SCC &,260 CGSCCAnalysisManager &, LazyCallGraph &));261 262 MOCK_METHOD3(invalidate, bool(LazyCallGraph::SCC &, const PreservedAnalyses &,263 CGSCCAnalysisManager::Invalidator &));264 265 MockAnalysisHandle() { setDefaults(); }266};267 268template <>269struct MockAnalysisHandle<Module>270 : MockAnalysisHandleBase<MockAnalysisHandle<Module>, Module> {271 MOCK_METHOD2(run, Analysis::Result(Module &, ModuleAnalysisManager &));272 273 MOCK_METHOD3(invalidate, bool(Module &, const PreservedAnalyses &,274 ModuleAnalysisManager::Invalidator &));275 276 MockAnalysisHandle() { setDefaults(); }277};278 279static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {280 SMDiagnostic Err;281 return parseAssemblyString(IR, Err, C);282}283 284/// Helper for HasName matcher that returns getName both for IRUnit and285/// for IRUnit pointer wrapper into llvm::Any (wrapped by PassInstrumentation).286template <typename IRUnitT> std::string getName(const IRUnitT &IR) {287 return std::string(IR.getName());288}289 290template <> std::string getName(const StringRef &name) {291 return std::string(name);292}293 294template <> std::string getName(const Any &WrappedIR) {295 if (const auto *const *M = llvm::any_cast<const Module *>(&WrappedIR))296 return (*M)->getName().str();297 if (const auto *const *F = llvm::any_cast<const Function *>(&WrappedIR))298 return (*F)->getName().str();299 if (const auto *const *L = llvm::any_cast<const Loop *>(&WrappedIR))300 return (*L)->getName().str();301 if (const auto *const *C =302 llvm::any_cast<const LazyCallGraph::SCC *>(&WrappedIR))303 return (*C)->getName();304 return "<UNKNOWN>";305}306/// Define a custom matcher for objects which support a 'getName' method.307///308/// LLVM often has IR objects or analysis objects which expose a name309/// and in tests it is convenient to match these by name for readability.310/// Usually, this name is either a StringRef or a plain std::string. This311/// matcher supports any type exposing a getName() method of this form whose312/// return value is compatible with an std::ostream. For StringRef, this uses313/// the shift operator defined above.314///315/// It should be used as:316///317/// HasName("my_function")318///319/// No namespace or other qualification is required.320MATCHER_P(HasName, Name, "") {321 *result_listener << "has name '" << getName(arg) << "'";322 return Name == getName(arg);323}324 325MATCHER_P(HasNameRegex, Name, "") {326 *result_listener << "has name '" << getName(arg) << "'";327 llvm::Regex r(Name);328 return r.match(getName(arg));329}330 331struct MockPassInstrumentationCallbacks {332 PassInstrumentationCallbacks Callbacks;333 334 MockPassInstrumentationCallbacks() {335 ON_CALL(*this, runBeforePass(_, _)).WillByDefault(Return(true));336 }337 MOCK_METHOD2(runBeforePass, bool(StringRef PassID, llvm::Any));338 MOCK_METHOD2(runBeforeSkippedPass, void(StringRef PassID, llvm::Any));339 MOCK_METHOD2(runBeforeNonSkippedPass, void(StringRef PassID, llvm::Any));340 MOCK_METHOD3(runAfterPass,341 void(StringRef PassID, llvm::Any, const PreservedAnalyses &PA));342 MOCK_METHOD2(runAfterPassInvalidated,343 void(StringRef PassID, const PreservedAnalyses &PA));344 MOCK_METHOD2(runBeforeAnalysis, void(StringRef PassID, llvm::Any));345 MOCK_METHOD2(runAfterAnalysis, void(StringRef PassID, llvm::Any));346 347 void registerPassInstrumentation() {348 Callbacks.registerShouldRunOptionalPassCallback(349 [this](StringRef P, llvm::Any IR) {350 return this->runBeforePass(P, IR);351 });352 Callbacks.registerBeforeSkippedPassCallback(353 [this](StringRef P, llvm::Any IR) {354 this->runBeforeSkippedPass(P, IR);355 });356 Callbacks.registerBeforeNonSkippedPassCallback(357 [this](StringRef P, llvm::Any IR) {358 this->runBeforeNonSkippedPass(P, IR);359 });360 Callbacks.registerAfterPassCallback(361 [this](StringRef P, llvm::Any IR, const PreservedAnalyses &PA) {362 this->runAfterPass(P, IR, PA);363 });364 Callbacks.registerAfterPassInvalidatedCallback(365 [this](StringRef P, const PreservedAnalyses &PA) {366 this->runAfterPassInvalidated(P, PA);367 });368 Callbacks.registerBeforeAnalysisCallback([this](StringRef P, llvm::Any IR) {369 return this->runBeforeAnalysis(P, IR);370 });371 Callbacks.registerAfterAnalysisCallback(372 [this](StringRef P, llvm::Any IR) { this->runAfterAnalysis(P, IR); });373 }374 375 void ignoreNonMockPassInstrumentation(StringRef IRName) {376 // Generic EXPECT_CALLs are needed to match instrumentation on unimportant377 // parts of a pipeline that we do not care about (e.g. various passes added378 // by default by PassBuilder - Verifier pass etc).379 // Make sure to avoid ignoring Mock passes/analysis, we definitely want380 // to check these explicitly.381 EXPECT_CALL(*this,382 runBeforePass(Not(HasNameRegex("Mock")), HasName(IRName)))383 .Times(AnyNumber());384 EXPECT_CALL(385 *this, runBeforeSkippedPass(Not(HasNameRegex("Mock")), HasName(IRName)))386 .Times(AnyNumber());387 EXPECT_CALL(*this, runBeforeNonSkippedPass(Not(HasNameRegex("Mock")),388 HasName(IRName)))389 .Times(AnyNumber());390 EXPECT_CALL(*this,391 runAfterPass(Not(HasNameRegex("Mock")), HasName(IRName), _))392 .Times(AnyNumber());393 EXPECT_CALL(*this,394 runBeforeAnalysis(Not(HasNameRegex("Mock")), HasName(IRName)))395 .Times(AnyNumber());396 EXPECT_CALL(*this,397 runAfterAnalysis(Not(HasNameRegex("Mock")), HasName(IRName)))398 .Times(AnyNumber());399 }400};401 402template <typename IRUnitT>403using ExtraMockPassHandle =404 std::conditional_t<std::is_same_v<IRUnitT, Loop>, MockPassHandle<LoopNest>,405 MockPassHandle<IRUnitT>>;406 407template <typename PassManagerT> class PassBuilderCallbacksTest;408 409/// This test fixture is shared between all the actual tests below and410/// takes care of setting up appropriate defaults.411///412/// The template specialization serves to extract the IRUnit and AM types from413/// the given PassManagerT.414template <typename TestIRUnitT, typename... ExtraPassArgTs,415 typename... ExtraAnalysisArgTs>416class PassBuilderCallbacksTest<PassManager<417 TestIRUnitT, AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>,418 ExtraPassArgTs...>> : public testing::Test {419protected:420 using IRUnitT = TestIRUnitT;421 using AnalysisManagerT = AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>;422 using PassManagerT =423 PassManager<TestIRUnitT, AnalysisManagerT, ExtraPassArgTs...>;424 using AnalysisT = typename MockAnalysisHandle<IRUnitT>::Analysis;425 426 LLVMContext Context;427 std::unique_ptr<Module> M;428 429 MockPassInstrumentationCallbacks CallbacksHandle;430 431 PassBuilder PB;432 ModulePassManager PM;433 LoopAnalysisManager LAM;434 FunctionAnalysisManager FAM;435 CGSCCAnalysisManager CGAM;436 ModuleAnalysisManager AM;437 438 MockPassHandle<IRUnitT> PassHandle;439 ExtraMockPassHandle<IRUnitT> ExtraPassHandle;440 441 MockAnalysisHandle<IRUnitT> AnalysisHandle;442 443 static PreservedAnalyses getAnalysisResult(IRUnitT &U, AnalysisManagerT &AM,444 ExtraAnalysisArgTs &&... Args) {445 (void)AM.template getResult<AnalysisT>(446 U, std::forward<ExtraAnalysisArgTs>(Args)...);447 return PreservedAnalyses::all();448 }449 450 PassBuilderCallbacksTest()451 : M(parseIR(Context,452 "declare void @bar()\n"453 "define void @foo(i32 %n) {\n"454 "entry:\n"455 " br label %loop\n"456 "loop:\n"457 " %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]\n"458 " %iv.next = add i32 %iv, 1\n"459 " tail call void @bar()\n"460 " %cmp = icmp eq i32 %iv, %n\n"461 " br i1 %cmp, label %exit, label %loop\n"462 "exit:\n"463 " ret void\n"464 "}\n")),465 CallbacksHandle(), PB(nullptr, PipelineTuningOptions(), std::nullopt,466 &CallbacksHandle.Callbacks),467 PM(), LAM(), FAM(), CGAM(), AM() {468 469 EXPECT_TRUE(&CallbacksHandle.Callbacks ==470 PB.getPassInstrumentationCallbacks());471 472 /// Register a callback for analysis registration.473 ///474 /// The callback is a function taking a reference to an AnalyisManager475 /// object. When called, the callee gets to register its own analyses with476 /// this PassBuilder instance.477 PB.registerAnalysisRegistrationCallback([this](AnalysisManagerT &AM) {478 // Register our mock analysis479 AM.registerPass([this] { return AnalysisHandle.getAnalysis(); });480 });481 482 /// Register a callback for pipeline parsing.483 ///484 /// During parsing of a textual pipeline, the PassBuilder will call these485 /// callbacks for each encountered pass name that it does not know. This486 /// includes both simple pass names as well as names of sub-pipelines. In487 /// the latter case, the InnerPipeline is not empty.488 PB.registerPipelineParsingCallback(489 [this](StringRef Name, PassManagerT &PM,490 ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {491 /// Handle parsing of the names of analysis utilities such as492 /// require<test-analysis> and invalidate<test-analysis> for our493 /// analysis mock handle494 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", Name, PM))495 return true;496 497 /// Parse the name of our pass mock handle498 if (Name == "test-transform") {499 PM.addPass(PassHandle.getPass());500 if (std::is_same<IRUnitT, Loop>::value)501 PM.addPass(ExtraPassHandle.getPass());502 return true;503 }504 return false;505 });506 507 /// Register builtin analyses and cross-register the analysis proxies508 PB.registerModuleAnalyses(AM);509 PB.registerCGSCCAnalyses(CGAM);510 PB.registerFunctionAnalyses(FAM);511 PB.registerLoopAnalyses(LAM);512 PB.crossRegisterProxies(LAM, FAM, CGAM, AM);513 }514};515 516using ModuleCallbacksTest = PassBuilderCallbacksTest<ModulePassManager>;517using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCCPassManager>;518using FunctionCallbacksTest = PassBuilderCallbacksTest<FunctionPassManager>;519using LoopCallbacksTest = PassBuilderCallbacksTest<LoopPassManager>;520 521/// Test parsing of the name of our mock pass for all IRUnits.522///523/// The pass should by default run our mock analysis and then preserve it.524TEST_F(ModuleCallbacksTest, Passes) {525 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));526 EXPECT_CALL(PassHandle, run(HasName("<string>"), _))527 .WillOnce(&getAnalysisResult);528 529 StringRef PipelineText = "test-transform";530 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())531 << "Pipeline was: " << PipelineText;532 533 PM.run(*M, AM);534}535 536TEST_F(ModuleCallbacksTest, InstrumentedPasses) {537 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));538 EXPECT_CALL(PassHandle, run(HasName("<string>"), _))539 .WillOnce(&getAnalysisResult);540 541 CallbacksHandle.registerPassInstrumentation();542 // Non-mock instrumentation not specifically mentioned below can be ignored.543 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");544 545 // PassInstrumentation calls should happen in-sequence, in the same order546 // as passes/analyses are scheduled.547 ::testing::Sequence PISequence;548 EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"),549 HasName("<string>")))550 .InSequence(PISequence);551 EXPECT_CALL(CallbacksHandle,552 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"),553 HasName("<string>")))554 .InSequence(PISequence);555 EXPECT_CALL(CallbacksHandle,556 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"),557 HasName("<string>")))558 .InSequence(PISequence);559 EXPECT_CALL(560 CallbacksHandle,561 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("<string>")))562 .InSequence(PISequence);563 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"),564 HasName("<string>"), _))565 .InSequence(PISequence);566 567 // No passes are skipped, so there should be no calls to568 // runBeforeSkippedPass().569 EXPECT_CALL(570 CallbacksHandle,571 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("<string>")))572 .Times(0);573 574 StringRef PipelineText = "test-transform";575 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())576 << "Pipeline was: " << PipelineText;577 578 PM.run(*M, AM);579}580 581TEST_F(ModuleCallbacksTest, InstrumentedSkippedPasses) {582 CallbacksHandle.registerPassInstrumentation();583 // Non-mock instrumentation run here can safely be ignored.584 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");585 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");586 587 // Skip all passes by returning false. Pass managers and adaptor passes are588 // also passes that observed by the callbacks.589 EXPECT_CALL(CallbacksHandle, runBeforePass(_, _))590 .WillRepeatedly(Return(false));591 592 EXPECT_CALL(CallbacksHandle,593 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), _))594 .Times(3);595 596 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)).Times(0);597 EXPECT_CALL(PassHandle, run(HasName("<string>"), _)).Times(0);598 599 // As the pass is skipped there is no nonskippedpass/afterPass,600 // beforeAnalysis/afterAnalysis as well.601 EXPECT_CALL(CallbacksHandle,602 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _))603 .Times(0);604 EXPECT_CALL(CallbacksHandle,605 runAfterPass(HasNameRegex("MockPassHandle"), _, _))606 .Times(0);607 EXPECT_CALL(CallbacksHandle,608 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))609 .Times(0);610 EXPECT_CALL(CallbacksHandle,611 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))612 .Times(0);613 614 // Order is important here. `Adaptor` expectations should be checked first615 // because the its argument contains 'PassManager' (for example:616 // ModuleToFunctionPassAdaptor{{.*}}PassManager{{.*}}). Check617 // `runBeforeNonSkippedPass` and `runAfterPass` to show that they are not618 // skipped.619 //620 // Pass managers are not ignored.621 // 5 = (1) ModulePassManager + (2) FunctionPassMangers + (1) LoopPassManager +622 // (1) CGSCCPassManager623 EXPECT_CALL(CallbacksHandle,624 runBeforeNonSkippedPass(HasNameRegex("PassManager"), _))625 .Times(5);626 EXPECT_CALL(627 CallbacksHandle,628 runBeforeNonSkippedPass(HasNameRegex("ModuleToFunctionPassAdaptor"), _))629 .Times(1);630 EXPECT_CALL(CallbacksHandle,631 runBeforeNonSkippedPass(632 HasNameRegex("ModuleToPostOrderCGSCCPassAdaptor"), _))633 .Times(1);634 EXPECT_CALL(635 CallbacksHandle,636 runBeforeNonSkippedPass(HasNameRegex("CGSCCToFunctionPassAdaptor"), _))637 .Times(1);638 EXPECT_CALL(639 CallbacksHandle,640 runBeforeNonSkippedPass(HasNameRegex("FunctionToLoopPassAdaptor"), _))641 .Times(1);642 643 // The `runAfterPass` checks are the same as these of644 // `runBeforeNonSkippedPass`.645 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("PassManager"), _, _))646 .Times(5);647 EXPECT_CALL(CallbacksHandle,648 runAfterPass(HasNameRegex("ModuleToFunctionPassAdaptor"), _, _))649 .Times(1);650 EXPECT_CALL(651 CallbacksHandle,652 runAfterPass(HasNameRegex("ModuleToPostOrderCGSCCPassAdaptor"), _, _))653 .Times(1);654 EXPECT_CALL(CallbacksHandle,655 runAfterPass(HasNameRegex("CGSCCToFunctionPassAdaptor"), _, _))656 .Times(1);657 EXPECT_CALL(CallbacksHandle,658 runAfterPass(HasNameRegex("FunctionToLoopPassAdaptor"), _, _))659 .Times(1);660 661 // Ignore analyses introduced by adaptor passes.662 EXPECT_CALL(CallbacksHandle,663 runBeforeAnalysis(Not(HasNameRegex("MockAnalysisHandle")), _))664 .Times(AnyNumber());665 EXPECT_CALL(CallbacksHandle,666 runAfterAnalysis(Not(HasNameRegex("MockAnalysisHandle")), _))667 .Times(AnyNumber());668 669 // Register Funtion and Loop version of "test-transform" for testing670 PB.registerPipelineParsingCallback(671 [](StringRef Name, FunctionPassManager &FPM,672 ArrayRef<PassBuilder::PipelineElement>) {673 if (Name == "test-transform") {674 FPM.addPass(MockPassHandle<Function>().getPass());675 return true;676 }677 return false;678 });679 PB.registerPipelineParsingCallback(680 [](StringRef Name, LoopPassManager &LPM,681 ArrayRef<PassBuilder::PipelineElement>) {682 if (Name == "test-transform") {683 LPM.addPass(MockPassHandle<Loop>().getPass());684 return true;685 }686 return false;687 });688 689 StringRef PipelineText = "test-transform,function(test-transform),cgscc("690 "function(loop(test-transform)))";691 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())692 << "Pipeline was: " << PipelineText;693 694 PM.run(*M, AM);695}696 697TEST_F(FunctionCallbacksTest, Passes) {698 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));699 EXPECT_CALL(PassHandle, run(HasName("foo"), _)).WillOnce(&getAnalysisResult);700 701 StringRef PipelineText = "test-transform";702 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())703 << "Pipeline was: " << PipelineText;704 PM.run(*M, AM);705}706 707TEST_F(FunctionCallbacksTest, InstrumentedPasses) {708 CallbacksHandle.registerPassInstrumentation();709 // Non-mock instrumentation not specifically mentioned below can be ignored.710 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");711 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");712 713 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));714 EXPECT_CALL(PassHandle, run(HasName("foo"), _)).WillOnce(&getAnalysisResult);715 716 // PassInstrumentation calls should happen in-sequence, in the same order717 // as passes/analyses are scheduled.718 ::testing::Sequence PISequence;719 EXPECT_CALL(CallbacksHandle,720 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))721 .InSequence(PISequence);722 EXPECT_CALL(723 CallbacksHandle,724 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo")))725 .InSequence(PISequence);726 EXPECT_CALL(727 CallbacksHandle,728 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))729 .InSequence(PISequence);730 EXPECT_CALL(731 CallbacksHandle,732 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))733 .InSequence(PISequence);734 EXPECT_CALL(CallbacksHandle,735 runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo"), _))736 .InSequence(PISequence);737 738 // No passes are skipped, so there should be no calls to739 // runBeforeSkippedPass().740 EXPECT_CALL(741 CallbacksHandle,742 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo")))743 .Times(0);744 745 // Our mock pass does not invalidate IR.746 EXPECT_CALL(CallbacksHandle,747 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))748 .Times(0);749 750 StringRef PipelineText = "test-transform";751 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())752 << "Pipeline was: " << PipelineText;753 PM.run(*M, AM);754}755 756TEST_F(FunctionCallbacksTest, InstrumentedSkippedPasses) {757 CallbacksHandle.registerPassInstrumentation();758 // Non-mock instrumentation run here can safely be ignored.759 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");760 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");761 762 // Skip the pass by returning false.763 EXPECT_CALL(CallbacksHandle,764 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))765 .WillOnce(Return(false));766 767 EXPECT_CALL(768 CallbacksHandle,769 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo")))770 .Times(1);771 772 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)).Times(0);773 EXPECT_CALL(PassHandle, run(HasName("foo"), _)).Times(0);774 775 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis776 // as well.777 EXPECT_CALL(CallbacksHandle,778 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _))779 .Times(0);780 EXPECT_CALL(CallbacksHandle,781 runAfterPass(HasNameRegex("MockPassHandle"), _, _))782 .Times(0);783 EXPECT_CALL(CallbacksHandle,784 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))785 .Times(0);786 EXPECT_CALL(CallbacksHandle,787 runAfterPass(HasNameRegex("MockPassHandle"), _, _))788 .Times(0);789 EXPECT_CALL(CallbacksHandle,790 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))791 .Times(0);792 EXPECT_CALL(CallbacksHandle,793 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))794 .Times(0);795 796 StringRef PipelineText = "test-transform";797 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())798 << "Pipeline was: " << PipelineText;799 PM.run(*M, AM);800}801 802TEST_F(LoopCallbacksTest, Passes) {803 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));804 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))805 .WillOnce(WithArgs<0, 1, 2>(&getAnalysisResult));806 EXPECT_CALL(ExtraPassHandle, run(HasName("loop"), _, _, _));807 808 StringRef PipelineText = "test-transform";809 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())810 << "Pipeline was: " << PipelineText;811 PM.run(*M, AM);812}813 814TEST_F(LoopCallbacksTest, InstrumentedPasses) {815 CallbacksHandle.registerPassInstrumentation();816 // Non-mock instrumentation not specifically mentioned below can be ignored.817 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");818 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");819 CallbacksHandle.ignoreNonMockPassInstrumentation("loop");820 821 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));822 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))823 .WillOnce(WithArgs<0, 1, 2>(&getAnalysisResult));824 EXPECT_CALL(ExtraPassHandle, run(HasName("loop"), _, _, _));825 826 // PassInstrumentation calls should happen in-sequence, in the same order827 // as passes/analyses are scheduled.828 ::testing::Sequence PISequence;829 EXPECT_CALL(CallbacksHandle,830 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))831 .InSequence(PISequence);832 EXPECT_CALL(833 CallbacksHandle,834 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop")))835 .InSequence(PISequence);836 EXPECT_CALL(837 CallbacksHandle,838 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))839 .InSequence(PISequence);840 EXPECT_CALL(841 CallbacksHandle,842 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))843 .InSequence(PISequence);844 EXPECT_CALL(CallbacksHandle,845 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"), _))846 .InSequence(PISequence);847 848 EXPECT_CALL(CallbacksHandle,849 runBeforePass(HasNameRegex("MockPassHandle<.*LoopNest>"),850 HasName("loop")))851 .InSequence(PISequence);852 EXPECT_CALL(CallbacksHandle,853 runBeforeNonSkippedPass(854 HasNameRegex("MockPassHandle<.*LoopNest>"), HasName("loop")))855 .InSequence(PISequence);856 EXPECT_CALL(CallbacksHandle,857 runAfterPass(HasNameRegex("MockPassHandle<.*LoopNest>"),858 HasName("loop"), _))859 .InSequence(PISequence);860 861 // Our mock pass does not invalidate IR.862 EXPECT_CALL(CallbacksHandle,863 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))864 .Times(0);865 866 // No passes are skipped, so there should be no calls to867 // runBeforeSkippedPass().868 EXPECT_CALL(869 CallbacksHandle,870 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop")))871 .Times(0);872 873 StringRef PipelineText = "test-transform";874 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())875 << "Pipeline was: " << PipelineText;876 PM.run(*M, AM);877}878 879TEST_F(LoopCallbacksTest, InstrumentedInvalidatingPasses) {880 CallbacksHandle.registerPassInstrumentation();881 // Non-mock instrumentation not specifically mentioned below can be ignored.882 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");883 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");884 CallbacksHandle.ignoreNonMockPassInstrumentation("loop");885 886 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));887 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))888 .WillOnce(DoAll(WithArgs<0, 1, 2, 3>(&PassHandle.invalidateLoop),889 WithArgs<0, 1, 2>(&getAnalysisResult)));890 891 // PassInstrumentation calls should happen in-sequence, in the same order892 // as passes/analyses are scheduled.893 ::testing::Sequence PISequence;894 EXPECT_CALL(CallbacksHandle,895 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))896 .InSequence(PISequence);897 EXPECT_CALL(898 CallbacksHandle,899 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop")))900 .InSequence(PISequence);901 EXPECT_CALL(902 CallbacksHandle,903 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))904 .InSequence(PISequence);905 EXPECT_CALL(906 CallbacksHandle,907 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))908 .InSequence(PISequence);909 EXPECT_CALL(CallbacksHandle,910 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))911 .InSequence(PISequence);912 EXPECT_CALL(CallbacksHandle,913 runAfterPassInvalidated(HasNameRegex("^PassManager"), _))914 .InSequence(PISequence);915 916 // Our mock pass invalidates IR, thus normal runAfterPass is never called.917 EXPECT_CALL(CallbacksHandle,918 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"), _))919 .Times(0);920 921 StringRef PipelineText = "test-transform";922 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())923 << "Pipeline was: " << PipelineText;924 PM.run(*M, AM);925}926 927TEST_F(LoopCallbacksTest, InstrumentedInvalidatingLoopNestPasses) {928 CallbacksHandle.registerPassInstrumentation();929 // Non-mock instrumentation not specifically mentioned below can be ignored.930 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");931 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");932 CallbacksHandle.ignoreNonMockPassInstrumentation("loop");933 934 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));935 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))936 .WillOnce(WithArgs<0, 1, 2>(&getAnalysisResult));937 EXPECT_CALL(ExtraPassHandle, run(HasName("loop"), _, _, _))938 .WillOnce(DoAll(&ExtraPassHandle.invalidateLoopNest,939 [&](LoopNest &, LoopAnalysisManager &,940 LoopStandardAnalysisResults &,941 LPMUpdater &) { return PreservedAnalyses::all(); }));942 943 // PassInstrumentation calls should happen in-sequence, in the same order944 // as passes/analyses are scheduled.945 ::testing::Sequence PISequence;946 EXPECT_CALL(CallbacksHandle,947 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))948 .InSequence(PISequence);949 EXPECT_CALL(950 CallbacksHandle,951 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop")))952 .InSequence(PISequence);953 EXPECT_CALL(954 CallbacksHandle,955 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))956 .InSequence(PISequence);957 EXPECT_CALL(958 CallbacksHandle,959 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))960 .InSequence(PISequence);961 EXPECT_CALL(CallbacksHandle,962 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"), _))963 .InSequence(PISequence);964 965 EXPECT_CALL(CallbacksHandle,966 runBeforePass(HasNameRegex("MockPassHandle<.*LoopNest>"),967 HasName("loop")))968 .InSequence(PISequence);969 EXPECT_CALL(CallbacksHandle,970 runBeforeNonSkippedPass(971 HasNameRegex("MockPassHandle<.*LoopNest>"), HasName("loop")))972 .InSequence(PISequence);973 EXPECT_CALL(974 CallbacksHandle,975 runAfterPassInvalidated(HasNameRegex("MockPassHandle<.*LoopNest>"), _))976 .InSequence(PISequence);977 978 EXPECT_CALL(CallbacksHandle,979 runAfterPassInvalidated(HasNameRegex("^PassManager"), _))980 .InSequence(PISequence);981 982 // Our mock pass invalidates IR, thus normal runAfterPass is never called.983 EXPECT_CALL(CallbacksHandle, runAfterPassInvalidated(984 HasNameRegex("MockPassHandle<.*Loop>"), _))985 .Times(0);986 EXPECT_CALL(CallbacksHandle,987 runAfterPass(HasNameRegex("MockPassHandle<.*LoopNest>"),988 HasName("loop"), _))989 .Times(0);990 991 StringRef PipelineText = "test-transform";992 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())993 << "Pipeline was: " << PipelineText;994 PM.run(*M, AM);995}996 997TEST_F(LoopCallbacksTest, InstrumentedSkippedPasses) {998 CallbacksHandle.registerPassInstrumentation();999 // Non-mock instrumentation run here can safely be ignored.1000 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");1001 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");1002 CallbacksHandle.ignoreNonMockPassInstrumentation("loop");1003 1004 // Skip the pass by returning false.1005 EXPECT_CALL(1006 CallbacksHandle,1007 runBeforePass(HasNameRegex("MockPassHandle<.*Loop>"), HasName("loop")))1008 .WillOnce(Return(false));1009 1010 EXPECT_CALL(CallbacksHandle,1011 runBeforeSkippedPass(HasNameRegex("MockPassHandle<.*Loop>"),1012 HasName("loop")))1013 .Times(1);1014 1015 EXPECT_CALL(CallbacksHandle,1016 runBeforePass(HasNameRegex("MockPassHandle<.*LoopNest>"),1017 HasName("loop")))1018 .WillOnce(Return(false));1019 1020 EXPECT_CALL(CallbacksHandle,1021 runBeforeSkippedPass(HasNameRegex("MockPassHandle<.*LoopNest>"),1022 HasName("loop")))1023 .Times(1);1024 1025 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)).Times(0);1026 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)).Times(0);1027 EXPECT_CALL(ExtraPassHandle, run(HasName("loop"), _, _, _)).Times(0);1028 1029 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis1030 // as well.1031 EXPECT_CALL(CallbacksHandle, runBeforeNonSkippedPass(1032 HasNameRegex("MockPassHandle<.*Loop>"), _))1033 .Times(0);1034 EXPECT_CALL(CallbacksHandle,1035 runAfterPass(HasNameRegex("MockPassHandle<.*Loop>"), _, _))1036 .Times(0);1037 EXPECT_CALL(CallbacksHandle, runAfterPassInvalidated(1038 HasNameRegex("MockPassHandle<.*Loop>"), _))1039 .Times(0);1040 EXPECT_CALL(1041 CallbacksHandle,1042 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle<.*LoopNest>"), _))1043 .Times(0);1044 EXPECT_CALL(CallbacksHandle,1045 runAfterPass(HasNameRegex("MockPassHandle<.*LoopNest>"), _, _))1046 .Times(0);1047 EXPECT_CALL(1048 CallbacksHandle,1049 runAfterPassInvalidated(HasNameRegex("MockPassHandle<.*LoopNest>"), _))1050 .Times(0);1051 EXPECT_CALL(CallbacksHandle,1052 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))1053 .Times(0);1054 EXPECT_CALL(CallbacksHandle,1055 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))1056 .Times(0);1057 1058 StringRef PipelineText = "test-transform";1059 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())1060 << "Pipeline was: " << PipelineText;1061 PM.run(*M, AM);1062}1063 1064TEST_F(CGSCCCallbacksTest, Passes) {1065 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));1066 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))1067 .WillOnce(WithArgs<0, 1, 2>(&getAnalysisResult));1068 1069 StringRef PipelineText = "test-transform";1070 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())1071 << "Pipeline was: " << PipelineText;1072 PM.run(*M, AM);1073}1074 1075TEST_F(CGSCCCallbacksTest, InstrumentedPasses) {1076 CallbacksHandle.registerPassInstrumentation();1077 // Non-mock instrumentation not specifically mentioned below can be ignored.1078 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");1079 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");1080 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");1081 1082 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));1083 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))1084 .WillOnce(WithArgs<0, 1, 2>(&getAnalysisResult));1085 1086 // PassInstrumentation calls should happen in-sequence, in the same order1087 // as passes/analyses are scheduled.1088 ::testing::Sequence PISequence;1089 EXPECT_CALL(CallbacksHandle,1090 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))1091 .InSequence(PISequence);1092 EXPECT_CALL(1093 CallbacksHandle,1094 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))1095 .InSequence(PISequence);1096 EXPECT_CALL(1097 CallbacksHandle,1098 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))1099 .InSequence(PISequence);1100 EXPECT_CALL(1101 CallbacksHandle,1102 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))1103 .InSequence(PISequence);1104 EXPECT_CALL(CallbacksHandle,1105 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"), _))1106 .InSequence(PISequence);1107 1108 // Our mock pass does not invalidate IR.1109 EXPECT_CALL(CallbacksHandle,1110 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))1111 .Times(0);1112 1113 // No passes are skipped, so there should be no calls to1114 // runBeforeSkippedPass().1115 EXPECT_CALL(1116 CallbacksHandle,1117 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))1118 .Times(0);1119 1120 StringRef PipelineText = "test-transform";1121 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())1122 << "Pipeline was: " << PipelineText;1123 PM.run(*M, AM);1124}1125 1126TEST_F(CGSCCCallbacksTest, InstrumentedInvalidatingPasses) {1127 CallbacksHandle.registerPassInstrumentation();1128 // Non-mock instrumentation not specifically mentioned below can be ignored.1129 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");1130 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");1131 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");1132 1133 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));1134 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))1135 .WillOnce(DoAll(WithArgs<0, 1, 2, 3>(&PassHandle.invalidateSCC),1136 WithArgs<0, 1, 2>(&getAnalysisResult)));1137 1138 // PassInstrumentation calls should happen in-sequence, in the same order1139 // as passes/analyses are scheduled.1140 ::testing::Sequence PISequence;1141 EXPECT_CALL(CallbacksHandle,1142 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))1143 .InSequence(PISequence);1144 EXPECT_CALL(1145 CallbacksHandle,1146 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))1147 .InSequence(PISequence);1148 EXPECT_CALL(1149 CallbacksHandle,1150 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))1151 .InSequence(PISequence);1152 EXPECT_CALL(1153 CallbacksHandle,1154 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))1155 .InSequence(PISequence);1156 EXPECT_CALL(CallbacksHandle,1157 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))1158 .InSequence(PISequence);1159 EXPECT_CALL(CallbacksHandle,1160 runAfterPassInvalidated(HasNameRegex("^PassManager"), _))1161 .InSequence(PISequence);1162 1163 // Our mock pass does invalidate IR, thus normal runAfterPass is never called.1164 EXPECT_CALL(CallbacksHandle,1165 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"), _))1166 .Times(0);1167 1168 StringRef PipelineText = "test-transform";1169 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())1170 << "Pipeline was: " << PipelineText;1171 PM.run(*M, AM);1172}1173 1174TEST_F(CGSCCCallbacksTest, InstrumentedSkippedPasses) {1175 CallbacksHandle.registerPassInstrumentation();1176 // Non-mock instrumentation run here can safely be ignored.1177 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");1178 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");1179 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");1180 1181 // Skip the pass by returning false.1182 EXPECT_CALL(CallbacksHandle,1183 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))1184 .WillOnce(Return(false));1185 1186 EXPECT_CALL(1187 CallbacksHandle,1188 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))1189 .Times(1);1190 1191 // neither Analysis nor Pass are called.1192 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)).Times(0);1193 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)).Times(0);1194 1195 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis1196 // as well.1197 EXPECT_CALL(CallbacksHandle,1198 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _))1199 .Times(0);1200 EXPECT_CALL(CallbacksHandle,1201 runAfterPass(HasNameRegex("MockPassHandle"), _, _))1202 .Times(0);1203 EXPECT_CALL(CallbacksHandle,1204 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))1205 .Times(0);1206 EXPECT_CALL(CallbacksHandle,1207 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))1208 .Times(0);1209 EXPECT_CALL(CallbacksHandle,1210 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))1211 .Times(0);1212 1213 StringRef PipelineText = "test-transform";1214 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())1215 << "Pipeline was: " << PipelineText;1216 PM.run(*M, AM);1217}1218 1219/// Test parsing of the names of analysis utilities for our mock analysis1220/// for all IRUnits.1221///1222/// We first require<>, then invalidate<> it, expecting the analysis to be run1223/// once and subsequently invalidated.1224TEST_F(ModuleCallbacksTest, AnalysisUtilities) {1225 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));1226 EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));1227 1228 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";1229 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())1230 << "Pipeline was: " << PipelineText;1231 PM.run(*M, AM);1232}1233 1234TEST_F(CGSCCCallbacksTest, PassUtilities) {1235 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));1236 EXPECT_CALL(AnalysisHandle, invalidate(HasName("(foo)"), _, _));1237 1238 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";1239 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())1240 << "Pipeline was: " << PipelineText;1241 PM.run(*M, AM);1242}1243 1244TEST_F(FunctionCallbacksTest, AnalysisUtilities) {1245 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));1246 EXPECT_CALL(AnalysisHandle, invalidate(HasName("foo"), _, _));1247 1248 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";1249 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())1250 << "Pipeline was: " << PipelineText;1251 PM.run(*M, AM);1252}1253 1254TEST_F(LoopCallbacksTest, PassUtilities) {1255 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));1256 EXPECT_CALL(AnalysisHandle, invalidate(HasName("loop"), _, _));1257 1258 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";1259 1260 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())1261 << "Pipeline was: " << PipelineText;1262 PM.run(*M, AM);1263}1264 1265/// Test parsing of the top-level pipeline.1266///1267/// The ParseTopLevelPipeline callback takes over parsing of the entire pipeline1268/// from PassBuilder if it encounters an unknown pipeline entry at the top level1269/// (i.e., the first entry on the pipeline).1270/// This test parses a pipeline named 'another-pipeline', whose only elements1271/// may be the test-transform pass or the analysis utilities1272TEST_F(ModuleCallbacksTest, ParseTopLevelPipeline) {1273 PB.registerParseTopLevelPipelineCallback(1274 [this](ModulePassManager &MPM,1275 ArrayRef<PassBuilder::PipelineElement> Pipeline) {1276 auto &FirstName = Pipeline.front().Name;1277 auto &InnerPipeline = Pipeline.front().InnerPipeline;1278 if (FirstName == "another-pipeline") {1279 for (auto &E : InnerPipeline) {1280 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", E.Name,1281 PM))1282 continue;1283 1284 if (E.Name == "test-transform") {1285 PM.addPass(PassHandle.getPass());1286 continue;1287 }1288 return false;1289 }1290 }1291 return true;1292 });1293 1294 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));1295 EXPECT_CALL(PassHandle, run(HasName("<string>"), _))1296 .WillOnce(&getAnalysisResult);1297 EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));1298 1299 StringRef PipelineText =1300 "another-pipeline(test-transform,invalidate<test-analysis>)";1301 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())1302 << "Pipeline was: " << PipelineText;1303 PM.run(*M, AM);1304 1305 /// Test the negative case1306 PipelineText = "another-pipeline(instcombine)";1307 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Failed())1308 << "Pipeline was: " << PipelineText;1309}1310} // end anonymous namespace1311