1 //===- llvm/unittest/Transforms/Vectorize/VPlanHCFGTest.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/VPlanTransforms.h" 11 #include "VPlanTestBase.h" 12 #include "gtest/gtest.h" 13 14 namespace llvm { 15 namespace { 16 17 class VPlanHCFGTest : public VPlanTestBase {}; 18 19 TEST_F(VPlanHCFGTest, testBuildHCFGInnerLoop) { 20 const char *ModuleString = 21 "define void @f(i32* %A, i64 %N) {\n" 22 "entry:\n" 23 " br label %for.body\n" 24 "for.body:\n" 25 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n" 26 " %arr.idx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv\n" 27 " %l1 = load i32, i32* %arr.idx, align 4\n" 28 " %res = add i32 %l1, 10\n" 29 " store i32 %res, i32* %arr.idx, align 4\n" 30 " %indvars.iv.next = add i64 %indvars.iv, 1\n" 31 " %exitcond = icmp ne i64 %indvars.iv.next, %N\n" 32 " br i1 %exitcond, label %for.body, label %for.end\n" 33 "for.end:\n" 34 " ret void\n" 35 "}\n"; 36 37 Module &M = parseModule(ModuleString); 38 39 Function *F = M.getFunction("f"); 40 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor(); 41 auto Plan = buildHCFG(LoopHeader); 42 43 VPBasicBlock *Entry = Plan->getEntry()->getEntryBasicBlock(); 44 EXPECT_NE(nullptr, Entry->getSingleSuccessor()); 45 EXPECT_EQ(0u, Entry->getNumPredecessors()); 46 EXPECT_EQ(1u, Entry->getNumSuccessors()); 47 EXPECT_EQ(nullptr, Entry->getCondBit()); 48 49 VPBasicBlock *VecBB = Entry->getSingleSuccessor()->getEntryBasicBlock(); 50 EXPECT_EQ(7u, VecBB->size()); 51 EXPECT_EQ(2u, VecBB->getNumPredecessors()); 52 EXPECT_EQ(2u, VecBB->getNumSuccessors()); 53 54 auto Iter = VecBB->begin(); 55 VPInstruction *Phi = dyn_cast<VPInstruction>(&*Iter++); 56 EXPECT_EQ(Instruction::PHI, Phi->getOpcode()); 57 58 VPInstruction *Idx = dyn_cast<VPInstruction>(&*Iter++); 59 EXPECT_EQ(Instruction::GetElementPtr, Idx->getOpcode()); 60 EXPECT_EQ(2u, Idx->getNumOperands()); 61 EXPECT_EQ(Phi, Idx->getOperand(1)); 62 63 VPInstruction *Load = dyn_cast<VPInstruction>(&*Iter++); 64 EXPECT_EQ(Instruction::Load, Load->getOpcode()); 65 EXPECT_EQ(1u, Load->getNumOperands()); 66 EXPECT_EQ(Idx, Load->getOperand(0)); 67 68 VPInstruction *Add = dyn_cast<VPInstruction>(&*Iter++); 69 EXPECT_EQ(Instruction::Add, Add->getOpcode()); 70 EXPECT_EQ(2u, Add->getNumOperands()); 71 EXPECT_EQ(Load, Add->getOperand(0)); 72 73 VPInstruction *Store = dyn_cast<VPInstruction>(&*Iter++); 74 EXPECT_EQ(Instruction::Store, Store->getOpcode()); 75 EXPECT_EQ(2u, Store->getNumOperands()); 76 EXPECT_EQ(Add, Store->getOperand(0)); 77 EXPECT_EQ(Idx, Store->getOperand(1)); 78 79 VPInstruction *IndvarAdd = dyn_cast<VPInstruction>(&*Iter++); 80 EXPECT_EQ(Instruction::Add, IndvarAdd->getOpcode()); 81 EXPECT_EQ(2u, IndvarAdd->getNumOperands()); 82 EXPECT_EQ(Phi, IndvarAdd->getOperand(0)); 83 84 VPInstruction *ICmp = dyn_cast<VPInstruction>(&*Iter++); 85 EXPECT_EQ(Instruction::ICmp, ICmp->getOpcode()); 86 EXPECT_EQ(2u, ICmp->getNumOperands()); 87 EXPECT_EQ(IndvarAdd, ICmp->getOperand(0)); 88 EXPECT_EQ(VecBB->getCondBit(), ICmp); 89 90 LoopVectorizationLegality::InductionList Inductions; 91 SmallPtrSet<Instruction *, 1> DeadInstructions; 92 VPlanTransforms::VPInstructionsToVPRecipes(LI->getLoopFor(LoopHeader), Plan, 93 &Inductions, DeadInstructions); 94 } 95 96 TEST_F(VPlanHCFGTest, testVPInstructionToVPRecipesInner) { 97 const char *ModuleString = 98 "define void @f(i32* %A, i64 %N) {\n" 99 "entry:\n" 100 " br label %for.body\n" 101 "for.body:\n" 102 " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n" 103 " %arr.idx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv\n" 104 " %l1 = load i32, i32* %arr.idx, align 4\n" 105 " %res = add i32 %l1, 10\n" 106 " store i32 %res, i32* %arr.idx, align 4\n" 107 " %indvars.iv.next = add i64 %indvars.iv, 1\n" 108 " %exitcond = icmp ne i64 %indvars.iv.next, %N\n" 109 " br i1 %exitcond, label %for.body, label %for.end\n" 110 "for.end:\n" 111 " ret void\n" 112 "}\n"; 113 114 Module &M = parseModule(ModuleString); 115 116 Function *F = M.getFunction("f"); 117 BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor(); 118 auto Plan = buildHCFG(LoopHeader); 119 120 LoopVectorizationLegality::InductionList Inductions; 121 SmallPtrSet<Instruction *, 1> DeadInstructions; 122 VPlanTransforms::VPInstructionsToVPRecipes(LI->getLoopFor(LoopHeader), Plan, 123 &Inductions, DeadInstructions); 124 125 VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock(); 126 EXPECT_NE(nullptr, Entry->getSingleSuccessor()); 127 EXPECT_EQ(0u, Entry->getNumPredecessors()); 128 EXPECT_EQ(1u, Entry->getNumSuccessors()); 129 130 VPBasicBlock *VecBB = Entry->getSingleSuccessor()->getEntryBasicBlock(); 131 EXPECT_EQ(6u, VecBB->size()); 132 EXPECT_EQ(2u, VecBB->getNumPredecessors()); 133 EXPECT_EQ(2u, VecBB->getNumSuccessors()); 134 135 auto Iter = VecBB->begin(); 136 auto *Phi = dyn_cast<VPWidenPHIRecipe>(&*Iter++); 137 EXPECT_NE(nullptr, Phi); 138 139 auto *Idx = dyn_cast<VPWidenGEPRecipe>(&*Iter++); 140 EXPECT_NE(nullptr, Idx); 141 142 auto *Load = dyn_cast<VPWidenMemoryInstructionRecipe>(&*Iter++); 143 EXPECT_NE(nullptr, Load); 144 145 auto *Add = dyn_cast<VPWidenRecipe>(&*Iter++); 146 EXPECT_NE(nullptr, Add); 147 148 auto *Store = dyn_cast<VPWidenMemoryInstructionRecipe>(&*Iter++); 149 EXPECT_NE(nullptr, Store); 150 151 auto *LastWiden = dyn_cast<VPWidenRecipe>(&*Iter++); 152 EXPECT_NE(nullptr, LastWiden); 153 EXPECT_EQ(VecBB->end(), Iter); 154 } 155 156 } // namespace 157 } // namespace llvm 158