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