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