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<Function> 179 : MockPassHandleBase<MockPassHandle<Function>, Function> { 180 MOCK_METHOD2(run, PreservedAnalyses(Function &, FunctionAnalysisManager &)); 181 182 MockPassHandle() { setDefaults(); } 183 }; 184 185 template <> 186 struct MockPassHandle<LazyCallGraph::SCC> 187 : MockPassHandleBase<MockPassHandle<LazyCallGraph::SCC>, LazyCallGraph::SCC, 188 CGSCCAnalysisManager, LazyCallGraph &, 189 CGSCCUpdateResult &> { 190 MOCK_METHOD4(run, 191 PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &, 192 LazyCallGraph &G, CGSCCUpdateResult &UR)); 193 194 static void invalidateSCC(LazyCallGraph::SCC &C, CGSCCAnalysisManager &, 195 LazyCallGraph &, CGSCCUpdateResult &UR) { 196 UR.InvalidatedSCCs.insert(&C); 197 } 198 199 MockPassHandle() { setDefaults(); } 200 }; 201 202 template <> 203 struct MockPassHandle<Module> 204 : MockPassHandleBase<MockPassHandle<Module>, Module> { 205 MOCK_METHOD2(run, PreservedAnalyses(Module &, ModuleAnalysisManager &)); 206 207 MockPassHandle() { setDefaults(); } 208 }; 209 210 /// Mock handles for analyses for the IRUnits Module, CGSCC, Function, Loop. 211 /// These handles define the appropriate run() and invalidate() mock interfaces 212 /// for the respective IRUnit type. 213 template <typename IRUnitT> struct MockAnalysisHandle; 214 template <> 215 struct MockAnalysisHandle<Loop> 216 : MockAnalysisHandleBase<MockAnalysisHandle<Loop>, Loop, 217 LoopAnalysisManager, 218 LoopStandardAnalysisResults &> { 219 220 MOCK_METHOD3_T(run, typename Analysis::Result(Loop &, LoopAnalysisManager &, 221 LoopStandardAnalysisResults &)); 222 223 MOCK_METHOD3_T(invalidate, bool(Loop &, const PreservedAnalyses &, 224 LoopAnalysisManager::Invalidator &)); 225 226 MockAnalysisHandle<Loop>() { this->setDefaults(); } 227 }; 228 229 template <> 230 struct MockAnalysisHandle<Function> 231 : MockAnalysisHandleBase<MockAnalysisHandle<Function>, Function> { 232 MOCK_METHOD2(run, Analysis::Result(Function &, FunctionAnalysisManager &)); 233 234 MOCK_METHOD3(invalidate, bool(Function &, const PreservedAnalyses &, 235 FunctionAnalysisManager::Invalidator &)); 236 237 MockAnalysisHandle<Function>() { setDefaults(); } 238 }; 239 240 template <> 241 struct MockAnalysisHandle<LazyCallGraph::SCC> 242 : MockAnalysisHandleBase<MockAnalysisHandle<LazyCallGraph::SCC>, 243 LazyCallGraph::SCC, CGSCCAnalysisManager, 244 LazyCallGraph &> { 245 MOCK_METHOD3(run, Analysis::Result(LazyCallGraph::SCC &, 246 CGSCCAnalysisManager &, LazyCallGraph &)); 247 248 MOCK_METHOD3(invalidate, bool(LazyCallGraph::SCC &, const PreservedAnalyses &, 249 CGSCCAnalysisManager::Invalidator &)); 250 251 MockAnalysisHandle<LazyCallGraph::SCC>() { setDefaults(); } 252 }; 253 254 template <> 255 struct MockAnalysisHandle<Module> 256 : MockAnalysisHandleBase<MockAnalysisHandle<Module>, Module> { 257 MOCK_METHOD2(run, Analysis::Result(Module &, ModuleAnalysisManager &)); 258 259 MOCK_METHOD3(invalidate, bool(Module &, const PreservedAnalyses &, 260 ModuleAnalysisManager::Invalidator &)); 261 262 MockAnalysisHandle<Module>() { setDefaults(); } 263 }; 264 265 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { 266 SMDiagnostic Err; 267 return parseAssemblyString(IR, Err, C); 268 } 269 270 /// Helper for HasName matcher that returns getName both for IRUnit and 271 /// for IRUnit pointer wrapper into llvm::Any (wrapped by PassInstrumentation). 272 template <typename IRUnitT> std::string getName(const IRUnitT &IR) { 273 return std::string(IR.getName()); 274 } 275 276 template <> std::string getName(const StringRef &name) { 277 return std::string(name); 278 } 279 280 template <> std::string getName(const llvm::Any &WrappedIR) { 281 if (any_isa<const Module *>(WrappedIR)) 282 return any_cast<const Module *>(WrappedIR)->getName().str(); 283 if (any_isa<const Function *>(WrappedIR)) 284 return any_cast<const Function *>(WrappedIR)->getName().str(); 285 if (any_isa<const Loop *>(WrappedIR)) 286 return any_cast<const Loop *>(WrappedIR)->getName().str(); 287 if (any_isa<const LazyCallGraph::SCC *>(WrappedIR)) 288 return any_cast<const LazyCallGraph::SCC *>(WrappedIR)->getName(); 289 return "<UNKNOWN>"; 290 } 291 /// Define a custom matcher for objects which support a 'getName' method. 292 /// 293 /// LLVM often has IR objects or analysis objects which expose a name 294 /// and in tests it is convenient to match these by name for readability. 295 /// Usually, this name is either a StringRef or a plain std::string. This 296 /// matcher supports any type exposing a getName() method of this form whose 297 /// return value is compatible with an std::ostream. For StringRef, this uses 298 /// the shift operator defined above. 299 /// 300 /// It should be used as: 301 /// 302 /// HasName("my_function") 303 /// 304 /// No namespace or other qualification is required. 305 MATCHER_P(HasName, Name, "") { 306 *result_listener << "has name '" << getName(arg) << "'"; 307 return Name == getName(arg); 308 } 309 310 MATCHER_P(HasNameRegex, Name, "") { 311 *result_listener << "has name '" << getName(arg) << "'"; 312 llvm::Regex r(Name); 313 return r.match(getName(arg)); 314 } 315 316 struct MockPassInstrumentationCallbacks { 317 PassInstrumentationCallbacks Callbacks; 318 319 MockPassInstrumentationCallbacks() { 320 ON_CALL(*this, runBeforePass(_, _)).WillByDefault(Return(true)); 321 } 322 MOCK_METHOD2(runBeforePass, bool(StringRef PassID, llvm::Any)); 323 MOCK_METHOD2(runBeforeSkippedPass, void(StringRef PassID, llvm::Any)); 324 MOCK_METHOD2(runBeforeNonSkippedPass, void(StringRef PassID, llvm::Any)); 325 MOCK_METHOD2(runAfterPass, void(StringRef PassID, llvm::Any)); 326 MOCK_METHOD1(runAfterPassInvalidated, void(StringRef PassID)); 327 MOCK_METHOD2(runBeforeAnalysis, void(StringRef PassID, llvm::Any)); 328 MOCK_METHOD2(runAfterAnalysis, void(StringRef PassID, llvm::Any)); 329 330 void registerPassInstrumentation() { 331 Callbacks.registerBeforePassCallback([this](StringRef P, llvm::Any IR) { 332 return this->runBeforePass(P, IR); 333 }); 334 Callbacks.registerBeforeSkippedPassCallback( 335 [this](StringRef P, llvm::Any IR) { 336 this->runBeforeSkippedPass(P, IR); 337 }); 338 Callbacks.registerBeforeNonSkippedPassCallback( 339 [this](StringRef P, llvm::Any IR) { 340 this->runBeforeNonSkippedPass(P, IR); 341 }); 342 Callbacks.registerAfterPassCallback( 343 [this](StringRef P, llvm::Any IR) { this->runAfterPass(P, IR); }); 344 Callbacks.registerAfterPassInvalidatedCallback( 345 [this](StringRef P) { this->runAfterPassInvalidated(P); }); 346 Callbacks.registerBeforeAnalysisCallback([this](StringRef P, llvm::Any IR) { 347 return this->runBeforeAnalysis(P, IR); 348 }); 349 Callbacks.registerAfterAnalysisCallback( 350 [this](StringRef P, llvm::Any IR) { this->runAfterAnalysis(P, IR); }); 351 } 352 353 void ignoreNonMockPassInstrumentation(StringRef IRName) { 354 // Generic EXPECT_CALLs are needed to match instrumentation on unimportant 355 // parts of a pipeline that we do not care about (e.g. various passes added 356 // by default by PassBuilder - Verifier pass etc). 357 // Make sure to avoid ignoring Mock passes/analysis, we definitely want 358 // to check these explicitly. 359 EXPECT_CALL(*this, 360 runBeforePass(Not(HasNameRegex("Mock")), HasName(IRName))) 361 .Times(AnyNumber()); 362 EXPECT_CALL( 363 *this, runBeforeSkippedPass(Not(HasNameRegex("Mock")), HasName(IRName))) 364 .Times(AnyNumber()); 365 EXPECT_CALL(*this, runBeforeNonSkippedPass(Not(HasNameRegex("Mock")), 366 HasName(IRName))) 367 .Times(AnyNumber()); 368 EXPECT_CALL(*this, runAfterPass(Not(HasNameRegex("Mock")), HasName(IRName))) 369 .Times(AnyNumber()); 370 EXPECT_CALL(*this, 371 runBeforeAnalysis(Not(HasNameRegex("Mock")), HasName(IRName))) 372 .Times(AnyNumber()); 373 EXPECT_CALL(*this, 374 runAfterAnalysis(Not(HasNameRegex("Mock")), HasName(IRName))) 375 .Times(AnyNumber()); 376 } 377 }; 378 379 template <typename PassManagerT> class PassBuilderCallbacksTest; 380 381 /// This test fixture is shared between all the actual tests below and 382 /// takes care of setting up appropriate defaults. 383 /// 384 /// The template specialization serves to extract the IRUnit and AM types from 385 /// the given PassManagerT. 386 template <typename TestIRUnitT, typename... ExtraPassArgTs, 387 typename... ExtraAnalysisArgTs> 388 class PassBuilderCallbacksTest<PassManager< 389 TestIRUnitT, AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>, 390 ExtraPassArgTs...>> : public testing::Test { 391 protected: 392 using IRUnitT = TestIRUnitT; 393 using AnalysisManagerT = AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>; 394 using PassManagerT = 395 PassManager<TestIRUnitT, AnalysisManagerT, ExtraPassArgTs...>; 396 using AnalysisT = typename MockAnalysisHandle<IRUnitT>::Analysis; 397 398 LLVMContext Context; 399 std::unique_ptr<Module> M; 400 401 MockPassInstrumentationCallbacks CallbacksHandle; 402 403 PassBuilder PB; 404 ModulePassManager PM; 405 LoopAnalysisManager LAM; 406 FunctionAnalysisManager FAM; 407 CGSCCAnalysisManager CGAM; 408 ModuleAnalysisManager AM; 409 410 MockPassHandle<IRUnitT> PassHandle; 411 MockAnalysisHandle<IRUnitT> AnalysisHandle; 412 413 static PreservedAnalyses getAnalysisResult(IRUnitT &U, AnalysisManagerT &AM, 414 ExtraAnalysisArgTs &&... Args) { 415 (void)AM.template getResult<AnalysisT>( 416 U, std::forward<ExtraAnalysisArgTs>(Args)...); 417 return PreservedAnalyses::all(); 418 } 419 420 PassBuilderCallbacksTest() 421 : M(parseIR(Context, 422 "declare void @bar()\n" 423 "define void @foo(i32 %n) {\n" 424 "entry:\n" 425 " br label %loop\n" 426 "loop:\n" 427 " %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]\n" 428 " %iv.next = add i32 %iv, 1\n" 429 " tail call void @bar()\n" 430 " %cmp = icmp eq i32 %iv, %n\n" 431 " br i1 %cmp, label %exit, label %loop\n" 432 "exit:\n" 433 " ret void\n" 434 "}\n")), 435 CallbacksHandle(), 436 PB(nullptr, PipelineTuningOptions(), None, &CallbacksHandle.Callbacks), 437 PM(true), LAM(true), FAM(true), CGAM(true), AM(true) { 438 439 EXPECT_TRUE(&CallbacksHandle.Callbacks == 440 PB.getPassInstrumentationCallbacks()); 441 442 /// Register a callback for analysis registration. 443 /// 444 /// The callback is a function taking a reference to an AnalyisManager 445 /// object. When called, the callee gets to register its own analyses with 446 /// this PassBuilder instance. 447 PB.registerAnalysisRegistrationCallback([this](AnalysisManagerT &AM) { 448 // Register our mock analysis 449 AM.registerPass([this] { return AnalysisHandle.getAnalysis(); }); 450 }); 451 452 /// Register a callback for pipeline parsing. 453 /// 454 /// During parsing of a textual pipeline, the PassBuilder will call these 455 /// callbacks for each encountered pass name that it does not know. This 456 /// includes both simple pass names as well as names of sub-pipelines. In 457 /// the latter case, the InnerPipeline is not empty. 458 PB.registerPipelineParsingCallback( 459 [this](StringRef Name, PassManagerT &PM, 460 ArrayRef<PassBuilder::PipelineElement> InnerPipeline) { 461 /// Handle parsing of the names of analysis utilities such as 462 /// require<test-analysis> and invalidate<test-analysis> for our 463 /// analysis mock handle 464 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", Name, PM)) 465 return true; 466 467 /// Parse the name of our pass mock handle 468 if (Name == "test-transform") { 469 PM.addPass(PassHandle.getPass()); 470 return true; 471 } 472 return false; 473 }); 474 475 /// Register builtin analyses and cross-register the analysis proxies 476 PB.registerModuleAnalyses(AM); 477 PB.registerCGSCCAnalyses(CGAM); 478 PB.registerFunctionAnalyses(FAM); 479 PB.registerLoopAnalyses(LAM); 480 PB.crossRegisterProxies(LAM, FAM, CGAM, AM); 481 } 482 }; 483 484 using ModuleCallbacksTest = PassBuilderCallbacksTest<ModulePassManager>; 485 using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCCPassManager>; 486 using FunctionCallbacksTest = PassBuilderCallbacksTest<FunctionPassManager>; 487 using LoopCallbacksTest = PassBuilderCallbacksTest<LoopPassManager>; 488 489 /// Test parsing of the name of our mock pass for all IRUnits. 490 /// 491 /// The pass should by default run our mock analysis and then preserve it. 492 TEST_F(ModuleCallbacksTest, Passes) { 493 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)); 494 EXPECT_CALL(PassHandle, run(HasName("<string>"), _)) 495 .WillOnce(Invoke(getAnalysisResult)); 496 497 StringRef PipelineText = "test-transform"; 498 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 499 << "Pipeline was: " << PipelineText; 500 501 PM.run(*M, AM); 502 } 503 504 TEST_F(ModuleCallbacksTest, InstrumentedPasses) { 505 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)); 506 EXPECT_CALL(PassHandle, run(HasName("<string>"), _)) 507 .WillOnce(Invoke(getAnalysisResult)); 508 509 CallbacksHandle.registerPassInstrumentation(); 510 // Non-mock instrumentation not specifically mentioned below can be ignored. 511 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 512 513 // PassInstrumentation calls should happen in-sequence, in the same order 514 // as passes/analyses are scheduled. 515 ::testing::Sequence PISequence; 516 EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"), 517 HasName("<string>"))) 518 .InSequence(PISequence); 519 EXPECT_CALL(CallbacksHandle, 520 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), 521 HasName("<string>"))) 522 .InSequence(PISequence); 523 EXPECT_CALL(CallbacksHandle, 524 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), 525 HasName("<string>"))) 526 .InSequence(PISequence); 527 EXPECT_CALL( 528 CallbacksHandle, 529 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("<string>"))) 530 .InSequence(PISequence); 531 EXPECT_CALL(CallbacksHandle, 532 runAfterPass(HasNameRegex("MockPassHandle"), HasName("<string>"))) 533 .InSequence(PISequence); 534 535 // No passes are skipped, so there should be no calls to 536 // runBeforeSkippedPass(). 537 EXPECT_CALL( 538 CallbacksHandle, 539 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("<string>"))) 540 .Times(0); 541 542 StringRef PipelineText = "test-transform"; 543 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 544 << "Pipeline was: " << PipelineText; 545 546 PM.run(*M, AM); 547 } 548 549 TEST_F(ModuleCallbacksTest, InstrumentedSkippedPasses) { 550 CallbacksHandle.registerPassInstrumentation(); 551 // Non-mock instrumentation run here can safely be ignored. 552 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 553 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 554 555 // Skip all passes by returning false. Pass managers and adaptor passes are 556 // also passes that observed by the callbacks. 557 EXPECT_CALL(CallbacksHandle, runBeforePass(_, _)) 558 .WillRepeatedly(Return(false)); 559 560 EXPECT_CALL(CallbacksHandle, 561 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), _)) 562 .Times(3); 563 564 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)).Times(0); 565 EXPECT_CALL(PassHandle, run(HasName("<string>"), _)).Times(0); 566 567 // As the pass is skipped there is no nonskippedpass/afterPass, 568 // beforeAnalysis/afterAnalysis as well. 569 EXPECT_CALL(CallbacksHandle, 570 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _)) 571 .Times(0); 572 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) 573 .Times(0); 574 EXPECT_CALL(CallbacksHandle, 575 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 576 .Times(0); 577 EXPECT_CALL(CallbacksHandle, 578 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 579 .Times(0); 580 581 // Order is important here. `Adaptor` expectations should be checked first 582 // because the its argument contains 'PassManager' (for example: 583 // ModuleToFunctionPassAdaptor{{.*}}PassManager{{.*}}). Check 584 // `runBeforeNonSkippedPass` and `runAfterPass` to show that they are not 585 // skipped. 586 // 587 // Pass managers are not ignored. 588 // 5 = (1) ModulePassManager + (2) FunctionPassMangers + (1) LoopPassManager + 589 // (1) CGSCCPassManager 590 EXPECT_CALL(CallbacksHandle, 591 runBeforeNonSkippedPass(HasNameRegex("PassManager"), _)) 592 .Times(5); 593 EXPECT_CALL( 594 CallbacksHandle, 595 runBeforeNonSkippedPass(HasNameRegex("ModuleToFunctionPassAdaptor"), _)) 596 .Times(1); 597 EXPECT_CALL(CallbacksHandle, 598 runBeforeNonSkippedPass( 599 HasNameRegex("ModuleToPostOrderCGSCCPassAdaptor"), _)) 600 .Times(1); 601 EXPECT_CALL( 602 CallbacksHandle, 603 runBeforeNonSkippedPass(HasNameRegex("CGSCCToFunctionPassAdaptor"), _)) 604 .Times(1); 605 EXPECT_CALL( 606 CallbacksHandle, 607 runBeforeNonSkippedPass(HasNameRegex("FunctionToLoopPassAdaptor"), _)) 608 .Times(1); 609 610 // The `runAfterPass` checks are the same as these of 611 // `runBeforeNonSkippedPass`. 612 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("PassManager"), _)) 613 .Times(5); 614 EXPECT_CALL(CallbacksHandle, 615 runAfterPass(HasNameRegex("ModuleToFunctionPassAdaptor"), _)) 616 .Times(1); 617 EXPECT_CALL( 618 CallbacksHandle, 619 runAfterPass(HasNameRegex("ModuleToPostOrderCGSCCPassAdaptor"), _)) 620 .Times(1); 621 EXPECT_CALL(CallbacksHandle, 622 runAfterPass(HasNameRegex("CGSCCToFunctionPassAdaptor"), _)) 623 .Times(1); 624 EXPECT_CALL(CallbacksHandle, 625 runAfterPass(HasNameRegex("FunctionToLoopPassAdaptor"), _)) 626 .Times(1); 627 628 // Ignore analyses introduced by adaptor passes. 629 EXPECT_CALL(CallbacksHandle, 630 runBeforeAnalysis(Not(HasNameRegex("MockAnalysisHandle")), _)) 631 .Times(AnyNumber()); 632 EXPECT_CALL(CallbacksHandle, 633 runAfterAnalysis(Not(HasNameRegex("MockAnalysisHandle")), _)) 634 .Times(AnyNumber()); 635 636 // Register Funtion and Loop version of "test-transform" for testing 637 PB.registerPipelineParsingCallback( 638 [](StringRef Name, FunctionPassManager &FPM, 639 ArrayRef<PassBuilder::PipelineElement>) { 640 if (Name == "test-transform") { 641 FPM.addPass(MockPassHandle<Function>().getPass()); 642 return true; 643 } 644 return false; 645 }); 646 PB.registerPipelineParsingCallback( 647 [](StringRef Name, LoopPassManager &LPM, 648 ArrayRef<PassBuilder::PipelineElement>) { 649 if (Name == "test-transform") { 650 LPM.addPass(MockPassHandle<Loop>().getPass()); 651 return true; 652 } 653 return false; 654 }); 655 656 StringRef PipelineText = "test-transform,function(test-transform),cgscc(" 657 "function(loop(test-transform)))"; 658 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 659 << "Pipeline was: " << PipelineText; 660 661 PM.run(*M, AM); 662 } 663 664 TEST_F(FunctionCallbacksTest, Passes) { 665 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)); 666 EXPECT_CALL(PassHandle, run(HasName("foo"), _)) 667 .WillOnce(Invoke(getAnalysisResult)); 668 669 StringRef PipelineText = "test-transform"; 670 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 671 << "Pipeline was: " << PipelineText; 672 PM.run(*M, AM); 673 } 674 675 TEST_F(FunctionCallbacksTest, InstrumentedPasses) { 676 CallbacksHandle.registerPassInstrumentation(); 677 // Non-mock instrumentation not specifically mentioned below can be ignored. 678 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 679 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 680 681 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)); 682 EXPECT_CALL(PassHandle, run(HasName("foo"), _)) 683 .WillOnce(Invoke(getAnalysisResult)); 684 685 // PassInstrumentation calls should happen in-sequence, in the same order 686 // as passes/analyses are scheduled. 687 ::testing::Sequence PISequence; 688 EXPECT_CALL(CallbacksHandle, 689 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo"))) 690 .InSequence(PISequence); 691 EXPECT_CALL( 692 CallbacksHandle, 693 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo"))) 694 .InSequence(PISequence); 695 EXPECT_CALL( 696 CallbacksHandle, 697 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo"))) 698 .InSequence(PISequence); 699 EXPECT_CALL( 700 CallbacksHandle, 701 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo"))) 702 .InSequence(PISequence); 703 EXPECT_CALL(CallbacksHandle, 704 runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo"))) 705 .InSequence(PISequence); 706 707 // No passes are skipped, so there should be no calls to 708 // runBeforeSkippedPass(). 709 EXPECT_CALL( 710 CallbacksHandle, 711 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo"))) 712 .Times(0); 713 714 // Our mock pass does not invalidate IR. 715 EXPECT_CALL(CallbacksHandle, 716 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 717 .Times(0); 718 719 StringRef PipelineText = "test-transform"; 720 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 721 << "Pipeline was: " << PipelineText; 722 PM.run(*M, AM); 723 } 724 725 TEST_F(FunctionCallbacksTest, InstrumentedSkippedPasses) { 726 CallbacksHandle.registerPassInstrumentation(); 727 // Non-mock instrumentation run here can safely be ignored. 728 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 729 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 730 731 // Skip the pass by returning false. 732 EXPECT_CALL(CallbacksHandle, 733 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo"))) 734 .WillOnce(Return(false)); 735 736 EXPECT_CALL( 737 CallbacksHandle, 738 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo"))) 739 .Times(1); 740 741 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)).Times(0); 742 EXPECT_CALL(PassHandle, run(HasName("foo"), _)).Times(0); 743 744 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis 745 // as well. 746 EXPECT_CALL(CallbacksHandle, 747 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _)) 748 .Times(0); 749 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) 750 .Times(0); 751 EXPECT_CALL(CallbacksHandle, 752 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 753 .Times(0); 754 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) 755 .Times(0); 756 EXPECT_CALL(CallbacksHandle, 757 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 758 .Times(0); 759 EXPECT_CALL(CallbacksHandle, 760 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 761 .Times(0); 762 763 StringRef PipelineText = "test-transform"; 764 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 765 << "Pipeline was: " << PipelineText; 766 PM.run(*M, AM); 767 } 768 769 TEST_F(LoopCallbacksTest, Passes) { 770 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)); 771 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)) 772 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); 773 774 StringRef PipelineText = "test-transform"; 775 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 776 << "Pipeline was: " << PipelineText; 777 PM.run(*M, AM); 778 } 779 780 TEST_F(LoopCallbacksTest, InstrumentedPasses) { 781 CallbacksHandle.registerPassInstrumentation(); 782 // Non-mock instrumentation not specifically mentioned below can be ignored. 783 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 784 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 785 CallbacksHandle.ignoreNonMockPassInstrumentation("loop"); 786 787 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)); 788 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)) 789 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); 790 791 // PassInstrumentation calls should happen in-sequence, in the same order 792 // as passes/analyses are scheduled. 793 ::testing::Sequence PISequence; 794 EXPECT_CALL(CallbacksHandle, 795 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop"))) 796 .InSequence(PISequence); 797 EXPECT_CALL( 798 CallbacksHandle, 799 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop"))) 800 .InSequence(PISequence); 801 EXPECT_CALL( 802 CallbacksHandle, 803 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop"))) 804 .InSequence(PISequence); 805 EXPECT_CALL( 806 CallbacksHandle, 807 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop"))) 808 .InSequence(PISequence); 809 EXPECT_CALL(CallbacksHandle, 810 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"))) 811 .InSequence(PISequence); 812 813 // Our mock pass does not invalidate IR. 814 EXPECT_CALL(CallbacksHandle, 815 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 816 .Times(0); 817 818 // No passes are skipped, so there should be no calls to 819 // runBeforeSkippedPass(). 820 EXPECT_CALL( 821 CallbacksHandle, 822 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop"))) 823 .Times(0); 824 825 StringRef PipelineText = "test-transform"; 826 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 827 << "Pipeline was: " << PipelineText; 828 PM.run(*M, AM); 829 } 830 831 TEST_F(LoopCallbacksTest, InstrumentedInvalidatingPasses) { 832 CallbacksHandle.registerPassInstrumentation(); 833 // Non-mock instrumentation not specifically mentioned below can be ignored. 834 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 835 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 836 CallbacksHandle.ignoreNonMockPassInstrumentation("loop"); 837 838 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)); 839 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)) 840 .WillOnce(DoAll(WithArgs<0, 1, 2, 3>(Invoke(PassHandle.invalidateLoop)), 841 WithArgs<0, 1, 2>(Invoke(getAnalysisResult)))); 842 843 // PassInstrumentation calls should happen in-sequence, in the same order 844 // as passes/analyses are scheduled. 845 ::testing::Sequence PISequence; 846 EXPECT_CALL(CallbacksHandle, 847 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop"))) 848 .InSequence(PISequence); 849 EXPECT_CALL( 850 CallbacksHandle, 851 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop"))) 852 .InSequence(PISequence); 853 EXPECT_CALL( 854 CallbacksHandle, 855 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop"))) 856 .InSequence(PISequence); 857 EXPECT_CALL( 858 CallbacksHandle, 859 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop"))) 860 .InSequence(PISequence); 861 EXPECT_CALL(CallbacksHandle, 862 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 863 .InSequence(PISequence); 864 EXPECT_CALL(CallbacksHandle, 865 runAfterPassInvalidated(HasNameRegex("^PassManager"))) 866 .InSequence(PISequence); 867 868 // Our mock pass invalidates IR, thus normal runAfterPass is never called. 869 EXPECT_CALL(CallbacksHandle, 870 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"))) 871 .Times(0); 872 873 StringRef PipelineText = "test-transform"; 874 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 875 << "Pipeline was: " << PipelineText; 876 PM.run(*M, AM); 877 } 878 879 TEST_F(LoopCallbacksTest, InstrumentedSkippedPasses) { 880 CallbacksHandle.registerPassInstrumentation(); 881 // Non-mock instrumentation run here can safely be ignored. 882 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 883 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 884 CallbacksHandle.ignoreNonMockPassInstrumentation("loop"); 885 886 // Skip the pass by returning false. 887 EXPECT_CALL(CallbacksHandle, 888 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop"))) 889 .WillOnce(Return(false)); 890 891 EXPECT_CALL( 892 CallbacksHandle, 893 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop"))) 894 .Times(1); 895 896 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)).Times(0); 897 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)).Times(0); 898 899 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis 900 // as well. 901 EXPECT_CALL(CallbacksHandle, 902 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _)) 903 .Times(0); 904 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) 905 .Times(0); 906 EXPECT_CALL(CallbacksHandle, 907 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 908 .Times(0); 909 EXPECT_CALL(CallbacksHandle, 910 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 911 .Times(0); 912 EXPECT_CALL(CallbacksHandle, 913 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 914 .Times(0); 915 916 StringRef PipelineText = "test-transform"; 917 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 918 << "Pipeline was: " << PipelineText; 919 PM.run(*M, AM); 920 } 921 922 TEST_F(CGSCCCallbacksTest, Passes) { 923 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)); 924 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)) 925 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); 926 927 StringRef PipelineText = "test-transform"; 928 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 929 << "Pipeline was: " << PipelineText; 930 PM.run(*M, AM); 931 } 932 933 TEST_F(CGSCCCallbacksTest, InstrumentedPasses) { 934 CallbacksHandle.registerPassInstrumentation(); 935 // Non-mock instrumentation not specifically mentioned below can be ignored. 936 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 937 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 938 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)"); 939 940 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)); 941 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)) 942 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); 943 944 // PassInstrumentation calls should happen in-sequence, in the same order 945 // as passes/analyses are scheduled. 946 ::testing::Sequence PISequence; 947 EXPECT_CALL(CallbacksHandle, 948 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 949 .InSequence(PISequence); 950 EXPECT_CALL( 951 CallbacksHandle, 952 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 953 .InSequence(PISequence); 954 EXPECT_CALL( 955 CallbacksHandle, 956 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)"))) 957 .InSequence(PISequence); 958 EXPECT_CALL( 959 CallbacksHandle, 960 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)"))) 961 .InSequence(PISequence); 962 EXPECT_CALL(CallbacksHandle, 963 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 964 .InSequence(PISequence); 965 966 // Our mock pass does not invalidate IR. 967 EXPECT_CALL(CallbacksHandle, 968 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 969 .Times(0); 970 971 // No passes are skipped, so there should be no calls to 972 // runBeforeSkippedPass(). 973 EXPECT_CALL( 974 CallbacksHandle, 975 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 976 .Times(0); 977 978 StringRef PipelineText = "test-transform"; 979 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 980 << "Pipeline was: " << PipelineText; 981 PM.run(*M, AM); 982 } 983 984 TEST_F(CGSCCCallbacksTest, InstrumentedInvalidatingPasses) { 985 CallbacksHandle.registerPassInstrumentation(); 986 // Non-mock instrumentation not specifically mentioned below can be ignored. 987 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 988 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 989 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)"); 990 991 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)); 992 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)) 993 .WillOnce(DoAll(WithArgs<0, 1, 2, 3>(Invoke(PassHandle.invalidateSCC)), 994 WithArgs<0, 1, 2>(Invoke(getAnalysisResult)))); 995 996 // PassInstrumentation calls should happen in-sequence, in the same order 997 // as passes/analyses are scheduled. 998 ::testing::Sequence PISequence; 999 EXPECT_CALL(CallbacksHandle, 1000 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 1001 .InSequence(PISequence); 1002 EXPECT_CALL( 1003 CallbacksHandle, 1004 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 1005 .InSequence(PISequence); 1006 EXPECT_CALL( 1007 CallbacksHandle, 1008 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)"))) 1009 .InSequence(PISequence); 1010 EXPECT_CALL( 1011 CallbacksHandle, 1012 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)"))) 1013 .InSequence(PISequence); 1014 EXPECT_CALL(CallbacksHandle, 1015 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 1016 .InSequence(PISequence); 1017 EXPECT_CALL(CallbacksHandle, 1018 runAfterPassInvalidated(HasNameRegex("^PassManager"))) 1019 .InSequence(PISequence); 1020 1021 // Our mock pass does invalidate IR, thus normal runAfterPass is never called. 1022 EXPECT_CALL(CallbacksHandle, 1023 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 1024 .Times(0); 1025 1026 StringRef PipelineText = "test-transform"; 1027 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 1028 << "Pipeline was: " << PipelineText; 1029 PM.run(*M, AM); 1030 } 1031 1032 TEST_F(CGSCCCallbacksTest, InstrumentedSkippedPasses) { 1033 CallbacksHandle.registerPassInstrumentation(); 1034 // Non-mock instrumentation run here can safely be ignored. 1035 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 1036 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 1037 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)"); 1038 1039 // Skip the pass by returning false. 1040 EXPECT_CALL(CallbacksHandle, 1041 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 1042 .WillOnce(Return(false)); 1043 1044 EXPECT_CALL( 1045 CallbacksHandle, 1046 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 1047 .Times(1); 1048 1049 // neither Analysis nor Pass are called. 1050 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)).Times(0); 1051 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)).Times(0); 1052 1053 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis 1054 // as well. 1055 EXPECT_CALL(CallbacksHandle, 1056 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _)) 1057 .Times(0); 1058 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) 1059 .Times(0); 1060 EXPECT_CALL(CallbacksHandle, 1061 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 1062 .Times(0); 1063 EXPECT_CALL(CallbacksHandle, 1064 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 1065 .Times(0); 1066 EXPECT_CALL(CallbacksHandle, 1067 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 1068 .Times(0); 1069 1070 StringRef PipelineText = "test-transform"; 1071 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 1072 << "Pipeline was: " << PipelineText; 1073 PM.run(*M, AM); 1074 } 1075 1076 /// Test parsing of the names of analysis utilities for our mock analysis 1077 /// for all IRUnits. 1078 /// 1079 /// We first require<>, then invalidate<> it, expecting the analysis to be run 1080 /// once and subsequently invalidated. 1081 TEST_F(ModuleCallbacksTest, AnalysisUtilities) { 1082 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)); 1083 EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _)); 1084 1085 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>"; 1086 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 1087 << "Pipeline was: " << PipelineText; 1088 PM.run(*M, AM); 1089 } 1090 1091 TEST_F(CGSCCCallbacksTest, PassUtilities) { 1092 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)); 1093 EXPECT_CALL(AnalysisHandle, invalidate(HasName("(foo)"), _, _)); 1094 1095 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>"; 1096 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 1097 << "Pipeline was: " << PipelineText; 1098 PM.run(*M, AM); 1099 } 1100 1101 TEST_F(FunctionCallbacksTest, AnalysisUtilities) { 1102 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)); 1103 EXPECT_CALL(AnalysisHandle, invalidate(HasName("foo"), _, _)); 1104 1105 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>"; 1106 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 1107 << "Pipeline was: " << PipelineText; 1108 PM.run(*M, AM); 1109 } 1110 1111 TEST_F(LoopCallbacksTest, PassUtilities) { 1112 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)); 1113 EXPECT_CALL(AnalysisHandle, invalidate(HasName("loop"), _, _)); 1114 1115 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>"; 1116 1117 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 1118 << "Pipeline was: " << PipelineText; 1119 PM.run(*M, AM); 1120 } 1121 1122 /// Test parsing of the top-level pipeline. 1123 /// 1124 /// The ParseTopLevelPipeline callback takes over parsing of the entire pipeline 1125 /// from PassBuilder if it encounters an unknown pipeline entry at the top level 1126 /// (i.e., the first entry on the pipeline). 1127 /// This test parses a pipeline named 'another-pipeline', whose only elements 1128 /// may be the test-transform pass or the analysis utilities 1129 TEST_F(ModuleCallbacksTest, ParseTopLevelPipeline) { 1130 PB.registerParseTopLevelPipelineCallback([this]( 1131 ModulePassManager &MPM, ArrayRef<PassBuilder::PipelineElement> Pipeline, 1132 bool VerifyEachPass, bool DebugLogging) { 1133 auto &FirstName = Pipeline.front().Name; 1134 auto &InnerPipeline = Pipeline.front().InnerPipeline; 1135 if (FirstName == "another-pipeline") { 1136 for (auto &E : InnerPipeline) { 1137 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", E.Name, PM)) 1138 continue; 1139 1140 if (E.Name == "test-transform") { 1141 PM.addPass(PassHandle.getPass()); 1142 continue; 1143 } 1144 return false; 1145 } 1146 } 1147 return true; 1148 }); 1149 1150 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)); 1151 EXPECT_CALL(PassHandle, run(HasName("<string>"), _)) 1152 .WillOnce(Invoke(getAnalysisResult)); 1153 EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _)); 1154 1155 StringRef PipelineText = 1156 "another-pipeline(test-transform,invalidate<test-analysis>)"; 1157 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 1158 << "Pipeline was: " << PipelineText; 1159 PM.run(*M, AM); 1160 1161 /// Test the negative case 1162 PipelineText = "another-pipeline(instcombine)"; 1163 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Failed()) 1164 << "Pipeline was: " << PipelineText; 1165 } 1166 } // end anonymous namespace 1167