LLVM 22.0.0git
VPlanVerifier.cpp
Go to the documentation of this file.
1//===-- VPlanVerifier.cpp -------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This file defines the class VPlanVerifier, which contains utility functions
11/// to check the consistency and invariants of a VPlan.
12///
13//===----------------------------------------------------------------------===//
14
15#include "VPlanVerifier.h"
16#include "VPlan.h"
17#include "VPlanCFG.h"
18#include "VPlanDominatorTree.h"
19#include "VPlanHelpers.h"
20#include "VPlanPatternMatch.h"
22#include "llvm/ADT/TypeSwitch.h"
23
24#define DEBUG_TYPE "loop-vectorize"
25
26using namespace llvm;
27
28namespace {
29class VPlanVerifier {
30 const VPDominatorTree &VPDT;
31 VPTypeAnalysis &TypeInfo;
32 bool VerifyLate;
33
35
36 // Verify that phi-like recipes are at the beginning of \p VPBB, with no
37 // other recipes in between. Also check that only header blocks contain
38 // VPHeaderPHIRecipes.
39 bool verifyPhiRecipes(const VPBasicBlock *VPBB);
40
41 /// Verify that \p EVL is used correctly. The user must be either in
42 /// EVL-based recipes as a last operand or VPInstruction::Add which is
43 /// incoming value into EVL's recipe.
44 bool verifyEVLRecipe(const VPInstruction &EVL) const;
45
46 bool verifyVPBasicBlock(const VPBasicBlock *VPBB);
47
48 bool verifyBlock(const VPBlockBase *VPB);
49
50 /// Helper function that verifies the CFG invariants of the VPBlockBases
51 /// within
52 /// \p Region. Checks in this function are generic for VPBlockBases. They are
53 /// not specific for VPBasicBlocks or VPRegionBlocks.
54 bool verifyBlocksInRegion(const VPRegionBlock *Region);
55
56 /// Verify the CFG invariants of VPRegionBlock \p Region and its nested
57 /// VPBlockBases. Do not recurse inside nested VPRegionBlocks.
58 bool verifyRegion(const VPRegionBlock *Region);
59
60 /// Verify the CFG invariants of VPRegionBlock \p Region and its nested
61 /// VPBlockBases. Recurse inside nested VPRegionBlocks.
62 bool verifyRegionRec(const VPRegionBlock *Region);
63
64public:
65 VPlanVerifier(VPDominatorTree &VPDT, VPTypeAnalysis &TypeInfo,
66 bool VerifyLate)
67 : VPDT(VPDT), TypeInfo(TypeInfo), VerifyLate(VerifyLate) {}
68
69 bool verify(const VPlan &Plan);
70};
71} // namespace
72
73bool VPlanVerifier::verifyPhiRecipes(const VPBasicBlock *VPBB) {
74 auto RecipeI = VPBB->begin();
75 auto End = VPBB->end();
76 unsigned NumActiveLaneMaskPhiRecipes = 0;
77 bool IsHeaderVPBB = VPBlockUtils::isHeader(VPBB, VPDT);
78 while (RecipeI != End && RecipeI->isPhi()) {
79 if (isa<VPActiveLaneMaskPHIRecipe>(RecipeI))
80 NumActiveLaneMaskPhiRecipes++;
81
82 if (IsHeaderVPBB &&
83 !isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPhi>(*RecipeI)) {
84 errs() << "Found non-header PHI recipe in header VPBB";
85#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
86 errs() << ": ";
87 RecipeI->dump();
88#endif
89 return false;
90 }
91
92 if (!IsHeaderVPBB && isa<VPHeaderPHIRecipe>(*RecipeI)) {
93 errs() << "Found header PHI recipe in non-header VPBB";
94#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
95 errs() << ": ";
96 RecipeI->dump();
97#endif
98 return false;
99 }
100
101 // Check if the recipe operands match the number of predecessors.
102 // TODO Extend to other phi-like recipes.
103 if (auto *PhiIRI = dyn_cast<VPIRPhi>(&*RecipeI)) {
104 if (PhiIRI->getNumOperands() != VPBB->getNumPredecessors()) {
105 errs() << "Phi-like recipe with different number of operands and "
106 "predecessors.\n";
107 // TODO: Print broken recipe. At the moment printing an ill-formed
108 // phi-like recipe may crash.
109 return false;
110 }
111 }
112
113 RecipeI++;
114 }
115
116 if (!VerifyLate && NumActiveLaneMaskPhiRecipes > 1) {
117 errs() << "There should be no more than one VPActiveLaneMaskPHIRecipe";
118 return false;
119 }
120
121 while (RecipeI != End) {
122 if (RecipeI->isPhi() && !isa<VPBlendRecipe>(&*RecipeI)) {
123 errs() << "Found phi-like recipe after non-phi recipe";
124
125#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
126 errs() << ": ";
127 RecipeI->dump();
128 errs() << "after\n";
129 std::prev(RecipeI)->dump();
130#endif
131 return false;
132 }
133 RecipeI++;
134 }
135 return true;
136}
137
138bool VPlanVerifier::verifyEVLRecipe(const VPInstruction &EVL) const {
140 errs() << "verifyEVLRecipe should only be called on "
141 "VPInstruction::ExplicitVectorLength\n";
142 return false;
143 }
144 auto VerifyEVLUse = [&](const VPRecipeBase &R,
145 const unsigned ExpectedIdx) -> bool {
146 SmallVector<const VPValue *> Ops(R.operands());
147 unsigned UseCount = count(Ops, &EVL);
148 if (UseCount != 1 || Ops[ExpectedIdx] != &EVL) {
149 errs() << "EVL is used as non-last operand in EVL-based recipe\n";
150 return false;
151 }
152 return true;
153 };
154 return all_of(EVL.users(), [this, &VerifyEVLUse](VPUser *U) {
155 return TypeSwitch<const VPUser *, bool>(U)
156 .Case<VPWidenIntrinsicRecipe>([&](const VPWidenIntrinsicRecipe *S) {
157 return VerifyEVLUse(*S, S->getNumOperands() - 1);
158 })
161 [&](const VPRecipeBase *S) { return VerifyEVLUse(*S, 2); })
162 .Case<VPScalarIVStepsRecipe>([&](auto *R) {
163 if (R->getNumOperands() != 3) {
164 errs() << "Unrolling with EVL tail folding not yet supported\n";
165 return false;
166 }
167 return VerifyEVLUse(*R, 2);
168 })
169 .Case<VPWidenLoadEVLRecipe, VPVectorEndPointerRecipe>(
170 [&](const VPRecipeBase *R) { return VerifyEVLUse(*R, 1); })
171 .Case<VPInstructionWithType>(
172 [&](const VPInstructionWithType *S) { return VerifyEVLUse(*S, 0); })
173 .Case<VPInstruction>([&](const VPInstruction *I) {
174 if (I->getOpcode() == Instruction::PHI ||
175 I->getOpcode() == Instruction::ICmp ||
176 I->getOpcode() == Instruction::Sub)
177 return VerifyEVLUse(*I, 1);
178 switch (I->getOpcode()) {
179 case Instruction::Add:
180 break;
181 case Instruction::UIToFP:
182 case Instruction::Trunc:
183 case Instruction::ZExt:
184 case Instruction::Mul:
185 case Instruction::FMul:
187 // Opcodes above can only use EVL after wide inductions have been
188 // expanded.
189 if (!VerifyLate) {
190 errs() << "EVL used by unexpected VPInstruction\n";
191 return false;
192 }
193 break;
194 default:
195 errs() << "EVL used by unexpected VPInstruction\n";
196 return false;
197 }
198 // EVLIVIncrement is only used by EVLIV & BranchOnCount.
199 // Having more than two users is unexpected.
200 if ((I->getNumUsers() != 1) &&
201 (I->getNumUsers() != 2 || none_of(I->users(), [&I](VPUser *U) {
202 using namespace llvm::VPlanPatternMatch;
203 return match(U, m_BranchOnCount(m_Specific(I), m_VPValue()));
204 }))) {
205 errs() << "EVL is used in VPInstruction with multiple users\n";
206 return false;
207 }
208 if (!VerifyLate && !isa<VPEVLBasedIVPHIRecipe>(*I->users().begin())) {
209 errs() << "Result of VPInstruction::Add with EVL operand is "
210 "not used by VPEVLBasedIVPHIRecipe\n";
211 return false;
212 }
213 return true;
214 })
215 .Default([&](const VPUser *U) {
216 errs() << "EVL has unexpected user\n";
217 return false;
218 });
219 });
220}
221
222bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
223 if (!verifyPhiRecipes(VPBB))
224 return false;
225
226 // Verify that defs in VPBB dominate all their uses.
228 unsigned Cnt = 0;
229 for (const VPRecipeBase &R : *VPBB)
230 RecipeNumbering[&R] = Cnt++;
231
232 for (const VPRecipeBase &R : *VPBB) {
233 if (isa<VPIRInstruction>(&R) && !isa<VPIRBasicBlock>(VPBB)) {
234 errs() << "VPIRInstructions ";
235#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
236 R.dump();
237 errs() << " ";
238#endif
239 errs() << "not in a VPIRBasicBlock!\n";
240 return false;
241 }
242 for (const VPValue *V : R.definedValues()) {
243 // Verify that we can infer a scalar type for each defined value. With
244 // assertions enabled, inferScalarType will perform some consistency
245 // checks during type inference.
246 if (!TypeInfo.inferScalarType(V)) {
247 errs() << "Failed to infer scalar type!\n";
248 return false;
249 }
250
251 for (const VPUser *U : V->users()) {
252 auto *UI = cast<VPRecipeBase>(U);
253 if (auto *Phi = dyn_cast<VPPhiAccessors>(UI)) {
254 for (const auto &[IncomingVPV, IncomingVPBB] :
255 Phi->incoming_values_and_blocks()) {
256 if (IncomingVPV != V)
257 continue;
258
259 if (VPDT.dominates(VPBB, IncomingVPBB))
260 continue;
261
262 errs() << "Incoming def does not dominate incoming block!\n";
263#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
264 VPSlotTracker Tracker(VPBB->getPlan());
265 IncomingVPV->getDefiningRecipe()->print(errs(), " ", Tracker);
266 errs() << "\n does not dominate " << IncomingVPBB->getName()
267 << " for\n";
268 UI->print(errs(), " ", Tracker);
269#endif
270 return false;
271 }
272 continue;
273 }
274 // TODO: Also verify VPPredInstPHIRecipe.
275 if (isa<VPPredInstPHIRecipe>(UI))
276 continue;
277
278 // If the user is in the same block, check it comes after R in the
279 // block.
280 if (UI->getParent() == VPBB) {
281 if (RecipeNumbering[UI] >= RecipeNumbering[&R])
282 continue;
283 } else {
284 if (VPDT.dominates(VPBB, UI->getParent()))
285 continue;
286 }
287
288 errs() << "Use before def!\n";
289#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
290 VPSlotTracker Tracker(VPBB->getPlan());
291 UI->print(errs(), " ", Tracker);
292 errs() << "\n before\n";
293 R.print(errs(), " ", Tracker);
294 errs() << "\n";
295#endif
296 return false;
297 }
298 }
299 if (const auto *EVL = dyn_cast<VPInstruction>(&R)) {
301 !verifyEVLRecipe(*EVL)) {
302 errs() << "EVL VPValue is not used correctly\n";
303 return false;
304 }
305 }
306 }
307
308 auto *IRBB = dyn_cast<VPIRBasicBlock>(VPBB);
309 if (!IRBB)
310 return true;
311
312 if (!WrappedIRBBs.insert(IRBB->getIRBasicBlock()).second) {
313 errs() << "Same IR basic block used by multiple wrapper blocks!\n";
314 return false;
315 }
316
317 return true;
318}
319
320/// Utility function that checks whether \p VPBlockVec has duplicate
321/// VPBlockBases.
322static bool hasDuplicates(const SmallVectorImpl<VPBlockBase *> &VPBlockVec) {
324 for (const auto *Block : VPBlockVec) {
325 if (!VPBlockSet.insert(Block).second)
326 return true;
327 }
328 return false;
329}
330
331bool VPlanVerifier::verifyBlock(const VPBlockBase *VPB) {
332 auto *VPBB = dyn_cast<VPBasicBlock>(VPB);
333 // Check block's condition bit.
334 if (!isa<VPIRBasicBlock>(VPB)) {
335 if (VPB->getNumSuccessors() > 1 ||
336 (VPBB && VPBB->getParent() && VPBB->isExiting() &&
337 !VPBB->getParent()->isReplicator())) {
338 if (!VPBB || !VPBB->getTerminator()) {
339 errs() << "Block has multiple successors but doesn't "
340 "have a proper branch recipe!\n";
341 return false;
342 }
343 } else {
344 if (VPBB && VPBB->getTerminator()) {
345 errs() << "Unexpected branch recipe!\n";
346 return false;
347 }
348 }
349 }
350
351 // Check block's successors.
352 const auto &Successors = VPB->getSuccessors();
353 // There must be only one instance of a successor in block's successor list.
354 // TODO: This won't work for switch statements.
355 if (hasDuplicates(Successors)) {
356 errs() << "Multiple instances of the same successor.\n";
357 return false;
358 }
359
360 for (const VPBlockBase *Succ : Successors) {
361 // There must be a bi-directional link between block and successor.
362 const auto &SuccPreds = Succ->getPredecessors();
363 if (!is_contained(SuccPreds, VPB)) {
364 errs() << "Missing predecessor link.\n";
365 return false;
366 }
367 }
368
369 // Check block's predecessors.
370 const auto &Predecessors = VPB->getPredecessors();
371 // There must be only one instance of a predecessor in block's predecessor
372 // list.
373 // TODO: This won't work for switch statements.
374 if (hasDuplicates(Predecessors)) {
375 errs() << "Multiple instances of the same predecessor.\n";
376 return false;
377 }
378
379 for (const VPBlockBase *Pred : Predecessors) {
380 // Block and predecessor must be inside the same region.
381 if (Pred->getParent() != VPB->getParent()) {
382 errs() << "Predecessor is not in the same region.\n";
383 return false;
384 }
385
386 // There must be a bi-directional link between block and predecessor.
387 const auto &PredSuccs = Pred->getSuccessors();
388 if (!is_contained(PredSuccs, VPB)) {
389 errs() << "Missing successor link.\n";
390 return false;
391 }
392 }
393 return !VPBB || verifyVPBasicBlock(VPBB);
394}
395
396bool VPlanVerifier::verifyBlocksInRegion(const VPRegionBlock *Region) {
397 for (const VPBlockBase *VPB : vp_depth_first_shallow(Region->getEntry())) {
398 // Check block's parent.
399 if (VPB->getParent() != Region) {
400 errs() << "VPBlockBase has wrong parent\n";
401 return false;
402 }
403
404 if (!verifyBlock(VPB))
405 return false;
406 }
407 return true;
408}
409
410bool VPlanVerifier::verifyRegion(const VPRegionBlock *Region) {
411 const VPBlockBase *Entry = Region->getEntry();
412 const VPBlockBase *Exiting = Region->getExiting();
413
414 // Entry and Exiting shouldn't have any predecessor/successor, respectively.
415 if (Entry->getNumPredecessors() != 0) {
416 errs() << "region entry block has predecessors\n";
417 return false;
418 }
419 if (Exiting->getNumSuccessors() != 0) {
420 errs() << "region exiting block has successors\n";
421 return false;
422 }
423
424 return verifyBlocksInRegion(Region);
425}
426
427bool VPlanVerifier::verifyRegionRec(const VPRegionBlock *Region) {
428 // Recurse inside nested regions and check all blocks inside the region.
429 return verifyRegion(Region) &&
431 [this](const VPBlockBase *VPB) {
432 const auto *SubRegion = dyn_cast<VPRegionBlock>(VPB);
433 return !SubRegion || verifyRegionRec(SubRegion);
434 });
435}
436
437bool VPlanVerifier::verify(const VPlan &Plan) {
439 [this](const VPBlockBase *VPB) { return !verifyBlock(VPB); }))
440 return false;
441
442 const VPRegionBlock *TopRegion = Plan.getVectorLoopRegion();
443 // TODO: Verify all blocks using vp_depth_first_deep iterators.
444 if (!TopRegion)
445 return true;
446
447 if (!verifyRegionRec(TopRegion))
448 return false;
449
450 if (TopRegion->getParent()) {
451 errs() << "VPlan Top Region should have no parent.\n";
452 return false;
453 }
454
455 const VPBasicBlock *Entry = dyn_cast<VPBasicBlock>(TopRegion->getEntry());
456 if (!Entry) {
457 errs() << "VPlan entry block is not a VPBasicBlock\n";
458 return false;
459 }
460
461 if (!isa<VPCanonicalIVPHIRecipe>(&*Entry->begin())) {
462 errs() << "VPlan vector loop header does not start with a "
463 "VPCanonicalIVPHIRecipe\n";
464 return false;
465 }
466
467 const VPBasicBlock *Exiting = dyn_cast<VPBasicBlock>(TopRegion->getExiting());
468 if (!Exiting) {
469 errs() << "VPlan exiting block is not a VPBasicBlock\n";
470 return false;
471 }
472
473 if (Exiting->empty()) {
474 errs() << "VPlan vector loop exiting block must end with BranchOnCount or "
475 "BranchOnCond VPInstruction but is empty\n";
476 return false;
477 }
478
479 auto *LastInst = dyn_cast<VPInstruction>(std::prev(Exiting->end()));
480 if (!LastInst || (LastInst->getOpcode() != VPInstruction::BranchOnCount &&
481 LastInst->getOpcode() != VPInstruction::BranchOnCond)) {
482 errs() << "VPlan vector loop exit must end with BranchOnCount or "
483 "BranchOnCond VPInstruction\n";
484 return false;
485 }
486
487 return true;
488}
489
490bool llvm::verifyVPlanIsValid(const VPlan &Plan, bool VerifyLate) {
491 VPDominatorTree VPDT;
492 VPDT.recalculate(const_cast<VPlan &>(Plan));
493 VPTypeAnalysis TypeInfo(Plan);
494 VPlanVerifier Verifier(VPDT, TypeInfo, VerifyLate);
495 return Verifier.verify(Plan);
496}
@ Default
Definition: DwarfDebug.cpp:86
bool End
Definition: ELF_riscv.cpp:480
#define I(x, y, z)
Definition: MD5.cpp:58
ppc ctr loops verify
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:
void recalculate(ParentType &Func)
recalculate - compute a dominator tree for the given function
BlockT * getEntry() const
Get the entry BasicBlock of the Region.
Definition: RegionInfo.h:320
Implements a dense probed hash-table based set with some number of buckets stored inline.
Definition: DenseSet.h:283
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:541
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:574
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph.
Definition: VPlan.h:3639
iterator end()
Definition: VPlan.h:3676
iterator begin()
Recipe iterator methods.
Definition: VPlan.h:3674
bool empty() const
Definition: VPlan.h:3685
VPBlockBase is the building block of the Hierarchical Control-Flow Graph.
Definition: VPlan.h:81
VPRegionBlock * getParent()
Definition: VPlan.h:173
size_t getNumSuccessors() const
Definition: VPlan.h:219
size_t getNumPredecessors() const
Definition: VPlan.h:220
const VPBlocksTy & getPredecessors() const
Definition: VPlan.h:204
const VPBlocksTy & getSuccessors() const
Definition: VPlan.h:198
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.
Definition: VPlan.cpp:210
Template specialization of the standard LLVM dominator tree utility for VPBlockBases.
A specialization of VPInstruction augmenting it with a dedicated result type, to be used when the opc...
Definition: VPlan.h:1172
This is a concrete Recipe that models a single VPlan-level instruction.
Definition: VPlan.h:967
unsigned getOpcode() const
Definition: VPlan.h:1104
VPRecipeBase is a base class modeling a sequence of one or more output IR instructions.
Definition: VPlan.h:391
A recipe to represent inloop reduction operations with vector-predication intrinsics,...
Definition: VPlan.h:2687
VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks which form a Single-Entry-S...
Definition: VPlan.h:3827
const VPBlockBase * getEntry() const
Definition: VPlan.h:3863
const VPBlockBase * getExiting() const
Definition: VPlan.h:3875
This class can be used to assign names to VPValues.
Definition: VPlanHelpers.h:382
An analysis for type-inference for VPValues.
Definition: VPlanAnalysis.h:43
This class augments VPValue with operands which provide the inverse def-use edges from VPValue's user...
Definition: VPlanValue.h:197
user_range users()
Definition: VPlanValue.h:134
A recipe for handling phi nodes of integer and floating-point inductions, producing their vector valu...
Definition: VPlan.h:2088
VPlan models a candidate for vectorization, encoding various decisions take to produce efficient outp...
Definition: VPlan.h:3930
VPBasicBlock * getEntry()
Definition: VPlan.h:4029
LLVM_ABI_FOR_TEST VPRegionBlock * getVectorLoopRegion()
Returns the VPRegionBlock of the vector loop.
Definition: VPlan.cpp:1037
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:194
@ Entry
Definition: COFF.h:862
NodeAddr< PhiNode * > Phi
Definition: RDFGraph.h:390
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1744
LLVM_ABI_FOR_TEST bool verifyVPlanIsValid(const VPlan &Plan, bool VerifyLate=false)
Verify invariants for general VPlans.
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.
Definition: VPlanCFG.h:216
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1751
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1758
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...
Definition: STLExtras.h:1973
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition: STLExtras.h:1916
A recipe for widening store operations with vector-predication intrinsics, using the value to store,...
Definition: VPlan.h:3212