[InstCombine] Signed saturation tests. NFC
[llvm-complete.git] / unittests / Transforms / Vectorize / VPlanSlpTest.cpp
blob403ffb1d315227ae1b45d6dc76def91b206bf810
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 //===----------------------------------------------------------------------===//
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"
16 namespace llvm {
17 namespace {
19 class VPlanSlpTest : public VPlanTestBase {
20 protected:
21 TargetLibraryInfoImpl TLII;
22 TargetLibraryInfo TLI;
23 DataLayout DL;
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;
33 VPlanSlpTest()
34 : TLII(), TLI(TLII),
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:"
37 "16:32:64-S128") {}
39 VPInterleavedAccessInfo getInterleavedAccessInfo(Function &F, Loop *L,
40 VPlan &Plan) {
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);
50 return {Plan, *IAI};
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"
61 "entry:\n"
62 " br label %for.body\n"
63 "for.body: ; preds = %for.body, "
64 "%entry\n"
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"
90 " ret void\n"
91 "}\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"
129 "entry:\n"
130 " br label %for.body\n"
131 "for.body: ; preds = %for.body, "
132 "%entry\n"
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"
158 " ret void\n"
159 "}\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"
201 "entry:\n"
202 " br label %for.body\n"
203 "for.body: ; preds = %for.body, "
204 "%entry\n"
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"
224 " ret void\n"
225 "}\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"
260 "entry:\n"
261 " br label %for.body\n"
262 "for.body: ; preds = %for.body, "
263 "%entry\n"
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"
283 " ret i32 %vA1\n"
284 "}\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,
307 VPBasicBlock *Body,
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) {
362 LLVMContext Ctx;
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"
367 "entry:\n"
368 " br label %for.body\n"
369 "for.body: ; preds = %for.body, "
370 "%entry\n"
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"
412 " ret void\n"
413 "}\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));
428 checkReorderExample(
429 Store1, Store2, Body,
430 getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan));
433 TEST_F(VPlanSlpTest, testSlpReorder_2) {
434 LLVMContext Ctx;
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"
439 "entry:\n"
440 " br label %for.body\n"
441 "for.body: ; preds = %for.body, "
442 "%entry\n"
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"
484 " ret void\n"
485 "}\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));
500 checkReorderExample(
501 Store1, Store2, Body,
502 getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan));
505 TEST_F(VPlanSlpTest, testSlpReorder_3) {
506 LLVMContext Ctx;
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"
511 "entry:\n"
512 " br label %for.body\n"
513 "for.body: ; preds = %for.body, "
514 "%entry\n"
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"
556 " ret void\n"
557 "}\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) {
582 LLVMContext Ctx;
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"
587 "entry:\n"
588 " br label %for.body\n"
589 "for.body: ; preds = %for.body, "
590 "%entry\n"
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"
632 " ret void\n"
633 "}\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));
648 checkReorderExample(
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"
661 "entry:\n"
662 " br label %for.body\n"
663 "for.body: ; preds = %for.body, "
664 "%entry\n"
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"
678 " br label %bb2\n"
679 "bb2:\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"
692 " ret void\n"
693 "}\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"
724 "entry:\n"
725 " br label %for.body\n"
726 "for.body: ; preds = %for.body, "
727 "%entry\n"
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"
743 " br label %bb2\n"
744 "bb2:\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"
755 " ret void\n"
756 "}\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"
786 "entry:\n"
787 " br label %for.body\n"
788 "for.body: ; preds = %for.body, "
789 "%entry\n"
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"
815 " ret void\n"
816 "}\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"
845 "entry:\n"
846 " br label %for.body\n"
847 "for.body: ; preds = %for.body, "
848 "%entry\n"
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"
874 " ret void\n"
875 "}\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());
897 } // namespace
898 } // namespace llvm