Skip to content

Commit f7c771d

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 bfe486f commit f7c771d

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
@@ -7702,6 +7702,7 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
77027702
BestVPlan.prepareToExecute(ILV.getTripCount(),
77037703
ILV.getOrCreateVectorTripCount(nullptr),
77047704
CanonicalIVStartValue, State);
7705+
VPlanTransforms::prepareToExecute(BestVPlan);
77057706

77067707
BestVPlan.execute(&State);
77077708

llvm/lib/Transforms/Vectorize/VPlan.cpp

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

10991099
auto *PhiR = cast<VPHeaderPHIRecipe>(&R);
1100-
bool NeedsScalar =
1101-
isa<VPCanonicalIVPHIRecipe, VPEVLBasedIVPHIRecipe>(PhiR) ||
1102-
(isa<VPReductionPHIRecipe>(PhiR) &&
1103-
cast<VPReductionPHIRecipe>(PhiR)->isInLoop());
1100+
bool NeedsScalar = isa<VPScalarPHIRecipe>(PhiR) ||
1101+
(isa<VPReductionPHIRecipe>(PhiR) &&
1102+
cast<VPReductionPHIRecipe>(PhiR)->isInLoop());
11041103
Value *Phi = State->get(PhiR, NeedsScalar);
11051104
Value *Val = State->get(PhiR->getBackedgeValue(), NeedsScalar);
11061105
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
@@ -2239,6 +2239,45 @@ class VPWidenPointerInductionRecipe : public VPHeaderPHIRecipe,
22392239
#endif
22402240
};
22412241

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

3118-
/// Generate the canonical scalar induction phi of the vector loop.
3119-
void execute(VPTransformState &State) override;
3157+
void execute(VPTransformState &State) override {
3158+
llvm_unreachable(
3159+
"cannot execute this recipe, should be replaced by VPScalarPHIRecipe");
3160+
}
31203161

31213162
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
31223163
/// Print the recipe.
@@ -3212,9 +3253,10 @@ class VPEVLBasedIVPHIRecipe : public VPHeaderPHIRecipe {
32123253
return D->getVPDefID() == VPDef::VPEVLBasedIVPHISC;
32133254
}
32143255

3215-
/// Generate phi for handling IV based on EVL over iterations correctly.
3216-
/// TODO: investigate if it can share the code with VPCanonicalIVPHIRecipe.
3217-
void execute(VPTransformState &State) override;
3256+
void execute(VPTransformState &State) override {
3257+
llvm_unreachable(
3258+
"cannot execute this recipe, should be replaced by VPScalarPHIRecipe");
3259+
}
32183260

32193261
/// Return the cost of this VPEVLBasedIVPHIRecipe.
32203262
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
@@ -3122,17 +3122,6 @@ InstructionCost VPInterleaveRecipe::computeCost(ElementCount VF,
31223122
VectorTy, std::nullopt, CostKind, 0);
31233123
}
31243124

