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