[llvm] [VPlan] Add VPPhiAccessors to provide interface for phi recipes (NFC) (PR #129388)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 13 11:04:11 PDT 2025
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/129388
>From b357af496024fe12bc56a39b89dbff036b65b952 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 27 Feb 2025 21:49:14 +0000
Subject: [PATCH 1/2] [VPlan] Add VPPhiAccessors to provide interface for phi
recipes (NFC)
Add a VPPhiAccessors class to provide interfaces to access incoming
values and blocks, with corresponding iterators.
The first user is VPWidenPhiRecipe, with the other phi-like recipes
following soon.
This will also be used to verify def-use chains where users are phi-like
recipes, simplifying https://github.com/llvm/llvm-project/pull/124838.
---
.../Transforms/Vectorize/LoopVectorize.cpp | 6 +-
llvm/lib/Transforms/Vectorize/VPlan.h | 65 +++++++++++++++++--
.../lib/Transforms/Vectorize/VPlanRecipes.cpp | 46 +++++++------
3 files changed, 87 insertions(+), 30 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index e2612698b6b0f..98ff1a4cdc449 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -3069,11 +3069,9 @@ void InnerLoopVectorizer::fixNonInductionPHIs(VPTransformState &State) {
PHINode *NewPhi = cast<PHINode>(State.get(VPPhi));
// Make sure the builder has a valid insert point.
Builder.SetInsertPoint(NewPhi);
- for (unsigned Idx = 0; Idx < VPPhi->getNumOperands(); ++Idx) {
- VPValue *Inc = VPPhi->getIncomingValue(Idx);
- VPBasicBlock *VPBB = VPPhi->getIncomingBlock(Idx);
+
+ for (const auto &[Inc, VPBB] : VPPhi->incoming_values_and_blocks())
NewPhi->addIncoming(State.get(Inc), State.CFG.VPBB2IRBB[VPBB]);
- }
}
}
}
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 70e684826ed2d..4d5f2014a40dc 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -1085,6 +1085,62 @@ class VPIRInstruction : public VPRecipeBase {
void extractLastLaneOfOperand(VPBuilder &Builder);
};
+/// Helper type to provide functions to access incoming values and blocks for
+/// phi-like recipes. RecipeTy must be a sub-class of VPRecipeBase.
+template <typename RecipeTy> class VPPhiAccessors {
+ /// Return a VPRecipeBase* to the current object.
+ const VPRecipeBase *getAsRecipe() const {
+ return static_cast<const RecipeTy *>(this);
+ }
+
+public:
+ /// Returns the \p I th incoming VPValue.
+ VPValue *getIncomingValue(unsigned I) const {
+ return getAsRecipe()->getOperand(I);
+ }
+
+ /// Returns an interator range over the incoming values
+ VPUser::const_operand_range incoming_values() const {
+ return getAsRecipe()->operands();
+ }
+
+ /// Returns the \p I th incoming block.
+ const VPBasicBlock *getIncomingBlock(unsigned Idx) const;
+
+ using const_incoming_block_iterator =
+ mapped_iterator<detail::index_iterator,
+ std::function<const VPBasicBlock *(size_t)>>;
+ using const_incoming_blocks_range =
+ iterator_range<const_incoming_block_iterator>;
+
+ const_incoming_block_iterator incoming_block_begin() const {
+ return const_incoming_block_iterator(
+ detail::index_iterator(0),
+ [this](size_t Idx) { return getIncomingBlock(Idx); });
+ }
+ const_incoming_block_iterator incoming_block_end() const {
+ return const_incoming_block_iterator(
+ detail::index_iterator(getAsRecipe()->getVPDefID() ==
+ VPDef::VPWidenIntOrFpInductionSC
+ ? 2
+ : getAsRecipe()->getNumOperands()),
+ [this](size_t Idx) { return getIncomingBlock(Idx); });
+ }
+
+ /// Returns an iterator range over the incoming blocks.
+ const_incoming_blocks_range incoming_blocks() const {
+ return make_range(incoming_block_begin(), incoming_block_end());
+ }
+
+ /// Returns an iterator range over pairs of incoming values and corrsponding
+ /// incoming blocks.
+ detail::zippy<llvm::detail::zip_shortest, VPUser::const_operand_range,
+ const_incoming_blocks_range>
+ incoming_values_and_blocks() const {
+ return zip(incoming_values(), incoming_blocks());
+ }
+};
+
/// 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
@@ -1944,7 +2000,8 @@ class VPScalarPHIRecipe : public VPHeaderPHIRecipe {
/// recipe is placed in an entry block to a (non-replicate) region, it must have
/// exactly 2 incoming values, the first from the predecessor of the region and
/// the second from the exiting block of the region.
-class VPWidenPHIRecipe : public VPSingleDefRecipe {
+class VPWidenPHIRecipe : public VPSingleDefRecipe,
+ public VPPhiAccessors<VPWidenPHIRecipe> {
public:
/// Create a new VPWidenPHIRecipe for \p Phi with start value \p Start and
/// debug location \p DL.
@@ -1970,12 +2027,6 @@ class VPWidenPHIRecipe : public VPSingleDefRecipe {
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
-
- /// Returns the \p I th incoming VPBasicBlock.
- VPBasicBlock *getIncomingBlock(unsigned I);
-
- /// Returns the \p I th incoming VPValue.
- VPValue *getIncomingValue(unsigned I) { return getOperand(I); }
};
/// A recipe for handling first-order recurrence phis. The start value is the
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index e9f50e88867b2..efac05785203c 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -1031,6 +1031,29 @@ void VPIRInstruction::print(raw_ostream &O, const Twine &Indent,
}
#endif
+static const VPBasicBlock *getIncomingBlockForRecipe(const VPRecipeBase *R,
+ unsigned I) {
+ const VPBasicBlock *Parent = R->getParent();
+ const VPBlockBase *Pred = nullptr;
+ if (Parent->getNumPredecessors() > 0) {
+ Pred = Parent->getPredecessors()[I];
+ } else {
+ auto *Region = Parent->getParent();
+ assert(Region && !Region->isReplicator() && Region->getEntry() == Parent &&
+ "must be in the entry block of a non-replicate region");
+ assert(
+ I < 2 &&
+ (R->getNumOperands() == 2 || isa<VPWidenIntOrFpInductionRecipe>(R)) &&
+ "when placed in an entry block, only 2 incoming blocks are available");
+
+ // I == 0 selects the predecessor of the region, I == 1 selects the region
+ // itself whose exiting block feeds the phi across the backedge.
+ Pred = I == 0 ? Region->getSinglePredecessor() : Region;
+ }
+
+ return Pred->getExitingBasicBlock();
+}
+
void VPWidenCallRecipe::execute(VPTransformState &State) {
assert(State.VF.isVector() && "not widening");
State.setDebugLocFrom(getDebugLoc());
@@ -3580,25 +3603,10 @@ void VPReductionPHIRecipe::print(raw_ostream &O, const Twine &Indent,
}
#endif
-VPBasicBlock *VPWidenPHIRecipe::getIncomingBlock(unsigned I) {
- VPBasicBlock *Parent = getParent();
- VPBlockBase *Pred = nullptr;
- if (Parent->getNumPredecessors() > 0) {
- Pred = Parent->getPredecessors()[I];
- } else {
- auto *Region = Parent->getParent();
- assert(Region && !Region->isReplicator() && Region->getEntry() == Parent &&
- "must be in the entry block of a non-replicate region");
- assert(
- I < 2 && getNumOperands() == 2 &&
- "when placed in an entry block, only 2 incoming blocks are available");
-
- // I == 0 selects the predecessor of the region, I == 1 selects the region
- // itself whose exiting block feeds the phi across the backedge.
- Pred = I == 0 ? Region->getSinglePredecessor() : Region;
- }
-
- return Pred->getExitingBasicBlock();
+template <>
+const VPBasicBlock *
+VPPhiAccessors<VPWidenPHIRecipe>::getIncomingBlock(unsigned Idx) const {
+ return getIncomingBlockForRecipe(getAsRecipe(), Idx);
}
void VPWidenPHIRecipe::execute(VPTransformState &State) {
>From c61233f4096202789ebeaa11061d70bb53cdd2af Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 13 Mar 2025 16:25:03 +0000
Subject: [PATCH 2/2] !fixup address latest comments, thanks
---
llvm/lib/Transforms/Vectorize/VPlan.h | 15 ++++++---------
llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp | 17 ++++++++++-------
2 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 1915b90675193..63d946a0dede9 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -1095,9 +1095,9 @@ template <typename RecipeTy> class VPPhiAccessors {
}
public:
- /// Returns the \p I th incoming VPValue.
- VPValue *getIncomingValue(unsigned I) const {
- return getAsRecipe()->getOperand(I);
+ /// Returns the incoming VPValue with index \p Idx.
+ VPValue *getIncomingValue(unsigned Idx) const {
+ return getAsRecipe()->getOperand(Idx);
}
/// Returns an interator range over the incoming values
@@ -1105,7 +1105,7 @@ template <typename RecipeTy> class VPPhiAccessors {
return getAsRecipe()->operands();
}
- /// Returns the \p I th incoming block.
+ /// Returns the incoming block with index \p Idx.
const VPBasicBlock *getIncomingBlock(unsigned Idx) const;
using const_incoming_block_iterator =
@@ -1121,10 +1121,7 @@ template <typename RecipeTy> class VPPhiAccessors {
}
const_incoming_block_iterator incoming_block_end() const {
return const_incoming_block_iterator(
- detail::index_iterator(getAsRecipe()->getVPDefID() ==
- VPDef::VPWidenIntOrFpInductionSC
- ? 2
- : getAsRecipe()->getNumOperands()),
+ detail::index_iterator(getAsRecipe()->getNumOperands()),
[this](size_t Idx) { return getIncomingBlock(Idx); });
}
@@ -1133,7 +1130,7 @@ template <typename RecipeTy> class VPPhiAccessors {
return make_range(incoming_block_begin(), incoming_block_end());
}
- /// Returns an iterator range over pairs of incoming values and corrsponding
+ /// Returns an iterator range over pairs of incoming values and correspondingx
/// incoming blocks.
detail::zippy<llvm::detail::zip_shortest, VPUser::const_operand_range,
const_incoming_blocks_range>
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 8f2142b6c3260..73f0c329e5b66 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -1042,24 +1042,27 @@ void VPIRInstruction::print(raw_ostream &O, const Twine &Indent,
}
#endif
+/// Returns the incoming block at index \p Idx for \p R. This handles both
+/// recipes placed in entry blocks of loop regions (incoming blocks are the
+/// region's predecessor and the region's exit) and other locations (incoming
+/// blocks are the direct predecessors).
static const VPBasicBlock *getIncomingBlockForRecipe(const VPRecipeBase *R,
- unsigned I) {
+ unsigned Idx) {
const VPBasicBlock *Parent = R->getParent();
const VPBlockBase *Pred = nullptr;
if (Parent->getNumPredecessors() > 0) {
- Pred = Parent->getPredecessors()[I];
+ Pred = Parent->getPredecessors()[Idx];
} else {
auto *Region = Parent->getParent();
assert(Region && !Region->isReplicator() && Region->getEntry() == Parent &&
"must be in the entry block of a non-replicate region");
assert(
- I < 2 &&
- (R->getNumOperands() == 2 || isa<VPWidenIntOrFpInductionRecipe>(R)) &&
+ Idx < 2 && R->getNumOperands() == 2 &&
"when placed in an entry block, only 2 incoming blocks are available");
- // I == 0 selects the predecessor of the region, I == 1 selects the region
- // itself whose exiting block feeds the phi across the backedge.
- Pred = I == 0 ? Region->getSinglePredecessor() : Region;
+ // Idx == 0 selects the predecessor of the region, Idx == 1 selects the
+ // region itself whose exiting block feeds the phi across the backedge.
+ Pred = Idx == 0 ? Region->getSinglePredecessor() : Region;
}
return Pred->getExitingBasicBlock();
More information about the llvm-commits
mailing list