[llvm] [VPlan] Add VPConstantInt for VPIRValues wrapping ConstantInts (NFC) (PR #175458)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 12 04:08:50 PST 2026
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/175458
>From 102b6aaa3d80f663bed58f0453795f592c2dbbbf Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 11 Jan 2026 17:09:16 +0000
Subject: [PATCH 1/2] [VPlan] Add VPConstantInt for VPIRValues wrapping
ConstantInts (NFC)
Follow-up to https://github.com/llvm/llvm-project/pull/174282: Introduce
a new VPConstantInt overlay for VPIRValue, to make it easier to check
and access constant int IR values.
---
.../Transforms/Vectorize/LoopVectorize.cpp | 3 +-
llvm/lib/Transforms/Vectorize/VPlan.h | 12 ++++---
.../Transforms/Vectorize/VPlanAnalysis.cpp | 4 +--
.../Transforms/Vectorize/VPlanPatternMatch.h | 18 +++-------
.../lib/Transforms/Vectorize/VPlanRecipes.cpp | 35 +++++++------------
llvm/lib/Transforms/Vectorize/VPlanValue.h | 20 +++++++++++
6 files changed, 48 insertions(+), 44 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index cdc6ecfa21bcb..2d321f6a32692 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -4276,8 +4276,7 @@ VectorizationFactor LoopVectorizationPlanner::selectVectorizationFactor() {
}
case VPInstruction::ActiveLaneMask: {
unsigned Multiplier =
- cast<ConstantInt>(VPI->getOperand(2)->getLiveInIRValue())
- ->getZExtValue();
+ cast<VPConstantInt>(VPI->getOperand(2))->getZExtValue();
C += VPI->cost(VF * Multiplier, CostCtx);
break;
}
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 83fe45bfd0bbf..e8dcdaf728b29 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -3103,8 +3103,8 @@ class VPExpressionRecipe : public VPSingleDefRecipe {
assert(Red->getRecurrenceKind() == RecurKind::Add &&
"Expected an add reduction");
assert(getNumOperands() >= 3 && "Expected at least three operands");
- [[maybe_unused]] auto *SubConst = dyn_cast<ConstantInt>(getOperand(2)->getLiveInIRValue());
- assert(SubConst && SubConst->getValue() == 0 &&
+ [[maybe_unused]] auto *SubConst = dyn_cast<VPConstantInt>(getOperand(2));
+ assert(SubConst && SubConst->isZero() &&
Sub->getOpcode() == Instruction::Sub && "Expected a negating sub");
}
@@ -4506,8 +4506,12 @@ class VPlan {
VPIRValue *getOrAddLiveIn(Value *V) {
assert(V && "Trying to get or add the VPIRValue of a null Value");
auto [It, Inserted] = LiveIns.try_emplace(V);
- if (Inserted)
- It->second = new VPIRValue(V);
+ if (Inserted) {
+ if (auto *CI = dyn_cast<ConstantInt>(V))
+ It->second = new VPConstantInt(CI);
+ else
+ It->second = new VPIRValue(V);
+ }
assert(isa<VPIRValue>(It->second) &&
"Only VPIRValues should be in mapping");
diff --git a/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp b/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp
index 27e7915a71675..20dcbff2389d4 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp
@@ -162,8 +162,8 @@ Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenRecipe *R) {
case Instruction::ExtractValue: {
assert(R->getNumOperands() == 2 && "expected single level extractvalue");
auto *StructTy = cast<StructType>(inferScalarType(R->getOperand(0)));
- auto *CI = cast<ConstantInt>(R->getOperand(1)->getLiveInIRValue());
- return StructTy->getTypeAtIndex(CI->getZExtValue());
+ return StructTy->getTypeAtIndex(
+ cast<VPConstantInt>(R->getOperand(1))->getZExtValue());
}
case Instruction::Select:
return inferScalarType(R->getOperand(1));
diff --git a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
index 3732d009b9537..629becaf77ed0 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
@@ -109,17 +109,13 @@ template <typename Pred, unsigned BitWidth = 0> struct int_pred_ty {
auto *VPI = dyn_cast<VPInstruction>(VPV);
if (VPI && VPI->getOpcode() == VPInstruction::Broadcast)
VPV = VPI->getOperand(0);
- auto *IRV = dyn_cast<VPIRValue>(VPV);
- if (!IRV)
- return false;
- assert(!IRV->getType()->isVectorTy() && "Unexpected vector live-in");
- const auto *CI = dyn_cast<ConstantInt>(IRV->getValue());
+ auto *CI = dyn_cast<VPConstantInt>(VPV);
if (!CI)
return false;
- if (BitWidth != 0 && CI->getBitWidth() != BitWidth)
+ if (BitWidth != 0 && CI->getAPInt().getBitWidth() != BitWidth)
return false;
- return P.isValue(CI->getValue());
+ return P.isValue(CI->getAPInt());
}
};
@@ -183,14 +179,10 @@ struct bind_apint {
bind_apint(const APInt *&Res) : Res(Res) {}
bool match(VPValue *VPV) const {
- auto *IRV = dyn_cast<VPIRValue>(VPV);
- if (!IRV)
- return false;
- assert(!IRV->getType()->isVectorTy() && "Unexpected vector live-in");
- const auto *CI = dyn_cast<ConstantInt>(IRV->getValue());
+ auto *CI = dyn_cast<VPConstantInt>(VPV);
if (!CI)
return false;
- Res = &CI->getValue();
+ Res = &CI->getAPInt();
return true;
}
};
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 2c0772320c3cf..5b1b6e702dc12 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -393,7 +393,7 @@ VPUnrollPartAccessor<PartOpIdx>::getUnrollPartOperand(const VPUser &U) const {
template <unsigned PartOpIdx>
unsigned VPUnrollPartAccessor<PartOpIdx>::getUnrollPart(const VPUser &U) const {
if (auto *UnrollPartOp = getUnrollPartOperand(U))
- return cast<ConstantInt>(UnrollPartOp->getLiveInIRValue())->getZExtValue();
+ return cast<VPConstantInt>(UnrollPartOp)->getZExtValue();
return 0;
}
@@ -534,11 +534,8 @@ Value *VPInstruction::generate(VPTransformState &State) {
}
case Instruction::ExtractElement: {
assert(State.VF.isVector() && "Only extract elements from vectors");
- if (auto *IdxIRV = dyn_cast<VPIRValue>(getOperand(1))) {
- unsigned IdxToExtract =
- cast<ConstantInt>(IdxIRV->getValue())->getZExtValue();
- return State.get(getOperand(0), VPLane(IdxToExtract));
- }
+ if (auto *Idx = dyn_cast<VPConstantInt>(getOperand(1)))
+ return State.get(getOperand(0), VPLane(Idx->getZExtValue()));
Value *Vec = State.get(getOperand(0));
Value *Idx = State.get(getOperand(1), /*IsScalar=*/true);
return Builder.CreateExtractElement(Vec, Idx, Name);
@@ -579,7 +576,7 @@ Value *VPInstruction::generate(VPTransformState &State) {
Name);
ElementCount EC = State.VF.multiplyCoefficientBy(
- cast<ConstantInt>(getOperand(2)->getLiveInIRValue())->getZExtValue());
+ cast<VPConstantInt>(getOperand(2))->getZExtValue());
auto *PredTy = VectorType::get(Builder.getInt1Ty(), EC);
return Builder.CreateIntrinsic(Intrinsic::get_active_lane_mask,
{PredTy, ScalarTC->getType()},
@@ -696,7 +693,7 @@ Value *VPInstruction::generate(VPTransformState &State) {
// If this start vector is scaled then it should produce a vector with fewer
// elements than the VF.
ElementCount VF = State.VF.divideCoefficientBy(
- cast<ConstantInt>(getOperand(2)->getLiveInIRValue())->getZExtValue());
+ cast<VPConstantInt>(getOperand(2))->getZExtValue());
auto *Iden = Builder.CreateVectorSplat(VF, State.get(getOperand(1), true));
return Builder.CreateInsertElement(Iden, State.get(getOperand(0), true),
Builder.getInt32(0));
@@ -1208,8 +1205,7 @@ InstructionCost VPInstruction::computeCost(ElementCount VF,
}
case VPInstruction::ActiveLaneMask: {
Type *ArgTy = Ctx.Types.inferScalarType(getOperand(0));
- unsigned Multiplier =
- cast<ConstantInt>(getOperand(2)->getLiveInIRValue())->getZExtValue();
+ unsigned Multiplier = cast<VPConstantInt>(getOperand(2))->getZExtValue();
Type *RetTy = toVectorTy(Type::getInt1Ty(Ctx.LLVMCtx), VF * Multiplier);
IntrinsicCostAttributes Attrs(Intrinsic::get_active_lane_mask, RetTy,
{ArgTy, ArgTy});
@@ -2005,12 +2001,9 @@ InstructionCost VPHistogramRecipe::computeCost(ElementCount VF,
// a multiply, and add that into the cost.
InstructionCost MulCost =
Ctx.TTI.getArithmeticInstrCost(Instruction::Mul, VTy, Ctx.CostKind);
- if (auto *IncAmountIRV = dyn_cast<VPIRValue>(IncAmt)) {
- ConstantInt *CI = dyn_cast<ConstantInt>(IncAmountIRV->getValue());
-
- if (CI && CI->getZExtValue() == 1)
+ if (auto *CI = dyn_cast<VPConstantInt>(IncAmt))
+ if (CI->isOne())
MulCost = TTI::TCC_Free;
- }
// Find the cost of the histogram operation itself.
Type *PtrTy = VectorType::get(AddressTy, VF);
@@ -2193,8 +2186,8 @@ void VPWidenRecipe::execute(VPTransformState &State) {
case Instruction::ExtractValue: {
assert(getNumOperands() == 2 && "expected single level extractvalue");
Value *Op = State.get(getOperand(0));
- auto *CI = cast<ConstantInt>(getOperand(1)->getLiveInIRValue());
- Value *Extract = Builder.CreateExtractValue(Op, CI->getZExtValue());
+ Value *Extract = Builder.CreateExtractValue(
+ Op, cast<VPConstantInt>(getOperand(1))->getZExtValue());
State.set(this, Extract);
break;
}
@@ -2362,12 +2355,8 @@ bool VPWidenIntOrFpInductionRecipe::isCanonical() const {
// The step may be defined by a recipe in the preheader (e.g. if it requires
// SCEV expansion), but for the canonical induction the step is required to be
// 1, which is represented as live-in.
- const VPIRValue *Step = dyn_cast<VPIRValue>(getStepValue());
- if (!Step)
- return false;
- ;
- auto *StepC = dyn_cast<ConstantInt>(Step->getValue());
- auto *StartC = dyn_cast<ConstantInt>(getStartValue()->getValue());
+ auto *StepC = dyn_cast<VPConstantInt>(getStepValue());
+ auto *StartC = dyn_cast<VPConstantInt>(getStartValue());
return StartC && StartC->isZero() && StepC && StepC->isOne() &&
getScalarType() == getRegion()->getCanonicalIVType();
}
diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h
index cae0633dbb185..0579aaf744ca6 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanValue.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h
@@ -24,6 +24,8 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/iterator_range.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
namespace llvm {
@@ -197,6 +199,24 @@ struct VPIRValue : public VPValue {
}
};
+/// An overlay on VPIRValue for VPValues that wrap a ConstantInt. Provides
+/// convenient accessors for the underlying constant.
+struct VPConstantInt : public VPIRValue {
+ VPConstantInt(ConstantInt *CI) : VPIRValue(CI) {}
+
+ uint64_t getZExtValue() const { return getCI()->getZExtValue(); }
+ const APInt &getAPInt() const { return getCI()->getValue(); }
+ bool isZero() const { return getCI()->isZero(); }
+ bool isOne() const { return getCI()->isOne(); }
+
+ static bool classof(const VPValue *V) {
+ return isa<VPIRValue>(V) && isa<ConstantInt>(V->getUnderlyingValue());
+ }
+
+private:
+ ConstantInt *getCI() const { return cast<ConstantInt>(getValue()); }
+};
+
/// A symbolic live-in VPValue, used for values like vector trip count, VF, and
/// VFxUF.
struct VPSymbolicValue : public VPValue {
>From f2fce6f27339ef3cc47d4c78d39a01a77eb22dc5 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 12 Jan 2026 12:05:54 +0000
Subject: [PATCH 2/2] !fixup address comments, some cleanup, thanks
---
llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h | 2 +-
llvm/lib/Transforms/Vectorize/VPlanValue.h | 14 +++++++-------
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
index f6c0c65ebb14e..0c7d4fd5ce4c8 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
@@ -113,7 +113,7 @@ template <typename Pred, unsigned BitWidth = 0> struct int_pred_ty {
if (!CI)
return false;
- if (BitWidth != 0 && CI->getAPInt().getBitWidth() != BitWidth)
+ if (BitWidth != 0 && CI->getBitWidth() != BitWidth)
return false;
return P.isValue(CI->getAPInt());
}
diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h
index 0579aaf744ca6..64b52d54526d4 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanValue.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h
@@ -204,17 +204,17 @@ struct VPIRValue : public VPValue {
struct VPConstantInt : public VPIRValue {
VPConstantInt(ConstantInt *CI) : VPIRValue(CI) {}
- uint64_t getZExtValue() const { return getCI()->getZExtValue(); }
- const APInt &getAPInt() const { return getCI()->getValue(); }
- bool isZero() const { return getCI()->isZero(); }
- bool isOne() const { return getCI()->isOne(); }
-
static bool classof(const VPValue *V) {
return isa<VPIRValue>(V) && isa<ConstantInt>(V->getUnderlyingValue());
}
-private:
- ConstantInt *getCI() const { return cast<ConstantInt>(getValue()); }
+ bool isOne() const { return getAPInt().isOne(); }
+ bool isZero() const { return getAPInt().isZero(); }
+ const APInt &getAPInt() const {
+ return cast<ConstantInt>(getValue())->getValue();
+ }
+ unsigned getBitWidth() const { return getAPInt().getBitWidth(); }
+ uint64_t getZExtValue() const { return getAPInt().getZExtValue(); }
};
/// A symbolic live-in VPValue, used for values like vector trip count, VF, and
More information about the llvm-commits
mailing list