xref: /llvm-project/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp (revision f0c5caa8144307ec59fbafeed1ba37bb3603b00f)
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 "llvm/ADT/DepthFirstIterator.h"
20 #include "llvm/ADT/SmallPtrSet.h"
21 #include "llvm/Support/CommandLine.h"
22 
23 #define DEBUG_TYPE "loop-vectorize"
24 
25 using namespace llvm;
26 
27 namespace {
28 class VPlanVerifier {
29   const VPDominatorTree &VPDT;
30 
31   SmallPtrSet<BasicBlock *, 8> WrappedIRBBs;
32 
33   // Verify that phi-like recipes are at the beginning of \p VPBB, with no
34   // other recipes in between. Also check that only header blocks contain
35   // VPHeaderPHIRecipes.
36   bool verifyPhiRecipes(const VPBasicBlock *VPBB);
37 
38   bool verifyVPBasicBlock(const VPBasicBlock *VPBB);
39 
40   bool verifyBlock(const VPBlockBase *VPB);
41 
42   /// Helper function that verifies the CFG invariants of the VPBlockBases
43   /// within
44   /// \p Region. Checks in this function are generic for VPBlockBases. They are
45   /// not specific for VPBasicBlocks or VPRegionBlocks.
46   bool verifyBlocksInRegion(const VPRegionBlock *Region);
47 
48   /// Verify the CFG invariants of VPRegionBlock \p Region and its nested
49   /// VPBlockBases. Do not recurse inside nested VPRegionBlocks.
50   bool verifyRegion(const VPRegionBlock *Region);
51 
52   /// Verify the CFG invariants of VPRegionBlock \p Region and its nested
53   /// VPBlockBases. Recurse inside nested VPRegionBlocks.
54   bool verifyRegionRec(const VPRegionBlock *Region);
55 
56 public:
57   VPlanVerifier(VPDominatorTree &VPDT) : VPDT(VPDT) {}
58 
59   bool verify(const VPlan &Plan);
60 };
61 } // namespace
62 
63 bool VPlanVerifier::verifyPhiRecipes(const VPBasicBlock *VPBB) {
64   auto RecipeI = VPBB->begin();
65   auto End = VPBB->end();
66   unsigned NumActiveLaneMaskPhiRecipes = 0;
67   const VPRegionBlock *ParentR = VPBB->getParent();
68   bool IsHeaderVPBB = ParentR && !ParentR->isReplicator() &&
69                       ParentR->getEntryBasicBlock() == VPBB;
70   while (RecipeI != End && RecipeI->isPhi()) {
71     if (isa<VPActiveLaneMaskPHIRecipe>(RecipeI))
72       NumActiveLaneMaskPhiRecipes++;
73 
74     if (IsHeaderVPBB && !isa<VPHeaderPHIRecipe, VPWidenPHIRecipe>(*RecipeI)) {
75       errs() << "Found non-header PHI recipe in header VPBB";
76 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
77       errs() << ": ";
78       RecipeI->dump();
79 #endif
80       return false;
81     }
82 
83     if (!IsHeaderVPBB && isa<VPHeaderPHIRecipe>(*RecipeI)) {
84       errs() << "Found header PHI recipe in non-header VPBB";
85 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
86       errs() << ": ";
87       RecipeI->dump();
88 #endif
89       return false;
90     }
91 
92     RecipeI++;
93   }
94 
95   if (NumActiveLaneMaskPhiRecipes > 1) {
96     errs() << "There should be no more than one VPActiveLaneMaskPHIRecipe";
97     return false;
98   }
99 
100   while (RecipeI != End) {
101     if (RecipeI->isPhi() && !isa<VPBlendRecipe>(&*RecipeI)) {
102       errs() << "Found phi-like recipe after non-phi recipe";
103 
104 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
105       errs() << ": ";
106       RecipeI->dump();
107       errs() << "after\n";
108       std::prev(RecipeI)->dump();
109 #endif
110       return false;
111     }
112     RecipeI++;
113   }
114   return true;
115 }
116 
117 bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
118   if (!verifyPhiRecipes(VPBB))
119     return false;
120 
121   // Verify that defs in VPBB dominate all their uses. The current
122   // implementation is still incomplete.
123   DenseMap<const VPRecipeBase *, unsigned> RecipeNumbering;
124   unsigned Cnt = 0;
125   for (const VPRecipeBase &R : *VPBB)
126     RecipeNumbering[&R] = Cnt++;
127 
128   for (const VPRecipeBase &R : *VPBB) {
129     if (isa<VPIRInstruction>(&R) ^ isa<VPIRBasicBlock>(VPBB)) {
130       errs() << "VPIRInstructions ";
131 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
132       R.dump();
133       errs() << " ";
134 #endif
135       errs() << "not in a VPIRBasicBlock!\n";
136       return false;
137     }
138     for (const VPValue *V : R.definedValues()) {
139       for (const VPUser *U : V->users()) {
140         auto *UI = dyn_cast<VPRecipeBase>(U);
141         // TODO: check dominance of incoming values for phis properly.
142         if (!UI ||
143             isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPredInstPHIRecipe>(UI))
144           continue;
145 
146         // If the user is in the same block, check it comes after R in the
147         // block.
148         if (UI->getParent() == VPBB) {
149           if (RecipeNumbering[UI] < RecipeNumbering[&R]) {
150             errs() << "Use before def!\n";
151             return false;
152           }
153           continue;
154         }
155 
156         if (!VPDT.dominates(VPBB, UI->getParent())) {
157           errs() << "Use before def!\n";
158           return false;
159         }
160       }
161     }
162   }
163 
164   auto *IRBB = dyn_cast<VPIRBasicBlock>(VPBB);
165   if (!IRBB)
166     return true;
167 
168   if (!WrappedIRBBs.insert(IRBB->getIRBasicBlock()).second) {
169     errs() << "Same IR basic block used by multiple wrapper blocks!\n";
170     return false;
171   }
172 
173   VPBlockBase *MiddleBB =
174       IRBB->getPlan()->getVectorLoopRegion()->getSingleSuccessor();
175   if (IRBB != IRBB->getPlan()->getPreheader() &&
176       IRBB->getSinglePredecessor() != MiddleBB) {
177     errs() << "VPIRBasicBlock can only be used as pre-header or a successor of "
178               "middle-block at the moment!\n";
179     return false;
180   }
181   return true;
182 }
183 
184 /// Utility function that checks whether \p VPBlockVec has duplicate
185 /// VPBlockBases.
186 static bool hasDuplicates(const SmallVectorImpl<VPBlockBase *> &VPBlockVec) {
187   SmallDenseSet<const VPBlockBase *, 8> VPBlockSet;
188   for (const auto *Block : VPBlockVec) {
189     if (!VPBlockSet.insert(Block).second)
190       return true;
191   }
192   return false;
193 }
194 
195 bool VPlanVerifier::verifyBlock(const VPBlockBase *VPB) {
196   auto *VPBB = dyn_cast<VPBasicBlock>(VPB);
197   // Check block's condition bit.
198   if (VPB->getNumSuccessors() > 1 ||
199       (VPBB && VPBB->getParent() && VPBB->isExiting() &&
200        !VPBB->getParent()->isReplicator())) {
201     if (!VPBB || !VPBB->getTerminator()) {
202       errs() << "Block has multiple successors but doesn't "
203                 "have a proper branch recipe!\n";
204       return false;
205     }
206   } else {
207     if (VPBB && VPBB->getTerminator()) {
208       errs() << "Unexpected branch recipe!\n";
209       return false;
210     }
211   }
212 
213   // Check block's successors.
214   const auto &Successors = VPB->getSuccessors();
215   // There must be only one instance of a successor in block's successor list.
216   // TODO: This won't work for switch statements.
217   if (hasDuplicates(Successors)) {
218     errs() << "Multiple instances of the same successor.\n";
219     return false;
220   }
221 
222   for (const VPBlockBase *Succ : Successors) {
223     // There must be a bi-directional link between block and successor.
224     const auto &SuccPreds = Succ->getPredecessors();
225     if (!is_contained(SuccPreds, VPB)) {
226       errs() << "Missing predecessor link.\n";
227       return false;
228     }
229   }
230 
231   // Check block's predecessors.
232   const auto &Predecessors = VPB->getPredecessors();
233   // There must be only one instance of a predecessor in block's predecessor
234   // list.
235   // TODO: This won't work for switch statements.
236   if (hasDuplicates(Predecessors)) {
237     errs() << "Multiple instances of the same predecessor.\n";
238     return false;
239   }
240 
241   for (const VPBlockBase *Pred : Predecessors) {
242     // Block and predecessor must be inside the same region.
243     if (Pred->getParent() != VPB->getParent()) {
244       errs() << "Predecessor is not in the same region.\n";
245       return false;
246     }
247 
248     // There must be a bi-directional link between block and predecessor.
249     const auto &PredSuccs = Pred->getSuccessors();
250     if (!is_contained(PredSuccs, VPB)) {
251       errs() << "Missing successor link.\n";
252       return false;
253     }
254   }
255   return !VPBB || verifyVPBasicBlock(VPBB);
256 }
257 
258 bool VPlanVerifier::verifyBlocksInRegion(const VPRegionBlock *Region) {
259   for (const VPBlockBase *VPB : vp_depth_first_shallow(Region->getEntry())) {
260     // Check block's parent.
261     if (VPB->getParent() != Region) {
262       errs() << "VPBlockBase has wrong parent\n";
263       return false;
264     }
265 
266     if (!verifyBlock(VPB))
267       return false;
268   }
269   return true;
270 }
271 
272 bool VPlanVerifier::verifyRegion(const VPRegionBlock *Region) {
273   const VPBlockBase *Entry = Region->getEntry();
274   const VPBlockBase *Exiting = Region->getExiting();
275 
276   // Entry and Exiting shouldn't have any predecessor/successor, respectively.
277   if (Entry->getNumPredecessors() != 0) {
278     errs() << "region entry block has predecessors\n";
279     return false;
280   }
281   if (Exiting->getNumSuccessors() != 0) {
282     errs() << "region exiting block has successors\n";
283     return false;
284   }
285 
286   return verifyBlocksInRegion(Region);
287 }
288 
289 bool VPlanVerifier::verifyRegionRec(const VPRegionBlock *Region) {
290   // Recurse inside nested regions and check all blocks inside the region.
291   return verifyRegion(Region) &&
292          all_of(vp_depth_first_shallow(Region->getEntry()),
293                 [this](const VPBlockBase *VPB) {
294                   const auto *SubRegion = dyn_cast<VPRegionBlock>(VPB);
295                   return !SubRegion || verifyRegionRec(SubRegion);
296                 });
297 }
298 
299 bool VPlanVerifier::verify(const VPlan &Plan) {
300   if (any_of(vp_depth_first_shallow(Plan.getEntry()),
301              [this](const VPBlockBase *VPB) { return !verifyBlock(VPB); }))
302     return false;
303 
304   const VPRegionBlock *TopRegion = Plan.getVectorLoopRegion();
305   if (!verifyRegionRec(TopRegion))
306     return false;
307 
308   if (TopRegion->getParent()) {
309     errs() << "VPlan Top Region should have no parent.\n";
310     return false;
311   }
312 
313   const VPBasicBlock *Entry = dyn_cast<VPBasicBlock>(TopRegion->getEntry());
314   if (!Entry) {
315     errs() << "VPlan entry block is not a VPBasicBlock\n";
316     return false;
317   }
318 
319   if (!isa<VPCanonicalIVPHIRecipe>(&*Entry->begin())) {
320     errs() << "VPlan vector loop header does not start with a "
321               "VPCanonicalIVPHIRecipe\n";
322     return false;
323   }
324 
325   const VPBasicBlock *Exiting = dyn_cast<VPBasicBlock>(TopRegion->getExiting());
326   if (!Exiting) {
327     errs() << "VPlan exiting block is not a VPBasicBlock\n";
328     return false;
329   }
330 
331   if (Exiting->empty()) {
332     errs() << "VPlan vector loop exiting block must end with BranchOnCount or "
333               "BranchOnCond VPInstruction but is empty\n";
334     return false;
335   }
336 
337   auto *LastInst = dyn_cast<VPInstruction>(std::prev(Exiting->end()));
338   if (!LastInst || (LastInst->getOpcode() != VPInstruction::BranchOnCount &&
339                     LastInst->getOpcode() != VPInstruction::BranchOnCond)) {
340     errs() << "VPlan vector loop exit must end with BranchOnCount or "
341               "BranchOnCond VPInstruction\n";
342     return false;
343   }
344 
345   for (const auto &KV : Plan.getLiveOuts())
346     if (KV.second->getNumOperands() != 1) {
347       errs() << "live outs must have a single operand\n";
348       return false;
349     }
350 
351   return true;
352 }
353 
354 bool llvm::verifyVPlanIsValid(const VPlan &Plan) {
355   VPDominatorTree VPDT;
356   VPDT.recalculate(const_cast<VPlan &>(Plan));
357   VPlanVerifier Verifier(VPDT);
358   return Verifier.verify(Plan);
359 }
360