1 //===- CGSCCPassManagerTest.cpp -------------------------------------------===// 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/Analysis/CGSCCPassManager.h" 11 #include "llvm/Analysis/LazyCallGraph.h" 12 #include "llvm/AsmParser/Parser.h" 13 #include "llvm/IR/Function.h" 14 #include "llvm/IR/InstIterator.h" 15 #include "llvm/IR/LLVMContext.h" 16 #include "llvm/IR/Module.h" 17 #include "llvm/IR/PassManager.h" 18 #include "llvm/Support/SourceMgr.h" 19 #include "gtest/gtest.h" 20 21 using namespace llvm; 22 23 namespace { 24 25 class TestModuleAnalysis : public AnalysisInfoMixin<TestModuleAnalysis> { 26 public: 27 struct Result { 28 Result(int Count) : FunctionCount(Count) {} 29 int FunctionCount; 30 }; 31 32 TestModuleAnalysis(int &Runs) : Runs(Runs) {} 33 34 Result run(Module &M, ModuleAnalysisManager &AM) { 35 ++Runs; 36 return Result(M.size()); 37 } 38 39 private: 40 friend AnalysisInfoMixin<TestModuleAnalysis>; 41 static AnalysisKey Key; 42 43 int &Runs; 44 }; 45 46 AnalysisKey TestModuleAnalysis::Key; 47 48 class TestSCCAnalysis : public AnalysisInfoMixin<TestSCCAnalysis> { 49 public: 50 struct Result { 51 Result(int Count) : FunctionCount(Count) {} 52 int FunctionCount; 53 }; 54 55 TestSCCAnalysis(int &Runs) : Runs(Runs) {} 56 57 Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &) { 58 ++Runs; 59 return Result(C.size()); 60 } 61 62 private: 63 friend AnalysisInfoMixin<TestSCCAnalysis>; 64 static AnalysisKey Key; 65 66 int &Runs; 67 }; 68 69 AnalysisKey TestSCCAnalysis::Key; 70 71 class TestFunctionAnalysis : public AnalysisInfoMixin<TestFunctionAnalysis> { 72 public: 73 struct Result { 74 Result(int Count) : InstructionCount(Count) {} 75 int InstructionCount; 76 }; 77 78 TestFunctionAnalysis(int &Runs) : Runs(Runs) {} 79 80 Result run(Function &F, FunctionAnalysisManager &AM) { 81 ++Runs; 82 int Count = 0; 83 for (Instruction &I : instructions(F)) { 84 (void)I; 85 ++Count; 86 } 87 return Result(Count); 88 } 89 90 private: 91 friend AnalysisInfoMixin<TestFunctionAnalysis>; 92 static AnalysisKey Key; 93 94 int &Runs; 95 }; 96 97 AnalysisKey TestFunctionAnalysis::Key; 98 99 class TestImmutableFunctionAnalysis 100 : public AnalysisInfoMixin<TestImmutableFunctionAnalysis> { 101 public: 102 struct Result { 103 bool invalidate(Function &, const PreservedAnalyses &, 104 FunctionAnalysisManager::Invalidator &) { 105 return false; 106 } 107 }; 108 109 TestImmutableFunctionAnalysis(int &Runs) : Runs(Runs) {} 110 111 Result run(Function &F, FunctionAnalysisManager &AM) { 112 ++Runs; 113 return Result(); 114 } 115 116 private: 117 friend AnalysisInfoMixin<TestImmutableFunctionAnalysis>; 118 static AnalysisKey Key; 119 120 int &Runs; 121 }; 122 123 AnalysisKey TestImmutableFunctionAnalysis::Key; 124 125 struct LambdaModulePass : public PassInfoMixin<LambdaModulePass> { 126 template <typename T> 127 LambdaModulePass(T &&Arg) : Func(std::forward<T>(Arg)) {} 128 129 PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM) { 130 return Func(F, AM); 131 } 132 133 std::function<PreservedAnalyses(Module &, ModuleAnalysisManager &)> Func; 134 }; 135 136 struct LambdaSCCPass : public PassInfoMixin<LambdaSCCPass> { 137 template <typename T> LambdaSCCPass(T &&Arg) : Func(std::forward<T>(Arg)) {} 138 139 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 140 LazyCallGraph &CG, CGSCCUpdateResult &UR) { 141 return Func(C, AM, CG, UR); 142 } 143 144 std::function<PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &, 145 LazyCallGraph &, CGSCCUpdateResult &)> 146 Func; 147 }; 148 149 struct LambdaFunctionPass : public PassInfoMixin<LambdaFunctionPass> { 150 template <typename T> 151 LambdaFunctionPass(T &&Arg) : Func(std::forward<T>(Arg)) {} 152 153 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) { 154 return Func(F, AM); 155 } 156 157 std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)> Func; 158 }; 159 160 std::unique_ptr<Module> parseIR(const char *IR) { 161 // We just use a static context here. This is never called from multiple 162 // threads so it is harmless no matter how it is implemented. We just need 163 // the context to outlive the module which it does. 164 static LLVMContext C; 165 SMDiagnostic Err; 166 return parseAssemblyString(IR, Err, C); 167 } 168 169 class CGSCCPassManagerTest : public ::testing::Test { 170 protected: 171 LLVMContext Context; 172 FunctionAnalysisManager FAM; 173 CGSCCAnalysisManager CGAM; 174 ModuleAnalysisManager MAM; 175 176 std::unique_ptr<Module> M; 177 178 public: 179 CGSCCPassManagerTest() 180 : FAM(/*DebugLogging*/ true), CGAM(/*DebugLogging*/ true), 181 MAM(/*DebugLogging*/ true), 182 M(parseIR( 183 // Define a module with the following call graph, where calls go 184 // out the bottom of nodes and enter the top: 185 // 186 // f 187 // |\ _ 188 // | \ / | 189 // g h1 | 190 // | | | 191 // | h2 | 192 // | | | 193 // | h3 | 194 // | / \_/ 195 // |/ 196 // x 197 // 198 "define void @f() {\n" 199 "entry:\n" 200 " call void @g()\n" 201 " call void @h1()\n" 202 " ret void\n" 203 "}\n" 204 "define void @g() {\n" 205 "entry:\n" 206 " call void @g()\n" 207 " call void @x()\n" 208 " ret void\n" 209 "}\n" 210 "define void @h1() {\n" 211 "entry:\n" 212 " call void @h2()\n" 213 " ret void\n" 214 "}\n" 215 "define void @h2() {\n" 216 "entry:\n" 217 " call void @h3()\n" 218 " call void @x()\n" 219 " ret void\n" 220 "}\n" 221 "define void @h3() {\n" 222 "entry:\n" 223 " call void @h1()\n" 224 " ret void\n" 225 "}\n" 226 "define void @x() {\n" 227 "entry:\n" 228 " ret void\n" 229 "}\n")) { 230 MAM.registerPass([&] { return LazyCallGraphAnalysis(); }); 231 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); 232 MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); }); 233 CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(); }); 234 CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); }); 235 FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); }); 236 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); }); 237 } 238 }; 239 240 TEST_F(CGSCCPassManagerTest, Basic) { 241 int FunctionAnalysisRuns = 0; 242 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 243 int ImmutableFunctionAnalysisRuns = 0; 244 FAM.registerPass([&] { 245 return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns); 246 }); 247 248 int SCCAnalysisRuns = 0; 249 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); 250 251 int ModuleAnalysisRuns = 0; 252 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); 253 254 ModulePassManager MPM(/*DebugLogging*/ true); 255 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 256 257 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 258 FunctionPassManager FPM1(/*DebugLogging*/ true); 259 int FunctionPassRunCount1 = 0; 260 FPM1.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) { 261 ++FunctionPassRunCount1; 262 return PreservedAnalyses::none(); 263 })); 264 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 265 266 int SCCPassRunCount1 = 0; 267 int AnalyzedInstrCount1 = 0; 268 int AnalyzedSCCFunctionCount1 = 0; 269 int AnalyzedModuleFunctionCount1 = 0; 270 CGPM1.addPass( 271 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 272 LazyCallGraph &CG, CGSCCUpdateResult &UR) { 273 ++SCCPassRunCount1; 274 275 const ModuleAnalysisManager &MAM = 276 AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG).getManager(); 277 FunctionAnalysisManager &FAM = 278 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); 279 if (TestModuleAnalysis::Result *TMA = 280 MAM.getCachedResult<TestModuleAnalysis>( 281 *C.begin()->getFunction().getParent())) 282 AnalyzedModuleFunctionCount1 += TMA->FunctionCount; 283 284 TestSCCAnalysis::Result &AR = AM.getResult<TestSCCAnalysis>(C, CG); 285 AnalyzedSCCFunctionCount1 += AR.FunctionCount; 286 for (LazyCallGraph::Node &N : C) { 287 TestFunctionAnalysis::Result &FAR = 288 FAM.getResult<TestFunctionAnalysis>(N.getFunction()); 289 AnalyzedInstrCount1 += FAR.InstructionCount; 290 291 // Just ensure we get the immutable results. 292 (void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction()); 293 } 294 295 return PreservedAnalyses::all(); 296 })); 297 298 FunctionPassManager FPM2(/*DebugLogging*/ true); 299 int FunctionPassRunCount2 = 0; 300 FPM2.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) { 301 ++FunctionPassRunCount2; 302 return PreservedAnalyses::none(); 303 })); 304 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 305 306 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 307 308 FunctionPassManager FPM3(/*DebugLogging*/ true); 309 int FunctionPassRunCount3 = 0; 310 FPM3.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) { 311 ++FunctionPassRunCount3; 312 return PreservedAnalyses::none(); 313 })); 314 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM3))); 315 316 MPM.run(*M, MAM); 317 318 EXPECT_EQ(4, SCCPassRunCount1); 319 EXPECT_EQ(6, FunctionPassRunCount1); 320 EXPECT_EQ(6, FunctionPassRunCount2); 321 EXPECT_EQ(6, FunctionPassRunCount3); 322 323 EXPECT_EQ(1, ModuleAnalysisRuns); 324 EXPECT_EQ(4, SCCAnalysisRuns); 325 EXPECT_EQ(6, FunctionAnalysisRuns); 326 EXPECT_EQ(6, ImmutableFunctionAnalysisRuns); 327 328 EXPECT_EQ(14, AnalyzedInstrCount1); 329 EXPECT_EQ(6, AnalyzedSCCFunctionCount1); 330 EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1); 331 } 332 333 // Test that an SCC pass which fails to preserve a module analysis does in fact 334 // invalidate that module analysis. 335 TEST_F(CGSCCPassManagerTest, TestSCCPassInvalidatesModuleAnalysis) { 336 int ModuleAnalysisRuns = 0; 337 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); 338 339 ModulePassManager MPM(/*DebugLogging*/ true); 340 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 341 342 // The first CGSCC run we preserve everything and make sure that works and 343 // the module analysis is available in the second CGSCC run from the one 344 // required module pass above. 345 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 346 int CountFoundModuleAnalysis1 = 0; 347 CGPM1.addPass( 348 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 349 LazyCallGraph &CG, CGSCCUpdateResult &UR) { 350 const auto &MAM = 351 AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG).getManager(); 352 auto *TMA = MAM.getCachedResult<TestModuleAnalysis>( 353 *C.begin()->getFunction().getParent()); 354 355 if (TMA) 356 ++CountFoundModuleAnalysis1; 357 358 return PreservedAnalyses::all(); 359 })); 360 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 361 362 // The second CGSCC run checks that the module analysis got preserved the 363 // previous time and in one SCC fails to preserve it. 364 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 365 int CountFoundModuleAnalysis2 = 0; 366 CGPM2.addPass( 367 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 368 LazyCallGraph &CG, CGSCCUpdateResult &UR) { 369 const auto &MAM = 370 AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG).getManager(); 371 auto *TMA = MAM.getCachedResult<TestModuleAnalysis>( 372 *C.begin()->getFunction().getParent()); 373 374 if (TMA) 375 ++CountFoundModuleAnalysis2; 376 377 // Only fail to preserve analyses on one SCC and make sure that gets 378 // propagated. 379 return C.getName() == "(g)" ? PreservedAnalyses::none() 380 : PreservedAnalyses::all(); 381 })); 382 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 383 384 // The third CGSCC run should fail to find a cached module analysis as it 385 // should have been invalidated by the above CGSCC run. 386 CGSCCPassManager CGPM3(/*DebugLogging*/ true); 387 int CountFoundModuleAnalysis3 = 0; 388 CGPM3.addPass( 389 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 390 LazyCallGraph &CG, CGSCCUpdateResult &UR) { 391 const auto &MAM = 392 AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG).getManager(); 393 auto *TMA = MAM.getCachedResult<TestModuleAnalysis>( 394 *C.begin()->getFunction().getParent()); 395 396 if (TMA) 397 ++CountFoundModuleAnalysis3; 398 399 return PreservedAnalyses::none(); 400 })); 401 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3))); 402 403 MPM.run(*M, MAM); 404 405 EXPECT_EQ(1, ModuleAnalysisRuns); 406 EXPECT_EQ(4, CountFoundModuleAnalysis1); 407 EXPECT_EQ(4, CountFoundModuleAnalysis2); 408 EXPECT_EQ(0, CountFoundModuleAnalysis3); 409 } 410 411 // Similar to the above, but test that this works for function passes embedded 412 // *within* a CGSCC layer. 413 TEST_F(CGSCCPassManagerTest, TestFunctionPassInsideCGSCCInvalidatesModuleAnalysis) { 414 int ModuleAnalysisRuns = 0; 415 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); 416 417 ModulePassManager MPM(/*DebugLogging*/ true); 418 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 419 420 // The first run we preserve everything and make sure that works and the 421 // module analysis is available in the second run from the one required 422 // module pass above. 423 FunctionPassManager FPM1(/*DebugLogging*/ true); 424 // Start true and mark false if we ever failed to find a module analysis 425 // because we expect this to succeed for each SCC. 426 bool FoundModuleAnalysis1 = true; 427 FPM1.addPass( 428 LambdaFunctionPass([&](Function &F, FunctionAnalysisManager &AM) { 429 const auto &MAM = 430 AM.getResult<ModuleAnalysisManagerFunctionProxy>(F).getManager(); 431 auto *TMA = MAM.getCachedResult<TestModuleAnalysis>(*F.getParent()); 432 433 if (!TMA) 434 FoundModuleAnalysis1 = false; 435 436 return PreservedAnalyses::all(); 437 })); 438 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 439 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 440 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 441 442 // The second run checks that the module analysis got preserved the previous 443 // time and in one function fails to preserve it. 444 FunctionPassManager FPM2(/*DebugLogging*/ true); 445 // Again, start true and mark false if we ever failed to find a module analysis 446 // because we expect this to succeed for each SCC. 447 bool FoundModuleAnalysis2 = true; 448 FPM2.addPass( 449 LambdaFunctionPass([&](Function &F, FunctionAnalysisManager &AM) { 450 const auto &MAM = 451 AM.getResult<ModuleAnalysisManagerFunctionProxy>(F).getManager(); 452 auto *TMA = MAM.getCachedResult<TestModuleAnalysis>(*F.getParent()); 453 454 if (!TMA) 455 FoundModuleAnalysis2 = false; 456 457 // Only fail to preserve analyses on one SCC and make sure that gets 458 // propagated. 459 return F.getName() == "h2" ? PreservedAnalyses::none() 460 : PreservedAnalyses::all(); 461 })); 462 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 463 CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 464 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 465 466 // The third run should fail to find a cached module analysis as it should 467 // have been invalidated by the above run. 468 FunctionPassManager FPM3(/*DebugLogging*/ true); 469 // Start false and mark true if we ever *succeeded* to find a module 470 // analysis, as we expect this to fail for every function. 471 bool FoundModuleAnalysis3 = false; 472 FPM3.addPass( 473 LambdaFunctionPass([&](Function &F, FunctionAnalysisManager &AM) { 474 const auto &MAM = 475 AM.getResult<ModuleAnalysisManagerFunctionProxy>(F).getManager(); 476 auto *TMA = MAM.getCachedResult<TestModuleAnalysis>(*F.getParent()); 477 478 if (TMA) 479 FoundModuleAnalysis3 = true; 480 481 return PreservedAnalyses::none(); 482 })); 483 CGSCCPassManager CGPM3(/*DebugLogging*/ true); 484 CGPM3.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM3))); 485 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3))); 486 487 MPM.run(*M, MAM); 488 489 EXPECT_EQ(1, ModuleAnalysisRuns); 490 EXPECT_TRUE(FoundModuleAnalysis1); 491 EXPECT_TRUE(FoundModuleAnalysis2); 492 EXPECT_FALSE(FoundModuleAnalysis3); 493 } 494 495 // Test that a Module pass which fails to preserve an SCC analysis in fact 496 // invalidates that analysis. 497 TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAnalysis) { 498 int SCCAnalysisRuns = 0; 499 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); 500 501 ModulePassManager MPM(/*DebugLogging*/ true); 502 503 // First force the analysis to be run. 504 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 505 CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC, 506 CGSCCAnalysisManager, LazyCallGraph &, 507 CGSCCUpdateResult &>()); 508 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 509 510 // Now run a module pass that preserves the LazyCallGraph and the proxy but 511 // not the SCC analysis. 512 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { 513 PreservedAnalyses PA; 514 PA.preserve<LazyCallGraphAnalysis>(); 515 PA.preserve<CGSCCAnalysisManagerModuleProxy>(); 516 PA.preserve<FunctionAnalysisManagerModuleProxy>(); 517 return PA; 518 })); 519 520 // And now a second CGSCC run which requires the SCC analysis again. This 521 // will trigger re-running it. 522 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 523 CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC, 524 CGSCCAnalysisManager, LazyCallGraph &, 525 CGSCCUpdateResult &>()); 526 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 527 528 MPM.run(*M, MAM); 529 // Two runs and four SCCs. 530 EXPECT_EQ(2 * 4, SCCAnalysisRuns); 531 } 532 533 // Check that marking the SCC analysis preserved is sufficient to avoid 534 // invaliadtion. This should only run the analysis once for each SCC. 535 TEST_F(CGSCCPassManagerTest, TestModulePassCanPreserveSCCAnalysis) { 536 int SCCAnalysisRuns = 0; 537 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); 538 539 ModulePassManager MPM(/*DebugLogging*/ true); 540 541 // First force the analysis to be run. 542 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 543 CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC, 544 CGSCCAnalysisManager, LazyCallGraph &, 545 CGSCCUpdateResult &>()); 546 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 547 548 // Now run a module pass that preserves each of the necessary components 549 // (but not everything). 550 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { 551 PreservedAnalyses PA; 552 PA.preserve<LazyCallGraphAnalysis>(); 553 PA.preserve<CGSCCAnalysisManagerModuleProxy>(); 554 PA.preserve<FunctionAnalysisManagerModuleProxy>(); 555 PA.preserve<TestSCCAnalysis>(); 556 return PA; 557 })); 558 559 // And now a second CGSCC run which requires the SCC analysis again but find 560 // it in the cache. 561 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 562 CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC, 563 CGSCCAnalysisManager, LazyCallGraph &, 564 CGSCCUpdateResult &>()); 565 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 566 567 MPM.run(*M, MAM); 568 // Four SCCs 569 EXPECT_EQ(4, SCCAnalysisRuns); 570 } 571 572 // Check that even when the analysis is preserved, if the SCC information isn't 573 // we still nuke things because the SCC keys could change. 574 TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAnalysisOnCGChange) { 575 int SCCAnalysisRuns = 0; 576 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); 577 578 ModulePassManager MPM(/*DebugLogging*/ true); 579 580 // First force the analysis to be run. 581 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 582 CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC, 583 CGSCCAnalysisManager, LazyCallGraph &, 584 CGSCCUpdateResult &>()); 585 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 586 587 // Now run a module pass that preserves the analysis but not the call 588 // graph or proxy. 589 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { 590 PreservedAnalyses PA; 591 PA.preserve<TestSCCAnalysis>(); 592 return PA; 593 })); 594 595 // And now a second CGSCC run which requires the SCC analysis again. 596 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 597 CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC, 598 CGSCCAnalysisManager, LazyCallGraph &, 599 CGSCCUpdateResult &>()); 600 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 601 602 MPM.run(*M, MAM); 603 // Two runs and four SCCs. 604 EXPECT_EQ(2 * 4, SCCAnalysisRuns); 605 } 606 607 // Test that an SCC pass which fails to preserve a Function analysis in fact 608 // invalidates that analysis. 609 TEST_F(CGSCCPassManagerTest, TestSCCPassInvalidatesFunctionAnalysis) { 610 int FunctionAnalysisRuns = 0; 611 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 612 613 // Create a very simple module with a single function and SCC to make testing 614 // these issues much easier. 615 std::unique_ptr<Module> M = parseIR("declare void @g()\n" 616 "declare void @h()\n" 617 "define void @f() {\n" 618 "entry:\n" 619 " call void @g()\n" 620 " call void @h()\n" 621 " ret void\n" 622 "}\n"); 623 624 CGSCCPassManager CGPM(/*DebugLogging*/ true); 625 626 // First force the analysis to be run. 627 FunctionPassManager FPM1(/*DebugLogging*/ true); 628 FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 629 CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 630 631 // Now run a module pass that preserves the LazyCallGraph and proxy but not 632 // the SCC analysis. 633 CGPM.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &, 634 LazyCallGraph &, CGSCCUpdateResult &) { 635 PreservedAnalyses PA; 636 PA.preserve<LazyCallGraphAnalysis>(); 637 return PA; 638 })); 639 640 // And now a second CGSCC run which requires the SCC analysis again. This 641 // will trigger re-running it. 642 FunctionPassManager FPM2(/*DebugLogging*/ true); 643 FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 644 CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 645 646 ModulePassManager MPM(/*DebugLogging*/ true); 647 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 648 MPM.run(*M, MAM); 649 EXPECT_EQ(2, FunctionAnalysisRuns); 650 } 651 652 // Check that marking the SCC analysis preserved is sufficient. This should 653 // only run the analysis once the SCC. 654 TEST_F(CGSCCPassManagerTest, TestSCCPassCanPreserveFunctionAnalysis) { 655 int FunctionAnalysisRuns = 0; 656 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 657 658 // Create a very simple module with a single function and SCC to make testing 659 // these issues much easier. 660 std::unique_ptr<Module> M = parseIR("declare void @g()\n" 661 "declare void @h()\n" 662 "define void @f() {\n" 663 "entry:\n" 664 " call void @g()\n" 665 " call void @h()\n" 666 " ret void\n" 667 "}\n"); 668 669 CGSCCPassManager CGPM(/*DebugLogging*/ true); 670 671 // First force the analysis to be run. 672 FunctionPassManager FPM1(/*DebugLogging*/ true); 673 FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 674 CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 675 676 // Now run a module pass that preserves each of the necessary components 677 // (but 678 // not everything). 679 CGPM.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &, 680 LazyCallGraph &, CGSCCUpdateResult &) { 681 PreservedAnalyses PA; 682 PA.preserve<LazyCallGraphAnalysis>(); 683 PA.preserve<TestFunctionAnalysis>(); 684 return PA; 685 })); 686 687 // And now a second CGSCC run which requires the SCC analysis again but find 688 // it in the cache. 689 FunctionPassManager FPM2(/*DebugLogging*/ true); 690 FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 691 CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 692 693 ModulePassManager MPM(/*DebugLogging*/ true); 694 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 695 MPM.run(*M, MAM); 696 EXPECT_EQ(1, FunctionAnalysisRuns); 697 } 698 699 // Note that there is no test for invalidating the call graph or other 700 // structure with an SCC pass because there is no mechanism to do that from 701 // withinsuch a pass. Instead, such a pass has to directly update the call 702 // graph structure. 703 704 // Test that a madule pass invalidates function analyses when the CGSCC proxies 705 // and pass manager. 706 TEST_F(CGSCCPassManagerTest, 707 TestModulePassInvalidatesFunctionAnalysisNestedInCGSCC) { 708 MAM.registerPass([&] { return LazyCallGraphAnalysis(); }); 709 710 int FunctionAnalysisRuns = 0; 711 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 712 713 ModulePassManager MPM(/*DebugLogging*/ true); 714 715 // First force the analysis to be run. 716 FunctionPassManager FPM1(/*DebugLogging*/ true); 717 FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 718 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 719 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 720 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 721 722 // Now run a module pass that preserves the LazyCallGraph and proxy but not 723 // the Function analysis. 724 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { 725 PreservedAnalyses PA; 726 PA.preserve<LazyCallGraphAnalysis>(); 727 PA.preserve<CGSCCAnalysisManagerModuleProxy>(); 728 return PA; 729 })); 730 731 // And now a second CGSCC run which requires the SCC analysis again. This 732 // will trigger re-running it. 733 FunctionPassManager FPM2(/*DebugLogging*/ true); 734 FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 735 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 736 CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 737 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 738 739 MPM.run(*M, MAM); 740 // Two runs and 6 functions. 741 EXPECT_EQ(2 * 6, FunctionAnalysisRuns); 742 } 743 744 // Check that by marking the function pass and FAM proxy as preserved, this 745 // propagates all the way through. 746 TEST_F(CGSCCPassManagerTest, 747 TestModulePassCanPreserveFunctionAnalysisNestedInCGSCC) { 748 MAM.registerPass([&] { return LazyCallGraphAnalysis(); }); 749 750 int FunctionAnalysisRuns = 0; 751 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 752 753 ModulePassManager MPM(/*DebugLogging*/ true); 754 755 // First force the analysis to be run. 756 FunctionPassManager FPM1(/*DebugLogging*/ true); 757 FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 758 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 759 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 760 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 761 762 // Now run a module pass that preserves the LazyCallGraph, the proxy, and 763 // the Function analysis. 764 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { 765 PreservedAnalyses PA; 766 PA.preserve<LazyCallGraphAnalysis>(); 767 PA.preserve<CGSCCAnalysisManagerModuleProxy>(); 768 PA.preserve<FunctionAnalysisManagerModuleProxy>(); 769 PA.preserve<TestFunctionAnalysis>(); 770 return PA; 771 })); 772 773 // And now a second CGSCC run which requires the SCC analysis again. This 774 // will trigger re-running it. 775 FunctionPassManager FPM2(/*DebugLogging*/ true); 776 FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 777 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 778 CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 779 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 780 781 MPM.run(*M, MAM); 782 // One run and 6 functions. 783 EXPECT_EQ(6, FunctionAnalysisRuns); 784 } 785 786 // Check that if the lazy call graph itself isn't preserved we still manage to 787 // invalidate everything. 788 TEST_F(CGSCCPassManagerTest, 789 TestModulePassInvalidatesFunctionAnalysisNestedInCGSCCOnCGChange) { 790 MAM.registerPass([&] { return LazyCallGraphAnalysis(); }); 791 792 int FunctionAnalysisRuns = 0; 793 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 794 795 ModulePassManager MPM(/*DebugLogging*/ true); 796 797 // First force the analysis to be run. 798 FunctionPassManager FPM1(/*DebugLogging*/ true); 799 FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 800 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 801 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 802 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 803 804 // Now run a module pass that preserves the LazyCallGraph but not the 805 // Function analysis. 806 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { 807 PreservedAnalyses PA; 808 return PA; 809 })); 810 811 // And now a second CGSCC run which requires the SCC analysis again. This 812 // will trigger re-running it. 813 FunctionPassManager FPM2(/*DebugLogging*/ true); 814 FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 815 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 816 CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 817 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 818 819 MPM.run(*M, MAM); 820 // Two runs and 6 functions. 821 EXPECT_EQ(2 * 6, FunctionAnalysisRuns); 822 } 823 824 /// A test CGSCC-level analysis pass which caches in its result another 825 /// analysis pass and uses it to serve queries. This requires the result to 826 /// invalidate itself when its dependency is invalidated. 827 /// 828 /// FIXME: Currently this doesn't also depend on a function analysis, and if it 829 /// did we would fail to invalidate it correctly. 830 struct TestIndirectSCCAnalysis 831 : public AnalysisInfoMixin<TestIndirectSCCAnalysis> { 832 struct Result { 833 Result(TestSCCAnalysis::Result &SCCDep, TestModuleAnalysis::Result &MDep) 834 : SCCDep(SCCDep), MDep(MDep) {} 835 TestSCCAnalysis::Result &SCCDep; 836 TestModuleAnalysis::Result &MDep; 837 838 bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA, 839 CGSCCAnalysisManager::Invalidator &Inv) { 840 auto PAC = PA.getChecker<TestIndirectSCCAnalysis>(); 841 return !(PAC.preserved() || 842 PAC.preservedSet<AllAnalysesOn<LazyCallGraph::SCC>>()) || 843 Inv.invalidate<TestSCCAnalysis>(C, PA); 844 } 845 }; 846 847 TestIndirectSCCAnalysis(int &Runs) : Runs(Runs) {} 848 849 /// Run the analysis pass over the function and return a result. 850 Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 851 LazyCallGraph &CG) { 852 ++Runs; 853 auto &SCCDep = AM.getResult<TestSCCAnalysis>(C, CG); 854 855 auto &ModuleProxy = AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG); 856 const ModuleAnalysisManager &MAM = ModuleProxy.getManager(); 857 // For the test, we insist that the module analysis starts off in the 858 // cache. 859 auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>( 860 *C.begin()->getFunction().getParent()); 861 // Register the dependency as module analysis dependencies have to be 862 // pre-registered on the proxy. 863 ModuleProxy.registerOuterAnalysisInvalidation<TestModuleAnalysis, 864 TestIndirectSCCAnalysis>(); 865 866 return Result(SCCDep, MDep); 867 } 868 869 private: 870 friend AnalysisInfoMixin<TestIndirectSCCAnalysis>; 871 static AnalysisKey Key; 872 873 int &Runs; 874 }; 875 876 AnalysisKey TestIndirectSCCAnalysis::Key; 877 878 /// A test analysis pass which caches in its result the result from the above 879 /// indirect analysis pass. 880 /// 881 /// This allows us to ensure that whenever an analysis pass is invalidated due 882 /// to dependencies (especially dependencies across IR units that trigger 883 /// asynchronous invalidation) we correctly detect that this may in turn cause 884 /// other analysis to be invalidated. 885 struct TestDoublyIndirectSCCAnalysis 886 : public AnalysisInfoMixin<TestDoublyIndirectSCCAnalysis> { 887 struct Result { 888 Result(TestIndirectSCCAnalysis::Result &IDep) : IDep(IDep) {} 889 TestIndirectSCCAnalysis::Result &IDep; 890 891 bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA, 892 CGSCCAnalysisManager::Invalidator &Inv) { 893 auto PAC = PA.getChecker<TestDoublyIndirectSCCAnalysis>(); 894 return !(PAC.preserved() || 895 PAC.preservedSet<AllAnalysesOn<LazyCallGraph::SCC>>()) || 896 Inv.invalidate<TestIndirectSCCAnalysis>(C, PA); 897 } 898 }; 899 900 TestDoublyIndirectSCCAnalysis(int &Runs) : Runs(Runs) {} 901 902 /// Run the analysis pass over the function and return a result. 903 Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 904 LazyCallGraph &CG) { 905 ++Runs; 906 auto &IDep = AM.getResult<TestIndirectSCCAnalysis>(C, CG); 907 return Result(IDep); 908 } 909 910 private: 911 friend AnalysisInfoMixin<TestDoublyIndirectSCCAnalysis>; 912 static AnalysisKey Key; 913 914 int &Runs; 915 }; 916 917 AnalysisKey TestDoublyIndirectSCCAnalysis::Key; 918 919 /// A test analysis pass which caches results from three different IR unit 920 /// layers and requires intermediate layers to correctly propagate the entire 921 /// distance. 922 struct TestIndirectFunctionAnalysis 923 : public AnalysisInfoMixin<TestIndirectFunctionAnalysis> { 924 struct Result { 925 Result(TestFunctionAnalysis::Result &FDep, TestModuleAnalysis::Result &MDep, 926 TestSCCAnalysis::Result &SCCDep) 927 : FDep(FDep), MDep(MDep), SCCDep(SCCDep) {} 928 TestFunctionAnalysis::Result &FDep; 929 TestModuleAnalysis::Result &MDep; 930 TestSCCAnalysis::Result &SCCDep; 931 932 bool invalidate(Function &F, const PreservedAnalyses &PA, 933 FunctionAnalysisManager::Invalidator &Inv) { 934 auto PAC = PA.getChecker<TestIndirectFunctionAnalysis>(); 935 return !(PAC.preserved() || 936 PAC.preservedSet<AllAnalysesOn<Function>>()) || 937 Inv.invalidate<TestFunctionAnalysis>(F, PA); 938 } 939 }; 940 941 TestIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {} 942 943 /// Run the analysis pass over the function and return a result. 944 Result run(Function &F, FunctionAnalysisManager &AM) { 945 ++Runs; 946 auto &FDep = AM.getResult<TestFunctionAnalysis>(F); 947 948 auto &ModuleProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F); 949 const ModuleAnalysisManager &MAM = ModuleProxy.getManager(); 950 // For the test, we insist that the module analysis starts off in the 951 // cache. 952 auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>(*F.getParent()); 953 // Register the dependency as module analysis dependencies have to be 954 // pre-registered on the proxy. 955 ModuleProxy.registerOuterAnalysisInvalidation< 956 TestModuleAnalysis, TestIndirectFunctionAnalysis>(); 957 958 // For thet test we assume this is run inside a CGSCC pass manager. 959 const LazyCallGraph &CG = 960 *MAM.getCachedResult<LazyCallGraphAnalysis>(*F.getParent()); 961 auto &CGSCCProxy = AM.getResult<CGSCCAnalysisManagerFunctionProxy>(F); 962 const CGSCCAnalysisManager &CGAM = CGSCCProxy.getManager(); 963 // For the test, we insist that the CGSCC analysis starts off in the cache. 964 auto &SCCDep = 965 *CGAM.getCachedResult<TestSCCAnalysis>(*CG.lookupSCC(*CG.lookup(F))); 966 // Register the dependency as CGSCC analysis dependencies have to be 967 // pre-registered on the proxy. 968 CGSCCProxy.registerOuterAnalysisInvalidation< 969 TestSCCAnalysis, TestIndirectFunctionAnalysis>(); 970 971 return Result(FDep, MDep, SCCDep); 972 } 973 974 private: 975 friend AnalysisInfoMixin<TestIndirectFunctionAnalysis>; 976 static AnalysisKey Key; 977 978 int &Runs; 979 }; 980 981 AnalysisKey TestIndirectFunctionAnalysis::Key; 982 983 TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) { 984 int ModuleAnalysisRuns = 0; 985 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); 986 987 int SCCAnalysisRuns = 0, IndirectSCCAnalysisRuns = 0, 988 DoublyIndirectSCCAnalysisRuns = 0; 989 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); 990 CGAM.registerPass( 991 [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns); }); 992 CGAM.registerPass([&] { 993 return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns); 994 }); 995 996 int FunctionAnalysisRuns = 0, IndirectFunctionAnalysisRuns = 0; 997 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 998 FAM.registerPass([&] { 999 return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns); 1000 }); 1001 1002 ModulePassManager MPM(/*DebugLogging*/ true); 1003 1004 int FunctionCount = 0; 1005 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1006 // First just use the analysis to get the function count and preserve 1007 // everything. 1008 CGPM.addPass( 1009 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 1010 LazyCallGraph &CG, CGSCCUpdateResult &) { 1011 auto &DoublyIndirectResult = 1012 AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); 1013 auto &IndirectResult = DoublyIndirectResult.IDep; 1014 FunctionCount += IndirectResult.SCCDep.FunctionCount; 1015 return PreservedAnalyses::all(); 1016 })); 1017 // Next, invalidate 1018 // - both analyses for the (f) and (x) SCCs, 1019 // - just the underlying (indirect) analysis for (g) SCC, and 1020 // - just the direct analysis for (h1,h2,h3) SCC. 1021 CGPM.addPass( 1022 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 1023 LazyCallGraph &CG, CGSCCUpdateResult &) { 1024 auto &DoublyIndirectResult = 1025 AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); 1026 auto &IndirectResult = DoublyIndirectResult.IDep; 1027 FunctionCount += IndirectResult.SCCDep.FunctionCount; 1028 auto PA = PreservedAnalyses::none(); 1029 if (C.getName() == "(g)") 1030 PA.preserve<TestSCCAnalysis>(); 1031 else if (C.getName() == "(h3, h1, h2)") 1032 PA.preserve<TestIndirectSCCAnalysis>(); 1033 return PA; 1034 })); 1035 // Finally, use the analysis again on each function, forcing re-computation 1036 // for all of them. 1037 CGPM.addPass( 1038 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 1039 LazyCallGraph &CG, CGSCCUpdateResult &) { 1040 auto &DoublyIndirectResult = 1041 AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); 1042 auto &IndirectResult = DoublyIndirectResult.IDep; 1043 FunctionCount += IndirectResult.SCCDep.FunctionCount; 1044 return PreservedAnalyses::all(); 1045 })); 1046 1047 // Create a second CGSCC pass manager. This will cause the module-level 1048 // invalidation to occur, which will force yet another invalidation of the 1049 // indirect SCC-level analysis as the module analysis it depends on gets 1050 // invalidated. 1051 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 1052 CGPM2.addPass( 1053 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 1054 LazyCallGraph &CG, CGSCCUpdateResult &) { 1055 auto &DoublyIndirectResult = 1056 AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); 1057 auto &IndirectResult = DoublyIndirectResult.IDep; 1058 FunctionCount += IndirectResult.SCCDep.FunctionCount; 1059 return PreservedAnalyses::all(); 1060 })); 1061 1062 // Add a requires pass to populate the module analysis and then our function 1063 // pass pipeline. 1064 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 1065 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1066 // Now require the module analysis again (it will have been invalidated once) 1067 // and then use it again from a function pass manager. 1068 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 1069 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 1070 MPM.run(*M, MAM); 1071 1072 // There are generally two possible runs for each of the four SCCs. But 1073 // for one SCC, we only invalidate the indirect analysis so the base one 1074 // only gets run seven times. 1075 EXPECT_EQ(7, SCCAnalysisRuns); 1076 // The module analysis pass should be run twice here. 1077 EXPECT_EQ(2, ModuleAnalysisRuns); 1078 // The indirect analysis is invalidated (either directly or indirectly) three 1079 // times for each of four SCCs. 1080 EXPECT_EQ(3 * 4, IndirectSCCAnalysisRuns); 1081 EXPECT_EQ(3 * 4, DoublyIndirectSCCAnalysisRuns); 1082 1083 // Four passes count each of six functions once (via SCCs). 1084 EXPECT_EQ(4 * 6, FunctionCount); 1085 } 1086 } 1087