25#define DEBUG_TYPE "loop-vectorize"
49 bool verifyLastActiveLaneRecipe(
const VPInstruction &LastActiveLane)
const;
72 : VPDT(VPDT), TypeInfo(TypeInfo), VerifyLate(VerifyLate) {}
78bool VPlanVerifier::verifyPhiRecipes(
const VPBasicBlock *VPBB) {
79 auto RecipeI = VPBB->
begin();
80 auto End = VPBB->
end();
81 unsigned NumActiveLaneMaskPhiRecipes = 0;
83 while (RecipeI != End && RecipeI->isPhi()) {
85 NumActiveLaneMaskPhiRecipes++;
89 errs() <<
"Found non-header PHI recipe in header VPBB";
90#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
98 errs() <<
"Found header PHI recipe in non-header VPBB";
99#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
110 errs() <<
"Phi-like recipe with different number of operands and "
121 if (!VerifyLate && NumActiveLaneMaskPhiRecipes > 1) {
122 errs() <<
"There should be no more than one VPActiveLaneMaskPHIRecipe";
126 while (RecipeI != End) {
128 errs() <<
"Found phi-like recipe after non-phi recipe";
130#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
134 std::prev(RecipeI)->dump();
143bool VPlanVerifier::verifyEVLRecipe(
const VPInstruction &EVL)
const {
145 errs() <<
"verifyEVLRecipe should only be called on "
146 "VPInstruction::ExplicitVectorLength\n";
149 auto VerifyEVLUse = [&](
const VPRecipeBase &
R,
150 const unsigned ExpectedIdx) ->
bool {
152 unsigned UseCount =
count(
Ops, &EVL);
153 if (UseCount != 1 ||
Ops[ExpectedIdx] != &EVL) {
154 errs() <<
"EVL is used as non-last operand in EVL-based recipe\n";
159 return all_of(EVL.
users(), [
this, &VerifyEVLUse](VPUser *U) {
160 return TypeSwitch<const VPUser *, bool>(U)
161 .Case<VPWidenIntrinsicRecipe>([&](const VPWidenIntrinsicRecipe *S) {
162 return VerifyEVLUse(*S, S->getNumOperands() - 1);
164 .Case<VPWidenStoreEVLRecipe, VPReductionEVLRecipe,
165 VPWidenIntOrFpInductionRecipe, VPWidenPointerInductionRecipe>(
166 [&](
const VPRecipeBase *S) {
return VerifyEVLUse(*S, 2); })
167 .Case<VPScalarIVStepsRecipe>([&](
auto *R) {
168 if (
R->getNumOperands() != 3) {
169 errs() <<
"Unrolling with EVL tail folding not yet supported\n";
172 return VerifyEVLUse(*R, 2);
174 .Case<VPWidenLoadEVLRecipe, VPVectorEndPointerRecipe,
175 VPInterleaveEVLRecipe>(
176 [&](
const VPRecipeBase *R) {
return VerifyEVLUse(*R, 1); })
177 .Case<VPInstructionWithType>(
178 [&](
const VPInstructionWithType *S) {
return VerifyEVLUse(*S, 0); })
179 .Case<VPInstruction>([&](
const VPInstruction *
I) {
180 if (
I->getOpcode() == Instruction::PHI ||
181 I->getOpcode() == Instruction::ICmp ||
182 I->getOpcode() == Instruction::Sub)
183 return VerifyEVLUse(*
I, 1);
184 switch (
I->getOpcode()) {
185 case Instruction::Add:
187 case Instruction::UIToFP:
188 case Instruction::Trunc:
189 case Instruction::ZExt:
190 case Instruction::Mul:
191 case Instruction::Shl:
192 case Instruction::FMul:
197 errs() <<
"EVL used by unexpected VPInstruction\n";
202 errs() <<
"EVL used by unexpected VPInstruction\n";
208 I->getNumUsers() != 1 &&
209 (
I->getNumUsers() != 2 ||
212 errs() <<
"EVL is used in VPInstruction with multiple users\n";
216 errs() <<
"Result of VPInstruction::Add with EVL operand is "
217 "not used by VPEVLBasedIVPHIRecipe\n";
222 .
Default([&](
const VPUser *U) {
223 errs() <<
"EVL has unexpected user\n";
229bool VPlanVerifier::verifyLastActiveLaneRecipe(
230 const VPInstruction &LastActiveLane)
const {
232 "must be called with VPInstruction::LastActiveLane");
235 errs() <<
"LastActiveLane must have at least one operand\n";
243 for (VPValue *
Op : LastActiveLane.
operands()) {
248 auto BroadcastOrEVL =
254 errs() <<
"LastActiveLane operand ";
255#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
256 VPSlotTracker Tracker(&Plan);
257 Op->printAsOperand(
errs(), Tracker);
259 errs() <<
" must be prefix mask (a header mask or an "
260 "EVL-derived mask currently)\n";
267bool VPlanVerifier::verifyVPBasicBlock(
const VPBasicBlock *VPBB) {
268 if (!verifyPhiRecipes(VPBB))
272 DenseMap<const VPRecipeBase *, unsigned> RecipeNumbering;
274 for (
const VPRecipeBase &R : *VPBB)
275 RecipeNumbering[&
R] = Cnt++;
277 for (
const VPRecipeBase &R : *VPBB) {
279 errs() <<
"VPIRInstructions ";
280#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
284 errs() <<
"not in a VPIRBasicBlock!\n";
287 for (
const VPValue *V :
R.definedValues()) {
292 errs() <<
"Failed to infer scalar type!\n";
296 for (
const VPUser *U :
V->users()) {
299 UI->getNumOperands() != UI->getParent()->getNumPredecessors()) {
300 errs() <<
"Phi-like recipe with different number of operands and "
306 for (
const auto &[IncomingVPV, IncomingVPBB] :
307 Phi->incoming_values_and_blocks()) {
308 if (IncomingVPV != V)
314 errs() <<
"Incoming def does not dominate incoming block!\n";
315#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
316 VPSlotTracker Tracker(VPBB->getPlan());
317 IncomingVPV->getDefiningRecipe()->print(
errs(),
" ", Tracker);
318 errs() <<
"\n does not dominate " << IncomingVPBB->getName()
320 UI->print(
errs(),
" ", Tracker);
332 if (UI->getParent() == VPBB) {
333 if (RecipeNumbering[UI] >= RecipeNumbering[&R])
336 if (VPDT.
dominates(VPBB, UI->getParent()))
340 errs() <<
"Use before def!\n";
341#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
342 VPSlotTracker Tracker(VPBB->getPlan());
343 UI->print(
errs(),
" ", Tracker);
344 errs() <<
"\n before\n";
345 R.print(
errs(),
" ", Tracker);
352 switch (VPI->getOpcode()) {
354 if (!verifyEVLRecipe(*VPI)) {
355 errs() <<
"EVL VPValue is not used correctly\n";
360 if (!verifyLastActiveLaneRecipe(*VPI))
373 if (!WrappedIRBBs.
insert(IRBB->getIRBasicBlock()).second) {
374 errs() <<
"Same IR basic block used by multiple wrapper blocks!\n";
385 for (
const auto *
Block : VPBlockVec) {
392bool VPlanVerifier::verifyBlock(
const VPBlockBase *VPB) {
397 (VPBB->getParent() && VPBB->isExiting() &&
398 !VPBB->getParent()->isReplicator())) {
399 if (!VPBB->getTerminator()) {
400 errs() <<
"Block has multiple successors but doesn't "
401 "have a proper branch recipe!\n";
404 }
else if (VPBB->getTerminator()) {
405 errs() <<
"Unexpected branch recipe!\n";
415 errs() <<
"Multiple instances of the same successor.\n";
419 for (
const VPBlockBase *Succ : Successors) {
421 const auto &SuccPreds = Succ->getPredecessors();
423 errs() <<
"Missing predecessor link.\n";
434 errs() <<
"Multiple instances of the same predecessor.\n";
438 for (
const VPBlockBase *Pred : Predecessors) {
440 if (Pred->getParent() != VPB->
getParent()) {
441 errs() <<
"Predecessor is not in the same region.\n";
446 const auto &PredSuccs = Pred->getSuccessors();
448 errs() <<
"Missing successor link.\n";
452 return !VPBB || verifyVPBasicBlock(VPBB);
455bool VPlanVerifier::verifyBlocksInRegion(
const VPRegionBlock *Region) {
459 errs() <<
"VPBlockBase has wrong parent\n";
463 if (!verifyBlock(VPB))
469bool VPlanVerifier::verifyRegion(
const VPRegionBlock *Region) {
471 const VPBlockBase *Exiting =
Region->getExiting();
474 if (
Entry->hasPredecessors()) {
475 errs() <<
"region entry block has predecessors\n";
479 errs() <<
"region exiting block has successors\n";
483 return verifyBlocksInRegion(Region);
486bool VPlanVerifier::verifyRegionRec(
const VPRegionBlock *Region) {
488 return verifyRegion(Region) &&
490 [
this](
const VPBlockBase *VPB) {
491 const auto *SubRegion = dyn_cast<VPRegionBlock>(VPB);
492 return !SubRegion || verifyRegionRec(SubRegion);
496bool VPlanVerifier::verify(
const VPlan &Plan) {
498 [
this](
const VPBlockBase *VPB) { return !verifyBlock(VPB); }))
506 if (!verifyRegionRec(TopRegion))
510 errs() <<
"VPlan Top Region should have no parent.\n";
516 errs() <<
"VPlan entry block is not a VPBasicBlock\n";
521 errs() <<
"VPlan vector loop header does not start with a "
522 "VPCanonicalIVPHIRecipe\n";
528 errs() <<
"VPlan exiting block is not a VPBasicBlock\n";
532 if (Exiting->
empty()) {
533 errs() <<
"VPlan vector loop exiting block must end with BranchOnCount, "
534 "BranchOnCond, or BranchOnTwoConds VPInstruction but is empty\n";
542 errs() <<
"VPlan vector loop exit must end with BranchOnCount, "
543 "BranchOnCond, or BranchOnTwoConds VPInstruction\n";
553 VPlanVerifier
Verifier(VPDT, TypeInfo, VerifyLate);
554 return Verifier.verify(Plan);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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
VPBasicBlock * getParent()
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.
unsigned getNumOperands() const
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.
CmpClass_match< LHS, RHS, ICmpInst > m_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
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::StepVector > m_StepVector()
VPInstruction_match< VPInstruction::BranchOnTwoConds > m_BranchOnTwoConds()
VPInstruction_match< VPInstruction::BranchOnCount > m_BranchOnCount()
VPInstruction_match< VPInstruction::Broadcast, Op0_t > m_Broadcast(const Op0_t &Op0)
class_match< VPValue > m_VPValue()
Match an arbitrary VPValue and ignore it.
VPInstruction_match< VPInstruction::ExplicitVectorLength, Op0_t > m_EVL(const Op0_t &Op0)
VPInstruction_match< VPInstruction::BranchOnCond > m_BranchOnCond()
NodeAddr< PhiNode * > Phi
bool isHeaderMask(const VPValue *V, const VPlan &Plan)
Return true if V is a header mask in Plan.
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...
DWARFExpression::Operation Op
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.