xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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 "llvm/ADT/SmallPtrSet.h"
21 #include "llvm/ADT/TypeSwitch.h"
22 
23 #define DEBUG_TYPE "loop-vectorize"
24 
25 using namespace llvm;
26 
27 namespace {
28 class VPlanVerifier {
29   const VPDominatorTree &VPDT;
30   VPTypeAnalysis &TypeInfo;
31   bool VerifyLate;
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 EVL is used correctly. The user must be either in
41   /// EVL-based recipes as a last operand or VPInstruction::Add which is
42   /// incoming value into EVL's recipe.
43   bool verifyEVLRecipe(const VPInstruction &EVL) const;
44 
45   bool verifyVPBasicBlock(const VPBasicBlock *VPBB);
46 
47   bool verifyBlock(const VPBlockBase *VPB);
48 
49   /// Helper function that verifies the CFG invariants of the VPBlockBases
50   /// within
51   /// \p Region. Checks in this function are generic for VPBlockBases. They are
52   /// not specific for VPBasicBlocks or VPRegionBlocks.
53   bool verifyBlocksInRegion(const VPRegionBlock *Region);
54 
55   /// Verify the CFG invariants of VPRegionBlock \p Region and its nested
56   /// VPBlockBases. Do not recurse inside nested VPRegionBlocks.
57   bool verifyRegion(const VPRegionBlock *Region);
58 
59   /// Verify the CFG invariants of VPRegionBlock \p Region and its nested
60   /// VPBlockBases. Recurse inside nested VPRegionBlocks.
61   bool verifyRegionRec(const VPRegionBlock *Region);
62 
63 public:
64   VPlanVerifier(VPDominatorTree &VPDT, VPTypeAnalysis &TypeInfo,
65                 bool VerifyLate)
66       : VPDT(VPDT), TypeInfo(TypeInfo), VerifyLate(VerifyLate) {}
67 
68   bool verify(const VPlan &Plan);
69 };
70 } // namespace
71 
72 bool VPlanVerifier::verifyPhiRecipes(const VPBasicBlock *VPBB) {
73   auto RecipeI = VPBB->begin();
74   auto End = VPBB->end();
75   unsigned NumActiveLaneMaskPhiRecipes = 0;
76   bool IsHeaderVPBB = VPBlockUtils::isHeader(VPBB, VPDT);
77   while (RecipeI != End && RecipeI->isPhi()) {
78     if (isa<VPActiveLaneMaskPHIRecipe>(RecipeI))
79       NumActiveLaneMaskPhiRecipes++;
80 
81     if (IsHeaderVPBB && !isa<VPHeaderPHIRecipe, VPWidenPHIRecipe>(*RecipeI) &&
82         !isa<VPInstruction>(*RecipeI) &&
83         cast<VPInstruction>(RecipeI)->getOpcode() == Instruction::PHI) {
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 
138 bool VPlanVerifier::verifyEVLRecipe(const VPInstruction &EVL) const {
139   if (EVL.getOpcode() != VPInstruction::ExplicitVectorLength) {
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         })
159         .Case<VPWidenStoreEVLRecipe, VPReductionEVLRecipe,
160               VPWidenIntOrFpInductionRecipe>(
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             return VerifyEVLUse(*I, 1);
176           switch (I->getOpcode()) {
177           case Instruction::Add:
178             break;
179           case Instruction::UIToFP:
180           case Instruction::Trunc:
181           case Instruction::ZExt:
182           case Instruction::Mul:
183           case Instruction::FMul:
184             // Opcodes above can only use EVL after wide inductions have been
185             // expanded.
186             if (!VerifyLate) {
187               errs() << "EVL used by unexpected VPInstruction\n";
188               return false;
189             }
190             break;
191           default:
192             errs() << "EVL used by unexpected VPInstruction\n";
193             return false;
194           }
195           if (I->getNumUsers() != 1) {
196             errs() << "EVL is used in VPInstruction with multiple users\n";
197             return false;
198           }
199           if (!VerifyLate && !isa<VPEVLBasedIVPHIRecipe>(*I->users().begin())) {
200             errs() << "Result of VPInstruction::Add with EVL operand is "
201                       "not used by VPEVLBasedIVPHIRecipe\n";
202             return false;
203           }
204           return true;
205         })
206         .Default([&](const VPUser *U) {
207           errs() << "EVL has unexpected user\n";
208           return false;
209         });
210   });
211 }
212 
213 bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
214   if (!verifyPhiRecipes(VPBB))
215     return false;
216 
217   // Verify that defs in VPBB dominate all their uses.
218   DenseMap<const VPRecipeBase *, unsigned> RecipeNumbering;
219   unsigned Cnt = 0;
220   for (const VPRecipeBase &R : *VPBB)
221     RecipeNumbering[&R] = Cnt++;
222 
223   for (const VPRecipeBase &R : *VPBB) {
224     if (isa<VPIRInstruction>(&R) && !isa<VPIRBasicBlock>(VPBB)) {
225       errs() << "VPIRInstructions ";
226 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
227       R.dump();
228       errs() << " ";
229 #endif
230       errs() << "not in a VPIRBasicBlock!\n";
231       return false;
232     }
233     for (const VPValue *V : R.definedValues()) {
234       // Verify that we can infer a scalar type for each defined value. With
235       // assertions enabled, inferScalarType will perform some consistency
236       // checks during type inference.
237       if (!TypeInfo.inferScalarType(V)) {
238         errs() << "Failed to infer scalar type!\n";
239         return false;
240       }
241 
242       for (const VPUser *U : V->users()) {
243         auto *UI = cast<VPRecipeBase>(U);
244         if (auto *Phi = dyn_cast<VPPhiAccessors>(UI)) {
245           for (unsigned Idx = 0; Idx != Phi->getNumIncoming(); ++Idx) {
246             VPValue *IncomingVPV = Phi->getIncomingValue(Idx);
247             if (IncomingVPV != V)
248               continue;
249 
250             const VPBasicBlock *IncomingVPBB = Phi->getIncomingBlock(Idx);
251             if (VPDT.dominates(VPBB, IncomingVPBB))
252               continue;
253 
254             errs() << "Incoming def at index " << Idx
255                    << " does not dominate incoming block!\n";
256 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
257             VPSlotTracker Tracker(VPBB->getPlan());
258             IncomingVPV->getDefiningRecipe()->print(errs(), "  ", Tracker);
259             errs() << "\n  does not dominate " << IncomingVPBB->getName()
260                    << " for\n";
261             UI->print(errs(), "  ", Tracker);
262 #endif
263             return false;
264           }
265           continue;
266         }
267         // TODO: Also verify VPPredInstPHIRecipe.
268         if (isa<VPPredInstPHIRecipe>(UI))
269           continue;
270 
271         // If the user is in the same block, check it comes after R in the
272         // block.
273         if (UI->getParent() == VPBB) {
274           if (RecipeNumbering[UI] >= RecipeNumbering[&R])
275             continue;
276         } else {
277           if (VPDT.dominates(VPBB, UI->getParent()))
278             continue;
279         }
280 
281         errs() << "Use before def!\n";
282 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
283         VPSlotTracker Tracker(VPBB->getPlan());
284         UI->print(errs(), "  ", Tracker);
285         errs() << "\n  before\n";
286         R.print(errs(), "  ", Tracker);
287         errs() << "\n";
288 #endif
289         return false;
290       }
291     }
292     if (const auto *EVL = dyn_cast<VPInstruction>(&R)) {
293       if (EVL->getOpcode() == VPInstruction::ExplicitVectorLength &&
294           !verifyEVLRecipe(*EVL)) {
295         errs() << "EVL VPValue is not used correctly\n";
296         return false;
297       }
298     }
299   }
300 
301   auto *IRBB = dyn_cast<VPIRBasicBlock>(VPBB);
302   if (!IRBB)
303     return true;
304 
305   if (!WrappedIRBBs.insert(IRBB->getIRBasicBlock()).second) {
306     errs() << "Same IR basic block used by multiple wrapper blocks!\n";
307     return false;
308   }
309 
310   return true;
311 }
312 
313 /// Utility function that checks whether \p VPBlockVec has duplicate
314 /// VPBlockBases.
315 static bool hasDuplicates(const SmallVectorImpl<VPBlockBase *> &VPBlockVec) {
316   SmallDenseSet<const VPBlockBase *, 8> VPBlockSet;
317   for (const auto *Block : VPBlockVec) {
318     if (!VPBlockSet.insert(Block).second)
319       return true;
320   }
321   return false;
322 }
323 
324 bool VPlanVerifier::verifyBlock(const VPBlockBase *VPB) {
325   auto *VPBB = dyn_cast<VPBasicBlock>(VPB);
326   // Check block's condition bit.
327   if (!isa<VPIRBasicBlock>(VPB)) {
328     if (VPB->getNumSuccessors() > 1 ||
329         (VPBB && VPBB->getParent() && VPBB->isExiting() &&
330          !VPBB->getParent()->isReplicator())) {
331       if (!VPBB || !VPBB->getTerminator()) {
332         errs() << "Block has multiple successors but doesn't "
333                   "have a proper branch recipe!\n";
334         return false;
335       }
336     } else {
337       if (VPBB && VPBB->getTerminator()) {
338         errs() << "Unexpected branch recipe!\n";
339         return false;
340       }
341     }
342   }
343 
344   // Check block's successors.
345   const auto &Successors = VPB->getSuccessors();
346   // There must be only one instance of a successor in block's successor list.
347   // TODO: This won't work for switch statements.
348   if (hasDuplicates(Successors)) {
349     errs() << "Multiple instances of the same successor.\n";
350     return false;
351   }
352 
353   for (const VPBlockBase *Succ : Successors) {
354     // There must be a bi-directional link between block and successor.
355     const auto &SuccPreds = Succ->getPredecessors();
356     if (!is_contained(SuccPreds, VPB)) {
357       errs() << "Missing predecessor link.\n";
358       return false;
359     }
360   }
361 
362   // Check block's predecessors.
363   const auto &Predecessors = VPB->getPredecessors();
364   // There must be only one instance of a predecessor in block's predecessor
365   // list.
366   // TODO: This won't work for switch statements.
367   if (hasDuplicates(Predecessors)) {
368     errs() << "Multiple instances of the same predecessor.\n";
369     return false;
370   }
371 
372   for (const VPBlockBase *Pred : Predecessors) {
373     // Block and predecessor must be inside the same region.
374     if (Pred->getParent() != VPB->getParent()) {
375       errs() << "Predecessor is not in the same region.\n";
376       return false;
377     }
378 
379     // There must be a bi-directional link between block and predecessor.
380     const auto &PredSuccs = Pred->getSuccessors();
381     if (!is_contained(PredSuccs, VPB)) {
382       errs() << "Missing successor link.\n";
383       return false;
384     }
385   }
386   return !VPBB || verifyVPBasicBlock(VPBB);
387 }
388 
389 bool VPlanVerifier::verifyBlocksInRegion(const VPRegionBlock *Region) {
390   for (const VPBlockBase *VPB : vp_depth_first_shallow(Region->getEntry())) {
391     // Check block's parent.
392     if (VPB->getParent() != Region) {
393       errs() << "VPBlockBase has wrong parent\n";
394       return false;
395     }
396 
397     if (!verifyBlock(VPB))
398       return false;
399   }
400   return true;
401 }
402 
403 bool VPlanVerifier::verifyRegion(const VPRegionBlock *Region) {
404   const VPBlockBase *Entry = Region->getEntry();
405   const VPBlockBase *Exiting = Region->getExiting();
406 
407   // Entry and Exiting shouldn't have any predecessor/successor, respectively.
408   if (Entry->getNumPredecessors() != 0) {
409     errs() << "region entry block has predecessors\n";
410     return false;
411   }
412   if (Exiting->getNumSuccessors() != 0) {
413     errs() << "region exiting block has successors\n";
414     return false;
415   }
416 
417   return verifyBlocksInRegion(Region);
418 }
419 
420 bool VPlanVerifier::verifyRegionRec(const VPRegionBlock *Region) {
421   // Recurse inside nested regions and check all blocks inside the region.
422   return verifyRegion(Region) &&
423          all_of(vp_depth_first_shallow(Region->getEntry()),
424                 [this](const VPBlockBase *VPB) {
425                   const auto *SubRegion = dyn_cast<VPRegionBlock>(VPB);
426                   return !SubRegion || verifyRegionRec(SubRegion);
427                 });
428 }
429 
430 bool VPlanVerifier::verify(const VPlan &Plan) {
431   if (any_of(vp_depth_first_shallow(Plan.getEntry()),
432              [this](const VPBlockBase *VPB) { return !verifyBlock(VPB); }))
433     return false;
434 
435   const VPRegionBlock *TopRegion = Plan.getVectorLoopRegion();
436   // TODO: Verify all blocks using vp_depth_first_deep iterators.
437   if (!TopRegion)
438     return true;
439 
440   if (!verifyRegionRec(TopRegion))
441     return false;
442 
443   if (TopRegion->getParent()) {
444     errs() << "VPlan Top Region should have no parent.\n";
445     return false;
446   }
447 
448   const VPBasicBlock *Entry = dyn_cast<VPBasicBlock>(TopRegion->getEntry());
449   if (!Entry) {
450     errs() << "VPlan entry block is not a VPBasicBlock\n";
451     return false;
452   }
453 
454   if (!isa<VPCanonicalIVPHIRecipe>(&*Entry->begin())) {
455     errs() << "VPlan vector loop header does not start with a "
456               "VPCanonicalIVPHIRecipe\n";
457     return false;
458   }
459 
460   const VPBasicBlock *Exiting = dyn_cast<VPBasicBlock>(TopRegion->getExiting());
461   if (!Exiting) {
462     errs() << "VPlan exiting block is not a VPBasicBlock\n";
463     return false;
464   }
465 
466   if (Exiting->empty()) {
467     errs() << "VPlan vector loop exiting block must end with BranchOnCount or "
468               "BranchOnCond VPInstruction but is empty\n";
469     return false;
470   }
471 
472   auto *LastInst = dyn_cast<VPInstruction>(std::prev(Exiting->end()));
473   if (!LastInst || (LastInst->getOpcode() != VPInstruction::BranchOnCount &&
474                     LastInst->getOpcode() != VPInstruction::BranchOnCond)) {
475     errs() << "VPlan vector loop exit must end with BranchOnCount or "
476               "BranchOnCond VPInstruction\n";
477     return false;
478   }
479 
480   return true;
481 }
482 
483 bool llvm::verifyVPlanIsValid(const VPlan &Plan, bool VerifyLate) {
484   VPDominatorTree VPDT;
485   VPDT.recalculate(const_cast<VPlan &>(Plan));
486   VPTypeAnalysis TypeInfo(Plan);
487   VPlanVerifier Verifier(VPDT, TypeInfo, VerifyLate);
488   return Verifier.verify(Plan);
489 }
490