• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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