blob: 4f12def8f0d9adc47d65f9d41aecb4803e9e3939 [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
Chandler Carruthdab4eae2016-11-23 17:53:26 +000024class TestLoopAnalysis : public AnalysisInfoMixin<TestLoopAnalysis> {
25 friend AnalysisInfoMixin<TestLoopAnalysis>;
26 static AnalysisKey Key;
Justin Bognereecc3c82016-02-25 07:23:08 +000027
28 int &Runs;
29
30public:
31 struct Result {
32 Result(int Count) : BlockCount(Count) {}
33 int BlockCount;
34 };
35
Justin Bognereecc3c82016-02-25 07:23:08 +000036 TestLoopAnalysis(int &Runs) : Runs(Runs) {}
37
38 /// \brief Run the analysis pass over the loop and return a result.
Sean Silva0746f3b2016-08-09 00:28:52 +000039 Result run(Loop &L, LoopAnalysisManager &AM) {
Justin Bognereecc3c82016-02-25 07:23:08 +000040 ++Runs;
41 int Count = 0;
42
43 for (auto I = L.block_begin(), E = L.block_end(); I != E; ++I)
44 ++Count;
45 return Result(Count);
46 }
47};
48
Chandler Carruthdab4eae2016-11-23 17:53:26 +000049AnalysisKey TestLoopAnalysis::Key;
Justin Bognereecc3c82016-02-25 07:23:08 +000050
51class TestLoopPass {
52 std::vector<StringRef> &VisitedLoops;
53 int &AnalyzedBlockCount;
54 bool OnlyUseCachedResults;
55
56public:
57 TestLoopPass(std::vector<StringRef> &VisitedLoops, int &AnalyzedBlockCount,
58 bool OnlyUseCachedResults = false)
59 : VisitedLoops(VisitedLoops), AnalyzedBlockCount(AnalyzedBlockCount),
60 OnlyUseCachedResults(OnlyUseCachedResults) {}
61
Sean Silva0746f3b2016-08-09 00:28:52 +000062 PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM) {
Justin Bognereecc3c82016-02-25 07:23:08 +000063 VisitedLoops.push_back(L.getName());
64
65 if (OnlyUseCachedResults) {
66 // Hack to force the use of the cached interface.
Chandler Carruthb47f8012016-03-11 11:05:24 +000067 if (auto *AR = AM.getCachedResult<TestLoopAnalysis>(L))
Justin Bognereecc3c82016-02-25 07:23:08 +000068 AnalyzedBlockCount += AR->BlockCount;
69 } else {
70 // Typical path just runs the analysis as needed.
Chandler Carruthb47f8012016-03-11 11:05:24 +000071 auto &AR = AM.getResult<TestLoopAnalysis>(L);
Justin Bognereecc3c82016-02-25 07:23:08 +000072 AnalyzedBlockCount += AR.BlockCount;
73 }
74
75 return PreservedAnalyses::all();
76 }
77
78 static StringRef name() { return "TestLoopPass"; }
79};
80
81// A test loop pass that invalidates the analysis for loops with the given name.
82class TestLoopInvalidatingPass {
83 StringRef Name;
84
85public:
86 TestLoopInvalidatingPass(StringRef LoopName) : Name(LoopName) {}
87
Sean Silva0746f3b2016-08-09 00:28:52 +000088 PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM) {
Justin Bognere839c3e2016-05-03 21:35:08 +000089 return L.getName() == Name ? getLoopPassPreservedAnalyses()
Justin Bognereecc3c82016-02-25 07:23:08 +000090 : PreservedAnalyses::all();
91 }
92
93 static StringRef name() { return "TestLoopInvalidatingPass"; }
94};
95
Mehdi Amini03b42e42016-04-14 21:59:01 +000096std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
Justin Bognereecc3c82016-02-25 07:23:08 +000097 SMDiagnostic Err;
98 return parseAssemblyString(IR, Err, C);
99}
100
101class LoopPassManagerTest : public ::testing::Test {
102protected:
Mehdi Amini03b42e42016-04-14 21:59:01 +0000103 LLVMContext Context;
Justin Bognereecc3c82016-02-25 07:23:08 +0000104 std::unique_ptr<Module> M;
105
106public:
107 LoopPassManagerTest()
Mehdi Amini03b42e42016-04-14 21:59:01 +0000108 : M(parseIR(Context, "define void @f() {\n"
109 "entry:\n"
110 " br label %loop.0\n"
111 "loop.0:\n"
112 " br i1 undef, label %loop.0.0, label %end\n"
113 "loop.0.0:\n"
114 " br i1 undef, label %loop.0.0, label %loop.0.1\n"
115 "loop.0.1:\n"
116 " br i1 undef, label %loop.0.1, label %loop.0\n"
117 "end:\n"
118 " ret void\n"
119 "}\n"
120 "\n"
121 "define void @g() {\n"
122 "entry:\n"
123 " br label %loop.g.0\n"
124 "loop.g.0:\n"
125 " br i1 undef, label %loop.g.0, label %end\n"
126 "end:\n"
127 " ret void\n"
128 "}\n")) {}
Justin Bognereecc3c82016-02-25 07:23:08 +0000129};
130
131#define EXPECT_N_ELEMENTS_EQ(N, EXPECTED, ACTUAL) \
132 do { \
133 EXPECT_EQ(N##UL, ACTUAL.size()); \
134 for (int I = 0; I < N; ++I) \
135 EXPECT_TRUE(EXPECTED[I] == ACTUAL[I]) << "Element " << I << " is " \
136 << ACTUAL[I] << ". Expected " \
137 << EXPECTED[I] << "."; \
138 } while (0)
139
140TEST_F(LoopPassManagerTest, Basic) {
141 LoopAnalysisManager LAM(true);
142 int LoopAnalysisRuns = 0;
143 LAM.registerPass([&] { return TestLoopAnalysis(LoopAnalysisRuns); });
144
145 FunctionAnalysisManager FAM(true);
146 // We need DominatorTreeAnalysis for LoopAnalysis.
147 FAM.registerPass([&] { return DominatorTreeAnalysis(); });
148 FAM.registerPass([&] { return LoopAnalysis(); });
149 FAM.registerPass([&] { return LoopAnalysisManagerFunctionProxy(LAM); });
150 LAM.registerPass([&] { return FunctionAnalysisManagerLoopProxy(FAM); });
151
152 ModuleAnalysisManager MAM(true);
153 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
154 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
155
156 ModulePassManager MPM(true);
157 FunctionPassManager FPM(true);
158
159 // Visit all of the loops.
160 std::vector<StringRef> VisitedLoops1;
161 int AnalyzedBlockCount1 = 0;
162 {
163 LoopPassManager LPM;
164 LPM.addPass(TestLoopPass(VisitedLoops1, AnalyzedBlockCount1));
165
166 FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM)));
167 }
168
169 // Only use cached analyses.
170 std::vector<StringRef> VisitedLoops2;
171 int AnalyzedBlockCount2 = 0;
172 {
173 LoopPassManager LPM;
174 LPM.addPass(TestLoopInvalidatingPass("loop.g.0"));
175 LPM.addPass(TestLoopPass(VisitedLoops2, AnalyzedBlockCount2,
176 /*OnlyUseCachedResults=*/true));
177
178 FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM)));
179 }
180
181 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
Chandler Carruthb47f8012016-03-11 11:05:24 +0000182 MPM.run(*M, MAM);
Justin Bognereecc3c82016-02-25 07:23:08 +0000183
184 StringRef ExpectedLoops[] = {"loop.0.0", "loop.0.1", "loop.0", "loop.g.0"};
185
186 // Validate the counters and order of loops visited.
187 // loop.0 has 3 blocks whereas loop.0.0, loop.0.1, and loop.g.0 each have 1.
188 EXPECT_N_ELEMENTS_EQ(4, ExpectedLoops, VisitedLoops1);
189 EXPECT_EQ(6, AnalyzedBlockCount1);
190
191 EXPECT_N_ELEMENTS_EQ(4, ExpectedLoops, VisitedLoops2);
192 // The block from loop.g.0 won't be counted, since it wasn't cached.
193 EXPECT_EQ(5, AnalyzedBlockCount2);
194
195 // The first LPM runs the loop analysis for all four loops, the second uses
196 // cached results for everything.
197 EXPECT_EQ(4, LoopAnalysisRuns);
198}
199}