Skip to content

Commit b592917

Browse files
[LV] Added verification of EVL recipes (#107630)
1 parent 01df775 commit b592917

File tree

1 file changed

+74
-0
lines changed

1 file changed

+74
-0
lines changed

llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
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+
117184
bool 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

Comments
 (0)