[llvm] [VPlan] Factor vputils::getOpcodeOrIntrinsicID (NFC) (PR #208993)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 14 02:29:54 PDT 2026
https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/208993
>From cc2e075141fc1202d8a3322620832d0da23f0c87 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 | 42 ++++---------------
llvm/lib/Transforms/Vectorize/VPlanUtils.cpp | 31 ++++++++++++--
llvm/lib/Transforms/Vectorize/VPlanUtils.h | 9 ++++
4 files changed, 48 insertions(+), 37 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 46e2ad4716323..874aabf6ddb50 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 4da74c5146c52..604810f66aa0d 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1249,39 +1249,13 @@ static void recursivelyDeleteDeadRecipes(VPValue *V) {
}
}
-/// 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.
-static std::optional<std::pair<bool, unsigned>>
-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; });
-}
-
/// Try to fold \p R using InstSimplifyFolder. Will succeed and return a
/// non-nullptr VPValue for a handled opcode or intrinsic ID if corresponding \p
/// Operands are foldable live-ins.
static VPIRValue *tryToFoldLiveIns(VPSingleDefRecipe &R,
ArrayRef<VPValue *> Operands,
const DataLayout &DL) {
- auto OpcodeOrIID = getOpcodeOrIntrinsicID(&R);
+ auto OpcodeOrIID = vputils::getOpcodeOrIntrinsicID(&R);
if (!OpcodeOrIID)
return nullptr;
@@ -2069,7 +2043,7 @@ static void narrowToSingleScalarRecipes(VPlan &Plan) {
continue;
auto *Clone = VPBuilder::createSingleScalarOp(
- getOpcodeOrIntrinsicID(RepOrWidenR)->second, RepOrWidenR->operands(),
+ vputils::getOpcode(RepOrWidenR), RepOrWidenR->operands(),
/*Mask=*/nullptr, *RepOrWidenR, {}, DebugLoc::getUnknown(),
RepOrWidenR->getUnderlyingInstr());
Clone->insertBefore(RepOrWidenR);
@@ -2533,7 +2507,7 @@ struct VPCSEDenseMapInfo : public DenseMapInfo<VPSingleDefRecipe *> {
// We can extend the list of handled recipes in the future,
// provided we account for the data embedded in them while checking for
// equality or hashing.
- auto C = getOpcodeOrIntrinsicID(Def);
+ auto C = vputils::getOpcodeOrIntrinsicID(Def);
// The issue with (Insert|Extract)Value is that the index of the
// insert/extract is not a proper operand in LLVM IR, and hence also not in
@@ -2549,7 +2523,7 @@ struct VPCSEDenseMapInfo : public DenseMapInfo<VPSingleDefRecipe *> {
/// Hash the underlying data of \p Def.
static unsigned getHashValue(const VPSingleDefRecipe *Def) {
hash_code Result = hash_combine(
- Def->getVPRecipeID(), getOpcodeOrIntrinsicID(Def),
+ Def->getVPRecipeID(), vputils::getOpcodeOrIntrinsicID(Def),
getGEPSourceElementType(Def), Def->getScalarType(),
vputils::isSingleScalar(Def), hash_combine_range(Def->operands()));
if (auto *RFlags = dyn_cast<VPRecipeWithIRFlags>(Def))
@@ -2563,12 +2537,14 @@ struct VPCSEDenseMapInfo : public DenseMapInfo<VPSingleDefRecipe *> {
/// Check equality of underlying data of \p L and \p R.
static bool isEqual(const VPSingleDefRecipe *L, const VPSingleDefRecipe *R) {
if (L->getVPRecipeID() != R->getVPRecipeID() ||
- getOpcodeOrIntrinsicID(L) != getOpcodeOrIntrinsicID(R) ||
+ vputils::getOpcodeOrIntrinsicID(L) !=
+ vputils::getOpcodeOrIntrinsicID(R) ||
getGEPSourceElementType(L) != getGEPSourceElementType(R) ||
vputils::isSingleScalar(L) != vputils::isSingleScalar(R) ||
!equal(L->operands(), R->operands()))
return false;
- assert(getOpcodeOrIntrinsicID(L) && getOpcodeOrIntrinsicID(R) &&
+ assert(vputils::getOpcodeOrIntrinsicID(L) &&
+ vputils::getOpcodeOrIntrinsicID(R) &&
"must have valid opcode info for both recipes");
if (auto *LFlags = dyn_cast<VPRecipeWithIRFlags>(L))
if (LFlags->hasPredicate() &&
@@ -5906,7 +5882,7 @@ static bool canNarrowOps(ArrayRef<VPValue *> Ops, bool IsScalable) {
if (!isa<VPWidenRecipe, VPWidenCastRecipe>(V))
return false;
auto *R = cast<VPRecipeWithIRFlags>(V);
- if (getOpcodeOrIntrinsicID(R) != 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 7b4ffce87434c..a0241bd6be998 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
@@ -361,6 +361,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) {
@@ -383,11 +407,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 = vputils::getOpcode(V);
return Instruction::isUnaryOp(Opcode) || Instruction::isBinaryOp(Opcode);
}
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUtils.h b/llvm/lib/Transforms/Vectorize/VPlanUtils.h
index 2980b704ec8da..24f87ea1d153e 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.h
@@ -106,6 +106,15 @@ template <typename Ty> Intrinsic::ID getIntrinsicID(const Ty *R) {
return Intrinsic::not_intrinsic;
}
+/// Get the instruction opcode data embedded in recipe underlying \p V.
+unsigned getOpcode(const VPValue *V);
+
+/// Get the instruction opcode or intrinsic ID data embedded in recipe
+/// underlying \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 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
/// the location is conservatively set to nullptr.
More information about the llvm-commits
mailing list