Skip to content

Commit 2ae1d69

Browse files
committed
[VPlan] Delay adding canonical IV increment and exit branches.
This patch delays adding canonical IV increments, computing the next active lane mask and the branch recipes to exit the vector loop. During initial construction of a VPlan, only add the canonical IV phi and active-lane-mask phis if needed. Similarly, do not add the branches to exit the loop initially. Computing the next IV value, the next active-lane-mask or the exit branches are details that are only needed to simplify codegen (execute of the individual recipes). This makes the inital VPlans more abstract (and simpler), in that we initially leave out some details. Initial VPlans still have the canonical induction recipe, which provides the value of the canonical induction at every iteration, but we leave out the detail of how it is computed, which is not needed until code generation. Similar reasoning applies to active lane mask increments and branch recipes. The vector loop region initially abstractly models the loop processing all vector iterations, without specifying how exactly exiting the region is handled. Again these details are only needed for code generation. To introduce the missing pieces and complete the abstract VPlan, a new prepareToExecute transform is added and run just before exiting the VPlan. This is an attempt to further employ gradual lowering, as outlined in https://llvm.org/devmtg/2023-10/slides/techtalks/Hahn-VPlan-StatusUpdateAndRoadmap.pdf and already applied for replicate region handling.
1 parent d6bbe2e commit 2ae1d69

28 files changed

+237
-206
lines changed

llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7428,6 +7428,14 @@ LoopVectorizationPlanner::executePlan(
74287428
"expanded SCEVs to reuse can only be used during epilogue vectorization");
74297429
(void)IsEpilogueVectorization;
74307430

7431+
TailFoldingStyle Style =
7432+
CM.getTailFoldingStyle(!isIndvarOverflowCheckKnownFalse(&CM, BestVF));
7433+
// When not folding the tail, we know that the induction increment will not
7434+
// overflow.
7435+
bool HasNUW = Style == TailFoldingStyle::None;
7436+
bool WithoutRuntimeCheck =
7437+
Style == TailFoldingStyle::DataAndControlFlowWithoutRuntimeCheck;
7438+
VPlanTransforms::finalizePlan(BestVPlan, HasNUW, WithoutRuntimeCheck);
74317439
VPlanTransforms::optimizeForVFAndUF(BestVPlan, BestVF, BestUF, PSE);
74327440

74337441
LLVM_DEBUG(dbgs() << "Executing best plan with VF=" << BestVF
@@ -8467,17 +8475,16 @@ void LoopVectorizationPlanner::buildVPlansWithVPRecipes(ElementCount MinVF,
84678475
if (CM.foldTailWithEVL() &&
84688476
!VPlanTransforms::tryAddExplicitVectorLength(*Plan))
84698477
break;
8470-
assert(verifyVPlanIsValid(*Plan) && "VPlan is invalid");
8478+
assert(verifyVPlanIsValid(*Plan, /*IsAbstract*/ true) &&
8479+
"VPlan is invalid");
84718480
VPlans.push_back(std::move(Plan));
84728481
}
84738482
VF = SubRange.End;
84748483
}
84758484
}
84768485

