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