xref: /llvm-project/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp (revision 8caeb2e0c2fb8a5f1689c11775b81ceee76de958)
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