blob: 35d232805568d1ee1f253145dec0e3f336b19e17 [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 Carruth0f0ef132016-09-02 10:49:58 +0000131 // We have to explicitly define all the special member functions because MSVC
132 // refuses to generate them.
133 LambdaSCCPass(LambdaSCCPass &&Arg) : Func(std::move(Arg.Func)) {}
134 LambdaSCCPass &operator=(LambdaSCCPass &&RHS) {
135 Func = std::move(RHS.Func);
136 return *this;
137 }
Chandler Carruth74319922016-02-23 10:02:02 +0000138
Chandler Carruth88823462016-08-24 09:37:14 +0000139 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
140 LazyCallGraph &CG, CGSCCUpdateResult &UR) {
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000141 return Func(C, AM, CG, UR);
Chandler Carruth74319922016-02-23 10:02:02 +0000142 }
143
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000144 std::function<PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &,
145 LazyCallGraph &, CGSCCUpdateResult &)>
146 Func;
Chandler Carruth74319922016-02-23 10:02:02 +0000147};
148
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000149struct LambdaFunctionPass : public PassInfoMixin<LambdaFunctionPass> {
150 template <typename T> LambdaFunctionPass(T &&Arg) : Func(std::forward<T>(Arg)) {}
Chandler Carruth0f0ef132016-09-02 10:49:58 +0000151 // We have to explicitly define all the special member functions because MSVC
152 // refuses to generate them.
153 LambdaFunctionPass(LambdaFunctionPass &&Arg) : Func(std::move(Arg.Func)) {}
154 LambdaFunctionPass &operator=(LambdaFunctionPass &&RHS) {
155 Func = std::move(RHS.Func);
156 return *this;
157 }
Chandler Carruth74319922016-02-23 10:02:02 +0000158
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000159 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
160 return Func(F, AM);
Chandler Carruth74319922016-02-23 10:02:02 +0000161 }
162
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000163 std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)> Func;
Chandler Carruth74319922016-02-23 10:02:02 +0000164};
165
Chandler Carruth6c138ce2016-06-28 00:38:42 +0000166std::unique_ptr<Module> parseIR(const char *IR) {
167 // We just use a static context here. This is never called from multiple
168 // threads so it is harmless no matter how it is implemented. We just need
169 // the context to outlive the module which it does.
170 static LLVMContext C;
Chandler Carruth74319922016-02-23 10:02:02 +0000171 SMDiagnostic Err;
172 return parseAssemblyString(IR, Err, C);
173}
174
Chandler Carruth4f837422016-09-02 01:14:05 +0000175class CGSCCPassManagerTest : public ::testing::Test {
176protected:
177 LLVMContext Context;
178 std::unique_ptr<Module> M;
179
180public:
181 CGSCCPassManagerTest()
182 : M(parseIR("define void @f() {\n"
183 "entry:\n"
184 " call void @g()\n"
185 " call void @h1()\n"
186 " ret void\n"
187 "}\n"
188 "define void @g() {\n"
189 "entry:\n"
190 " call void @g()\n"
191 " call void @x()\n"
192 " ret void\n"
193 "}\n"
194 "define void @h1() {\n"
195 "entry:\n"
196 " call void @h2()\n"
197 " ret void\n"
198 "}\n"
199 "define void @h2() {\n"
200 "entry:\n"
201 " call void @h3()\n"
202 " call void @x()\n"
203 " ret void\n"
204 "}\n"
205 "define void @h3() {\n"
206 "entry:\n"
207 " call void @h1()\n"
208 " ret void\n"
209 "}\n"
210 "define void @x() {\n"
211 "entry:\n"
212 " ret void\n"
213 "}\n")) {}
214};
215
216TEST_F(CGSCCPassManagerTest, Basic) {
Chandler Carruth74319922016-02-23 10:02:02 +0000217 FunctionAnalysisManager FAM(/*DebugLogging*/ true);
218 int FunctionAnalysisRuns = 0;
219 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
Chandler Carruthc5d211e2016-02-23 10:47:57 +0000220 int ImmutableFunctionAnalysisRuns = 0;
221 FAM.registerPass([&] {
222 return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns);
223 });
Chandler Carruth74319922016-02-23 10:02:02 +0000224
225 CGSCCAnalysisManager CGAM(/*DebugLogging*/ true);
226 int SCCAnalysisRuns = 0;
227 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
228
229 ModuleAnalysisManager MAM(/*DebugLogging*/ true);
230 int ModuleAnalysisRuns = 0;
231 MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
232 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
233
234 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
235 MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
236 CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); });
237 CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
238 FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
239 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
240
241 ModulePassManager MPM(/*DebugLogging*/ true);
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000242 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
Chandler Carruth74319922016-02-23 10:02:02 +0000243
244 CGSCCPassManager CGPM1(/*DebugLogging*/ true);
245 int SCCPassRunCount1 = 0;
246 int AnalyzedInstrCount1 = 0;
247 int AnalyzedSCCFunctionCount1 = 0;
248 int AnalyzedModuleFunctionCount1 = 0;
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000249 CGPM1.addPass(
250 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
251 LazyCallGraph &CG, CGSCCUpdateResult &UR) {
252 ++SCCPassRunCount1;
253
254 const ModuleAnalysisManager &MAM =
255 AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG).getManager();
256 FunctionAnalysisManager &FAM =
257 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
258 if (TestModuleAnalysis::Result *TMA =
259 MAM.getCachedResult<TestModuleAnalysis>(
260 *C.begin()->getFunction().getParent()))
261 AnalyzedModuleFunctionCount1 += TMA->FunctionCount;
262
263 TestSCCAnalysis::Result &AR = AM.getResult<TestSCCAnalysis>(C, CG);
264 AnalyzedSCCFunctionCount1 += AR.FunctionCount;
265 for (LazyCallGraph::Node &N : C) {
266 TestFunctionAnalysis::Result &FAR =
267 FAM.getResult<TestFunctionAnalysis>(N.getFunction());
268 AnalyzedInstrCount1 += FAR.InstructionCount;
269
270 // Just ensure we get the immutable results.
271 (void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction());
272 }
273
274 return PreservedAnalyses::all();
275 }));
Chandler Carruth74319922016-02-23 10:02:02 +0000276
277 FunctionPassManager FPM1(/*DebugLogging*/ true);
278 int FunctionPassRunCount1 = 0;
Chandler Carruthd4e80a92016-09-02 01:08:04 +0000279 FPM1.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
280 ++FunctionPassRunCount1;
281 return PreservedAnalyses::all();
282 }));
Chandler Carruth74319922016-02-23 10:02:02 +0000283 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
284 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
285
Chandler Carruthb47f8012016-03-11 11:05:24 +0000286 MPM.run(*M, MAM);
Chandler Carruth74319922016-02-23 10:02:02 +0000287
Chandler Carruth74319922016-02-23 10:02:02 +0000288 EXPECT_EQ(1, ModuleAnalysisRuns);
289 EXPECT_EQ(4, SCCAnalysisRuns);
290 EXPECT_EQ(6, FunctionAnalysisRuns);
Chandler Carruthc5d211e2016-02-23 10:47:57 +0000291 EXPECT_EQ(6, ImmutableFunctionAnalysisRuns);
Chandler Carruth74319922016-02-23 10:02:02 +0000292
293 EXPECT_EQ(4, SCCPassRunCount1);
294 EXPECT_EQ(14, AnalyzedInstrCount1);
295 EXPECT_EQ(6, AnalyzedSCCFunctionCount1);
296 EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);
297}
298
Chandler Carruth74319922016-02-23 10:02:02 +0000299}