1818#include " VPlanDominatorTree.h"
1919#include " llvm/ADT/DepthFirstIterator.h"
2020#include " llvm/ADT/SmallPtrSet.h"
21+ #include " llvm/ADT/TypeSwitch.h"
2122#include " llvm/Support/CommandLine.h"
2223
2324#define DEBUG_TYPE " loop-vectorize"
@@ -35,6 +36,11 @@ class VPlanVerifier {
3536 // VPHeaderPHIRecipes.
3637 bool verifyPhiRecipes (const VPBasicBlock *VPBB);
3738
39+ // / Verify that \p EVL is used correctly. The user must be either in
40+ // / EVL-based recipes as a last operand or VPInstruction::Add which is
41+ // / incoming value into EVL's recipe.
42+ bool verifyEVLRecipe (const VPInstruction &EVL) const ;
43+
3844 bool verifyVPBasicBlock (const VPBasicBlock *VPBB);
3945
4046 bool verifyBlock (const VPBlockBase *VPB);
@@ -114,6 +120,67 @@ bool VPlanVerifier::verifyPhiRecipes(const VPBasicBlock *VPBB) {
114120 return true ;
115121}
116122
123+ bool VPlanVerifier::verifyEVLRecipe (const VPInstruction &EVL) const {
124+ if (EVL.getOpcode () != VPInstruction::ExplicitVectorLength) {
125+ errs () << " verifyEVLRecipe should only be called on "
126+ " VPInstruction::ExplicitVectorLength\n " ;
127+ return false ;
128+ }
129+ auto VerifyEVLUse = [&](const VPRecipeBase &R,
130+ const unsigned ExpectedIdx) -> bool {
131+ SmallVector<const VPValue *> Ops (R.operands ());
132+ unsigned UseCount = count (Ops, &EVL);
133+ if (UseCount != 1 || Ops[ExpectedIdx] != &EVL) {
134+ errs () << " EVL is used as non-last operand in EVL-based recipe\n " ;
135+ return false ;
136+ }
137+ return true ;
138+ };
139+ for (const VPUser *U : EVL.users ()) {
140+ if (!TypeSwitch<const VPUser *, bool >(U)
141+ .Case <VPWidenStoreEVLRecipe>([&](const VPWidenStoreEVLRecipe *S) {
142+ return VerifyEVLUse (*S, 2 );
143+ })
144+ .Case <VPWidenLoadEVLRecipe>([&](const VPWidenLoadEVLRecipe *L) {
145+ return VerifyEVLUse (*L, 1 );
146+ })
147+ .Case <VPWidenEVLRecipe>([&](const VPWidenEVLRecipe *W) {
148+ return VerifyEVLUse (
149+ *W, Instruction::isUnaryOp (W->getOpcode ()) ? 1 : 2 );
150+ })
151+ .Case <VPReductionEVLRecipe>([&](const VPReductionEVLRecipe *R) {
152+ return VerifyEVLUse (*R, 2 );
153+ })
154+ .Case <VPScalarCastRecipe>(
155+ [&](const VPScalarCastRecipe *S) { return true ; })
156+ .Case <VPInstruction>([&](const VPInstruction *I) {
157+ if (I->getOpcode () != Instruction::Add) {
158+ errs ()
159+ << " EVL is used as an operand in non-VPInstruction::Add\n " ;
160+ return false ;
161+ }
162+ if (I->getNumUsers () != 1 ) {
163+ errs () << " EVL is used in VPInstruction:Add with multiple "
164+ " users\n " ;
165+ return false ;
166+ }
167+ if (!isa<VPEVLBasedIVPHIRecipe>(*I->users ().begin ())) {
168+ errs () << " Result of VPInstruction::Add with EVL operand is "
169+ " not used by VPEVLBasedIVPHIRecipe\n " ;
170+ return false ;
171+ }
172+ return true ;
173+ })
174+ .Default ([&](const VPUser *U) {
175+ errs () << " EVL has unexpected user\n " ;
176+ return false ;
177+ })) {
178+ return false ;
179+ }
180+ }
181+ return true ;
182+ }
183+
117184bool VPlanVerifier::verifyVPBasicBlock (const VPBasicBlock *VPBB) {
118185 if (!verifyPhiRecipes (VPBB))
119186 return false ;
@@ -159,6 +226,13 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
159226 }
160227 }
161228 }
229+ if (const auto *EVL = dyn_cast<VPInstruction>(&R)) {
230+ if (EVL->getOpcode () == VPInstruction::ExplicitVectorLength &&
231+ !verifyEVLRecipe (*EVL)) {
232+ errs () << " EVL VPValue is not used correctly\n " ;
233+ return false ;
234+ }
235+ }
162236 }
163237
164238 auto *IRBB = dyn_cast<VPIRBasicBlock>(VPBB);
0 commit comments