Skip to content

Commit 1740a4f

Browse files
committed
[VPlan] Introduce VPScalarPHIRecipe, use for can & EVL IV codegen (NFC).
Introduce a general recipe to generate a scalar phi. Lower VPCanonicalIVPHIRecipe and VPEVLBasedIVRecipe to VPScalarIVPHIrecipe before plan execution, avoiding the need for duplicated ::execute implementations. There are other cases that could benefit, including in-loop reduction phis. Builds on a similar idea as #82270.
1 parent d822c09 commit 1740a4f

File tree

8 files changed

+106
-36
lines changed

8 files changed

+106
-36
lines changed

llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7706,6 +7706,7 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
77067706
BestVPlan.prepareToExecute(ILV.getTripCount(),
77077707
ILV.getOrCreateVectorTripCount(nullptr),
77087708
CanonicalIVStartValue, State);
7709+
VPlanTransforms::prepareToExecute(BestVPlan);
77097710

77107711
BestVPlan.execute(&State);
77117712

llvm/lib/Transforms/Vectorize/VPlan.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,10 +1080,9 @@ void VPlan::execute(VPTransformState *State) {
10801080
}
10811081

10821082
auto *PhiR = cast<VPHeaderPHIRecipe>(&R);
1083-
bool NeedsScalar =
1084-
isa<VPCanonicalIVPHIRecipe, VPEVLBasedIVPHIRecipe>(PhiR) ||
1085-
(isa<VPReductionPHIRecipe>(PhiR) &&
1086-
cast<VPReductionPHIRecipe>(PhiR)->isInLoop());
1083+
bool NeedsScalar = isa<VPScalarPHIRecipe>(PhiR) ||
1084+
(isa<VPReductionPHIRecipe>(PhiR) &&
1085+
cast<VPReductionPHIRecipe>(PhiR)->isInLoop());
10871086
Value *Phi = State->get(PhiR, NeedsScalar);
10881087
Value *Val = State->get(PhiR->getBackedgeValue(), NeedsScalar);
10891088
cast<PHINode>(Phi)->addIncoming(Val, VectorLatchBB);

llvm/lib/Transforms/Vectorize/VPlan.h

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,6 +2237,45 @@ class VPWidenPointerInductionRecipe : public VPHeaderPHIRecipe,
22372237
#endif
22382238
};
22392239

2240+
/// Recipe to generate a scalar PHI. Used to generate code for recipes that
2241+
/// produce scalar header phis, including VPCanonicalIVPHIRecipe and
2242+
/// VPEVLBasedIVPHIRecipe.
2243+
class VPScalarPHIRecipe : public VPHeaderPHIRecipe {
2244+
std::string Name;
2245+
2246+
public:
2247+
VPScalarPHIRecipe(VPValue *Start, VPValue *BackedgeValue, DebugLoc DL,
2248+
StringRef Name)
2249+
: VPHeaderPHIRecipe(VPDef::VPScalarPHISC, nullptr, Start, DL),
2250+
Name(Name.str()) {
2251+
addOperand(BackedgeValue);
2252+
}
2253+
2254+
~VPScalarPHIRecipe() override = default;
2255+
2256+
VPScalarPHIRecipe *clone() override {
2257+
llvm_unreachable("cloning not implemented yet");
2258+
}
2259+
2260+
VP_CLASSOF_IMPL(VPDef::VPScalarPHISC)
2261+
2262+
/// Generate the phi/select nodes.
2263+
void execute(VPTransformState &State) override;
2264+
2265+
/// Returns true if the recipe only uses the first lane of operand \p Op.
2266+
bool onlyFirstLaneUsed(const VPValue *Op) const override {
2267+
assert(is_contained(operands(), Op) &&
2268+
"Op must be an operand of the recipe");
2269+
return true;
2270+
}
2271+
2272+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2273+
/// Print the recipe.
2274+
void print(raw_ostream &O, const Twine &Indent,
2275+
VPSlotTracker &SlotTracker) const override;
2276+
#endif
2277+
};
2278+
22402279
/// A recipe for handling phis that are widened in the vector loop.
22412280
/// In the VPlan native path, all incoming VPValues & VPBasicBlock pairs are
22422281
/// managed in the recipe directly.
@@ -3132,8 +3171,10 @@ class VPCanonicalIVPHIRecipe : public VPHeaderPHIRecipe {
31323171
return D->getVPDefID() == VPDef::VPCanonicalIVPHISC;
31333172
}
31343173

3135-
/// Generate the canonical scalar induction phi of the vector loop.
3136-
void execute(VPTransformState &State) override;
3174+
void execute(VPTransformState &State) override {
3175+
llvm_unreachable(
3176+
"cannot execute this recipe, should be replaced by VPScalarPHIRecipe");
3177+
}
31373178

