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"
21#include "VPlanUtils.h"
22#include "llvm/ADT/SmallPtrSet.h"
23
24#define DEBUG_TYPE "loop-vectorize"
25
26using namespace llvm;
27using namespace VPlanPatternMatch;
28
29namespace {
30class VPlanVerifier {
31 const VPDominatorTree &VPDT;
32
33 SmallPtrSet<BasicBlock *, 8> WrappedIRBBs;
34
35 // Verify that phi-like recipes are at the beginning of \p VPBB, with no
36 // other recipes in between. Also check that only header blocks contain
37 // VPHeaderPHIRecipes.
38 bool verifyPhiRecipes(const VPBasicBlock *VPBB);
39
40 /// Verify that \p LastActiveLane's operand is guaranteed to be a prefix-mask.
41 bool verifyLastActiveLaneRecipe(const VPInstruction &LastActiveLane) const;
42
43 bool verifyVPBasicBlock(const VPBasicBlock *VPBB);
44
45 bool verifyBlock(const VPBlockBase *VPB);
46
47 /// Helper function that verifies the CFG invariants of the VPBlockBases
48 /// within
49 /// \p Region. Checks in this function are generic for VPBlockBases. They are
50 /// not specific for VPBasicBlocks or VPRegionBlocks.
51 bool verifyBlocksInRegion(const VPRegionBlock *Region);
52
53 /// Verify the CFG invariants of VPRegionBlock \p Region and its nested
54 /// VPBlockBases. Do not recurse inside nested VPRegionBlocks.
55 bool verifyRegion(const VPRegionBlock *Region);
56
57 /// Verify the CFG invariants of VPRegionBlock \p Region and its nested
58 /// VPBlockBases. Recurse inside nested VPRegionBlocks.
59 bool verifyRegionRec(const VPRegionBlock *Region);
60
61public:
62 VPlanVerifier(VPDominatorTree &VPDT) : VPDT(VPDT) {}
63
64 bool verify(const VPlan &Plan);
65};
66} // namespace
67
68bool VPlanVerifier::verifyPhiRecipes(const VPBasicBlock *VPBB) {
69 auto RecipeI = VPBB->begin();
70 auto End = VPBB->end();
71 unsigned NumActiveLaneMaskPhiRecipes = 0;
72 bool IsHeaderVPBB = VPBlockUtils::isHeader(VPB: VPBB, VPDT);
73 while (RecipeI != End && RecipeI->isPhi()) {
74 if (isa<VPActiveLaneMaskPHIRecipe>(Val: RecipeI))
75 NumActiveLaneMaskPhiRecipes++;
76
77 if (IsHeaderVPBB &&
78 !isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPhi>(Val: *RecipeI)) {
79 errs() << "Found non-header PHI recipe in header VPBB";
80#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
81 errs() << ": ";
82 RecipeI->dump();
83#endif
84 return false;
85 }
86
87 if (!IsHeaderVPBB && isa<VPHeaderPHIRecipe>(Val: *RecipeI)) {
88 errs() << "Found header PHI recipe in non-header VPBB";
89#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
90 errs() << ": ";
91 RecipeI->dump();
92#endif
93 return false;
94 }
95
96 // In region form, VPCurrentIterationPHIRecipe must be the first header phi
97 // recipe. In a plain CFG VPlan, it must either be the first or second.
98 if (isa<VPCurrentIterationPHIRecipe>(Val: RecipeI) &&
99 (VPBB->getPlan()->getVectorLoopRegion()
100 ? RecipeI->getIterator() != VPBB->begin()
101 : RecipeI->getIterator() != VPBB->begin() &&
102 RecipeI->getIterator() != std::next(x: VPBB->begin()))) {
103 errs() << "CurrentIteration PHI is not the first/second recipe\n";
104 return false;
105 }
106
107 // Check if the recipe operands match the number of predecessors.
108 // TODO Extend to other phi-like recipes.
109 if (auto *PhiIRI = dyn_cast<VPIRPhi>(Val: &*RecipeI)) {
110 if (PhiIRI->getNumOperands() != VPBB->getNumPredecessors()) {
111 errs() << "Phi-like recipe with different number of operands and "
112 "predecessors.\n";
113 // TODO: Print broken recipe. At the moment printing an ill-formed
114 // phi-like recipe may crash.
115 return false;
116 }
117 }
118
119 RecipeI++;
120 }
121
122 if (!VPBB->getPlan()->isUnrolled() && NumActiveLaneMaskPhiRecipes > 1) {
123 errs() << "There should be no more than one VPActiveLaneMaskPHIRecipe";
124 return false;
125 }
126
127 while (RecipeI != End) {
128 if (RecipeI->isPhi() && !isa<VPBlendRecipe>(Val: &*RecipeI)) {
129 errs() << "Found phi-like recipe after non-phi recipe";
130
131#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
132 errs() << ": ";
133 RecipeI->dump();
134 errs() << "after\n";
135 std::prev(RecipeI)->dump();
136#endif
137 return false;
138 }
139 RecipeI++;
140 }
141 return true;
142}
143
144static bool isKnownMonotonic(VPValue *V) {
145 VPValue *X, *Y;
146 if (match(V, P: m_Add(Op0: m_VPValue(V&: X), Op1: m_VPValue(V&: Y))))
147 return cast<VPRecipeWithIRFlags>(Val: V)->hasNoUnsignedWrap() &&
148 isKnownMonotonic(V: X) && isKnownMonotonic(V: Y);
149 if (match(V, P: m_StepVector()))
150 return true;
151 // Only handle a subset of IVs until we can guarantee there's no overflow.
152 if (auto *WidenIV = dyn_cast<VPWidenIntOrFpInductionRecipe>(Val: V))
153 return WidenIV->isCanonical() || WidenIV->hasNoUnsignedWrap();
154 if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Val: V))
155 return match(V: Steps->getOperand(N: 0),
156 P: m_CombineOr(
157 Ps: m_CanonicalIV(),
158 Ps: m_DerivedIV(Op0: m_ZeroInt(), Op1: m_CanonicalIV(), Op2: m_One()))) &&
159 match(V: Steps->getStepValue(), P: m_One());
160 if (isa<VPWidenCanonicalIVRecipe>(Val: V))
161 return true;
162 return vputils::isUniformAcrossVFsAndUFs(V);
163}
164
165bool VPlanVerifier::verifyLastActiveLaneRecipe(
166 const VPInstruction &LastActiveLane) const {
167 assert(LastActiveLane.getOpcode() == VPInstruction::LastActiveLane &&
168 "must be called with VPInstruction::LastActiveLane");
169
170 if (LastActiveLane.getNumOperands() < 1) {
171 errs() << "LastActiveLane must have at least one operand\n";
172 return false;
173 }
174
175 // All operands must be prefix-mask. This means an icmp ult/ule LHS, RHS where
176 // the LHS is monotonically increasing and RHS is uniform across VFs and UF.
177 for (VPValue *Op : LastActiveLane.operands()) {
178 VPValue *Mask = Op;
179 VPValue *HeaderMask;
180
181 // Look through any `and`s with the incoming alias mask or a
182 // loop_dependence_war_mask, which are always prefix masks.
183 // TODO: Verify the full loop.dependence.mask chain.
184 if (match(V: Op,
185 P: m_c_BinaryAnd(
186 Op0: m_VPValue(V&: HeaderMask),
187 Op1: m_CombineOr(
188 Ps: m_c_BinaryAnd(
189 Op0: m_Intrinsic<Intrinsic::loop_dependence_war_mask>(),
190 Op1: m_VPValue()),
191 Ps: m_Intrinsic<Intrinsic::loop_dependence_war_mask>(),
192 Ps: m_VPInstruction<VPInstruction::IncomingAliasMask>()))))
193 Mask = HeaderMask;
194
195 // The header mask is a prefix mask. Before being materialized it is the
196 // loop region's abstract header mask; afterwards it is an active lane mask
197 // (an intrinsic or a phi), or the icmp checked below.
198 if (match(V: Mask, P: m_HeaderMask()) || isa<VPActiveLaneMaskPHIRecipe>(Val: Mask) ||
199 match(V: Mask, P: m_VPInstruction<VPInstruction::ActiveLaneMask>()))
200 continue;
201
202 CmpPredicate Pred;
203 VPValue *LHS, *RHS;
204 if (match(V: Mask, P: m_ICmp(Pred, Op0: m_VPValue(V&: LHS), Op1: m_VPValue(V&: RHS))) &&
205 (Pred == CmpInst::ICMP_ULE || Pred == CmpInst::ICMP_ULT) &&
206 isKnownMonotonic(V: LHS) &&
207 (vputils::isUniformAcrossVFsAndUFs(V: RHS) ||
208 match(V: RHS, P: m_EVL(Op0: m_VPValue()))))
209 continue;
210
211 errs() << "LastActiveLane operand ";
212#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
213 VPSlotTracker Tracker(LastActiveLane.getParent()->getPlan());
214 Op->printAsOperand(errs(), Tracker);
215#endif
216 errs() << " must be prefix mask (a header mask or an "
217 "EVL-derived mask currently)\n";
218 return false;
219 }
220
221 return true;
222}
223
224bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
225 if (!verifyPhiRecipes(VPBB))
226 return false;
227
228 // Verify that defs in VPBB dominate all their uses.
229 DenseMap<const VPRecipeBase *, unsigned> RecipeNumbering;
230 unsigned Cnt = 0;
231 for (const VPRecipeBase &R : *VPBB)
232 RecipeNumbering[&R] = Cnt++;
233
234 for (const VPRecipeBase &R : *VPBB) {
235 if (isa<VPIRInstruction>(Val: &R) && !isa<VPIRBasicBlock>(Val: VPBB)) {
236 errs() << "VPIRInstructions ";
237#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
238 R.dump();
239 errs() << " ";
240#endif
241 errs() << "not in a VPIRBasicBlock!\n";
242 return false;
243 }
244 for (const VPValue *V : R.definedValues()) {
245 // Verify that each defined value has a scalar type.
246 if (!V->getScalarType()) {
247 errs() << "VPValue without scalar type!\n";
248 return false;
249 }
250
251 for (const VPUser *U : V->users()) {
252 auto *UI = cast<VPRecipeBase>(Val: U);
253 if (isa<VPIRPhi>(Val: UI) &&
254 UI->getNumOperands() != UI->getParent()->getNumPredecessors()) {
255 errs() << "Phi-like recipe with different number of operands and "
256 "predecessors.\n";
257 return false;
258 }
259
260 if (auto *Phi = dyn_cast<VPPhiAccessors>(Val: UI)) {
261 for (const auto &[IncomingVPV, IncomingVPBB] :
262 Phi->incoming_values_and_blocks()) {
263 if (IncomingVPV != V)
264 continue;
265
266 if (VPDT.dominates(A: VPBB, B: IncomingVPBB))
267 continue;
268
269 errs() << "Incoming def does not dominate incoming block!\n";
270#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
271 VPSlotTracker Tracker(VPBB->getPlan());
272 IncomingVPV->getDefiningRecipe()->print(errs(), " ", Tracker);
273 errs() << "\n does not dominate " << IncomingVPBB->getName()
274 << " for\n";
275 UI->print(errs(), " ", Tracker);
276#endif
277 return false;
278 }
279 continue;
280 }
281 // TODO: Also verify VPPredInstPHIRecipe.
282 if (isa<VPPredInstPHIRecipe>(Val: UI))
283 continue;
284
285 // If the user is in the same block, check it comes after R in the
286 // block.
287 if (UI->getParent() == VPBB) {
288 if (RecipeNumbering[UI] >= RecipeNumbering[&R])
289 continue;
290 } else {
291 // MaskedCond may be used from blocks it don't dominate; the block
292 // will be linearized and it will dominate its users after
293 // linearization.
294 if (match(V: &R, P: m_VPInstruction<VPInstruction::MaskedCond>()) ||
295 VPDT.dominates(A: VPBB, B: UI->getParent()))
296 continue;
297 }
298
299 // Recipes in blocks with a MaskedCond may be used in exit blocks; the
300 // block will be linearized and its recipes will dominate their users
301 // after linearization.
302 bool BlockHasMaskedCond = any_of(Range: *VPBB, P: [](const VPRecipeBase &R) {
303 return match(V: &R, P: m_VPInstruction<VPInstruction::MaskedCond>());
304 });
305 if (BlockHasMaskedCond &&
306 any_of(Range: VPBB->getPlan()->getExitBlocks(), P: [UI](VPIRBasicBlock *EB) {
307 return is_contained(Range&: EB->getPredecessors(), Element: UI->getParent());
308 })) {
309 continue;
310 }
311
312 errs() << "Use before def!\n";
313#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
314 VPSlotTracker Tracker(VPBB->getPlan());
315 UI->print(errs(), " ", Tracker);
316 errs() << "\n before\n";
317 R.print(errs(), " ", Tracker);
318 errs() << "\n";
319#endif
320 return false;
321 }
322 }
323 if (const auto *VPI = dyn_cast<VPInstruction>(Val: &R)) {
324 switch (VPI->getOpcode()) {
325 case VPInstruction::LastActiveLane:
326 if (!verifyLastActiveLaneRecipe(LastActiveLane: *VPI))
327 return false;
328 break;
329 default:
330 break;
331 }
332 }
333 if (const auto *DIV = dyn_cast<VPDerivedIVRecipe>(Val: &R)) {
334 if (!DIV->getStartValue()->isDefinedOutsideLoopRegions()) {
335 errs() << "VPDerivedIVRecipe must have start value defined outside "
336 "loop regions\n";
337 return false;
338 }
339 }
340 if (const auto *ScalarIVSteps = dyn_cast<VPScalarIVStepsRecipe>(Val: &R)) {
341 unsigned NumOps = ScalarIVSteps->getNumOperands();
342 if (NumOps != 3 && NumOps != 4) {
343 errs() << "VPScalarIVStepsRecipe must have 3 or 4 operands\n";
344 return false;
345 }
346 }
347 }
348
349 auto *IRBB = dyn_cast<VPIRBasicBlock>(Val: VPBB);
350 if (!IRBB)
351 return true;
352
353 if (!WrappedIRBBs.insert(Ptr: IRBB->getIRBasicBlock()).second) {
354 errs() << "Same IR basic block used by multiple wrapper blocks!\n";
355 return false;
356 }
357
358 return true;
359}
360
361bool VPlanVerifier::verifyBlock(const VPBlockBase *VPB) {
362 auto *VPBB = dyn_cast<VPBasicBlock>(Val: VPB);
363 // Check block's condition bit.
364 if (VPBB && !isa<VPIRBasicBlock>(Val: VPB)) {
365 // For plain CFG VPlans, verify header and latch block structure.
366 if (!VPBB->getParent()) {
367 if (VPBlockUtils::isHeader(VPB: VPBB, VPDT)) {
368 if (VPB->getNumPredecessors() != 2) {
369 errs()
370 << "Header block in plain CFG VPlan must have 2 predecessors!\n";
371 return false;
372 }
373 // Predecessor 0 is preheader, predecessor 1 is latch.
374 if (!VPBlockUtils::isLatch(VPB: VPB->getPredecessors()[1], VPDT)) {
375 errs() << "Header's second predecessor must be the latch!\n";
376 return false;
377 }
378 }
379
380 if (VPBlockUtils::isLatch(VPB: VPBB, VPDT)) {
381 if (!match(V: VPBB->getTerminator(), P: m_Branch())) {
382 errs() << "Latch block must have a branch terminator!\n";
383 return false;
384 }
385 // Successor 0 is middle block, successor 1 is header.
386 if (VPBlockUtils::isHeader(VPB: VPB->getSuccessors()[0], VPDT)) {
387 errs() << "Latch's first successor must not be the header (must be "
388 "middle block)!\n";
389 return false;
390 }
391 }
392 } else if (VPB->getNumSuccessors() > 1 ||
393 (VPBB->isExiting() && !VPBB->getParent()->isReplicator())) {
394 if (!VPBB->getTerminator()) {
395 errs() << "Block has multiple successors but doesn't "
396 "have a proper branch recipe!\n";
397 return false;
398 }
399 } else if (VPBB->getTerminator()) {
400 errs() << "Unexpected branch recipe!\n";
401 return false;
402 }
403 }
404
405 // Check block's successors.
406 const auto &Successors = VPB->getSuccessors();
407 for (const VPBlockBase *Succ : Successors) {
408 // There must be a bi-directional link between block and successor.
409 const auto &SuccPreds = Succ->getPredecessors();
410 if (!is_contained(Range: SuccPreds, Element: VPB)) {
411 errs() << "Missing predecessor link.\n";
412 return false;
413 }
414 }
415
416 // Check block's predecessors.
417 const auto &Predecessors = VPB->getPredecessors();
418
419 for (const VPBlockBase *Pred : Predecessors) {
420 // Block and predecessor must be inside the same region.
421 if (Pred->getParent() != VPB->getParent()) {
422 errs() << "Predecessor is not in the same region.\n";
423 return false;
424 }
425
426 // There must be a bi-directional link between block and predecessor.
427 const auto &PredSuccs = Pred->getSuccessors();
428 if (!is_contained(Range: PredSuccs, Element: VPB)) {
429 errs() << "Missing successor link.\n";
430 return false;
431 }
432 }
433 return !VPBB || verifyVPBasicBlock(VPBB);
434}
435
436bool VPlanVerifier::verifyBlocksInRegion(const VPRegionBlock *Region) {
437 for (const VPBlockBase *VPB : vp_depth_first_shallow(G: Region->getEntry())) {
438 // Check block's parent.
439 if (VPB->getParent() != Region) {
440 errs() << "VPBlockBase has wrong parent\n";
441 return false;
442 }
443
444 if (!verifyBlock(VPB))
445 return false;
446 }
447 return true;
448}
449
450bool VPlanVerifier::verifyRegion(const VPRegionBlock *Region) {
451 const VPBlockBase *Entry = Region->getEntry();
452 const VPBlockBase *Exiting = Region->getExiting();
453
454 // Entry and Exiting shouldn't have any predecessor/successor, respectively.
455 if (Entry->hasPredecessors()) {
456 errs() << "region entry block has predecessors\n";
457 return false;
458 }
459 if (Exiting->getNumSuccessors() != 0) {
460 errs() << "region exiting block has successors\n";
461 return false;
462 }
463
464 return verifyBlocksInRegion(Region);
465}
466
467bool VPlanVerifier::verifyRegionRec(const VPRegionBlock *Region) {
468 // Recurse inside nested regions and check all blocks inside the region.
469 return verifyRegion(Region) &&
470 all_of(Range: vp_depth_first_shallow(G: Region->getEntry()),
471 P: [this](const VPBlockBase *VPB) {
472 const auto *SubRegion = dyn_cast<VPRegionBlock>(Val: VPB);
473 return !SubRegion || verifyRegionRec(Region: SubRegion);
474 });
475}
476
477bool VPlanVerifier::verify(const VPlan &Plan) {
478 if (any_of(Range: vp_depth_first_shallow(G: Plan.getEntry()),
479 P: [this](const VPBlockBase *VPB) { return !verifyBlock(VPB); }))
480 return false;
481
482 // Check that the plan has a single loop region reachable from entry, and it
483 // matches the one returned by getVectorLoopRegion.
484 const VPRegionBlock *TopRegion = Plan.getVectorLoopRegion();
485 if (any_of(Range: VPBlockUtils::blocksOnly<const VPRegionBlock>(
486 Range: vp_depth_first_shallow(G: Plan.getEntry())),
487 P: [TopRegion](const VPRegionBlock *R) {
488 return !R->isReplicator() && R != TopRegion;
489 })) {
490 errs() << "VPlan must have a single top-level loop region, reachable from "
491 "the entry by following the last successor of each block\n";
492 return false;
493 }
494
495 // TODO: Verify all blocks using vp_depth_first_deep iterators.
496 if (!TopRegion)
497 return true;
498
499 if (!verifyRegionRec(Region: TopRegion))
500 return false;
501
502 if (TopRegion->getParent()) {
503 errs() << "VPlan Top Region should have no parent.\n";
504 return false;
505 }
506
507 const VPBasicBlock *Entry = dyn_cast<VPBasicBlock>(Val: TopRegion->getEntry());
508 if (!Entry) {
509 errs() << "VPlan entry block is not a VPBasicBlock\n";
510 return false;
511 }
512
513 const VPBasicBlock *Exiting = dyn_cast<VPBasicBlock>(Val: TopRegion->getExiting());
514 if (!Exiting) {
515 errs() << "VPlan exiting block is not a VPBasicBlock\n";
516 return false;
517 }
518
519 if (Exiting->empty()) {
520 errs() << "VPlan vector loop exiting block must end with BranchOnCount, "
521 "BranchOnCond, or BranchOnTwoConds VPInstruction but is empty\n";
522 return false;
523 }
524
525 auto *LastInst = dyn_cast<VPInstruction>(Val: std::prev(x: Exiting->end()));
526 if (!match(V: LastInst, P: m_Branch())) {
527 errs() << "VPlan vector loop exit must end with BranchOnCount, "
528 "BranchOnCond, or BranchOnTwoConds VPInstruction\n";
529 return false;
530 }
531
532 return true;
533}
534
535bool llvm::verifyVPlanIsValid(const VPlan &Plan) {
536 // The entry must be the root of the plan's top-level CFG: the dominator tree
537 // constructed below and the verifier's block walks all start there.
538 if (Plan.getEntry()->hasPredecessors()) {
539 errs() << "VPlan entry block has predecessors\n";
540 return false;
541 }
542
543 VPDominatorTree VPDT(const_cast<VPlan &>(Plan));
544 VPlanVerifier Verifier(VPDT);
545 return Verifier.verify(Plan);
546}
547