13385caaaSFlorian Hahn //===- llvm/unittest/Transforms/Vectorize/VPlanHCFGTest.cpp ---------------===//
23385caaaSFlorian Hahn //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63385caaaSFlorian Hahn //
73385caaaSFlorian Hahn //===----------------------------------------------------------------------===//
83385caaaSFlorian Hahn
93385caaaSFlorian Hahn #include "../lib/Transforms/Vectorize/VPlan.h"
10e60b36cfSFlorian Hahn #include "../lib/Transforms/Vectorize/VPlanTransforms.h"
117e64c1eeSFlorian Hahn #include "VPlanTestBase.h"
123385caaaSFlorian Hahn #include "gtest/gtest.h"
13e6a74803SFlorian Hahn #include <string>
143385caaaSFlorian Hahn
153385caaaSFlorian Hahn namespace llvm {
163385caaaSFlorian Hahn namespace {
173385caaaSFlorian Hahn
187e64c1eeSFlorian Hahn class VPlanHCFGTest : public VPlanTestBase {};
193385caaaSFlorian Hahn
TEST_F(VPlanHCFGTest,testBuildHCFGInnerLoop)203385caaaSFlorian Hahn TEST_F(VPlanHCFGTest, testBuildHCFGInnerLoop) {
213385caaaSFlorian Hahn const char *ModuleString =
223385caaaSFlorian Hahn "define void @f(i32* %A, i64 %N) {\n"
233385caaaSFlorian Hahn "entry:\n"
243385caaaSFlorian Hahn " br label %for.body\n"
253385caaaSFlorian Hahn "for.body:\n"
263385caaaSFlorian Hahn " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
273385caaaSFlorian Hahn " %arr.idx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv\n"
283385caaaSFlorian Hahn " %l1 = load i32, i32* %arr.idx, align 4\n"
293385caaaSFlorian Hahn " %res = add i32 %l1, 10\n"
303385caaaSFlorian Hahn " store i32 %res, i32* %arr.idx, align 4\n"
313385caaaSFlorian Hahn " %indvars.iv.next = add i64 %indvars.iv, 1\n"
323385caaaSFlorian Hahn " %exitcond = icmp ne i64 %indvars.iv.next, %N\n"
333385caaaSFlorian Hahn " br i1 %exitcond, label %for.body, label %for.end\n"
343385caaaSFlorian Hahn "for.end:\n"
353385caaaSFlorian Hahn " ret void\n"
363385caaaSFlorian Hahn "}\n";
373385caaaSFlorian Hahn
387e64c1eeSFlorian Hahn Module &M = parseModule(ModuleString);
393385caaaSFlorian Hahn
407e64c1eeSFlorian Hahn Function *F = M.getFunction("f");
413385caaaSFlorian Hahn BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
427e64c1eeSFlorian Hahn auto Plan = buildHCFG(LoopHeader);
433385caaaSFlorian Hahn
44d0953014SDiego Caballero VPBasicBlock *Entry = Plan->getEntry()->getEntryBasicBlock();
453385caaaSFlorian Hahn EXPECT_NE(nullptr, Entry->getSingleSuccessor());
463385caaaSFlorian Hahn EXPECT_EQ(0u, Entry->getNumPredecessors());
473385caaaSFlorian Hahn EXPECT_EQ(1u, Entry->getNumSuccessors());
483385caaaSFlorian Hahn
4905776122SFlorian Hahn // Check that the region following the preheader is a single basic-block
5005776122SFlorian Hahn // region (loop).
513385caaaSFlorian Hahn VPBasicBlock *VecBB = Entry->getSingleSuccessor()->getEntryBasicBlock();
52*fe65c567SFlorian Hahn EXPECT_EQ(8u, VecBB->size());
5305776122SFlorian Hahn EXPECT_EQ(0u, VecBB->getNumPredecessors());
5405776122SFlorian Hahn EXPECT_EQ(0u, VecBB->getNumSuccessors());
5505776122SFlorian Hahn EXPECT_EQ(VecBB->getParent()->getEntryBasicBlock(), VecBB);
5605776122SFlorian Hahn EXPECT_EQ(VecBB->getParent()->getExitingBasicBlock(), VecBB);
5705afa555SFlorian Hahn EXPECT_EQ(&*Plan, VecBB->getPlan());
583385caaaSFlorian Hahn
593385caaaSFlorian Hahn auto Iter = VecBB->begin();
60c11fd0dfSFlorian Hahn VPWidenPHIRecipe *Phi = dyn_cast<VPWidenPHIRecipe>(&*Iter++);
61c11fd0dfSFlorian Hahn EXPECT_NE(nullptr, Phi);
623385caaaSFlorian Hahn
633385caaaSFlorian Hahn VPInstruction *Idx = dyn_cast<VPInstruction>(&*Iter++);
643385caaaSFlorian Hahn EXPECT_EQ(Instruction::GetElementPtr, Idx->getOpcode());
653385caaaSFlorian Hahn EXPECT_EQ(2u, Idx->getNumOperands());
663385caaaSFlorian Hahn EXPECT_EQ(Phi, Idx->getOperand(1));
673385caaaSFlorian Hahn
683385caaaSFlorian Hahn VPInstruction *Load = dyn_cast<VPInstruction>(&*Iter++);
693385caaaSFlorian Hahn EXPECT_EQ(Instruction::Load, Load->getOpcode());
703385caaaSFlorian Hahn EXPECT_EQ(1u, Load->getNumOperands());
713385caaaSFlorian Hahn EXPECT_EQ(Idx, Load->getOperand(0));
723385caaaSFlorian Hahn
733385caaaSFlorian Hahn VPInstruction *Add = dyn_cast<VPInstruction>(&*Iter++);
743385caaaSFlorian Hahn EXPECT_EQ(Instruction::Add, Add->getOpcode());
753385caaaSFlorian Hahn EXPECT_EQ(2u, Add->getNumOperands());
763385caaaSFlorian Hahn EXPECT_EQ(Load, Add->getOperand(0));
773385caaaSFlorian Hahn
783385caaaSFlorian Hahn VPInstruction *Store = dyn_cast<VPInstruction>(&*Iter++);
793385caaaSFlorian Hahn EXPECT_EQ(Instruction::Store, Store->getOpcode());
803385caaaSFlorian Hahn EXPECT_EQ(2u, Store->getNumOperands());
813385caaaSFlorian Hahn EXPECT_EQ(Add, Store->getOperand(0));
823385caaaSFlorian Hahn EXPECT_EQ(Idx, Store->getOperand(1));
833385caaaSFlorian Hahn
843385caaaSFlorian Hahn VPInstruction *IndvarAdd = dyn_cast<VPInstruction>(&*Iter++);
853385caaaSFlorian Hahn EXPECT_EQ(Instruction::Add, IndvarAdd->getOpcode());
863385caaaSFlorian Hahn EXPECT_EQ(2u, IndvarAdd->getNumOperands());
873385caaaSFlorian Hahn EXPECT_EQ(Phi, IndvarAdd->getOperand(0));
883385caaaSFlorian Hahn
893385caaaSFlorian Hahn VPInstruction *ICmp = dyn_cast<VPInstruction>(&*Iter++);
903385caaaSFlorian Hahn EXPECT_EQ(Instruction::ICmp, ICmp->getOpcode());
913385caaaSFlorian Hahn EXPECT_EQ(2u, ICmp->getNumOperands());
923385caaaSFlorian Hahn EXPECT_EQ(IndvarAdd, ICmp->getOperand(0));
933385caaaSFlorian Hahn
9492205cb2SAndrei Elovikov #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
95fd2c15e6SFlorian Hahn // Add an external value to check we do not print the list of external values,
96fd2c15e6SFlorian Hahn // as this is not required with the new printing.
97fd2c15e6SFlorian Hahn Plan->addVPValue(&*F->arg_begin());
98e6a74803SFlorian Hahn std::string FullDump;
9993a9d2deSAndrei Elovikov raw_string_ostream OS(FullDump);
10093a9d2deSAndrei Elovikov Plan->printDOT(OS);
1016120cb42SFlorian Hahn const char *ExpectedStr = R"(digraph VPlan {
102e6a74803SFlorian Hahn graph [labelloc=t, fontsize=30; label="Vectorization Plan"]
103e6a74803SFlorian Hahn node [shape=rect, fontname=Courier, fontsize=30]
104e6a74803SFlorian Hahn edge [fontname=Courier, fontsize=30]
105e6a74803SFlorian Hahn compound=true
10605776122SFlorian Hahn N0 [label =
10705776122SFlorian Hahn "vector.ph:\l" +
10805776122SFlorian Hahn "Successor(s): for.body\l"
109e6a74803SFlorian Hahn ]
11005776122SFlorian Hahn N0 -> N1 [ label="" lhead=cluster_N2]
11105776122SFlorian Hahn subgraph cluster_N2 {
11205776122SFlorian Hahn fontname=Courier
11305776122SFlorian Hahn label="\<x1\> for.body"
11405776122SFlorian Hahn N1 [label =
1154388c979SFlorian Hahn "vector.body:\l" +
116a6b06b78SFlorian Hahn " WIDEN-PHI ir\<%indvars.iv\> = phi ir\<0\>, ir\<%indvars.iv.next\>\l" +
11793a9d2deSAndrei Elovikov " EMIT ir\<%arr.idx\> = getelementptr ir\<%A\> ir\<%indvars.iv\>\l" +
11893a9d2deSAndrei Elovikov " EMIT ir\<%l1\> = load ir\<%arr.idx\>\l" +
11993a9d2deSAndrei Elovikov " EMIT ir\<%res\> = add ir\<%l1\> ir\<10\>\l" +
12093a9d2deSAndrei Elovikov " EMIT store ir\<%res\> ir\<%arr.idx\>\l" +
12193a9d2deSAndrei Elovikov " EMIT ir\<%indvars.iv.next\> = add ir\<%indvars.iv\> ir\<1\>\l" +
12293a9d2deSAndrei Elovikov " EMIT ir\<%exitcond\> = icmp ir\<%indvars.iv.next\> ir\<%N\>\l" +
123*fe65c567SFlorian Hahn " EMIT branch-on-cond ir\<%exitcond\>\l" +
124*fe65c567SFlorian Hahn "No successors\l"
125e6a74803SFlorian Hahn ]
12605776122SFlorian Hahn }
12705776122SFlorian Hahn N1 -> N3 [ label="" ltail=cluster_N2]
128e6a74803SFlorian Hahn N3 [label =
12993a9d2deSAndrei Elovikov "for.end:\l" +
13093a9d2deSAndrei Elovikov "No successors\l"
131e6a74803SFlorian Hahn ]
132e6a74803SFlorian Hahn }
1336120cb42SFlorian Hahn )";
1346120cb42SFlorian Hahn EXPECT_EQ(ExpectedStr, FullDump);
13592205cb2SAndrei Elovikov #endif
136e6a74803SFlorian Hahn
1373385caaaSFlorian Hahn SmallPtrSet<Instruction *, 1> DeadInstructions;
138978883d2SFlorian Hahn VPlanTransforms::VPInstructionsToVPRecipes(
139978883d2SFlorian Hahn LI->getLoopFor(LoopHeader), Plan, [](PHINode *P) { return nullptr; },
140978883d2SFlorian Hahn DeadInstructions, *SE);
1413385caaaSFlorian Hahn }
1423385caaaSFlorian Hahn
TEST_F(VPlanHCFGTest,testVPInstructionToVPRecipesInner)1433385caaaSFlorian Hahn TEST_F(VPlanHCFGTest, testVPInstructionToVPRecipesInner) {
1443385caaaSFlorian Hahn const char *ModuleString =
1453385caaaSFlorian Hahn "define void @f(i32* %A, i64 %N) {\n"
1463385caaaSFlorian Hahn "entry:\n"
1473385caaaSFlorian Hahn " br label %for.body\n"
1483385caaaSFlorian Hahn "for.body:\n"
1493385caaaSFlorian Hahn " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
1503385caaaSFlorian Hahn " %arr.idx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv\n"
1513385caaaSFlorian Hahn " %l1 = load i32, i32* %arr.idx, align 4\n"
1523385caaaSFlorian Hahn " %res = add i32 %l1, 10\n"
1533385caaaSFlorian Hahn " store i32 %res, i32* %arr.idx, align 4\n"
1543385caaaSFlorian Hahn " %indvars.iv.next = add i64 %indvars.iv, 1\n"
1553385caaaSFlorian Hahn " %exitcond = icmp ne i64 %indvars.iv.next, %N\n"
1563385caaaSFlorian Hahn " br i1 %exitcond, label %for.body, label %for.end\n"
1573385caaaSFlorian Hahn "for.end:\n"
1583385caaaSFlorian Hahn " ret void\n"
1593385caaaSFlorian Hahn "}\n";
1603385caaaSFlorian Hahn
1617e64c1eeSFlorian Hahn Module &M = parseModule(ModuleString);
1623385caaaSFlorian Hahn
1637e64c1eeSFlorian Hahn Function *F = M.getFunction("f");
1643385caaaSFlorian Hahn BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
1657e64c1eeSFlorian Hahn auto Plan = buildHCFG(LoopHeader);
1663385caaaSFlorian Hahn
1673385caaaSFlorian Hahn SmallPtrSet<Instruction *, 1> DeadInstructions;
168978883d2SFlorian Hahn VPlanTransforms::VPInstructionsToVPRecipes(
169978883d2SFlorian Hahn LI->getLoopFor(LoopHeader), Plan, [](PHINode *P) { return nullptr; },
170978883d2SFlorian Hahn DeadInstructions, *SE);
1713385caaaSFlorian Hahn
1723385caaaSFlorian Hahn VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
1733385caaaSFlorian Hahn EXPECT_NE(nullptr, Entry->getSingleSuccessor());
1743385caaaSFlorian Hahn EXPECT_EQ(0u, Entry->getNumPredecessors());
1753385caaaSFlorian Hahn EXPECT_EQ(1u, Entry->getNumSuccessors());
1763385caaaSFlorian Hahn
17705776122SFlorian Hahn // Check that the region following the preheader is a single basic-block
17805776122SFlorian Hahn // region (loop).
1793385caaaSFlorian Hahn VPBasicBlock *VecBB = Entry->getSingleSuccessor()->getEntryBasicBlock();
180*fe65c567SFlorian Hahn EXPECT_EQ(8u, VecBB->size());
18105776122SFlorian Hahn EXPECT_EQ(0u, VecBB->getNumPredecessors());
18205776122SFlorian Hahn EXPECT_EQ(0u, VecBB->getNumSuccessors());
18305776122SFlorian Hahn EXPECT_EQ(VecBB->getParent()->getEntryBasicBlock(), VecBB);
18405776122SFlorian Hahn EXPECT_EQ(VecBB->getParent()->getExitingBasicBlock(), VecBB);
1853385caaaSFlorian Hahn
1863385caaaSFlorian Hahn auto Iter = VecBB->begin();
18749d00824SFlorian Hahn EXPECT_NE(nullptr, dyn_cast<VPWidenPHIRecipe>(&*Iter++));
18849d00824SFlorian Hahn EXPECT_NE(nullptr, dyn_cast<VPWidenGEPRecipe>(&*Iter++));
18949d00824SFlorian Hahn EXPECT_NE(nullptr, dyn_cast<VPWidenMemoryInstructionRecipe>(&*Iter++));
19049d00824SFlorian Hahn EXPECT_NE(nullptr, dyn_cast<VPWidenRecipe>(&*Iter++));
19149d00824SFlorian Hahn EXPECT_NE(nullptr, dyn_cast<VPWidenMemoryInstructionRecipe>(&*Iter++));
19249d00824SFlorian Hahn EXPECT_NE(nullptr, dyn_cast<VPWidenRecipe>(&*Iter++));
19349d00824SFlorian Hahn EXPECT_NE(nullptr, dyn_cast<VPWidenRecipe>(&*Iter++));
194*fe65c567SFlorian Hahn EXPECT_NE(nullptr, dyn_cast<VPInstruction>(&*Iter++));
1953385caaaSFlorian Hahn EXPECT_EQ(VecBB->end(), Iter);
1963385caaaSFlorian Hahn }
1973385caaaSFlorian Hahn
1983385caaaSFlorian Hahn } // namespace
1993385caaaSFlorian Hahn } // namespace llvm
200