24#define DEBUG_TYPE "loop-vectorize"
67 : VPDT(VPDT), TypeInfo(TypeInfo), VerifyLate(VerifyLate) {}
73bool VPlanVerifier::verifyPhiRecipes(
const VPBasicBlock *VPBB) {
74 auto RecipeI = VPBB->
begin();
76 unsigned NumActiveLaneMaskPhiRecipes = 0;
78 while (RecipeI !=
End && RecipeI->isPhi()) {
79 if (isa<VPActiveLaneMaskPHIRecipe>(RecipeI))
80 NumActiveLaneMaskPhiRecipes++;
83 !isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPhi>(*RecipeI)) {
84 errs() <<
"Found non-header PHI recipe in header VPBB";
85#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
92 if (!IsHeaderVPBB && isa<VPHeaderPHIRecipe>(*RecipeI)) {
93 errs() <<
"Found header PHI recipe in non-header VPBB";
94#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
103 if (
auto *PhiIRI = dyn_cast<VPIRPhi>(&*RecipeI)) {
105 errs() <<
"Phi-like recipe with different number of operands and "
116 if (!VerifyLate && NumActiveLaneMaskPhiRecipes > 1) {
117 errs() <<
"There should be no more than one VPActiveLaneMaskPHIRecipe";
121 while (RecipeI !=
End) {
122 if (RecipeI->isPhi() && !isa<VPBlendRecipe>(&*RecipeI)) {
123 errs() <<
"Found phi-like recipe after non-phi recipe";
125#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
129 std::prev(RecipeI)->dump();
138bool VPlanVerifier::verifyEVLRecipe(
const VPInstruction &EVL)
const {
140 errs() <<
"verifyEVLRecipe should only be called on "
141 "VPInstruction::ExplicitVectorLength\n";
145 const unsigned ExpectedIdx) ->
bool {
147 unsigned UseCount =
count(Ops, &EVL);
148 if (UseCount != 1 || Ops[ExpectedIdx] != &EVL) {
149 errs() <<
"EVL is used as non-last operand in EVL-based recipe\n";
155 return TypeSwitch<const VPUser *, bool>(U)
156 .Case<VPWidenIntrinsicRecipe>([&](const VPWidenIntrinsicRecipe *S) {
157 return VerifyEVLUse(*S, S->getNumOperands() - 1);
161 [&](
const VPRecipeBase *S) {
return VerifyEVLUse(*S, 2); })
162 .Case<VPScalarIVStepsRecipe>([&](
auto *R) {
163 if (
R->getNumOperands() != 3) {
164 errs() <<
"Unrolling with EVL tail folding not yet supported\n";
167 return VerifyEVLUse(*R, 2);
169 .Case<VPWidenLoadEVLRecipe, VPVectorEndPointerRecipe>(
170 [&](
const VPRecipeBase *R) {
return VerifyEVLUse(*R, 1); })
171 .Case<VPInstructionWithType>(
174 if (
I->getOpcode() == Instruction::PHI ||
175 I->getOpcode() == Instruction::ICmp ||
176 I->getOpcode() == Instruction::Sub)
177 return VerifyEVLUse(*
I, 1);
178 switch (
I->getOpcode()) {
179 case Instruction::Add:
181 case Instruction::UIToFP:
182 case Instruction::Trunc:
183 case Instruction::ZExt:
184 case Instruction::Mul:
185 case Instruction::FMul:
190 errs() <<
"EVL used by unexpected VPInstruction\n";
195 errs() <<
"EVL used by unexpected VPInstruction\n";
200 if ((
I->getNumUsers() != 1) &&
202 using namespace llvm::VPlanPatternMatch;
203 return match(U, m_BranchOnCount(m_Specific(I), m_VPValue()));
205 errs() <<
"EVL is used in VPInstruction with multiple users\n";
208 if (!VerifyLate && !isa<VPEVLBasedIVPHIRecipe>(*
I->users().begin())) {
209 errs() <<
"Result of VPInstruction::Add with EVL operand is "
210 "not used by VPEVLBasedIVPHIRecipe\n";
216 errs() <<
"EVL has unexpected user\n";
222bool VPlanVerifier::verifyVPBasicBlock(
const VPBasicBlock *VPBB) {
223 if (!verifyPhiRecipes(VPBB))
230 RecipeNumbering[&
R] = Cnt++;
233 if (isa<VPIRInstruction>(&R) && !isa<VPIRBasicBlock>(VPBB)) {
234 errs() <<
"VPIRInstructions ";
235#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
239 errs() <<
"not in a VPIRBasicBlock!\n";
242 for (
const VPValue *V :
R.definedValues()) {
246 if (!TypeInfo.inferScalarType(V)) {
247 errs() <<
"Failed to infer scalar type!\n";
251 for (
const VPUser *U :
V->users()) {
252 auto *UI = cast<VPRecipeBase>(U);
253 if (
auto *Phi = dyn_cast<VPPhiAccessors>(UI)) {
254 for (
const auto &[IncomingVPV, IncomingVPBB] :
255 Phi->incoming_values_and_blocks()) {
256 if (IncomingVPV != V)
259 if (VPDT.dominates(VPBB, IncomingVPBB))
262 errs() <<
"Incoming def does not dominate incoming block!\n";
263#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
265 IncomingVPV->getDefiningRecipe()->print(
errs(),
" ", Tracker);
266 errs() <<
"\n does not dominate " << IncomingVPBB->getName()
268 UI->print(
errs(),
" ", Tracker);
275 if (isa<VPPredInstPHIRecipe>(UI))
280 if (UI->getParent() == VPBB) {
281 if (RecipeNumbering[UI] >= RecipeNumbering[&R])
284 if (VPDT.dominates(VPBB, UI->getParent()))
288 errs() <<
"Use before def!\n";
289#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
291 UI->print(
errs(),
" ", Tracker);
292 errs() <<
"\n before\n";
293 R.print(
errs(),
" ", Tracker);
299 if (
const auto *EVL = dyn_cast<VPInstruction>(&R)) {
301 !verifyEVLRecipe(*EVL)) {
302 errs() <<
"EVL VPValue is not used correctly\n";
308 auto *IRBB = dyn_cast<VPIRBasicBlock>(VPBB);
312 if (!WrappedIRBBs.insert(IRBB->getIRBasicBlock()).second) {
313 errs() <<
"Same IR basic block used by multiple wrapper blocks!\n";
324 for (
const auto *
Block : VPBlockVec) {
331bool VPlanVerifier::verifyBlock(
const VPBlockBase *VPB) {
332 auto *VPBB = dyn_cast<VPBasicBlock>(VPB);
334 if (!isa<VPIRBasicBlock>(VPB)) {
336 (VPBB && VPBB->getParent() && VPBB->isExiting() &&
337 !VPBB->getParent()->isReplicator())) {
338 if (!VPBB || !VPBB->getTerminator()) {
339 errs() <<
"Block has multiple successors but doesn't "
340 "have a proper branch recipe!\n";
344 if (VPBB && VPBB->getTerminator()) {
345 errs() <<
"Unexpected branch recipe!\n";
356 errs() <<
"Multiple instances of the same successor.\n";
362 const auto &SuccPreds = Succ->getPredecessors();
364 errs() <<
"Missing predecessor link.\n";
375 errs() <<
"Multiple instances of the same predecessor.\n";
381 if (Pred->getParent() != VPB->
getParent()) {
382 errs() <<
"Predecessor is not in the same region.\n";
387 const auto &PredSuccs = Pred->getSuccessors();
389 errs() <<
"Missing successor link.\n";
393 return !VPBB || verifyVPBasicBlock(VPBB);
400 errs() <<
"VPBlockBase has wrong parent\n";
404 if (!verifyBlock(VPB))
415 if (
Entry->getNumPredecessors() != 0) {
416 errs() <<
"region entry block has predecessors\n";
420 errs() <<
"region exiting block has successors\n";
424 return verifyBlocksInRegion(
Region);
429 return verifyRegion(
Region) &&
432 const auto *SubRegion = dyn_cast<VPRegionBlock>(VPB);
433 return !SubRegion || verifyRegionRec(SubRegion);
437bool VPlanVerifier::verify(
const VPlan &Plan) {
439 [
this](
const VPBlockBase *VPB) { return !verifyBlock(VPB); }))
447 if (!verifyRegionRec(TopRegion))
451 errs() <<
"VPlan Top Region should have no parent.\n";
457 errs() <<
"VPlan entry block is not a VPBasicBlock\n";
461 if (!isa<VPCanonicalIVPHIRecipe>(&*
Entry->begin())) {
462 errs() <<
"VPlan vector loop header does not start with a "
463 "VPCanonicalIVPHIRecipe\n";
469 errs() <<
"VPlan exiting block is not a VPBasicBlock\n";
473 if (Exiting->
empty()) {
474 errs() <<
"VPlan vector loop exiting block must end with BranchOnCount or "
475 "BranchOnCond VPInstruction but is empty\n";
479 auto *LastInst = dyn_cast<VPInstruction>(std::prev(Exiting->
end()));
482 errs() <<
"VPlan vector loop exit must end with BranchOnCount or "
483 "BranchOnCond VPInstruction\n";
494 VPlanVerifier
Verifier(VPDT, TypeInfo, VerifyLate);
verify safepoint Safepoint IR Verifier
This file defines the SmallPtrSet class.
This file implements the TypeSwitch template, which mimics a switch() statement whose cases are type ...
This file implements dominator tree analysis for a single level of a VPlan's H-CFG.
This file contains the declarations of different VPlan-related auxiliary helpers.
static bool hasDuplicates(const SmallVectorImpl< VPBlockBase * > &VPBlockVec)
Utility function that checks whether VPBlockVec has duplicate VPBlockBases.
This file declares the class VPlanVerifier, which contains utility functions to check the consistency...
This file contains the declarations of the Vectorization Plan base classes:
void recalculate(ParentType &Func)
recalculate - compute a dominator tree for the given function
BlockT * getEntry() const
Get the entry BasicBlock of the Region.
Implements a dense probed hash-table based set with some number of buckets stored inline.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph.
iterator begin()
Recipe iterator methods.
VPBlockBase is the building block of the Hierarchical Control-Flow Graph.
VPRegionBlock * getParent()
size_t getNumSuccessors() const
size_t getNumPredecessors() const
const VPBlocksTy & getPredecessors() const
const VPBlocksTy & getSuccessors() const
static bool isHeader(const VPBlockBase *VPB, const VPDominatorTree &VPDT)
Returns true if VPB is a loop header, based on regions or VPDT in their absence.
Template specialization of the standard LLVM dominator tree utility for VPBlockBases.
A specialization of VPInstruction augmenting it with a dedicated result type, to be used when the opc...
This is a concrete Recipe that models a single VPlan-level instruction.
unsigned getOpcode() const
VPRecipeBase is a base class modeling a sequence of one or more output IR instructions.
A recipe to represent inloop reduction operations with vector-predication intrinsics,...
VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks which form a Single-Entry-S...
const VPBlockBase * getEntry() const
const VPBlockBase * getExiting() const
This class can be used to assign names to VPValues.
An analysis for type-inference for VPValues.
This class augments VPValue with operands which provide the inverse def-use edges from VPValue's user...
A recipe for handling phi nodes of integer and floating-point inductions, producing their vector valu...
VPlan models a candidate for vectorization, encoding various decisions take to produce efficient outp...
VPBasicBlock * getEntry()
LLVM_ABI_FOR_TEST VPRegionBlock * getVectorLoopRegion()
Returns the VPRegionBlock of the vector loop.
std::pair< iterator, bool > insert(const ValueT &V)
NodeAddr< PhiNode * > Phi
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI_FOR_TEST bool verifyVPlanIsValid(const VPlan &Plan, bool VerifyLate=false)
Verify invariants for general VPlans.
iterator_range< df_iterator< VPBlockShallowTraversalWrapper< VPBlockBase * > > > vp_depth_first_shallow(VPBlockBase *G)
Returns an iterator range to traverse the graph starting at G in depth-first order.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
A recipe for widening store operations with vector-predication intrinsics, using the value to store,...