22#define DEBUG_TYPE "loop-vectorize"
67bool VPlanVerifier::verifyPhiRecipes(
const VPBasicBlock *VPBB) {
68 auto RecipeI = VPBB->
begin();
70 unsigned NumActiveLaneMaskPhiRecipes = 0;
72 bool IsHeaderVPBB = ParentR && !ParentR->
isReplicator() &&
74 while (RecipeI !=
End && RecipeI->isPhi()) {
75 if (isa<VPActiveLaneMaskPHIRecipe>(RecipeI))
76 NumActiveLaneMaskPhiRecipes++;
78 if (IsHeaderVPBB && !isa<VPHeaderPHIRecipe, VPWidenPHIRecipe>(*RecipeI)) {
79 errs() <<
"Found non-header PHI recipe in header VPBB";
80#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
87 if (!IsHeaderVPBB && isa<VPHeaderPHIRecipe>(*RecipeI)) {
88 errs() <<
"Found header PHI recipe in non-header VPBB";
89#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
99 if (NumActiveLaneMaskPhiRecipes > 1) {
100 errs() <<
"There should be no more than one VPActiveLaneMaskPHIRecipe";
104 while (RecipeI !=
End) {
105 if (RecipeI->isPhi() && !isa<VPBlendRecipe>(&*RecipeI)) {
106 errs() <<
"Found phi-like recipe after non-phi recipe";
108#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
112 std::prev(RecipeI)->dump();
121bool VPlanVerifier::verifyEVLRecipe(
const VPInstruction &EVL)
const {
123 errs() <<
"verifyEVLRecipe should only be called on "
124 "VPInstruction::ExplicitVectorLength\n";
128 const unsigned ExpectedIdx) ->
bool {
130 unsigned UseCount =
count(Ops, &EVL);
131 if (UseCount != 1 || Ops[ExpectedIdx] != &EVL) {
132 errs() <<
"EVL is used as non-last operand in EVL-based recipe\n";
138 return TypeSwitch<const VPUser *, bool>(U)
139 .Case<VPWidenIntrinsicRecipe>([&](const VPWidenIntrinsicRecipe *S) {
140 return VerifyEVLUse(*S, S->getNumOperands() - 1);
143 [&](
const VPRecipeBase *S) {
return VerifyEVLUse(*S, 2); })
144 .Case<VPWidenLoadEVLRecipe, VPReverseVectorPointerRecipe>(
145 [&](
const VPRecipeBase *R) {
return VerifyEVLUse(*R, 1); })
147 return VerifyEVLUse(*W,
150 .Case<VPScalarCastRecipe>(
153 if (
I->getOpcode() != Instruction::Add) {
154 errs() <<
"EVL is used as an operand in non-VPInstruction::Add\n";
157 if (
I->getNumUsers() != 1) {
158 errs() <<
"EVL is used in VPInstruction:Add with multiple "
162 if (!isa<VPEVLBasedIVPHIRecipe>(*
I->users().begin())) {
163 errs() <<
"Result of VPInstruction::Add with EVL operand is "
164 "not used by VPEVLBasedIVPHIRecipe\n";
170 errs() <<
"EVL has unexpected user\n";
176bool VPlanVerifier::verifyVPBasicBlock(
const VPBasicBlock *VPBB) {
177 if (!verifyPhiRecipes(VPBB))
185 RecipeNumbering[&
R] = Cnt++;
188 if (isa<VPIRInstruction>(&R) && !isa<VPIRBasicBlock>(VPBB)) {
189 errs() <<
"VPIRInstructions ";
190#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
194 errs() <<
"not in a VPIRBasicBlock!\n";
197 for (
const VPValue *V :
R.definedValues()) {
198 for (
const VPUser *U :
V->users()) {
199 auto *UI = dyn_cast<VPRecipeBase>(U);
202 isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPredInstPHIRecipe>(UI))
207 if (UI->getParent() == VPBB) {
208 if (RecipeNumbering[UI] < RecipeNumbering[&R]) {
209 errs() <<
"Use before def!\n";
215 if (!VPDT.dominates(VPBB, UI->getParent())) {
216 errs() <<
"Use before def!\n";
221 if (
const auto *EVL = dyn_cast<VPInstruction>(&R)) {
223 !verifyEVLRecipe(*EVL)) {
224 errs() <<
"EVL VPValue is not used correctly\n";
230 auto *IRBB = dyn_cast<VPIRBasicBlock>(VPBB);
234 if (!WrappedIRBBs.insert(IRBB->getIRBasicBlock()).second) {
235 errs() <<
"Same IR basic block used by multiple wrapper blocks!\n";
246 for (
const auto *
Block : VPBlockVec) {
253bool VPlanVerifier::verifyBlock(
const VPBlockBase *VPB) {
254 auto *VPBB = dyn_cast<VPBasicBlock>(VPB);
257 (VPBB && VPBB->getParent() && VPBB->isExiting() &&
258 !VPBB->getParent()->isReplicator())) {
259 if (!VPBB || !VPBB->getTerminator()) {
260 errs() <<
"Block has multiple successors but doesn't "
261 "have a proper branch recipe!\n";
265 if (VPBB && VPBB->getTerminator()) {
266 errs() <<
"Unexpected branch recipe!\n";
276 errs() <<
"Multiple instances of the same successor.\n";
282 const auto &SuccPreds = Succ->getPredecessors();
284 errs() <<
"Missing predecessor link.\n";
295 errs() <<
"Multiple instances of the same predecessor.\n";
301 if (Pred->getParent() != VPB->
getParent()) {
302 errs() <<
"Predecessor is not in the same region.\n";
307 const auto &PredSuccs = Pred->getSuccessors();
309 errs() <<
"Missing successor link.\n";
313 return !VPBB || verifyVPBasicBlock(VPBB);
320 errs() <<
"VPBlockBase has wrong parent\n";
324 if (!verifyBlock(VPB))
335 if (
Entry->getNumPredecessors() != 0) {
336 errs() <<
"region entry block has predecessors\n";
340 errs() <<
"region exiting block has successors\n";
344 return verifyBlocksInRegion(
Region);
349 return verifyRegion(
Region) &&
352 const auto *SubRegion = dyn_cast<VPRegionBlock>(VPB);
353 return !SubRegion || verifyRegionRec(SubRegion);
357bool VPlanVerifier::verify(
const VPlan &Plan) {
359 [
this](
const VPBlockBase *VPB) { return !verifyBlock(VPB); }))
363 if (!verifyRegionRec(TopRegion))
367 errs() <<
"VPlan Top Region should have no parent.\n";
373 errs() <<
"VPlan entry block is not a VPBasicBlock\n";
377 if (!isa<VPCanonicalIVPHIRecipe>(&*
Entry->begin())) {
378 errs() <<
"VPlan vector loop header does not start with a "
379 "VPCanonicalIVPHIRecipe\n";
385 errs() <<
"VPlan exiting block is not a VPBasicBlock\n";
389 if (Exiting->
empty()) {
390 errs() <<
"VPlan vector loop exiting block must end with BranchOnCount or "
391 "BranchOnCond VPInstruction but is empty\n";
395 auto *LastInst = dyn_cast<VPInstruction>(std::prev(Exiting->
end()));
398 errs() <<
"VPlan vector loop exit must end with BranchOnCount or "
399 "BranchOnCond VPInstruction\n";
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.
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,...