brintos

brintos / llvm-project-archived public Read only

0
0
Text · 50.0 KiB · 9aad6e3 Raw
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