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