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, LazyCallGraph &) {
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 LambdaSCCPass : public PassInfoMixin<LambdaSCCPass> {
130   template <typename T> LambdaSCCPass(T &&Arg) : Func(std::forward<T>(Arg)) {}
131   // 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   }
138 
139   PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
140                         LazyCallGraph &CG, CGSCCUpdateResult &UR) {
141     return Func(C, AM, CG, UR);
142   }
143 
144   std::function<PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &,
145                                   LazyCallGraph &, CGSCCUpdateResult &)>
146       Func;
147 };
148 
149 struct LambdaFunctionPass : public PassInfoMixin<LambdaFunctionPass> {
150   template <typename T> LambdaFunctionPass(T &&Arg) : Func(std::forward<T>(Arg)) {}
151   // 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   }
158 
159   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
160     return Func(F, AM);
161   }
162 
163   std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)> Func;
164 };
165 
166 std::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;
171   SMDiagnostic Err;
172   return parseAssemblyString(IR, Err, C);
173 }
174 
175 class CGSCCPassManagerTest : public ::testing::Test {
176 protected:
177   LLVMContext Context;
178   std::unique_ptr<Module> M;
179 
180 public:
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 
216 TEST_F(CGSCCPassManagerTest, Basic) {
217   FunctionAnalysisManager FAM(/*DebugLogging*/ true);
218   int FunctionAnalysisRuns = 0;
219   FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
220   int ImmutableFunctionAnalysisRuns = 0;
221   FAM.registerPass([&] {
222     return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns);
223   });
224 
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);
242   MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
243 
244   CGSCCPassManager CGPM1(/*DebugLogging*/ true);
245   int SCCPassRunCount1 = 0;
246   int AnalyzedInstrCount1 = 0;
247   int AnalyzedSCCFunctionCount1 = 0;
248   int AnalyzedModuleFunctionCount1 = 0;
249   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       }));
276 
277   FunctionPassManager FPM1(/*DebugLogging*/ true);
278   int FunctionPassRunCount1 = 0;
279   FPM1.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
280     ++FunctionPassRunCount1;
281     return PreservedAnalyses::all();
282   }));
283   CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
284   MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
285 
286   MPM.run(*M, MAM);
287 
288   EXPECT_EQ(1, ModuleAnalysisRuns);
289   EXPECT_EQ(4, SCCAnalysisRuns);
290   EXPECT_EQ(6, FunctionAnalysisRuns);
291   EXPECT_EQ(6, ImmutableFunctionAnalysisRuns);
292 
293   EXPECT_EQ(4, SCCPassRunCount1);
294   EXPECT_EQ(14, AnalyzedInstrCount1);
295   EXPECT_EQ(6, AnalyzedSCCFunctionCount1);
296   EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);
297 }
298 
299 }
300