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