10b57cec5SDimitry Andric //===-- VPlanVerifier.cpp -------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This file defines the class VPlanVerifier, which contains utility functions 110b57cec5SDimitry Andric /// to check the consistency and invariants of a VPlan. 120b57cec5SDimitry Andric /// 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "VPlanVerifier.h" 165ffd83dbSDimitry Andric #include "VPlan.h" 17bdd1243dSDimitry Andric #include "VPlanCFG.h" 1806c3fb27SDimitry Andric #include "VPlanDominatorTree.h" 190b57cec5SDimitry Andric #include "llvm/ADT/DepthFirstIterator.h" 20*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 21480093f4SDimitry Andric #include "llvm/Support/CommandLine.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #define DEBUG_TYPE "loop-vectorize" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 27*0fca6ea1SDimitry Andric namespace { 28*0fca6ea1SDimitry Andric class VPlanVerifier { 29*0fca6ea1SDimitry Andric const VPDominatorTree &VPDT; 300b57cec5SDimitry Andric 31*0fca6ea1SDimitry Andric SmallPtrSet<BasicBlock *, 8> WrappedIRBBs; 32349cc55cSDimitry Andric 33bdd1243dSDimitry Andric // Verify that phi-like recipes are at the beginning of \p VPBB, with no 34bdd1243dSDimitry Andric // other recipes in between. Also check that only header blocks contain 35bdd1243dSDimitry Andric // VPHeaderPHIRecipes. 36*0fca6ea1SDimitry Andric bool verifyPhiRecipes(const VPBasicBlock *VPBB); 37*0fca6ea1SDimitry Andric 38*0fca6ea1SDimitry Andric bool verifyVPBasicBlock(const VPBasicBlock *VPBB); 39*0fca6ea1SDimitry Andric 40*0fca6ea1SDimitry Andric bool verifyBlock(const VPBlockBase *VPB); 41*0fca6ea1SDimitry Andric 42*0fca6ea1SDimitry Andric /// Helper function that verifies the CFG invariants of the VPBlockBases 43*0fca6ea1SDimitry Andric /// within 44*0fca6ea1SDimitry Andric /// \p Region. Checks in this function are generic for VPBlockBases. They are 45*0fca6ea1SDimitry Andric /// not specific for VPBasicBlocks or VPRegionBlocks. 46*0fca6ea1SDimitry Andric bool verifyBlocksInRegion(const VPRegionBlock *Region); 47*0fca6ea1SDimitry Andric 48*0fca6ea1SDimitry Andric /// Verify the CFG invariants of VPRegionBlock \p Region and its nested 49*0fca6ea1SDimitry Andric /// VPBlockBases. Do not recurse inside nested VPRegionBlocks. 50*0fca6ea1SDimitry Andric bool verifyRegion(const VPRegionBlock *Region); 51*0fca6ea1SDimitry Andric 52*0fca6ea1SDimitry Andric /// Verify the CFG invariants of VPRegionBlock \p Region and its nested 53*0fca6ea1SDimitry Andric /// VPBlockBases. Recurse inside nested VPRegionBlocks. 54*0fca6ea1SDimitry Andric bool verifyRegionRec(const VPRegionBlock *Region); 55*0fca6ea1SDimitry Andric 56*0fca6ea1SDimitry Andric public: 57*0fca6ea1SDimitry Andric VPlanVerifier(VPDominatorTree &VPDT) : VPDT(VPDT) {} 58*0fca6ea1SDimitry Andric 59*0fca6ea1SDimitry Andric bool verify(const VPlan &Plan); 60*0fca6ea1SDimitry Andric }; 61*0fca6ea1SDimitry Andric } // namespace 62*0fca6ea1SDimitry Andric 63*0fca6ea1SDimitry Andric bool VPlanVerifier::verifyPhiRecipes(const VPBasicBlock *VPBB) { 64349cc55cSDimitry Andric auto RecipeI = VPBB->begin(); 65349cc55cSDimitry Andric auto End = VPBB->end(); 66753f127fSDimitry Andric unsigned NumActiveLaneMaskPhiRecipes = 0; 67bdd1243dSDimitry Andric const VPRegionBlock *ParentR = VPBB->getParent(); 68bdd1243dSDimitry Andric bool IsHeaderVPBB = ParentR && !ParentR->isReplicator() && 69bdd1243dSDimitry Andric ParentR->getEntryBasicBlock() == VPBB; 70753f127fSDimitry Andric while (RecipeI != End && RecipeI->isPhi()) { 71753f127fSDimitry Andric if (isa<VPActiveLaneMaskPHIRecipe>(RecipeI)) 72753f127fSDimitry Andric NumActiveLaneMaskPhiRecipes++; 73bdd1243dSDimitry Andric 74*0fca6ea1SDimitry Andric if (IsHeaderVPBB && !isa<VPHeaderPHIRecipe, VPWidenPHIRecipe>(*RecipeI)) { 75bdd1243dSDimitry Andric errs() << "Found non-header PHI recipe in header VPBB"; 76bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 77bdd1243dSDimitry Andric errs() << ": "; 78bdd1243dSDimitry Andric RecipeI->dump(); 79bdd1243dSDimitry Andric #endif 80bdd1243dSDimitry Andric return false; 81bdd1243dSDimitry Andric } 82bdd1243dSDimitry Andric 83bdd1243dSDimitry Andric if (!IsHeaderVPBB && isa<VPHeaderPHIRecipe>(*RecipeI)) { 84bdd1243dSDimitry Andric errs() << "Found header PHI recipe in non-header VPBB"; 85bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 86bdd1243dSDimitry Andric errs() << ": "; 87bdd1243dSDimitry Andric RecipeI->dump(); 88bdd1243dSDimitry Andric #endif 89bdd1243dSDimitry Andric return false; 90bdd1243dSDimitry Andric } 91bdd1243dSDimitry Andric 92349cc55cSDimitry Andric RecipeI++; 93753f127fSDimitry Andric } 94753f127fSDimitry Andric 95753f127fSDimitry Andric if (NumActiveLaneMaskPhiRecipes > 1) { 96753f127fSDimitry Andric errs() << "There should be no more than one VPActiveLaneMaskPHIRecipe"; 97753f127fSDimitry Andric return false; 98753f127fSDimitry Andric } 99349cc55cSDimitry Andric 100349cc55cSDimitry Andric while (RecipeI != End) { 101349cc55cSDimitry Andric if (RecipeI->isPhi() && !isa<VPBlendRecipe>(&*RecipeI)) { 102349cc55cSDimitry Andric errs() << "Found phi-like recipe after non-phi recipe"; 103349cc55cSDimitry Andric 104349cc55cSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 105349cc55cSDimitry Andric errs() << ": "; 106349cc55cSDimitry Andric RecipeI->dump(); 107349cc55cSDimitry Andric errs() << "after\n"; 108349cc55cSDimitry Andric std::prev(RecipeI)->dump(); 109349cc55cSDimitry Andric #endif 110349cc55cSDimitry Andric return false; 111349cc55cSDimitry Andric } 112349cc55cSDimitry Andric RecipeI++; 113349cc55cSDimitry Andric } 114bdd1243dSDimitry Andric return true; 115bdd1243dSDimitry Andric } 116bdd1243dSDimitry Andric 117*0fca6ea1SDimitry Andric bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) { 118bdd1243dSDimitry Andric if (!verifyPhiRecipes(VPBB)) 119bdd1243dSDimitry Andric return false; 120753f127fSDimitry Andric 121fcaf7f86SDimitry Andric // Verify that defs in VPBB dominate all their uses. The current 122fcaf7f86SDimitry Andric // implementation is still incomplete. 123fcaf7f86SDimitry Andric DenseMap<const VPRecipeBase *, unsigned> RecipeNumbering; 124fcaf7f86SDimitry Andric unsigned Cnt = 0; 125fcaf7f86SDimitry Andric for (const VPRecipeBase &R : *VPBB) 126fcaf7f86SDimitry Andric RecipeNumbering[&R] = Cnt++; 127fcaf7f86SDimitry Andric 128fcaf7f86SDimitry Andric for (const VPRecipeBase &R : *VPBB) { 129fcaf7f86SDimitry Andric for (const VPValue *V : R.definedValues()) { 130fcaf7f86SDimitry Andric for (const VPUser *U : V->users()) { 131fcaf7f86SDimitry Andric auto *UI = dyn_cast<VPRecipeBase>(U); 13206c3fb27SDimitry Andric // TODO: check dominance of incoming values for phis properly. 133*0fca6ea1SDimitry Andric if (!UI || 134*0fca6ea1SDimitry Andric isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPredInstPHIRecipe>(UI)) 135fcaf7f86SDimitry Andric continue; 136fcaf7f86SDimitry Andric 137fcaf7f86SDimitry Andric // If the user is in the same block, check it comes after R in the 138fcaf7f86SDimitry Andric // block. 139fcaf7f86SDimitry Andric if (UI->getParent() == VPBB) { 140fcaf7f86SDimitry Andric if (RecipeNumbering[UI] < RecipeNumbering[&R]) { 141fcaf7f86SDimitry Andric errs() << "Use before def!\n"; 142fcaf7f86SDimitry Andric return false; 143fcaf7f86SDimitry Andric } 144fcaf7f86SDimitry Andric continue; 145fcaf7f86SDimitry Andric } 146fcaf7f86SDimitry Andric 14706c3fb27SDimitry Andric if (!VPDT.dominates(VPBB, UI->getParent())) { 148fcaf7f86SDimitry Andric errs() << "Use before def!\n"; 149fcaf7f86SDimitry Andric return false; 150fcaf7f86SDimitry Andric } 151fcaf7f86SDimitry Andric } 152fcaf7f86SDimitry Andric } 153fcaf7f86SDimitry Andric } 154*0fca6ea1SDimitry Andric 155*0fca6ea1SDimitry Andric auto *IRBB = dyn_cast<VPIRBasicBlock>(VPBB); 156*0fca6ea1SDimitry Andric if (!IRBB) 157753f127fSDimitry Andric return true; 158753f127fSDimitry Andric 159*0fca6ea1SDimitry Andric if (!WrappedIRBBs.insert(IRBB->getIRBasicBlock()).second) { 160*0fca6ea1SDimitry Andric errs() << "Same IR basic block used by multiple wrapper blocks!\n"; 161753f127fSDimitry Andric return false; 162349cc55cSDimitry Andric } 1630eae32dcSDimitry Andric 164*0fca6ea1SDimitry Andric VPBlockBase *MiddleBB = 165*0fca6ea1SDimitry Andric IRBB->getPlan()->getVectorLoopRegion()->getSingleSuccessor(); 166*0fca6ea1SDimitry Andric if (IRBB != IRBB->getPlan()->getPreheader() && 167*0fca6ea1SDimitry Andric IRBB->getSinglePredecessor() != MiddleBB) { 168*0fca6ea1SDimitry Andric errs() << "VPIRBasicBlock can only be used as pre-header or a successor of " 169*0fca6ea1SDimitry Andric "middle-block at the moment!\n"; 170*0fca6ea1SDimitry Andric return false; 171*0fca6ea1SDimitry Andric } 172*0fca6ea1SDimitry Andric return true; 173*0fca6ea1SDimitry Andric } 174*0fca6ea1SDimitry Andric 175*0fca6ea1SDimitry Andric /// Utility function that checks whether \p VPBlockVec has duplicate 176*0fca6ea1SDimitry Andric /// VPBlockBases. 177*0fca6ea1SDimitry Andric static bool hasDuplicates(const SmallVectorImpl<VPBlockBase *> &VPBlockVec) { 178*0fca6ea1SDimitry Andric SmallDenseSet<const VPBlockBase *, 8> VPBlockSet; 179*0fca6ea1SDimitry Andric for (const auto *Block : VPBlockVec) { 180*0fca6ea1SDimitry Andric if (VPBlockSet.count(Block)) 181*0fca6ea1SDimitry Andric return true; 182*0fca6ea1SDimitry Andric VPBlockSet.insert(Block); 183*0fca6ea1SDimitry Andric } 184*0fca6ea1SDimitry Andric return false; 185*0fca6ea1SDimitry Andric } 186*0fca6ea1SDimitry Andric 187*0fca6ea1SDimitry Andric bool VPlanVerifier::verifyBlock(const VPBlockBase *VPB) { 188*0fca6ea1SDimitry Andric auto *VPBB = dyn_cast<VPBasicBlock>(VPB); 189*0fca6ea1SDimitry Andric // Check block's condition bit. 190*0fca6ea1SDimitry Andric if (VPB->getNumSuccessors() > 1 || 191*0fca6ea1SDimitry Andric (VPBB && VPBB->getParent() && VPBB->isExiting() && 192*0fca6ea1SDimitry Andric !VPBB->getParent()->isReplicator())) { 193*0fca6ea1SDimitry Andric if (!VPBB || !VPBB->getTerminator()) { 194*0fca6ea1SDimitry Andric errs() << "Block has multiple successors but doesn't " 195*0fca6ea1SDimitry Andric "have a proper branch recipe!\n"; 196*0fca6ea1SDimitry Andric return false; 197*0fca6ea1SDimitry Andric } 198*0fca6ea1SDimitry Andric } else { 199*0fca6ea1SDimitry Andric if (VPBB && VPBB->getTerminator()) { 200*0fca6ea1SDimitry Andric errs() << "Unexpected branch recipe!\n"; 201*0fca6ea1SDimitry Andric return false; 202*0fca6ea1SDimitry Andric } 203*0fca6ea1SDimitry Andric } 204*0fca6ea1SDimitry Andric 205*0fca6ea1SDimitry Andric // Check block's successors. 206*0fca6ea1SDimitry Andric const auto &Successors = VPB->getSuccessors(); 207*0fca6ea1SDimitry Andric // There must be only one instance of a successor in block's successor list. 208*0fca6ea1SDimitry Andric // TODO: This won't work for switch statements. 209*0fca6ea1SDimitry Andric if (hasDuplicates(Successors)) { 210*0fca6ea1SDimitry Andric errs() << "Multiple instances of the same successor.\n"; 211*0fca6ea1SDimitry Andric return false; 212*0fca6ea1SDimitry Andric } 213*0fca6ea1SDimitry Andric 214*0fca6ea1SDimitry Andric for (const VPBlockBase *Succ : Successors) { 215*0fca6ea1SDimitry Andric // There must be a bi-directional link between block and successor. 216*0fca6ea1SDimitry Andric const auto &SuccPreds = Succ->getPredecessors(); 217*0fca6ea1SDimitry Andric if (!is_contained(SuccPreds, VPB)) { 218*0fca6ea1SDimitry Andric errs() << "Missing predecessor link.\n"; 219*0fca6ea1SDimitry Andric return false; 220*0fca6ea1SDimitry Andric } 221*0fca6ea1SDimitry Andric } 222*0fca6ea1SDimitry Andric 223*0fca6ea1SDimitry Andric // Check block's predecessors. 224*0fca6ea1SDimitry Andric const auto &Predecessors = VPB->getPredecessors(); 225*0fca6ea1SDimitry Andric // There must be only one instance of a predecessor in block's predecessor 226*0fca6ea1SDimitry Andric // list. 227*0fca6ea1SDimitry Andric // TODO: This won't work for switch statements. 228*0fca6ea1SDimitry Andric if (hasDuplicates(Predecessors)) { 229*0fca6ea1SDimitry Andric errs() << "Multiple instances of the same predecessor.\n"; 230*0fca6ea1SDimitry Andric return false; 231*0fca6ea1SDimitry Andric } 232*0fca6ea1SDimitry Andric 233*0fca6ea1SDimitry Andric for (const VPBlockBase *Pred : Predecessors) { 234*0fca6ea1SDimitry Andric // Block and predecessor must be inside the same region. 235*0fca6ea1SDimitry Andric if (Pred->getParent() != VPB->getParent()) { 236*0fca6ea1SDimitry Andric errs() << "Predecessor is not in the same region.\n"; 237*0fca6ea1SDimitry Andric return false; 238*0fca6ea1SDimitry Andric } 239*0fca6ea1SDimitry Andric 240*0fca6ea1SDimitry Andric // There must be a bi-directional link between block and predecessor. 241*0fca6ea1SDimitry Andric const auto &PredSuccs = Pred->getSuccessors(); 242*0fca6ea1SDimitry Andric if (!is_contained(PredSuccs, VPB)) { 243*0fca6ea1SDimitry Andric errs() << "Missing successor link.\n"; 244*0fca6ea1SDimitry Andric return false; 245*0fca6ea1SDimitry Andric } 246*0fca6ea1SDimitry Andric } 247*0fca6ea1SDimitry Andric return !VPBB || verifyVPBasicBlock(VPBB); 248*0fca6ea1SDimitry Andric } 249*0fca6ea1SDimitry Andric 250*0fca6ea1SDimitry Andric bool VPlanVerifier::verifyBlocksInRegion(const VPRegionBlock *Region) { 251*0fca6ea1SDimitry Andric for (const VPBlockBase *VPB : vp_depth_first_shallow(Region->getEntry())) { 252*0fca6ea1SDimitry Andric // Check block's parent. 253*0fca6ea1SDimitry Andric if (VPB->getParent() != Region) { 254*0fca6ea1SDimitry Andric errs() << "VPBlockBase has wrong parent\n"; 255*0fca6ea1SDimitry Andric return false; 256*0fca6ea1SDimitry Andric } 257*0fca6ea1SDimitry Andric 258*0fca6ea1SDimitry Andric if (!verifyBlock(VPB)) 259*0fca6ea1SDimitry Andric return false; 260*0fca6ea1SDimitry Andric } 261*0fca6ea1SDimitry Andric return true; 262*0fca6ea1SDimitry Andric } 263*0fca6ea1SDimitry Andric 264*0fca6ea1SDimitry Andric bool VPlanVerifier::verifyRegion(const VPRegionBlock *Region) { 265*0fca6ea1SDimitry Andric const VPBlockBase *Entry = Region->getEntry(); 266*0fca6ea1SDimitry Andric const VPBlockBase *Exiting = Region->getExiting(); 267*0fca6ea1SDimitry Andric 268*0fca6ea1SDimitry Andric // Entry and Exiting shouldn't have any predecessor/successor, respectively. 269*0fca6ea1SDimitry Andric if (Entry->getNumPredecessors() != 0) { 270*0fca6ea1SDimitry Andric errs() << "region entry block has predecessors\n"; 271*0fca6ea1SDimitry Andric return false; 272*0fca6ea1SDimitry Andric } 273*0fca6ea1SDimitry Andric if (Exiting->getNumSuccessors() != 0) { 274*0fca6ea1SDimitry Andric errs() << "region exiting block has successors\n"; 275*0fca6ea1SDimitry Andric return false; 276*0fca6ea1SDimitry Andric } 277*0fca6ea1SDimitry Andric 278*0fca6ea1SDimitry Andric return verifyBlocksInRegion(Region); 279*0fca6ea1SDimitry Andric } 280*0fca6ea1SDimitry Andric 281*0fca6ea1SDimitry Andric bool VPlanVerifier::verifyRegionRec(const VPRegionBlock *Region) { 282*0fca6ea1SDimitry Andric // Recurse inside nested regions and check all blocks inside the region. 283*0fca6ea1SDimitry Andric return verifyRegion(Region) && 284*0fca6ea1SDimitry Andric all_of(vp_depth_first_shallow(Region->getEntry()), 285*0fca6ea1SDimitry Andric [this](const VPBlockBase *VPB) { 286*0fca6ea1SDimitry Andric const auto *SubRegion = dyn_cast<VPRegionBlock>(VPB); 287*0fca6ea1SDimitry Andric return !SubRegion || verifyRegionRec(SubRegion); 288*0fca6ea1SDimitry Andric }); 289*0fca6ea1SDimitry Andric } 290*0fca6ea1SDimitry Andric 291*0fca6ea1SDimitry Andric bool VPlanVerifier::verify(const VPlan &Plan) { 292*0fca6ea1SDimitry Andric if (any_of(vp_depth_first_shallow(Plan.getEntry()), 293*0fca6ea1SDimitry Andric [this](const VPBlockBase *VPB) { return !verifyBlock(VPB); })) 294*0fca6ea1SDimitry Andric return false; 295*0fca6ea1SDimitry Andric 29681ad6265SDimitry Andric const VPRegionBlock *TopRegion = Plan.getVectorLoopRegion(); 297*0fca6ea1SDimitry Andric if (!verifyRegionRec(TopRegion)) 298*0fca6ea1SDimitry Andric return false; 299*0fca6ea1SDimitry Andric 300*0fca6ea1SDimitry Andric if (TopRegion->getParent()) { 301*0fca6ea1SDimitry Andric errs() << "VPlan Top Region should have no parent.\n"; 302*0fca6ea1SDimitry Andric return false; 303*0fca6ea1SDimitry Andric } 304*0fca6ea1SDimitry Andric 3050eae32dcSDimitry Andric const VPBasicBlock *Entry = dyn_cast<VPBasicBlock>(TopRegion->getEntry()); 3060eae32dcSDimitry Andric if (!Entry) { 3070eae32dcSDimitry Andric errs() << "VPlan entry block is not a VPBasicBlock\n"; 3080eae32dcSDimitry Andric return false; 3090eae32dcSDimitry Andric } 31004eeddc0SDimitry Andric 31104eeddc0SDimitry Andric if (!isa<VPCanonicalIVPHIRecipe>(&*Entry->begin())) { 31204eeddc0SDimitry Andric errs() << "VPlan vector loop header does not start with a " 31304eeddc0SDimitry Andric "VPCanonicalIVPHIRecipe\n"; 31404eeddc0SDimitry Andric return false; 31504eeddc0SDimitry Andric } 31604eeddc0SDimitry Andric 31781ad6265SDimitry Andric const VPBasicBlock *Exiting = dyn_cast<VPBasicBlock>(TopRegion->getExiting()); 31881ad6265SDimitry Andric if (!Exiting) { 31981ad6265SDimitry Andric errs() << "VPlan exiting block is not a VPBasicBlock\n"; 3200eae32dcSDimitry Andric return false; 3210eae32dcSDimitry Andric } 3220eae32dcSDimitry Andric 32381ad6265SDimitry Andric if (Exiting->empty()) { 324753f127fSDimitry Andric errs() << "VPlan vector loop exiting block must end with BranchOnCount or " 325753f127fSDimitry Andric "BranchOnCond VPInstruction but is empty\n"; 32604eeddc0SDimitry Andric return false; 32704eeddc0SDimitry Andric } 32804eeddc0SDimitry Andric 32981ad6265SDimitry Andric auto *LastInst = dyn_cast<VPInstruction>(std::prev(Exiting->end())); 330753f127fSDimitry Andric if (!LastInst || (LastInst->getOpcode() != VPInstruction::BranchOnCount && 331753f127fSDimitry Andric LastInst->getOpcode() != VPInstruction::BranchOnCond)) { 332753f127fSDimitry Andric errs() << "VPlan vector loop exit must end with BranchOnCount or " 333753f127fSDimitry Andric "BranchOnCond VPInstruction\n"; 33404eeddc0SDimitry Andric return false; 33504eeddc0SDimitry Andric } 33604eeddc0SDimitry Andric 337bdd1243dSDimitry Andric for (const auto &KV : Plan.getLiveOuts()) 33881ad6265SDimitry Andric if (KV.second->getNumOperands() != 1) { 33981ad6265SDimitry Andric errs() << "live outs must have a single operand\n"; 34081ad6265SDimitry Andric return false; 34181ad6265SDimitry Andric } 34281ad6265SDimitry Andric 343349cc55cSDimitry Andric return true; 344349cc55cSDimitry Andric } 345*0fca6ea1SDimitry Andric 346*0fca6ea1SDimitry Andric bool llvm::verifyVPlanIsValid(const VPlan &Plan) { 347*0fca6ea1SDimitry Andric VPDominatorTree VPDT; 348*0fca6ea1SDimitry Andric VPDT.recalculate(const_cast<VPlan &>(Plan)); 349*0fca6ea1SDimitry Andric VPlanVerifier Verifier(VPDT); 350*0fca6ea1SDimitry Andric return Verifier.verify(Plan); 351*0fca6ea1SDimitry Andric } 352