25#define DEBUG_TYPE "loop-vectorize"
43 bool verifyLastActiveLaneRecipe(
const VPInstruction &LastActiveLane)
const;
71 : VPDT(VPDT), TypeInfo(TypeInfo) {}
77bool VPlanVerifier::verifyPhiRecipes(
const VPBasicBlock *VPBB) {
78 auto RecipeI = VPBB->
begin();
79 auto End = VPBB->
end();
80 unsigned NumActiveLaneMaskPhiRecipes = 0;
82 while (RecipeI != End && RecipeI->isPhi()) {
84 NumActiveLaneMaskPhiRecipes++;
88 errs() <<
"Found non-header PHI recipe in header VPBB";
89#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
97 errs() <<
"Found header PHI recipe in non-header VPBB";
98#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
106 RecipeI->getIterator() != VPBB->
begin()) {
107 errs() <<
"CurrentIteration PHI is not the first recipe\n";
115 errs() <<
"Phi-like recipe with different number of operands and "
127 errs() <<
"There should be no more than one VPActiveLaneMaskPHIRecipe";
131 while (RecipeI != End) {
133 errs() <<
"Found phi-like recipe after non-phi recipe";
135#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
139 std::prev(RecipeI)->dump();
157 return WidenIV->isCanonical() || WidenIV->hasNoUnsignedWrap();
159 return match(Steps->getOperand(0),
169bool VPlanVerifier::verifyLastActiveLaneRecipe(
170 const VPInstruction &LastActiveLane)
const {
172 "must be called with VPInstruction::LastActiveLane");
175 errs() <<
"LastActiveLane must have at least one operand\n";
182 for (VPValue *
Op : LastActiveLane.
operands()) {
210 errs() <<
"LastActiveLane operand ";
211#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
212 VPSlotTracker Tracker(&Plan);
213 Op->printAsOperand(
errs(), Tracker);
215 errs() <<
" must be prefix mask (a header mask or an "
216 "EVL-derived mask currently)\n";
223bool VPlanVerifier::verifyRecipeTypes(
const VPRecipeBase &R)
const {
228 auto CheckScalarType = [&](
Type *Derived) ->
bool {
229 if (Derived == SR->getScalarType())
231 errs() <<
"Recipe result type does not match type derived from operands";
232#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
240 auto CheckOperandTypes = [&]() ->
bool {
242 return getScalarTypeOrInfer(R.getOperand(0)) ==
243 getScalarTypeOrInfer(Op);
246 errs() <<
"Recipe operand types do not match";
247#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
256 return CheckScalarType(WII->getTruncInst()
257 ? WII->getTruncInst()->getType()
258 : WII->getStartValue()->getScalarType());
260 switch (
R.getVPRecipeID()) {
261 case VPRecipeBase::VPVectorPointerSC:
262 case VPRecipeBase::VPVectorEndPointerSC:
263 case VPRecipeBase::VPWidenGEPSC:
264 case VPRecipeBase::VPScalarIVStepsSC:
265 case VPRecipeBase::VPWidenPointerInductionSC:
266 case VPRecipeBase::VPDerivedIVSC:
268 case VPRecipeBase::VPWidenPHISC:
269 case VPRecipeBase::VPPredInstPHISC:
270 case VPRecipeBase::VPReductionPHISC:
271 case VPRecipeBase::VPActiveLaneMaskPHISC:
272 case VPRecipeBase::VPCurrentIterationPHISC:
273 case VPRecipeBase::VPFirstOrderRecurrencePHISC:
274 return CheckOperandTypes() &&
276 case VPRecipeBase::VPInstructionSC: {
284 Instruction::Alloca, Instruction::Call},
288 return CheckScalarType(
291 case VPRecipeBase::VPReplicateSC: {
294 if (RepR->isPredicated())
296 return CheckScalarType(
299 case VPRecipeBase::VPWidenSC: {
304 case VPRecipeBase::VPExpressionSC:
306 ->getOperandOfResultType()
314bool VPlanVerifier::verifyVPBasicBlock(
const VPBasicBlock *VPBB) {
315 if (!verifyPhiRecipes(VPBB))
319 DenseMap<const VPRecipeBase *, unsigned> RecipeNumbering;
321 for (
const VPRecipeBase &R : *VPBB)
322 RecipeNumbering[&
R] = Cnt++;
324 for (
const VPRecipeBase &R : *VPBB) {
326 errs() <<
"VPIRInstructions ";
327#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
331 errs() <<
"not in a VPIRBasicBlock!\n";
334 if (!verifyRecipeTypes(R))
336 for (
const VPValue *V :
R.definedValues()) {
341 errs() <<
"Failed to infer scalar type!\n";
350 for (
const VPUser *U :
V->users()) {
353 UI->getNumOperands() != UI->getParent()->getNumPredecessors()) {
354 errs() <<
"Phi-like recipe with different number of operands and "
360 for (
const auto &[IncomingVPV, IncomingVPBB] :
361 Phi->incoming_values_and_blocks()) {
362 if (IncomingVPV != V)
368 errs() <<
"Incoming def does not dominate incoming block!\n";
369#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
370 VPSlotTracker Tracker(VPBB->getPlan());
371 IncomingVPV->getDefiningRecipe()->print(
errs(),
" ", Tracker);
372 errs() <<
"\n does not dominate " << IncomingVPBB->getName()
374 UI->print(
errs(),
" ", Tracker);
386 if (UI->getParent() == VPBB) {
387 if (RecipeNumbering[UI] >= RecipeNumbering[&R])
390 if (VPDT.
dominates(VPBB, UI->getParent()))
397 bool BlockHasMaskedCond =
any_of(*VPBB, [](
const VPRecipeBase &R) {
400 if (BlockHasMaskedCond &&
401 any_of(VPBB->getPlan()->getExitBlocks(), [UI](VPIRBasicBlock *EB) {
402 return is_contained(EB->getPredecessors(), UI->getParent());
407 errs() <<
"Use before def!\n";
408#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
409 VPSlotTracker Tracker(VPBB->getPlan());
410 UI->print(
errs(),
" ", Tracker);
411 errs() <<
"\n before\n";
412 R.print(
errs(),
" ", Tracker);
419 switch (VPI->getOpcode()) {
421 if (!verifyLastActiveLaneRecipe(*VPI))
429 unsigned NumOps = ScalarIVSteps->getNumOperands();
431 errs() <<
"VPScalarIVStepsRecipe must have 3 or 4 operands\n";
441 if (!WrappedIRBBs.
insert(IRBB->getIRBasicBlock()).second) {
442 errs() <<
"Same IR basic block used by multiple wrapper blocks!\n";
449bool VPlanVerifier::verifyBlock(
const VPBlockBase *VPB) {
454 if (!VPBB->getParent()) {
458 <<
"Header block in plain CFG VPlan must have 2 predecessors!\n";
463 errs() <<
"Header's second predecessor must be the latch!\n";
469 auto BranchTerminator =
472 if (!
match(VPBB->getTerminator(), BranchTerminator)) {
473 errs() <<
"Latch block must have a branch terminator!\n";
478 errs() <<
"Latch's first successor must not be the header (must be "
484 (VPBB->isExiting() && !VPBB->getParent()->isReplicator())) {
485 if (!VPBB->getTerminator()) {
486 errs() <<
"Block has multiple successors but doesn't "
487 "have a proper branch recipe!\n";
490 }
else if (VPBB->getTerminator()) {
491 errs() <<
"Unexpected branch recipe!\n";
498 for (
const VPBlockBase *Succ : Successors) {
500 const auto &SuccPreds = Succ->getPredecessors();
502 errs() <<
"Missing predecessor link.\n";
510 for (
const VPBlockBase *Pred : Predecessors) {
512 if (Pred->getParent() != VPB->
getParent()) {
513 errs() <<
"Predecessor is not in the same region.\n";
518 const auto &PredSuccs = Pred->getSuccessors();
520 errs() <<
"Missing successor link.\n";
524 return !VPBB || verifyVPBasicBlock(VPBB);
527bool VPlanVerifier::verifyBlocksInRegion(
const VPRegionBlock *Region) {
531 errs() <<
"VPBlockBase has wrong parent\n";
535 if (!verifyBlock(VPB))
541bool VPlanVerifier::verifyRegion(
const VPRegionBlock *Region) {
543 const VPBlockBase *Exiting =
Region->getExiting();
546 if (
Entry->hasPredecessors()) {
547 errs() <<
"region entry block has predecessors\n";
551 errs() <<
"region exiting block has successors\n";
555 return verifyBlocksInRegion(Region);
558bool VPlanVerifier::verifyRegionRec(
const VPRegionBlock *Region) {
560 return verifyRegion(Region) &&
562 [
this](
const VPBlockBase *VPB) {
563 const auto *SubRegion = dyn_cast<VPRegionBlock>(VPB);
564 return !SubRegion || verifyRegionRec(SubRegion);
568bool VPlanVerifier::verify(
const VPlan &Plan) {
570 [
this](
const VPBlockBase *VPB) { return !verifyBlock(VPB); }))
578 if (!verifyRegionRec(TopRegion))
582 errs() <<
"VPlan Top Region should have no parent.\n";
588 errs() <<
"VPlan entry block is not a VPBasicBlock\n";
594 errs() <<
"VPlan exiting block is not a VPBasicBlock\n";
598 if (Exiting->
empty()) {
599 errs() <<
"VPlan vector loop exiting block must end with BranchOnCount, "
600 "BranchOnCond, or BranchOnTwoConds VPInstruction but is empty\n";
608 errs() <<
"VPlan vector loop exit must end with BranchOnCount, "
609 "BranchOnCond, or BranchOnTwoConds VPInstruction\n";
619 VPlanVerifier
Verifier(VPDT, TypeInfo);
620 return Verifier.verify(Plan);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static Value * getOpcode(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
verify safepoint Safepoint IR Verifier
This file defines the SmallPtrSet class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
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 isKnownMonotonic(VPValue *V)
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:
@ ICMP_ULT
unsigned less than
@ ICMP_ULE
unsigned less or equal
bool dominates(const DomTreeNodeBase< NodeT > *A, const DomTreeNodeBase< NodeT > *B) const
dominates - Returns true iff A dominates B.
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.
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 isLatch(const VPBlockBase *VPB, const VPDominatorTree &VPDT)
Returns true if VPB is a loop latch, using isHeader().
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
VPRecipeBase is a base class modeling a sequence of one or more output IR instructions.
VPBasicBlock * getParent()
VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks which form a Single-Entry-S...
const VPBlockBase * getEntry() const
const VPBlockBase * getExiting() const
static Type * computeScalarType(const Instruction *I, ArrayRef< VPValue * > Operands)
Compute the scalar result type for a VPReplicateRecipe wrapping I with Operands (excluding any predic...
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
This is the base class of the VPlan Def/Use graph, used for modeling the data flow into,...
VPlan models a candidate for vectorization, encoding various decisions take to produce efficient outp...
VPBasicBlock * getEntry()
bool isUnrolled() const
Returns true if the VPlan already has been unrolled, i.e.
LLVM_ABI_FOR_TEST VPRegionBlock * getVectorLoopRegion()
Returns the VPRegionBlock of the vector loop.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
SpecificConstantMatch m_ZeroInt()
Convenience matchers for specific integer values.
match_combine_or< Ty... > m_CombineOr(const Ty &...Ps)
Combine pattern matchers matching any of Ps patterns.
BinaryOp_match< LHS, RHS, Instruction::Add > m_Add(const LHS &L, const RHS &R)
bool match(Val *V, const Pattern &P)
cst_pred_ty< is_one > m_One()
Match an integer 1 or a vector with all elements equal to 1.
IntrinsicID_match m_Intrinsic()
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
CmpClass_match< LHS, RHS, ICmpInst > m_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
AllRecipe_commutative_match< Instruction::And, Op0_t, Op1_t > m_c_BinaryAnd(const Op0_t &Op0, const Op1_t &Op1)
Match a binary AND operation.
VPInstruction_match< VPInstruction::StepVector > m_StepVector()
VPInstruction_match< VPInstruction::BranchOnTwoConds > m_BranchOnTwoConds()
VPInstruction_match< VPInstruction::BranchOnCount > m_BranchOnCount()
canonical_iv_match m_CanonicalIV()
auto m_VPValue()
Match an arbitrary VPValue and ignore it.
VPInstruction_match< VPInstruction::ExplicitVectorLength, Op0_t > m_EVL(const Op0_t &Op0)
match_bind< VPInstruction > m_VPInstruction(VPInstruction *&V)
Match a VPInstruction, capturing if we match.
auto m_DerivedIV(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2)
VPInstruction_match< VPInstruction::BranchOnCond > m_BranchOnCond()
NodeAddr< PhiNode * > Phi
bool isUniformAcrossVFsAndUFs(const VPValue *V)
Checks if V is uniform across all VF lanes and UF parts.
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.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
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.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI Type * computeScalarTypeForInstruction(unsigned Opcode, ArrayRef< VPValue * > Operands)
Compute the scalar result type for an IR Opcode given Operands.
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.
DWARFExpression::Operation Op
LLVM_ABI Type * getScalarTypeOrInfer(VPValue *V)
Return the scalar type of V.
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.
LLVM_ABI_FOR_TEST bool verifyVPlanIsValid(const VPlan &Plan)
Verify invariants for general VPlans.