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-exception 6 // 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 26 using namespace llvm; 27 28 namespace { 29 using testing::AnyNumber; 30 using testing::DoAll; 31 using testing::Not; 32 using testing::Return; 33 using testing::WithArgs; 34 using testing::_; 35 36 /// A CRTP base for analysis mock handles 37 /// 38 /// This class reconciles mocking with the value semantics implementation of the 39 /// AnalysisManager. Analysis mock handles should derive from this class and 40 /// call \c setDefault() in their constroctur for wiring up the defaults defined 41 /// by this base with their mock run() and invalidate() implementations. 42 template <typename DerivedT, typename IRUnitT, 43 typename AnalysisManagerT = AnalysisManager<IRUnitT>, 44 typename... ExtraArgTs> 45 class MockAnalysisHandleBase { 46 public: 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 86 protected: 87 // FIXME: MSVC seems unable to handle a lambda argument to Invoke from within 88 // 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 default 97 /// mock actions. (We can't do this in our constructor because this has to 98 /// 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 handles 109 /// 110 /// This class reconciles mocking with the value semantics implementation of the 111 /// PassManager. Pass mock handles should derive from this class and 112 /// call \c setDefault() in their constroctur for wiring up the defaults defined 113 /// by this base with their mock run() and invalidate() implementations. 114 template <typename DerivedT, typename IRUnitT, typename AnalysisManagerT, 115 typename... ExtraArgTs> 116 AnalysisKey MockAnalysisHandleBase<DerivedT, IRUnitT, AnalysisManagerT, 117 ExtraArgTs...>::Analysis::Key; 118 119 template <typename DerivedT, typename IRUnitT, 120 typename AnalysisManagerT = AnalysisManager<IRUnitT>, 121 typename... ExtraArgTs> 122 class MockPassHandleBase { 123 public: 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 145 protected: 146 /// Derived classes should call this in their constructor to set up default 147 /// mock actions. (We can't do this in our constructor because this has to 148 /// 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 respective 158 /// IRUnit type. 159 template <typename IRUnitT> struct MockPassHandle; 160 template <> 161 struct 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 175 template <> 176 struct 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 191 template <> 192 struct MockPassHandle<Function> 193 : MockPassHandleBase<MockPassHandle<Function>, Function> { 194 MOCK_METHOD2(run, PreservedAnalyses(Function &, FunctionAnalysisManager &)); 195 196 MockPassHandle() { setDefaults(); } 197 }; 198 199 template <> 200 struct 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 216 template <> 217 struct 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 interfaces 226 /// for the respective IRUnit type. 227 template <typename IRUnitT> struct MockAnalysisHandle; 228 template <> 229 struct 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 243 template <> 244 struct 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 254 template <> 255 struct 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 268 template <> 269 struct 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 279 static 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 and 285 /// for IRUnit pointer wrapper into llvm::Any (wrapped by PassInstrumentation). 286 template <typename IRUnitT> std::string getName(const IRUnitT &IR) { 287 return std::string(IR.getName()); 288 } 289 290 template <> std::string getName(const StringRef &name) { 291 return std::string(name); 292 } 293 294 template <> 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 name 309 /// 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. This 311 /// matcher supports any type exposing a getName() method of this form whose 312 /// return value is compatible with an std::ostream. For StringRef, this uses 313 /// 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. 320 MATCHER_P(HasName, Name, "") { 321 *result_listener << "has name '" << getName(arg) << "'"; 322 return Name == getName(arg); 323 } 324 325 MATCHER_P(HasNameRegex, Name, "") { 326 *result_listener << "has name '" << getName(arg) << "'"; 327 llvm::Regex r(Name); 328 return r.match(getName(arg)); 329 } 330 331 struct 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 unimportant 377 // parts of a pipeline that we do not care about (e.g. various passes added 378 // by default by PassBuilder - Verifier pass etc). 379 // Make sure to avoid ignoring Mock passes/analysis, we definitely want 380 // 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 402 template <typename IRUnitT> 403 using ExtraMockPassHandle = 404 std::conditional_t<std::is_same_v<IRUnitT, Loop>, MockPassHandle<LoopNest>, 405 MockPassHandle<IRUnitT>>; 406 407 template <typename PassManagerT> class PassBuilderCallbacksTest; 408 409 /// This test fixture is shared between all the actual tests below and 410 /// takes care of setting up appropriate defaults. 411 /// 412 /// The template specialization serves to extract the IRUnit and AM types from 413 /// the given PassManagerT. 414 template <typename TestIRUnitT, typename... ExtraPassArgTs, 415 typename... ExtraAnalysisArgTs> 416 class PassBuilderCallbacksTest<PassManager< 417 TestIRUnitT, AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>, 418 ExtraPassArgTs...>> : public testing::Test { 419 protected: 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 AnalyisManager 475 /// object. When called, the callee gets to register its own analyses with 476 /// this PassBuilder instance. 477 PB.registerAnalysisRegistrationCallback([this](AnalysisManagerT &AM) { 478 // Register our mock analysis 479 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 these 485 /// callbacks for each encountered pass name that it does not know. This 486 /// includes both simple pass names as well as names of sub-pipelines. In 487 /// 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 as 492 /// require<test-analysis> and invalidate<test-analysis> for our 493 /// analysis mock handle 494 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", Name, PM)) 495 return true; 496 497 /// Parse the name of our pass mock handle 498 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 proxies 508 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 516 using ModuleCallbacksTest = PassBuilderCallbacksTest<ModulePassManager>; 517 using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCCPassManager>; 518 using FunctionCallbacksTest = PassBuilderCallbacksTest<FunctionPassManager>; 519 using 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. 524 TEST_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 536 TEST_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 order 546 // 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 to 568 // 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 581 TEST_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 are 588 // 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 first 615 // because the its argument contains 'PassManager' (for example: 616 // ModuleToFunctionPassAdaptor{{.*}}PassManager{{.*}}). Check 617 // `runBeforeNonSkippedPass` and `runAfterPass` to show that they are not 618 // skipped. 619 // 620 // Pass managers are not ignored. 621 // 5 = (1) ModulePassManager + (2) FunctionPassMangers + (1) LoopPassManager + 622 // (1) CGSCCPassManager 623 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 of 644 // `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 testing 670 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 697 TEST_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 707 TEST_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 order 717 // 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 to 739 // 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 756 TEST_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/afterAnalysis 776 // 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 802 TEST_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 814 TEST_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 order 827 // 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 to 867 // 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 879 TEST_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 order 892 // 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 927 TEST_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 order 944 // 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 997 TEST_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/afterAnalysis 1030 // 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 1064 TEST_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 1075 TEST_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 order 1087 // 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 to 1114 // 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 1126 TEST_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 order 1139 // 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 1174 TEST_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/afterAnalysis 1196 // 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 analysis 1220 /// for all IRUnits. 1221 /// 1222 /// We first require<>, then invalidate<> it, expecting the analysis to be run 1223 /// once and subsequently invalidated. 1224 TEST_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 1234 TEST_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 1244 TEST_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 1254 TEST_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 pipeline 1268 /// from PassBuilder if it encounters an unknown pipeline entry at the top level 1269 /// (i.e., the first entry on the pipeline). 1270 /// This test parses a pipeline named 'another-pipeline', whose only elements 1271 /// may be the test-transform pass or the analysis utilities 1272 TEST_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 case 1306 PipelineText = "another-pipeline(instcombine)"; 1307 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Failed()) 1308 << "Pipeline was: " << PipelineText; 1309 } 1310 } // end anonymous namespace 1311