24#define DEBUG_TYPE "loop-vectorize"
68 : VPDT(VPDT), TypeInfo(TypeInfo), VerifyLate(VerifyLate) {}
74bool VPlanVerifier::verifyPhiRecipes(
const VPBasicBlock *VPBB) {
75 auto RecipeI = VPBB->
begin();
76 auto End = VPBB->
end();
77 unsigned NumActiveLaneMaskPhiRecipes = 0;
79 while (RecipeI != End && RecipeI->isPhi()) {
81 NumActiveLaneMaskPhiRecipes++;
85 errs() <<
"Found non-header PHI recipe in header VPBB";
86#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
94 errs() <<
"Found header PHI recipe in non-header VPBB";
95#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
106 errs() <<
"Phi-like recipe with different number of operands and "
117 if (!VerifyLate && NumActiveLaneMaskPhiRecipes > 1) {
118 errs() <<
"There should be no more than one VPActiveLaneMaskPHIRecipe";
122 while (RecipeI != End) {
124 errs() <<
"Found phi-like recipe after non-phi recipe";
126#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
130 std::prev(RecipeI)->dump();
139bool VPlanVerifier::verifyEVLRecipe(
const VPInstruction &EVL)
const {
141 errs() <<
"verifyEVLRecipe should only be called on "
142 "VPInstruction::ExplicitVectorLength\n";
145 auto VerifyEVLUse = [&](
const VPRecipeBase &
R,
146 const unsigned ExpectedIdx) ->
bool {
148 unsigned UseCount =
count(
Ops, &EVL);
149 if (UseCount != 1 ||
Ops[ExpectedIdx] != &EVL) {
150 errs() <<
"EVL is used as non-last operand in EVL-based recipe\n";
155 return all_of(EVL.
users(), [
this, &VerifyEVLUse](VPUser *U) {
156 return TypeSwitch<const VPUser *, bool>(U)
157 .Case<VPWidenIntrinsicRecipe>([&](const VPWidenIntrinsicRecipe *S) {
158 return VerifyEVLUse(*S, S->getNumOperands() - 1);
160 .Case<VPWidenStoreEVLRecipe, VPReductionEVLRecipe,
161 VPWidenIntOrFpInductionRecipe, VPWidenPointerInductionRecipe>(
162 [&](
const VPRecipeBase *S) {
return VerifyEVLUse(*S, 2); })
163 .Case<VPScalarIVStepsRecipe>([&](
auto *R) {
164 if (
R->getNumOperands() != 3) {
165 errs() <<
"Unrolling with EVL tail folding not yet supported\n";
168 return VerifyEVLUse(*R, 2);
170 .Case<VPWidenLoadEVLRecipe, VPVectorEndPointerRecipe,
171 VPInterleaveEVLRecipe>(
172 [&](
const VPRecipeBase *R) {
return VerifyEVLUse(*R, 1); })
173 .Case<VPInstructionWithType>(
174 [&](
const VPInstructionWithType *S) {
return VerifyEVLUse(*S, 0); })
175 .Case<VPInstruction>([&](
const VPInstruction *
I) {
176 if (
I->getOpcode() == Instruction::PHI ||
177 I->getOpcode() == Instruction::ICmp ||
178 I->getOpcode() == Instruction::Sub)
179 return VerifyEVLUse(*
I, 1);
180 switch (
I->getOpcode()) {
181 case Instruction::Add:
183 case Instruction::UIToFP:
184 case Instruction::Trunc:
185 case Instruction::ZExt:
186 case Instruction::Mul:
187 case Instruction::FMul:
192 errs() <<
"EVL used by unexpected VPInstruction\n";
197 errs() <<
"EVL used by unexpected VPInstruction\n";
203 I->getNumUsers() != 1 &&
204 (
I->getNumUsers() != 2 ||
207 errs() <<
"EVL is used in VPInstruction with multiple users\n";
211 errs() <<
"Result of VPInstruction::Add with EVL operand is "
212 "not used by VPEVLBasedIVPHIRecipe\n";
217 .
Default([&](
const VPUser *U) {
218 errs() <<
"EVL has unexpected user\n";
224bool VPlanVerifier::verifyVPBasicBlock(
const VPBasicBlock *VPBB) {
225 if (!verifyPhiRecipes(VPBB))
229 DenseMap<const VPRecipeBase *, unsigned> RecipeNumbering;
231 for (
const VPRecipeBase &R : *VPBB)
232 RecipeNumbering[&
R] = Cnt++;
234 for (
const VPRecipeBase &R : *VPBB) {
236 errs() <<
"VPIRInstructions ";
237#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
241 errs() <<
"not in a VPIRBasicBlock!\n";
244 for (
const VPValue *V :
R.definedValues()) {
249 errs() <<
"Failed to infer scalar type!\n";
253 for (
const VPUser *U :
V->users()) {
256 UI->getNumOperands() != UI->getParent()->getNumPredecessors()) {
257 errs() <<
"Phi-like recipe with different number of operands and "
263 for (
const auto &[IncomingVPV, IncomingVPBB] :
264 Phi->incoming_values_and_blocks()) {
265 if (IncomingVPV != V)
271 errs() <<
"Incoming def does not dominate incoming block!\n";
272#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
273 VPSlotTracker Tracker(VPBB->getPlan());
274 IncomingVPV->getDefiningRecipe()->print(
errs(),
" ", Tracker);
275 errs() <<
"\n does not dominate " << IncomingVPBB->getName()
277 UI->print(
errs(),
" ", Tracker);
289 if (UI->getParent() == VPBB) {
290 if (RecipeNumbering[UI] >= RecipeNumbering[&R])
293 if (VPDT.
dominates(VPBB, UI->getParent()))
297 errs() <<
"Use before def!\n";
298#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
299 VPSlotTracker Tracker(VPBB->getPlan());
300 UI->print(
errs(),
" ", Tracker);
301 errs() <<
"\n before\n";
302 R.print(
errs(),
" ", Tracker);
309 switch (VPI->getOpcode()) {
311 if (!verifyEVLRecipe(*VPI)) {
312 errs() <<
"EVL VPValue is not used correctly\n";
326 if (!WrappedIRBBs.
insert(IRBB->getIRBasicBlock()).second) {
327 errs() <<
"Same IR basic block used by multiple wrapper blocks!\n";
338 for (
const auto *
Block : VPBlockVec) {
345bool VPlanVerifier::verifyBlock(
const VPBlockBase *VPB) {
350 (VPBB && VPBB->getParent() && VPBB->isExiting() &&
351 !VPBB->getParent()->isReplicator())) {
352 if (!VPBB || !VPBB->getTerminator()) {
353 errs() <<
"Block has multiple successors but doesn't "
354 "have a proper branch recipe!\n";
358 if (VPBB && VPBB->getTerminator()) {
359 errs() <<
"Unexpected branch recipe!\n";
370 errs() <<
"Multiple instances of the same successor.\n";
374 for (
const VPBlockBase *Succ : Successors) {
376 const auto &SuccPreds = Succ->getPredecessors();
378 errs() <<
"Missing predecessor link.\n";
389 errs() <<
"Multiple instances of the same predecessor.\n";
393 for (
const VPBlockBase *Pred : Predecessors) {
395 if (Pred->getParent() != VPB->
getParent()) {
396 errs() <<
"Predecessor is not in the same region.\n";
401 const auto &PredSuccs = Pred->getSuccessors();
403 errs() <<
"Missing successor link.\n";
407 return !VPBB || verifyVPBasicBlock(VPBB);
410bool VPlanVerifier::verifyBlocksInRegion(
const VPRegionBlock *Region) {
414 errs() <<
"VPBlockBase has wrong parent\n";
418 if (!verifyBlock(VPB))
424bool VPlanVerifier::verifyRegion(
const VPRegionBlock *Region) {
426 const VPBlockBase *Exiting =
Region->getExiting();
429 if (
Entry->hasPredecessors()) {
430 errs() <<
"region entry block has predecessors\n";
434 errs() <<
"region exiting block has successors\n";
438 return verifyBlocksInRegion(Region);
441bool VPlanVerifier::verifyRegionRec(
const VPRegionBlock *Region) {
443 return verifyRegion(Region) &&
445 [
this](
const VPBlockBase *VPB) {
446 const auto *SubRegion = dyn_cast<VPRegionBlock>(VPB);
447 return !SubRegion || verifyRegionRec(SubRegion);
451bool VPlanVerifier::verify(
const VPlan &Plan) {
453 [
this](
const VPBlockBase *VPB) { return !verifyBlock(VPB); }))
461 if (!verifyRegionRec(TopRegion))
465 errs() <<
"VPlan Top Region should have no parent.\n";
471 errs() <<
"VPlan entry block is not a VPBasicBlock\n";
476 errs() <<
"VPlan vector loop header does not start with a "
477 "VPCanonicalIVPHIRecipe\n";
483 errs() <<
"VPlan exiting block is not a VPBasicBlock\n";
487 if (Exiting->
empty()) {
488 errs() <<
"VPlan vector loop exiting block must end with BranchOnCount or "
489 "BranchOnCond VPInstruction but is empty\n";
495 errs() <<
"VPlan vector loop exit must end with BranchOnCount or "
496 "BranchOnCond VPInstruction\n";
506 VPlanVerifier
Verifier(VPDT, TypeInfo, VerifyLate);
507 return Verifier.verify(Plan);
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
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:
bool dominates(const DomTreeNodeBase< NodeT > *A, const DomTreeNodeBase< NodeT > *B) const
dominates - Returns true iff A dominates B.
Implements a dense probed hash-table based set with some number of buckets stored inline.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
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...
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.
This is a concrete Recipe that models a single VPlan-level instruction.
unsigned getOpcode() const
VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks which form a Single-Entry-S...
const VPBlockBase * getEntry() const
const VPBlockBase * getExiting() const
An analysis for type-inference for VPValues.
Type * inferScalarType(const VPValue *V)
Infer the type of V. Returns the scalar type of V.
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)
bool match(Val *V, const Pattern &P)
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
MatchFunctor< Val, Pattern > match_fn(const Pattern &P)
A match functor that can be used as a UnaryPredicate in functional algorithms like all_of.
match_combine_or< LTy, RTy > m_CombineOr(const LTy &L, const RTy &R)
Combine two pattern matchers matching L || R.
VPInstruction_match< VPInstruction::BranchOnCount > m_BranchOnCount()
class_match< VPValue > m_VPValue()
Match an arbitrary VPValue and ignore it.
VPInstruction_match< VPInstruction::BranchOnCond > m_BranchOnCond()
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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
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.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
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...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.