Skip to content

Commit c83fdc9

Browse files
committed
[LV] Perform recurrence sinking directly on VPlan.
This patch updates LV to sink recipes directly using the VPlan use chains. The initial patch only moves sinking to be purely VPlan-based. Follow-up patches will move legality checks to VPlan as well. At the moment, there's a single test failure remaining. Reviewed By: Ayal Differential Revision: https://reviews.llvm.org/D142589
1 parent 1f01cdd commit c83fdc9

File tree

6 files changed

+214
-156
lines changed

6 files changed

+214
-156
lines changed

llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,6 @@ class LoopVectorizationLegality {
293293
/// Return the fixed-order recurrences found in the loop.
294294
RecurrenceSet &getFixedOrderRecurrences() { return FixedOrderRecurrences; }
295295

296-
/// Return the set of instructions to sink to handle fixed-order recurrences.
297-
MapVector<Instruction *, Instruction *> &getSinkAfter() { return SinkAfter; }
298-
299296
/// Returns the widest induction type.
300297
Type *getWidestInductionType() { return WidestIndTy; }
301298

llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,9 @@ class LoopVectorizationPlanner {
350350

351351
/// Build a VPlan using VPRecipes according to the information gather by
352352
/// Legal. This method is only used for the legacy inner loop vectorizer.
353-
VPlanPtr buildVPlanWithVPRecipes(
354-
VFRange &Range, SmallPtrSetImpl<Instruction *> &DeadInstructions,
355-
const MapVector<Instruction *, Instruction *> &SinkAfter);
353+
VPlanPtr
354+
buildVPlanWithVPRecipes(VFRange &Range,
355+
SmallPtrSetImpl<Instruction *> &DeadInstructions);
356356

357357
/// Build VPlans for power-of-2 VF's between \p MinVF and \p MaxVF inclusive,
358358
/// according to the information gathered by Legal when it checked if it is

llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Lines changed: 11 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -8687,34 +8687,10 @@ void LoopVectorizationPlanner::buildVPlansWithVPRecipes(ElementCount MinVF,
86878687
auto &ConditionalAssumes = Legal->getConditionalAssumes();
86888688
DeadInstructions.insert(ConditionalAssumes.begin(), ConditionalAssumes.end());
86898689

8690-
MapVector<Instruction *, Instruction *> &SinkAfter = Legal->getSinkAfter();
8691-
// Dead instructions do not need sinking. Remove them from SinkAfter.
8692-
for (Instruction *I : DeadInstructions)
8693-
SinkAfter.erase(I);
8694-
8695-
// Cannot sink instructions after dead instructions (there won't be any
8696-
// recipes for them). Instead, find the first non-dead previous instruction.
8697-
for (auto &P : Legal->getSinkAfter()) {
8698-
Instruction *SinkTarget = P.second;
8699-
Instruction *FirstInst = &*SinkTarget->getParent()->begin();
8700-
(void)FirstInst;
8701-
while (DeadInstructions.contains(SinkTarget)) {
8702-
assert(
8703-
SinkTarget != FirstInst &&
8704-
"Must find a live instruction (at least the one feeding the "
8705-
"fixed-order recurrence PHI) before reaching beginning of the block");
8706-
SinkTarget = SinkTarget->getPrevNode();
8707-
assert(SinkTarget != P.first &&
8708-
"sink source equals target, no sinking required");
8709-
}
8710-
P.second = SinkTarget;
8711-
}
8712-
87138690
auto MaxVFPlusOne = MaxVF.getWithIncrement(1);
87148691
for (ElementCount VF = MinVF; ElementCount::isKnownLT(VF, MaxVFPlusOne);) {
87158692
VFRange SubRange = {VF, MaxVFPlusOne};
8716-
VPlans.push_back(
8717-
buildVPlanWithVPRecipes(SubRange, DeadInstructions, SinkAfter));
8693+
VPlans.push_back(buildVPlanWithVPRecipes(SubRange, DeadInstructions));
87188694
VF = SubRange.End;
87198695
}
87208696
}
@@ -8820,8 +8796,7 @@ static void addUsersInExitBlock(VPBasicBlock *HeaderVPBB,
88208796
}
88218797

88228798
VPlanPtr LoopVectorizationPlanner::buildVPlanWithVPRecipes(
8823-
VFRange &Range, SmallPtrSetImpl<Instruction *> &DeadInstructions,
8824-
const MapVector<Instruction *, Instruction *> &SinkAfter) {
8799+
VFRange &Range, SmallPtrSetImpl<Instruction *> &DeadInstructions) {
88258800

88268801
SmallPtrSet<const InterleaveGroup<Instruction> *, 1> InterleaveGroups;
88278802

@@ -8832,12 +8807,6 @@ VPlanPtr LoopVectorizationPlanner::buildVPlanWithVPRecipes(
88328807
// process after constructing the initial VPlan.
88338808
// ---------------------------------------------------------------------------
88348809

8835-
// Mark instructions we'll need to sink later and their targets as
8836-
// ingredients whose recipe we'll need to record.
8837-
for (const auto &Entry : SinkAfter) {
8838-
RecipeBuilder.recordRecipeOf(Entry.first);
8839-
RecipeBuilder.recordRecipeOf(Entry.second);
8840-
}
88418810
for (const auto &Reduction : CM.getInLoopReductionChains()) {
88428811
PHINode *Phi = Reduction.first;
88438812
RecurKind Kind =
@@ -8905,7 +8874,6 @@ VPlanPtr LoopVectorizationPlanner::buildVPlanWithVPRecipes(
89058874
DFS.perform(LI);
89068875

89078876
VPBasicBlock *VPBB = HeaderVPBB;
8908-
SmallVector<VPWidenIntOrFpInductionRecipe *> InductionsToMove;
89098877
for (BasicBlock *BB : make_range(DFS.beginRPO(), DFS.endRPO())) {
89108878
// Relevant instructions from basic block BB will be grouped into VPRecipe
89118879
// ingredients and fill a new VPBasicBlock.
@@ -8960,19 +8928,15 @@ VPlanPtr LoopVectorizationPlanner::buildVPlanWithVPRecipes(
89608928
Plan->addVPValue(UV, Def);
89618929
}
89628930

8931+
RecipeBuilder.setRecipe(Instr, Recipe);
89638932
if (isa<VPWidenIntOrFpInductionRecipe>(Recipe) &&
89648933
HeaderVPBB->getFirstNonPhi() != VPBB->end()) {
8965-
// Keep track of VPWidenIntOrFpInductionRecipes not in the phi section
8966-
// of the header block. That can happen for truncates of induction
8967-
// variables. Those recipes are moved to the phi section of the header
8968-
// block after applying SinkAfter, which relies on the original
8969-
// position of the trunc.
8934+
// Move VPWidenIntOrFpInductionRecipes for optimized truncates to the
8935+
// phi section of HeaderVPBB.
89708936
assert(isa<TruncInst>(Instr));
8971-
InductionsToMove.push_back(
8972-
cast<VPWidenIntOrFpInductionRecipe>(Recipe));
8973-
}
8974-
RecipeBuilder.setRecipe(Instr, Recipe);
8975-
VPBB->appendRecipe(Recipe);
8937+
Recipe->insertBefore(*HeaderVPBB, HeaderVPBB->getFirstNonPhi());
8938+
} else
8939+
VPBB->appendRecipe(Recipe);
89768940
continue;
89778941
}
89788942

@@ -9007,115 +8971,16 @@ VPlanPtr LoopVectorizationPlanner::buildVPlanWithVPRecipes(
90078971
// bring the VPlan to its final state.
90088972
// ---------------------------------------------------------------------------
90098973

9010-
// Apply Sink-After legal constraints.
9011-
auto GetReplicateRegion = [](VPRecipeBase *R) -> VPRegionBlock * {
9012-
auto *Region = dyn_cast_or_null<VPRegionBlock>(R->getParent()->getParent());
9013-
if (Region && Region->isReplicator()) {
9014-
assert(Region->getNumSuccessors() == 1 &&
9015-
Region->getNumPredecessors() == 1 && "Expected SESE region!");
9016-
assert(R->getParent()->size() == 1 &&
9017-
"A recipe in an original replicator region must be the only "
9018-
"recipe in its block");
9019-
return Region;
9020-
}
9021-
return nullptr;
9022-
};
9023-
for (const auto &Entry : SinkAfter) {
9024-
VPRecipeBase *Sink = RecipeBuilder.getRecipe(Entry.first);
9025-
VPRecipeBase *Target = RecipeBuilder.getRecipe(Entry.second);
9026-
9027-
auto *TargetRegion = GetReplicateRegion(Target);
9028-
auto *SinkRegion = GetReplicateRegion(Sink);
9029-
if (!SinkRegion) {
9030-
// If the sink source is not a replicate region, sink the recipe directly.
9031-
if (TargetRegion) {
9032-
// The target is in a replication region, make sure to move Sink to
9033-
// the block after it, not into the replication region itself.
9034-
VPBasicBlock *NextBlock =
9035-
cast<VPBasicBlock>(TargetRegion->getSuccessors().front());
9036-
Sink->moveBefore(*NextBlock, NextBlock->getFirstNonPhi());
9037-
} else
9038-
Sink->moveAfter(Target);
9039-
continue;
9040-
}
9041-
9042-
// The sink source is in a replicate region. Unhook the region from the CFG.
9043-
auto *SinkPred = SinkRegion->getSinglePredecessor();
9044-
auto *SinkSucc = SinkRegion->getSingleSuccessor();
9045-
VPBlockUtils::disconnectBlocks(SinkPred, SinkRegion);
9046-
VPBlockUtils::disconnectBlocks(SinkRegion, SinkSucc);
9047-
VPBlockUtils::connectBlocks(SinkPred, SinkSucc);
9048-
9049-
if (TargetRegion) {
9050-
// The target recipe is also in a replicate region, move the sink region
9051-
// after the target region.
9052-
auto *TargetSucc = TargetRegion->getSingleSuccessor();
9053-
VPBlockUtils::disconnectBlocks(TargetRegion, TargetSucc);
9054-
VPBlockUtils::connectBlocks(TargetRegion, SinkRegion);
9055-
VPBlockUtils::connectBlocks(SinkRegion, TargetSucc);
9056-
} else {
9057-
// The sink source is in a replicate region, we need to move the whole
9058-
// replicate region, which should only contain a single recipe in the
9059-
// main block.
9060-
auto *SplitBlock =
9061-
Target->getParent()->splitAt(std::next(Target->getIterator()));
9062-
9063-
auto *SplitPred = SplitBlock->getSinglePredecessor();
9064-
9065-
VPBlockUtils::disconnectBlocks(SplitPred, SplitBlock);
9066-
VPBlockUtils::connectBlocks(SplitPred, SinkRegion);
9067-
VPBlockUtils::connectBlocks(SinkRegion, SplitBlock);
9068-
}
9069-
}
9070-
90718974
VPlanTransforms::removeRedundantCanonicalIVs(*Plan);
90728975
VPlanTransforms::removeRedundantInductionCasts(*Plan);
90738976

9074-
// Now that sink-after is done, move induction recipes for optimized truncates
9075-
// to the phi section of the header block.
9076-
for (VPWidenIntOrFpInductionRecipe *Ind : InductionsToMove)
9077-
Ind->moveBefore(*HeaderVPBB, HeaderVPBB->getFirstNonPhi());
9078-
90798977
// Adjust the recipes for any inloop reductions.
90808978
adjustRecipesForReductions(cast<VPBasicBlock>(TopRegion->getExiting()), Plan,
90818979
RecipeBuilder, Range.Start);
90828980

9083-
// Introduce a recipe to combine the incoming and previous values of a
9084-
// fixed-order recurrence.
9085-
for (VPRecipeBase &R :
9086-
Plan->getVectorLoopRegion()->getEntryBasicBlock()->phis()) {
9087-
auto *RecurPhi = dyn_cast<VPFirstOrderRecurrencePHIRecipe>(&R);
9088-
if (!RecurPhi)
9089-
continue;
9090-
9091-
VPRecipeBase *PrevRecipe = &RecurPhi->getBackedgeRecipe();
9092-
// Fixed-order recurrences do not contain cycles, so this loop is guaranteed
9093-
// to terminate.
9094-
while (auto *PrevPhi =
9095-
dyn_cast<VPFirstOrderRecurrencePHIRecipe>(PrevRecipe))
9096-
PrevRecipe = &PrevPhi->getBackedgeRecipe();
9097-
VPBasicBlock *InsertBlock = PrevRecipe->getParent();
9098-
auto *Region = GetReplicateRegion(PrevRecipe);
9099-
if (Region)
9100-
InsertBlock = dyn_cast<VPBasicBlock>(Region->getSingleSuccessor());
9101-
if (!InsertBlock) {
9102-
InsertBlock = new VPBasicBlock(Region->getName() + ".succ");
9103-
VPBlockUtils::insertBlockAfter(InsertBlock, Region);
9104-
}
9105-
if (Region || PrevRecipe->isPhi())
9106-
Builder.setInsertPoint(InsertBlock, InsertBlock->getFirstNonPhi());
9107-
else
9108-
Builder.setInsertPoint(InsertBlock, std::next(PrevRecipe->getIterator()));
9109-
9110-
auto *RecurSplice = cast<VPInstruction>(
9111-
Builder.createNaryOp(VPInstruction::FirstOrderRecurrenceSplice,
9112-
{RecurPhi, RecurPhi->getBackedgeValue()}));
9113-
9114-
RecurPhi->replaceAllUsesWith(RecurSplice);
9115-
// Set the first operand of RecurSplice to RecurPhi again, after replacing
9116-
// all users.
9117-
RecurSplice->setOperand(0, RecurPhi);
9118-
}
8981+
// Sink users of fixed-order recurrence past the recipe defining the previous
8982+
// value and introduce FirstOrderRecurrenceSplice VPInstructions.
8983+
VPlanTransforms::adjustFixedOrderRecurrences(*Plan, Builder);
91198984

91208985
// Interleave memory: for each Interleave Group we marked earlier as relevant
91218986
// for this VPlan, replace the Recipes widening its memory instructions with a

0 commit comments

Comments
 (0)