1 //===- CGSCCPassManagerTest.cpp -------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/Analysis/CGSCCPassManager.h"
11 #include "llvm/Analysis/LazyCallGraph.h"
12 #include "llvm/AsmParser/Parser.h"
13 #include "llvm/IR/Function.h"
14 #include "llvm/IR/InstIterator.h"
15 #include "llvm/IR/LLVMContext.h"
16 #include "llvm/IR/Module.h"
17 #include "llvm/IR/PassManager.h"
18 #include "llvm/Support/SourceMgr.h"
19 #include "gtest/gtest.h"
20 
21 using namespace llvm;
22 
23 namespace {
24 
25 class TestModuleAnalysis {
26 public:
27   struct Result {
Result__anonaea2d7d60111::TestModuleAnalysis::Result28     Result(int Count) : FunctionCount(Count) {}
29     int FunctionCount;
30   };
31 
ID()32   static void *ID() { return (void *)&PassID; }
name()33   static StringRef name() { return "TestModuleAnalysis"; }
34 
TestModuleAnalysis(int & Runs)35   TestModuleAnalysis(int &Runs) : Runs(Runs) {}
36 
run(Module & M,ModuleAnalysisManager & AM)37   Result run(Module &M, ModuleAnalysisManager &AM) {
38     ++Runs;
39     return Result(M.size());
40   }
41 
42 private:
43   static char PassID;
44 
45   int &Runs;
46 };
47 
48 char TestModuleAnalysis::PassID;
49 
50 class TestSCCAnalysis {
51 public:
52   struct Result {
Result__anonaea2d7d60111::TestSCCAnalysis::Result53     Result(int Count) : FunctionCount(Count) {}
54     int FunctionCount;
55   };
56 
ID()57   static void *ID() { return (void *)&PassID; }
name()58   static StringRef name() { return "TestSCCAnalysis"; }
59 
TestSCCAnalysis(int & Runs)60   TestSCCAnalysis(int &Runs) : Runs(Runs) {}
61 
run(LazyCallGraph::SCC & C,CGSCCAnalysisManager & AM)62   Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
63     ++Runs;
64     return Result(C.size());
65   }
66 
67 private:
68   static char PassID;
69 
70   int &Runs;
71 };
72 
73 char TestSCCAnalysis::PassID;
74 
75 class TestFunctionAnalysis {
76 public:
77   struct Result {
Result__anonaea2d7d60111::TestFunctionAnalysis::Result78     Result(int Count) : InstructionCount(Count) {}
79     int InstructionCount;
80   };
81 
ID()82   static void *ID() { return (void *)&PassID; }
name()83   static StringRef name() { return "TestFunctionAnalysis"; }
84 
TestFunctionAnalysis(int & Runs)85   TestFunctionAnalysis(int &Runs) : Runs(Runs) {}
86 
run(Function & F,FunctionAnalysisManager & AM)87   Result run(Function &F, FunctionAnalysisManager &AM) {
88     ++Runs;
89     int Count = 0;
90     for (Instruction &I : instructions(F)) {
91       (void)I;
92       ++Count;
93     }
94     return Result(Count);
95   }
96 
97 private:
98   static char PassID;
99 
100   int &Runs;
101 };
102 
103 char TestFunctionAnalysis::PassID;
104 
105 class TestImmutableFunctionAnalysis {
106 public:
107   struct Result {
invalidate__anonaea2d7d60111::TestImmutableFunctionAnalysis::Result108     bool invalidate(Function &, const PreservedAnalyses &) { return false; }
109   };
110 
ID()111   static void *ID() { return (void *)&PassID; }
name()112   static StringRef name() { return "TestImmutableFunctionAnalysis"; }
113 
TestImmutableFunctionAnalysis(int & Runs)114   TestImmutableFunctionAnalysis(int &Runs) : Runs(Runs) {}
115 
run(Function & F,FunctionAnalysisManager & AM)116   Result run(Function &F, FunctionAnalysisManager &AM) {
117     ++Runs;
118     return Result();
119   }
120 
121 private:
122   static char PassID;
123 
124   int &Runs;
125 };
126 
127 char TestImmutableFunctionAnalysis::PassID;
128 
129 struct TestModulePass {
TestModulePass__anonaea2d7d60111::TestModulePass130   TestModulePass(int &RunCount) : RunCount(RunCount) {}
131 
run__anonaea2d7d60111::TestModulePass132   PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
133     ++RunCount;
134     (void)AM.getResult<TestModuleAnalysis>(M);
135     return PreservedAnalyses::all();
136   }
137 
name__anonaea2d7d60111::TestModulePass138   static StringRef name() { return "TestModulePass"; }
139 
140   int &RunCount;
141 };
142 
143 struct TestSCCPass {
TestSCCPass__anonaea2d7d60111::TestSCCPass144   TestSCCPass(int &RunCount, int &AnalyzedInstrCount,
145               int &AnalyzedSCCFunctionCount, int &AnalyzedModuleFunctionCount,
146               bool OnlyUseCachedResults = false)
147       : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount),
148         AnalyzedSCCFunctionCount(AnalyzedSCCFunctionCount),
149         AnalyzedModuleFunctionCount(AnalyzedModuleFunctionCount),
150         OnlyUseCachedResults(OnlyUseCachedResults) {}
151 
run__anonaea2d7d60111::TestSCCPass152   PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
153     ++RunCount;
154 
155     const ModuleAnalysisManager &MAM =
156         AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C).getManager();
157     FunctionAnalysisManager &FAM =
158         AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager();
159     if (TestModuleAnalysis::Result *TMA =
160             MAM.getCachedResult<TestModuleAnalysis>(
161                 *C.begin()->getFunction().getParent()))
162       AnalyzedModuleFunctionCount += TMA->FunctionCount;
163 
164     if (OnlyUseCachedResults) {
165       // Hack to force the use of the cached interface.
166       if (TestSCCAnalysis::Result *AR = AM.getCachedResult<TestSCCAnalysis>(C))
167         AnalyzedSCCFunctionCount += AR->FunctionCount;
168       for (LazyCallGraph::Node &N : C)
169         if (TestFunctionAnalysis::Result *FAR =
170                 FAM.getCachedResult<TestFunctionAnalysis>(N.getFunction()))
171           AnalyzedInstrCount += FAR->InstructionCount;
172     } else {
173       // Typical path just runs the analysis as needed.
174       TestSCCAnalysis::Result &AR = AM.getResult<TestSCCAnalysis>(C);
175       AnalyzedSCCFunctionCount += AR.FunctionCount;
176       for (LazyCallGraph::Node &N : C) {
177         TestFunctionAnalysis::Result &FAR =
178             FAM.getResult<TestFunctionAnalysis>(N.getFunction());
179         AnalyzedInstrCount += FAR.InstructionCount;
180 
181         // Just ensure we get the immutable results.
182         (void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction());
183       }
184     }
185 
186     return PreservedAnalyses::all();
187   }
188 
name__anonaea2d7d60111::TestSCCPass189   static StringRef name() { return "TestSCCPass"; }
190 
191   int &RunCount;
192   int &AnalyzedInstrCount;
193   int &AnalyzedSCCFunctionCount;
194   int &AnalyzedModuleFunctionCount;
195   bool OnlyUseCachedResults;
196 };
197 
198 struct TestFunctionPass {
TestFunctionPass__anonaea2d7d60111::TestFunctionPass199   TestFunctionPass(int &RunCount) : RunCount(RunCount) {}
200 
run__anonaea2d7d60111::TestFunctionPass201   PreservedAnalyses run(Function &F, AnalysisManager<Function> &) {
202     ++RunCount;
203     return PreservedAnalyses::none();
204   }
205 
name__anonaea2d7d60111::TestFunctionPass206   static StringRef name() { return "TestFunctionPass"; }
207 
208   int &RunCount;
209 };
210 
parseIR(const char * IR)211 std::unique_ptr<Module> parseIR(const char *IR) {
212   // We just use a static context here. This is never called from multiple
213   // threads so it is harmless no matter how it is implemented. We just need
214   // the context to outlive the module which it does.
215   static LLVMContext C;
216   SMDiagnostic Err;
217   return parseAssemblyString(IR, Err, C);
218 }
219 
TEST(CGSCCPassManagerTest,Basic)220 TEST(CGSCCPassManagerTest, Basic) {
221   auto M = parseIR("define void @f() {\n"
222                    "entry:\n"
223                    "  call void @g()\n"
224                    "  call void @h1()\n"
225                    "  ret void\n"
226                    "}\n"
227                    "define void @g() {\n"
228                    "entry:\n"
229                    "  call void @g()\n"
230                    "  call void @x()\n"
231                    "  ret void\n"
232                    "}\n"
233                    "define void @h1() {\n"
234                    "entry:\n"
235                    "  call void @h2()\n"
236                    "  ret void\n"
237                    "}\n"
238                    "define void @h2() {\n"
239                    "entry:\n"
240                    "  call void @h3()\n"
241                    "  call void @x()\n"
242                    "  ret void\n"
243                    "}\n"
244                    "define void @h3() {\n"
245                    "entry:\n"
246                    "  call void @h1()\n"
247                    "  ret void\n"
248                    "}\n"
249                    "define void @x() {\n"
250                    "entry:\n"
251                    "  ret void\n"
252                    "}\n");
253   FunctionAnalysisManager FAM(/*DebugLogging*/ true);
254   int FunctionAnalysisRuns = 0;
255   FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
256   int ImmutableFunctionAnalysisRuns = 0;
257   FAM.registerPass([&] {
258     return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns);
259   });
260 
261   CGSCCAnalysisManager CGAM(/*DebugLogging*/ true);
262   int SCCAnalysisRuns = 0;
263   CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
264 
265   ModuleAnalysisManager MAM(/*DebugLogging*/ true);
266   int ModuleAnalysisRuns = 0;
267   MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
268   MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
269 
270   MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
271   MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
272   CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); });
273   CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
274   FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
275   FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
276 
277   ModulePassManager MPM(/*DebugLogging*/ true);
278   int ModulePassRunCount1 = 0;
279   MPM.addPass(TestModulePass(ModulePassRunCount1));
280 
281   CGSCCPassManager CGPM1(/*DebugLogging*/ true);
282   int SCCPassRunCount1 = 0;
283   int AnalyzedInstrCount1 = 0;
284   int AnalyzedSCCFunctionCount1 = 0;
285   int AnalyzedModuleFunctionCount1 = 0;
286   CGPM1.addPass(TestSCCPass(SCCPassRunCount1, AnalyzedInstrCount1,
287                             AnalyzedSCCFunctionCount1,
288                             AnalyzedModuleFunctionCount1));
289 
290   FunctionPassManager FPM1(/*DebugLogging*/ true);
291   int FunctionPassRunCount1 = 0;
292   FPM1.addPass(TestFunctionPass(FunctionPassRunCount1));
293   CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
294   MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
295 
296   MPM.run(*M, MAM);
297 
298   EXPECT_EQ(1, ModulePassRunCount1);
299 
300   EXPECT_EQ(1, ModuleAnalysisRuns);
301   EXPECT_EQ(4, SCCAnalysisRuns);
302   EXPECT_EQ(6, FunctionAnalysisRuns);
303   EXPECT_EQ(6, ImmutableFunctionAnalysisRuns);
304 
305   EXPECT_EQ(4, SCCPassRunCount1);
306   EXPECT_EQ(14, AnalyzedInstrCount1);
307   EXPECT_EQ(6, AnalyzedSCCFunctionCount1);
308   EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);
309 }
310 
311 }
312