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/Instructions.h" 16 #include "llvm/IR/LLVMContext.h" 17 #include "llvm/IR/Module.h" 18 #include "llvm/IR/PassManager.h" 19 #include "llvm/IR/Verifier.h" 20 #include "llvm/Support/SourceMgr.h" 21 #include "llvm/Transforms/Utils/CallGraphUpdater.h" 22 #include "gtest/gtest.h" 23 24 using namespace llvm; 25 26 namespace { 27 28 class TestModuleAnalysis : public AnalysisInfoMixin<TestModuleAnalysis> { 29 public: 30 struct Result { 31 Result(int Count) : FunctionCount(Count) {} 32 int FunctionCount; 33 bool invalidate(Module &, const PreservedAnalyses &PA, 34 ModuleAnalysisManager::Invalidator &) { 35 // Check whether the analysis or all analyses on modules have been 36 // preserved. 37 auto PAC = PA.getChecker<TestModuleAnalysis>(); 38 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Module>>()); 39 } 40 }; 41 42 TestModuleAnalysis(int &Runs) : Runs(Runs) {} 43 44 Result run(Module &M, ModuleAnalysisManager &AM) { 45 ++Runs; 46 return Result(M.size()); 47 } 48 49 private: 50 friend AnalysisInfoMixin<TestModuleAnalysis>; 51 static AnalysisKey Key; 52 53 int &Runs; 54 }; 55 56 AnalysisKey TestModuleAnalysis::Key; 57 58 class TestSCCAnalysis : public AnalysisInfoMixin<TestSCCAnalysis> { 59 public: 60 struct Result { 61 Result(int Count) : FunctionCount(Count) {} 62 int FunctionCount; 63 bool invalidate(LazyCallGraph::SCC &, const PreservedAnalyses &PA, 64 CGSCCAnalysisManager::Invalidator &) { 65 // Check whether the analysis or all analyses on SCCs have been 66 // preserved. 67 auto PAC = PA.getChecker<TestSCCAnalysis>(); 68 return !(PAC.preserved() || 69 PAC.preservedSet<AllAnalysesOn<LazyCallGraph::SCC>>()); 70 } 71 }; 72 73 TestSCCAnalysis(int &Runs) : Runs(Runs) {} 74 75 Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &) { 76 ++Runs; 77 return Result(C.size()); 78 } 79 80 private: 81 friend AnalysisInfoMixin<TestSCCAnalysis>; 82 static AnalysisKey Key; 83 84 int &Runs; 85 }; 86 87 AnalysisKey TestSCCAnalysis::Key; 88 89 class TestFunctionAnalysis : public AnalysisInfoMixin<TestFunctionAnalysis> { 90 public: 91 struct Result { 92 Result(int Count) : InstructionCount(Count) {} 93 int InstructionCount; 94 bool invalidate(Function &, const PreservedAnalyses &PA, 95 FunctionAnalysisManager::Invalidator &) { 96 // Check whether the analysis or all analyses on functions have been 97 // preserved. 98 auto PAC = PA.getChecker<TestFunctionAnalysis>(); 99 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>()); 100 } 101 }; 102 103 TestFunctionAnalysis(int &Runs) : Runs(Runs) {} 104 105 Result run(Function &F, FunctionAnalysisManager &AM) { 106 ++Runs; 107 int Count = 0; 108 for (Instruction &I : instructions(F)) { 109 (void)I; 110 ++Count; 111 } 112 return Result(Count); 113 } 114 115 private: 116 friend AnalysisInfoMixin<TestFunctionAnalysis>; 117 static AnalysisKey Key; 118 119 int &Runs; 120 }; 121 122 AnalysisKey TestFunctionAnalysis::Key; 123 124 class TestImmutableFunctionAnalysis 125 : public AnalysisInfoMixin<TestImmutableFunctionAnalysis> { 126 public: 127 struct Result { 128 bool invalidate(Function &, const PreservedAnalyses &, 129 FunctionAnalysisManager::Invalidator &) { 130 return false; 131 } 132 }; 133 134 TestImmutableFunctionAnalysis(int &Runs) : Runs(Runs) {} 135 136 Result run(Function &F, FunctionAnalysisManager &AM) { 137 ++Runs; 138 return Result(); 139 } 140 141 private: 142 friend AnalysisInfoMixin<TestImmutableFunctionAnalysis>; 143 static AnalysisKey Key; 144 145 int &Runs; 146 }; 147 148 AnalysisKey TestImmutableFunctionAnalysis::Key; 149 150 struct LambdaModulePass : public PassInfoMixin<LambdaModulePass> { 151 template <typename T> 152 LambdaModulePass(T &&Arg) : Func(std::forward<T>(Arg)) {} 153 154 PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM) { 155 return Func(F, AM); 156 } 157 158 std::function<PreservedAnalyses(Module &, ModuleAnalysisManager &)> Func; 159 }; 160 161 struct LambdaSCCPass : public PassInfoMixin<LambdaSCCPass> { 162 template <typename T> LambdaSCCPass(T &&Arg) : Func(std::forward<T>(Arg)) {} 163 164 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 165 LazyCallGraph &CG, CGSCCUpdateResult &UR) { 166 return Func(C, AM, CG, UR); 167 } 168 169 std::function<PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &, 170 LazyCallGraph &, CGSCCUpdateResult &)> 171 Func; 172 }; 173 174 struct LambdaFunctionPass : public PassInfoMixin<LambdaFunctionPass> { 175 template <typename T> 176 LambdaFunctionPass(T &&Arg) : Func(std::forward<T>(Arg)) {} 177 178 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) { 179 return Func(F, AM); 180 } 181 182 std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)> Func; 183 }; 184 185 std::unique_ptr<Module> parseIR(const char *IR) { 186 // We just use a static context here. This is never called from multiple 187 // threads so it is harmless no matter how it is implemented. We just need 188 // the context to outlive the module which it does. 189 static LLVMContext C; 190 SMDiagnostic Err; 191 return parseAssemblyString(IR, Err, C); 192 } 193 194 class CGSCCPassManagerTest : public ::testing::Test { 195 protected: 196 LLVMContext Context; 197 FunctionAnalysisManager FAM; 198 CGSCCAnalysisManager CGAM; 199 ModuleAnalysisManager MAM; 200 201 std::unique_ptr<Module> M; 202 203 public: 204 CGSCCPassManagerTest() 205 : FAM(/*DebugLogging*/ true), CGAM(/*DebugLogging*/ true), 206 MAM(/*DebugLogging*/ true), 207 M(parseIR( 208 // Define a module with the following call graph, where calls go 209 // out the bottom of nodes and enter the top: 210 // 211 // f 212 // |\ _ 213 // | \ / | 214 // g h1 | 215 // | | | 216 // | h2 | 217 // | | | 218 // | h3 | 219 // | / \_/ 220 // |/ 221 // x 222 // 223 "define void @x() {\n" 224 "entry:\n" 225 " ret void\n" 226 "}\n" 227 "define void @h3() {\n" 228 "entry:\n" 229 " call void @h1()\n" 230 " ret void\n" 231 "}\n" 232 "define void @h2() {\n" 233 "entry:\n" 234 " call void @h3()\n" 235 " call void @x()\n" 236 " ret void\n" 237 "}\n" 238 "define void @h1() {\n" 239 "entry:\n" 240 " call void @h2()\n" 241 " ret void\n" 242 "}\n" 243 "define void @g() {\n" 244 "entry:\n" 245 " call void @g()\n" 246 " call void @x()\n" 247 " ret void\n" 248 "}\n" 249 "define void @f() {\n" 250 "entry:\n" 251 " call void @g()\n" 252 " call void @h1()\n" 253 " ret void\n" 254 "}\n")) { 255 FAM.registerPass([&] { return TargetLibraryAnalysis(); }); 256 MAM.registerPass([&] { return LazyCallGraphAnalysis(); }); 257 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); 258 259 // Register required pass instrumentation analysis. 260 MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); 261 CGAM.registerPass([&] { return PassInstrumentationAnalysis(); }); 262 FAM.registerPass([&] { return PassInstrumentationAnalysis(); }); 263 264 // Cross-register proxies. 265 MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); }); 266 CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(); }); 267 CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); }); 268 FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); }); 269 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); }); 270 } 271 }; 272 273 TEST_F(CGSCCPassManagerTest, Basic) { 274 int FunctionAnalysisRuns = 0; 275 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 276 int ImmutableFunctionAnalysisRuns = 0; 277 FAM.registerPass([&] { 278 return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns); 279 }); 280 281 int SCCAnalysisRuns = 0; 282 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); 283 284 int ModuleAnalysisRuns = 0; 285 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); 286 287 ModulePassManager MPM(/*DebugLogging*/ true); 288 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 289 290 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 291 FunctionPassManager FPM1(/*DebugLogging*/ true); 292 int FunctionPassRunCount1 = 0; 293 FPM1.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) { 294 ++FunctionPassRunCount1; 295 return PreservedAnalyses::none(); 296 })); 297 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 298 299 int SCCPassRunCount1 = 0; 300 int AnalyzedInstrCount1 = 0; 301 int AnalyzedSCCFunctionCount1 = 0; 302 int AnalyzedModuleFunctionCount1 = 0; 303 CGPM1.addPass( 304 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 305 LazyCallGraph &CG, CGSCCUpdateResult &UR) { 306 ++SCCPassRunCount1; 307 308 // Note: The proper way to get to a module pass from a CGSCC pass is 309 // through the ModuleAnalysisManagerCGSCCProxy: 310 // ``` 311 // const auto &MAMProxy = 312 // AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG); 313 // ``` 314 // However getting a stateful analysis is incorrect usage, and the call 315 // to getCachedResult below asserts: 316 // ``` 317 // if (TestModuleAnalysis::Result *TMA = 318 // MAMProxy.getCachedResult<TestModuleAnalysis>( 319 // *C.begin()->getFunction().getParent())) 320 // AnalyzedModuleFunctionCount1 += TMA->FunctionCount; 321 // ``` 322 // For the purposes of this unittest, use the above MAM directly. 323 if (TestModuleAnalysis::Result *TMA = 324 MAM.getCachedResult<TestModuleAnalysis>( 325 *C.begin()->getFunction().getParent())) 326 AnalyzedModuleFunctionCount1 += TMA->FunctionCount; 327 328 FunctionAnalysisManager &FAM = 329 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); 330 TestSCCAnalysis::Result &AR = AM.getResult<TestSCCAnalysis>(C, CG); 331 AnalyzedSCCFunctionCount1 += AR.FunctionCount; 332 for (LazyCallGraph::Node &N : C) { 333 TestFunctionAnalysis::Result &FAR = 334 FAM.getResult<TestFunctionAnalysis>(N.getFunction()); 335 AnalyzedInstrCount1 += FAR.InstructionCount; 336 337 // Just ensure we get the immutable results. 338 (void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction()); 339 } 340 341 return PreservedAnalyses::all(); 342 })); 343 344 FunctionPassManager FPM2(/*DebugLogging*/ true); 345 int FunctionPassRunCount2 = 0; 346 FPM2.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) { 347 ++FunctionPassRunCount2; 348 return PreservedAnalyses::none(); 349 })); 350 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 351 352 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 353 354 FunctionPassManager FPM3(/*DebugLogging*/ true); 355 int FunctionPassRunCount3 = 0; 356 FPM3.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) { 357 ++FunctionPassRunCount3; 358 return PreservedAnalyses::none(); 359 })); 360 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM3))); 361 362 MPM.run(*M, MAM); 363 364 EXPECT_EQ(4, SCCPassRunCount1); 365 EXPECT_EQ(6, FunctionPassRunCount1); 366 EXPECT_EQ(6, FunctionPassRunCount2); 367 EXPECT_EQ(6, FunctionPassRunCount3); 368 369 EXPECT_EQ(1, ModuleAnalysisRuns); 370 EXPECT_EQ(4, SCCAnalysisRuns); 371 EXPECT_EQ(6, FunctionAnalysisRuns); 372 EXPECT_EQ(6, ImmutableFunctionAnalysisRuns); 373 374 EXPECT_EQ(14, AnalyzedInstrCount1); 375 EXPECT_EQ(6, AnalyzedSCCFunctionCount1); 376 EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1); 377 } 378 379 // Test that an SCC pass which fails to preserve a module analysis does in fact 380 // invalidate that module analysis. 381 TEST_F(CGSCCPassManagerTest, TestSCCPassInvalidatesModuleAnalysis) { 382 int ModuleAnalysisRuns = 0; 383 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); 384 385 ModulePassManager MPM(/*DebugLogging*/ true); 386 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 387 388 // The first CGSCC run we preserve everything and make sure that works and 389 // the module analysis is available in the second CGSCC run from the one 390 // required module pass above. 391 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 392 int CountFoundModuleAnalysis1 = 0; 393 CGPM1.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, 394 CGSCCAnalysisManager &AM, LazyCallGraph &CG, 395 CGSCCUpdateResult &UR) { 396 const auto &MAMProxy = AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG); 397 if (MAMProxy.cachedResultExists<TestModuleAnalysis>( 398 *C.begin()->getFunction().getParent())) 399 ++CountFoundModuleAnalysis1; 400 401 return PreservedAnalyses::all(); 402 })); 403 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 404 405 // The second CGSCC run checks that the module analysis got preserved the 406 // previous time and in one SCC fails to preserve it. 407 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 408 int CountFoundModuleAnalysis2 = 0; 409 CGPM2.addPass( 410 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 411 LazyCallGraph &CG, CGSCCUpdateResult &UR) { 412 const auto &MAMProxy = 413 AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG); 414 if (MAMProxy.cachedResultExists<TestModuleAnalysis>( 415 *C.begin()->getFunction().getParent())) 416 ++CountFoundModuleAnalysis2; 417 418 // Only fail to preserve analyses on one SCC and make sure that gets 419 // propagated. 420 return C.getName() == "(g)" ? PreservedAnalyses::none() 421 : PreservedAnalyses::all(); 422 })); 423 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 424 425 // The third CGSCC run should fail to find a cached module analysis as it 426 // should have been invalidated by the above CGSCC run. 427 CGSCCPassManager CGPM3(/*DebugLogging*/ true); 428 int CountFoundModuleAnalysis3 = 0; 429 CGPM3.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, 430 CGSCCAnalysisManager &AM, LazyCallGraph &CG, 431 CGSCCUpdateResult &UR) { 432 const auto &MAMProxy = AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG); 433 if (MAMProxy.cachedResultExists<TestModuleAnalysis>( 434 *C.begin()->getFunction().getParent())) 435 ++CountFoundModuleAnalysis3; 436 437 return PreservedAnalyses::none(); 438 })); 439 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3))); 440 441 MPM.run(*M, MAM); 442 443 EXPECT_EQ(1, ModuleAnalysisRuns); 444 EXPECT_EQ(4, CountFoundModuleAnalysis1); 445 EXPECT_EQ(4, CountFoundModuleAnalysis2); 446 EXPECT_EQ(0, CountFoundModuleAnalysis3); 447 } 448 449 // Similar to the above, but test that this works for function passes embedded 450 // *within* a CGSCC layer. 451 TEST_F(CGSCCPassManagerTest, TestFunctionPassInsideCGSCCInvalidatesModuleAnalysis) { 452 int ModuleAnalysisRuns = 0; 453 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); 454 455 ModulePassManager MPM(/*DebugLogging*/ true); 456 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 457 458 // The first run we preserve everything and make sure that works and the 459 // module analysis is available in the second run from the one required 460 // module pass above. 461 FunctionPassManager FPM1(/*DebugLogging*/ true); 462 // Start true and mark false if we ever failed to find a module analysis 463 // because we expect this to succeed for each SCC. 464 bool FoundModuleAnalysis1 = true; 465 FPM1.addPass(LambdaFunctionPass([&](Function &F, 466 FunctionAnalysisManager &AM) { 467 const auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F); 468 if (!MAMProxy.cachedResultExists<TestModuleAnalysis>(*F.getParent())) 469 FoundModuleAnalysis1 = false; 470 471 return PreservedAnalyses::all(); 472 })); 473 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 474 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 475 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 476 477 // The second run checks that the module analysis got preserved the previous 478 // time and in one function fails to preserve it. 479 FunctionPassManager FPM2(/*DebugLogging*/ true); 480 // Again, start true and mark false if we ever failed to find a module analysis 481 // because we expect this to succeed for each SCC. 482 bool FoundModuleAnalysis2 = true; 483 FPM2.addPass(LambdaFunctionPass([&](Function &F, 484 FunctionAnalysisManager &AM) { 485 const auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F); 486 if (!MAMProxy.cachedResultExists<TestModuleAnalysis>(*F.getParent())) 487 FoundModuleAnalysis2 = false; 488 489 // Only fail to preserve analyses on one SCC and make sure that gets 490 // propagated. 491 return F.getName() == "h2" ? PreservedAnalyses::none() 492 : PreservedAnalyses::all(); 493 })); 494 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 495 CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 496 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 497 498 // The third run should fail to find a cached module analysis as it should 499 // have been invalidated by the above run. 500 FunctionPassManager FPM3(/*DebugLogging*/ true); 501 // Start false and mark true if we ever *succeeded* to find a module 502 // analysis, as we expect this to fail for every function. 503 bool FoundModuleAnalysis3 = false; 504 FPM3.addPass(LambdaFunctionPass([&](Function &F, 505 FunctionAnalysisManager &AM) { 506 const auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F); 507 if (MAMProxy.cachedResultExists<TestModuleAnalysis>(*F.getParent())) 508 FoundModuleAnalysis3 = true; 509 510 return PreservedAnalyses::none(); 511 })); 512 CGSCCPassManager CGPM3(/*DebugLogging*/ true); 513 CGPM3.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM3))); 514 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3))); 515 516 MPM.run(*M, MAM); 517 518 EXPECT_EQ(1, ModuleAnalysisRuns); 519 EXPECT_TRUE(FoundModuleAnalysis1); 520 EXPECT_TRUE(FoundModuleAnalysis2); 521 EXPECT_FALSE(FoundModuleAnalysis3); 522 } 523 524 // Test that a Module pass which fails to preserve an SCC analysis in fact 525 // invalidates that analysis. 526 TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAnalysis) { 527 int SCCAnalysisRuns = 0; 528 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); 529 530 ModulePassManager MPM(/*DebugLogging*/ true); 531 532 // First force the analysis to be run. 533 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 534 CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC, 535 CGSCCAnalysisManager, LazyCallGraph &, 536 CGSCCUpdateResult &>()); 537 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 538 539 // Now run a module pass that preserves the LazyCallGraph and the proxy but 540 // not the SCC analysis. 541 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { 542 PreservedAnalyses PA; 543 PA.preserve<LazyCallGraphAnalysis>(); 544 PA.preserve<CGSCCAnalysisManagerModuleProxy>(); 545 PA.preserve<FunctionAnalysisManagerModuleProxy>(); 546 return PA; 547 })); 548 549 // And now a second CGSCC run which requires the SCC analysis again. This 550 // will trigger re-running it. 551 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 552 CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC, 553 CGSCCAnalysisManager, LazyCallGraph &, 554 CGSCCUpdateResult &>()); 555 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 556 557 MPM.run(*M, MAM); 558 // Two runs and four SCCs. 559 EXPECT_EQ(2 * 4, SCCAnalysisRuns); 560 } 561 562 // Check that marking the SCC analysis preserved is sufficient to avoid 563 // invaliadtion. This should only run the analysis once for each SCC. 564 TEST_F(CGSCCPassManagerTest, TestModulePassCanPreserveSCCAnalysis) { 565 int SCCAnalysisRuns = 0; 566 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); 567 568 ModulePassManager MPM(/*DebugLogging*/ true); 569 570 // First force the analysis to be run. 571 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 572 CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC, 573 CGSCCAnalysisManager, LazyCallGraph &, 574 CGSCCUpdateResult &>()); 575 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 576 577 // Now run a module pass that preserves each of the necessary components 578 // (but not everything). 579 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { 580 PreservedAnalyses PA; 581 PA.preserve<LazyCallGraphAnalysis>(); 582 PA.preserve<CGSCCAnalysisManagerModuleProxy>(); 583 PA.preserve<FunctionAnalysisManagerModuleProxy>(); 584 PA.preserve<TestSCCAnalysis>(); 585 return PA; 586 })); 587 588 // And now a second CGSCC run which requires the SCC analysis again but find 589 // it in the cache. 590 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 591 CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC, 592 CGSCCAnalysisManager, LazyCallGraph &, 593 CGSCCUpdateResult &>()); 594 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 595 596 MPM.run(*M, MAM); 597 // Four SCCs 598 EXPECT_EQ(4, SCCAnalysisRuns); 599 } 600 601 // Check that even when the analysis is preserved, if the SCC information isn't 602 // we still nuke things because the SCC keys could change. 603 TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAnalysisOnCGChange) { 604 int SCCAnalysisRuns = 0; 605 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); 606 607 ModulePassManager MPM(/*DebugLogging*/ true); 608 609 // First force the analysis to be run. 610 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 611 CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC, 612 CGSCCAnalysisManager, LazyCallGraph &, 613 CGSCCUpdateResult &>()); 614 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 615 616 // Now run a module pass that preserves the analysis but not the call 617 // graph or proxy. 618 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { 619 PreservedAnalyses PA; 620 PA.preserve<TestSCCAnalysis>(); 621 return PA; 622 })); 623 624 // And now a second CGSCC run which requires the SCC analysis again. 625 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 626 CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC, 627 CGSCCAnalysisManager, LazyCallGraph &, 628 CGSCCUpdateResult &>()); 629 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 630 631 MPM.run(*M, MAM); 632 // Two runs and four SCCs. 633 EXPECT_EQ(2 * 4, SCCAnalysisRuns); 634 } 635 636 // Test that an SCC pass which fails to preserve a Function analysis in fact 637 // invalidates that analysis. 638 TEST_F(CGSCCPassManagerTest, TestSCCPassInvalidatesFunctionAnalysis) { 639 int FunctionAnalysisRuns = 0; 640 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 641 642 // Create a very simple module with a single function and SCC to make testing 643 // these issues much easier. 644 std::unique_ptr<Module> M = parseIR("declare void @g()\n" 645 "declare void @h()\n" 646 "define void @f() {\n" 647 "entry:\n" 648 " call void @g()\n" 649 " call void @h()\n" 650 " ret void\n" 651 "}\n"); 652 653 CGSCCPassManager CGPM(/*DebugLogging*/ true); 654 655 // First force the analysis to be run. 656 FunctionPassManager FPM1(/*DebugLogging*/ true); 657 FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 658 CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 659 660 // Now run a module pass that preserves the LazyCallGraph and proxy but not 661 // the SCC analysis. 662 CGPM.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &, 663 LazyCallGraph &, CGSCCUpdateResult &) { 664 PreservedAnalyses PA; 665 PA.preserve<LazyCallGraphAnalysis>(); 666 return PA; 667 })); 668 669 // And now a second CGSCC run which requires the SCC analysis again. This 670 // will trigger re-running it. 671 FunctionPassManager FPM2(/*DebugLogging*/ true); 672 FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 673 CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 674 675 ModulePassManager MPM(/*DebugLogging*/ true); 676 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 677 MPM.run(*M, MAM); 678 EXPECT_EQ(2, FunctionAnalysisRuns); 679 } 680 681 // Check that marking the SCC analysis preserved is sufficient. This should 682 // only run the analysis once the SCC. 683 TEST_F(CGSCCPassManagerTest, TestSCCPassCanPreserveFunctionAnalysis) { 684 int FunctionAnalysisRuns = 0; 685 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 686 687 // Create a very simple module with a single function and SCC to make testing 688 // these issues much easier. 689 std::unique_ptr<Module> M = parseIR("declare void @g()\n" 690 "declare void @h()\n" 691 "define void @f() {\n" 692 "entry:\n" 693 " call void @g()\n" 694 " call void @h()\n" 695 " ret void\n" 696 "}\n"); 697 698 CGSCCPassManager CGPM(/*DebugLogging*/ true); 699 700 // First force the analysis to be run. 701 FunctionPassManager FPM1(/*DebugLogging*/ true); 702 FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 703 CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 704 705 // Now run a module pass that preserves each of the necessary components 706 // (but 707 // not everything). 708 CGPM.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &, 709 LazyCallGraph &, CGSCCUpdateResult &) { 710 PreservedAnalyses PA; 711 PA.preserve<LazyCallGraphAnalysis>(); 712 PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); 713 PA.preserve<TestFunctionAnalysis>(); 714 return PA; 715 })); 716 717 // And now a second CGSCC run which requires the SCC analysis again but find 718 // it in the cache. 719 FunctionPassManager FPM2(/*DebugLogging*/ true); 720 FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 721 CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 722 723 ModulePassManager MPM(/*DebugLogging*/ true); 724 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 725 MPM.run(*M, MAM); 726 EXPECT_EQ(1, FunctionAnalysisRuns); 727 } 728 729 // Note that there is no test for invalidating the call graph or other 730 // structure with an SCC pass because there is no mechanism to do that from 731 // withinsuch a pass. Instead, such a pass has to directly update the call 732 // graph structure. 733 734 // Test that a madule pass invalidates function analyses when the CGSCC proxies 735 // and pass manager. 736 TEST_F(CGSCCPassManagerTest, 737 TestModulePassInvalidatesFunctionAnalysisNestedInCGSCC) { 738 MAM.registerPass([&] { return LazyCallGraphAnalysis(); }); 739 740 int FunctionAnalysisRuns = 0; 741 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 742 743 ModulePassManager MPM(/*DebugLogging*/ true); 744 745 // First force the analysis to be run. 746 FunctionPassManager FPM1(/*DebugLogging*/ true); 747 FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 748 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 749 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 750 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 751 752 // Now run a module pass that preserves the LazyCallGraph and proxies but not 753 // the Function analysis. 754 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { 755 PreservedAnalyses PA; 756 PA.preserve<LazyCallGraphAnalysis>(); 757 PA.preserve<CGSCCAnalysisManagerModuleProxy>(); 758 PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); 759 PA.preserve<FunctionAnalysisManagerModuleProxy>(); 760 return PA; 761 })); 762 763 // And now a second CGSCC run which requires the SCC analysis again. This 764 // will trigger re-running it. 765 FunctionPassManager FPM2(/*DebugLogging*/ true); 766 FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 767 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 768 CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 769 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 770 771 MPM.run(*M, MAM); 772 // Two runs and 6 functions. 773 EXPECT_EQ(2 * 6, FunctionAnalysisRuns); 774 } 775 776 // Check that by marking the function pass and proxies as preserved, this 777 // propagates all the way through. 778 TEST_F(CGSCCPassManagerTest, 779 TestModulePassCanPreserveFunctionAnalysisNestedInCGSCC) { 780 MAM.registerPass([&] { return LazyCallGraphAnalysis(); }); 781 782 int FunctionAnalysisRuns = 0; 783 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 784 785 ModulePassManager MPM(/*DebugLogging*/ true); 786 787 // First force the analysis to be run. 788 FunctionPassManager FPM1(/*DebugLogging*/ true); 789 FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 790 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 791 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 792 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 793 794 // Now run a module pass that preserves the LazyCallGraph, the proxy, and 795 // the Function analysis. 796 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { 797 PreservedAnalyses PA; 798 PA.preserve<LazyCallGraphAnalysis>(); 799 PA.preserve<CGSCCAnalysisManagerModuleProxy>(); 800 PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); 801 PA.preserve<FunctionAnalysisManagerModuleProxy>(); 802 PA.preserve<TestFunctionAnalysis>(); 803 return PA; 804 })); 805 806 // And now a second CGSCC run which requires the SCC analysis again. This 807 // will trigger re-running it. 808 FunctionPassManager FPM2(/*DebugLogging*/ true); 809 FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 810 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 811 CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 812 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 813 814 MPM.run(*M, MAM); 815 // One run and 6 functions. 816 EXPECT_EQ(6, FunctionAnalysisRuns); 817 } 818 819 // Check that if the lazy call graph itself isn't preserved we still manage to 820 // invalidate everything. 821 TEST_F(CGSCCPassManagerTest, 822 TestModulePassInvalidatesFunctionAnalysisNestedInCGSCCOnCGChange) { 823 MAM.registerPass([&] { return LazyCallGraphAnalysis(); }); 824 825 int FunctionAnalysisRuns = 0; 826 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 827 828 ModulePassManager MPM(/*DebugLogging*/ true); 829 830 // First force the analysis to be run. 831 FunctionPassManager FPM1(/*DebugLogging*/ true); 832 FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 833 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 834 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 835 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 836 837 // Now run a module pass that preserves the LazyCallGraph but not the 838 // Function analysis. 839 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { 840 PreservedAnalyses PA; 841 return PA; 842 })); 843 844 // And now a second CGSCC run which requires the SCC analysis again. This 845 // will trigger re-running it. 846 FunctionPassManager FPM2(/*DebugLogging*/ true); 847 FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>()); 848 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 849 CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); 850 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 851 852 MPM.run(*M, MAM); 853 // Two runs and 6 functions. 854 EXPECT_EQ(2 * 6, FunctionAnalysisRuns); 855 } 856 857 /// A test CGSCC-level analysis pass which caches in its result another 858 /// analysis pass and uses it to serve queries. This requires the result to 859 /// invalidate itself when its dependency is invalidated. 860 /// 861 /// FIXME: Currently this doesn't also depend on a function analysis, and if it 862 /// did we would fail to invalidate it correctly. 863 struct TestIndirectSCCAnalysis 864 : public AnalysisInfoMixin<TestIndirectSCCAnalysis> { 865 struct Result { 866 Result(TestSCCAnalysis::Result &SCCDep, TestModuleAnalysis::Result &MDep) 867 : SCCDep(SCCDep), MDep(MDep) {} 868 TestSCCAnalysis::Result &SCCDep; 869 TestModuleAnalysis::Result &MDep; 870 871 bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA, 872 CGSCCAnalysisManager::Invalidator &Inv) { 873 auto PAC = PA.getChecker<TestIndirectSCCAnalysis>(); 874 return !(PAC.preserved() || 875 PAC.preservedSet<AllAnalysesOn<LazyCallGraph::SCC>>()) || 876 Inv.invalidate<TestSCCAnalysis>(C, PA); 877 } 878 }; 879 880 TestIndirectSCCAnalysis(int &Runs, ModuleAnalysisManager &MAM) 881 : Runs(Runs), MAM(MAM) {} 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 // For the test, we insist that the module analysis starts off in the 891 // cache. Getting a cached result that isn't stateless triggers an assert. 892 // auto &MDep = *ModuleProxy.getCachedResult<TestModuleAnalysis>( 893 // *C.begin()->getFunction().getParent()); 894 // Use MAM, for the purposes of this unittest. 895 auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>( 896 *C.begin()->getFunction().getParent()); 897 // Register the dependency as module analysis dependencies have to be 898 // pre-registered on the proxy. 899 ModuleProxy.registerOuterAnalysisInvalidation<TestModuleAnalysis, 900 TestIndirectSCCAnalysis>(); 901 902 return Result(SCCDep, MDep); 903 } 904 905 private: 906 friend AnalysisInfoMixin<TestIndirectSCCAnalysis>; 907 static AnalysisKey Key; 908 909 int &Runs; 910 ModuleAnalysisManager &MAM; 911 }; 912 913 AnalysisKey TestIndirectSCCAnalysis::Key; 914 915 /// A test analysis pass which caches in its result the result from the above 916 /// indirect analysis pass. 917 /// 918 /// This allows us to ensure that whenever an analysis pass is invalidated due 919 /// to dependencies (especially dependencies across IR units that trigger 920 /// asynchronous invalidation) we correctly detect that this may in turn cause 921 /// other analysis to be invalidated. 922 struct TestDoublyIndirectSCCAnalysis 923 : public AnalysisInfoMixin<TestDoublyIndirectSCCAnalysis> { 924 struct Result { 925 Result(TestIndirectSCCAnalysis::Result &IDep) : IDep(IDep) {} 926 TestIndirectSCCAnalysis::Result &IDep; 927 928 bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA, 929 CGSCCAnalysisManager::Invalidator &Inv) { 930 auto PAC = PA.getChecker<TestDoublyIndirectSCCAnalysis>(); 931 return !(PAC.preserved() || 932 PAC.preservedSet<AllAnalysesOn<LazyCallGraph::SCC>>()) || 933 Inv.invalidate<TestIndirectSCCAnalysis>(C, PA); 934 } 935 }; 936 937 TestDoublyIndirectSCCAnalysis(int &Runs) : Runs(Runs) {} 938 939 /// Run the analysis pass over the function and return a result. 940 Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 941 LazyCallGraph &CG) { 942 ++Runs; 943 auto &IDep = AM.getResult<TestIndirectSCCAnalysis>(C, CG); 944 return Result(IDep); 945 } 946 947 private: 948 friend AnalysisInfoMixin<TestDoublyIndirectSCCAnalysis>; 949 static AnalysisKey Key; 950 951 int &Runs; 952 }; 953 954 AnalysisKey TestDoublyIndirectSCCAnalysis::Key; 955 956 /// A test analysis pass which caches results from three different IR unit 957 /// layers and requires intermediate layers to correctly propagate the entire 958 /// distance. 959 struct TestIndirectFunctionAnalysis 960 : public AnalysisInfoMixin<TestIndirectFunctionAnalysis> { 961 struct Result { 962 Result(TestFunctionAnalysis::Result &FDep, TestModuleAnalysis::Result &MDep, 963 TestSCCAnalysis::Result &SCCDep) 964 : FDep(FDep), MDep(MDep), SCCDep(SCCDep) {} 965 TestFunctionAnalysis::Result &FDep; 966 TestModuleAnalysis::Result &MDep; 967 TestSCCAnalysis::Result &SCCDep; 968 969 bool invalidate(Function &F, const PreservedAnalyses &PA, 970 FunctionAnalysisManager::Invalidator &Inv) { 971 auto PAC = PA.getChecker<TestIndirectFunctionAnalysis>(); 972 return !(PAC.preserved() || 973 PAC.preservedSet<AllAnalysesOn<Function>>()) || 974 Inv.invalidate<TestFunctionAnalysis>(F, PA); 975 } 976 }; 977 978 TestIndirectFunctionAnalysis(int &Runs, ModuleAnalysisManager &MAM, 979 CGSCCAnalysisManager &CGAM) 980 : Runs(Runs), MAM(MAM), CGAM(CGAM) {} 981 982 /// Run the analysis pass over the function and return a result. 983 Result run(Function &F, FunctionAnalysisManager &AM) { 984 ++Runs; 985 auto &FDep = AM.getResult<TestFunctionAnalysis>(F); 986 987 auto &ModuleProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F); 988 // For the test, we insist that the module analysis starts off in the 989 // cache. Getting a cached result that isn't stateless triggers an assert. 990 // Use MAM, for the purposes of this unittest. 991 auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>(*F.getParent()); 992 // Register the dependency as module analysis dependencies have to be 993 // pre-registered on the proxy. 994 ModuleProxy.registerOuterAnalysisInvalidation< 995 TestModuleAnalysis, TestIndirectFunctionAnalysis>(); 996 997 // For the test we assume this is run inside a CGSCC pass manager. 998 // Use MAM, for the purposes of this unittest. 999 const LazyCallGraph &CG = 1000 *MAM.getCachedResult<LazyCallGraphAnalysis>(*F.getParent()); 1001 auto &CGSCCProxy = AM.getResult<CGSCCAnalysisManagerFunctionProxy>(F); 1002 // For the test, we insist that the CGSCC analysis starts off in the cache. 1003 // Getting a cached result that isn't stateless triggers an assert. 1004 // Use CGAM, for the purposes of this unittest. 1005 auto &SCCDep = 1006 *CGAM.getCachedResult<TestSCCAnalysis>(*CG.lookupSCC(*CG.lookup(F))); 1007 // Register the dependency as CGSCC analysis dependencies have to be 1008 // pre-registered on the proxy. 1009 CGSCCProxy.registerOuterAnalysisInvalidation< 1010 TestSCCAnalysis, TestIndirectFunctionAnalysis>(); 1011 1012 return Result(FDep, MDep, SCCDep); 1013 } 1014 1015 private: 1016 friend AnalysisInfoMixin<TestIndirectFunctionAnalysis>; 1017 static AnalysisKey Key; 1018 1019 int &Runs; 1020 ModuleAnalysisManager &MAM; 1021 CGSCCAnalysisManager &CGAM; 1022 }; 1023 1024 AnalysisKey TestIndirectFunctionAnalysis::Key; 1025 1026 TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) { 1027 int ModuleAnalysisRuns = 0; 1028 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); 1029 1030 int SCCAnalysisRuns = 0, IndirectSCCAnalysisRuns = 0, 1031 DoublyIndirectSCCAnalysisRuns = 0; 1032 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); 1033 CGAM.registerPass( 1034 [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns, MAM); }); 1035 CGAM.registerPass([&] { 1036 return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns); 1037 }); 1038 1039 int FunctionAnalysisRuns = 0, IndirectFunctionAnalysisRuns = 0; 1040 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 1041 FAM.registerPass([&] { 1042 return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns, MAM, 1043 CGAM); 1044 }); 1045 1046 ModulePassManager MPM(/*DebugLogging*/ true); 1047 1048 int FunctionCount = 0; 1049 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1050 // First just use the analysis to get the function count and preserve 1051 // everything. 1052 CGPM.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 CGPM.addPass(createCGSCCToFunctionPassAdaptor( 1062 RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>())); 1063 1064 // Next, invalidate 1065 // - both analyses for the (f) and (x) SCCs, 1066 // - just the underlying (indirect) analysis for (g) SCC, and 1067 // - just the direct analysis for (h1,h2,h3) SCC. 1068 CGPM.addPass( 1069 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 1070 LazyCallGraph &CG, CGSCCUpdateResult &) { 1071 auto &DoublyIndirectResult = 1072 AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); 1073 auto &IndirectResult = DoublyIndirectResult.IDep; 1074 FunctionCount += IndirectResult.SCCDep.FunctionCount; 1075 auto PA = PreservedAnalyses::none(); 1076 PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); 1077 PA.preserveSet<AllAnalysesOn<Function>>(); 1078 if (C.getName() == "(g)") 1079 PA.preserve<TestSCCAnalysis>(); 1080 else if (C.getName() == "(h3, h1, h2)") 1081 PA.preserve<TestIndirectSCCAnalysis>(); 1082 return PA; 1083 })); 1084 // Finally, use the analysis again on each SCC (and function), forcing 1085 // re-computation for all of them. 1086 CGPM.addPass( 1087 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 1088 LazyCallGraph &CG, CGSCCUpdateResult &) { 1089 auto &DoublyIndirectResult = 1090 AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); 1091 auto &IndirectResult = DoublyIndirectResult.IDep; 1092 FunctionCount += IndirectResult.SCCDep.FunctionCount; 1093 return PreservedAnalyses::all(); 1094 })); 1095 CGPM.addPass(createCGSCCToFunctionPassAdaptor( 1096 RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>())); 1097 1098 // Create a second CGSCC pass manager. This will cause the module-level 1099 // invalidation to occur, which will force yet another invalidation of the 1100 // indirect SCC-level analysis as the module analysis it depends on gets 1101 // invalidated. 1102 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 1103 CGPM2.addPass( 1104 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 1105 LazyCallGraph &CG, CGSCCUpdateResult &) { 1106 auto &DoublyIndirectResult = 1107 AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); 1108 auto &IndirectResult = DoublyIndirectResult.IDep; 1109 FunctionCount += IndirectResult.SCCDep.FunctionCount; 1110 return PreservedAnalyses::all(); 1111 })); 1112 CGPM2.addPass(createCGSCCToFunctionPassAdaptor( 1113 RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>())); 1114 1115 // Add a requires pass to populate the module analysis and then our CGSCC 1116 // pass pipeline. 1117 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 1118 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1119 // Now require the module analysis again (it will have been invalidated once) 1120 // and then use it again from our second CGSCC pipeline.. 1121 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 1122 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 1123 MPM.run(*M, MAM); 1124 1125 // There are generally two possible runs for each of the four SCCs. But 1126 // for one SCC, we only invalidate the indirect analysis so the base one 1127 // only gets run seven times. 1128 EXPECT_EQ(7, SCCAnalysisRuns); 1129 // The module analysis pass should be run twice here. 1130 EXPECT_EQ(2, ModuleAnalysisRuns); 1131 // The indirect analysis is invalidated (either directly or indirectly) three 1132 // times for each of four SCCs. 1133 EXPECT_EQ(3 * 4, IndirectSCCAnalysisRuns); 1134 EXPECT_EQ(3 * 4, DoublyIndirectSCCAnalysisRuns); 1135 1136 // We run the indirect function analysis once per function the first time. 1137 // Then we re-run it for every SCC but "(g)". Then we re-run it for every 1138 // function again. 1139 EXPECT_EQ(6 + 5 + 6, IndirectFunctionAnalysisRuns); 1140 1141 // Four passes count each of six functions once (via SCCs). 1142 EXPECT_EQ(4 * 6, FunctionCount); 1143 } 1144 1145 TEST_F(CGSCCPassManagerTest, TestAnalysisInvalidationCGSCCUpdate) { 1146 int ModuleAnalysisRuns = 0; 1147 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); 1148 1149 int SCCAnalysisRuns = 0, IndirectSCCAnalysisRuns = 0, 1150 DoublyIndirectSCCAnalysisRuns = 0; 1151 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); 1152 CGAM.registerPass( 1153 [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns, MAM); }); 1154 CGAM.registerPass([&] { 1155 return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns); 1156 }); 1157 1158 int FunctionAnalysisRuns = 0, IndirectFunctionAnalysisRuns = 0; 1159 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 1160 FAM.registerPass([&] { 1161 return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns, MAM, 1162 CGAM); 1163 }); 1164 1165 ModulePassManager MPM(/*DebugLogging*/ true); 1166 1167 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1168 // First just use the analysis to get the function count and preserve 1169 // everything. 1170 using RequireTestIndirectFunctionAnalysisPass = 1171 RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>; 1172 using RequireTestDoublyIndirectSCCAnalysisPass = 1173 RequireAnalysisPass<TestDoublyIndirectSCCAnalysis, LazyCallGraph::SCC, 1174 CGSCCAnalysisManager, LazyCallGraph &, 1175 CGSCCUpdateResult &>; 1176 CGPM.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); 1177 CGPM.addPass(createCGSCCToFunctionPassAdaptor( 1178 RequireTestIndirectFunctionAnalysisPass())); 1179 1180 // Next, we inject an SCC pass that invalidates everything for the `(h3, h1, 1181 // h2)` SCC but also deletes the call edge from `h2` to `h3` and updates the 1182 // CG. This should successfully invalidate (and force to be re-run) all the 1183 // analyses for that SCC and for the functions. 1184 CGPM.addPass( 1185 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 1186 LazyCallGraph &CG, CGSCCUpdateResult &UR) { 1187 (void)AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); 1188 if (C.getName() != "(h3, h1, h2)") 1189 return PreservedAnalyses::all(); 1190 1191 // Build the preserved set. 1192 auto PA = PreservedAnalyses::none(); 1193 PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); 1194 PA.preserve<TestIndirectSCCAnalysis>(); 1195 PA.preserve<TestDoublyIndirectSCCAnalysis>(); 1196 1197 // Delete the call from `h2` to `h3`. 1198 auto &H2N = *llvm::find_if( 1199 C, [](LazyCallGraph::Node &N) { return N.getName() == "h2"; }); 1200 auto &H2F = H2N.getFunction(); 1201 auto &H3F = *cast<CallInst>(H2F.begin()->begin())->getCalledFunction(); 1202 assert(H3F.getName() == "h3" && "Wrong called function!"); 1203 H2F.begin()->begin()->eraseFromParent(); 1204 // Insert a bitcast of `h3` so that we retain a ref edge to it. 1205 (void)CastInst::CreatePointerCast(&H3F, 1206 Type::getInt8PtrTy(H2F.getContext()), 1207 "dummy", &*H2F.begin()->begin()); 1208 1209 // Now update the call graph. 1210 auto &NewC = 1211 updateCGAndAnalysisManagerForFunctionPass(CG, C, H2N, AM, UR, FAM); 1212 assert(&NewC != &C && "Should get a new SCC due to update!"); 1213 (void)&NewC; 1214 1215 return PA; 1216 })); 1217 // Now use the analysis again on each SCC and function, forcing 1218 // re-computation for all of them. 1219 CGPM.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); 1220 CGPM.addPass(createCGSCCToFunctionPassAdaptor( 1221 RequireTestIndirectFunctionAnalysisPass())); 1222 1223 // Create another CGSCC pipeline that requires all the analyses again. 1224 CGSCCPassManager CGPM2(/*DebugLogging*/ true); 1225 CGPM2.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); 1226 CGPM2.addPass(createCGSCCToFunctionPassAdaptor( 1227 RequireTestIndirectFunctionAnalysisPass())); 1228 1229 // Next we inject an SCC pass that finds the `(h2)` SCC, adds a call to `h3` 1230 // back to `h2`, and then invalidates everything for what will then be the 1231 // `(h3, h1, h2)` SCC again. 1232 CGSCCPassManager CGPM3(/*DebugLogging*/ true); 1233 CGPM3.addPass( 1234 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 1235 LazyCallGraph &CG, CGSCCUpdateResult &UR) { 1236 (void)AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); 1237 if (C.getName() != "(h2)") 1238 return PreservedAnalyses::all(); 1239 1240 // Build the preserved set. 1241 auto PA = PreservedAnalyses::none(); 1242 PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); 1243 PA.preserve<TestIndirectSCCAnalysis>(); 1244 PA.preserve<TestDoublyIndirectSCCAnalysis>(); 1245 1246 // Delete the bitcast of `h3` that we added earlier. 1247 auto &H2N = *C.begin(); 1248 auto &H2F = H2N.getFunction(); 1249 auto &H3F = *cast<Function>(cast<BitCastInst>(H2F.begin()->begin())->getOperand(0)); 1250 assert(H3F.getName() == "h3" && "Wrong called function!"); 1251 H2F.begin()->begin()->eraseFromParent(); 1252 // And insert a call to `h3`. 1253 (void)CallInst::Create(&H3F, {}, "", &*H2F.begin()->begin()); 1254 1255 // Now update the call graph. 1256 auto &NewC = 1257 updateCGAndAnalysisManagerForFunctionPass(CG, C, H2N, AM, UR, FAM); 1258 assert(&NewC != &C && "Should get a new SCC due to update!"); 1259 (void)&NewC; 1260 1261 return PA; 1262 })); 1263 // Now use the analysis again on each SCC and function, forcing 1264 // re-computation for all of them. 1265 CGPM3.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); 1266 CGPM3.addPass(createCGSCCToFunctionPassAdaptor( 1267 RequireTestIndirectFunctionAnalysisPass())); 1268 1269 // Create a second CGSCC pass manager. This will cause the module-level 1270 // invalidation to occur, which will force yet another invalidation of the 1271 // indirect SCC-level analysis as the module analysis it depends on gets 1272 // invalidated. 1273 CGSCCPassManager CGPM4(/*DebugLogging*/ true); 1274 CGPM4.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); 1275 CGPM4.addPass(createCGSCCToFunctionPassAdaptor( 1276 RequireTestIndirectFunctionAnalysisPass())); 1277 1278 // Add a requires pass to populate the module analysis and then one of our 1279 // CGSCC pipelines. Repeat for all four CGSCC pipelines. 1280 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 1281 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1282 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 1283 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); 1284 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 1285 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3))); 1286 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); 1287 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM4))); 1288 MPM.run(*M, MAM); 1289 1290 // We run over four SCCs the first time. But then we split an SCC into three. 1291 // And then we merge those three back into one. However, this also 1292 // invalidates all three SCCs further down in the PO walk. 1293 EXPECT_EQ(4 + 3 + 3, SCCAnalysisRuns); 1294 // The module analysis pass should be run three times. 1295 EXPECT_EQ(3, ModuleAnalysisRuns); 1296 // We run over four SCCs the first time. Then over the two new ones. Then the 1297 // entire module is invalidated causing a full run over all seven. Then we 1298 // fold three SCCs back to one, re-compute for it and the two SCCs above it 1299 // in the graph, and then run over the whole module again. 1300 EXPECT_EQ(4 + 2 + 7 + 3 + 4, IndirectSCCAnalysisRuns); 1301 EXPECT_EQ(4 + 2 + 7 + 3 + 4, DoublyIndirectSCCAnalysisRuns); 1302 1303 // First we run over all six functions. Then we re-run it over three when we 1304 // split their SCCs. Then we re-run over the whole module. Then we re-run 1305 // over three functions merged back into a single SCC, then those three 1306 // functions again, the two functions in SCCs above it in the graph, and then 1307 // over the whole module again. 1308 EXPECT_EQ(6 + 3 + 6 + 3 + 2 + 6, FunctionAnalysisRuns); 1309 1310 // Re run the function analysis over the entire module, and then re-run it 1311 // over the `(h3, h1, h2)` SCC due to invalidation. Then we re-run it over 1312 // the entire module, then the three functions merged back into a single SCC, 1313 // those three functions again, then the two functions in SCCs above it in 1314 // the graph, and then over the whole module. 1315 EXPECT_EQ(6 + 3 + 6 + 3 + 2 + 6, IndirectFunctionAnalysisRuns); 1316 } 1317 1318 // The (negative) tests below check for assertions so we only run them if NDEBUG 1319 // is not defined. 1320 #ifndef NDEBUG 1321 1322 struct LambdaSCCPassNoPreserve : public PassInfoMixin<LambdaSCCPassNoPreserve> { 1323 template <typename T> 1324 LambdaSCCPassNoPreserve(T &&Arg) : Func(std::forward<T>(Arg)) {} 1325 1326 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 1327 LazyCallGraph &CG, CGSCCUpdateResult &UR) { 1328 Func(C, AM, CG, UR); 1329 PreservedAnalyses PA; 1330 // We update the core CGSCC data structures and so can preserve the proxy to 1331 // the function analysis manager. 1332 PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); 1333 return PA; 1334 } 1335 1336 std::function<void(LazyCallGraph::SCC &, CGSCCAnalysisManager &, 1337 LazyCallGraph &, CGSCCUpdateResult &)> 1338 Func; 1339 }; 1340 1341 TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses0) { 1342 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1343 CGPM.addPass(LambdaSCCPassNoPreserve( 1344 [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, 1345 CGSCCUpdateResult &UR) { 1346 if (C.getName() != "(h3, h1, h2)") 1347 return; 1348 1349 auto &FAM = 1350 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); 1351 Function *FnX = M->getFunction("x"); 1352 Function *FnH1 = M->getFunction("h1"); 1353 Function *FnH2 = M->getFunction("h2"); 1354 Function *FnH3 = M->getFunction("h3"); 1355 ASSERT_NE(FnX, nullptr); 1356 ASSERT_NE(FnH1, nullptr); 1357 ASSERT_NE(FnH2, nullptr); 1358 ASSERT_NE(FnH3, nullptr); 1359 1360 // And insert a call to `h1`, `h2`, and `h3`. 1361 Instruction *IP = &FnH2->getEntryBlock().front(); 1362 (void)CallInst::Create(FnH1, {}, "", IP); 1363 (void)CallInst::Create(FnH2, {}, "", IP); 1364 (void)CallInst::Create(FnH3, {}, "", IP); 1365 1366 auto &H2N = *llvm::find_if( 1367 C, [](LazyCallGraph::Node &N) { return N.getName() == "h2"; }); 1368 ASSERT_NO_FATAL_FAILURE( 1369 updateCGAndAnalysisManagerForCGSCCPass(CG, C, H2N, AM, UR, FAM)); 1370 })); 1371 1372 ModulePassManager MPM(/*DebugLogging*/ true); 1373 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1374 MPM.run(*M, MAM); 1375 } 1376 1377 TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses1) { 1378 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1379 CGPM.addPass(LambdaSCCPassNoPreserve([&](LazyCallGraph::SCC &C, 1380 CGSCCAnalysisManager &AM, 1381 LazyCallGraph &CG, 1382 CGSCCUpdateResult &UR) { 1383 if (C.getName() != "(h3, h1, h2)") 1384 return; 1385 1386 auto &FAM = 1387 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); 1388 Function *FnX = M->getFunction("x"); 1389 Function *FnH1 = M->getFunction("h1"); 1390 Function *FnH2 = M->getFunction("h2"); 1391 Function *FnH3 = M->getFunction("h3"); 1392 ASSERT_NE(FnX, nullptr); 1393 ASSERT_NE(FnH1, nullptr); 1394 ASSERT_NE(FnH2, nullptr); 1395 ASSERT_NE(FnH3, nullptr); 1396 1397 // And insert a call to `h1`, `h2`, and `h3`. 1398 Instruction *IP = &FnH2->getEntryBlock().front(); 1399 (void)CallInst::Create(FnH1, {}, "", IP); 1400 (void)CallInst::Create(FnH2, {}, "", IP); 1401 (void)CallInst::Create(FnH3, {}, "", IP); 1402 1403 auto &H2N = *llvm::find_if( 1404 C, [](LazyCallGraph::Node &N) { return N.getName() == "h2"; }); 1405 ASSERT_DEATH( 1406 updateCGAndAnalysisManagerForFunctionPass(CG, C, H2N, AM, UR, FAM), 1407 "Any new calls should be modeled as"); 1408 })); 1409 1410 ModulePassManager MPM(/*DebugLogging*/ true); 1411 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1412 MPM.run(*M, MAM); 1413 } 1414 1415 TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses2) { 1416 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1417 CGPM.addPass(LambdaSCCPassNoPreserve( 1418 [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, 1419 CGSCCUpdateResult &UR) { 1420 if (C.getName() != "(f)") 1421 return; 1422 1423 auto &FAM = 1424 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); 1425 Function *FnF = M->getFunction("f"); 1426 Function *FnH2 = M->getFunction("h2"); 1427 ASSERT_NE(FnF, nullptr); 1428 ASSERT_NE(FnH2, nullptr); 1429 1430 // And insert a call to `h2` 1431 Instruction *IP = &FnF->getEntryBlock().front(); 1432 (void)CallInst::Create(FnH2, {}, "", IP); 1433 1434 auto &FN = *llvm::find_if( 1435 C, [](LazyCallGraph::Node &N) { return N.getName() == "f"; }); 1436 ASSERT_NO_FATAL_FAILURE( 1437 updateCGAndAnalysisManagerForCGSCCPass(CG, C, FN, AM, UR, FAM)); 1438 })); 1439 1440 ModulePassManager MPM(/*DebugLogging*/ true); 1441 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1442 MPM.run(*M, MAM); 1443 } 1444 1445 TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses3) { 1446 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1447 CGPM.addPass(LambdaSCCPassNoPreserve([&](LazyCallGraph::SCC &C, 1448 CGSCCAnalysisManager &AM, 1449 LazyCallGraph &CG, 1450 CGSCCUpdateResult &UR) { 1451 if (C.getName() != "(f)") 1452 return; 1453 1454 auto &FAM = 1455 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); 1456 Function *FnF = M->getFunction("f"); 1457 Function *FnH2 = M->getFunction("h2"); 1458 ASSERT_NE(FnF, nullptr); 1459 ASSERT_NE(FnH2, nullptr); 1460 1461 // And insert a call to `h2` 1462 Instruction *IP = &FnF->getEntryBlock().front(); 1463 (void)CallInst::Create(FnH2, {}, "", IP); 1464 1465 auto &FN = *llvm::find_if( 1466 C, [](LazyCallGraph::Node &N) { return N.getName() == "f"; }); 1467 ASSERT_DEATH( 1468 updateCGAndAnalysisManagerForFunctionPass(CG, C, FN, AM, UR, FAM), 1469 "Any new calls should be modeled as"); 1470 })); 1471 1472 ModulePassManager MPM(/*DebugLogging*/ true); 1473 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1474 MPM.run(*M, MAM); 1475 } 1476 1477 TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses4) { 1478 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1479 CGPM.addPass(LambdaSCCPassNoPreserve( 1480 [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, 1481 CGSCCUpdateResult &UR) { 1482 if (C.getName() != "(f)") 1483 return; 1484 1485 auto &FAM = 1486 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); 1487 Function *FnF = M->getFunction("f"); 1488 Function *FnewF = Function::Create(FnF->getFunctionType(), 1489 FnF->getLinkage(), "newF", *M); 1490 BasicBlock *BB = BasicBlock::Create(FnewF->getContext(), "", FnewF); 1491 ReturnInst::Create(FnewF->getContext(), BB); 1492 1493 // Use the CallGraphUpdater to update the call graph for the new 1494 // function. 1495 CallGraphUpdater CGU; 1496 CGU.initialize(CG, C, AM, UR); 1497 CGU.registerOutlinedFunction(*FnewF); 1498 1499 // And insert a call to `newF` 1500 Instruction *IP = &FnF->getEntryBlock().front(); 1501 (void)CallInst::Create(FnewF, {}, "", IP); 1502 1503 auto &FN = *llvm::find_if( 1504 C, [](LazyCallGraph::Node &N) { return N.getName() == "f"; }); 1505 1506 ASSERT_NO_FATAL_FAILURE( 1507 updateCGAndAnalysisManagerForCGSCCPass(CG, C, FN, AM, UR, FAM)); 1508 })); 1509 1510 ModulePassManager MPM(/*DebugLogging*/ true); 1511 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1512 MPM.run(*M, MAM); 1513 } 1514 1515 TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses5) { 1516 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1517 CGPM.addPass(LambdaSCCPassNoPreserve([&](LazyCallGraph::SCC &C, 1518 CGSCCAnalysisManager &AM, 1519 LazyCallGraph &CG, 1520 CGSCCUpdateResult &UR) { 1521 if (C.getName() != "(f)") 1522 return; 1523 1524 auto &FAM = 1525 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); 1526 Function *FnF = M->getFunction("f"); 1527 Function *FnewF = 1528 Function::Create(FnF->getFunctionType(), FnF->getLinkage(), "newF", *M); 1529 BasicBlock *BB = BasicBlock::Create(FnewF->getContext(), "", FnewF); 1530 ReturnInst::Create(FnewF->getContext(), BB); 1531 1532 // Use the CallGraphUpdater to update the call graph for the new 1533 // function. 1534 CallGraphUpdater CGU; 1535 CGU.initialize(CG, C, AM, UR); 1536 CGU.registerOutlinedFunction(*FnewF); 1537 1538 // And insert a call to `newF` 1539 Instruction *IP = &FnF->getEntryBlock().front(); 1540 (void)CallInst::Create(FnewF, {}, "", IP); 1541 1542 auto &FN = *llvm::find_if( 1543 C, [](LazyCallGraph::Node &N) { return N.getName() == "f"; }); 1544 1545 ASSERT_DEATH( 1546 updateCGAndAnalysisManagerForFunctionPass(CG, C, FN, AM, UR, FAM), 1547 "Any new calls should be modeled as"); 1548 })); 1549 1550 ModulePassManager MPM(/*DebugLogging*/ true); 1551 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1552 MPM.run(*M, MAM); 1553 } 1554 1555 TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses6) { 1556 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1557 CGPM.addPass(LambdaSCCPassNoPreserve( 1558 [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, 1559 CGSCCUpdateResult &UR) { 1560 if (C.getName() != "(h3, h1, h2)") 1561 return; 1562 1563 Function *FnX = M->getFunction("x"); 1564 Function *FnH1 = M->getFunction("h1"); 1565 Function *FnH2 = M->getFunction("h2"); 1566 Function *FnH3 = M->getFunction("h3"); 1567 ASSERT_NE(FnX, nullptr); 1568 ASSERT_NE(FnH1, nullptr); 1569 ASSERT_NE(FnH2, nullptr); 1570 ASSERT_NE(FnH3, nullptr); 1571 1572 // And insert a call to `h1`, `h2`, and `h3`. 1573 Instruction *IP = &FnH2->getEntryBlock().front(); 1574 (void)CallInst::Create(FnH1, {}, "", IP); 1575 (void)CallInst::Create(FnH2, {}, "", IP); 1576 (void)CallInst::Create(FnH3, {}, "", IP); 1577 1578 // Use the CallGraphUpdater to update the call graph for the new 1579 // function. 1580 CallGraphUpdater CGU; 1581 CGU.initialize(CG, C, AM, UR); 1582 ASSERT_NO_FATAL_FAILURE(CGU.reanalyzeFunction(*FnH2)); 1583 })); 1584 1585 ModulePassManager MPM(/*DebugLogging*/ true); 1586 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1587 MPM.run(*M, MAM); 1588 } 1589 1590 TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses7) { 1591 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1592 CGPM.addPass(LambdaSCCPassNoPreserve( 1593 [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, 1594 CGSCCUpdateResult &UR) { 1595 if (C.getName() != "(f)") 1596 return; 1597 1598 Function *FnF = M->getFunction("f"); 1599 Function *FnH2 = M->getFunction("h2"); 1600 ASSERT_NE(FnF, nullptr); 1601 ASSERT_NE(FnH2, nullptr); 1602 1603 // And insert a call to `h2` 1604 Instruction *IP = &FnF->getEntryBlock().front(); 1605 (void)CallInst::Create(FnH2, {}, "", IP); 1606 1607 // Use the CallGraphUpdater to update the call graph for the new 1608 // function. 1609 CallGraphUpdater CGU; 1610 CGU.initialize(CG, C, AM, UR); 1611 ASSERT_NO_FATAL_FAILURE(CGU.reanalyzeFunction(*FnF)); 1612 })); 1613 1614 ModulePassManager MPM(/*DebugLogging*/ true); 1615 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1616 MPM.run(*M, MAM); 1617 } 1618 1619 TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses8) { 1620 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1621 CGPM.addPass(LambdaSCCPassNoPreserve( 1622 [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, 1623 CGSCCUpdateResult &UR) { 1624 if (C.getName() != "(f)") 1625 return; 1626 1627 Function *FnF = M->getFunction("f"); 1628 Function *FnewF = Function::Create(FnF->getFunctionType(), 1629 FnF->getLinkage(), "newF", *M); 1630 BasicBlock *BB = BasicBlock::Create(FnewF->getContext(), "", FnewF); 1631 auto *RI = ReturnInst::Create(FnewF->getContext(), BB); 1632 while (FnF->getEntryBlock().size() > 1) 1633 FnF->getEntryBlock().front().moveBefore(RI); 1634 ASSERT_NE(FnF, nullptr); 1635 1636 // Create an unsused constant that is referencing the old (=replaced) 1637 // function. 1638 ConstantExpr::getBitCast(FnF, Type::getInt8PtrTy(FnF->getContext())); 1639 1640 // Use the CallGraphUpdater to update the call graph. 1641 CallGraphUpdater CGU; 1642 CGU.initialize(CG, C, AM, UR); 1643 ASSERT_NO_FATAL_FAILURE(CGU.replaceFunctionWith(*FnF, *FnewF)); 1644 ASSERT_TRUE(FnF->isDeclaration()); 1645 ASSERT_EQ(FnF->getNumUses(), 0U); 1646 })); 1647 1648 ModulePassManager MPM(/*DebugLogging*/ true); 1649 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1650 MPM.run(*M, MAM); 1651 } 1652 1653 TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses9) { 1654 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1655 CGPM.addPass(LambdaSCCPassNoPreserve( 1656 [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, 1657 CGSCCUpdateResult &UR) { 1658 if (C.getName() != "(f)") 1659 return; 1660 1661 Function *FnF = M->getFunction("f"); 1662 1663 // Use the CallGraphUpdater to update the call graph. 1664 { 1665 CallGraphUpdater CGU; 1666 CGU.initialize(CG, C, AM, UR); 1667 ASSERT_NO_FATAL_FAILURE(CGU.removeFunction(*FnF)); 1668 ASSERT_EQ(M->getFunctionList().size(), 6U); 1669 } 1670 ASSERT_EQ(M->getFunctionList().size(), 5U); 1671 })); 1672 1673 ModulePassManager MPM(/*DebugLogging*/ true); 1674 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1675 MPM.run(*M, MAM); 1676 } 1677 1678 TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses10) { 1679 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1680 CGPM.addPass(LambdaSCCPassNoPreserve( 1681 [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, 1682 CGSCCUpdateResult &UR) { 1683 if (C.getName() != "(h3, h1, h2)") 1684 return; 1685 1686 Function *FnX = M->getFunction("x"); 1687 Function *FnH1 = M->getFunction("h1"); 1688 Function *FnH2 = M->getFunction("h2"); 1689 Function *FnH3 = M->getFunction("h3"); 1690 ASSERT_NE(FnX, nullptr); 1691 ASSERT_NE(FnH1, nullptr); 1692 ASSERT_NE(FnH2, nullptr); 1693 ASSERT_NE(FnH3, nullptr); 1694 1695 // And insert a call to `h1`, and `h3`. 1696 Instruction *IP = &FnH1->getEntryBlock().front(); 1697 (void)CallInst::Create(FnH1, {}, "", IP); 1698 (void)CallInst::Create(FnH3, {}, "", IP); 1699 1700 // Remove the `h2` call. 1701 ASSERT_TRUE(isa<CallBase>(IP)); 1702 ASSERT_EQ(cast<CallBase>(IP)->getCalledFunction(), FnH2); 1703 IP->eraseFromParent(); 1704 1705 // Use the CallGraphUpdater to update the call graph. 1706 CallGraphUpdater CGU; 1707 CGU.initialize(CG, C, AM, UR); 1708 ASSERT_NO_FATAL_FAILURE(CGU.reanalyzeFunction(*FnH1)); 1709 ASSERT_NO_FATAL_FAILURE(CGU.removeFunction(*FnH2)); 1710 })); 1711 1712 ModulePassManager MPM(/*DebugLogging*/ true); 1713 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1714 MPM.run(*M, MAM); 1715 } 1716 1717 // Start with call recursive f, create f -> g and ref recursive f. 1718 TEST_F(CGSCCPassManagerTest, TestInsertionOfNewFunctions1) { 1719 std::unique_ptr<Module> M = parseIR("define void @f() {\n" 1720 "entry:\n" 1721 " call void @f()\n" 1722 " ret void\n" 1723 "}\n"); 1724 1725 bool Ran = false; 1726 1727 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1728 CGPM.addPass(LambdaSCCPassNoPreserve( 1729 [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, 1730 CGSCCUpdateResult &UR) { 1731 if (Ran) 1732 return; 1733 1734 auto &FAM = 1735 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); 1736 1737 // Don't iterate over SCC while changing it. 1738 SmallVector<LazyCallGraph::Node *> Nodes; 1739 for (auto &N : C) 1740 Nodes.push_back(&N); 1741 1742 for (LazyCallGraph::Node *N : Nodes) { 1743 Function &F = N->getFunction(); 1744 if (F.getName() != "f") 1745 continue; 1746 1747 // Create a new function 'g'. 1748 auto *G = Function::Create(F.getFunctionType(), F.getLinkage(), 1749 F.getAddressSpace(), "g", F.getParent()); 1750 auto *GBB = 1751 BasicBlock::Create(F.getParent()->getContext(), "entry", G); 1752 (void)ReturnInst::Create(G->getContext(), GBB); 1753 // Instruct the LazyCallGraph to create a new node for 'g', as the 1754 // single node in a new SCC, into the call graph. As a result 1755 // the call graph is composed of a single RefSCC with two SCCs: 1756 // [(f), (g)]. 1757 1758 // "Demote" the 'f -> f' call edge to a ref edge. 1759 // 1. Erase the call edge from 'f' to 'f'. 1760 F.getEntryBlock().front().eraseFromParent(); 1761 // 2. Insert a ref edge from 'f' to 'f'. 1762 (void)CastInst::CreatePointerCast( 1763 &F, Type::getInt8PtrTy(F.getContext()), "f.ref", 1764 &F.getEntryBlock().front()); 1765 1766 ASSERT_FALSE(verifyModule(*F.getParent(), &errs())); 1767 1768 ASSERT_NO_FATAL_FAILURE( 1769 updateCGAndAnalysisManagerForCGSCCPass(CG, C, *N, AM, UR, FAM)) 1770 << "Updating the call graph with a demoted, self-referential " 1771 "call edge 'f -> f', and a newly inserted ref edge 'f -> g', " 1772 "caused a fatal failure"; 1773 1774 Ran = true; 1775 } 1776 })); 1777 1778 ModulePassManager MPM(/*DebugLogging*/ true); 1779 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1780 MPM.run(*M, MAM); 1781 ASSERT_TRUE(Ran); 1782 } 1783 1784 // Start with f, end with f -> (g1 <-> g2) and f -ref-> (h1 <-> h2). 1785 TEST_F(CGSCCPassManagerTest, TestInsertionOfNewFunctions2) { 1786 std::unique_ptr<Module> M = parseIR("define void @f() {\n" 1787 "entry:\n" 1788 " ret void\n" 1789 "}\n"); 1790 1791 bool Ran = false; 1792 1793 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1794 CGPM.addPass(LambdaSCCPassNoPreserve([&](LazyCallGraph::SCC &C, 1795 CGSCCAnalysisManager &AM, 1796 LazyCallGraph &CG, 1797 CGSCCUpdateResult &UR) { 1798 if (Ran) 1799 return; 1800 1801 auto &FAM = 1802 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); 1803 1804 // Don't iterate over SCC while changing it. 1805 SmallVector<LazyCallGraph::Node *> Nodes; 1806 for (auto &N : C) 1807 Nodes.push_back(&N); 1808 1809 for (LazyCallGraph::Node *N : Nodes) { 1810 Function &F = N->getFunction(); 1811 if (F.getName() != "f") 1812 continue; 1813 1814 // Create mutually recursive functions (call) 'g1' and 'g2'. 1815 auto *G1 = Function::Create(F.getFunctionType(), F.getLinkage(), 1816 F.getAddressSpace(), "g1", F.getParent()); 1817 auto *G2 = Function::Create(F.getFunctionType(), F.getLinkage(), 1818 F.getAddressSpace(), "g2", F.getParent()); 1819 BasicBlock *G1BB = 1820 BasicBlock::Create(F.getParent()->getContext(), "entry", G1); 1821 BasicBlock *G2BB = 1822 BasicBlock::Create(F.getParent()->getContext(), "entry", G2); 1823 (void)CallInst::Create(G2, {}, "", G1BB); 1824 (void)ReturnInst::Create(G1->getContext(), G1BB); 1825 (void)CallInst::Create(G1, {}, "", G2BB); 1826 (void)ReturnInst::Create(G2->getContext(), G2BB); 1827 1828 // Add 'f -> g1' call edge. 1829 (void)CallInst::Create(G1, {}, "", &F.getEntryBlock().front()); 1830 // Add 'f -> g2' call edge. 1831 (void)CallInst::Create(G2, {}, "", &F.getEntryBlock().front()); 1832 1833 // Create mutually recursive functions (ref only) 'h1' and 'h2'. 1834 auto *H1 = Function::Create(F.getFunctionType(), F.getLinkage(), 1835 F.getAddressSpace(), "h1", F.getParent()); 1836 auto *H2 = Function::Create(F.getFunctionType(), F.getLinkage(), 1837 F.getAddressSpace(), "h2", F.getParent()); 1838 BasicBlock *H1BB = 1839 BasicBlock::Create(F.getParent()->getContext(), "entry", H1); 1840 BasicBlock *H2BB = 1841 BasicBlock::Create(F.getParent()->getContext(), "entry", H2); 1842 (void)CastInst::CreatePointerCast(H2, Type::getInt8PtrTy(F.getContext()), 1843 "h2.ref", H1BB); 1844 (void)ReturnInst::Create(H1->getContext(), H1BB); 1845 (void)CastInst::CreatePointerCast(H1, Type::getInt8PtrTy(F.getContext()), 1846 "h1.ref", H2BB); 1847 (void)ReturnInst::Create(H2->getContext(), H2BB); 1848 1849 // Add 'f -> h1' ref edge. 1850 (void)CastInst::CreatePointerCast(H1, Type::getInt8PtrTy(F.getContext()), 1851 "h1.ref", &F.getEntryBlock().front()); 1852 // Add 'f -> h2' ref edge. 1853 (void)CastInst::CreatePointerCast(H2, Type::getInt8PtrTy(F.getContext()), 1854 "h2.ref", &F.getEntryBlock().front()); 1855 1856 ASSERT_FALSE(verifyModule(*F.getParent(), &errs())); 1857 1858 ASSERT_NO_FATAL_FAILURE( 1859 updateCGAndAnalysisManagerForCGSCCPass(CG, C, *N, AM, UR, FAM)) 1860 << "Updating the call graph with mutually recursive g1 <-> g2, h1 " 1861 "<-> h2 caused a fatal failure"; 1862 1863 Ran = true; 1864 } 1865 })); 1866 1867 ModulePassManager MPM(/*DebugLogging*/ true); 1868 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1869 MPM.run(*M, MAM); 1870 ASSERT_TRUE(Ran); 1871 } 1872 1873 TEST_F(CGSCCPassManagerTest, TestInsertionOfNewNonTrivialCallEdge) { 1874 std::unique_ptr<Module> M = parseIR("define void @f1() {\n" 1875 "entry:\n" 1876 " %a = bitcast void ()* @f4 to i8*\n" 1877 " %b = bitcast void ()* @f2 to i8*\n" 1878 " ret void\n" 1879 "}\n" 1880 "define void @f2() {\n" 1881 "entry:\n" 1882 " %a = bitcast void ()* @f1 to i8*\n" 1883 " %b = bitcast void ()* @f3 to i8*\n" 1884 " ret void\n" 1885 "}\n" 1886 "define void @f3() {\n" 1887 "entry:\n" 1888 " %a = bitcast void ()* @f2 to i8*\n" 1889 " %b = bitcast void ()* @f4 to i8*\n" 1890 " ret void\n" 1891 "}\n" 1892 "define void @f4() {\n" 1893 "entry:\n" 1894 " %a = bitcast void ()* @f3 to i8*\n" 1895 " %b = bitcast void ()* @f1 to i8*\n" 1896 " ret void\n" 1897 "}\n"); 1898 1899 bool Ran = false; 1900 CGSCCPassManager CGPM(/*DebugLogging*/ true); 1901 CGPM.addPass(LambdaSCCPassNoPreserve([&](LazyCallGraph::SCC &C, 1902 CGSCCAnalysisManager &AM, 1903 LazyCallGraph &CG, 1904 CGSCCUpdateResult &UR) { 1905 if (Ran) 1906 return; 1907 1908 auto &FAM = 1909 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); 1910 1911 // Don't iterate over SCC while changing it. 1912 SmallVector<LazyCallGraph::Node *> Nodes; 1913 for (auto &N : C) 1914 Nodes.push_back(&N); 1915 1916 for (LazyCallGraph::Node *N : Nodes) { 1917 Function &F = N->getFunction(); 1918 if (F.getName() != "f1") 1919 continue; 1920 1921 Function *F3 = F.getParent()->getFunction("f3"); 1922 ASSERT_TRUE(F3 != nullptr); 1923 1924 // Create call from f1 to f3. 1925 (void)CallInst::Create(F3, {}, "", F.getEntryBlock().getTerminator()); 1926 1927 ASSERT_NO_FATAL_FAILURE( 1928 updateCGAndAnalysisManagerForCGSCCPass(CG, C, *N, AM, UR, FAM)) 1929 << "Updating the call graph with mutually recursive g1 <-> g2, h1 " 1930 "<-> h2 caused a fatal failure"; 1931 1932 Ran = true; 1933 } 1934 })); 1935 1936 ModulePassManager MPM(/*DebugLogging*/ true); 1937 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); 1938 MPM.run(*M, MAM); 1939 1940 ASSERT_TRUE(Ran); 1941 } 1942 1943 #endif 1944 } // namespace 1945