Skip to content

Commit 4d1959b

Browse files
authored
[VPlan] Generalize collectUsersInExitBlocks for multiple exit bbs. (#115066)
Generalize collectUsersInExitBlock to collecting exit users in multiple exit blocks. Exit blocks are leaf nodes in the VPlan (without successors) except the scalar header. Split off in preparation for #112138 PR: #115066
1 parent 3200385 commit 4d1959b

File tree

3 files changed

+55
-38
lines changed

3 files changed

+55
-38
lines changed

llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8864,56 +8864,56 @@ static void addScalarResumePhis(VPRecipeBuilder &Builder, VPlan &Plan) {
88648864
}
88658865
}
88668866

8867-
// Collect VPIRInstructions for phis in the original exit block that are modeled
8867+
// Collect VPIRInstructions for phis in the exit blocks that are modeled
88688868
// in VPlan and add the exiting VPValue as operand. Some exiting values are not
88698869
// modeled explicitly yet and won't be included. Those are un-truncated
88708870
// VPWidenIntOrFpInductionRecipe, VPWidenPointerInductionRecipe and induction
88718871
// increments.
8872-
static SetVector<VPIRInstruction *> collectUsersInExitBlock(
8872+
static SetVector<VPIRInstruction *> collectUsersInExitBlocks(
88738873
Loop *OrigLoop, VPRecipeBuilder &Builder, VPlan &Plan,
88748874
const MapVector<PHINode *, InductionDescriptor> &Inductions) {
8875-
auto *MiddleVPBB = Plan.getMiddleBlock();
8876-
// No edge from the middle block to the unique exit block has been inserted
8877-
// and there is nothing to fix from vector loop; phis should have incoming
8878-
// from scalar loop only.
8879-
if (MiddleVPBB->getNumSuccessors() != 2)
8880-
return {};
88818875
SetVector<VPIRInstruction *> ExitUsersToFix;
8882-
VPBasicBlock *ExitVPBB = cast<VPIRBasicBlock>(MiddleVPBB->getSuccessors()[0]);
8883-
BasicBlock *ExitingBB = OrigLoop->getExitingBlock();
8884-
for (VPRecipeBase &R : *ExitVPBB) {
8885-
auto *ExitIRI = dyn_cast<VPIRInstruction>(&R);
8886-
if (!ExitIRI)
8887-
continue;
8888-
auto *ExitPhi = dyn_cast<PHINode>(&ExitIRI->getInstruction());
8889-
if (!ExitPhi)
8890-
break;
8891-
Value *IncomingValue = ExitPhi->getIncomingValueForBlock(ExitingBB);
8892-
VPValue *V = Builder.getVPValueOrAddLiveIn(IncomingValue);
8893-
// Exit values for inductions are computed and updated outside of VPlan and
8894-
// independent of induction recipes.
8895-
// TODO: Compute induction exit values in VPlan.
8896-
if ((isa<VPWidenIntOrFpInductionRecipe>(V) &&
8897-
!cast<VPWidenIntOrFpInductionRecipe>(V)->getTruncInst()) ||
8898-
isa<VPWidenPointerInductionRecipe>(V) ||
8899-
(isa<Instruction>(IncomingValue) &&
8900-
OrigLoop->contains(cast<Instruction>(IncomingValue)) &&
8901-
any_of(IncomingValue->users(), [&Inductions](User *U) {
8902-
auto *P = dyn_cast<PHINode>(U);
8903-
return P && Inductions.contains(P);
8904-
})))
8905-
continue;
8906-
ExitUsersToFix.insert(ExitIRI);
8907-
ExitIRI->addOperand(V);
8876+
for (VPIRBasicBlock *ExitVPBB : Plan.getExitBlocks()) {
8877+
BasicBlock *ExitBB = ExitVPBB->getIRBasicBlock();
8878+
BasicBlock *ExitingBB = find_singleton<BasicBlock>(
8879+
to_vector(predecessors(ExitBB)),
8880+
[OrigLoop](BasicBlock *Pred, bool AllowRepeats) {
8881+
return OrigLoop->contains(Pred) ? Pred : nullptr;
8882+
});
8883+
for (VPRecipeBase &R : *ExitVPBB) {
8884+
auto *ExitIRI = dyn_cast<VPIRInstruction>(&R);
8885+
if (!ExitIRI)
8886+
continue;
8887+
auto *ExitPhi = dyn_cast<PHINode>(&ExitIRI->getInstruction());
8888+
if (!ExitPhi)
8889+
break;
8890+
Value *IncomingValue = ExitPhi->getIncomingValueForBlock(ExitingBB);
8891+
VPValue *V = Builder.getVPValueOrAddLiveIn(IncomingValue);
8892+
// Exit values for inductions are computed and updated outside of VPlan
8893+
// and independent of induction recipes.
8894+
// TODO: Compute induction exit values in VPlan.
8895+
if ((isa<VPWidenIntOrFpInductionRecipe>(V) &&
8896+
!cast<VPWidenIntOrFpInductionRecipe>(V)->getTruncInst()) ||
8897+
isa<VPWidenPointerInductionRecipe>(V) ||
8898+
(isa<Instruction>(IncomingValue) &&
8899+
OrigLoop->contains(cast<Instruction>(IncomingValue)) &&
8900+
any_of(IncomingValue->users(), [&Inductions](User *U) {
8901+
auto *P = dyn_cast<PHINode>(U);
8902+
return P && Inductions.contains(P);
8903+
})))
8904+
continue;
8905+
ExitUsersToFix.insert(ExitIRI);
8906+
ExitIRI->addOperand(V);
8907+
}
89088908
}
89098909
return ExitUsersToFix;
89108910
}
89118911

89128912
// Add exit values to \p Plan. Extracts are added for each entry in \p
89138913
// ExitUsersToFix if needed and their operands are updated.
89148914
static void
8915-
addUsersInExitBlock(VPlan &Plan,
8916-
const SetVector<VPIRInstruction *> &ExitUsersToFix) {
8915+
addUsersInExitBlocks(VPlan &Plan,
8916+
const SetVector<VPIRInstruction *> &ExitUsersToFix) {
89178917
if (ExitUsersToFix.empty())
89188918
return;
89198919

@@ -8929,6 +8929,8 @@ addUsersInExitBlock(VPlan &Plan,
89298929
if (V->isLiveIn())
89308930
continue;
89318931

8932+
assert(ExitIRI->getParent()->getSinglePredecessor() == MiddleVPBB &&
8933+
"Exit value not handled yet for this edge.");
89328934
LLVMContext &Ctx = ExitIRI->getInstruction().getContext();
89338935
VPValue *Ext = B.createNaryOp(VPInstruction::ExtractFromEnd,
89348936
{V, Plan.getOrAddLiveIn(ConstantInt::get(
@@ -9206,10 +9208,10 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
92069208
RecipeBuilder.fixHeaderPhis();
92079209

92089210
addScalarResumePhis(RecipeBuilder, *Plan);
9209-
SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlock(
9211+
SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlocks(
92109212
OrigLoop, RecipeBuilder, *Plan, Legal->getInductionVars());
92119213
addExitUsersForFirstOrderRecurrences(*Plan, ExitUsersToFix);
9212-
addUsersInExitBlock(*Plan, ExitUsersToFix);
9214+
addUsersInExitBlocks(*Plan, ExitUsersToFix);
92139215
// ---------------------------------------------------------------------------
92149216
// Transform initial VPlan: Apply previously taken decisions, in order, to
92159217
// bring the VPlan to its final state.

llvm/lib/Transforms/Vectorize/VPlan.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3839,6 +3839,12 @@ class VPlan {
38393839
return cast<VPBasicBlock>(getVectorLoopRegion()->getSingleSuccessor());
38403840
}
38413841

3842+
/// Return an iterator range over the VPIRBasicBlock wrapping the exit blocks
3843+
/// of the VPlan, that is leaf nodes except the scalar header. Defined in
3844+
/// VPlanHCFG, as the definition of the type needs access to the definitions
3845+
/// of VPBlockShallowTraversalWrapper.
3846+
auto getExitBlocks();
3847+
38423848
/// The trip count of the original loop.
38433849
VPValue *getTripCount() const {
38443850
assert(TripCount && "trip count needs to be set before accessing it");

llvm/lib/Transforms/Vectorize/VPlanCFG.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,15 @@ template <> struct GraphTraits<VPlan *> {
306306
}
307307
};
308308

309+
inline auto VPlan::getExitBlocks() {
310+
VPBlockBase *ScalarHeader = getScalarHeader();
311+
return make_filter_range(
312+
VPBlockUtils::blocksOnly<VPIRBasicBlock>(
313+
vp_depth_first_shallow(getVectorLoopRegion()->getSingleSuccessor())),
314+
[ScalarHeader](VPIRBasicBlock *VPIRBB) {
315+
return VPIRBB != ScalarHeader && VPIRBB->getNumSuccessors() == 0;
316+
});
317+
}
309318
} // namespace llvm
310319

311320
#endif // LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H

0 commit comments

Comments
 (0)