1 //===- llvm/unittest/Analysis/LoopPassManagerTest.cpp - LPM tests ---------===//
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 "gtest/gtest.h"
11 #include "llvm/Analysis/LoopPassManager.h"
12 #include "llvm/AsmParser/Parser.h"
13 #include "llvm/IR/Dominators.h"
14 #include "llvm/IR/Function.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
20 using namespace llvm;
21
22 namespace {
23
24 class TestLoopAnalysis {
25 /// \brief Private static data to provide unique ID.
26 static char PassID;
27
28 int &Runs;
29
30 public:
31 struct Result {
Result__anon8c6983180111::TestLoopAnalysis::Result32 Result(int Count) : BlockCount(Count) {}
33 int BlockCount;
34 };
35
36 /// \brief Returns an opaque, unique ID for this pass type.
ID()37 static void *ID() { return (void *)&PassID; }
38
39 /// \brief Returns the name of the analysis.
name()40 static StringRef name() { return "TestLoopAnalysis"; }
41
TestLoopAnalysis(int & Runs)42 TestLoopAnalysis(int &Runs) : Runs(Runs) {}
43
44 /// \brief Run the analysis pass over the loop and return a result.
run(Loop & L,AnalysisManager<Loop> & AM)45 Result run(Loop &L, AnalysisManager<Loop> &AM) {
46 ++Runs;
47 int Count = 0;
48
49 for (auto I = L.block_begin(), E = L.block_end(); I != E; ++I)
50 ++Count;
51 return Result(Count);
52 }
53 };
54
55 char TestLoopAnalysis::PassID;
56
57 class TestLoopPass {
58 std::vector<StringRef> &VisitedLoops;
59 int &AnalyzedBlockCount;
60 bool OnlyUseCachedResults;
61
62 public:
TestLoopPass(std::vector<StringRef> & VisitedLoops,int & AnalyzedBlockCount,bool OnlyUseCachedResults=false)63 TestLoopPass(std::vector<StringRef> &VisitedLoops, int &AnalyzedBlockCount,
64 bool OnlyUseCachedResults = false)
65 : VisitedLoops(VisitedLoops), AnalyzedBlockCount(AnalyzedBlockCount),
66 OnlyUseCachedResults(OnlyUseCachedResults) {}
67
run(Loop & L,AnalysisManager<Loop> & AM)68 PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM) {
69 VisitedLoops.push_back(L.getName());
70
71 if (OnlyUseCachedResults) {
72 // Hack to force the use of the cached interface.
73 if (auto *AR = AM.getCachedResult<TestLoopAnalysis>(L))
74 AnalyzedBlockCount += AR->BlockCount;
75 } else {
76 // Typical path just runs the analysis as needed.
77 auto &AR = AM.getResult<TestLoopAnalysis>(L);
78 AnalyzedBlockCount += AR.BlockCount;
79 }
80
81 return PreservedAnalyses::all();
82 }
83
name()84 static StringRef name() { return "TestLoopPass"; }
85 };
86
87 // A test loop pass that invalidates the analysis for loops with the given name.
88 class TestLoopInvalidatingPass {
89 StringRef Name;
90
91 public:
TestLoopInvalidatingPass(StringRef LoopName)92 TestLoopInvalidatingPass(StringRef LoopName) : Name(LoopName) {}
93
run(Loop & L,AnalysisManager<Loop> & AM)94 PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM) {
95 return L.getName() == Name ? getLoopPassPreservedAnalyses()
96 : PreservedAnalyses::all();
97 }
98
name()99 static StringRef name() { return "TestLoopInvalidatingPass"; }
100 };
101
parseIR(LLVMContext & C,const char * IR)102 std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
103 SMDiagnostic Err;
104 return parseAssemblyString(IR, Err, C);
105 }
106
107 class LoopPassManagerTest : public ::testing::Test {
108 protected:
109 LLVMContext Context;
110 std::unique_ptr<Module> M;
111
112 public:
LoopPassManagerTest()113 LoopPassManagerTest()
114 : M(parseIR(Context, "define void @f() {\n"
115 "entry:\n"
116 " br label %loop.0\n"
117 "loop.0:\n"
118 " br i1 undef, label %loop.0.0, label %end\n"
119 "loop.0.0:\n"
120 " br i1 undef, label %loop.0.0, label %loop.0.1\n"
121 "loop.0.1:\n"
122 " br i1 undef, label %loop.0.1, label %loop.0\n"
123 "end:\n"
124 " ret void\n"
125 "}\n"
126 "\n"
127 "define void @g() {\n"
128 "entry:\n"
129 " br label %loop.g.0\n"
130 "loop.g.0:\n"
131 " br i1 undef, label %loop.g.0, label %end\n"
132 "end:\n"
133 " ret void\n"
134 "}\n")) {}
135 };
136
137 #define EXPECT_N_ELEMENTS_EQ(N, EXPECTED, ACTUAL) \
138 do { \
139 EXPECT_EQ(N##UL, ACTUAL.size()); \
140 for (int I = 0; I < N; ++I) \
141 EXPECT_TRUE(EXPECTED[I] == ACTUAL[I]) << "Element " << I << " is " \
142 << ACTUAL[I] << ". Expected " \
143 << EXPECTED[I] << "."; \
144 } while (0)
145
TEST_F(LoopPassManagerTest,Basic)146 TEST_F(LoopPassManagerTest, Basic) {
147 LoopAnalysisManager LAM(true);
148 int LoopAnalysisRuns = 0;
149 LAM.registerPass([&] { return TestLoopAnalysis(LoopAnalysisRuns); });
150
151 FunctionAnalysisManager FAM(true);
152 // We need DominatorTreeAnalysis for LoopAnalysis.
153 FAM.registerPass([&] { return DominatorTreeAnalysis(); });
154 FAM.registerPass([&] { return LoopAnalysis(); });
155 FAM.registerPass([&] { return LoopAnalysisManagerFunctionProxy(LAM); });
156 LAM.registerPass([&] { return FunctionAnalysisManagerLoopProxy(FAM); });
157
158 ModuleAnalysisManager MAM(true);
159 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
160 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
161
162 ModulePassManager MPM(true);
163 FunctionPassManager FPM(true);
164
165 // Visit all of the loops.
166 std::vector<StringRef> VisitedLoops1;
167 int AnalyzedBlockCount1 = 0;
168 {
169 LoopPassManager LPM;
170 LPM.addPass(TestLoopPass(VisitedLoops1, AnalyzedBlockCount1));
171
172 FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM)));
173 }
174
175 // Only use cached analyses.
176 std::vector<StringRef> VisitedLoops2;
177 int AnalyzedBlockCount2 = 0;
178 {
179 LoopPassManager LPM;
180 LPM.addPass(TestLoopInvalidatingPass("loop.g.0"));
181 LPM.addPass(TestLoopPass(VisitedLoops2, AnalyzedBlockCount2,
182 /*OnlyUseCachedResults=*/true));
183
184 FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM)));
185 }
186
187 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
188 MPM.run(*M, MAM);
189
190 StringRef ExpectedLoops[] = {"loop.0.0", "loop.0.1", "loop.0", "loop.g.0"};
191
192 // Validate the counters and order of loops visited.
193 // loop.0 has 3 blocks whereas loop.0.0, loop.0.1, and loop.g.0 each have 1.
194 EXPECT_N_ELEMENTS_EQ(4, ExpectedLoops, VisitedLoops1);
195 EXPECT_EQ(6, AnalyzedBlockCount1);
196
197 EXPECT_N_ELEMENTS_EQ(4, ExpectedLoops, VisitedLoops2);
198 // The block from loop.g.0 won't be counted, since it wasn't cached.
199 EXPECT_EQ(5, AnalyzedBlockCount2);
200
201 // The first LPM runs the loop analysis for all four loops, the second uses
202 // cached results for everything.
203 EXPECT_EQ(4, LoopAnalysisRuns);
204 }
205 }
206