xref: /llvm-project/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp (revision 0558fe3bbf575f562e8bde4cb73cf47e0b6a8153)
1 //===- llvm/unittest/Transforms/Vectorize/VPlanHCFGTest.cpp ---------------===//
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 "../lib/Transforms/Vectorize/VPlan.h"
10 #include "../lib/Transforms/Vectorize/VPlanTransforms.h"
11 #include "VPlanTestBase.h"
12 #include "llvm/Analysis/TargetLibraryInfo.h"
13 #include "llvm/TargetParser/Triple.h"
14 #include "gtest/gtest.h"
15 #include <string>
16 
17 namespace llvm {
18 namespace {
19 
20 class VPlanHCFGTest : public VPlanTestBase {};
21 
22 TEST_F(VPlanHCFGTest, testBuildHCFGInnerLoop) {
23   const char *ModuleString =
24       "define void @f(ptr %A, i64 %N) {\n"
25       "entry:\n"
26       "  br label %for.body\n"
27       "for.body:\n"
28       "  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
29       "  %arr.idx = getelementptr inbounds i32, ptr %A, i64 %indvars.iv\n"
30       "  %l1 = load i32, ptr %arr.idx, align 4\n"
31       "  %res = add i32 %l1, 10\n"
32       "  store i32 %res, ptr %arr.idx, align 4\n"
33       "  %indvars.iv.next = add i64 %indvars.iv, 1\n"
34       "  %exitcond = icmp ne i64 %indvars.iv.next, %N\n"
35       "  br i1 %exitcond, label %for.body, label %for.end\n"
36       "for.end:\n"
37       "  ret void\n"
38       "}\n";
39 
40   Module &M = parseModule(ModuleString);
41 
42   Function *F = M.getFunction("f");
43   BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
44   auto Plan = buildHCFG(LoopHeader);
45 
46   VPBasicBlock *Entry = Plan->getEntry()->getEntryBasicBlock();
47   EXPECT_NE(nullptr, Entry->getSingleSuccessor());
48   EXPECT_EQ(0u, Entry->getNumPredecessors());
49   EXPECT_EQ(1u, Entry->getNumSuccessors());
50 
51   // Check that the region following the preheader is a single basic-block
52   // region (loop).
53   VPBasicBlock *VecBB = Plan->getVectorLoopRegion()->getEntryBasicBlock();
54   EXPECT_EQ(8u, VecBB->size());
55   EXPECT_EQ(0u, VecBB->getNumPredecessors());
56   EXPECT_EQ(0u, VecBB->getNumSuccessors());
57   EXPECT_EQ(VecBB->getParent()->getEntryBasicBlock(), VecBB);
58   EXPECT_EQ(VecBB->getParent()->getExitingBasicBlock(), VecBB);
59   EXPECT_EQ(&*Plan, VecBB->getPlan());
60 
61   auto Iter = VecBB->begin();
62   VPWidenPHIRecipe *Phi = dyn_cast<VPWidenPHIRecipe>(&*Iter++);
63   EXPECT_NE(nullptr, Phi);
64 
65   VPInstruction *Idx = dyn_cast<VPInstruction>(&*Iter++);
66   EXPECT_EQ(Instruction::GetElementPtr, Idx->getOpcode());
67   EXPECT_EQ(2u, Idx->getNumOperands());
68   EXPECT_EQ(Phi, Idx->getOperand(1));
69 
70   VPInstruction *Load = dyn_cast<VPInstruction>(&*Iter++);
71   EXPECT_EQ(Instruction::Load, Load->getOpcode());
72   EXPECT_EQ(1u, Load->getNumOperands());
73   EXPECT_EQ(Idx, Load->getOperand(0));
74 
75   VPInstruction *Add = dyn_cast<VPInstruction>(&*Iter++);
76   EXPECT_EQ(Instruction::Add, Add->getOpcode());
77   EXPECT_EQ(2u, Add->getNumOperands());
78   EXPECT_EQ(Load, Add->getOperand(0));
79 
80   VPInstruction *Store = dyn_cast<VPInstruction>(&*Iter++);
81   EXPECT_EQ(Instruction::Store, Store->getOpcode());
82   EXPECT_EQ(2u, Store->getNumOperands());
83   EXPECT_EQ(Add, Store->getOperand(0));
84   EXPECT_EQ(Idx, Store->getOperand(1));
85 
86   VPInstruction *IndvarAdd = dyn_cast<VPInstruction>(&*Iter++);
87   EXPECT_EQ(Instruction::Add, IndvarAdd->getOpcode());
88   EXPECT_EQ(2u, IndvarAdd->getNumOperands());
89   EXPECT_EQ(Phi, IndvarAdd->getOperand(0));
90 
91   VPInstruction *ICmp = dyn_cast<VPInstruction>(&*Iter++);
92   EXPECT_EQ(Instruction::ICmp, ICmp->getOpcode());
93   EXPECT_EQ(2u, ICmp->getNumOperands());
94   EXPECT_EQ(IndvarAdd, ICmp->getOperand(0));
95 
96 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
97   // Add an external value to check we do not print the list of external values,
98   // as this is not required with the new printing.
99   Plan->getOrAddLiveIn(&*F->arg_begin());
100   std::string FullDump;
101   raw_string_ostream OS(FullDump);
102   Plan->printDOT(OS);
103   const char *ExpectedStr = R"(digraph VPlan {
104 graph [labelloc=t, fontsize=30; label="Vectorization Plan\n for UF\>=1\nLive-in vp\<%0\> = vector-trip-count\nLive-in ir\<%N\> = original trip-count\n"]
105 node [shape=rect, fontname=Courier, fontsize=30]
106 edge [fontname=Courier, fontsize=30]
107 compound=true
108   N0 [label =
109     "ir-bb\<entry\>:\l" +
110     "No successors\l"
111   ]
112   N1 [label =
113     "vector.ph:\l" +
114     "Successor(s): vector loop\l"
115   ]
116   N1 -> N2 [ label="" lhead=cluster_N3]
117   subgraph cluster_N3 {
118     fontname=Courier
119     label="\<x1\> vector loop"
120     N2 [label =
121       "vector.body:\l" +
122       "  WIDEN-PHI ir\<%indvars.iv\> = phi ir\<0\>, ir\<%indvars.iv.next\>\l" +
123       "  EMIT ir\<%arr.idx\> = getelementptr ir\<%A\>, ir\<%indvars.iv\>\l" +
124       "  EMIT ir\<%l1\> = load ir\<%arr.idx\>\l" +
125       "  EMIT ir\<%res\> = add ir\<%l1\>, ir\<10\>\l" +
126       "  EMIT store ir\<%res\>, ir\<%arr.idx\>\l" +
127       "  EMIT ir\<%indvars.iv.next\> = add ir\<%indvars.iv\>, ir\<1\>\l" +
128       "  EMIT ir\<%exitcond\> = icmp ir\<%indvars.iv.next\>, ir\<%N\>\l" +
129       "  EMIT branch-on-cond ir\<%exitcond\>\l" +
130       "No successors\l"
131     ]
132   }
133   N2 -> N4 [ label="" ltail=cluster_N3]
134   N4 [label =
135     "middle.block:\l" +
136     "  EMIT vp\<%cmp.n\> = icmp eq ir\<%N\>, vp\<%0\>\l" +
137     "  EMIT branch-on-cond vp\<%cmp.n\>\l" +
138     "Successor(s): ir-bb\<for.end\>, scalar.ph\l"
139   ]
140   N4 -> N5 [ label="T"]
141   N4 -> N6 [ label="F"]
142   N5 [label =
143     "ir-bb\<for.end\>:\l" +
144     "No successors\l"
145   ]
146   N6 [label =
147     "scalar.ph:\l" +
148     "No successors\l"
149   ]
150 }
151 )";
152   EXPECT_EQ(ExpectedStr, FullDump);
153 #endif
154   TargetLibraryInfoImpl TLII(Triple(M.getTargetTriple()));
155   TargetLibraryInfo TLI(TLII);
156   VPlanTransforms::VPInstructionsToVPRecipes(
157       Plan, [](PHINode *P) { return nullptr; }, *SE, TLI);
158 }
159 
160 TEST_F(VPlanHCFGTest, testVPInstructionToVPRecipesInner) {
161   const char *ModuleString =
162       "define void @f(ptr %A, i64 %N) {\n"
163       "entry:\n"
164       "  br label %for.body\n"
165       "for.body:\n"
166       "  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
167       "  %arr.idx = getelementptr inbounds i32, ptr %A, i64 %indvars.iv\n"
168       "  %l1 = load i32, ptr %arr.idx, align 4\n"
169       "  %res = add i32 %l1, 10\n"
170       "  store i32 %res, ptr %arr.idx, align 4\n"
171       "  %indvars.iv.next = add i64 %indvars.iv, 1\n"
172       "  %exitcond = icmp ne i64 %indvars.iv.next, %N\n"
173       "  br i1 %exitcond, label %for.body, label %for.end\n"
174       "for.end:\n"
175       "  ret void\n"
176       "}\n";
177 
178   Module &M = parseModule(ModuleString);
179 
180   Function *F = M.getFunction("f");
181   BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
182   auto Plan = buildHCFG(LoopHeader);
183 
184   TargetLibraryInfoImpl TLII(Triple(M.getTargetTriple()));
185   TargetLibraryInfo TLI(TLII);
186   VPlanTransforms::VPInstructionsToVPRecipes(
187       Plan, [](PHINode *P) { return nullptr; }, *SE, TLI);
188 
189   VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
190   EXPECT_NE(nullptr, Entry->getSingleSuccessor());
191   EXPECT_EQ(0u, Entry->getNumPredecessors());
192   EXPECT_EQ(1u, Entry->getNumSuccessors());
193 
194   // Check that the region following the preheader is a single basic-block
195   // region (loop).
196   VPBasicBlock *VecBB = Plan->getVectorLoopRegion()->getEntryBasicBlock();
197   EXPECT_EQ(8u, VecBB->size());
198   EXPECT_EQ(0u, VecBB->getNumPredecessors());
199   EXPECT_EQ(0u, VecBB->getNumSuccessors());
200   EXPECT_EQ(VecBB->getParent()->getEntryBasicBlock(), VecBB);
201   EXPECT_EQ(VecBB->getParent()->getExitingBasicBlock(), VecBB);
202 
203   auto Iter = VecBB->begin();
204   EXPECT_NE(nullptr, dyn_cast<VPWidenPHIRecipe>(&*Iter++));
205   EXPECT_NE(nullptr, dyn_cast<VPWidenGEPRecipe>(&*Iter++));
206   EXPECT_NE(nullptr, dyn_cast<VPWidenMemoryRecipe>(&*Iter++));
207   EXPECT_NE(nullptr, dyn_cast<VPWidenRecipe>(&*Iter++));
208   EXPECT_NE(nullptr, dyn_cast<VPWidenMemoryRecipe>(&*Iter++));
209   EXPECT_NE(nullptr, dyn_cast<VPWidenRecipe>(&*Iter++));
210   EXPECT_NE(nullptr, dyn_cast<VPWidenRecipe>(&*Iter++));
211   EXPECT_NE(nullptr, dyn_cast<VPInstruction>(&*Iter++));
212   EXPECT_EQ(VecBB->end(), Iter);
213 }
214 
215 } // namespace
216 } // namespace llvm
217