Skip to content

Commit c305e73

Browse files
committed
[VPlan] Add new VPIRPhi overlay for VPIRInsts wrapping phi nodes (NFC).
Add a new VPIRPhi subclass of VPIRInstruction, that purely serves as an overlay, to provide more convenient checking (via directly doing isa/dyn_cast/cast) and specialied execute/print implementations. Both VPIRInstruction and VPIRPhi share the same VPDefID, and are differentiated by the backing IR instruction. This pattern could alos be used to provide more specialized interfaces for some VPInstructions ocpodes, without introducing new, completely spearate recipes. An example would be modeling VPWidenPHIRecipe & VPScalarPHIRecip using VPInstructions opcodes and providing an interface to retrieve incoming blocks and values through a VPInstruction subclass similar to VPIRPhi.
1 parent 9f37cdc commit c305e73

File tree

6 files changed

+89
-50
lines changed

6 files changed

+89
-50
lines changed

llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9089,14 +9089,14 @@ static void addScalarResumePhis(VPRecipeBuilder &Builder, VPlan &Plan,
90899089
VPValue *OneVPV = Plan.getOrAddLiveIn(
90909090
ConstantInt::get(Plan.getCanonicalIV()->getScalarType(), 1));
90919091
for (VPRecipeBase &ScalarPhiR : *Plan.getScalarHeader()) {
9092-
auto *ScalarPhiIRI = cast<VPIRInstruction>(&ScalarPhiR);
9093-
auto *ScalarPhiI = dyn_cast<PHINode>(&ScalarPhiIRI->getInstruction());
9094-
if (!ScalarPhiI)
9092+
auto *ScalarPhiIRI = dyn_cast<VPIRPhi>(&ScalarPhiR);
9093+
if (!ScalarPhiIRI)
90959094
break;
90969095

90979096
// TODO: Extract final value from induction recipe initially, optimize to
90989097
// pre-computed end value together in optimizeInductionExitUsers.
9099-
auto *VectorPhiR = cast<VPHeaderPHIRecipe>(Builder.getRecipe(ScalarPhiI));
9098+
auto *VectorPhiR =
9099+
cast<VPHeaderPHIRecipe>(Builder.getRecipe(&ScalarPhiIRI->getIRPhi()));
91009100
if (auto *WideIVR = dyn_cast<VPWidenInductionRecipe>(VectorPhiR)) {
91019101
if (VPInstruction *ResumePhi = addResumePhiRecipeForInduction(
91029102
WideIVR, VectorPHBuilder, ScalarPHBuilder, TypeInfo,
@@ -9146,20 +9146,19 @@ collectUsersInExitBlocks(Loop *OrigLoop, VPRecipeBuilder &Builder,
91469146
continue;
91479147

91489148
for (VPRecipeBase &R : *ExitVPBB) {
9149-
auto *ExitIRI = dyn_cast<VPIRInstruction>(&R);
9149+
auto *ExitIRI = dyn_cast<VPIRPhi>(&R);
91509150
if (!ExitIRI)
9151-
continue;
9152-
auto *ExitPhi = dyn_cast<PHINode>(&ExitIRI->getInstruction());
9153-
if (!ExitPhi)
91549151
break;
91559152
if (ExitVPBB->getSinglePredecessor() != Plan.getMiddleBlock()) {
91569153
assert(ExitIRI->getNumOperands() ==
91579154
ExitVPBB->getPredecessors().size() &&
91589155
"early-exit must update exit values on construction");
91599156
continue;
91609157
}
9158+
9159+
PHINode &ExitPhi = ExitIRI->getIRPhi();
91619160
BasicBlock *ExitingBB = OrigLoop->getLoopLatch();
9162-
Value *IncomingValue = ExitPhi->getIncomingValueForBlock(ExitingBB);
9161+
Value *IncomingValue = ExitPhi.getIncomingValueForBlock(ExitingBB);
91639162
VPValue *V = Builder.getVPValueOrAddLiveIn(IncomingValue);
91649163
ExitIRI->addOperand(V);
91659164
if (V->isLiveIn())
@@ -10297,11 +10296,10 @@ static void preparePlanForMainVectorLoop(VPlan &MainPlan, VPlan &EpiPlan) {
1029710296
cast<PHINode>(R.getVPSingleValue()->getUnderlyingValue()));
1029810297
}
1029910298
for (VPRecipeBase &R : make_early_inc_range(*MainPlan.getScalarHeader())) {
10300-
auto *VPIRInst = cast<VPIRInstruction>(&R);
10301-
auto *IRI = dyn_cast<PHINode>(&VPIRInst->getInstruction());
10302-
if (!IRI)
10299+
auto *VPIRInst = dyn_cast<VPIRPhi>(&R);
10300+
if (!VPIRInst)
1030310301
break;
10304-
if (EpiWidenedPhis.contains(IRI))
10302+
if (EpiWidenedPhis.contains(&VPIRInst->getIRPhi()))
1030510303
continue;
1030610304
// There is no corresponding wide induction in the epilogue plan that would
1030710305
// need a resume value. Remove the VPIRInst wrapping the scalar header phi

llvm/lib/Transforms/Vectorize/VPlan.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1295,7 +1295,7 @@ VPIRBasicBlock *VPlan::createVPIRBasicBlock(BasicBlock *IRBB) {
12951295
auto *VPIRBB = createEmptyVPIRBasicBlock(IRBB);
12961296
for (Instruction &I :
12971297
make_range(IRBB->begin(), IRBB->getTerminator()->getIterator()))
1298-
VPIRBB->appendRecipe(new VPIRInstruction(I));
1298+
VPIRBB->appendRecipe(VPIRInstruction::create(I));
12991299
return VPIRBB;
13001300
}
13011301

llvm/lib/Transforms/Vectorize/VPlan.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,16 +1032,19 @@ class VPInstruction : public VPRecipeWithIRFlags,
10321032
class VPIRInstruction : public VPRecipeBase {
10331033
Instruction &I;
10341034

1035-
public:
1035+
protected:
10361036
VPIRInstruction(Instruction &I)
10371037
: VPRecipeBase(VPDef::VPIRInstructionSC, ArrayRef<VPValue *>()), I(I) {}
10381038

1039+
public:
10391040
~VPIRInstruction() override = default;
10401041

1042+
static VPIRInstruction *create(Instruction &I);
1043+
10411044
VP_CLASSOF_IMPL(VPDef::VPIRInstructionSC)
10421045

10431046
VPIRInstruction *clone() override {
1044-
auto *R = new VPIRInstruction(I);
1047+
auto *R = create(I);
10451048
for (auto *Op : operands())
10461049
R->addOperand(Op);
10471050
return R;
@@ -1085,6 +1088,27 @@ class VPIRInstruction : public VPRecipeBase {
10851088
void extractLastLaneOfOperand(VPBuilder &Builder);
10861089
};
10871090

1091+
/// An overlay for VPIRInstructions wrapping PHI nodes enabling convenient use
1092+
/// cast/dyn_cast/isa and execute() implementation.
1093+
struct VPIRPhi : public VPIRInstruction {
1094+
VPIRPhi(PHINode &PN) : VPIRInstruction(PN) {}
1095+
1096+
static inline bool classof(const VPRecipeBase *U) {
1097+
auto *R = dyn_cast<VPIRInstruction>(U);
1098+
return R && isa<PHINode>(R->getInstruction());
1099+
}
1100+
1101+
PHINode &getIRPhi() { return cast<PHINode>(getInstruction()); }
1102+
1103+
void execute(VPTransformState &State) override;
1104+
1105+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1106+
/// Print the recipe.
1107+
void print(raw_ostream &O, const Twine &Indent,
1108+
VPSlotTracker &SlotTracker) const override;
1109+
#endif
1110+
};
1111+
10881112
/// VPWidenRecipe is a recipe for producing a widened instruction using the
10891113
/// opcode and operands of the recipe. This recipe covers most of the
10901114
/// traditional vectorization cases where each recipe transforms into a

llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -961,30 +961,15 @@ void VPInstruction::print(raw_ostream &O, const Twine &Indent,
961961
}
962962
#endif
963963

964-
void VPIRInstruction::execute(VPTransformState &State) {
965-
assert((isa<PHINode>(&I) || getNumOperands() == 0) &&
966-
"Only PHINodes can have extra operands");
967-
for (const auto &[Idx, Op] : enumerate(operands())) {
968-
VPValue *ExitValue = Op;
969-
auto Lane = vputils::isUniformAfterVectorization(ExitValue)
970-
? VPLane::getFirstLane()
971-
: VPLane::getLastLaneForVF(State.VF);
972-
VPBlockBase *Pred = getParent()->getPredecessors()[Idx];
973-
auto *PredVPBB = Pred->getExitingBasicBlock();
974-
BasicBlock *PredBB = State.CFG.VPBB2IRBB[PredVPBB];
975-
// Set insertion point in PredBB in case an extract needs to be generated.
976-
// TODO: Model extracts explicitly.
977-
State.Builder.SetInsertPoint(PredBB, PredBB->getFirstNonPHIIt());
978-
Value *V = State.get(ExitValue, VPLane(Lane));
979-
auto *Phi = cast<PHINode>(&I);
980-
// If there is no existing block for PredBB in the phi, add a new incoming
981-
// value. Otherwise update the existing incoming value for PredBB.
982-
if (Phi->getBasicBlockIndex(PredBB) == -1)
983-
Phi->addIncoming(V, PredBB);
984-
else
985-
Phi->setIncomingValueForBlock(PredBB, V);
986-
}
964+
VPIRInstruction *VPIRInstruction ::create(Instruction &I) {
965+
if (auto *Phi = dyn_cast<PHINode>(&I))
966+
return new VPIRPhi(*Phi);
967+
return new VPIRInstruction(I);
968+
}
987969

970+
void VPIRInstruction::execute(VPTransformState &State) {
971+
assert(!isa<VPIRPhi>(this) && getNumOperands() == 0 &&
972+
"PHINodes must be handled by VPIRPhi");
988973
// Advance the insert point after the wrapped IR instruction. This allows
989974
// interleaving VPIRInstructions and other recipes.
990975
State.Builder.SetInsertPoint(I.getParent(), std::next(I.getIterator()));
@@ -1017,6 +1002,40 @@ void VPIRInstruction::extractLastLaneOfOperand(VPBuilder &Builder) {
10171002
void VPIRInstruction::print(raw_ostream &O, const Twine &Indent,
10181003
VPSlotTracker &SlotTracker) const {
10191004
O << Indent << "IR " << I;
1005+
}
1006+
#endif
1007+
1008+
void VPIRPhi::execute(VPTransformState &State) {
1009+
PHINode *Phi = &getIRPhi();
1010+
for (const auto &[Idx, Op] : enumerate(operands())) {
1011+
VPValue *ExitValue = Op;
1012+
auto Lane = vputils::isUniformAfterVectorization(ExitValue)
1013+
? VPLane::getFirstLane()
1014+
: VPLane::getLastLaneForVF(State.VF);
1015+
VPBlockBase *Pred = getParent()->getPredecessors()[Idx];
1016+
auto *PredVPBB = Pred->getExitingBasicBlock();
1017+
BasicBlock *PredBB = State.CFG.VPBB2IRBB[PredVPBB];
1018+
// Set insertion point in PredBB in case an extract needs to be generated.
1019+
// TODO: Model extracts explicitly.
1020+
State.Builder.SetInsertPoint(PredBB, PredBB->getFirstNonPHIIt());
1021+
Value *V = State.get(ExitValue, VPLane(Lane));
1022+
// If there is no existing block for PredBB in the phi, add a new incoming
1023+
// value. Otherwise update the existing incoming value for PredBB.
1024+
if (Phi->getBasicBlockIndex(PredBB) == -1)
1025+
Phi->addIncoming(V, PredBB);
1026+
else
1027+
Phi->setIncomingValueForBlock(PredBB, V);
1028+
}
1029+
1030+
// Advance the insert point after the wrapped IR instruction. This allows
1031+
// interleaving VPIRInstructions and other recipes.
1032+
State.Builder.SetInsertPoint(Phi->getParent(), std::next(Phi->getIterator()));
1033+
}
1034+
1035+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1036+
void VPIRPhi::print(raw_ostream &O, const Twine &Indent,
1037+
VPSlotTracker &SlotTracker) const {
1038+
VPIRInstruction::print(O, Indent, SlotTracker);
10201039

10211040
if (getNumOperands() != 0) {
10221041
O << " (extra operand" << (getNumOperands() > 1 ? "s" : "") << ": ";

llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -749,8 +749,8 @@ void VPlanTransforms::optimizeInductionExitUsers(
749749
VPTypeAnalysis TypeInfo(Plan.getCanonicalIV()->getScalarType());
750750
VPBuilder B(Plan.getMiddleBlock()->getTerminator());
751751
for (VPRecipeBase &R : *ExitVPBB) {
752-
auto *ExitIRI = cast<VPIRInstruction>(&R);
753-
if (!isa<PHINode>(ExitIRI->getInstruction()))
752+
auto *ExitIRI = dyn_cast<VPIRPhi>(&R);
753+
if (!ExitIRI)
754754
break;
755755

756756
VPValue *Incoming;
@@ -2088,20 +2088,20 @@ void VPlanTransforms::handleUncountableEarlyExit(
20882088
VPBuilder MiddleBuilder(NewMiddle);
20892089
VPBuilder EarlyExitB(VectorEarlyExitVPBB);
20902090
for (VPRecipeBase &R : *VPEarlyExitBlock) {
2091-
auto *ExitIRI = cast<VPIRInstruction>(&R);
2092-
auto *ExitPhi = dyn_cast<PHINode>(&ExitIRI->getInstruction());
2093-
if (!ExitPhi)
2091+
auto *ExitIRI = dyn_cast<VPIRPhi>(&R);
2092+
if (!ExitIRI)
20942093
break;
20952094

2095+
PHINode &ExitPhi = ExitIRI->getIRPhi();
20962096
VPValue *IncomingFromEarlyExit = RecipeBuilder.getVPValueOrAddLiveIn(
2097-
ExitPhi->getIncomingValueForBlock(UncountableExitingBlock));
2097+
ExitPhi.getIncomingValueForBlock(UncountableExitingBlock));
20982098

20992099
if (OrigLoop->getUniqueExitBlock()) {
21002100
// If there's a unique exit block, VPEarlyExitBlock has 2 predecessors
21012101
// (MiddleVPBB and NewMiddle). Add the incoming value from MiddleVPBB
21022102
// which is coming from the original latch.
21032103
VPValue *IncomingFromLatch = RecipeBuilder.getVPValueOrAddLiveIn(
2104-
ExitPhi->getIncomingValueForBlock(OrigLoop->getLoopLatch()));
2104+
ExitPhi.getIncomingValueForBlock(OrigLoop->getLoopLatch()));
21052105
ExitIRI->addOperand(IncomingFromLatch);
21062106
ExitIRI->extractLastLaneOfOperand(MiddleBuilder);
21072107
}

llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,8 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
204204
for (const VPUser *U : V->users()) {
205205
auto *UI = cast<VPRecipeBase>(U);
206206
// TODO: check dominance of incoming values for phis properly.
207-
if (!UI ||
208-
isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPredInstPHIRecipe>(UI) ||
209-
(isa<VPIRInstruction>(UI) &&
210-
isa<PHINode>(cast<VPIRInstruction>(UI)->getInstruction())))
207+
if (!UI || isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPredInstPHIRecipe,
208+
VPIRPhi>(UI))
211209
continue;
212210

213211
// If the user is in the same block, check it comes after R in the

0 commit comments

Comments
 (0)