1 //===- llvm/unittest/Transforms/Vectorize/VPlanSlpTest.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/VPlanHCFGBuilder.h"
11 #include "VPlanTestBase.h"
12 #include "llvm/Analysis/VectorUtils.h"
13 #include "gtest/gtest.h"
14
15 namespace llvm {
16 namespace {
17
18 class VPlanSlpTest : public VPlanTestBase {
19 protected:
20 TargetLibraryInfoImpl TLII;
21 TargetLibraryInfo TLI;
22 DataLayout DL;
23
24 std::unique_ptr<AssumptionCache> AC;
25 std::unique_ptr<ScalarEvolution> SE;
26 std::unique_ptr<AAResults> AARes;
27 std::unique_ptr<BasicAAResult> BasicAA;
28 std::unique_ptr<LoopAccessInfo> LAI;
29 std::unique_ptr<PredicatedScalarEvolution> PSE;
30 std::unique_ptr<InterleavedAccessInfo> IAI;
31
VPlanSlpTest()32 VPlanSlpTest()
33 : TLII(), TLI(TLII),
34 DL("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-"
35 "f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:"
36 "16:32:64-S128") {}
37
getInterleavedAccessInfo(Function & F,Loop * L,VPlan & Plan)38 VPInterleavedAccessInfo getInterleavedAccessInfo(Function &F, Loop *L,
39 VPlan &Plan) {
40 AC.reset(new AssumptionCache(F));
41 SE.reset(new ScalarEvolution(F, TLI, *AC, *DT, *LI));
42 BasicAA.reset(new BasicAAResult(DL, F, TLI, *AC, &*DT, &*LI));
43 AARes.reset(new AAResults(TLI));
44 AARes->addAAResult(*BasicAA);
45 PSE.reset(new PredicatedScalarEvolution(*SE, *L));
46 LAI.reset(new LoopAccessInfo(L, &*SE, &TLI, &*AARes, &*DT, &*LI));
47 IAI.reset(new InterleavedAccessInfo(*PSE, L, &*DT, &*LI, &*LAI));
48 IAI->analyzeInterleaving(false);
49 return {Plan, *IAI};
50 }
51 };
52
TEST_F(VPlanSlpTest,testSlpSimple_2)53 TEST_F(VPlanSlpTest, testSlpSimple_2) {
54 const char *ModuleString =
55 "%struct.Test = type { i32, i32 }\n"
56 "%struct.Test3 = type { i32, i32, i32 }\n"
57 "%struct.Test4xi8 = type { i8, i8, i8 }\n"
58 "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
59 "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
60 "entry:\n"
61 " br label %for.body\n"
62 "for.body: ; preds = %for.body, "
63 "%entry\n"
64 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
65 " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
66 "%indvars.iv, i32 0\n"
67 " %vA0 = load i32, i32* %A0, align 4\n"
68 " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
69 "%indvars.iv, i32 0\n"
70 " %vB0 = load i32, i32* %B0, align 4\n"
71 " %add0 = add nsw i32 %vA0, %vB0\n"
72 " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
73 "%indvars.iv, i32 1\n"
74 " %vA1 = load i32, i32* %A1, align 4\n"
75 " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
76 "%indvars.iv, i32 1\n"
77 " %vB1 = load i32, i32* %B1, align 4\n"
78 " %add1 = add nsw i32 %vA1, %vB1\n"
79 " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
80 "%indvars.iv, i32 0\n"
81 " store i32 %add0, i32* %C0, align 4\n"
82 " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
83 "%indvars.iv, i32 1\n"
84 " store i32 %add1, i32* %C1, align 4\n"
85 " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
86 " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
87 " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
88 "for.cond.cleanup: ; preds = %for.body\n"
89 " ret void\n"
90 "}\n";
91
92 Module &M = parseModule(ModuleString);
93
94 Function *F = M.getFunction("add_x2");
95 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
96 auto Plan = buildHCFG(LoopHeader);
97 auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
98
99 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
100 EXPECT_NE(nullptr, Entry->getSingleSuccessor());
101 VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
102
103 VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
104 VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
105
106 VPlanSlp Slp(VPIAI, *Body);
107 SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
108 VPInstruction *CombinedStore = Slp.buildGraph(StoreRoot);
109 EXPECT_EQ(64u, Slp.getWidestBundleBits());
110 EXPECT_EQ(VPInstruction::SLPStore, CombinedStore->getOpcode());
111
112 auto *CombinedAdd = cast<VPInstruction>(CombinedStore->getOperand(0));
113 EXPECT_EQ(Instruction::Add, CombinedAdd->getOpcode());
114
115 auto *CombinedLoadA = cast<VPInstruction>(CombinedAdd->getOperand(0));
116 auto *CombinedLoadB = cast<VPInstruction>(CombinedAdd->getOperand(1));
117 EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadA->getOpcode());
118 EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadB->getOpcode());
119 }
120
TEST_F(VPlanSlpTest,testSlpSimple_3)121 TEST_F(VPlanSlpTest, testSlpSimple_3) {
122 const char *ModuleString =
123 "%struct.Test = type { i32, i32 }\n"
124 "%struct.Test3 = type { i32, i32, i32 }\n"
125 "%struct.Test4xi8 = type { i8, i8, i8 }\n"
126 "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
127 "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
128 "entry:\n"
129 " br label %for.body\n"
130 "for.body: ; preds = %for.body, "
131 "%entry\n"
132 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
133 " %A0 = getelementptr %struct.Test, %struct.Test* %A, i64 "
134 " %indvars.iv, i32 0\n"
135 " %vA0 = load i32, i32* %A0, align 4\n"
136 " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
137 " %indvars.iv, i32 0\n"
138 " %vB0 = load i32, i32* %B0, align 4\n"
139 " %add0 = add nsw i32 %vA0, %vB0\n"
140 " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
141 " %indvars.iv, i32 1\n"
142 " %vA1 = load i32, i32* %A1, align 4\n"
143 " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
144 " %indvars.iv, i32 1\n"
145 " %vB1 = load i32, i32* %B1, align 4\n"
146 " %add1 = add nsw i32 %vA1, %vB1\n"
147 " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
148 " %indvars.iv, i32 0\n"
149 " store i32 %add0, i32* %C0, align 4\n"
150 " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
151 " %indvars.iv, i32 1\n"
152 " store i32 %add1, i32* %C1, align 4\n"
153 " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
154 " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
155 " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
156 "for.cond.cleanup: ; preds = %for.body\n"
157 " ret void\n"
158 "}\n";
159
160 Module &M = parseModule(ModuleString);
161
162 Function *F = M.getFunction("add_x2");
163 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
164 auto Plan = buildHCFG(LoopHeader);
165
166 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
167 EXPECT_NE(nullptr, Entry->getSingleSuccessor());
168 VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
169
170 VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
171 VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
172
173 auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
174
175 VPlanSlp Slp(VPIAI, *Body);
176 SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
177 VPInstruction *CombinedStore = Slp.buildGraph(StoreRoot);
178 EXPECT_EQ(64u, Slp.getWidestBundleBits());
179 EXPECT_EQ(VPInstruction::SLPStore, CombinedStore->getOpcode());
180
181 auto *CombinedAdd = cast<VPInstruction>(CombinedStore->getOperand(0));
182 EXPECT_EQ(Instruction::Add, CombinedAdd->getOpcode());
183
184 auto *CombinedLoadA = cast<VPInstruction>(CombinedAdd->getOperand(0));
185 auto *CombinedLoadB = cast<VPInstruction>(CombinedAdd->getOperand(1));
186 EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadA->getOpcode());
187 EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadB->getOpcode());
188
189 VPInstruction *GetA = cast<VPInstruction>(&*std::next(Body->begin(), 1));
190 VPInstruction *GetB = cast<VPInstruction>(&*std::next(Body->begin(), 3));
191 EXPECT_EQ(GetA, CombinedLoadA->getOperand(0));
192 EXPECT_EQ(GetB, CombinedLoadB->getOperand(0));
193 }
194
TEST_F(VPlanSlpTest,testSlpReuse_1)195 TEST_F(VPlanSlpTest, testSlpReuse_1) {
196 const char *ModuleString =
197 "%struct.Test = type { i32, i32 }\n"
198 "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
199 "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
200 "entry:\n"
201 " br label %for.body\n"
202 "for.body: ; preds = %for.body, "
203 "%entry\n"
204 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
205 " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
206 "%indvars.iv, i32 0\n"
207 " %vA0 = load i32, i32* %A0, align 4\n"
208 " %add0 = add nsw i32 %vA0, %vA0\n"
209 " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
210 "%indvars.iv, i32 1\n"
211 " %vA1 = load i32, i32* %A1, align 4\n"
212 " %add1 = add nsw i32 %vA1, %vA1\n"
213 " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
214 "%indvars.iv, i32 0\n"
215 " store i32 %add0, i32* %C0, align 4\n"
216 " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
217 "%indvars.iv, i32 1\n"
218 " store i32 %add1, i32* %C1, align 4\n"
219 " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
220 " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
221 " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
222 "for.cond.cleanup: ; preds = %for.body\n"
223 " ret void\n"
224 "}\n";
225
226 Module &M = parseModule(ModuleString);
227
228 Function *F = M.getFunction("add_x2");
229 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
230 auto Plan = buildHCFG(LoopHeader);
231 auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
232
233 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
234 EXPECT_NE(nullptr, Entry->getSingleSuccessor());
235 VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
236
237 VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 8));
238 VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 10));
239
240 VPlanSlp Slp(VPIAI, *Body);
241 SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
242 VPInstruction *CombinedStore = Slp.buildGraph(StoreRoot);
243 EXPECT_EQ(64u, Slp.getWidestBundleBits());
244 EXPECT_EQ(VPInstruction::SLPStore, CombinedStore->getOpcode());
245
246 auto *CombinedAdd = cast<VPInstruction>(CombinedStore->getOperand(0));
247 EXPECT_EQ(Instruction::Add, CombinedAdd->getOpcode());
248
249 auto *CombinedLoadA = cast<VPInstruction>(CombinedAdd->getOperand(0));
250 EXPECT_EQ(CombinedLoadA, CombinedAdd->getOperand(1));
251 EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadA->getOpcode());
252 }
253
TEST_F(VPlanSlpTest,testSlpReuse_2)254 TEST_F(VPlanSlpTest, testSlpReuse_2) {
255 const char *ModuleString =
256 "%struct.Test = type { i32, i32 }\n"
257 "define i32 @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
258 "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
259 "entry:\n"
260 " br label %for.body\n"
261 "for.body: ; preds = %for.body, "
262 "%entry\n"
263 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
264 " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
265 "%indvars.iv, i32 0\n"
266 " %vA0 = load i32, i32* %A0, align 4\n"
267 " %add0 = add nsw i32 %vA0, %vA0\n"
268 " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
269 "%indvars.iv, i32 0\n"
270 " store i32 %add0, i32* %C0, align 4\n"
271 " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
272 "%indvars.iv, i32 1\n"
273 " %vA1 = load i32, i32* %A1, align 4\n"
274 " %add1 = add nsw i32 %vA1, %vA1\n"
275 " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
276 "%indvars.iv, i32 1\n"
277 " store i32 %add1, i32* %C1, align 4\n"
278 " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
279 " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
280 " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
281 "for.cond.cleanup: ; preds = %for.body\n"
282 " ret i32 %vA1\n"
283 "}\n";
284
285 Module &M = parseModule(ModuleString);
286
287 Function *F = M.getFunction("add_x2");
288 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
289 auto Plan = buildHCFG(LoopHeader);
290 auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
291
292 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
293 EXPECT_NE(nullptr, Entry->getSingleSuccessor());
294 VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
295
296 VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 5));
297 VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 10));
298
299 VPlanSlp Slp(VPIAI, *Body);
300 SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
301 Slp.buildGraph(StoreRoot);
302 EXPECT_FALSE(Slp.isCompletelySLP());
303 }
304
checkReorderExample(VPInstruction * Store1,VPInstruction * Store2,VPBasicBlock * Body,VPInterleavedAccessInfo && IAI)305 static void checkReorderExample(VPInstruction *Store1, VPInstruction *Store2,
306 VPBasicBlock *Body,
307 VPInterleavedAccessInfo &&IAI) {
308 VPlanSlp Slp(IAI, *Body);
309 SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
310 VPInstruction *CombinedStore = Slp.buildGraph(StoreRoot);
311
312 EXPECT_TRUE(Slp.isCompletelySLP());
313 EXPECT_EQ(CombinedStore->getOpcode(), VPInstruction::SLPStore);
314
315 VPInstruction *CombinedAdd =
316 cast<VPInstruction>(CombinedStore->getOperand(0));
317 EXPECT_EQ(CombinedAdd->getOpcode(), Instruction::Add);
318
319 VPInstruction *CombinedMulAB =
320 cast<VPInstruction>(CombinedAdd->getOperand(0));
321 VPInstruction *CombinedMulCD =
322 cast<VPInstruction>(CombinedAdd->getOperand(1));
323 EXPECT_EQ(CombinedMulAB->getOpcode(), Instruction::Mul);
324
325 VPInstruction *CombinedLoadA =
326 cast<VPInstruction>(CombinedMulAB->getOperand(0));
327 EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadA->getOpcode());
328 VPInstruction *LoadvA0 = cast<VPInstruction>(&*std::next(Body->begin(), 2));
329 VPInstruction *LoadvA1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
330 EXPECT_EQ(LoadvA0->getOperand(0), CombinedLoadA->getOperand(0));
331 EXPECT_EQ(LoadvA1->getOperand(0), CombinedLoadA->getOperand(1));
332
333 VPInstruction *CombinedLoadB =
334 cast<VPInstruction>(CombinedMulAB->getOperand(1));
335 EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadB->getOpcode());
336 VPInstruction *LoadvB0 = cast<VPInstruction>(&*std::next(Body->begin(), 4));
337 VPInstruction *LoadvB1 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
338 EXPECT_EQ(LoadvB0->getOperand(0), CombinedLoadB->getOperand(0));
339 EXPECT_EQ(LoadvB1->getOperand(0), CombinedLoadB->getOperand(1));
340
341 EXPECT_EQ(CombinedMulCD->getOpcode(), Instruction::Mul);
342
343 VPInstruction *CombinedLoadC =
344 cast<VPInstruction>(CombinedMulCD->getOperand(0));
345 EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadC->getOpcode());
346 VPInstruction *LoadvC0 = cast<VPInstruction>(&*std::next(Body->begin(), 7));
347 VPInstruction *LoadvC1 = cast<VPInstruction>(&*std::next(Body->begin(), 17));
348 EXPECT_EQ(LoadvC0->getOperand(0), CombinedLoadC->getOperand(0));
349 EXPECT_EQ(LoadvC1->getOperand(0), CombinedLoadC->getOperand(1));
350
351 VPInstruction *CombinedLoadD =
352 cast<VPInstruction>(CombinedMulCD->getOperand(1));
353 EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadD->getOpcode());
354 VPInstruction *LoadvD0 = cast<VPInstruction>(&*std::next(Body->begin(), 9));
355 VPInstruction *LoadvD1 = cast<VPInstruction>(&*std::next(Body->begin(), 19));
356 EXPECT_EQ(LoadvD0->getOperand(0), CombinedLoadD->getOperand(0));
357 EXPECT_EQ(LoadvD1->getOperand(0), CombinedLoadD->getOperand(1));
358 }
359
TEST_F(VPlanSlpTest,testSlpReorder_1)360 TEST_F(VPlanSlpTest, testSlpReorder_1) {
361 LLVMContext Ctx;
362 const char *ModuleString =
363 "%struct.Test = type { i32, i32 }\n"
364 "define void @add_x3(%struct.Test* %A, %struct.Test* %B, %struct.Test* "
365 "%C, %struct.Test* %D, %struct.Test* %E) {\n"
366 "entry:\n"
367 " br label %for.body\n"
368 "for.body: ; preds = %for.body, "
369 "%entry\n"
370 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
371 " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
372 "%indvars.iv, i32 0\n"
373 " %vA0 = load i32, i32* %A0, align 4\n"
374 " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
375 "%indvars.iv, i32 0\n"
376 " %vB0 = load i32, i32* %B0, align 4\n"
377 " %mul11 = mul nsw i32 %vA0, %vB0\n"
378 " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
379 "%indvars.iv, i32 0\n"
380 " %vC0 = load i32, i32* %C0, align 4\n"
381 " %D0 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
382 "%indvars.iv, i32 0\n"
383 " %vD0 = load i32, i32* %D0, align 4\n"
384 " %mul12 = mul nsw i32 %vC0, %vD0\n"
385 " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
386 "%indvars.iv, i32 1\n"
387 " %vA1 = load i32, i32* %A1, align 4\n"
388 " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
389 "%indvars.iv, i32 1\n"
390 " %vB1 = load i32, i32* %B1, align 4\n"
391 " %mul21 = mul nsw i32 %vA1, %vB1\n"
392 " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
393 "%indvars.iv, i32 1\n"
394 " %vC1 = load i32, i32* %C1, align 4\n"
395 " %D1 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
396 "%indvars.iv, i32 1\n"
397 " %vD1 = load i32, i32* %D1, align 4\n"
398 " %mul22 = mul nsw i32 %vC1, %vD1\n"
399 " %add1 = add nsw i32 %mul11, %mul12\n"
400 " %add2 = add nsw i32 %mul22, %mul21\n"
401 " %E0 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
402 "%indvars.iv, i32 0\n"
403 " store i32 %add1, i32* %E0, align 4\n"
404 " %E1 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
405 "%indvars.iv, i32 1\n"
406 " store i32 %add2, i32* %E1, align 4\n"
407 " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
408 " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
409 " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
410 "for.cond.cleanup: ; preds = %for.body\n"
411 " ret void\n"
412 "}\n";
413
414 Module &M = parseModule(ModuleString);
415
416 Function *F = M.getFunction("add_x3");
417 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
418 auto Plan = buildHCFG(LoopHeader);
419
420 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
421 EXPECT_NE(nullptr, Entry->getSingleSuccessor());
422 VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
423
424 VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 24));
425 VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 26));
426
427 checkReorderExample(
428 Store1, Store2, Body,
429 getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan));
430 }
431
TEST_F(VPlanSlpTest,testSlpReorder_2)432 TEST_F(VPlanSlpTest, testSlpReorder_2) {
433 LLVMContext Ctx;
434 const char *ModuleString =
435 "%struct.Test = type { i32, i32 }\n"
436 "define void @add_x3(%struct.Test* %A, %struct.Test* %B, %struct.Test* "
437 "%C, %struct.Test* %D, %struct.Test* %E) {\n"
438 "entry:\n"
439 " br label %for.body\n"
440 "for.body: ; preds = %for.body, "
441 "%entry\n"
442 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
443 " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
444 "%indvars.iv, i32 0\n"
445 " %vA0 = load i32, i32* %A0, align 4\n"
446 " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
447 "%indvars.iv, i32 0\n"
448 " %vB0 = load i32, i32* %B0, align 4\n"
449 " %mul11 = mul nsw i32 %vA0, %vB0\n"
450 " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
451 "%indvars.iv, i32 0\n"
452 " %vC0 = load i32, i32* %C0, align 4\n"
453 " %D0 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
454 "%indvars.iv, i32 0\n"
455 " %vD0 = load i32, i32* %D0, align 4\n"
456 " %mul12 = mul nsw i32 %vC0, %vD0\n"
457 " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
458 "%indvars.iv, i32 1\n"
459 " %vA1 = load i32, i32* %A1, align 4\n"
460 " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
461 "%indvars.iv, i32 1\n"
462 " %vB1 = load i32, i32* %B1, align 4\n"
463 " %mul21 = mul nsw i32 %vB1, %vA1\n"
464 " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
465 "%indvars.iv, i32 1\n"
466 " %vC1 = load i32, i32* %C1, align 4\n"
467 " %D1 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
468 "%indvars.iv, i32 1\n"
469 " %vD1 = load i32, i32* %D1, align 4\n"
470 " %mul22 = mul nsw i32 %vD1, %vC1\n"
471 " %add1 = add nsw i32 %mul11, %mul12\n"
472 " %add2 = add nsw i32 %mul22, %mul21\n"
473 " %E0 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
474 "%indvars.iv, i32 0\n"
475 " store i32 %add1, i32* %E0, align 4\n"
476 " %E1 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
477 "%indvars.iv, i32 1\n"
478 " store i32 %add2, i32* %E1, align 4\n"
479 " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
480 " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
481 " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
482 "for.cond.cleanup: ; preds = %for.body\n"
483 " ret void\n"
484 "}\n";
485
486 Module &M = parseModule(ModuleString);
487
488 Function *F = M.getFunction("add_x3");
489 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
490 auto Plan = buildHCFG(LoopHeader);
491
492 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
493 EXPECT_NE(nullptr, Entry->getSingleSuccessor());
494 VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
495
496 VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 24));
497 VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 26));
498
499 checkReorderExample(
500 Store1, Store2, Body,
501 getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan));
502 }
503
TEST_F(VPlanSlpTest,testSlpReorder_3)504 TEST_F(VPlanSlpTest, testSlpReorder_3) {
505 LLVMContext Ctx;
506 const char *ModuleString =
507 "%struct.Test = type { i32, i32 }\n"
508 "define void @add_x3(%struct.Test* %A, %struct.Test* %B, %struct.Test* "
509 "%C, %struct.Test* %D, %struct.Test* %E) {\n"
510 "entry:\n"
511 " br label %for.body\n"
512 "for.body: ; preds = %for.body, "
513 "%entry\n"
514 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
515 " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
516 "%indvars.iv, i32 1\n"
517 " %vA1 = load i32, i32* %A1, align 4\n"
518 " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
519 "%indvars.iv, i32 0\n"
520 " %vB0 = load i32, i32* %B0, align 4\n"
521 " %mul11 = mul nsw i32 %vA1, %vB0\n"
522 " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
523 "%indvars.iv, i32 0\n"
524 " %vC0 = load i32, i32* %C0, align 4\n"
525 " %D0 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
526 "%indvars.iv, i32 0\n"
527 " %vD0 = load i32, i32* %D0, align 4\n"
528 " %mul12 = mul nsw i32 %vC0, %vD0\n"
529 " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
530 "%indvars.iv, i32 0\n"
531 " %vA0 = load i32, i32* %A0, align 4\n"
532 " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
533 "%indvars.iv, i32 1\n"
534 " %vB1 = load i32, i32* %B1, align 4\n"
535 " %mul21 = mul nsw i32 %vB1, %vA0\n"
536 " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
537 "%indvars.iv, i32 1\n"
538 " %vC1 = load i32, i32* %C1, align 4\n"
539 " %D1 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
540 "%indvars.iv, i32 1\n"
541 " %vD1 = load i32, i32* %D1, align 4\n"
542 " %mul22 = mul nsw i32 %vD1, %vC1\n"
543 " %add1 = add nsw i32 %mul11, %mul12\n"
544 " %add2 = add nsw i32 %mul22, %mul21\n"
545 " %E0 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
546 "%indvars.iv, i32 0\n"
547 " store i32 %add1, i32* %E0, align 4\n"
548 " %E1 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
549 "%indvars.iv, i32 1\n"
550 " store i32 %add2, i32* %E1, align 4\n"
551 " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
552 " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
553 " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
554 "for.cond.cleanup: ; preds = %for.body\n"
555 " ret void\n"
556 "}\n";
557
558 Module &M = parseModule(ModuleString);
559
560 Function *F = M.getFunction("add_x3");
561 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
562 auto Plan = buildHCFG(LoopHeader);
563
564 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
565 EXPECT_NE(nullptr, Entry->getSingleSuccessor());
566 VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
567
568 VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 24));
569 VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 26));
570
571 auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
572 VPlanSlp Slp(VPIAI, *Body);
573 SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
574 EXPECT_EQ(nullptr, Slp.buildGraph(StoreRoot));
575
576 // FIXME Need to select better first value for lane0.
577 EXPECT_FALSE(Slp.isCompletelySLP());
578 }
579
TEST_F(VPlanSlpTest,testSlpReorder_4)580 TEST_F(VPlanSlpTest, testSlpReorder_4) {
581 LLVMContext Ctx;
582 const char *ModuleString =
583 "%struct.Test = type { i32, i32 }\n"
584 "define void @add_x3(%struct.Test* %A, %struct.Test* %B, %struct.Test* "
585 "%C, %struct.Test* %D, %struct.Test* %E) {\n"
586 "entry:\n"
587 " br label %for.body\n"
588 "for.body: ; preds = %for.body, "
589 "%entry\n"
590 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
591 " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
592 "%indvars.iv, i32 0\n"
593 " %vA0 = load i32, i32* %A0, align 4\n"
594 " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
595 "%indvars.iv, i32 0\n"
596 " %vB0 = load i32, i32* %B0, align 4\n"
597 " %mul11 = mul nsw i32 %vA0, %vB0\n"
598 " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
599 "%indvars.iv, i32 0\n"
600 " %vC0 = load i32, i32* %C0, align 4\n"
601 " %D0 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
602 "%indvars.iv, i32 0\n"
603 " %vD0 = load i32, i32* %D0, align 4\n"
604 " %mul12 = mul nsw i32 %vC0, %vD0\n"
605 " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
606 "%indvars.iv, i32 1\n"
607 " %vA1 = load i32, i32* %A1, align 4\n"
608 " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
609 "%indvars.iv, i32 1\n"
610 " %vB1 = load i32, i32* %B1, align 4\n"
611 " %mul21 = mul nsw i32 %vA1, %vB1\n"
612 " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
613 "%indvars.iv, i32 1\n"
614 " %vC1 = load i32, i32* %C1, align 4\n"
615 " %D1 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
616 "%indvars.iv, i32 1\n"
617 " %vD1 = load i32, i32* %D1, align 4\n"
618 " %mul22 = mul nsw i32 %vC1, %vD1\n"
619 " %add1 = add nsw i32 %mul11, %mul12\n"
620 " %add2 = add nsw i32 %mul22, %mul21\n"
621 " %E0 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
622 "%indvars.iv, i32 0\n"
623 " store i32 %add1, i32* %E0, align 4\n"
624 " %E1 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
625 "%indvars.iv, i32 1\n"
626 " store i32 %add2, i32* %E1, align 4\n"
627 " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
628 " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
629 " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
630 "for.cond.cleanup: ; preds = %for.body\n"
631 " ret void\n"
632 "}\n";
633
634 Module &M = parseModule(ModuleString);
635
636 Function *F = M.getFunction("add_x3");
637 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
638 auto Plan = buildHCFG(LoopHeader);
639
640 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
641 EXPECT_NE(nullptr, Entry->getSingleSuccessor());
642 VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
643
644 VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 24));
645 VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 26));
646
647 checkReorderExample(
648 Store1, Store2, Body,
649 getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan));
650 }
651
652 // Make sure we do not combine instructions with operands in different BBs.
TEST_F(VPlanSlpTest,testInstrsInDifferentBBs)653 TEST_F(VPlanSlpTest, testInstrsInDifferentBBs) {
654 const char *ModuleString =
655 "%struct.Test = type { i32, i32 }\n"
656 "%struct.Test3 = type { i32, i32, i32 }\n"
657 "%struct.Test4xi8 = type { i8, i8, i8 }\n"
658 "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
659 "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
660 "entry:\n"
661 " br label %for.body\n"
662 "for.body: ; preds = %for.body, "
663 "%entry\n"
664 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
665 " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
666 "%indvars.iv, i32 0\n"
667 " %vA0 = load i32, i32* %A0, align 4\n"
668 " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
669 "%indvars.iv, i32 0\n"
670 " %vB0 = load i32, i32* %B0, align 4\n"
671 " %add0 = add nsw i32 %vA0, %vB0\n"
672 " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
673 "%indvars.iv, i32 1\n"
674 " %vA1 = load i32, i32* %A1, align 4\n"
675 " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
676 "%indvars.iv, i32 1\n"
677 " br label %bb2\n"
678 "bb2:\n"
679 " %vB1 = load i32, i32* %B1, align 4\n"
680 " %add1 = add nsw i32 %vA1, %vB1\n"
681 " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
682 "%indvars.iv, i32 0\n"
683 " store i32 %add0, i32* %C0, align 4\n"
684 " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
685 "%indvars.iv, i32 1\n"
686 " store i32 %add1, i32* %C1, align 4\n"
687 " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
688 " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
689 " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
690 "for.cond.cleanup: ; preds = %for.body\n"
691 " ret void\n"
692 "}\n";
693
694 Module &M = parseModule(ModuleString);
695
696 Function *F = M.getFunction("add_x2");
697 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
698 auto Plan = buildHCFG(LoopHeader);
699 auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
700
701 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
702 EXPECT_NE(nullptr, Entry->getSingleSuccessor());
703 VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
704 VPBasicBlock *BB2 = Body->getSingleSuccessor()->getEntryBasicBlock();
705
706 VPInstruction *Store1 = cast<VPInstruction>(&*std::next(BB2->begin(), 3));
707 VPInstruction *Store2 = cast<VPInstruction>(&*std::next(BB2->begin(), 5));
708
709 VPlanSlp Slp(VPIAI, *BB2);
710 SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
711 EXPECT_EQ(nullptr, Slp.buildGraph(StoreRoot));
712 EXPECT_EQ(0u, Slp.getWidestBundleBits());
713 }
714
715 // Make sure we do not combine instructions with operands in different BBs.
TEST_F(VPlanSlpTest,testInstrsInDifferentBBs2)716 TEST_F(VPlanSlpTest, testInstrsInDifferentBBs2) {
717 const char *ModuleString =
718 "%struct.Test = type { i32, i32 }\n"
719 "%struct.Test3 = type { i32, i32, i32 }\n"
720 "%struct.Test4xi8 = type { i8, i8, i8 }\n"
721 "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
722 "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
723 "entry:\n"
724 " br label %for.body\n"
725 "for.body: ; preds = %for.body, "
726 "%entry\n"
727 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
728 " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
729 "%indvars.iv, i32 0\n"
730 " %vA0 = load i32, i32* %A0, align 4\n"
731 " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
732 "%indvars.iv, i32 0\n"
733 " %vB0 = load i32, i32* %B0, align 4\n"
734 " %add0 = add nsw i32 %vA0, %vB0\n"
735 " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
736 "%indvars.iv, i32 1\n"
737 " %vA1 = load i32, i32* %A1, align 4\n"
738 " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
739 "%indvars.iv, i32 1\n"
740 " %vB1 = load i32, i32* %B1, align 4\n"
741 " %add1 = add nsw i32 %vA1, %vB1\n"
742 " br label %bb2\n"
743 "bb2:\n"
744 " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
745 "%indvars.iv, i32 0\n"
746 " store i32 %add0, i32* %C0, align 4\n"
747 " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
748 "%indvars.iv, i32 1\n"
749 " store i32 %add1, i32* %C1, align 4\n"
750 " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
751 " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
752 " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
753 "for.cond.cleanup: ; preds = %for.body\n"
754 " ret void\n"
755 "}\n";
756
757 Module &M = parseModule(ModuleString);
758
759 Function *F = M.getFunction("add_x2");
760 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
761 auto Plan = buildHCFG(LoopHeader);
762 auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
763
764 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
765 EXPECT_NE(nullptr, Entry->getSingleSuccessor());
766 VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
767 VPBasicBlock *BB2 = Body->getSingleSuccessor()->getEntryBasicBlock();
768
769 VPInstruction *Store1 = cast<VPInstruction>(&*std::next(BB2->begin(), 1));
770 VPInstruction *Store2 = cast<VPInstruction>(&*std::next(BB2->begin(), 3));
771
772 VPlanSlp Slp(VPIAI, *BB2);
773 SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
774 EXPECT_EQ(nullptr, Slp.buildGraph(StoreRoot));
775 EXPECT_EQ(0u, Slp.getWidestBundleBits());
776 }
777
TEST_F(VPlanSlpTest,testSlpAtomicLoad)778 TEST_F(VPlanSlpTest, testSlpAtomicLoad) {
779 const char *ModuleString =
780 "%struct.Test = type { i32, i32 }\n"
781 "%struct.Test3 = type { i32, i32, i32 }\n"
782 "%struct.Test4xi8 = type { i8, i8, i8 }\n"
783 "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
784 "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
785 "entry:\n"
786 " br label %for.body\n"
787 "for.body: ; preds = %for.body, "
788 "%entry\n"
789 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
790 " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
791 "%indvars.iv, i32 0\n"
792 " %vA0 = load atomic i32, i32* %A0 monotonic, align 4\n"
793 " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
794 "%indvars.iv, i32 0\n"
795 " %vB0 = load i32, i32* %B0, align 4\n"
796 " %add0 = add nsw i32 %vA0, %vB0\n"
797 " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
798 "%indvars.iv, i32 1\n"
799 " %vA1 = load i32, i32* %A1, align 4\n"
800 " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
801 "%indvars.iv, i32 1\n"
802 " %vB1 = load i32, i32* %B1, align 4\n"
803 " %add1 = add nsw i32 %vA1, %vB1\n"
804 " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
805 "%indvars.iv, i32 0\n"
806 " store i32 %add0, i32* %C0, align 4\n"
807 " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
808 "%indvars.iv, i32 1\n"
809 " store i32 %add1, i32* %C1, align 4\n"
810 " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
811 " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
812 " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
813 "for.cond.cleanup: ; preds = %for.body\n"
814 " ret void\n"
815 "}\n";
816
817 Module &M = parseModule(ModuleString);
818
819 Function *F = M.getFunction("add_x2");
820 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
821 auto Plan = buildHCFG(LoopHeader);
822 auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
823
824 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
825 EXPECT_NE(nullptr, Entry->getSingleSuccessor());
826 VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
827
828 VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
829 VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
830
831 VPlanSlp Slp(VPIAI, *Body);
832 SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
833 EXPECT_EQ(nullptr, Slp.buildGraph(StoreRoot));
834 EXPECT_FALSE(Slp.isCompletelySLP());
835 }
836
TEST_F(VPlanSlpTest,testSlpAtomicStore)837 TEST_F(VPlanSlpTest, testSlpAtomicStore) {
838 const char *ModuleString =
839 "%struct.Test = type { i32, i32 }\n"
840 "%struct.Test3 = type { i32, i32, i32 }\n"
841 "%struct.Test4xi8 = type { i8, i8, i8 }\n"
842 "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
843 "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
844 "entry:\n"
845 " br label %for.body\n"
846 "for.body: ; preds = %for.body, "
847 "%entry\n"
848 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
849 " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
850 "%indvars.iv, i32 0\n"
851 " %vA0 = load i32, i32* %A0, align 4\n"
852 " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
853 "%indvars.iv, i32 0\n"
854 " %vB0 = load i32, i32* %B0, align 4\n"
855 " %add0 = add nsw i32 %vA0, %vB0\n"
856 " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
857 "%indvars.iv, i32 1\n"
858 " %vA1 = load i32, i32* %A1, align 4\n"
859 " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
860 "%indvars.iv, i32 1\n"
861 " %vB1 = load i32, i32* %B1, align 4\n"
862 " %add1 = add nsw i32 %vA1, %vB1\n"
863 " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
864 "%indvars.iv, i32 0\n"
865 " store atomic i32 %add0, i32* %C0 monotonic, align 4\n"
866 " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
867 "%indvars.iv, i32 1\n"
868 " store i32 %add1, i32* %C1, align 4\n"
869 " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
870 " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
871 " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
872 "for.cond.cleanup: ; preds = %for.body\n"
873 " ret void\n"
874 "}\n";
875
876 Module &M = parseModule(ModuleString);
877
878 Function *F = M.getFunction("add_x2");
879 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
880 auto Plan = buildHCFG(LoopHeader);
881 auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
882
883 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
884 EXPECT_NE(nullptr, Entry->getSingleSuccessor());
885 VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
886
887 VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
888 VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
889
890 VPlanSlp Slp(VPIAI, *Body);
891 SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
892 Slp.buildGraph(StoreRoot);
893 EXPECT_FALSE(Slp.isCompletelySLP());
894 }
895
896 } // namespace
897 } // namespace llvm
898