Skip to content

Commit d93551a

Browse files
fhahnAnkur-0429
authored andcommitted
[VPlan] Add exit phi operands during initial construction (NFC). (llvm#136455)
Add incoming exit phi operands during the initial VPlan construction. This ensures all users are added to the initial VPlan and is also needed in preparation to retaining exiting edges during initial construction. PR: llvm#136455
1 parent 71f8aed commit d93551a

File tree

5 files changed

+68
-38
lines changed

5 files changed

+68
-38
lines changed

llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9373,11 +9373,8 @@ static void addScalarResumePhis(VPRecipeBuilder &Builder, VPlan &Plan,
93739373
}
93749374
}
93759375

9376-
// Collect VPIRInstructions for phis in the exit blocks that are modeled
9377-
// in VPlan and add the exiting VPValue as operand.
9378-
static SetVector<VPIRInstruction *>
9379-
collectUsersInExitBlocks(Loop *OrigLoop, VPRecipeBuilder &Builder,
9380-
VPlan &Plan) {
9376+
// Collect VPIRInstructions for phis in the exit block from the latch only.
9377+
static SetVector<VPIRInstruction *> collectUsersInLatchExitBlock(VPlan &Plan) {
93819378
SetVector<VPIRInstruction *> ExitUsersToFix;
93829379
for (VPIRBasicBlock *ExitVPBB : Plan.getExitBlocks()) {
93839380
// Nothing to do for unreachable exit blocks.
@@ -9393,11 +9390,8 @@ collectUsersInExitBlocks(Loop *OrigLoop, VPRecipeBuilder &Builder,
93939390
continue;
93949391
}
93959392

9396-
PHINode &ExitPhi = ExitIRI->getIRPhi();
9397-
BasicBlock *ExitingBB = OrigLoop->getLoopLatch();
9398-
Value *IncomingValue = ExitPhi.getIncomingValueForBlock(ExitingBB);
9399-
VPValue *V = Builder.getVPValueOrAddLiveIn(IncomingValue);
9400-
ExitIRI->addOperand(V);
9393+
assert(ExitIRI->getNumOperands() == 1 && "must have a single operand");
9394+
VPValue *V = ExitIRI->getOperand(0);
94019395
if (V->isLiveIn())
94029396
continue;
94039397
assert(V->getDefiningRecipe()->getParent()->getEnclosingLoopRegion() &&
@@ -9426,7 +9420,7 @@ addUsersInExitBlocks(VPlan &Plan,
94269420
ExitIRI->getParent()->getSinglePredecessor() == MiddleVPBB &&
94279421
"exit values from early exits must be fixed when branch to "
94289422
"early-exit is added");
9429-
ExitIRI->extractLastLaneOfOperand(B);
9423+
ExitIRI->extractLastLaneOfFirstOperand(B);
94309424
}
94319425
}
94329426

@@ -9767,7 +9761,7 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
97679761
DenseMap<VPValue *, VPValue *> IVEndValues;
97689762
addScalarResumePhis(RecipeBuilder, *Plan, IVEndValues);
97699763
SetVector<VPIRInstruction *> ExitUsersToFix =
9770-
collectUsersInExitBlocks(OrigLoop, RecipeBuilder, *Plan);
9764+
collectUsersInLatchExitBlock(*Plan);
97719765
addExitUsersForFirstOrderRecurrences(*Plan, ExitUsersToFix);
97729766
addUsersInExitBlocks(*Plan, ExitUsersToFix);
97739767

llvm/lib/Transforms/Vectorize/VPlan.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,10 +1161,10 @@ class VPIRInstruction : public VPRecipeBase {
11611161
return true;
11621162
}
11631163

1164-
/// Update the recipes single operand to the last lane of the operand using \p
1165-
/// Builder. Must only be used for single operand VPIRInstructions wrapping a
1166-
/// PHINode.
1167-
void extractLastLaneOfOperand(VPBuilder &Builder);
1164+
/// Update the recipes first operand to the last lane of the operand using \p
1165+
/// Builder. Must only be used for VPIRInstructions with at least one operand
1166+
/// wrapping a PHINode.
1167+
void extractLastLaneOfFirstOperand(VPBuilder &Builder);
11681168
};
11691169

11701170
/// An overlay for VPIRInstructions wrapping PHI nodes enabling convenient use

llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,23 @@ std::unique_ptr<VPlan> PlainCFGBuilder::buildPlainCFG(
352352
Plan->getEntry()->setOneSuccessor(getOrCreateVPBB(TheLoop->getHeader()));
353353
Plan->getEntry()->setPlan(&*Plan);
354354

355+
// Fix VPlan loop-closed-ssa exit phi's by adding incoming operands to the
356+
// VPIRInstructions wrapping them.
357+
// // Note that the operand order corresponds to IR predecessor order, and may
358+
// need adjusting when VPlan predecessors are added, if an exit block has
359+
// multiple predecessor.
360+
for (auto *EB : Plan->getExitBlocks()) {
361+
for (VPRecipeBase &R : EB->phis()) {
362+
auto *PhiR = cast<VPIRPhi>(&R);
363+
PHINode &Phi = PhiR->getIRPhi();
364+
assert(PhiR->getNumOperands() == 0 &&
365+
"no phi operands should be added yet");
366+
for (BasicBlock *Pred : predecessors(EB->getIRBasicBlock()))
367+
PhiR->addOperand(
368+
getOrCreateVPOperand(Phi.getIncomingValueForBlock(Pred)));
369+
}
370+
}
371+
355372
for (const auto &[IRBB, VPB] : BB2VPBB)
356373
VPB2IRBB[VPB] = IRBB;
357374

@@ -462,19 +479,28 @@ void VPlanTransforms::createLoopRegions(VPlan &Plan, Type *InductionTy,
462479

463480
VPBasicBlock *ScalarPH = Plan.createVPBasicBlock("scalar.ph");
464481
VPBlockUtils::connectBlocks(ScalarPH, Plan.getScalarHeader());
465-
if (!RequiresScalarEpilogueCheck) {
466-
VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
467-
return;
468-
}
469482

470483
// If needed, add a check in the middle block to see if we have completed
471484
// all of the iterations in the first vector loop. Three cases:
472-
// 1) If (N - N%VF) == N, then we *don't* need to run the remainder.
485+
// 1) If we require a scalar epilogue, there is no conditional branch as
486+
// we unconditionally branch to the scalar preheader. Remove the recipes
487+
// from the exit blocks.
488+
// 2) If (N - N%VF) == N, then we *don't* need to run the remainder.
473489
// Thus if tail is to be folded, we know we don't need to run the
474490
// remainder and we can set the condition to true.
475-
// 2) If we require a scalar epilogue, there is no conditional branch as
476-
// we unconditionally branch to the scalar preheader. Do nothing.
477491
// 3) Otherwise, construct a runtime check.
492+
493+
if (!RequiresScalarEpilogueCheck) {
494+
VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
495+
// The exit blocks are unreachable, remove their recipes to make sure no
496+
// users remain that may pessimize transforms.
497+
for (auto *EB : Plan.getExitBlocks()) {
498+
for (VPRecipeBase &R : make_early_inc_range(*EB))
499+
R.eraseFromParent();
500+
}
501+
return;
502+
}
503+
478504
BasicBlock *IRExitBlock = TheLoop->getUniqueLatchExitBlock();
479505
auto *VPExitBlock = Plan.getExitBlock(IRExitBlock);
480506
// The connection order corresponds to the operands of the conditional branch.

llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,10 +1137,10 @@ InstructionCost VPIRInstruction::computeCost(ElementCount VF,
11371137
return 0;
11381138
}
11391139

1140-
void VPIRInstruction::extractLastLaneOfOperand(VPBuilder &Builder) {
1140+
void VPIRInstruction::extractLastLaneOfFirstOperand(VPBuilder &Builder) {
11411141
assert(isa<PHINode>(getInstruction()) &&
1142-
"can only add exiting operands to phi nodes");
1143-
assert(getNumOperands() == 1 && "must have a single operand");
1142+
"can only update exiting operands to phi nodes");
1143+
assert(getNumOperands() > 0 && "must have at least one operand");
11441144
VPValue *Exiting = getOperand(0);
11451145
if (!Exiting->isLiveIn()) {
11461146
LLVMContext &Ctx = getInstruction().getContext();

llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2505,35 +2505,45 @@ void VPlanTransforms::handleUncountableEarlyExit(
25052505
VPBuilder EarlyExitB(VectorEarlyExitVPBB);
25062506
for (VPRecipeBase &R : VPEarlyExitBlock->phis()) {
25072507
auto *ExitIRI = cast<VPIRPhi>(&R);
2508-
PHINode &ExitPhi = ExitIRI->getIRPhi();
2509-
VPValue *IncomingFromEarlyExit = RecipeBuilder.getVPValueOrAddLiveIn(
2510-
ExitPhi.getIncomingValueForBlock(UncountableExitingBlock));
2511-
2508+
// Early exit operand should always be last, i.e., 0 if VPEarlyExitBlock has
2509+
// a single predecessor and 1 if it has two.
2510+
unsigned EarlyExitIdx = ExitIRI->getNumOperands() - 1;
25122511
if (OrigLoop->getUniqueExitBlock()) {
2513-
// If there's a unique exit block, VPEarlyExitBlock has 2 predecessors
2514-
// (MiddleVPBB and NewMiddle). Add the incoming value from MiddleVPBB
2515-
// which is coming from the original latch.
2516-
VPValue *IncomingFromLatch = RecipeBuilder.getVPValueOrAddLiveIn(
2517-
ExitPhi.getIncomingValueForBlock(OrigLoop->getLoopLatch()));
2518-
ExitIRI->addOperand(IncomingFromLatch);
2519-
ExitIRI->extractLastLaneOfOperand(MiddleBuilder);
2512+
// If VPEarlyExitBlock has two predecessors, they are already ordered such
2513+
// that early exit is second (and latch exit is first), by construction.
2514+
// But its underlying IRBB (EarlyExitIRBB) may have its predecessors
2515+
// ordered the other way around, and it is the order of the latter which
2516+
// corresponds to the order of operands of VPEarlyExitBlock's phi recipes.
2517+
// Therefore, if early exit (UncountableExitingBlock) is the first
2518+
// predecessor of EarlyExitIRBB, we swap the operands of phi recipes,
2519+
// thereby bringing them to match VPEarlyExitBlock's predecessor order,
2520+
// with early exit being last (second). Otherwise they already match.
2521+
if (*pred_begin(VPEarlyExitBlock->getIRBasicBlock()) ==
2522+
UncountableExitingBlock)
2523+
ExitIRI->swapOperands();
2524+
2525+
// The first of two operands corresponds to the latch exit, via MiddleVPBB
2526+
// predecessor. Extract its last lane.
2527+
ExitIRI->extractLastLaneOfFirstOperand(MiddleBuilder);
25202528
}
25212529

2530+
VPValue *IncomingFromEarlyExit = ExitIRI->getOperand(EarlyExitIdx);
25222531
auto IsVector = [](ElementCount VF) { return VF.isVector(); };
25232532
// When the VFs are vectors, need to add `extract` to get the incoming value
25242533
// from early exit. When the range contains scalar VF, limit the range to
25252534
// scalar VF to prevent mis-compilation for the range containing both scalar
25262535
// and vector VFs.
25272536
if (!IncomingFromEarlyExit->isLiveIn() &&
25282537
LoopVectorizationPlanner::getDecisionAndClampRange(IsVector, Range)) {
2538+
// Update the incoming value from the early exit.
25292539
VPValue *FirstActiveLane = EarlyExitB.createNaryOp(
25302540
VPInstruction::FirstActiveLane, {EarlyExitTakenCond}, nullptr,
25312541
"first.active.lane");
25322542
IncomingFromEarlyExit = EarlyExitB.createNaryOp(
25332543
Instruction::ExtractElement, {IncomingFromEarlyExit, FirstActiveLane},
25342544
nullptr, "early.exit.value");
2545+
ExitIRI->setOperand(EarlyExitIdx, IncomingFromEarlyExit);
25352546
}
2536-
ExitIRI->addOperand(IncomingFromEarlyExit);
25372547
}
25382548
MiddleBuilder.createNaryOp(VPInstruction::BranchOnCond, {IsEarlyExitTaken});
25392549

0 commit comments

Comments
 (0)