8477-
// Add the necessary canonical IV and branch recipes required to control the
8478-
// loop.
8479-
static void addCanonicalIVRecipes(VPlan &Plan, Type *IdxTy, bool HasNUW,
8480-
DebugLoc DL) {
8486+
// Add the required canonical IV.
8487+
static void addCanonicalIV(VPlan &Plan, Type *IdxTy, bool HasNUW, DebugLoc DL) {
84818488
Value *StartIdx = ConstantInt::get(IdxTy, 0);
84828489
auto *StartV = Plan.getOrAddLiveIn(StartIdx);
84838490

@@ -8486,17 +8493,6 @@ static void addCanonicalIVRecipes(VPlan &Plan, Type *IdxTy, bool HasNUW,
84868493
VPRegionBlock *TopRegion = Plan.getVectorLoopRegion();
84878494
VPBasicBlock *Header = TopRegion->getEntryBasicBlock();
84888495
Header->insert(CanonicalIVPHI, Header->begin());
8489-
8490-
VPBuilder Builder(TopRegion->getExitingBasicBlock());
8491-
// Add a VPInstruction to increment the scalar canonical IV by VF * UF.
8492-
auto *CanonicalIVIncrement = Builder.createOverflowingOp(
8493-
Instruction::Add, {CanonicalIVPHI, &Plan.getVFxUF()}, {HasNUW, false}, DL,
8494-
"index.next");
8495-
CanonicalIVPHI->addOperand(CanonicalIVIncrement);
8496-
8497-
// Add the BranchOnCount VPInstruction to the latch.
8498-
Builder.createNaryOp(VPInstruction::BranchOnCount,
8499-
{CanonicalIVIncrement, &Plan.getVectorTripCount()}, DL);
85008496
}
85018497

85028498
// Add exit values to \p Plan. VPLiveOuts are added for each LCSSA phi in the
@@ -8555,7 +8551,7 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
85558551
// When not folding the tail, we know that the induction increment will not
85568552
// overflow.
85578553
bool HasNUW = Style == TailFoldingStyle::None;
8558-
addCanonicalIVRecipes(*Plan, Legal->getWidestInductionType(), HasNUW, DL);
8554+
addCanonicalIV(*Plan, Legal->getWidestInductionType(), HasNUW, DL);
85598555

85608556
VPRecipeBuilder RecipeBuilder(*Plan, OrigLoop, TLI, Legal, CM, PSE, Builder);
85618557

@@ -8806,9 +8802,8 @@ VPlanPtr LoopVectorizationPlanner::buildVPlan(VFRange &Range) {
88068802
// Tail folding is not supported for outer loops, so the induction increment
88078803
// is guaranteed to not wrap.
88088804
bool HasNUW = true;
8809-
addCanonicalIVRecipes(*Plan, Legal->getWidestInductionType(), HasNUW,
8810-
DebugLoc());
8811-
assert(verifyVPlanIsValid(*Plan) && "VPlan is invalid");
8805+
addCanonicalIV(*Plan, Legal->getWidestInductionType(), HasNUW, DebugLoc());
8806+
assert(verifyVPlanIsValid(*Plan, /*IsAbstract*/ true) && "VPlan is invalid");
88128807
return Plan;
88138808
}
88148809

@@ -8991,7 +8986,7 @@ void LoopVectorizationPlanner::adjustRecipesForReductions(
89918986
PreviousLink = RedRecipe;
89928987
}
89938988
}
8994-
Builder.setInsertPoint(&*LatchVPBB->begin());
8989+
Builder.setInsertPoint(LatchVPBB, LatchVPBB->begin());
89958990
for (VPRecipeBase &R :
89968991
Plan->getVectorLoopRegion()->getEntryBasicBlock()->phis()) {
89978992
VPReductionPHIRecipe *PhiR = dyn_cast<VPReductionPHIRecipe>(&R);

llvm/lib/Transforms/Vectorize/VPlan.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "VPlanCFG.h"
2121
#include "VPlanDominatorTree.h"
2222
#include "VPlanPatternMatch.h"
23+
#include "VPlanVerifier.h"
2324
#include "llvm/ADT/PostOrderIterator.h"
2425
#include "llvm/ADT/STLExtras.h"
2526
#include "llvm/ADT/SmallVector.h"
@@ -841,6 +842,8 @@ void VPlan::prepareToExecute(Value *TripCountV, Value *VectorTripCountV,
841842
/// Assumes a single pre-header basic-block was created for this. Introduce
842843
/// additional basic-blocks as needed, and fill them all.
843844
void VPlan::execute(VPTransformState *State) {
845+
assert(verifyVPlanIsValid(*this, /*IsAbstract*/ false) && "VPlan is invalid");
846+
844847
// Initialize CFG state.
845848
State->CFG.PrevVPBB = nullptr;
846849
State->CFG.ExitBB = State->CFG.PrevBB->getSingleSuccessor();

llvm/lib/Transforms/Vectorize/VPlan.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2580,7 +2580,8 @@ class VPCanonicalIVPHIRecipe : public VPHeaderPHIRecipe {
25802580

25812581
VPCanonicalIVPHIRecipe *clone() override {
25822582
auto *R = new VPCanonicalIVPHIRecipe(getOperand(0), getDebugLoc());
2583-
R->addOperand(getBackedgeValue());
2583+
if (getNumOperands() == 2)
2584+
R->addOperand(getBackedgeValue());
25842585
return R;
25852586
}
25862587

llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp

Lines changed: 75 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,16 +1235,10 @@ void VPlanTransforms::optimize(VPlan &Plan, ScalarEvolution &SE) {
12351235
static VPActiveLaneMaskPHIRecipe *addVPLaneMaskPhiAndUpdateExitBranch(
12361236
VPlan &Plan, bool DataAndControlFlowWithoutRuntimeCheck) {
12371237
VPRegionBlock *TopRegion = Plan.getVectorLoopRegion();
1238-
VPBasicBlock *EB = TopRegion->getExitingBasicBlock();
12391238
auto *CanonicalIVPHI = Plan.getCanonicalIV();
12401239
VPValue *StartV = CanonicalIVPHI->getStartValue();
12411240

1242-
auto *CanonicalIVIncrement =
1243-
cast<VPInstruction>(CanonicalIVPHI->getBackedgeValue());
1244-
// TODO: Check if dropping the flags is needed if
1245-
// !DataAndControlFlowWithoutRuntimeCheck.
1246-
CanonicalIVIncrement->dropPoisonGeneratingFlags();
1247-
DebugLoc DL = CanonicalIVIncrement->getDebugLoc();
1241+
DebugLoc DL = CanonicalIVPHI->getDebugLoc();
12481242
// We can't use StartV directly in the ActiveLaneMask VPInstruction, since
12491243
// we have to take unrolling into account. Each part needs to start at
12501244
// Part * VF
@@ -1254,21 +1248,6 @@ static VPActiveLaneMaskPHIRecipe *addVPLaneMaskPhiAndUpdateExitBranch(
12541248
// Create the ActiveLaneMask instruction using the correct start values.
12551249
VPValue *TC = Plan.getTripCount();
12561250

1257-
VPValue *TripCount, *IncrementValue;
1258-
if (!DataAndControlFlowWithoutRuntimeCheck) {
1259-
// When the loop is guarded by a runtime overflow check for the loop
1260-
// induction variable increment by VF, we can increment the value before
1261-
// the get.active.lane mask and use the unmodified tripcount.
1262-
IncrementValue = CanonicalIVIncrement;
1263-
TripCount = TC;
1264-
} else {
1265-
// When avoiding a runtime check, the active.lane.mask inside the loop
1266-
// uses a modified trip count and the induction variable increment is
1267-
// done after the active.lane.mask intrinsic is called.
1268-
IncrementValue = CanonicalIVPHI;
1269-
TripCount = Builder.createNaryOp(VPInstruction::CalculateTripCountMinusVF,
1270-
{TC}, DL);
1271-
}
12721251
auto *EntryIncrement = Builder.createOverflowingOp(
12731252
VPInstruction::CanonicalIVIncrementForPart, {StartV}, {false, false}, DL,
12741253
"index.part.next");
@@ -1282,24 +1261,6 @@ static VPActiveLaneMaskPHIRecipe *addVPLaneMaskPhiAndUpdateExitBranch(
12821261
// preheader ActiveLaneMask instruction.
12831262
auto LaneMaskPhi = new VPActiveLaneMaskPHIRecipe(EntryALM, DebugLoc());
12841263
LaneMaskPhi->insertAfter(CanonicalIVPHI);
1285-
1286-
// Create the active lane mask for the next iteration of the loop before the
1287-
// original terminator.
1288-
VPRecipeBase *OriginalTerminator = EB->getTerminator();
1289-
Builder.setInsertPoint(OriginalTerminator);
1290-
auto *InLoopIncrement =
1291-
Builder.createOverflowingOp(VPInstruction::CanonicalIVIncrementForPart,
1292-
{IncrementValue}, {false, false}, DL);
1293-
auto *ALM = Builder.createNaryOp(VPInstruction::ActiveLaneMask,
1294-
{InLoopIncrement, TripCount}, DL,
1295-
"active.lane.mask.next");
1296-
LaneMaskPhi->addOperand(ALM);
1297-
1298-
// Replace the original terminator with BranchOnCond. We have to invert the
1299-
// mask here because a true condition means jumping to the exit block.
1300-
auto *NotMask = Builder.createNot(ALM, DL);
1301-
Builder.createNaryOp(VPInstruction::BranchOnCond, {NotMask}, DL);
1302-
OriginalTerminator->eraseFromParent();
13031264
return LaneMaskPhi;
13041265
}
13051266

@@ -1418,6 +1379,7 @@ bool VPlanTransforms::tryAddExplicitVectorLength(VPlan &Plan) {
14181379
return false;
14191380
auto *CanonicalIVPHI = Plan.getCanonicalIV();
14201381
VPValue *StartV = CanonicalIVPHI->getStartValue();
1382+
VPBasicBlock *Latch = Plan.getVectorLoopRegion()->getExitingBasicBlock();
14211383

14221384
// Create the ExplicitVectorLengthPhi recipe in the main loop.
14231385
auto *EVLPhi = new VPEVLBasedIVPHIRecipe(StartV, DebugLoc());
@@ -1426,22 +1388,18 @@ bool VPlanTransforms::tryAddExplicitVectorLength(VPlan &Plan) {
14261388
{EVLPhi, Plan.getTripCount()});
14271389
VPEVL->insertBefore(*Header, Header->getFirstNonPhi());
14281390

1429-
auto *CanonicalIVIncrement =
1430-
cast<VPInstruction>(CanonicalIVPHI->getBackedgeValue());
14311391
VPSingleDefRecipe *OpVPEVL = VPEVL;
14321392
if (unsigned IVSize = CanonicalIVPHI->getScalarType()->getScalarSizeInBits();
14331393
IVSize != 32) {
14341394
OpVPEVL = new VPScalarCastRecipe(IVSize < 32 ? Instruction::Trunc
14351395
: Instruction::ZExt,
14361396
OpVPEVL, CanonicalIVPHI->getScalarType());
1437-
OpVPEVL->insertBefore(CanonicalIVIncrement);
1397+
Latch->appendRecipe(OpVPEVL);
14381398
}
14391399
auto *NextEVLIV =
1440-
new VPInstruction(Instruction::Add, {OpVPEVL, EVLPhi},
1441-
{CanonicalIVIncrement->hasNoUnsignedWrap(),
1442-
CanonicalIVIncrement->hasNoSignedWrap()},
1443-
CanonicalIVIncrement->getDebugLoc(), "index.evl.next");
1444-
NextEVLIV->insertBefore(CanonicalIVIncrement);
1400+
new VPInstruction(Instruction::Add, {OpVPEVL, EVLPhi}, {false, false},
1401+
CanonicalIVPHI->getDebugLoc(), "index.evl.next");
1402+
Latch->appendRecipe(NextEVLIV);
14451403
EVLPhi->addOperand(NextEVLIV);
14461404

14471405
for (VPValue *HeaderMask : collectAllHeaderMasks(Plan)) {
@@ -1468,9 +1426,8 @@ bool VPlanTransforms::tryAddExplicitVectorLength(VPlan &Plan) {
14681426
recursivelyDeleteDeadRecipes(HeaderMask);
14691427
}
14701428
// Replace all uses of VPCanonicalIVPHIRecipe by
1471-
// VPEVLBasedIVPHIRecipe except for the canonical IV increment.
1429+
// VPEVLBasedIVPHIRecipe.
14721430
CanonicalIVPHI->replaceAllUsesWith(EVLPhi);
1473-
CanonicalIVIncrement->setOperand(0, CanonicalIVPHI);
14741431
// TODO: support unroll factor > 1.
14751432
Plan.setUF(1);
14761433
return true;
@@ -1572,3 +1529,71 @@ void VPlanTransforms::dropPoisonGeneratingRecipes(
15721529
}
15731530
}
15741531
}
1532+
1533+
void VPlanTransforms::finalizePlan(VPlan &Plan, bool HasNUW,
1534+
bool DataAndControlFlowWithoutRuntimeCheck) {
1535+
auto *CanIV = Plan.getCanonicalIV();
1536+
1537+
VPBasicBlock *EB = Plan.getVectorLoopRegion()->getExitingBasicBlock();
1538+
VPBuilder Builder(EB);
1539+
DebugLoc DL = CanIV->getDebugLoc();
1540+
// Add a VPInstruction to increment the scalar canonical IV by VF * UF.
1541+
auto *CanonicalIVIncrement =
1542+
Builder.createOverflowingOp(Instruction::Add, {CanIV, &Plan.getVFxUF()},
1543+
{HasNUW, false}, DL, "index.next");
1544+
1545+
CanIV->addOperand(CanonicalIVIncrement);
1546+
1547+
auto FoundLaneMaskPhi = find_if(
1548+
Plan.getVectorLoopRegion()->getEntryBasicBlock()->phis(),
1549+
[](VPRecipeBase &P) { return isa<VPActiveLaneMaskPHIRecipe>(P); });
1550+
1551+
if (FoundLaneMaskPhi ==
1552+
Plan.getVectorLoopRegion()->getEntryBasicBlock()->phis().end()) {
1553+
// Add the BranchOnCount VPInstruction to the latch.
1554+
Builder.createNaryOp(VPInstruction::BranchOnCount,
1555+
{CanonicalIVIncrement, &Plan.getVectorTripCount()},
1556+
DL);
1557+
return;
1558+
}
1559+
auto *LaneMaskPhi = cast<VPActiveLaneMaskPHIRecipe>(&*FoundLaneMaskPhi);
1560+
auto *VecPreheader =
1561+
cast<VPBasicBlock>(Plan.getVectorLoopRegion()->getSinglePredecessor());
1562+
Builder.setInsertPoint(VecPreheader);
1563+
1564+
VPValue *TC = Plan.getTripCount();
1565+
1566+
// TODO: Check if dropping the flags is needed if
1567+
// !DataAndControlFlowWithoutRuntimeCheck.
1568+
CanonicalIVIncrement->dropPoisonGeneratingFlags();
1569+
VPValue *TripCount, *IncrementValue;
1570+
if (!DataAndControlFlowWithoutRuntimeCheck) {
1571+
// When the loop is guarded by a runtime overflow check for the loop
1572+
// induction variable increment by VF, we can increment the value before
1573+
// the get.active.lane mask and use the unmodified tripcount.
1574+
IncrementValue = CanonicalIVIncrement;
1575+
TripCount = TC;
1576+
} else {
1577+
// When avoiding a runtime check, the active.lane.mask inside the loop
1578+
// uses a modified trip count and the induction variable increment is
1579+
// done after the active.lane.mask intrinsic is called.
1580+
IncrementValue = CanIV;
1581+
TripCount = Builder.createNaryOp(VPInstruction::CalculateTripCountMinusVF,
1582+
{TC}, DL);
1583+
}
1584+
// Create the active lane mask for the next iteration of the loop before the
1585+
// original terminator.
1586+
Builder.setInsertPoint(EB);
1587+
auto *InLoopIncrement =
1588+
Builder.createOverflowingOp(VPInstruction::CanonicalIVIncrementForPart,
1589+
{IncrementValue}, {false, false}, DL);
1590+
auto *ALM = Builder.createNaryOp(VPInstruction::ActiveLaneMask,
1591+
{InLoopIncrement, TripCount}, DL,
1592+
"active.lane.mask.next");
1593+
LaneMaskPhi->addOperand(ALM);
1594+
1595+
// Replace the original terminator with BranchOnCond. We have to invert the
1596+
// mask here because a true condition means jumping to the exit block.
1597+
auto *NotMask = Builder.createNot(ALM, DL);
1598+
Builder.createNaryOp(VPInstruction::BranchOnCond, {NotMask}, DL);
1599+
}

llvm/lib/Transforms/Vectorize/VPlanTransforms.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ struct VPlanTransforms {
106106
/// this transformation.
107107
/// \returns true if the transformation succeeds, or false if it doesn't.
108108
static bool tryAddExplicitVectorLength(VPlan &Plan);
109+
110+
/// Finalize \p Plan by introducing recipes needed for code-gen, like
111+
/// introducing explicit increments for the canonical induction and the branch
112+
/// to exit the vector loop.
113+
static void finalizePlan(VPlan &Plan, bool HasNUW,
114+
bool DataAndControlFlowWithoutRuntimeCheck);
109115
};
110116

111117
} // namespace llvm

llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class VPlanVerifier {
3030

3131
SmallPtrSet<BasicBlock *, 8> WrappedIRBBs;
3232

33+
bool IsAbstract;
34+
3335
// Verify that phi-like recipes are at the beginning of \p VPBB, with no
3436
// other recipes in between. Also check that only header blocks contain
3537
// VPHeaderPHIRecipes.
@@ -54,7 +56,8 @@ class VPlanVerifier {
5456
bool verifyRegionRec(const VPRegionBlock *Region);
5557

5658
public:
57-
VPlanVerifier(VPDominatorTree &VPDT) : VPDT(VPDT) {}
59+
VPlanVerifier(VPDominatorTree &VPDT, bool IsAbstract)
60+
: VPDT(VPDT), IsAbstract(IsAbstract) {}
5861

5962
bool verify(const VPlan &Plan);
6063
};
@@ -185,7 +188,7 @@ bool VPlanVerifier::verifyBlock(const VPBlockBase *VPB) {
185188
if (VPB->getNumSuccessors() > 1 ||
186189
(VPBB && VPBB->getParent() && VPBB->isExiting() &&
187190
!VPBB->getParent()->isReplicator())) {
188-
if (!VPBB || !VPBB->getTerminator()) {
191+
if (!IsAbstract && (!VPBB || !VPBB->getTerminator())) {
189192
errs() << "Block has multiple successors but doesn't "
190193
"have a proper branch recipe!\n";
191194
return false;
@@ -315,18 +318,20 @@ bool VPlanVerifier::verify(const VPlan &Plan) {
315318
return false;
316319
}
317320

318-
if (Exiting->empty()) {
319-
errs() << "VPlan vector loop exiting block must end with BranchOnCount or "
320-
"BranchOnCond VPInstruction but is empty\n";
321-
return false;
322-
}
321+
if (!IsAbstract) {
322+
if (Exiting->empty()) {
323+
errs() << "VPlan vector loop exiting block must end with BranchOnCount or"
324+
"BranchOnCond VPInstruction but is empty\n";
325+
return false;
326+
}
323327

324-
auto *LastInst = dyn_cast<VPInstruction>(std::prev(Exiting->end()));
325-
if (!LastInst || (LastInst->getOpcode() != VPInstruction::BranchOnCount &&
326-
LastInst->getOpcode() != VPInstruction::BranchOnCond)) {
327-
errs() << "VPlan vector loop exit must end with BranchOnCount or "
328-
"BranchOnCond VPInstruction\n";
329-
return false;
328+
auto *LastInst = dyn_cast<VPInstruction>(std::prev(Exiting->end()));
329+
if (!LastInst || (LastInst->getOpcode() != VPInstruction::BranchOnCount &&
330+
LastInst->getOpcode() != VPInstruction::BranchOnCond)) {
331+
errs() << "VPlan vector loop exit must end with BranchOnCount or "
332+
"BranchOnCond VPInstruction\n";
333+
return false;
334+
}
330335
}
331336

332337
for (const auto &KV : Plan.getLiveOuts())
@@ -338,9 +343,9 @@ bool VPlanVerifier::verify(const VPlan &Plan) {
338343
return true;
339344
}
340345

341-
bool llvm::verifyVPlanIsValid(const VPlan &Plan) {
346+
bool llvm::verifyVPlanIsValid(const VPlan &Plan, bool IsAbstract) {
342347
VPDominatorTree VPDT;
343348
VPDT.recalculate(const_cast<VPlan &>(Plan));
344-
VPlanVerifier Verifier(VPDT);
349+
VPlanVerifier Verifier(VPDT, IsAbstract);
345350
return Verifier.verify(Plan);
346351
}

llvm/lib/Transforms/Vectorize/VPlanVerifier.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ class VPlan;
3333
/// 2. all phi-like recipes must be at the beginning of a block, with no other
3434
/// recipes in between. Note that currently there is still an exception for
3535
/// VPBlendRecipes.
36-
bool verifyVPlanIsValid(const VPlan &Plan);
36+
/// If \p IsAbstract, consider the VPlan to check as abstract, which means some
37+
/// aspects may not be finalized yet, for example, no terminators have been
38+
/// added to exit loop regions.
39+
bool verifyVPlanIsValid(const VPlan &Plan, bool IsAbstract = false);
3740

3841
} // namespace llvm
3942

0 commit comments

Comments
 (0)