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