blob: 3cbe203e14df2a1fa7536e14a41ca9f3c1901ec4 [file] [log] [blame]
Justin Bognereecc3c82016-02-25 07:23:08 +00001//===- 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
20using namespace llvm;
21
22namespace {
23
24class TestLoopAnalysis {
25 /// \brief Private static data to provide unique ID.
26 static char PassID;
27
28 int &Runs;
29
30public:
31 struct Result {
32 Result(int Count) : BlockCount(Count) {}
33 int BlockCount;
34 };
35
36 /// \brief Returns an opaque, unique ID for this pass type.
37 static void *ID() { return (void *)&PassID; }
38
39 /// \brief Returns the name of the analysis.
40 static StringRef name() { return "TestLoopAnalysis"; }
41
42 TestLoopAnalysis(int &Runs) : Runs(Runs) {}
43
44 /// \brief Run the analysis pass over the loop and return a result.
Chandler Carruthb47f8012016-03-11 11:05:24 +000045 Result run(Loop &L, AnalysisManager<Loop> &AM) {
Justin Bognereecc3c82016-02-25 07:23:08 +000046 ++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
55char TestLoopAnalysis::PassID;
56
57class TestLoopPass {
58 std::vector<StringRef> &VisitedLoops;
59 int &AnalyzedBlockCount;
60 bool OnlyUseCachedResults;
61
62public:
63 TestLoopPass(std::vector<StringRef> &VisitedLoops, int &AnalyzedBlockCount,
64 bool OnlyUseCachedResults = false)
65 : VisitedLoops(VisitedLoops), AnalyzedBlockCount(AnalyzedBlockCount),
66 OnlyUseCachedResults(OnlyUseCachedResults) {}
67
Chandler Carruthb47f8012016-03-11 11:05:24 +000068 PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM) {
Justin Bognereecc3c82016-02-25 07:23:08 +000069 VisitedLoops.push_back(L.getName());
70
71 if (OnlyUseCachedResults) {
72 // Hack to force the use of the cached interface.
Chandler Carruthb47f8012016-03-11 11:05:24 +000073 if (auto *AR = AM.getCachedResult<TestLoopAnalysis>(L))
Justin Bognereecc3c82016-02-25 07:23:08 +000074 AnalyzedBlockCount += AR->BlockCount;
75 } else {
76 // Typical path just runs the analysis as needed.
Chandler Carruthb47f8012016-03-11 11:05:24 +000077 auto &AR = AM.getResult<TestLoopAnalysis>(L);
Justin Bognereecc3c82016-02-25 07:23:08 +000078 AnalyzedBlockCount += AR.BlockCount;
79 }
80
81 return PreservedAnalyses::all();
82 }
83
84 static StringRef name() { return "TestLoopPass"; }
85};
86
87// A test loop pass that invalidates the analysis for loops with the given name.
88class TestLoopInvalidatingPass {
89 StringRef Name;
90
91public:
92 TestLoopInvalidatingPass(StringRef LoopName) : Name(LoopName) {}
93
Chandler Carruthb47f8012016-03-11 11:05:24 +000094 PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM) {
Justin Bognereecc3c82016-02-25 07:23:08 +000095 return L.getName() == Name ? PreservedAnalyses::none()
96 : PreservedAnalyses::all();
97 }
98
99 static StringRef name() { return "TestLoopInvalidatingPass"; }
100};
101
Mehdi Amini03b42e42016-04-14 21:59:01 +0000102std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
Justin Bognereecc3c82016-02-25 07:23:08 +0000103 SMDiagnostic Err;
104 return parseAssemblyString(IR, Err, C);
105}
106
107class LoopPassManagerTest : public ::testing::Test {
108protected:
Mehdi Amini03b42e42016-04-14 21:59:01 +0000109 LLVMContext Context;
Justin Bognereecc3c82016-02-25 07:23:08 +0000110 std::unique_ptr<Module> M;
111
112public:
113 LoopPassManagerTest()
Mehdi Amini03b42e42016-04-14 21:59:01 +0000114 : 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")) {}
Justin Bognereecc3c82016-02-25 07:23:08 +0000135};
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
146TEST_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)));
Chandler Carruthb47f8012016-03-11 11:05:24 +0000188 MPM.run(*M, MAM);
Justin Bognereecc3c82016-02-25 07:23:08 +0000189
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}