• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- UnrollAnalyzerTest.cpp - UnrollAnalyzer unit tests -----------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/Analysis/LoopInfo.h"
10 #include "llvm/Analysis/LoopUnrollAnalyzer.h"
11 #include "llvm/AsmParser/Parser.h"
12 #include "llvm/IR/Dominators.h"
13 #include "llvm/IR/LegacyPassManager.h"
14 #include "llvm/InitializePasses.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "gtest/gtest.h"
17 
18 using namespace llvm;
19 namespace llvm {
20 void initializeUnrollAnalyzerTestPass(PassRegistry &);
21 
22 static SmallVector<DenseMap<Value *, Constant *>, 16> SimplifiedValuesVector;
23 static unsigned TripCount = 0;
24 
25 namespace {
26 struct UnrollAnalyzerTest : public FunctionPass {
27   static char ID;
runOnFunctionllvm::__anon1a9323780111::UnrollAnalyzerTest28   bool runOnFunction(Function &F) override {
29     LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
30     ScalarEvolution *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
31 
32     Function::iterator FI = F.begin();
33     FI++; // First basic block is entry - skip it.
34     BasicBlock *Header = &*FI++;
35     Loop *L = LI->getLoopFor(Header);
36     BasicBlock *Exiting = L->getExitingBlock();
37 
38     SimplifiedValuesVector.clear();
39     TripCount = SE->getSmallConstantTripCount(L, Exiting);
40     for (unsigned Iteration = 0; Iteration < TripCount; Iteration++) {
41       DenseMap<Value *, Constant *> SimplifiedValues;
42       UnrolledInstAnalyzer Analyzer(Iteration, SimplifiedValues, *SE, L);
43       for (auto *BB : L->getBlocks())
44         for (Instruction &I : *BB)
45           Analyzer.visit(I);
46       SimplifiedValuesVector.push_back(SimplifiedValues);
47     }
48     return false;
49   }
getAnalysisUsagellvm::__anon1a9323780111::UnrollAnalyzerTest50   void getAnalysisUsage(AnalysisUsage &AU) const override {
51     AU.addRequired<DominatorTreeWrapperPass>();
52     AU.addRequired<LoopInfoWrapperPass>();
53     AU.addRequired<ScalarEvolutionWrapperPass>();
54     AU.setPreservesAll();
55   }
UnrollAnalyzerTestllvm::__anon1a9323780111::UnrollAnalyzerTest56   UnrollAnalyzerTest() : FunctionPass(ID) {
57     initializeUnrollAnalyzerTestPass(*PassRegistry::getPassRegistry());
58   }
59 };
60 }
61 
62 char UnrollAnalyzerTest::ID = 0;
63 
makeLLVMModule(LLVMContext & Context,const char * ModuleStr)64 std::unique_ptr<Module> makeLLVMModule(LLVMContext &Context,
65                                        const char *ModuleStr) {
66   SMDiagnostic Err;
67   return parseAssemblyString(ModuleStr, Err, Context);
68 }
69 
TEST(UnrollAnalyzerTest,BasicSimplifications)70 TEST(UnrollAnalyzerTest, BasicSimplifications) {
71   const char *ModuleStr =
72       "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n"
73       "define i64 @propagate_loop_phis() {\n"
74       "entry:\n"
75       "  br label %loop\n"
76       "loop:\n"
77       "  %iv = phi i64 [ 0, %entry ], [ %inc, %loop ]\n"
78       "  %x0 = phi i64 [ 0, %entry ], [ %x2, %loop ]\n"
79       "  %x1 = or i64 %x0, 1\n"
80       "  %x2 = or i64 %x1, 2\n"
81       "  %inc = add nuw nsw i64 %iv, 1\n"
82       "  %cond = icmp sge i64 %inc, 8\n"
83       "  br i1 %cond, label %loop.end, label %loop\n"
84       "loop.end:\n"
85       "  %x.lcssa = phi i64 [ %x2, %loop ]\n"
86       "  ret i64 %x.lcssa\n"
87       "}\n";
88   UnrollAnalyzerTest *P = new UnrollAnalyzerTest();
89   LLVMContext Context;
90   std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
91   legacy::PassManager Passes;
92   Passes.add(P);
93   Passes.run(*M);
94 
95   // Perform checks
96   Module::iterator MI = M->begin();
97   Function *F = &*MI++;
98   Function::iterator FI = F->begin();
99   FI++; // First basic block is entry - skip it.
100   BasicBlock *Header = &*FI++;
101 
102   BasicBlock::iterator BBI = Header->begin();
103   std::advance(BBI, 4);
104   Instruction *Y1 = &*BBI++;
105   Instruction *Y2 = &*BBI++;
106   // Check simplification expected on the 1st iteration.
107   // Check that "%inc = add nuw nsw i64 %iv, 1" is simplified to 1
108   auto I1 = SimplifiedValuesVector[0].find(Y1);
109   EXPECT_TRUE(I1 != SimplifiedValuesVector[0].end());
110   EXPECT_EQ(cast<ConstantInt>((*I1).second)->getZExtValue(), 1U);
111 
112   // Check that "%cond = icmp sge i64 %inc, 10" is simplified to false
113   auto I2 = SimplifiedValuesVector[0].find(Y2);
114   EXPECT_TRUE(I2 != SimplifiedValuesVector[0].end());
115   EXPECT_FALSE(cast<ConstantInt>((*I2).second)->getZExtValue());
116 
117   // Check simplification expected on the last iteration.
118   // Check that "%inc = add nuw nsw i64 %iv, 1" is simplified to 8
119   I1 = SimplifiedValuesVector[TripCount - 1].find(Y1);
120   EXPECT_TRUE(I1 != SimplifiedValuesVector[TripCount - 1].end());
121   EXPECT_EQ(cast<ConstantInt>((*I1).second)->getZExtValue(), TripCount);
122 
123   // Check that "%cond = icmp sge i64 %inc, 10" is simplified to false
124   I2 = SimplifiedValuesVector[TripCount - 1].find(Y2);
125   EXPECT_TRUE(I2 != SimplifiedValuesVector[TripCount - 1].end());
126   EXPECT_TRUE(cast<ConstantInt>((*I2).second)->getZExtValue());
127 }
128 
TEST(UnrollAnalyzerTest,OuterLoopSimplification)129 TEST(UnrollAnalyzerTest, OuterLoopSimplification) {
130   const char *ModuleStr =
131       "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n"
132       "define void @foo() {\n"
133       "entry:\n"
134       "  br label %outer.loop\n"
135       "outer.loop:\n"
136       "  %iv.outer = phi i64 [ 0, %entry ], [ %iv.outer.next, %outer.loop.latch ]\n"
137       "  %iv.outer.next = add nuw nsw i64 %iv.outer, 1\n"
138       "  br label %inner.loop\n"
139       "inner.loop:\n"
140       "  %iv.inner = phi i64 [ 0, %outer.loop ], [ %iv.inner.next, %inner.loop ]\n"
141       "  %iv.inner.next = add nuw nsw i64 %iv.inner, 1\n"
142       "  %exitcond.inner = icmp eq i64 %iv.inner.next, 1000\n"
143       "  br i1 %exitcond.inner, label %outer.loop.latch, label %inner.loop\n"
144       "outer.loop.latch:\n"
145       "  %exitcond.outer = icmp eq i64 %iv.outer.next, 40\n"
146       "  br i1 %exitcond.outer, label %exit, label %outer.loop\n"
147       "exit:\n"
148       "  ret void\n"
149       "}\n";
150 
151   UnrollAnalyzerTest *P = new UnrollAnalyzerTest();
152   LLVMContext Context;
153   std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
154   legacy::PassManager Passes;
155   Passes.add(P);
156   Passes.run(*M);
157 
158   Module::iterator MI = M->begin();
159   Function *F = &*MI++;
160   Function::iterator FI = F->begin();
161   FI++;
162   BasicBlock *Header = &*FI++;
163   BasicBlock *InnerBody = &*FI++;
164 
165   BasicBlock::iterator BBI = Header->begin();
166   BBI++;
167   Instruction *Y1 = &*BBI;
168   BBI = InnerBody->begin();
169   BBI++;
170   Instruction *Y2 = &*BBI;
171   // Check that we can simplify IV of the outer loop, but can't simplify the IV
172   // of the inner loop if we only know the iteration number of the outer loop.
173   //
174   //  Y1 is %iv.outer.next, Y2 is %iv.inner.next
175   auto I1 = SimplifiedValuesVector[0].find(Y1);
176   EXPECT_TRUE(I1 != SimplifiedValuesVector[0].end());
177   auto I2 = SimplifiedValuesVector[0].find(Y2);
178   EXPECT_TRUE(I2 == SimplifiedValuesVector[0].end());
179 }
TEST(UnrollAnalyzerTest,CmpSimplifications)180 TEST(UnrollAnalyzerTest, CmpSimplifications) {
181   const char *ModuleStr =
182       "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n"
183       "define void @branch_iv_trunc() {\n"
184       "entry:\n"
185       "  br label %for.body\n"
186       "for.body:\n"
187       "  %indvars.iv = phi i64 [ 0, %entry ], [ %tmp3, %for.body ]\n"
188       "  %tmp2 = trunc i64 %indvars.iv to i32\n"
189       "  %cmp3 = icmp eq i32 %tmp2, 5\n"
190       "  %tmp3 = add nuw nsw i64 %indvars.iv, 1\n"
191       "  %exitcond = icmp eq i64 %tmp3, 10\n"
192       "  br i1 %exitcond, label %for.end, label %for.body\n"
193       "for.end:\n"
194       "  ret void\n"
195       "}\n";
196   UnrollAnalyzerTest *P = new UnrollAnalyzerTest();
197   LLVMContext Context;
198   std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
199   legacy::PassManager Passes;
200   Passes.add(P);
201   Passes.run(*M);
202 
203   // Perform checks
204   Module::iterator MI = M->begin();
205   Function *F = &*MI++;
206   Function::iterator FI = F->begin();
207   FI++; // First basic block is entry - skip it.
208   BasicBlock *Header = &*FI++;
209 
210   BasicBlock::iterator BBI = Header->begin();
211   BBI++;
212   Instruction *Y1 = &*BBI++;
213   Instruction *Y2 = &*BBI++;
214   // Check simplification expected on the 5th iteration.
215   // Check that "%tmp2 = trunc i64 %indvars.iv to i32" is simplified to 5
216   // and "%cmp3 = icmp eq i32 %tmp2, 5" is simplified to 1 (i.e. true).
217   auto I1 = SimplifiedValuesVector[5].find(Y1);
218   EXPECT_TRUE(I1 != SimplifiedValuesVector[5].end());
219   EXPECT_EQ(cast<ConstantInt>((*I1).second)->getZExtValue(), 5U);
220   auto I2 = SimplifiedValuesVector[5].find(Y2);
221   EXPECT_TRUE(I2 != SimplifiedValuesVector[5].end());
222   EXPECT_EQ(cast<ConstantInt>((*I2).second)->getZExtValue(), 1U);
223 }
TEST(UnrollAnalyzerTest,PtrCmpSimplifications)224 TEST(UnrollAnalyzerTest, PtrCmpSimplifications) {
225   const char *ModuleStr =
226       "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n"
227       "define void @ptr_cmp(i8 *%a) {\n"
228       "entry:\n"
229       "  %limit = getelementptr i8, i8* %a, i64 40\n"
230       "  %start.iv2 = getelementptr i8, i8* %a, i64 7\n"
231       "  br label %loop.body\n"
232       "loop.body:\n"
233       "  %iv.0 = phi i8* [ %a, %entry ], [ %iv.1, %loop.body ]\n"
234       "  %iv2.0 = phi i8* [ %start.iv2, %entry ], [ %iv2.1, %loop.body ]\n"
235       "  %cmp = icmp eq i8* %iv2.0, %iv.0\n"
236       "  %iv.1 = getelementptr inbounds i8, i8* %iv.0, i64 1\n"
237       "  %iv2.1 = getelementptr inbounds i8, i8* %iv2.0, i64 1\n"
238       "  %exitcond = icmp ne i8* %iv.1, %limit\n"
239       "  br i1 %exitcond, label %loop.body, label %loop.exit\n"
240       "loop.exit:\n"
241       "  ret void\n"
242       "}\n";
243   UnrollAnalyzerTest *P = new UnrollAnalyzerTest();
244   LLVMContext Context;
245   std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
246   legacy::PassManager Passes;
247   Passes.add(P);
248   Passes.run(*M);
249 
250   // Perform checks
251   Module::iterator MI = M->begin();
252   Function *F = &*MI++;
253   Function::iterator FI = F->begin();
254   FI++; // First basic block is entry - skip it.
255   BasicBlock *Header = &*FI;
256 
257   BasicBlock::iterator BBI = Header->begin();
258   std::advance(BBI, 2);
259   Instruction *Y1 = &*BBI;
260   // Check simplification expected on the 5th iteration.
261   // Check that "%cmp = icmp eq i8* %iv2.0, %iv.0" is simplified to 0.
262   auto I1 = SimplifiedValuesVector[5].find(Y1);
263   EXPECT_TRUE(I1 != SimplifiedValuesVector[5].end());
264   EXPECT_EQ(cast<ConstantInt>((*I1).second)->getZExtValue(), 0U);
265 }
TEST(UnrollAnalyzerTest,CastSimplifications)266 TEST(UnrollAnalyzerTest, CastSimplifications) {
267   const char *ModuleStr =
268       "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n"
269       "@known_constant = internal unnamed_addr constant [10 x i32] [i32 0, i32 1, i32 0, i32 1, i32 0, i32 259, i32 0, i32 1, i32 0, i32 1], align 16\n"
270       "define void @const_load_cast() {\n"
271       "entry:\n"
272       "  br label %loop\n"
273       "\n"
274       "loop:\n"
275       "  %iv = phi i64 [ 0, %entry ], [ %inc, %loop ]\n"
276       "  %array_const_idx = getelementptr inbounds [10 x i32], [10 x i32]* @known_constant, i64 0, i64 %iv\n"
277       "  %const_array_element = load i32, i32* %array_const_idx, align 4\n"
278       "  %se = sext i32 %const_array_element to i64\n"
279       "  %ze = zext i32 %const_array_element to i64\n"
280       "  %tr = trunc i32 %const_array_element to i8\n"
281       "  %inc = add nuw nsw i64 %iv, 1\n"
282       "  %exitcond86.i = icmp eq i64 %inc, 10\n"
283       "  br i1 %exitcond86.i, label %loop.end, label %loop\n"
284       "\n"
285       "loop.end:\n"
286       "  ret void\n"
287       "}\n";
288 
289   UnrollAnalyzerTest *P = new UnrollAnalyzerTest();
290   LLVMContext Context;
291   std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
292   legacy::PassManager Passes;
293   Passes.add(P);
294   Passes.run(*M);
295 
296   // Perform checks
297   Module::iterator MI = M->begin();
298   Function *F = &*MI++;
299   Function::iterator FI = F->begin();
300   FI++; // First basic block is entry - skip it.
301   BasicBlock *Header = &*FI++;
302 
303   BasicBlock::iterator BBI = Header->begin();
304   std::advance(BBI, 3);
305   Instruction *Y1 = &*BBI++;
306   Instruction *Y2 = &*BBI++;
307   Instruction *Y3 = &*BBI++;
308   // Check simplification expected on the 5th iteration.
309   // "%se = sext i32 %const_array_element to i64" should be simplified to 259,
310   // "%ze = zext i32 %const_array_element to i64" should be simplified to 259,
311   // "%tr = trunc i32 %const_array_element to i8" should be simplified to 3.
312   auto I1 = SimplifiedValuesVector[5].find(Y1);
313   EXPECT_TRUE(I1 != SimplifiedValuesVector[5].end());
314   EXPECT_EQ(cast<ConstantInt>((*I1).second)->getZExtValue(), 259U);
315   auto I2 = SimplifiedValuesVector[5].find(Y2);
316   EXPECT_TRUE(I2 != SimplifiedValuesVector[5].end());
317   EXPECT_EQ(cast<ConstantInt>((*I2).second)->getZExtValue(), 259U);
318   auto I3 = SimplifiedValuesVector[5].find(Y3);
319   EXPECT_TRUE(I3 != SimplifiedValuesVector[5].end());
320   EXPECT_EQ(cast<ConstantInt>((*I3).second)->getZExtValue(), 3U);
321 }
322 
323 } // end namespace llvm
324 
325 INITIALIZE_PASS_BEGIN(UnrollAnalyzerTest, "unrollanalyzertestpass",
326                       "unrollanalyzertestpass", false, false)
327 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
328 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
329 INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
330 INITIALIZE_PASS_END(UnrollAnalyzerTest, "unrollanalyzertestpass",
331                     "unrollanalyzertestpass", false, false)
332