[llvm] [VPlan] Factor vputils::getOpcodeOrIntrinsicID (NFC) (PR #208993)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 18 03:46:39 PDT 2026
https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/208993
>From 2d533261d1a5460b6d92d8e1a3ad9c8391a63fef Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <artagnon at tenstorrent.com>
Date: Sun, 12 Jul 2026 08:17:54 +0100
Subject: [PATCH] [VPlan] Factor vputils::getOpcodeOrIntrinsicID (NFC)
The check for recipes in vputils::isElementWise is necessary to prevent
regressions.
---
llvm/lib/Transforms/Vectorize/VPlan.h | 3 ++
.../Transforms/Vectorize/VPlanTransforms.cpp | 6 +--
llvm/lib/Transforms/Vectorize/VPlanUtils.cpp | 54 +++++++++----------
llvm/lib/Transforms/Vectorize/VPlanUtils.h | 12 +++--
4 files changed, 40 insertions(+), 35 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 13f47d72c5aef..edb24141f6073 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -2752,6 +2752,9 @@ class LLVM_ABI_FOR_TEST VPWidenPHIRecipe : public VPSingleDefRecipe,
~VPWidenPHIRecipe() override = default;
+ /// This recipe generates a PHI.
+ unsigned getOpcode() const { return Instruction::PHI; }
+
VP_CLASSOF_IMPL(VPRecipeBase::VPWidenPHISC)
/// Generate the phi/select nodes.
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 80d44ecd1a440..84d381576c020 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1879,8 +1879,7 @@ static void narrowToSingleScalarRecipes(VPlan &Plan) {
continue;
auto *Clone = VPBuilder::createSingleScalarOp(
- vputils::getOpcodeOrIntrinsicID(RepOrWidenR)->second,
- RepOrWidenR->operands(),
+ vputils::getOpcode(RepOrWidenR), RepOrWidenR->operands(),
/*Mask=*/nullptr, *RepOrWidenR, {}, DebugLoc::getUnknown(),
RepOrWidenR->getUnderlyingInstr());
Clone->insertBefore(RepOrWidenR);
@@ -5084,8 +5083,7 @@ static bool canNarrowOps(ArrayRef<VPValue *> Ops, bool IsScalable) {
if (!isa<VPWidenRecipe, VPWidenCastRecipe>(V))
return false;
auto *R = cast<VPRecipeWithIRFlags>(V);
- if (vputils::getOpcodeOrIntrinsicID(R) !=
- vputils::getOpcodeOrIntrinsicID(WideMember0))
+ if (vputils::getOpcode(R) != vputils::getOpcode(WideMember0))
return false;
if (R->getScalarType() != WideMember0->getScalarType())
return false;
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
index 4ffca9ca282ac..26d34304eb8f9 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
@@ -363,6 +363,30 @@ bool vputils::isAddressSCEVForCost(const SCEV *Addr, ScalarEvolution &SE,
match(Addr, m_scev_AffineAddRec(m_SCEV(), m_SCEV()));
}
+unsigned vputils::getOpcode(const VPValue *V) {
+ return TypeSwitch<const VPValue *, unsigned>(V)
+ .Case<VPInstruction, VPWidenRecipe, VPWidenCastRecipe, VPWidenGEPRecipe,
+ VPReplicateRecipe, VPWidenPHIRecipe>(
+ [](auto *I) { return I->getOpcode(); })
+ .Case<VPVectorPointerRecipe, VPPredInstPHIRecipe, VPScalarIVStepsRecipe>(
+ [](auto *I) {
+ // For recipes that do not directly map to LLVM IR instructions,
+ // assign opcodes after the last VPInstruction opcode (which is also
+ // after the last IR Instruction opcode), based on the VPRecipeID.
+ return VPInstruction::OpsEnd + 1 + I->getVPRecipeID();
+ })
+ .Default([](auto *) { return 0; });
+}
+
+std::optional<std::pair<bool, unsigned>>
+vputils::getOpcodeOrIntrinsicID(const VPValue *V) {
+ if (Intrinsic::ID IID = vputils::getIntrinsicID(V))
+ return std::make_pair(true, IID);
+ if (unsigned Opcode = vputils::getOpcode(V))
+ return std::make_pair(false, Opcode);
+ return {};
+}
+
/// Returns true if \p Opcode preserves uniformity, i.e., if all operands are
/// uniform, the result will also be uniform.
static bool preservesUniformity(unsigned Opcode) {
@@ -385,11 +409,10 @@ static bool preservesUniformity(unsigned Opcode) {
}
bool vputils::isElementwise(const VPValue *V) {
- unsigned Opcode = TypeSwitch<const VPValue *, unsigned>(V)
- .Case<VPInstruction, VPWidenRecipe>(
- [](auto *R) { return R->getOpcode(); })
- .Default([](auto *) { return 0; });
// TODO: Handle more opcodes and recipes.
+ if (!isa<VPInstruction, VPWidenRecipe>(V))
+ return false;
+ unsigned Opcode = getOpcode(V);
return Instruction::isUnaryOp(Opcode) || Instruction::isBinaryOp(Opcode);
}
@@ -905,29 +928,6 @@ VPValue *VPSCEVExpander::tryToExpand(const SCEV *S) {
}
}
-std::optional<std::pair<bool, unsigned>>
-vputils::getOpcodeOrIntrinsicID(const VPSingleDefRecipe *R) {
- if (Intrinsic::ID IID = vputils::getIntrinsicID(R))
- return std::make_pair(true, IID);
- return TypeSwitch<const VPSingleDefRecipe *,
- std::optional<std::pair<bool, unsigned>>>(R)
- .Case<VPInstruction, VPWidenRecipe, VPWidenCastRecipe, VPWidenGEPRecipe,
- VPReplicateRecipe>(
- [](auto *I) { return std::make_pair(false, I->getOpcode()); })
- .Case([](const VPWidenPHIRecipe *I) {
- return std::make_pair(false, Instruction::PHI);
- })
- .Case<VPVectorPointerRecipe, VPPredInstPHIRecipe, VPScalarIVStepsRecipe>(
- [](auto *I) {
- // For recipes that do not directly map to LLVM IR instructions,
- // assign opcodes after the last VPInstruction opcode (which is also
- // after the last IR Instruction opcode), based on the VPRecipeID.
- return std::make_pair(false, VPInstruction::OpsEnd + 1 +
- I->getVPRecipeID());
- })
- .Default([](auto *) { return std::nullopt; });
-}
-
bool vputils::isDeadRecipe(VPRecipeBase &R) {
// Do remove conditional assume instructions as their conditions may be
// flattened.
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUtils.h b/llvm/lib/Transforms/Vectorize/VPlanUtils.h
index d1c6af27de97f..56e09d8998953 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.h
@@ -109,11 +109,15 @@ template <typename Ty> Intrinsic::ID getIntrinsicID(const Ty *R) {
return Intrinsic::not_intrinsic;
}
-/// Get any instruction opcode or intrinsic ID data embedded in recipe \p R.
-/// Returns an optional pair, where the first element indicates whether it is
-/// an intrinsic ID.
+/// Return the instruction opcode for the recipe defining \p V or 0 for
+/// unsupported recipes and VPValues not defined by a recipe.
+unsigned getOpcode(const VPValue *V);
+
+/// Get the instruction opcode or intrinsic ID for the recipe defining \p V.
+/// Returns an optional pair, where the first element indicates whether it is an
+/// intrinsic ID.
std::optional<std::pair<bool, unsigned>>
-getOpcodeOrIntrinsicID(const VPSingleDefRecipe *R);
+getOpcodeOrIntrinsicID(const VPValue *V);
/// Return a MemoryLocation for \p R with noalias metadata populated from
/// \p R, if the recipe is supported and std::nullopt otherwise. The pointer of
More information about the llvm-commits
mailing list