22#define DEBUG_TYPE "loop-vectorize"
63 : VPDT(VPDT), TypeInfo(TypeInfo) {}
69bool VPlanVerifier::verifyPhiRecipes(
const VPBasicBlock *VPBB) {
70 auto RecipeI = VPBB->
begin();
72 unsigned NumActiveLaneMaskPhiRecipes = 0;
74 bool IsHeaderVPBB = ParentR && !ParentR->
isReplicator() &&
76 while (RecipeI !=
End && RecipeI->isPhi()) {
77 if (isa<VPActiveLaneMaskPHIRecipe>(RecipeI))
78 NumActiveLaneMaskPhiRecipes++;
80 if (IsHeaderVPBB && !isa<VPHeaderPHIRecipe, VPWidenPHIRecipe>(*RecipeI)) {
81 errs() <<
"Found non-header PHI recipe in header VPBB";
82#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
89 if (!IsHeaderVPBB && isa<VPHeaderPHIRecipe>(*RecipeI)) {
90 errs() <<
"Found header PHI recipe in non-header VPBB";
91#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
101 if (NumActiveLaneMaskPhiRecipes > 1) {
102 errs() <<
"There should be no more than one VPActiveLaneMaskPHIRecipe";
106 while (RecipeI !=
End) {
107 if (RecipeI->isPhi() && !isa<VPBlendRecipe>(&*RecipeI)) {
108 errs() <<
"Found phi-like recipe after non-phi recipe";
110#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
114 std::prev(RecipeI)->dump();
123bool VPlanVerifier::verifyEVLRecipe(
const VPInstruction &EVL)
const {
125 errs() <<
"verifyEVLRecipe should only be called on "
126 "VPInstruction::ExplicitVectorLength\n";
130 const unsigned ExpectedIdx) ->
bool {
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";
140 return TypeSwitch<const VPUser *, bool>(U)
141 .Case<VPWidenIntrinsicRecipe>([&](const VPWidenIntrinsicRecipe *S) {
142 return VerifyEVLUse(*S, S->getNumOperands() - 1);
145 [&](
const VPRecipeBase *S) {
return VerifyEVLUse(*S, 2); })
146 .Case<VPWidenLoadEVLRecipe, VPReverseVectorPointerRecipe>(
147 [&](
const VPRecipeBase *R) {
return VerifyEVLUse(*R, 1); })
149 return VerifyEVLUse(*W,
152 .Case<VPScalarCastRecipe>(
155 if (
I->getOpcode() != Instruction::Add) {
156 errs() <<
"EVL is used as an operand in non-VPInstruction::Add\n";
159 if (
I->getNumUsers() != 1) {
160 errs() <<
"EVL is used in VPInstruction:Add with multiple "
164 if (!isa<VPEVLBasedIVPHIRecipe>(*
I->users().begin())) {
165 errs() <<
"Result of VPInstruction::Add with EVL operand is "
166 "not used by VPEVLBasedIVPHIRecipe\n";
172 errs() <<
"EVL has unexpected user\n";
178bool VPlanVerifier::verifyVPBasicBlock(
const VPBasicBlock *VPBB) {
179 if (!verifyPhiRecipes(VPBB))
187 RecipeNumbering[&
R] = Cnt++;
190 if (isa<VPIRInstruction>(&R) && !isa<VPIRBasicBlock>(VPBB)) {
191 errs() <<
"VPIRInstructions ";
192#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
196 errs() <<
"not in a VPIRBasicBlock!\n";
199 for (
const VPValue *V :
R.definedValues()) {
203 if (!TypeInfo.inferScalarType(V)) {
204 errs() <<
"Failed to infer scalar type!\n";
208 for (
const VPUser *U :
V->users()) {
209 auto *UI = dyn_cast<VPRecipeBase>(U);
212 isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPredInstPHIRecipe>(UI))
217 if (UI->getParent() == VPBB) {
218 if (RecipeNumbering[UI] < RecipeNumbering[&R]) {
219 errs() <<
"Use before def!\n";
225 if (!VPDT.dominates(VPBB, UI->getParent())) {
226 errs() <<
"Use before def!\n";
231 if (
const auto *EVL = dyn_cast<VPInstruction>(&R)) {
233 !verifyEVLRecipe(*EVL)) {
234 errs() <<
"EVL VPValue is not used correctly\n";
240 auto *IRBB = dyn_cast<VPIRBasicBlock>(VPBB);
244 if (!WrappedIRBBs.insert(IRBB->getIRBasicBlock()).second) {
245 errs() <<
"Same IR basic block used by multiple wrapper blocks!\n";
256 for (
const auto *
Block : VPBlockVec) {
263bool VPlanVerifier::verifyBlock(
const VPBlockBase *VPB) {
264 auto *VPBB = dyn_cast<VPBasicBlock>(VPB);
267 (VPBB && VPBB->getParent() && VPBB->isExiting() &&
268 !VPBB->getParent()->isReplicator())) {
269 if (!VPBB || !VPBB->getTerminator()) {
270 errs() <<
"Block has multiple successors but doesn't "
271 "have a proper branch recipe!\n";
275 if (VPBB && VPBB->getTerminator()) {
276 errs() <<
"Unexpected branch recipe!\n";
286 errs() <<
"Multiple instances of the same successor.\n";
292 const auto &SuccPreds = Succ->getPredecessors();
294 errs() <<
"Missing predecessor link.\n";
305 errs() <<
"Multiple instances of the same predecessor.\n";
311 if (Pred->getParent() != VPB->
getParent()) {
312 errs() <<
"Predecessor is not in the same region.\n";
317 const auto &PredSuccs = Pred->getSuccessors();
319 errs() <<
"Missing successor link.\n";
323 return !VPBB || verifyVPBasicBlock(VPBB);
330 errs() <<
"VPBlockBase has wrong parent\n";
334 if (!verifyBlock(VPB))
345 if (
Entry->getNumPredecessors() != 0) {
346 errs() <<
"region entry block has predecessors\n";
350 errs() <<
"region exiting block has successors\n";
354 return verifyBlocksInRegion(
Region);
359 return verifyRegion(
Region) &&
362 const auto *SubRegion = dyn_cast<VPRegionBlock>(VPB);
363 return !SubRegion || verifyRegionRec(SubRegion);
367bool VPlanVerifier::verify(
const VPlan &Plan) {
369 [
this](
const VPBlockBase *VPB) { return !verifyBlock(VPB); }))
373 if (!verifyRegionRec(TopRegion))
377 errs() <<
"VPlan Top Region should have no parent.\n";
383 errs() <<
"VPlan entry block is not a VPBasicBlock\n";
387 if (!isa<VPCanonicalIVPHIRecipe>(&*
Entry->begin())) {
388 errs() <<
"VPlan vector loop header does not start with a "
389 "VPCanonicalIVPHIRecipe\n";
395 errs() <<
"VPlan exiting block is not a VPBasicBlock\n";
399 if (Exiting->
empty()) {
400 errs() <<
"VPlan vector loop exiting block must end with BranchOnCount or "
401 "BranchOnCond VPInstruction but is empty\n";
405 auto *LastInst = dyn_cast<VPInstruction>(std::prev(Exiting->
end()));
408 errs() <<
"VPlan vector loop exit must end with BranchOnCount or "
409 "BranchOnCond VPInstruction\n";
420 const_cast<VPlan &
>(Plan).getCanonicalIV()->getScalarType());
421 VPlanVerifier
Verifier(VPDT, TypeInfo);
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.
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
const VPBlocksTy & getPredecessors() const
const VPBasicBlock * getEntryBasicBlock() const
const VPBlocksTy & getSuccessors() const
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.
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
bool isReplicator() const
An indicator whether this region is to generate multiple replicated instances of output IR correspond...
const VPBlockBase * getExiting() const
VPScalarCastRecipe is a recipe to create scalar cast instructions.
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 widening operations with vector-predication intrinsics with explicit vector length (EVL)...
VPlan models a candidate for vectorization, encoding various decisions take to produce efficient outp...
VPBasicBlock * getEntry()
VPRegionBlock * getVectorLoopRegion()
Returns the VPRegionBlock of the vector loop.
std::pair< iterator, bool > insert(const ValueT &V)
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.
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.
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.
bool verifyVPlanIsValid(const VPlan &Plan)
Verify invariants for general VPlans.
A recipe for widening store operations with vector-predication intrinsics, using the value to store,...