3125-
void VPCanonicalIVPHIRecipe::execute(VPTransformState &State) {
3126-
Value *Start = getStartValue()->getLiveInIRValue();
3127-
PHINode *Phi = PHINode::Create(Start->getType(), 2, "index");
3128-
Phi->insertBefore(State.CFG.PrevBB->getFirstInsertionPt());
3129-
3130-
BasicBlock *VectorPH = State.CFG.getPreheaderBBFor(this);
3131-
Phi->addIncoming(Start, VectorPH);
3132-
Phi->setDebugLoc(getDebugLoc());
3133-
State.set(this, Phi, /*IsScalar*/ true);
3134-
}
3135-
31363125
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
31373126
void VPCanonicalIVPHIRecipe::print(raw_ostream &O, const Twine &Indent,
31383127
VPSlotTracker &SlotTracker) const {
@@ -3174,8 +3163,6 @@ void VPWidenPointerInductionRecipe::execute(VPTransformState &State) {
31743163
assert(!onlyScalarsGenerated(State.VF.isScalable()) &&
31753164
"Recipe should have been replaced");
31763165

3177-
auto *IVR = getParent()->getPlan()->getCanonicalIV();
3178-
PHINode *CanonicalIV = cast<PHINode>(State.get(IVR, /*IsScalar*/ true));
31793166
unsigned CurrentPart = getUnrollPart(*this);
31803167

31813168
// Build a pointer phi
@@ -3185,6 +3172,12 @@ void VPWidenPointerInductionRecipe::execute(VPTransformState &State) {
31853172
BasicBlock *VectorPH = State.CFG.getPreheaderBBFor(this);
31863173
PHINode *NewPointerPhi = nullptr;
31873174
if (CurrentPart == 0) {
3175+
auto *IVR = cast<VPHeaderPHIRecipe>(&getParent()
3176+
->getPlan()
3177+
->getVectorLoopRegion()
3178+
->getEntryBasicBlock()
3179+
->front());
3180+
PHINode *CanonicalIV = cast<PHINode>(State.get(IVR, /*IsScalar*/ true));
31883181
NewPointerPhi = PHINode::Create(ScStValueType, 2, "pointer.phi",
31893182
CanonicalIV->getIterator());
31903183
NewPointerPhi->addIncoming(ScalarStartValue, VectorPH);
@@ -3495,20 +3488,30 @@ void VPActiveLaneMaskPHIRecipe::print(raw_ostream &O, const Twine &Indent,
34953488
}
34963489
#endif
34973490

3498-
void VPEVLBasedIVPHIRecipe::execute(VPTransformState &State) {
3491+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3492+
void VPEVLBasedIVPHIRecipe::print(raw_ostream &O, const Twine &Indent,
3493+
VPSlotTracker &SlotTracker) const {
3494+
O << Indent << "EXPLICIT-VECTOR-LENGTH-BASED-IV-PHI ";
3495+
3496+
printAsOperand(O, SlotTracker);
3497+
O << " = phi ";
3498+
printOperands(O, SlotTracker);
3499+
}
3500+
#endif
3501+
3502+
void VPScalarPHIRecipe::execute(VPTransformState &State) {
34993503
BasicBlock *VectorPH = State.CFG.getPreheaderBBFor(this);
35003504
Value *Start = State.get(getOperand(0), VPLane(0));
3501-
PHINode *Phi = State.Builder.CreatePHI(Start->getType(), 2, "evl.based.iv");
3505+
PHINode *Phi = State.Builder.CreatePHI(Start->getType(), 2, Name);
35023506
Phi->addIncoming(Start, VectorPH);
35033507
Phi->setDebugLoc(getDebugLoc());
35043508
State.set(this, Phi, /*IsScalar=*/true);
35053509
}
35063510

35073511
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3508-
void VPEVLBasedIVPHIRecipe::print(raw_ostream &O, const Twine &Indent,
3509-
VPSlotTracker &SlotTracker) const {
3510-
O << Indent << "EXPLICIT-VECTOR-LENGTH-BASED-IV-PHI ";
3511-
3512+
void VPScalarPHIRecipe::print(raw_ostream &O, const Twine &Indent,
3513+
VPSlotTracker &SlotTracker) const {
3514+
O << Indent << "SCALAR-PHI";
35123515
printAsOperand(O, SlotTracker);
35133516
O << " = phi ";
35143517
printOperands(O, SlotTracker);

llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp

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

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
@@ -372,6 +372,7 @@ class VPDef {
372372
VPFirstOrderRecurrencePHISC,
373373
VPWidenIntOrFpInductionSC,
374374
VPWidenPointerInductionSC,
375+
VPScalarPHISC,
375376
VPReductionPHISC,
376377
// END: SubclassID for recipes that inherit VPHeaderPHIRecipe
377378
// END: Phi-like recipes

0 commit comments

Comments
 (0)