1 //===- unittests/IR/PassBuilderCallbacksTest.cpp - PB Callback Tests --===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Testing/Support/Error.h" 11 #include <functional> 12 #include <gmock/gmock.h> 13 #include <gtest/gtest.h> 14 #include <llvm/ADT/Any.h> 15 #include <llvm/Analysis/CGSCCPassManager.h> 16 #include <llvm/Analysis/LoopAnalysisManager.h> 17 #include <llvm/AsmParser/Parser.h> 18 #include <llvm/IR/LLVMContext.h> 19 #include <llvm/IR/PassInstrumentation.h> 20 #include <llvm/IR/PassManager.h> 21 #include <llvm/Passes/PassBuilder.h> 22 #include <llvm/Support/Regex.h> 23 #include <llvm/Support/SourceMgr.h> 24 #include <llvm/Transforms/Scalar/LoopPassManager.h> 25 26 using namespace llvm; 27 28 namespace { 29 using testing::AnyNumber; 30 using testing::AtLeast; 31 using testing::DoDefault; 32 using testing::Not; 33 using testing::Return; 34 using testing::Expectation; 35 using testing::Invoke; 36 using testing::WithArgs; 37 using testing::_; 38 39 /// A CRTP base for analysis mock handles 40 /// 41 /// This class reconciles mocking with the value semantics implementation of the 42 /// AnalysisManager. Analysis mock handles should derive from this class and 43 /// call \c setDefault() in their constroctur for wiring up the defaults defined 44 /// by this base with their mock run() and invalidate() implementations. 45 template <typename DerivedT, typename IRUnitT, 46 typename AnalysisManagerT = AnalysisManager<IRUnitT>, 47 typename... ExtraArgTs> 48 class MockAnalysisHandleBase { 49 public: 50 class Analysis : public AnalysisInfoMixin<Analysis> { 51 friend AnalysisInfoMixin<Analysis>; 52 friend MockAnalysisHandleBase; 53 static AnalysisKey Key; 54 55 DerivedT *Handle; 56 57 Analysis(DerivedT &Handle) : Handle(&Handle) { 58 static_assert(std::is_base_of<MockAnalysisHandleBase, DerivedT>::value, 59 "Must pass the derived type to this template!"); 60 } 61 62 public: 63 class Result { 64 friend MockAnalysisHandleBase; 65 66 DerivedT *Handle; 67 68 Result(DerivedT &Handle) : Handle(&Handle) {} 69 70 public: 71 // Forward invalidation events to the mock handle. 72 bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA, 73 typename AnalysisManagerT::Invalidator &Inv) { 74 return Handle->invalidate(IR, PA, Inv); 75 } 76 }; 77 78 Result run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs) { 79 return Handle->run(IR, AM, ExtraArgs...); 80 } 81 }; 82 83 Analysis getAnalysis() { return Analysis(static_cast<DerivedT &>(*this)); } 84 typename Analysis::Result getResult() { 85 return typename Analysis::Result(static_cast<DerivedT &>(*this)); 86 } 87 static StringRef getName() { return llvm::getTypeName<DerivedT>(); } 88 89 protected: 90 // FIXME: MSVC seems unable to handle a lambda argument to Invoke from within 91 // the template, so we use a boring static function. 92 static bool invalidateCallback(IRUnitT &IR, const PreservedAnalyses &PA, 93 typename AnalysisManagerT::Invalidator &Inv) { 94 auto PAC = PA.template getChecker<Analysis>(); 95 return !PAC.preserved() && 96 !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>(); 97 } 98 99 /// Derived classes should call this in their constructor to set up default 100 /// mock actions. (We can't do this in our constructor because this has to 101 /// run after the DerivedT is constructed.) 102 void setDefaults() { 103 ON_CALL(static_cast<DerivedT &>(*this), 104 run(_, _, testing::Matcher<ExtraArgTs>(_)...)) 105 .WillByDefault(Return(this->getResult())); 106 ON_CALL(static_cast<DerivedT &>(*this), invalidate(_, _, _)) 107 .WillByDefault(Invoke(&invalidateCallback)); 108 } 109 }; 110 111 /// A CRTP base for pass mock handles 112 /// 113 /// This class reconciles mocking with the value semantics implementation of the 114 /// PassManager. Pass mock handles should derive from this class and 115 /// call \c setDefault() in their constroctur for wiring up the defaults defined 116 /// by this base with their mock run() and invalidate() implementations. 117 template <typename DerivedT, typename IRUnitT, typename AnalysisManagerT, 118 typename... ExtraArgTs> 119 AnalysisKey MockAnalysisHandleBase<DerivedT, IRUnitT, AnalysisManagerT, 120 ExtraArgTs...>::Analysis::Key; 121 122 template <typename DerivedT, typename IRUnitT, 123 typename AnalysisManagerT = AnalysisManager<IRUnitT>, 124 typename... ExtraArgTs> 125 class MockPassHandleBase { 126 public: 127 class Pass : public PassInfoMixin<Pass> { 128 friend MockPassHandleBase; 129 130 DerivedT *Handle; 131 132 Pass(DerivedT &Handle) : Handle(&Handle) { 133 static_assert(std::is_base_of<MockPassHandleBase, DerivedT>::value, 134 "Must pass the derived type to this template!"); 135 } 136 137 public: 138 PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM, 139 ExtraArgTs... ExtraArgs) { 140 return Handle->run(IR, AM, ExtraArgs...); 141 } 142 }; 143 144 static StringRef getName() { return llvm::getTypeName<DerivedT>(); } 145 146 Pass getPass() { return Pass(static_cast<DerivedT &>(*this)); } 147 148 protected: 149 /// Derived classes should call this in their constructor to set up default 150 /// mock actions. (We can't do this in our constructor because this has to 151 /// run after the DerivedT is constructed.) 152 void setDefaults() { 153 ON_CALL(static_cast<DerivedT &>(*this), 154 run(_, _, testing::Matcher<ExtraArgTs>(_)...)) 155 .WillByDefault(Return(PreservedAnalyses::all())); 156 } 157 }; 158 159 /// Mock handles for passes for the IRUnits Module, CGSCC, Function, Loop. 160 /// These handles define the appropriate run() mock interface for the respective 161 /// IRUnit type. 162 template <typename IRUnitT> struct MockPassHandle; 163 template <> 164 struct MockPassHandle<Loop> 165 : MockPassHandleBase<MockPassHandle<Loop>, Loop, LoopAnalysisManager, 166 LoopStandardAnalysisResults &, LPMUpdater &> { 167 MOCK_METHOD4(run, 168 PreservedAnalyses(Loop &, LoopAnalysisManager &, 169 LoopStandardAnalysisResults &, LPMUpdater &)); 170 static void invalidateLoop(Loop &L, LoopAnalysisManager &, 171 LoopStandardAnalysisResults &, 172 LPMUpdater &Updater) { 173 Updater.markLoopAsDeleted(L, L.getName()); 174 } 175 MockPassHandle() { setDefaults(); } 176 }; 177 178 template <> 179 struct MockPassHandle<Function> 180 : MockPassHandleBase<MockPassHandle<Function>, Function> { 181 MOCK_METHOD2(run, PreservedAnalyses(Function &, FunctionAnalysisManager &)); 182 183 MockPassHandle() { setDefaults(); } 184 }; 185 186 template <> 187 struct MockPassHandle<LazyCallGraph::SCC> 188 : MockPassHandleBase<MockPassHandle<LazyCallGraph::SCC>, LazyCallGraph::SCC, 189 CGSCCAnalysisManager, LazyCallGraph &, 190 CGSCCUpdateResult &> { 191 MOCK_METHOD4(run, 192 PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &, 193 LazyCallGraph &G, CGSCCUpdateResult &UR)); 194 195 static void invalidateSCC(LazyCallGraph::SCC &C, CGSCCAnalysisManager &, 196 LazyCallGraph &, CGSCCUpdateResult &UR) { 197 UR.InvalidatedSCCs.insert(&C); 198 } 199 200 MockPassHandle() { setDefaults(); } 201 }; 202 203 template <> 204 struct MockPassHandle<Module> 205 : MockPassHandleBase<MockPassHandle<Module>, Module> { 206 MOCK_METHOD2(run, PreservedAnalyses(Module &, ModuleAnalysisManager &)); 207 208 MockPassHandle() { setDefaults(); } 209 }; 210 211 /// Mock handles for analyses for the IRUnits Module, CGSCC, Function, Loop. 212 /// These handles define the appropriate run() and invalidate() mock interfaces 213 /// for the respective IRUnit type. 214 template <typename IRUnitT> struct MockAnalysisHandle; 215 template <> 216 struct MockAnalysisHandle<Loop> 217 : MockAnalysisHandleBase<MockAnalysisHandle<Loop>, Loop, 218 LoopAnalysisManager, 219 LoopStandardAnalysisResults &> { 220 221 MOCK_METHOD3_T(run, typename Analysis::Result(Loop &, LoopAnalysisManager &, 222 LoopStandardAnalysisResults &)); 223 224 MOCK_METHOD3_T(invalidate, bool(Loop &, const PreservedAnalyses &, 225 LoopAnalysisManager::Invalidator &)); 226 227 MockAnalysisHandle<Loop>() { this->setDefaults(); } 228 }; 229 230 template <> 231 struct MockAnalysisHandle<Function> 232 : MockAnalysisHandleBase<MockAnalysisHandle<Function>, Function> { 233 MOCK_METHOD2(run, Analysis::Result(Function &, FunctionAnalysisManager &)); 234 235 MOCK_METHOD3(invalidate, bool(Function &, const PreservedAnalyses &, 236 FunctionAnalysisManager::Invalidator &)); 237 238 MockAnalysisHandle<Function>() { setDefaults(); } 239 }; 240 241 template <> 242 struct MockAnalysisHandle<LazyCallGraph::SCC> 243 : MockAnalysisHandleBase<MockAnalysisHandle<LazyCallGraph::SCC>, 244 LazyCallGraph::SCC, CGSCCAnalysisManager, 245 LazyCallGraph &> { 246 MOCK_METHOD3(run, Analysis::Result(LazyCallGraph::SCC &, 247 CGSCCAnalysisManager &, LazyCallGraph &)); 248 249 MOCK_METHOD3(invalidate, bool(LazyCallGraph::SCC &, const PreservedAnalyses &, 250 CGSCCAnalysisManager::Invalidator &)); 251 252 MockAnalysisHandle<LazyCallGraph::SCC>() { setDefaults(); } 253 }; 254 255 template <> 256 struct MockAnalysisHandle<Module> 257 : MockAnalysisHandleBase<MockAnalysisHandle<Module>, Module> { 258 MOCK_METHOD2(run, Analysis::Result(Module &, ModuleAnalysisManager &)); 259 260 MOCK_METHOD3(invalidate, bool(Module &, const PreservedAnalyses &, 261 ModuleAnalysisManager::Invalidator &)); 262 263 MockAnalysisHandle<Module>() { setDefaults(); } 264 }; 265 266 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { 267 SMDiagnostic Err; 268 return parseAssemblyString(IR, Err, C); 269 } 270 271 /// Helper for HasName matcher that returns getName both for IRUnit and 272 /// for IRUnit pointer wrapper into llvm::Any (wrapped by PassInstrumentation). 273 template <typename IRUnitT> std::string getName(const IRUnitT &IR) { 274 return IR.getName(); 275 } 276 277 template <> std::string getName(const StringRef &name) { return name; } 278 279 template <> std::string getName(const llvm::Any &WrappedIR) { 280 if (any_isa<const Module *>(WrappedIR)) 281 return any_cast<const Module *>(WrappedIR)->getName().str(); 282 if (any_isa<const Function *>(WrappedIR)) 283 return any_cast<const Function *>(WrappedIR)->getName().str(); 284 if (any_isa<const Loop *>(WrappedIR)) 285 return any_cast<const Loop *>(WrappedIR)->getName().str(); 286 if (any_isa<const LazyCallGraph::SCC *>(WrappedIR)) 287 return any_cast<const LazyCallGraph::SCC *>(WrappedIR)->getName(); 288 return "<UNKNOWN>"; 289 } 290 /// Define a custom matcher for objects which support a 'getName' method. 291 /// 292 /// LLVM often has IR objects or analysis objects which expose a name 293 /// and in tests it is convenient to match these by name for readability. 294 /// Usually, this name is either a StringRef or a plain std::string. This 295 /// matcher supports any type exposing a getName() method of this form whose 296 /// return value is compatible with an std::ostream. For StringRef, this uses 297 /// the shift operator defined above. 298 /// 299 /// It should be used as: 300 /// 301 /// HasName("my_function") 302 /// 303 /// No namespace or other qualification is required. 304 MATCHER_P(HasName, Name, "") { 305 *result_listener << "has name '" << getName(arg) << "'"; 306 return Name == getName(arg); 307 } 308 309 MATCHER_P(HasNameRegex, Name, "") { 310 *result_listener << "has name '" << getName(arg) << "'"; 311 llvm::Regex r(Name); 312 return r.match(getName(arg)); 313 } 314 315 struct MockPassInstrumentationCallbacks { 316 PassInstrumentationCallbacks Callbacks; 317 318 MockPassInstrumentationCallbacks() { 319 ON_CALL(*this, runBeforePass(_, _)).WillByDefault(Return(true)); 320 } 321 MOCK_METHOD2(runBeforePass, bool(StringRef PassID, llvm::Any)); 322 MOCK_METHOD2(runAfterPass, void(StringRef PassID, llvm::Any)); 323 MOCK_METHOD1(runAfterPassInvalidated, void(StringRef PassID)); 324 MOCK_METHOD2(runBeforeAnalysis, void(StringRef PassID, llvm::Any)); 325 MOCK_METHOD2(runAfterAnalysis, void(StringRef PassID, llvm::Any)); 326 327 void registerPassInstrumentation() { 328 Callbacks.registerBeforePassCallback([this](StringRef P, llvm::Any IR) { 329 return this->runBeforePass(P, IR); 330 }); 331 Callbacks.registerAfterPassCallback( 332 [this](StringRef P, llvm::Any IR) { this->runAfterPass(P, IR); }); 333 Callbacks.registerAfterPassInvalidatedCallback( 334 [this](StringRef P) { this->runAfterPassInvalidated(P); }); 335 Callbacks.registerBeforeAnalysisCallback([this](StringRef P, llvm::Any IR) { 336 return this->runBeforeAnalysis(P, IR); 337 }); 338 Callbacks.registerAfterAnalysisCallback( 339 [this](StringRef P, llvm::Any IR) { this->runAfterAnalysis(P, IR); }); 340 } 341 342 void ignoreNonMockPassInstrumentation(StringRef IRName) { 343 // Generic EXPECT_CALLs are needed to match instrumentation on unimportant 344 // parts of a pipeline that we do not care about (e.g. various passes added 345 // by default by PassBuilder - Verifier pass etc). 346 // Make sure to avoid ignoring Mock passes/analysis, we definitely want 347 // to check these explicitly. 348 EXPECT_CALL(*this, 349 runBeforePass(Not(HasNameRegex("Mock")), HasName(IRName))) 350 .Times(AnyNumber()); 351 EXPECT_CALL(*this, runAfterPass(Not(HasNameRegex("Mock")), HasName(IRName))) 352 .Times(AnyNumber()); 353 EXPECT_CALL(*this, 354 runBeforeAnalysis(Not(HasNameRegex("Mock")), HasName(IRName))) 355 .Times(AnyNumber()); 356 EXPECT_CALL(*this, 357 runAfterAnalysis(Not(HasNameRegex("Mock")), HasName(IRName))) 358 .Times(AnyNumber()); 359 } 360 }; 361 362 template <typename PassManagerT> class PassBuilderCallbacksTest; 363 364 /// This test fixture is shared between all the actual tests below and 365 /// takes care of setting up appropriate defaults. 366 /// 367 /// The template specialization serves to extract the IRUnit and AM types from 368 /// the given PassManagerT. 369 template <typename TestIRUnitT, typename... ExtraPassArgTs, 370 typename... ExtraAnalysisArgTs> 371 class PassBuilderCallbacksTest<PassManager< 372 TestIRUnitT, AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>, 373 ExtraPassArgTs...>> : public testing::Test { 374 protected: 375 using IRUnitT = TestIRUnitT; 376 using AnalysisManagerT = AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>; 377 using PassManagerT = 378 PassManager<TestIRUnitT, AnalysisManagerT, ExtraPassArgTs...>; 379 using AnalysisT = typename MockAnalysisHandle<IRUnitT>::Analysis; 380 381 LLVMContext Context; 382 std::unique_ptr<Module> M; 383 384 MockPassInstrumentationCallbacks CallbacksHandle; 385 386 PassBuilder PB; 387 ModulePassManager PM; 388 LoopAnalysisManager LAM; 389 FunctionAnalysisManager FAM; 390 CGSCCAnalysisManager CGAM; 391 ModuleAnalysisManager AM; 392 393 MockPassHandle<IRUnitT> PassHandle; 394 MockAnalysisHandle<IRUnitT> AnalysisHandle; 395 396 static PreservedAnalyses getAnalysisResult(IRUnitT &U, AnalysisManagerT &AM, 397 ExtraAnalysisArgTs &&... Args) { 398 (void)AM.template getResult<AnalysisT>( 399 U, std::forward<ExtraAnalysisArgTs>(Args)...); 400 return PreservedAnalyses::all(); 401 } 402 403 PassBuilderCallbacksTest() 404 : M(parseIR(Context, 405 "declare void @bar()\n" 406 "define void @foo(i32 %n) {\n" 407 "entry:\n" 408 " br label %loop\n" 409 "loop:\n" 410 " %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]\n" 411 " %iv.next = add i32 %iv, 1\n" 412 " tail call void @bar()\n" 413 " %cmp = icmp eq i32 %iv, %n\n" 414 " br i1 %cmp, label %exit, label %loop\n" 415 "exit:\n" 416 " ret void\n" 417 "}\n")), 418 CallbacksHandle(), PB(nullptr, None, &CallbacksHandle.Callbacks), 419 PM(true), LAM(true), FAM(true), CGAM(true), AM(true) { 420 421 /// Register a callback for analysis registration. 422 /// 423 /// The callback is a function taking a reference to an AnalyisManager 424 /// object. When called, the callee gets to register its own analyses with 425 /// this PassBuilder instance. 426 PB.registerAnalysisRegistrationCallback([this](AnalysisManagerT &AM) { 427 // Register our mock analysis 428 AM.registerPass([this] { return AnalysisHandle.getAnalysis(); }); 429 }); 430 431 /// Register a callback for pipeline parsing. 432 /// 433 /// During parsing of a textual pipeline, the PassBuilder will call these 434 /// callbacks for each encountered pass name that it does not know. This 435 /// includes both simple pass names as well as names of sub-pipelines. In 436 /// the latter case, the InnerPipeline is not empty. 437 PB.registerPipelineParsingCallback( 438 [this](StringRef Name, PassManagerT &PM, 439 ArrayRef<PassBuilder::PipelineElement> InnerPipeline) { 440 /// Handle parsing of the names of analysis utilities such as 441 /// require<test-analysis> and invalidate<test-analysis> for our 442 /// analysis mock handle 443 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", Name, PM)) 444 return true; 445 446 /// Parse the name of our pass mock handle 447 if (Name == "test-transform") { 448 PM.addPass(PassHandle.getPass()); 449 return true; 450 } 451 return false; 452 }); 453 454 /// Register builtin analyses and cross-register the analysis proxies 455 PB.registerModuleAnalyses(AM); 456 PB.registerCGSCCAnalyses(CGAM); 457 PB.registerFunctionAnalyses(FAM); 458 PB.registerLoopAnalyses(LAM); 459 PB.crossRegisterProxies(LAM, FAM, CGAM, AM); 460 } 461 }; 462 463 using ModuleCallbacksTest = PassBuilderCallbacksTest<ModulePassManager>; 464 using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCCPassManager>; 465 using FunctionCallbacksTest = PassBuilderCallbacksTest<FunctionPassManager>; 466 using LoopCallbacksTest = PassBuilderCallbacksTest<LoopPassManager>; 467 468 /// Test parsing of the name of our mock pass for all IRUnits. 469 /// 470 /// The pass should by default run our mock analysis and then preserve it. 471 TEST_F(ModuleCallbacksTest, Passes) { 472 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)); 473 EXPECT_CALL(PassHandle, run(HasName("<string>"), _)) 474 .WillOnce(Invoke(getAnalysisResult)); 475 476 StringRef PipelineText = "test-transform"; 477 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 478 << "Pipeline was: " << PipelineText; 479 480 PM.run(*M, AM); 481 } 482 483 TEST_F(ModuleCallbacksTest, InstrumentedPasses) { 484 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)); 485 EXPECT_CALL(PassHandle, run(HasName("<string>"), _)) 486 .WillOnce(Invoke(getAnalysisResult)); 487 488 CallbacksHandle.registerPassInstrumentation(); 489 // Non-mock instrumentation not specifically mentioned below can be ignored. 490 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 491 492 // PassInstrumentation calls should happen in-sequence, in the same order 493 // as passes/analyses are scheduled. 494 ::testing::Sequence PISequence; 495 EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"), 496 HasName("<string>"))) 497 .InSequence(PISequence); 498 EXPECT_CALL(CallbacksHandle, 499 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), 500 HasName("<string>"))) 501 .InSequence(PISequence); 502 EXPECT_CALL( 503 CallbacksHandle, 504 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("<string>"))) 505 .InSequence(PISequence); 506 EXPECT_CALL(CallbacksHandle, 507 runAfterPass(HasNameRegex("MockPassHandle"), HasName("<string>"))) 508 .InSequence(PISequence); 509 510 StringRef PipelineText = "test-transform"; 511 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 512 << "Pipeline was: " << PipelineText; 513 514 PM.run(*M, AM); 515 } 516 517 TEST_F(ModuleCallbacksTest, InstrumentedSkippedPasses) { 518 CallbacksHandle.registerPassInstrumentation(); 519 // Non-mock instrumentation run here can safely be ignored. 520 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 521 522 // Skip the pass by returning false. 523 EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"), 524 HasName("<string>"))) 525 .WillOnce(Return(false)); 526 527 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)).Times(0); 528 EXPECT_CALL(PassHandle, run(HasName("<string>"), _)).Times(0); 529 530 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis 531 // as well. 532 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) 533 .Times(0); 534 EXPECT_CALL(CallbacksHandle, 535 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 536 .Times(0); 537 EXPECT_CALL(CallbacksHandle, 538 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 539 .Times(0); 540 541 StringRef PipelineText = "test-transform"; 542 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 543 << "Pipeline was: " << PipelineText; 544 545 PM.run(*M, AM); 546 } 547 548 TEST_F(FunctionCallbacksTest, Passes) { 549 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)); 550 EXPECT_CALL(PassHandle, run(HasName("foo"), _)) 551 .WillOnce(Invoke(getAnalysisResult)); 552 553 StringRef PipelineText = "test-transform"; 554 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 555 << "Pipeline was: " << PipelineText; 556 PM.run(*M, AM); 557 } 558 559 TEST_F(FunctionCallbacksTest, InstrumentedPasses) { 560 CallbacksHandle.registerPassInstrumentation(); 561 // Non-mock instrumentation not specifically mentioned below can be ignored. 562 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 563 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 564 565 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)); 566 EXPECT_CALL(PassHandle, run(HasName("foo"), _)) 567 .WillOnce(Invoke(getAnalysisResult)); 568 569 // PassInstrumentation calls should happen in-sequence, in the same order 570 // as passes/analyses are scheduled. 571 ::testing::Sequence PISequence; 572 EXPECT_CALL(CallbacksHandle, 573 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo"))) 574 .InSequence(PISequence); 575 EXPECT_CALL( 576 CallbacksHandle, 577 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo"))) 578 .InSequence(PISequence); 579 EXPECT_CALL( 580 CallbacksHandle, 581 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo"))) 582 .InSequence(PISequence); 583 EXPECT_CALL(CallbacksHandle, 584 runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo"))) 585 .InSequence(PISequence); 586 587 // Our mock pass does not invalidate IR. 588 EXPECT_CALL(CallbacksHandle, 589 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 590 .Times(0); 591 592 StringRef PipelineText = "test-transform"; 593 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 594 << "Pipeline was: " << PipelineText; 595 PM.run(*M, AM); 596 } 597 598 TEST_F(FunctionCallbacksTest, InstrumentedSkippedPasses) { 599 CallbacksHandle.registerPassInstrumentation(); 600 // Non-mock instrumentation run here can safely be ignored. 601 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 602 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 603 604 // Skip the pass by returning false. 605 EXPECT_CALL(CallbacksHandle, 606 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo"))) 607 .WillOnce(Return(false)); 608 609 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)).Times(0); 610 EXPECT_CALL(PassHandle, run(HasName("foo"), _)).Times(0); 611 612 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis 613 // as well. 614 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) 615 .Times(0); 616 EXPECT_CALL(CallbacksHandle, 617 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 618 .Times(0); 619 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) 620 .Times(0); 621 EXPECT_CALL(CallbacksHandle, 622 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 623 .Times(0); 624 EXPECT_CALL(CallbacksHandle, 625 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 626 .Times(0); 627 628 StringRef PipelineText = "test-transform"; 629 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 630 << "Pipeline was: " << PipelineText; 631 PM.run(*M, AM); 632 } 633 634 TEST_F(LoopCallbacksTest, Passes) { 635 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)); 636 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)) 637 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); 638 639 StringRef PipelineText = "test-transform"; 640 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 641 << "Pipeline was: " << PipelineText; 642 PM.run(*M, AM); 643 } 644 645 TEST_F(LoopCallbacksTest, InstrumentedPasses) { 646 CallbacksHandle.registerPassInstrumentation(); 647 // Non-mock instrumentation not specifically mentioned below can be ignored. 648 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 649 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 650 CallbacksHandle.ignoreNonMockPassInstrumentation("loop"); 651 652 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)); 653 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)) 654 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); 655 656 // PassInstrumentation calls should happen in-sequence, in the same order 657 // as passes/analyses are scheduled. 658 ::testing::Sequence PISequence; 659 EXPECT_CALL(CallbacksHandle, 660 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop"))) 661 .InSequence(PISequence); 662 EXPECT_CALL( 663 CallbacksHandle, 664 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop"))) 665 .InSequence(PISequence); 666 EXPECT_CALL( 667 CallbacksHandle, 668 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop"))) 669 .InSequence(PISequence); 670 EXPECT_CALL(CallbacksHandle, 671 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"))) 672 .InSequence(PISequence); 673 674 // Our mock pass does not invalidate IR. 675 EXPECT_CALL(CallbacksHandle, 676 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 677 .Times(0); 678 679 StringRef PipelineText = "test-transform"; 680 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 681 << "Pipeline was: " << PipelineText; 682 PM.run(*M, AM); 683 } 684 685 TEST_F(LoopCallbacksTest, InstrumentedInvalidatingPasses) { 686 CallbacksHandle.registerPassInstrumentation(); 687 // Non-mock instrumentation not specifically mentioned below can be ignored. 688 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 689 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 690 CallbacksHandle.ignoreNonMockPassInstrumentation("loop"); 691 692 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)); 693 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)) 694 .WillOnce(DoAll(WithArgs<0, 1, 2, 3>(Invoke(PassHandle.invalidateLoop)), 695 WithArgs<0, 1, 2>(Invoke(getAnalysisResult)))); 696 697 // PassInstrumentation calls should happen in-sequence, in the same order 698 // as passes/analyses are scheduled. 699 ::testing::Sequence PISequence; 700 EXPECT_CALL(CallbacksHandle, 701 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop"))) 702 .InSequence(PISequence); 703 EXPECT_CALL( 704 CallbacksHandle, 705 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop"))) 706 .InSequence(PISequence); 707 EXPECT_CALL( 708 CallbacksHandle, 709 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop"))) 710 .InSequence(PISequence); 711 EXPECT_CALL(CallbacksHandle, 712 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 713 .InSequence(PISequence); 714 EXPECT_CALL(CallbacksHandle, 715 runAfterPassInvalidated(HasNameRegex("^PassManager"))) 716 .InSequence(PISequence); 717 718 // Our mock pass invalidates IR, thus normal runAfterPass is never called. 719 EXPECT_CALL(CallbacksHandle, 720 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"))) 721 .Times(0); 722 723 StringRef PipelineText = "test-transform"; 724 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 725 << "Pipeline was: " << PipelineText; 726 PM.run(*M, AM); 727 } 728 729 TEST_F(LoopCallbacksTest, InstrumentedSkippedPasses) { 730 CallbacksHandle.registerPassInstrumentation(); 731 // Non-mock instrumentation run here can safely be ignored. 732 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 733 CallbacksHandle.ignoreNonMockPassInstrumentation("foo"); 734 CallbacksHandle.ignoreNonMockPassInstrumentation("loop"); 735 736 // Skip the pass by returning false. 737 EXPECT_CALL(CallbacksHandle, 738 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop"))) 739 .WillOnce(Return(false)); 740 741 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)).Times(0); 742 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)).Times(0); 743 744 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis 745 // as well. 746 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) 747 .Times(0); 748 EXPECT_CALL(CallbacksHandle, 749 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 750 .Times(0); 751 EXPECT_CALL(CallbacksHandle, 752 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 753 .Times(0); 754 EXPECT_CALL(CallbacksHandle, 755 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 756 .Times(0); 757 758 StringRef PipelineText = "test-transform"; 759 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 760 << "Pipeline was: " << PipelineText; 761 PM.run(*M, AM); 762 } 763 764 TEST_F(CGSCCCallbacksTest, Passes) { 765 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)); 766 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)) 767 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); 768 769 StringRef PipelineText = "test-transform"; 770 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 771 << "Pipeline was: " << PipelineText; 772 PM.run(*M, AM); 773 } 774 775 TEST_F(CGSCCCallbacksTest, InstrumentedPasses) { 776 CallbacksHandle.registerPassInstrumentation(); 777 // Non-mock instrumentation not specifically mentioned below can be ignored. 778 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 779 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)"); 780 781 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)); 782 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)) 783 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); 784 785 // PassInstrumentation calls should happen in-sequence, in the same order 786 // as passes/analyses are scheduled. 787 ::testing::Sequence PISequence; 788 EXPECT_CALL(CallbacksHandle, 789 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 790 .InSequence(PISequence); 791 EXPECT_CALL( 792 CallbacksHandle, 793 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)"))) 794 .InSequence(PISequence); 795 EXPECT_CALL( 796 CallbacksHandle, 797 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)"))) 798 .InSequence(PISequence); 799 EXPECT_CALL(CallbacksHandle, 800 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 801 .InSequence(PISequence); 802 803 // Our mock pass does not invalidate IR. 804 EXPECT_CALL(CallbacksHandle, 805 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 806 .Times(0); 807 808 StringRef PipelineText = "test-transform"; 809 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 810 << "Pipeline was: " << PipelineText; 811 PM.run(*M, AM); 812 } 813 814 TEST_F(CGSCCCallbacksTest, InstrumentedInvalidatingPasses) { 815 CallbacksHandle.registerPassInstrumentation(); 816 // Non-mock instrumentation not specifically mentioned below can be ignored. 817 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 818 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)"); 819 820 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)); 821 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)) 822 .WillOnce(DoAll(WithArgs<0, 1, 2, 3>(Invoke(PassHandle.invalidateSCC)), 823 WithArgs<0, 1, 2>(Invoke(getAnalysisResult)))); 824 825 // PassInstrumentation calls should happen in-sequence, in the same order 826 // as passes/analyses are scheduled. 827 ::testing::Sequence PISequence; 828 EXPECT_CALL(CallbacksHandle, 829 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 830 .InSequence(PISequence); 831 EXPECT_CALL( 832 CallbacksHandle, 833 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)"))) 834 .InSequence(PISequence); 835 EXPECT_CALL( 836 CallbacksHandle, 837 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)"))) 838 .InSequence(PISequence); 839 EXPECT_CALL(CallbacksHandle, 840 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 841 .InSequence(PISequence); 842 EXPECT_CALL(CallbacksHandle, 843 runAfterPassInvalidated(HasNameRegex("^PassManager"))) 844 .InSequence(PISequence); 845 846 // Our mock pass does invalidate IR, thus normal runAfterPass is never called. 847 EXPECT_CALL(CallbacksHandle, 848 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 849 .Times(0); 850 851 StringRef PipelineText = "test-transform"; 852 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 853 << "Pipeline was: " << PipelineText; 854 PM.run(*M, AM); 855 } 856 857 TEST_F(CGSCCCallbacksTest, InstrumentedSkippedPasses) { 858 CallbacksHandle.registerPassInstrumentation(); 859 // Non-mock instrumentation run here can safely be ignored. 860 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>"); 861 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)"); 862 863 // Skip the pass by returning false. 864 EXPECT_CALL(CallbacksHandle, 865 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) 866 .WillOnce(Return(false)); 867 868 // neither Analysis nor Pass are called. 869 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)).Times(0); 870 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)).Times(0); 871 872 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis 873 // as well. 874 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _)) 875 .Times(0); 876 EXPECT_CALL(CallbacksHandle, 877 runAfterPassInvalidated(HasNameRegex("MockPassHandle"))) 878 .Times(0); 879 EXPECT_CALL(CallbacksHandle, 880 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 881 .Times(0); 882 EXPECT_CALL(CallbacksHandle, 883 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _)) 884 .Times(0); 885 886 StringRef PipelineText = "test-transform"; 887 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 888 << "Pipeline was: " << PipelineText; 889 PM.run(*M, AM); 890 } 891 892 /// Test parsing of the names of analysis utilities for our mock analysis 893 /// for all IRUnits. 894 /// 895 /// We first require<>, then invalidate<> it, expecting the analysis to be run 896 /// once and subsequently invalidated. 897 TEST_F(ModuleCallbacksTest, AnalysisUtilities) { 898 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)); 899 EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _)); 900 901 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>"; 902 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 903 << "Pipeline was: " << PipelineText; 904 PM.run(*M, AM); 905 } 906 907 TEST_F(CGSCCCallbacksTest, PassUtilities) { 908 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)); 909 EXPECT_CALL(AnalysisHandle, invalidate(HasName("(foo)"), _, _)); 910 911 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>"; 912 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 913 << "Pipeline was: " << PipelineText; 914 PM.run(*M, AM); 915 } 916 917 TEST_F(FunctionCallbacksTest, AnalysisUtilities) { 918 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)); 919 EXPECT_CALL(AnalysisHandle, invalidate(HasName("foo"), _, _)); 920 921 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>"; 922 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 923 << "Pipeline was: " << PipelineText; 924 PM.run(*M, AM); 925 } 926 927 TEST_F(LoopCallbacksTest, PassUtilities) { 928 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)); 929 EXPECT_CALL(AnalysisHandle, invalidate(HasName("loop"), _, _)); 930 931 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>"; 932 933 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 934 << "Pipeline was: " << PipelineText; 935 PM.run(*M, AM); 936 } 937 938 /// Test parsing of the top-level pipeline. 939 /// 940 /// The ParseTopLevelPipeline callback takes over parsing of the entire pipeline 941 /// from PassBuilder if it encounters an unknown pipeline entry at the top level 942 /// (i.e., the first entry on the pipeline). 943 /// This test parses a pipeline named 'another-pipeline', whose only elements 944 /// may be the test-transform pass or the analysis utilities 945 TEST_F(ModuleCallbacksTest, ParseTopLevelPipeline) { 946 PB.registerParseTopLevelPipelineCallback([this]( 947 ModulePassManager &MPM, ArrayRef<PassBuilder::PipelineElement> Pipeline, 948 bool VerifyEachPass, bool DebugLogging) { 949 auto &FirstName = Pipeline.front().Name; 950 auto &InnerPipeline = Pipeline.front().InnerPipeline; 951 if (FirstName == "another-pipeline") { 952 for (auto &E : InnerPipeline) { 953 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", E.Name, PM)) 954 continue; 955 956 if (E.Name == "test-transform") { 957 PM.addPass(PassHandle.getPass()); 958 continue; 959 } 960 return false; 961 } 962 } 963 return true; 964 }); 965 966 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)); 967 EXPECT_CALL(PassHandle, run(HasName("<string>"), _)) 968 .WillOnce(Invoke(getAnalysisResult)); 969 EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _)); 970 971 StringRef PipelineText = 972 "another-pipeline(test-transform,invalidate<test-analysis>)"; 973 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) 974 << "Pipeline was: " << PipelineText; 975 PM.run(*M, AM); 976 977 /// Test the negative case 978 PipelineText = "another-pipeline(instcombine)"; 979 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Failed()) 980 << "Pipeline was: " << PipelineText; 981 } 982 } // end anonymous namespace 983