[llvm] [VPlan] Add Type* and getType() to VPSymbolicValue (NFC) (PR #195183)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Tue May 12 02:00:36 PDT 2026
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/195183
>From e9eefc4a5fac0d54ef493edf2098108af06083af Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 19 Apr 2026 10:34:39 +0100
Subject: [PATCH 1/3] [VPlan] Add Type* and getType() to VPSymbolicValue (NFC)
Add a Type* field to VPSymbolicValue, along with a getType()
methods to query the stored scalar type.
This makes it easier to retrieve the type of various symbolic values,
and also simplifies VPTypeAnalysis construction.
---
llvm/lib/Transforms/Vectorize/VPlan.cpp | 9 ++++---
llvm/lib/Transforms/Vectorize/VPlan.h | 14 ++++++----
.../Transforms/Vectorize/VPlanAnalysis.cpp | 26 +++----------------
llvm/lib/Transforms/Vectorize/VPlanAnalysis.h | 8 ++----
.../Vectorize/VPlanConstruction.cpp | 7 ++---
llvm/lib/Transforms/Vectorize/VPlanUnroll.cpp | 2 +-
llvm/lib/Transforms/Vectorize/VPlanValue.h | 9 ++++++-
7 files changed, 33 insertions(+), 42 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index 197ef22dc7fc6..a53dc0efb9b06 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -894,7 +894,8 @@ VPInstruction *VPRegionBlock::getOrCreateCanonicalIVIncrement() {
CanIV->getDebugLoc(), "index.next");
}
-VPlan::VPlan(Loop *L) {
+VPlan::VPlan(Loop *L, Type *IdxTy)
+ : VectorTripCount(IdxTy), VF(IdxTy), UF(IdxTy), VFxUF(IdxTy) {
setEntry(createVPIRBasicBlock(L->getLoopPreheader()));
ScalarHeader = createVPIRBasicBlock(L->getHeader());
@@ -1257,7 +1258,8 @@ VPlan *VPlan::duplicate() {
NewScalarHeader = createVPIRBasicBlock(ScalarHeaderIRBB);
}
// Create VPlan, clone live-ins and remap operands in the cloned blocks.
- auto *NewPlan = new VPlan(cast<VPBasicBlock>(NewEntry), NewScalarHeader);
+ auto *NewPlan =
+ new VPlan(cast<VPBasicBlock>(NewEntry), NewScalarHeader, VF.getType());
DenseMap<VPValue *, VPValue *> Old2NewVPValues;
for (VPIRValue *OldLiveIn : getLiveIns())
Old2NewVPValues[OldLiveIn] = NewPlan->getOrAddLiveIn(OldLiveIn);
@@ -1279,7 +1281,8 @@ VPlan *VPlan::duplicate() {
"All VPSymbolicValues must be handled below");
if (BackedgeTakenCount)
- NewPlan->BackedgeTakenCount = new VPSymbolicValue();
+ NewPlan->BackedgeTakenCount =
+ new VPSymbolicValue(BackedgeTakenCount->getType());
// Map and propagate materialized state for symbolic values.
for (auto [OldSV, NewSV] :
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index ff056df396eb4..7b830fb408ec4 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -4568,8 +4568,10 @@ class VPlan {
/// Construct a VPlan with \p Entry to the plan and with \p ScalarHeader
/// wrapping the original header of the scalar loop.
- VPlan(VPBasicBlock *Entry, VPIRBasicBlock *ScalarHeader)
- : Entry(Entry), ScalarHeader(ScalarHeader) {
+ VPlan(VPBasicBlock *Entry, VPIRBasicBlock *ScalarHeader,
+ Type *IdxTy = nullptr)
+ : Entry(Entry), ScalarHeader(ScalarHeader), VectorTripCount(IdxTy),
+ VF(IdxTy), UF(IdxTy), VFxUF(IdxTy) {
Entry->setPlan(this);
assert(ScalarHeader->getNumSuccessors() == 0 &&
"scalar header must be a leaf node");
@@ -4579,11 +4581,12 @@ class VPlan {
/// Construct a VPlan for \p L. This will create VPIRBasicBlocks wrapping the
/// original preheader and scalar header of \p L, to be used as entry and
/// scalar header blocks of the new VPlan.
- VPlan(Loop *L);
+ VPlan(Loop *L, Type *IdxTy = nullptr);
/// Construct a VPlan with a new VPBasicBlock as entry, a VPIRBasicBlock
/// wrapping \p ScalarHeaderBB and a trip count of \p TC.
- VPlan(BasicBlock *ScalarHeaderBB) {
+ VPlan(BasicBlock *ScalarHeaderBB, Type *IdxTy = nullptr)
+ : VectorTripCount(IdxTy), VF(IdxTy), UF(IdxTy), VFxUF(IdxTy) {
setEntry(createVPBasicBlock("preheader"));
ScalarHeader = createVPIRBasicBlock(ScalarHeaderBB);
}
@@ -4682,8 +4685,9 @@ class VPlan {
/// The backedge taken count of the original loop.
VPValue *getOrCreateBackedgeTakenCount() {
+ // BTC shares the canonical IV type with VectorTripCount.
if (!BackedgeTakenCount)
- BackedgeTakenCount = new VPSymbolicValue();
+ BackedgeTakenCount = new VPSymbolicValue(VectorTripCount.getType());
return BackedgeTakenCount;
}
VPValue *getBackedgeTakenCount() const { return BackedgeTakenCount; }
diff --git a/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp b/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp
index 5697856559bc2..4fc0423a616fd 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp
@@ -24,23 +24,6 @@ using namespace VPlanPatternMatch;
#define DEBUG_TYPE "vplan"
-VPTypeAnalysis::VPTypeAnalysis(const VPlan &Plan)
- : Ctx(Plan.getContext()), DL(Plan.getDataLayout()) {
- if (auto LoopRegion = Plan.getVectorLoopRegion()) {
- CanonicalIVTy = LoopRegion->getCanonicalIVType();
- return;
- }
-
- // If there's no loop region, retrieve the type from the trip count
- // expression.
- auto *TC = Plan.getTripCount();
- if (auto *TCIRV = dyn_cast<VPIRValue>(TC)) {
- CanonicalIVTy = TCIRV->getType();
- return;
- }
- CanonicalIVTy = cast<VPExpandSCEVRecipe>(TC)->getSCEV()->getType();
-}
-
Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPBlendRecipe *R) {
Type *ResTy = inferScalarType(R->getIncomingValue(0));
for (unsigned I = 1, E = R->getNumIncomingValues(); I != E; ++I) {
@@ -120,7 +103,7 @@ Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPInstruction *R) {
case VPInstruction::LastActiveLane:
// Assume that the maximum possible number of elements in a vector fits
// within the index type for the default address space.
- return DL.getIndexType(Ctx, 0);
+ return R->getParent()->getPlan()->getDataLayout().getIndexType(Ctx, 0);
case VPInstruction::LogicalAnd:
case VPInstruction::LogicalOr:
assert(inferScalarType(R->getOperand(0))->isIntegerTy(1) &&
@@ -278,11 +261,8 @@ Type *VPTypeAnalysis::inferScalarType(const VPValue *V) {
if (auto *IRV = dyn_cast<VPIRValue>(V))
return IRV->getType();
- if (isa<VPSymbolicValue>(V)) {
- // All VPValues without any underlying IR value (like the vector trip count
- // or the backedge-taken count) have the same type as the canonical IV.
- return CanonicalIVTy;
- }
+ if (auto *SymbolicV = dyn_cast<VPSymbolicValue>(V))
+ return SymbolicV->getType();
if (auto *RegionV = dyn_cast<VPRegionValue>(V))
return RegionV->getType();
diff --git a/llvm/lib/Transforms/Vectorize/VPlanAnalysis.h b/llvm/lib/Transforms/Vectorize/VPlanAnalysis.h
index 416c4d9dc2f3b..d53afad80a595 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanAnalysis.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanAnalysis.h
@@ -9,6 +9,7 @@
#ifndef LLVM_TRANSFORMS_VECTORIZE_VPLANANALYSIS_H
#define LLVM_TRANSFORMS_VECTORIZE_VPLANANALYSIS_H
+#include "VPlan.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
@@ -46,12 +47,7 @@ struct VPCostContext;
/// of the previously inferred types.
class VPTypeAnalysis {
DenseMap<const VPValue *, Type *> CachedTypes;
- /// Type of the canonical induction variable. Used for all VPValues without
- /// any underlying IR value (like the vector trip count or the backedge-taken
- /// count).
- Type *CanonicalIVTy;
LLVMContext &Ctx;
- const DataLayout &DL;
Type *inferScalarTypeForRecipe(const VPBlendRecipe *R);
Type *inferScalarTypeForRecipe(const VPInstruction *R);
@@ -62,7 +58,7 @@ class VPTypeAnalysis {
Type *inferScalarTypeForRecipe(const VPReplicateRecipe *R);
public:
- VPTypeAnalysis(const VPlan &Plan);
+ VPTypeAnalysis(const VPlan &Plan) : Ctx(Plan.getContext()) {}
/// Infer the type of \p V. Returns the scalar type of \p V.
Type *inferScalarType(const VPValue *V);
diff --git a/llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp b/llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp
index 66b9c0e4bc0ec..282115d659da0 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp
@@ -78,8 +78,9 @@ class PlainCFGBuilder {
void createVPInstructionsForVPBB(VPBasicBlock *VPBB, BasicBlock *BB);
public:
- PlainCFGBuilder(Loop *Lp, LoopInfo *LI, LoopVersioning *LVer)
- : TheLoop(Lp), LI(LI), LVer(LVer), Plan(std::make_unique<VPlan>(Lp)) {}
+ PlainCFGBuilder(Loop *Lp, LoopInfo *LI, LoopVersioning *LVer, Type *IdxTy)
+ : TheLoop(Lp), LI(LI), LVer(LVer),
+ Plan(std::make_unique<VPlan>(Lp, IdxTy)) {}
/// Build plain CFG for TheLoop and connect it to Plan's entry.
std::unique_ptr<VPlan> buildPlainCFG();
@@ -635,7 +636,7 @@ std::unique_ptr<VPlan>
VPlanTransforms::buildVPlan0(Loop *TheLoop, LoopInfo &LI, Type *InductionTy,
DebugLoc IVDL, PredicatedScalarEvolution &PSE,
LoopVersioning *LVer) {
- PlainCFGBuilder Builder(TheLoop, &LI, LVer);
+ PlainCFGBuilder Builder(TheLoop, &LI, LVer, InductionTy);
std::unique_ptr<VPlan> VPlan0 = Builder.buildPlainCFG();
addInitialSkeleton(*VPlan0, InductionTy, IVDL, PSE, TheLoop);
simplifyLiveInsWithSCEV(*VPlan0, PSE);
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUnroll.cpp b/llvm/lib/Transforms/Vectorize/VPlanUnroll.cpp
index d5eb7e82b6f84..24539d340c23e 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUnroll.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanUnroll.cpp
@@ -345,7 +345,7 @@ void UnrollState::unrollRecipeByUF(VPRecipeBase &R) {
VPBuilder Builder(VPR);
const DataLayout &DL = Plan.getDataLayout();
Type *IndexTy = DL.getIndexType(TypeInfo.inferScalarType(VPR));
- Type *VFTy = TypeInfo.inferScalarType(&Plan.getVF());
+ Type *VFTy = Plan.getVF().getType();
VPValue *VF = Builder.createScalarZExtOrTrunc(
&Plan.getVF(), IndexTy, VFTy, DebugLoc::getUnknown());
// VFxUF does not wrap, so VF * Part also cannot wrap.
diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h
index 8f9806adf774e..1e79c48cc8f7c 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanValue.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h
@@ -278,12 +278,16 @@ struct VPConstantInt : public VPIRValue {
/// A symbolic live-in VPValue, used for values like vector trip count, VF, and
/// VFxUF.
struct VPSymbolicValue : public VPValue {
- VPSymbolicValue() : VPValue(VPVSymbolicSC, nullptr) {}
+ VPSymbolicValue(Type *Ty = nullptr)
+ : VPValue(VPVSymbolicSC, nullptr), Ty(Ty) {}
static bool classof(const VPValue *V) {
return V->getVPValueID() == VPVSymbolicSC;
}
+ /// Returns the scalar type of this symbolic value.
+ Type *getType() const { return Ty; }
+
/// Returns true if this symbolic value has been materialized.
bool isMaterialized() const { return Materialized; }
@@ -294,6 +298,9 @@ struct VPSymbolicValue : public VPValue {
}
private:
+ /// The scalar type of this symbolic value.
+ Type *Ty;
+
/// Track whether this symbolic value has been materialized (replaced).
/// After materialization, accessing users should trigger an assertion.
bool Materialized = false;
>From 01af14901f8c51c8e6cc3068cd518a5be7e8347a Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 11 May 2026 17:17:41 +0200
Subject: [PATCH 2/3] !fixup address comments thanks
---
llvm/lib/Transforms/Vectorize/VPlan.cpp | 4 ++--
llvm/lib/Transforms/Vectorize/VPlan.h | 17 ++++++++++-------
llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp | 2 +-
.../Transforms/Vectorize/VPlanTransforms.cpp | 2 +-
llvm/lib/Transforms/Vectorize/VPlanValue.h | 3 +--
.../Transforms/Vectorize/VPlanTestBase.h | 3 ++-
6 files changed, 17 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index df17332f40040..2ec1b002f56f8 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -874,7 +874,7 @@ VPlan::VPlan(Loop *L, Type *IdxTy)
}
VPlan::~VPlan() {
- VPSymbolicValue DummyValue;
+ VPSymbolicValue DummyValue(nullptr);
for (auto *VPB : CreatedBlocks) {
if (auto *VPBB = dyn_cast<VPBasicBlock>(VPB)) {
@@ -1238,7 +1238,7 @@ VPlan *VPlan::duplicate() {
}
// Create VPlan, clone live-ins and remap operands in the cloned blocks.
auto *NewPlan =
- new VPlan(cast<VPBasicBlock>(NewEntry), NewScalarHeader, VF.getType());
+ new VPlan(cast<VPBasicBlock>(NewEntry), NewScalarHeader, getIndexType());
DenseMap<VPValue *, VPValue *> Old2NewVPValues;
for (VPIRValue *OldLiveIn : getLiveIns())
Old2NewVPValues[OldLiveIn] = NewPlan->getOrAddLiveIn(OldLiveIn);
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index e53ff5c6d9152..a903f9ed75bd5 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -4566,9 +4566,9 @@ class VPlan {
SmallVector<VPBlockBase *> CreatedBlocks;
/// Construct a VPlan with \p Entry to the plan and with \p ScalarHeader
- /// wrapping the original header of the scalar loop.
- VPlan(VPBasicBlock *Entry, VPIRBasicBlock *ScalarHeader,
- Type *IdxTy = nullptr)
+ /// wrapping the original header of the scalar loop. The vector loop will have
+ /// index type \p IdxTy.
+ VPlan(VPBasicBlock *Entry, VPIRBasicBlock *ScalarHeader, Type *IdxTy)
: Entry(Entry), ScalarHeader(ScalarHeader), VectorTripCount(IdxTy),
VF(IdxTy), UF(IdxTy), VFxUF(IdxTy) {
Entry->setPlan(this);
@@ -4579,12 +4579,13 @@ class VPlan {
public:
/// Construct a VPlan for \p L. This will create VPIRBasicBlocks wrapping the
/// original preheader and scalar header of \p L, to be used as entry and
- /// scalar header blocks of the new VPlan.
- VPlan(Loop *L, Type *IdxTy = nullptr);
+ /// scalar header blocks of the new VPlan. The vector loop will have index
+ /// type \p IdxTy.
+ VPlan(Loop *L, Type *IdxTy);
/// Construct a VPlan with a new VPBasicBlock as entry, a VPIRBasicBlock
- /// wrapping \p ScalarHeaderBB and a trip count of \p TC.
- VPlan(BasicBlock *ScalarHeaderBB, Type *IdxTy = nullptr)
+ /// wrapping \p ScalarHeaderBB and vector loop index of type \p IdxTy.
+ VPlan(BasicBlock *ScalarHeaderBB, Type *IdxTy)
: VectorTripCount(IdxTy), VF(IdxTy), UF(IdxTy), VFxUF(IdxTy) {
setEntry(createVPBasicBlock("preheader"));
ScalarHeader = createVPIRBasicBlock(ScalarHeaderBB);
@@ -4918,6 +4919,8 @@ class VPlan {
return ScalarPH &&
is_contained(ScalarPH->getPredecessors(), getMiddleBlock());
}
+
+ Type *getIndexType() const { return VF.getType(); }
};
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 11a91dcd46867..6d5db90436c79 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -3017,7 +3017,7 @@ VPExpressionRecipe::VPExpressionRecipe(
if (Def && ExpressionRecipesAsSetOfUsers.contains(Def))
continue;
addOperand(Op);
- LiveInPlaceholders.push_back(new VPSymbolicValue());
+ LiveInPlaceholders.push_back(new VPSymbolicValue(nullptr));
}
}
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 32d89a34105a4..c836a280eac19 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -2678,7 +2678,7 @@ void VPlanTransforms::removeBranchOnConst(VPlan &Plan, bool OnlyLatches) {
// Detach all unreachable blocks from their successors, removing their recipes
// and incoming values from phi recipes.
- VPSymbolicValue Tmp;
+ VPSymbolicValue Tmp(nullptr);
for (VPBlockBase *B : AllBlocks) {
if (Reachable.contains(B))
continue;
diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h
index 1e79c48cc8f7c..777da17c904f3 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanValue.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h
@@ -278,8 +278,7 @@ struct VPConstantInt : public VPIRValue {
/// A symbolic live-in VPValue, used for values like vector trip count, VF, and
/// VFxUF.
struct VPSymbolicValue : public VPValue {
- VPSymbolicValue(Type *Ty = nullptr)
- : VPValue(VPVSymbolicSC, nullptr), Ty(Ty) {}
+ VPSymbolicValue(Type *Ty) : VPValue(VPVSymbolicSC, nullptr), Ty(Ty) {}
static bool classof(const VPValue *V) {
return V->getVPValueID() == VPVSymbolicSC;
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h b/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
index 2c1797a5a724e..4f8f3581afa8c 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
@@ -133,7 +133,8 @@ class VPlanTestBase : public testing::Test {
}
VPlan &getPlan() {
- Plans.push_back(std::make_unique<VPlan>(ScalarHeader));
+ Plans.push_back(
+ std::make_unique<VPlan>(ScalarHeader, IntegerType::get(C, 64)));
VPlan &Plan = *Plans.back();
VPValue *DefaultTC = Plan.getConstantInt(32, 1024);
Plan.setTripCount(DefaultTC);
>From 9befba56d59c8649e6aa286470bed1140f87fc2f Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 12 May 2026 10:00:17 +0100
Subject: [PATCH 3/3] !fixup add comment, thanks
---
llvm/lib/Transforms/Vectorize/VPlan.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index b58846ff04985..f6e77092e016c 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -4913,6 +4913,7 @@ class VPlan {
is_contained(ScalarPH->getPredecessors(), getMiddleBlock());
}
+ /// The type of the canonical induction variable of the vector loop.
Type *getIndexType() const { return VF.getType(); }
};
More information about the llvm-commits
mailing list