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