blob: 828ec991e1b4d0727be3b1e7582c7bd9a0b29cf5 [file] [log] [blame]
Chandler Carruth74319922016-02-23 10:02:02 +00001//===- 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
21using namespace llvm;
22
23namespace {
24
25class TestModuleAnalysis {
26public:
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
Chandler Carruthb47f8012016-03-11 11:05:24 +000037 Result run(Module &M, ModuleAnalysisManager &AM) {
Chandler Carruth74319922016-02-23 10:02:02 +000038 ++Runs;
39 return Result(M.size());
40 }
41
42private:
43 static char PassID;
44
45 int &Runs;
46};
47
48char TestModuleAnalysis::PassID;
49
50class TestSCCAnalysis {
51public:
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
Chandler Carruth88823462016-08-24 09:37:14 +000062 Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &) {
Chandler Carruth74319922016-02-23 10:02:02 +000063 ++Runs;
64 return Result(C.size());
65 }
66
67private:
68 static char PassID;
69
70 int &Runs;
71};
72
73char TestSCCAnalysis::PassID;
74
75class TestFunctionAnalysis {
76public:
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
Chandler Carruthb47f8012016-03-11 11:05:24 +000087 Result run(Function &F, FunctionAnalysisManager &AM) {
Chandler Carruth74319922016-02-23 10:02:02 +000088 ++Runs;
89 int Count = 0;
90 for (Instruction &I : instructions(F)) {
91 (void)I;
92 ++Count;
93 }
94 return Result(Count);
95 }
96
97private:
98 static char PassID;
99
100 int &Runs;
101};
102
103char TestFunctionAnalysis::PassID;
104
Chandler Carruthc5d211e2016-02-23 10:47:57 +0000105class TestImmutableFunctionAnalysis {
106public:
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
Chandler Carruthb47f8012016-03-11 11:05:24 +0000116 Result run(Function &F, FunctionAnalysisManager &AM) {
Chandler Carruthc5d211e2016-02-23 10:47:57 +0000117 ++Runs;
118 return Result();
119 }
120
121private:
122 static char PassID;
123
124 int &Runs;
125};
126
127char TestImmutableFunctionAnalysis::PassID;
128
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000129struct LambdaSCCPass : public PassInfoMixin<LambdaSCCPass> {
130 template <typename T> LambdaSCCPass(T &&Arg) : Func(std::forward<T>(Arg)) {}
Chandler Carruth74319922016-02-23 10:02:02 +0000131
Chandler Carruth88823462016-08-24 09:37:14 +0000132 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
133 LazyCallGraph &CG, CGSCCUpdateResult &UR) {
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000134 return Func(C, AM, CG, UR);
Chandler Carruth74319922016-02-23 10:02:02 +0000135 }
136
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000137 std::function<PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &,
138 LazyCallGraph &, CGSCCUpdateResult &)>
139 Func;
Chandler Carruth74319922016-02-23 10:02:02 +0000140};
141
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000142struct LambdaFunctionPass : public PassInfoMixin<LambdaFunctionPass> {
143 template <typename T> LambdaFunctionPass(T &&Arg) : Func(std::forward<T>(Arg)) {}
Chandler Carruth74319922016-02-23 10:02:02 +0000144
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000145 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
146 return Func(F, AM);
Chandler Carruth74319922016-02-23 10:02:02 +0000147 }
148
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000149 std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)> Func;
Chandler Carruth74319922016-02-23 10:02:02 +0000150};
151
Chandler Carruth6c138ce2016-06-28 00:38:42 +0000152std::unique_ptr<Module> parseIR(const char *IR) {
153 // We just use a static context here. This is never called from multiple
154 // threads so it is harmless no matter how it is implemented. We just need
155 // the context to outlive the module which it does.
156 static LLVMContext C;
Chandler Carruth74319922016-02-23 10:02:02 +0000157 SMDiagnostic Err;
158 return parseAssemblyString(IR, Err, C);
159}
160
Chandler Carruth6c138ce2016-06-28 00:38:42 +0000161TEST(CGSCCPassManagerTest, Basic) {
162 auto M = parseIR("define void @f() {\n"
163 "entry:\n"
164 " call void @g()\n"
165 " call void @h1()\n"
166 " ret void\n"
167 "}\n"
168 "define void @g() {\n"
169 "entry:\n"
170 " call void @g()\n"
171 " call void @x()\n"
172 " ret void\n"
173 "}\n"
174 "define void @h1() {\n"
175 "entry:\n"
176 " call void @h2()\n"
177 " ret void\n"
178 "}\n"
179 "define void @h2() {\n"
180 "entry:\n"
181 " call void @h3()\n"
182 " call void @x()\n"
183 " ret void\n"
184 "}\n"
185 "define void @h3() {\n"
186 "entry:\n"
187 " call void @h1()\n"
188 " ret void\n"
189 "}\n"
190 "define void @x() {\n"
191 "entry:\n"
192 " ret void\n"
193 "}\n");
Chandler Carruth74319922016-02-23 10:02:02 +0000194 FunctionAnalysisManager FAM(/*DebugLogging*/ true);
195 int FunctionAnalysisRuns = 0;
196 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
Chandler Carruthc5d211e2016-02-23 10:47:57 +0000197 int ImmutableFunctionAnalysisRuns = 0;
198 FAM.registerPass([&] {
199 return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns);
200 });
Chandler Carruth74319922016-02-23 10:02:02 +0000201
202 CGSCCAnalysisManager CGAM(/*DebugLogging*/ true);
203 int SCCAnalysisRuns = 0;
204 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
205
206 ModuleAnalysisManager MAM(/*DebugLogging*/ true);
207 int ModuleAnalysisRuns = 0;
208 MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
209 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
210
211 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
212 MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
213 CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); });
214 CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
215 FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
216 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
217
218 ModulePassManager MPM(/*DebugLogging*/ true);
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000219 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
Chandler Carruth74319922016-02-23 10:02:02 +0000220
221 CGSCCPassManager CGPM1(/*DebugLogging*/ true);
222 int SCCPassRunCount1 = 0;
223 int AnalyzedInstrCount1 = 0;
224 int AnalyzedSCCFunctionCount1 = 0;
225 int AnalyzedModuleFunctionCount1 = 0;
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000226 CGPM1.addPass(
227 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
228 LazyCallGraph &CG, CGSCCUpdateResult &UR) {
229 ++SCCPassRunCount1;
230
231 const ModuleAnalysisManager &MAM =
232 AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG).getManager();
233 FunctionAnalysisManager &FAM =
234 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
235 if (TestModuleAnalysis::Result *TMA =
236 MAM.getCachedResult<TestModuleAnalysis>(
237 *C.begin()->getFunction().getParent()))
238 AnalyzedModuleFunctionCount1 += TMA->FunctionCount;
239
240 TestSCCAnalysis::Result &AR = AM.getResult<TestSCCAnalysis>(C, CG);
241 AnalyzedSCCFunctionCount1 += AR.FunctionCount;
242 for (LazyCallGraph::Node &N : C) {
243 TestFunctionAnalysis::Result &FAR =
244 FAM.getResult<TestFunctionAnalysis>(N.getFunction());
245 AnalyzedInstrCount1 += FAR.InstructionCount;
246
247 // Just ensure we get the immutable results.
248 (void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction());
249 }
250
251 return PreservedAnalyses::all();
252 }));
Chandler Carruth74319922016-02-23 10:02:02 +0000253
254 FunctionPassManager FPM1(/*DebugLogging*/ true);
255 int FunctionPassRunCount1 = 0;
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000256 FPM1.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
257 ++FunctionPassRunCount1;
258 return PreservedAnalyses::all();
259 }));
Chandler Carruth74319922016-02-23 10:02:02 +0000260 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
261 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
262
Chandler Carruthb47f8012016-03-11 11:05:24 +0000263 MPM.run(*M, MAM);
Chandler Carruth74319922016-02-23 10:02:02 +0000264
Chandler Carruth74319922016-02-23 10:02:02 +0000265 EXPECT_EQ(1, ModuleAnalysisRuns);
266 EXPECT_EQ(4, SCCAnalysisRuns);
267 EXPECT_EQ(6, FunctionAnalysisRuns);
Chandler Carruthc5d211e2016-02-23 10:47:57 +0000268 EXPECT_EQ(6, ImmutableFunctionAnalysisRuns);
Chandler Carruth74319922016-02-23 10:02:02 +0000269
270 EXPECT_EQ(4, SCCPassRunCount1);
271 EXPECT_EQ(14, AnalyzedInstrCount1);
272 EXPECT_EQ(6, AnalyzedSCCFunctionCount1);
273 EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);
274}
275
276}