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