1 //===- llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.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/VPlanVerifier.h" 10 #include "../lib/Transforms/Vectorize/VPlan.h" 11 #include "VPlanTestBase.h" 12 #include "llvm/IR/Instruction.h" 13 #include "llvm/IR/Instructions.h" 14 #include "gtest/gtest.h" 15 16 using namespace llvm; 17 18 using VPVerifierTest = VPlanTestBase; 19 20 namespace { 21 TEST_F(VPVerifierTest, VPInstructionUseBeforeDefSameBB) { 22 VPlan &Plan = getPlan(); 23 VPValue *Zero = Plan.getOrAddLiveIn(ConstantInt::get(Type::getInt32Ty(C), 0)); 24 VPInstruction *DefI = new VPInstruction(Instruction::Add, {Zero}); 25 VPInstruction *UseI = new VPInstruction(Instruction::Sub, {DefI}); 26 auto *CanIV = new VPCanonicalIVPHIRecipe(Zero, {}); 27 28 VPBasicBlock *VPBB1 = Plan.getEntry(); 29 VPBB1->appendRecipe(UseI); 30 VPBB1->appendRecipe(DefI); 31 32 VPBasicBlock *VPBB2 = Plan.createVPBasicBlock(""); 33 VPBB2->appendRecipe(CanIV); 34 VPRegionBlock *R1 = Plan.createVPRegionBlock(VPBB2, VPBB2, "R1"); 35 VPBlockUtils::connectBlocks(VPBB1, R1); 36 VPBlockUtils::connectBlocks(R1, Plan.getScalarHeader()); 37 38 #if GTEST_HAS_STREAM_REDIRECTION 39 ::testing::internal::CaptureStderr(); 40 #endif 41 EXPECT_FALSE(verifyVPlanIsValid(Plan)); 42 #if GTEST_HAS_STREAM_REDIRECTION 43 EXPECT_STREQ("Use before def!\n", 44 ::testing::internal::GetCapturedStderr().c_str()); 45 #endif 46 } 47 48 TEST_F(VPVerifierTest, VPInstructionUseBeforeDefDifferentBB) { 49 VPlan &Plan = getPlan(); 50 VPValue *Zero = Plan.getOrAddLiveIn(ConstantInt::get(Type::getInt32Ty(C), 0)); 51 VPInstruction *DefI = new VPInstruction(Instruction::Add, {Zero}); 52 VPInstruction *UseI = new VPInstruction(Instruction::Sub, {DefI}); 53 auto *CanIV = new VPCanonicalIVPHIRecipe(Zero, {}); 54 VPInstruction *BranchOnCond = 55 new VPInstruction(VPInstruction::BranchOnCond, {CanIV}); 56 57 VPBasicBlock *VPBB1 = Plan.getEntry(); 58 VPBasicBlock *VPBB2 = Plan.createVPBasicBlock(""); 59 60 VPBB1->appendRecipe(UseI); 61 VPBB2->appendRecipe(CanIV); 62 VPBB2->appendRecipe(DefI); 63 VPBB2->appendRecipe(BranchOnCond); 64 65 VPRegionBlock *R1 = Plan.createVPRegionBlock(VPBB2, VPBB2, "R1"); 66 VPBlockUtils::connectBlocks(VPBB1, R1); 67 VPBlockUtils::connectBlocks(R1, Plan.getScalarHeader()); 68 69 #if GTEST_HAS_STREAM_REDIRECTION 70 ::testing::internal::CaptureStderr(); 71 #endif 72 EXPECT_FALSE(verifyVPlanIsValid(Plan)); 73 #if GTEST_HAS_STREAM_REDIRECTION 74 EXPECT_STREQ("Use before def!\n", 75 ::testing::internal::GetCapturedStderr().c_str()); 76 #endif 77 } 78 79 TEST_F(VPVerifierTest, VPBlendUseBeforeDefDifferentBB) { 80 VPlan &Plan = getPlan(); 81 IntegerType *Int32 = IntegerType::get(C, 32); 82 auto *Phi = PHINode::Create(Int32, 1); 83 VPValue *Zero = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 0)); 84 85 VPInstruction *DefI = new VPInstruction(Instruction::Add, {Zero}); 86 auto *CanIV = new VPCanonicalIVPHIRecipe(Zero, {}); 87 VPInstruction *BranchOnCond = 88 new VPInstruction(VPInstruction::BranchOnCond, {CanIV}); 89 auto *Blend = new VPBlendRecipe(Phi, {DefI}); 90 91 VPBasicBlock *VPBB1 = Plan.getEntry(); 92 VPBasicBlock *VPBB2 = Plan.createVPBasicBlock(""); 93 VPBasicBlock *VPBB3 = Plan.createVPBasicBlock(""); 94 VPBasicBlock *VPBB4 = Plan.createVPBasicBlock(""); 95 96 VPBB2->appendRecipe(CanIV); 97 VPBB3->appendRecipe(Blend); 98 VPBB4->appendRecipe(DefI); 99 VPBB4->appendRecipe(BranchOnCond); 100 101 VPBlockUtils::connectBlocks(VPBB2, VPBB3); 102 VPBlockUtils::connectBlocks(VPBB3, VPBB4); 103 VPRegionBlock *R1 = Plan.createVPRegionBlock(VPBB2, VPBB4, "R1"); 104 VPBlockUtils::connectBlocks(VPBB1, R1); 105 VPBB3->setParent(R1); 106 107 VPBlockUtils::connectBlocks(R1, Plan.getScalarHeader()); 108 109 #if GTEST_HAS_STREAM_REDIRECTION 110 ::testing::internal::CaptureStderr(); 111 #endif 112 EXPECT_FALSE(verifyVPlanIsValid(Plan)); 113 #if GTEST_HAS_STREAM_REDIRECTION 114 EXPECT_STREQ("Use before def!\n", 115 ::testing::internal::GetCapturedStderr().c_str()); 116 #endif 117 118 delete Phi; 119 } 120 121 TEST_F(VPVerifierTest, DuplicateSuccessorsOutsideRegion) { 122 VPlan &Plan = getPlan(); 123 VPValue *Zero = Plan.getOrAddLiveIn(ConstantInt::get(Type::getInt32Ty(C), 0)); 124 VPInstruction *I1 = new VPInstruction(Instruction::Add, {Zero}); 125 auto *CanIV = new VPCanonicalIVPHIRecipe(Zero, {}); 126 VPInstruction *BranchOnCond = 127 new VPInstruction(VPInstruction::BranchOnCond, {CanIV}); 128 VPInstruction *BranchOnCond2 = 129 new VPInstruction(VPInstruction::BranchOnCond, {I1}); 130 131 VPBasicBlock *VPBB1 = Plan.getEntry(); 132 VPBasicBlock *VPBB2 = Plan.createVPBasicBlock(""); 133 134 VPBB1->appendRecipe(I1); 135 VPBB1->appendRecipe(BranchOnCond2); 136 VPBB2->appendRecipe(CanIV); 137 VPBB2->appendRecipe(BranchOnCond); 138 139 VPRegionBlock *R1 = Plan.createVPRegionBlock(VPBB2, VPBB2, "R1"); 140 VPBlockUtils::connectBlocks(VPBB1, R1); 141 VPBlockUtils::connectBlocks(VPBB1, R1); 142 143 VPBlockUtils::connectBlocks(R1, Plan.getScalarHeader()); 144 145 #if GTEST_HAS_STREAM_REDIRECTION 146 ::testing::internal::CaptureStderr(); 147 #endif 148 EXPECT_FALSE(verifyVPlanIsValid(Plan)); 149 #if GTEST_HAS_STREAM_REDIRECTION 150 EXPECT_STREQ("Multiple instances of the same successor.\n", 151 ::testing::internal::GetCapturedStderr().c_str()); 152 #endif 153 } 154 155 TEST_F(VPVerifierTest, DuplicateSuccessorsInsideRegion) { 156 VPlan &Plan = getPlan(); 157 VPValue *Zero = Plan.getOrAddLiveIn(ConstantInt::get(Type::getInt32Ty(C), 0)); 158 VPInstruction *I1 = new VPInstruction(Instruction::Add, {Zero}); 159 auto *CanIV = new VPCanonicalIVPHIRecipe(Zero, {}); 160 VPInstruction *BranchOnCond = 161 new VPInstruction(VPInstruction::BranchOnCond, {CanIV}); 162 VPInstruction *BranchOnCond2 = 163 new VPInstruction(VPInstruction::BranchOnCond, {I1}); 164 165 VPBasicBlock *VPBB1 = Plan.getEntry(); 166 VPBasicBlock *VPBB2 = Plan.createVPBasicBlock(""); 167 VPBasicBlock *VPBB3 = Plan.createVPBasicBlock(""); 168 169 VPBB1->appendRecipe(I1); 170 VPBB2->appendRecipe(CanIV); 171 VPBB2->appendRecipe(BranchOnCond2); 172 VPBB3->appendRecipe(BranchOnCond); 173 174 VPBlockUtils::connectBlocks(VPBB2, VPBB3); 175 VPBlockUtils::connectBlocks(VPBB2, VPBB3); 176 VPRegionBlock *R1 = Plan.createVPRegionBlock(VPBB2, VPBB3, "R1"); 177 VPBlockUtils::connectBlocks(VPBB1, R1); 178 VPBB3->setParent(R1); 179 180 VPBlockUtils::connectBlocks(R1, Plan.getScalarHeader()); 181 182 #if GTEST_HAS_STREAM_REDIRECTION 183 ::testing::internal::CaptureStderr(); 184 #endif 185 EXPECT_FALSE(verifyVPlanIsValid(Plan)); 186 #if GTEST_HAS_STREAM_REDIRECTION 187 EXPECT_STREQ("Multiple instances of the same successor.\n", 188 ::testing::internal::GetCapturedStderr().c_str()); 189 #endif 190 } 191 192 TEST_F(VPVerifierTest, BlockOutsideRegionWithParent) { 193 VPlan &Plan = getPlan(); 194 195 VPBasicBlock *VPBB1 = Plan.getEntry(); 196 VPBasicBlock *VPBB2 = Plan.createVPBasicBlock(""); 197 198 VPValue *Zero = Plan.getOrAddLiveIn(ConstantInt::get(Type::getInt32Ty(C), 0)); 199 auto *CanIV = new VPCanonicalIVPHIRecipe(Zero, {}); 200 VPBB2->appendRecipe(CanIV); 201 202 VPInstruction *DefI = new VPInstruction(Instruction::Add, {Zero}); 203 VPInstruction *BranchOnCond = 204 new VPInstruction(VPInstruction::BranchOnCond, {DefI}); 205 206 VPBB1->appendRecipe(DefI); 207 VPBB2->appendRecipe(BranchOnCond); 208 209 VPRegionBlock *R1 = Plan.createVPRegionBlock(VPBB2, VPBB2, "R1"); 210 VPBlockUtils::connectBlocks(VPBB1, R1); 211 212 VPBlockUtils::connectBlocks(R1, Plan.getScalarHeader()); 213 VPBB1->setParent(R1); 214 215 #if GTEST_HAS_STREAM_REDIRECTION 216 ::testing::internal::CaptureStderr(); 217 #endif 218 EXPECT_FALSE(verifyVPlanIsValid(Plan)); 219 #if GTEST_HAS_STREAM_REDIRECTION 220 EXPECT_STREQ("Predecessor is not in the same region.\n", 221 ::testing::internal::GetCapturedStderr().c_str()); 222 #endif 223 } 224 225 } // namespace 226