-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[VPlan] Add new VPIRPhi overlay for VPIRInsts wrapping phi nodes (NFC). #129387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c305e73
85548a3
58a5e5d
4edb5c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1026,22 +1026,28 @@ class VPInstruction : public VPRecipeWithIRFlags, | |
}; | ||
|
||
/// A recipe to wrap on original IR instruction not to be modified during | ||
/// execution, execept for PHIs. For PHIs, a single VPValue operand is allowed, | ||
/// and it is used to add a new incoming value for the single predecessor VPBB. | ||
/// execution, except for PHIs. PHIs are modeled via the VPIRPhi subclass. | ||
/// Expect PHIs, VPIRInstructions cannot have any operands. | ||
class VPIRInstruction : public VPRecipeBase { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The above documentation deserves an update. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated thanks |
||
Instruction &I; | ||
|
||
public: | ||
protected: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth documenting that VPIRInstructions should be constructed by calling create() rather than the constructor directly, as a subclass may potentially be created. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done thanks! |
||
/// VPIRInstruction::create() should be used to create VPIRInstructions, as | ||
/// subclasses may need to be created, e.g. VPIRPhi. | ||
VPIRInstruction(Instruction &I) | ||
: VPRecipeBase(VPDef::VPIRInstructionSC, ArrayRef<VPValue *>()), I(I) {} | ||
|
||
public: | ||
~VPIRInstruction() override = default; | ||
|
||
/// Create a new VPIRPhi for \p \I, if it is a PHINode, otherwise create a | ||
/// VPIRInstruction. | ||
static VPIRInstruction *create(Instruction &I); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth documenting There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done thanks |
||
|
||
VP_CLASSOF_IMPL(VPDef::VPIRInstructionSC) | ||
|
||
VPIRInstruction *clone() override { | ||
auto *R = new VPIRInstruction(I); | ||
auto *R = create(I); | ||
for (auto *Op : operands()) | ||
R->addOperand(Op); | ||
return R; | ||
|
@@ -1085,6 +1091,29 @@ class VPIRInstruction : public VPRecipeBase { | |
void extractLastLaneOfOperand(VPBuilder &Builder); | ||
}; | ||
|
||
/// An overlay for VPIRInstructions wrapping PHI nodes enabling convenient use | ||
/// cast/dyn_cast/isa and execute() implementation. A single VPValue operand is | ||
/// allowed, and it is used to add a new incoming value for the single | ||
/// predecessor VPBB. | ||
struct VPIRPhi : public VPIRInstruction { | ||
VPIRPhi(PHINode &PN) : VPIRInstruction(PN) {} | ||
|
||
static inline bool classof(const VPRecipeBase *U) { | ||
auto *R = dyn_cast<VPIRInstruction>(U); | ||
return R && isa<PHINode>(R->getInstruction()); | ||
Comment on lines
+1102
to
+1103
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is needed because VPIRPhi reuses VPIRInstruction's VPDEF::VPIRInstructionSC rather than defining its own? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep |
||
} | ||
|
||
PHINode &getIRPhi() { return cast<PHINode>(getInstruction()); } | ||
|
||
void execute(VPTransformState &State) override; | ||
|
||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | ||
/// Print the recipe. | ||
void print(raw_ostream &O, const Twine &Indent, | ||
VPSlotTracker &SlotTracker) const override; | ||
#endif | ||
}; | ||
|
||
/// VPWidenRecipe is a recipe for producing a widened instruction using the | ||
/// opcode and operands of the recipe. This recipe covers most of the | ||
/// traditional vectorization cases where each recipe transforms into a | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -1061,30 +1061,15 @@ void VPInstruction::print(raw_ostream &O, const Twine &Indent, | |||||||
} | ||||||||
#endif | ||||||||
|
||||||||
void VPIRInstruction::execute(VPTransformState &State) { | ||||||||
assert((isa<PHINode>(&I) || getNumOperands() == 0) && | ||||||||
"Only PHINodes can have extra operands"); | ||||||||
for (const auto &[Idx, Op] : enumerate(operands())) { | ||||||||
VPValue *ExitValue = Op; | ||||||||
auto Lane = vputils::isUniformAfterVectorization(ExitValue) | ||||||||
? VPLane::getFirstLane() | ||||||||
: VPLane::getLastLaneForVF(State.VF); | ||||||||
VPBlockBase *Pred = getParent()->getPredecessors()[Idx]; | ||||||||
auto *PredVPBB = Pred->getExitingBasicBlock(); | ||||||||
BasicBlock *PredBB = State.CFG.VPBB2IRBB[PredVPBB]; | ||||||||
// Set insertion point in PredBB in case an extract needs to be generated. | ||||||||
// TODO: Model extracts explicitly. | ||||||||
State.Builder.SetInsertPoint(PredBB, PredBB->getFirstNonPHIIt()); | ||||||||
Value *V = State.get(ExitValue, VPLane(Lane)); | ||||||||
auto *Phi = cast<PHINode>(&I); | ||||||||
// If there is no existing block for PredBB in the phi, add a new incoming | ||||||||
// value. Otherwise update the existing incoming value for PredBB. | ||||||||
if (Phi->getBasicBlockIndex(PredBB) == -1) | ||||||||
Phi->addIncoming(V, PredBB); | ||||||||
else | ||||||||
Phi->setIncomingValueForBlock(PredBB, V); | ||||||||
} | ||||||||
VPIRInstruction *VPIRInstruction ::create(Instruction &I) { | ||||||||
if (auto *Phi = dyn_cast<PHINode>(&I)) | ||||||||
return new VPIRPhi(*Phi); | ||||||||
return new VPIRInstruction(I); | ||||||||
} | ||||||||
|
||||||||
void VPIRInstruction::execute(VPTransformState &State) { | ||||||||
assert(!isa<VPIRPhi>(this) && getNumOperands() == 0 && | ||||||||
"PHINodes must be handled by VPIRPhi"); | ||||||||
// Advance the insert point after the wrapped IR instruction. This allows | ||||||||
// interleaving VPIRInstructions and other recipes. | ||||||||
State.Builder.SetInsertPoint(I.getParent(), std::next(I.getIterator())); | ||||||||
|
@@ -1117,6 +1102,40 @@ void VPIRInstruction::extractLastLaneOfOperand(VPBuilder &Builder) { | |||||||
void VPIRInstruction::print(raw_ostream &O, const Twine &Indent, | ||||||||
VPSlotTracker &SlotTracker) const { | ||||||||
O << Indent << "IR " << I; | ||||||||
} | ||||||||
#endif | ||||||||
|
||||||||
void VPIRPhi::execute(VPTransformState &State) { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are VPIRPhi recipes expected to have at-least one operand?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are still cases we create VPIRPhi without operands, e.g. if the entry block contains existing lcssa phis, which do not need updating |
||||||||
PHINode *Phi = &getIRPhi(); | ||||||||
for (const auto &[Idx, Op] : enumerate(operands())) { | ||||||||
VPValue *ExitValue = Op; | ||||||||
auto Lane = vputils::isUniformAfterVectorization(ExitValue) | ||||||||
? VPLane::getFirstLane() | ||||||||
: VPLane::getLastLaneForVF(State.VF); | ||||||||
VPBlockBase *Pred = getParent()->getPredecessors()[Idx]; | ||||||||
auto *PredVPBB = Pred->getExitingBasicBlock(); | ||||||||
BasicBlock *PredBB = State.CFG.VPBB2IRBB[PredVPBB]; | ||||||||
// Set insertion point in PredBB in case an extract needs to be generated. | ||||||||
// TODO: Model extracts explicitly. | ||||||||
State.Builder.SetInsertPoint(PredBB, PredBB->getFirstNonPHIIt()); | ||||||||
Value *V = State.get(ExitValue, VPLane(Lane)); | ||||||||
// If there is no existing block for PredBB in the phi, add a new incoming | ||||||||
// value. Otherwise update the existing incoming value for PredBB. | ||||||||
if (Phi->getBasicBlockIndex(PredBB) == -1) | ||||||||
Phi->addIncoming(V, PredBB); | ||||||||
else | ||||||||
Phi->setIncomingValueForBlock(PredBB, V); | ||||||||
} | ||||||||
|
||||||||
// Advance the insert point after the wrapped IR instruction. This allows | ||||||||
// interleaving VPIRInstructions and other recipes. | ||||||||
State.Builder.SetInsertPoint(Phi->getParent(), std::next(Phi->getIterator())); | ||||||||
} | ||||||||
|
||||||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | ||||||||
void VPIRPhi::print(raw_ostream &O, const Twine &Indent, | ||||||||
VPSlotTracker &SlotTracker) const { | ||||||||
VPIRInstruction::print(O, Indent, SlotTracker); | ||||||||
|
||||||||
if (getNumOperands() != 0) { | ||||||||
O << " (extra operand" << (getNumOperands() > 1 ? "s" : "") << ": "; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This now indicates that the recipe is a VPIRPhi? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are still cases we create VPIRPhi without operands, e.g. if the entry block contains existing lcssa phis, which do not need updating |
||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Supporting non VPIRInstruction recipes introduced inside ExitVPBB, which admittedly has yet to be exercised, is dropped? Worth a comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep this was intentional and matches behavior in other places, for now there are only IR phis to handle.