123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898 |
- //===- llvm/unittest/Transforms/Vectorize/VPlanSlpTest.cpp ---------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "../lib/Transforms/Vectorize/VPlan.h"
- #include "../lib/Transforms/Vectorize/VPlanHCFGBuilder.h"
- #include "../lib/Transforms/Vectorize/VPlanHCFGTransforms.h"
- #include "VPlanTestBase.h"
- #include "llvm/Analysis/VectorUtils.h"
- #include "gtest/gtest.h"
- namespace llvm {
- namespace {
- class VPlanSlpTest : public VPlanTestBase {
- protected:
- TargetLibraryInfoImpl TLII;
- TargetLibraryInfo TLI;
- DataLayout DL;
- std::unique_ptr<AssumptionCache> AC;
- std::unique_ptr<ScalarEvolution> SE;
- std::unique_ptr<AAResults> AARes;
- std::unique_ptr<BasicAAResult> BasicAA;
- std::unique_ptr<LoopAccessInfo> LAI;
- std::unique_ptr<PredicatedScalarEvolution> PSE;
- std::unique_ptr<InterleavedAccessInfo> IAI;
- VPlanSlpTest()
- : TLII(), TLI(TLII),
- DL("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-"
- "f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:"
- "16:32:64-S128") {}
- VPInterleavedAccessInfo getInterleavedAccessInfo(Function &F, Loop *L,
- VPlan &Plan) {
- AC.reset(new AssumptionCache(F));
- SE.reset(new ScalarEvolution(F, TLI, *AC, *DT, *LI));
- BasicAA.reset(new BasicAAResult(DL, F, TLI, *AC, &*DT, &*LI));
- AARes.reset(new AAResults(TLI));
- AARes->addAAResult(*BasicAA);
- PSE.reset(new PredicatedScalarEvolution(*SE, *L));
- LAI.reset(new LoopAccessInfo(L, &*SE, &TLI, &*AARes, &*DT, &*LI));
- IAI.reset(new InterleavedAccessInfo(*PSE, L, &*DT, &*LI, &*LAI));
- IAI->analyzeInterleaving(false);
- return {Plan, *IAI};
- }
- };
- TEST_F(VPlanSlpTest, testSlpSimple_2) {
- const char *ModuleString =
- "%struct.Test = type { i32, i32 }\n"
- "%struct.Test3 = type { i32, i32, i32 }\n"
- "%struct.Test4xi8 = type { i8, i8, i8 }\n"
- "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
- "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
- "entry:\n"
- " br label %for.body\n"
- "for.body: ; preds = %for.body, "
- "%entry\n"
- " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
- " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 0\n"
- " %vA0 = load i32, i32* %A0, align 4\n"
- " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 0\n"
- " %vB0 = load i32, i32* %B0, align 4\n"
- " %add0 = add nsw i32 %vA0, %vB0\n"
- " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 1\n"
- " %vA1 = load i32, i32* %A1, align 4\n"
- " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 1\n"
- " %vB1 = load i32, i32* %B1, align 4\n"
- " %add1 = add nsw i32 %vA1, %vB1\n"
- " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 0\n"
- " store i32 %add0, i32* %C0, align 4\n"
- " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 1\n"
- " store i32 %add1, i32* %C1, align 4\n"
- " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
- " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
- " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
- "for.cond.cleanup: ; preds = %for.body\n"
- " ret void\n"
- "}\n";
- Module &M = parseModule(ModuleString);
- Function *F = M.getFunction("add_x2");
- BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
- auto Plan = buildHCFG(LoopHeader);
- auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
- VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
- EXPECT_NE(nullptr, Entry->getSingleSuccessor());
- VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
- VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
- VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
- VPlanSlp Slp(VPIAI, *Body);
- SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
- VPInstruction *CombinedStore = Slp.buildGraph(StoreRoot);
- EXPECT_EQ(64u, Slp.getWidestBundleBits());
- EXPECT_EQ(VPInstruction::SLPStore, CombinedStore->getOpcode());
- auto *CombinedAdd = cast<VPInstruction>(CombinedStore->getOperand(0));
- EXPECT_EQ(Instruction::Add, CombinedAdd->getOpcode());
- auto *CombinedLoadA = cast<VPInstruction>(CombinedAdd->getOperand(0));
- auto *CombinedLoadB = cast<VPInstruction>(CombinedAdd->getOperand(1));
- EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadA->getOpcode());
- EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadB->getOpcode());
- }
- TEST_F(VPlanSlpTest, testSlpSimple_3) {
- const char *ModuleString =
- "%struct.Test = type { i32, i32 }\n"
- "%struct.Test3 = type { i32, i32, i32 }\n"
- "%struct.Test4xi8 = type { i8, i8, i8 }\n"
- "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
- "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
- "entry:\n"
- " br label %for.body\n"
- "for.body: ; preds = %for.body, "
- "%entry\n"
- " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
- " %A0 = getelementptr %struct.Test, %struct.Test* %A, i64 "
- " %indvars.iv, i32 0\n"
- " %vA0 = load i32, i32* %A0, align 4\n"
- " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- " %indvars.iv, i32 0\n"
- " %vB0 = load i32, i32* %B0, align 4\n"
- " %add0 = add nsw i32 %vA0, %vB0\n"
- " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- " %indvars.iv, i32 1\n"
- " %vA1 = load i32, i32* %A1, align 4\n"
- " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- " %indvars.iv, i32 1\n"
- " %vB1 = load i32, i32* %B1, align 4\n"
- " %add1 = add nsw i32 %vA1, %vB1\n"
- " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- " %indvars.iv, i32 0\n"
- " store i32 %add0, i32* %C0, align 4\n"
- " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- " %indvars.iv, i32 1\n"
- " store i32 %add1, i32* %C1, align 4\n"
- " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
- " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
- " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
- "for.cond.cleanup: ; preds = %for.body\n"
- " ret void\n"
- "}\n";
- Module &M = parseModule(ModuleString);
- Function *F = M.getFunction("add_x2");
- BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
- auto Plan = buildHCFG(LoopHeader);
- VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
- EXPECT_NE(nullptr, Entry->getSingleSuccessor());
- VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
- VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
- VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
- auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
- VPlanSlp Slp(VPIAI, *Body);
- SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
- VPInstruction *CombinedStore = Slp.buildGraph(StoreRoot);
- EXPECT_EQ(64u, Slp.getWidestBundleBits());
- EXPECT_EQ(VPInstruction::SLPStore, CombinedStore->getOpcode());
- auto *CombinedAdd = cast<VPInstruction>(CombinedStore->getOperand(0));
- EXPECT_EQ(Instruction::Add, CombinedAdd->getOpcode());
- auto *CombinedLoadA = cast<VPInstruction>(CombinedAdd->getOperand(0));
- auto *CombinedLoadB = cast<VPInstruction>(CombinedAdd->getOperand(1));
- EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadA->getOpcode());
- EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadB->getOpcode());
- VPInstruction *GetA = cast<VPInstruction>(&*std::next(Body->begin(), 1));
- VPInstruction *GetB = cast<VPInstruction>(&*std::next(Body->begin(), 3));
- EXPECT_EQ(GetA, CombinedLoadA->getOperand(0));
- EXPECT_EQ(GetB, CombinedLoadB->getOperand(0));
- }
- TEST_F(VPlanSlpTest, testSlpReuse_1) {
- const char *ModuleString =
- "%struct.Test = type { i32, i32 }\n"
- "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
- "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
- "entry:\n"
- " br label %for.body\n"
- "for.body: ; preds = %for.body, "
- "%entry\n"
- " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
- " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 0\n"
- " %vA0 = load i32, i32* %A0, align 4\n"
- " %add0 = add nsw i32 %vA0, %vA0\n"
- " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 1\n"
- " %vA1 = load i32, i32* %A1, align 4\n"
- " %add1 = add nsw i32 %vA1, %vA1\n"
- " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 0\n"
- " store i32 %add0, i32* %C0, align 4\n"
- " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 1\n"
- " store i32 %add1, i32* %C1, align 4\n"
- " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
- " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
- " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
- "for.cond.cleanup: ; preds = %for.body\n"
- " ret void\n"
- "}\n";
- Module &M = parseModule(ModuleString);
- Function *F = M.getFunction("add_x2");
- BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
- auto Plan = buildHCFG(LoopHeader);
- auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
- VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
- EXPECT_NE(nullptr, Entry->getSingleSuccessor());
- VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
- VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 8));
- VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 10));
- VPlanSlp Slp(VPIAI, *Body);
- SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
- VPInstruction *CombinedStore = Slp.buildGraph(StoreRoot);
- EXPECT_EQ(64u, Slp.getWidestBundleBits());
- EXPECT_EQ(VPInstruction::SLPStore, CombinedStore->getOpcode());
- auto *CombinedAdd = cast<VPInstruction>(CombinedStore->getOperand(0));
- EXPECT_EQ(Instruction::Add, CombinedAdd->getOpcode());
- auto *CombinedLoadA = cast<VPInstruction>(CombinedAdd->getOperand(0));
- EXPECT_EQ(CombinedLoadA, CombinedAdd->getOperand(1));
- EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadA->getOpcode());
- }
- TEST_F(VPlanSlpTest, testSlpReuse_2) {
- const char *ModuleString =
- "%struct.Test = type { i32, i32 }\n"
- "define i32 @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
- "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
- "entry:\n"
- " br label %for.body\n"
- "for.body: ; preds = %for.body, "
- "%entry\n"
- " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
- " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 0\n"
- " %vA0 = load i32, i32* %A0, align 4\n"
- " %add0 = add nsw i32 %vA0, %vA0\n"
- " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 0\n"
- " store i32 %add0, i32* %C0, align 4\n"
- " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 1\n"
- " %vA1 = load i32, i32* %A1, align 4\n"
- " %add1 = add nsw i32 %vA1, %vA1\n"
- " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 1\n"
- " store i32 %add1, i32* %C1, align 4\n"
- " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
- " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
- " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
- "for.cond.cleanup: ; preds = %for.body\n"
- " ret i32 %vA1\n"
- "}\n";
- Module &M = parseModule(ModuleString);
- Function *F = M.getFunction("add_x2");
- BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
- auto Plan = buildHCFG(LoopHeader);
- auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
- VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
- EXPECT_NE(nullptr, Entry->getSingleSuccessor());
- VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
- VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 5));
- VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 10));
- VPlanSlp Slp(VPIAI, *Body);
- SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
- Slp.buildGraph(StoreRoot);
- EXPECT_FALSE(Slp.isCompletelySLP());
- }
- static void checkReorderExample(VPInstruction *Store1, VPInstruction *Store2,
- VPBasicBlock *Body,
- VPInterleavedAccessInfo &&IAI) {
- VPlanSlp Slp(IAI, *Body);
- SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
- VPInstruction *CombinedStore = Slp.buildGraph(StoreRoot);
- EXPECT_TRUE(Slp.isCompletelySLP());
- EXPECT_EQ(CombinedStore->getOpcode(), VPInstruction::SLPStore);
- VPInstruction *CombinedAdd =
- cast<VPInstruction>(CombinedStore->getOperand(0));
- EXPECT_EQ(CombinedAdd->getOpcode(), Instruction::Add);
- VPInstruction *CombinedMulAB =
- cast<VPInstruction>(CombinedAdd->getOperand(0));
- VPInstruction *CombinedMulCD =
- cast<VPInstruction>(CombinedAdd->getOperand(1));
- EXPECT_EQ(CombinedMulAB->getOpcode(), Instruction::Mul);
- VPInstruction *CombinedLoadA =
- cast<VPInstruction>(CombinedMulAB->getOperand(0));
- EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadA->getOpcode());
- VPInstruction *LoadvA0 = cast<VPInstruction>(&*std::next(Body->begin(), 2));
- VPInstruction *LoadvA1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
- EXPECT_EQ(LoadvA0->getOperand(0), CombinedLoadA->getOperand(0));
- EXPECT_EQ(LoadvA1->getOperand(0), CombinedLoadA->getOperand(1));
- VPInstruction *CombinedLoadB =
- cast<VPInstruction>(CombinedMulAB->getOperand(1));
- EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadB->getOpcode());
- VPInstruction *LoadvB0 = cast<VPInstruction>(&*std::next(Body->begin(), 4));
- VPInstruction *LoadvB1 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
- EXPECT_EQ(LoadvB0->getOperand(0), CombinedLoadB->getOperand(0));
- EXPECT_EQ(LoadvB1->getOperand(0), CombinedLoadB->getOperand(1));
- EXPECT_EQ(CombinedMulCD->getOpcode(), Instruction::Mul);
- VPInstruction *CombinedLoadC =
- cast<VPInstruction>(CombinedMulCD->getOperand(0));
- EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadC->getOpcode());
- VPInstruction *LoadvC0 = cast<VPInstruction>(&*std::next(Body->begin(), 7));
- VPInstruction *LoadvC1 = cast<VPInstruction>(&*std::next(Body->begin(), 17));
- EXPECT_EQ(LoadvC0->getOperand(0), CombinedLoadC->getOperand(0));
- EXPECT_EQ(LoadvC1->getOperand(0), CombinedLoadC->getOperand(1));
- VPInstruction *CombinedLoadD =
- cast<VPInstruction>(CombinedMulCD->getOperand(1));
- EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadD->getOpcode());
- VPInstruction *LoadvD0 = cast<VPInstruction>(&*std::next(Body->begin(), 9));
- VPInstruction *LoadvD1 = cast<VPInstruction>(&*std::next(Body->begin(), 19));
- EXPECT_EQ(LoadvD0->getOperand(0), CombinedLoadD->getOperand(0));
- EXPECT_EQ(LoadvD1->getOperand(0), CombinedLoadD->getOperand(1));
- }
- TEST_F(VPlanSlpTest, testSlpReorder_1) {
- LLVMContext Ctx;
- const char *ModuleString =
- "%struct.Test = type { i32, i32 }\n"
- "define void @add_x3(%struct.Test* %A, %struct.Test* %B, %struct.Test* "
- "%C, %struct.Test* %D, %struct.Test* %E) {\n"
- "entry:\n"
- " br label %for.body\n"
- "for.body: ; preds = %for.body, "
- "%entry\n"
- " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
- " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 0\n"
- " %vA0 = load i32, i32* %A0, align 4\n"
- " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 0\n"
- " %vB0 = load i32, i32* %B0, align 4\n"
- " %mul11 = mul nsw i32 %vA0, %vB0\n"
- " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 0\n"
- " %vC0 = load i32, i32* %C0, align 4\n"
- " %D0 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
- "%indvars.iv, i32 0\n"
- " %vD0 = load i32, i32* %D0, align 4\n"
- " %mul12 = mul nsw i32 %vC0, %vD0\n"
- " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 1\n"
- " %vA1 = load i32, i32* %A1, align 4\n"
- " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 1\n"
- " %vB1 = load i32, i32* %B1, align 4\n"
- " %mul21 = mul nsw i32 %vA1, %vB1\n"
- " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 1\n"
- " %vC1 = load i32, i32* %C1, align 4\n"
- " %D1 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
- "%indvars.iv, i32 1\n"
- " %vD1 = load i32, i32* %D1, align 4\n"
- " %mul22 = mul nsw i32 %vC1, %vD1\n"
- " %add1 = add nsw i32 %mul11, %mul12\n"
- " %add2 = add nsw i32 %mul22, %mul21\n"
- " %E0 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
- "%indvars.iv, i32 0\n"
- " store i32 %add1, i32* %E0, align 4\n"
- " %E1 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
- "%indvars.iv, i32 1\n"
- " store i32 %add2, i32* %E1, align 4\n"
- " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
- " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
- " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
- "for.cond.cleanup: ; preds = %for.body\n"
- " ret void\n"
- "}\n";
- Module &M = parseModule(ModuleString);
- Function *F = M.getFunction("add_x3");
- BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
- auto Plan = buildHCFG(LoopHeader);
- VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
- EXPECT_NE(nullptr, Entry->getSingleSuccessor());
- VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
- VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 24));
- VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 26));
- checkReorderExample(
- Store1, Store2, Body,
- getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan));
- }
- TEST_F(VPlanSlpTest, testSlpReorder_2) {
- LLVMContext Ctx;
- const char *ModuleString =
- "%struct.Test = type { i32, i32 }\n"
- "define void @add_x3(%struct.Test* %A, %struct.Test* %B, %struct.Test* "
- "%C, %struct.Test* %D, %struct.Test* %E) {\n"
- "entry:\n"
- " br label %for.body\n"
- "for.body: ; preds = %for.body, "
- "%entry\n"
- " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
- " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 0\n"
- " %vA0 = load i32, i32* %A0, align 4\n"
- " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 0\n"
- " %vB0 = load i32, i32* %B0, align 4\n"
- " %mul11 = mul nsw i32 %vA0, %vB0\n"
- " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 0\n"
- " %vC0 = load i32, i32* %C0, align 4\n"
- " %D0 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
- "%indvars.iv, i32 0\n"
- " %vD0 = load i32, i32* %D0, align 4\n"
- " %mul12 = mul nsw i32 %vC0, %vD0\n"
- " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 1\n"
- " %vA1 = load i32, i32* %A1, align 4\n"
- " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 1\n"
- " %vB1 = load i32, i32* %B1, align 4\n"
- " %mul21 = mul nsw i32 %vB1, %vA1\n"
- " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 1\n"
- " %vC1 = load i32, i32* %C1, align 4\n"
- " %D1 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
- "%indvars.iv, i32 1\n"
- " %vD1 = load i32, i32* %D1, align 4\n"
- " %mul22 = mul nsw i32 %vD1, %vC1\n"
- " %add1 = add nsw i32 %mul11, %mul12\n"
- " %add2 = add nsw i32 %mul22, %mul21\n"
- " %E0 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
- "%indvars.iv, i32 0\n"
- " store i32 %add1, i32* %E0, align 4\n"
- " %E1 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
- "%indvars.iv, i32 1\n"
- " store i32 %add2, i32* %E1, align 4\n"
- " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
- " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
- " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
- "for.cond.cleanup: ; preds = %for.body\n"
- " ret void\n"
- "}\n";
- Module &M = parseModule(ModuleString);
- Function *F = M.getFunction("add_x3");
- BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
- auto Plan = buildHCFG(LoopHeader);
- VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
- EXPECT_NE(nullptr, Entry->getSingleSuccessor());
- VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
- VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 24));
- VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 26));
- checkReorderExample(
- Store1, Store2, Body,
- getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan));
- }
- TEST_F(VPlanSlpTest, testSlpReorder_3) {
- LLVMContext Ctx;
- const char *ModuleString =
- "%struct.Test = type { i32, i32 }\n"
- "define void @add_x3(%struct.Test* %A, %struct.Test* %B, %struct.Test* "
- "%C, %struct.Test* %D, %struct.Test* %E) {\n"
- "entry:\n"
- " br label %for.body\n"
- "for.body: ; preds = %for.body, "
- "%entry\n"
- " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
- " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 1\n"
- " %vA1 = load i32, i32* %A1, align 4\n"
- " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 0\n"
- " %vB0 = load i32, i32* %B0, align 4\n"
- " %mul11 = mul nsw i32 %vA1, %vB0\n"
- " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 0\n"
- " %vC0 = load i32, i32* %C0, align 4\n"
- " %D0 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
- "%indvars.iv, i32 0\n"
- " %vD0 = load i32, i32* %D0, align 4\n"
- " %mul12 = mul nsw i32 %vC0, %vD0\n"
- " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 0\n"
- " %vA0 = load i32, i32* %A0, align 4\n"
- " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 1\n"
- " %vB1 = load i32, i32* %B1, align 4\n"
- " %mul21 = mul nsw i32 %vB1, %vA0\n"
- " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 1\n"
- " %vC1 = load i32, i32* %C1, align 4\n"
- " %D1 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
- "%indvars.iv, i32 1\n"
- " %vD1 = load i32, i32* %D1, align 4\n"
- " %mul22 = mul nsw i32 %vD1, %vC1\n"
- " %add1 = add nsw i32 %mul11, %mul12\n"
- " %add2 = add nsw i32 %mul22, %mul21\n"
- " %E0 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
- "%indvars.iv, i32 0\n"
- " store i32 %add1, i32* %E0, align 4\n"
- " %E1 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
- "%indvars.iv, i32 1\n"
- " store i32 %add2, i32* %E1, align 4\n"
- " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
- " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
- " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
- "for.cond.cleanup: ; preds = %for.body\n"
- " ret void\n"
- "}\n";
- Module &M = parseModule(ModuleString);
- Function *F = M.getFunction("add_x3");
- BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
- auto Plan = buildHCFG(LoopHeader);
- VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
- EXPECT_NE(nullptr, Entry->getSingleSuccessor());
- VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
- VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 24));
- VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 26));
- auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
- VPlanSlp Slp(VPIAI, *Body);
- SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
- EXPECT_EQ(nullptr, Slp.buildGraph(StoreRoot));
- // FIXME Need to select better first value for lane0.
- EXPECT_FALSE(Slp.isCompletelySLP());
- }
- TEST_F(VPlanSlpTest, testSlpReorder_4) {
- LLVMContext Ctx;
- const char *ModuleString =
- "%struct.Test = type { i32, i32 }\n"
- "define void @add_x3(%struct.Test* %A, %struct.Test* %B, %struct.Test* "
- "%C, %struct.Test* %D, %struct.Test* %E) {\n"
- "entry:\n"
- " br label %for.body\n"
- "for.body: ; preds = %for.body, "
- "%entry\n"
- " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
- " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 0\n"
- " %vA0 = load i32, i32* %A0, align 4\n"
- " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 0\n"
- " %vB0 = load i32, i32* %B0, align 4\n"
- " %mul11 = mul nsw i32 %vA0, %vB0\n"
- " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 0\n"
- " %vC0 = load i32, i32* %C0, align 4\n"
- " %D0 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
- "%indvars.iv, i32 0\n"
- " %vD0 = load i32, i32* %D0, align 4\n"
- " %mul12 = mul nsw i32 %vC0, %vD0\n"
- " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 1\n"
- " %vA1 = load i32, i32* %A1, align 4\n"
- " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 1\n"
- " %vB1 = load i32, i32* %B1, align 4\n"
- " %mul21 = mul nsw i32 %vA1, %vB1\n"
- " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 1\n"
- " %vC1 = load i32, i32* %C1, align 4\n"
- " %D1 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
- "%indvars.iv, i32 1\n"
- " %vD1 = load i32, i32* %D1, align 4\n"
- " %mul22 = mul nsw i32 %vC1, %vD1\n"
- " %add1 = add nsw i32 %mul11, %mul12\n"
- " %add2 = add nsw i32 %mul22, %mul21\n"
- " %E0 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
- "%indvars.iv, i32 0\n"
- " store i32 %add1, i32* %E0, align 4\n"
- " %E1 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
- "%indvars.iv, i32 1\n"
- " store i32 %add2, i32* %E1, align 4\n"
- " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
- " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
- " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
- "for.cond.cleanup: ; preds = %for.body\n"
- " ret void\n"
- "}\n";
- Module &M = parseModule(ModuleString);
- Function *F = M.getFunction("add_x3");
- BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
- auto Plan = buildHCFG(LoopHeader);
- VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
- EXPECT_NE(nullptr, Entry->getSingleSuccessor());
- VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
- VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 24));
- VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 26));
- checkReorderExample(
- Store1, Store2, Body,
- getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan));
- }
- // Make sure we do not combine instructions with operands in different BBs.
- TEST_F(VPlanSlpTest, testInstrsInDifferentBBs) {
- const char *ModuleString =
- "%struct.Test = type { i32, i32 }\n"
- "%struct.Test3 = type { i32, i32, i32 }\n"
- "%struct.Test4xi8 = type { i8, i8, i8 }\n"
- "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
- "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
- "entry:\n"
- " br label %for.body\n"
- "for.body: ; preds = %for.body, "
- "%entry\n"
- " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
- " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 0\n"
- " %vA0 = load i32, i32* %A0, align 4\n"
- " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 0\n"
- " %vB0 = load i32, i32* %B0, align 4\n"
- " %add0 = add nsw i32 %vA0, %vB0\n"
- " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 1\n"
- " %vA1 = load i32, i32* %A1, align 4\n"
- " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 1\n"
- " br label %bb2\n"
- "bb2:\n"
- " %vB1 = load i32, i32* %B1, align 4\n"
- " %add1 = add nsw i32 %vA1, %vB1\n"
- " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 0\n"
- " store i32 %add0, i32* %C0, align 4\n"
- " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 1\n"
- " store i32 %add1, i32* %C1, align 4\n"
- " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
- " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
- " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
- "for.cond.cleanup: ; preds = %for.body\n"
- " ret void\n"
- "}\n";
- Module &M = parseModule(ModuleString);
- Function *F = M.getFunction("add_x2");
- BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
- auto Plan = buildHCFG(LoopHeader);
- auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
- VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
- EXPECT_NE(nullptr, Entry->getSingleSuccessor());
- VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
- VPBasicBlock *BB2 = Body->getSingleSuccessor()->getEntryBasicBlock();
- VPInstruction *Store1 = cast<VPInstruction>(&*std::next(BB2->begin(), 3));
- VPInstruction *Store2 = cast<VPInstruction>(&*std::next(BB2->begin(), 5));
- VPlanSlp Slp(VPIAI, *BB2);
- SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
- EXPECT_EQ(nullptr, Slp.buildGraph(StoreRoot));
- EXPECT_EQ(0u, Slp.getWidestBundleBits());
- }
- // Make sure we do not combine instructions with operands in different BBs.
- TEST_F(VPlanSlpTest, testInstrsInDifferentBBs2) {
- const char *ModuleString =
- "%struct.Test = type { i32, i32 }\n"
- "%struct.Test3 = type { i32, i32, i32 }\n"
- "%struct.Test4xi8 = type { i8, i8, i8 }\n"
- "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
- "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
- "entry:\n"
- " br label %for.body\n"
- "for.body: ; preds = %for.body, "
- "%entry\n"
- " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
- " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 0\n"
- " %vA0 = load i32, i32* %A0, align 4\n"
- " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 0\n"
- " %vB0 = load i32, i32* %B0, align 4\n"
- " %add0 = add nsw i32 %vA0, %vB0\n"
- " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 1\n"
- " %vA1 = load i32, i32* %A1, align 4\n"
- " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 1\n"
- " %vB1 = load i32, i32* %B1, align 4\n"
- " %add1 = add nsw i32 %vA1, %vB1\n"
- " br label %bb2\n"
- "bb2:\n"
- " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 0\n"
- " store i32 %add0, i32* %C0, align 4\n"
- " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 1\n"
- " store i32 %add1, i32* %C1, align 4\n"
- " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
- " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
- " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
- "for.cond.cleanup: ; preds = %for.body\n"
- " ret void\n"
- "}\n";
- Module &M = parseModule(ModuleString);
- Function *F = M.getFunction("add_x2");
- BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
- auto Plan = buildHCFG(LoopHeader);
- auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
- VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
- EXPECT_NE(nullptr, Entry->getSingleSuccessor());
- VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
- VPBasicBlock *BB2 = Body->getSingleSuccessor()->getEntryBasicBlock();
- VPInstruction *Store1 = cast<VPInstruction>(&*std::next(BB2->begin(), 1));
- VPInstruction *Store2 = cast<VPInstruction>(&*std::next(BB2->begin(), 3));
- VPlanSlp Slp(VPIAI, *BB2);
- SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
- EXPECT_EQ(nullptr, Slp.buildGraph(StoreRoot));
- EXPECT_EQ(0u, Slp.getWidestBundleBits());
- }
- TEST_F(VPlanSlpTest, testSlpAtomicLoad) {
- const char *ModuleString =
- "%struct.Test = type { i32, i32 }\n"
- "%struct.Test3 = type { i32, i32, i32 }\n"
- "%struct.Test4xi8 = type { i8, i8, i8 }\n"
- "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
- "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
- "entry:\n"
- " br label %for.body\n"
- "for.body: ; preds = %for.body, "
- "%entry\n"
- " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
- " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 0\n"
- " %vA0 = load atomic i32, i32* %A0 monotonic, align 4\n"
- " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 0\n"
- " %vB0 = load i32, i32* %B0, align 4\n"
- " %add0 = add nsw i32 %vA0, %vB0\n"
- " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 1\n"
- " %vA1 = load i32, i32* %A1, align 4\n"
- " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 1\n"
- " %vB1 = load i32, i32* %B1, align 4\n"
- " %add1 = add nsw i32 %vA1, %vB1\n"
- " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 0\n"
- " store i32 %add0, i32* %C0, align 4\n"
- " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 1\n"
- " store i32 %add1, i32* %C1, align 4\n"
- " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
- " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
- " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
- "for.cond.cleanup: ; preds = %for.body\n"
- " ret void\n"
- "}\n";
- Module &M = parseModule(ModuleString);
- Function *F = M.getFunction("add_x2");
- BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
- auto Plan = buildHCFG(LoopHeader);
- auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
- VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
- EXPECT_NE(nullptr, Entry->getSingleSuccessor());
- VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
- VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
- VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
- VPlanSlp Slp(VPIAI, *Body);
- SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
- EXPECT_EQ(nullptr, Slp.buildGraph(StoreRoot));
- EXPECT_FALSE(Slp.isCompletelySLP());
- }
- TEST_F(VPlanSlpTest, testSlpAtomicStore) {
- const char *ModuleString =
- "%struct.Test = type { i32, i32 }\n"
- "%struct.Test3 = type { i32, i32, i32 }\n"
- "%struct.Test4xi8 = type { i8, i8, i8 }\n"
- "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
- "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
- "entry:\n"
- " br label %for.body\n"
- "for.body: ; preds = %for.body, "
- "%entry\n"
- " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
- " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 0\n"
- " %vA0 = load i32, i32* %A0, align 4\n"
- " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 0\n"
- " %vB0 = load i32, i32* %B0, align 4\n"
- " %add0 = add nsw i32 %vA0, %vB0\n"
- " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
- "%indvars.iv, i32 1\n"
- " %vA1 = load i32, i32* %A1, align 4\n"
- " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
- "%indvars.iv, i32 1\n"
- " %vB1 = load i32, i32* %B1, align 4\n"
- " %add1 = add nsw i32 %vA1, %vB1\n"
- " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 0\n"
- " store atomic i32 %add0, i32* %C0 monotonic, align 4\n"
- " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
- "%indvars.iv, i32 1\n"
- " store i32 %add1, i32* %C1, align 4\n"
- " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
- " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
- " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
- "for.cond.cleanup: ; preds = %for.body\n"
- " ret void\n"
- "}\n";
- Module &M = parseModule(ModuleString);
- Function *F = M.getFunction("add_x2");
- BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
- auto Plan = buildHCFG(LoopHeader);
- auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
- VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
- EXPECT_NE(nullptr, Entry->getSingleSuccessor());
- VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
- VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
- VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
- VPlanSlp Slp(VPIAI, *Body);
- SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
- Slp.buildGraph(StoreRoot);
- EXPECT_FALSE(Slp.isCompletelySLP());
- }
- } // namespace
- } // namespace llvm
|