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 {
28     Result(int Count) : FunctionCount(Count) {}
29     int FunctionCount;
30   };
31 
32   static void *ID() { return (void *)&PassID; }
33   static StringRef name() { return "TestModuleAnalysis"; }
34 
35   TestModuleAnalysis(int &Runs) : Runs(Runs) {}
36 
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 {
53     Result(int Count) : FunctionCount(Count) {}
54     int FunctionCount;
55   };
56 
57   static void *ID() { return (void *)&PassID; }
58   static StringRef name() { return "TestSCCAnalysis"; }
59 
60   TestSCCAnalysis(int &Runs) : Runs(Runs) {}
61 
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 {
78     Result(int Count) : InstructionCount(Count) {}
79     int InstructionCount;
80   };
81 
82   static void *ID() { return (void *)&PassID; }
83   static StringRef name() { return "TestFunctionAnalysis"; }
84 
85   TestFunctionAnalysis(int &Runs) : Runs(Runs) {}
86 
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 {
108     bool invalidate(Function &, const PreservedAnalyses &) { return false; }
109   };
110 
111   static void *ID() { return (void *)&PassID; }
112   static StringRef name() { return "TestImmutableFunctionAnalysis"; }
113 
114   TestImmutableFunctionAnalysis(int &Runs) : Runs(Runs) {}
115 
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 {
130   TestModulePass(int &RunCount) : RunCount(RunCount) {}
131 
132   PreservedAnalyses run(Module &M, ModuleAnalysisManager *AM) {
133     ++RunCount;
134     (void)AM->getResult<TestModuleAnalysis>(M);
135     return PreservedAnalyses::all();
136   }
137 
138   static StringRef name() { return "TestModulePass"; }
139 
140   int &RunCount;
141 };
142 
143 struct TestSCCPass {
144   TestSCCPass(int &RunCount, int &AnalyzedInstrCount,
145                    int &AnalyzedSCCFunctionCount,
146                    int &AnalyzedModuleFunctionCount,
147                    bool OnlyUseCachedResults = false)
148       : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount),
149         AnalyzedSCCFunctionCount(AnalyzedSCCFunctionCount),
150         AnalyzedModuleFunctionCount(AnalyzedModuleFunctionCount),
151         OnlyUseCachedResults(OnlyUseCachedResults) {}
152 
153   PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager *AM) {
154     ++RunCount;
155 
156     const ModuleAnalysisManager &MAM =
157         AM->getResult<ModuleAnalysisManagerCGSCCProxy>(C).getManager();
158     FunctionAnalysisManager &FAM =
159         AM->getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager();
160     if (TestModuleAnalysis::Result *TMA =
161             MAM.getCachedResult<TestModuleAnalysis>(
162                 *C.begin()->getFunction().getParent()))
163       AnalyzedModuleFunctionCount += TMA->FunctionCount;
164 
165     if (OnlyUseCachedResults) {
166       // Hack to force the use of the cached interface.
167       if (TestSCCAnalysis::Result *AR =
168               AM->getCachedResult<TestSCCAnalysis>(C))
169         AnalyzedSCCFunctionCount += AR->FunctionCount;
170       for (LazyCallGraph::Node &N : C)
171         if (TestFunctionAnalysis::Result *FAR =
172                 FAM.getCachedResult<TestFunctionAnalysis>(N.getFunction()))
173           AnalyzedInstrCount += FAR->InstructionCount;
174     } else {
175       // Typical path just runs the analysis as needed.
176       TestSCCAnalysis::Result &AR = AM->getResult<TestSCCAnalysis>(C);
177       AnalyzedSCCFunctionCount += AR.FunctionCount;
178       for (LazyCallGraph::Node &N : C) {
179         TestFunctionAnalysis::Result &FAR =
180             FAM.getResult<TestFunctionAnalysis>(N.getFunction());
181         AnalyzedInstrCount += FAR.InstructionCount;
182 
183         // Just ensure we get the immutable results.
184         (void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction());
185       }
186     }
187 
188     return PreservedAnalyses::all();
189   }
190 
191   static StringRef name() { return "TestSCCPass"; }
192 
193   int &RunCount;
194   int &AnalyzedInstrCount;
195   int &AnalyzedSCCFunctionCount;
196   int &AnalyzedModuleFunctionCount;
197   bool OnlyUseCachedResults;
198 };
199 
200 struct TestFunctionPass {
201   TestFunctionPass(int &RunCount) : RunCount(RunCount) {}
202 
203   PreservedAnalyses run(Function &M) {
204     ++RunCount;
205     return PreservedAnalyses::none();
206   }
207 
208   static StringRef name() { return "TestFunctionPass"; }
209 
210   int &RunCount;
211 };
212 
213 std::unique_ptr<Module> parseIR(const char *IR) {
214   LLVMContext &C = getGlobalContext();
215   SMDiagnostic Err;
216   return parseAssemblyString(IR, Err, C);
217 }
218 
219 class CGSCCPassManagerTest : public ::testing::Test {
220 protected:
221   std::unique_ptr<Module> M;
222 
223 public:
224   CGSCCPassManagerTest()
225       : M(parseIR("define void @f() {\n"
226                   "entry:\n"
227                   "  call void @g()\n"
228                   "  call void @h1()\n"
229                   "  ret void\n"
230                   "}\n"
231                   "define void @g() {\n"
232                   "entry:\n"
233                   "  call void @g()\n"
234                   "  call void @x()\n"
235                   "  ret void\n"
236                   "}\n"
237                   "define void @h1() {\n"
238                   "entry:\n"
239                   "  call void @h2()\n"
240                   "  ret void\n"
241                   "}\n"
242                   "define void @h2() {\n"
243                   "entry:\n"
244                   "  call void @h3()\n"
245                   "  call void @x()\n"
246                   "  ret void\n"
247                   "}\n"
248                   "define void @h3() {\n"
249                   "entry:\n"
250                   "  call void @h1()\n"
251                   "  ret void\n"
252                   "}\n"
253                   "define void @x() {\n"
254                   "entry:\n"
255                   "  ret void\n"
256                   "}\n"
257                   )) {}
258 };
259 
260 TEST_F(CGSCCPassManagerTest, Basic) {
261   FunctionAnalysisManager FAM(/*DebugLogging*/ true);
262   int FunctionAnalysisRuns = 0;
263   FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
264   int ImmutableFunctionAnalysisRuns = 0;
265   FAM.registerPass([&] {
266     return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns);
267   });
268 
269   CGSCCAnalysisManager CGAM(/*DebugLogging*/ true);
270   int SCCAnalysisRuns = 0;
271   CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
272 
273   ModuleAnalysisManager MAM(/*DebugLogging*/ true);
274   int ModuleAnalysisRuns = 0;
275   MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
276   MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
277 
278   MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
279   MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
280   CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); });
281   CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
282   FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
283   FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
284 
285   ModulePassManager MPM(/*DebugLogging*/ true);
286   int ModulePassRunCount1 = 0;
287   MPM.addPass(TestModulePass(ModulePassRunCount1));
288 
289   CGSCCPassManager CGPM1(/*DebugLogging*/ true);
290   int SCCPassRunCount1 = 0;
291   int AnalyzedInstrCount1 = 0;
292   int AnalyzedSCCFunctionCount1 = 0;
293   int AnalyzedModuleFunctionCount1 = 0;
294   CGPM1.addPass(TestSCCPass(SCCPassRunCount1, AnalyzedInstrCount1,
295                             AnalyzedSCCFunctionCount1,
296                             AnalyzedModuleFunctionCount1));
297 
298   FunctionPassManager FPM1(/*DebugLogging*/ true);
299   int FunctionPassRunCount1 = 0;
300   FPM1.addPass(TestFunctionPass(FunctionPassRunCount1));
301   CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
302   MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
303 
304   MPM.run(*M, &MAM);
305 
306   EXPECT_EQ(1, ModulePassRunCount1);
307 
308   EXPECT_EQ(1, ModuleAnalysisRuns);
309   EXPECT_EQ(4, SCCAnalysisRuns);
310   EXPECT_EQ(6, FunctionAnalysisRuns);
311   EXPECT_EQ(6, ImmutableFunctionAnalysisRuns);
312 
313   EXPECT_EQ(4, SCCPassRunCount1);
314   EXPECT_EQ(14, AnalyzedInstrCount1);
315   EXPECT_EQ(6, AnalyzedSCCFunctionCount1);
316   EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);
317 }
318 
319 }
320