31383179
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
31393180
/// Print the recipe.
@@ -3229,9 +3270,10 @@ class VPEVLBasedIVPHIRecipe : public VPHeaderPHIRecipe {
32293270
return D->getVPDefID() == VPDef::VPEVLBasedIVPHISC;
32303271
}
32313272

3232-
/// Generate phi for handling IV based on EVL over iterations correctly.
3233-
/// TODO: investigate if it can share the code with VPCanonicalIVPHIRecipe.
3234-
void execute(VPTransformState &State) override;
3273+
void execute(VPTransformState &State) override {
3274+
llvm_unreachable(
3275+
"cannot execute this recipe, should be replaced by VPScalarPHIRecipe");
3276+
}
32353277

32363278
/// Return the cost of this VPEVLBasedIVPHIRecipe.
32373279
InstructionCost computeCost(ElementCount VF,

llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -251,14 +251,14 @@ Type *VPTypeAnalysis::inferScalarType(const VPValue *V) {
251251
TypeSwitch<const VPRecipeBase *, Type *>(V->getDefiningRecipe())
252252
.Case<VPActiveLaneMaskPHIRecipe, VPCanonicalIVPHIRecipe,
253253
VPFirstOrderRecurrencePHIRecipe, VPReductionPHIRecipe,
254-
VPWidenPointerInductionRecipe, VPEVLBasedIVPHIRecipe>(
255-
[this](const auto *R) {
256-
// Handle header phi recipes, except VPWidenIntOrFpInduction
257-
// which needs special handling due it being possibly truncated.
258-
// TODO: consider inferring/caching type of siblings, e.g.,
259-
// backedge value, here and in cases below.
260-
return inferScalarType(R->getStartValue());
261-
})
254+
VPWidenPointerInductionRecipe, VPEVLBasedIVPHIRecipe,
255+
VPScalarPHIRecipe>([this](const auto *R) {
256+
// Handle header phi recipes, except VPWidenIntOrFpInduction
257+
// which needs special handling due it being possibly truncated.
258+
// TODO: consider inferring/caching type of siblings, e.g.,
259+
// backedge value, here and in cases below.
260+
return inferScalarType(R->getStartValue());
261+
})
262262
.Case<VPWidenIntOrFpInductionRecipe, VPDerivedIVRecipe>(
263263
[](const auto *R) { return R->getScalarType(); })
264264
.Case<VPReductionRecipe, VPPredInstPHIRecipe, VPWidenPHIRecipe,

llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3096,17 +3096,6 @@ InstructionCost VPInterleaveRecipe::computeCost(ElementCount VF,
30963096
VectorTy, std::nullopt, CostKind, 0);
30973097
}
30983098

3099-
void VPCanonicalIVPHIRecipe::execute(VPTransformState &State) {
3100-
Value *Start = getStartValue()->getLiveInIRValue();
3101-
PHINode *Phi = PHINode::Create(Start->getType(), 2, "index");
3102-
Phi->insertBefore(State.CFG.PrevBB->getFirstInsertionPt());
3103-
3104-
BasicBlock *VectorPH = State.CFG.getPreheaderBBFor(this);
3105-
Phi->addIncoming(Start, VectorPH);
3106-
Phi->setDebugLoc(getDebugLoc());
3107-
State.set(this, Phi, /*IsScalar*/ true);
3108-
}
3109-
31103099
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
31113100
void VPCanonicalIVPHIRecipe::print(raw_ostream &O, const Twine &Indent,
31123101
VPSlotTracker &SlotTracker) const {
@@ -3148,8 +3137,6 @@ void VPWidenPointerInductionRecipe::execute(VPTransformState &State) {
31483137
assert(!onlyScalarsGenerated(State.VF.isScalable()) &&
31493138
"Recipe should have been replaced");
31503139

3151-
auto *IVR = getParent()->getPlan()->getCanonicalIV();
3152-
PHINode *CanonicalIV = cast<PHINode>(State.get(IVR, /*IsScalar*/ true));
31533140
unsigned CurrentPart = getUnrollPart(*this);
31543141

31553142
// Build a pointer phi
@@ -3159,6 +3146,12 @@ void VPWidenPointerInductionRecipe::execute(VPTransformState &State) {
31593146
BasicBlock *VectorPH = State.CFG.getPreheaderBBFor(this);
31603147
PHINode *NewPointerPhi = nullptr;
31613148
if (CurrentPart == 0) {
3149+
auto *IVR = cast<VPHeaderPHIRecipe>(&getParent()
3150+
->getPlan()
3151+
->getVectorLoopRegion()
3152+
->getEntryBasicBlock()
3153+
->front());
3154+
PHINode *CanonicalIV = cast<PHINode>(State.get(IVR, /*IsScalar*/ true));
31623155
NewPointerPhi = PHINode::Create(ScStValueType, 2, "pointer.phi",
31633156
CanonicalIV->getIterator());
31643157
NewPointerPhi->addIncoming(ScalarStartValue, VectorPH);
@@ -3469,20 +3462,30 @@ void VPActiveLaneMaskPHIRecipe::print(raw_ostream &O, const Twine &Indent,
34693462
}
34703463
#endif
34713464

3472-
void VPEVLBasedIVPHIRecipe::execute(VPTransformState &State) {
3465+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3466+
void VPEVLBasedIVPHIRecipe::print(raw_ostream &O, const Twine &Indent,
3467+
VPSlotTracker &SlotTracker) const {
3468+
O << Indent << "EXPLICIT-VECTOR-LENGTH-BASED-IV-PHI ";
3469+
3470+
printAsOperand(O, SlotTracker);
3471+
O << " = phi ";
3472+
printOperands(O, SlotTracker);
3473+
}
3474+
#endif
3475+
3476+
void VPScalarPHIRecipe::execute(VPTransformState &State) {
34733477
BasicBlock *VectorPH = State.CFG.getPreheaderBBFor(this);
34743478
Value *Start = State.get(getOperand(0), VPLane(0));
3475-
PHINode *Phi = State.Builder.CreatePHI(Start->getType(), 2, "evl.based.iv");
3479+
PHINode *Phi = State.Builder.CreatePHI(Start->getType(), 2, Name);
34763480
Phi->addIncoming(Start, VectorPH);
34773481
Phi->setDebugLoc(getDebugLoc());
34783482
State.set(this, Phi, /*IsScalar=*/true);
34793483
}
34803484

34813485
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3482-
void VPEVLBasedIVPHIRecipe::print(raw_ostream &O, const Twine &Indent,
3483-
VPSlotTracker &SlotTracker) const {
3484-
O << Indent << "EXPLICIT-VECTOR-LENGTH-BASED-IV-PHI ";
3485-
3486+
void VPScalarPHIRecipe::print(raw_ostream &O, const Twine &Indent,
3487+
VPSlotTracker &SlotTracker) const {
3488+
O << Indent << "SCALAR-PHI";
34863489
printAsOperand(O, SlotTracker);
34873490
O << " = phi ";
34883491
printOperands(O, SlotTracker);

llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,3 +1794,24 @@ void VPlanTransforms::createInterleaveGroups(
17941794
}
17951795
}
17961796
}
1797+
1798+
void VPlanTransforms::prepareToExecute(VPlan &Plan) {
1799+
ReversePostOrderTraversal<VPBlockDeepTraversalWrapper<VPBlockBase *>> RPOT(
1800+
Plan.getVectorLoopRegion());
1801+
for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
1802+
vp_depth_first_deep(Plan.getEntry()))) {
1803+
for (VPRecipeBase &R : make_early_inc_range(VPBB->phis())) {
1804+
if (!isa<VPCanonicalIVPHIRecipe, VPEVLBasedIVPHIRecipe>(&R))
1805+
continue;
1806+
auto *PhiR = cast<VPHeaderPHIRecipe>(&R);
1807+
StringRef Name =
1808+
isa<VPCanonicalIVPHIRecipe>(PhiR) ? "index" : "evl.based.iv";
1809+
auto *ScalarR =
1810+
new VPScalarPHIRecipe(PhiR->getStartValue(), PhiR->getBackedgeValue(),
1811+
PhiR->getDebugLoc(), Name);
1812+
ScalarR->insertBefore(PhiR);
1813+
PhiR->replaceAllUsesWith(ScalarR);
1814+
PhiR->eraseFromParent();
1815+
}
1816+
}
1817+
}

llvm/lib/Transforms/Vectorize/VPlanTransforms.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ struct VPlanTransforms {
123123

124124
/// Remove dead recipes from \p Plan.
125125
static void removeDeadRecipes(VPlan &Plan);
126+
127+
/// Lower abstract recipes to concrete ones, that can be codegen'd.
128+
static void prepareToExecute(VPlan &Plan);
126129
};
127130

128131
} // namespace llvm

llvm/lib/Transforms/Vectorize/VPlanValue.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ class VPDef {
359359
VPFirstOrderRecurrencePHISC,
360360
VPWidenIntOrFpInductionSC,
361361
VPWidenPointerInductionSC,
362+
VPScalarPHISC,
362363
VPReductionPHISC,
363364
// END: SubclassID for recipes that inherit VPHeaderPHIRecipe
364365
// END: Phi-like recipes

0 commit comments

Comments
 (0)