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