[llvm] [LV][NFC] Factor out MinBWs of values from the cost model (PR #194492)
Hassnaa Hamdi via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 29 07:58:26 PDT 2026
https://github.com/hassnaaHamdi updated https://github.com/llvm/llvm-project/pull/194492
>From ebed19a58dc12ea067f7f031a6eded636a593611 Mon Sep 17 00:00:00 2001
From: Hassnaa Hamdi <hassnaa.hamdi at arm.com>
Date: Sun, 26 Apr 2026 17:27:43 +0000
Subject: [PATCH 1/2] [LV][NFC] Factor out MinBWs of values from the cost model
---
.../Vectorize/LoopVectorizationPlanner.cpp | 9 +++
.../Vectorize/LoopVectorizationPlanner.h | 21 ++++++-
.../Transforms/Vectorize/LoopVectorize.cpp | 61 ++++++++-----------
3 files changed, 52 insertions(+), 39 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.cpp
index 0e847f4767a8b..58a0fb029357d 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.cpp
@@ -563,6 +563,15 @@ bool VFSelectionContext::runtimeChecksRequired() {
return false;
}
+const MapVector<Instruction *, uint64_t> &
+VFSelectionContext::getMinimalBitwidths() {
+ if (!MinBWsComputed) {
+ MinBWs = computeMinimumValueSizes(TheLoop->getBlocks(), *DB, &TTI);
+ MinBWsComputed = true;
+ }
+ return MinBWs;
+}
+
void VFSelectionContext::collectInLoopReductions() {
// Avoid duplicating work finding in-loop reductions.
if (!InLoopReductions.empty())
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h
index b07a17f2d8baa..635fbdf2d4e73 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h
@@ -553,6 +553,8 @@ class VFSelectionContext {
const Loop *TheLoop;
const Function &F;
PredicatedScalarEvolution &PSE;
+ /// Demanded bits analysis.
+ DemandedBits *DB;
OptimizationRemarkEmitter *ORE;
const LoopVectorizeHints *Hints;
@@ -586,6 +588,14 @@ class VFSelectionContext {
/// computeFeasibleMaxVF.
std::optional<unsigned> MaxSafeElements;
+ /// Map of scalar integer values to the smallest bitwidth they can be legally
+ /// represented as. The vector equivalents of these values should be truncated
+ /// to this type.
+ MapVector<Instruction *, uint64_t> MinBWs;
+
+ /// Whether MinBWs has been computed.
+ bool MinBWsComputed = false;
+
public:
/// The kind of cost that we are calculating.
const TTI::TargetCostKind CostKind;
@@ -597,11 +607,11 @@ class VFSelectionContext {
VFSelectionContext(const TargetTransformInfo &TTI,
const LoopVectorizationLegality *Legal,
const Loop *TheLoop, const Function &F,
- PredicatedScalarEvolution &PSE,
+ PredicatedScalarEvolution &PSE, DemandedBits *DB,
OptimizationRemarkEmitter *ORE,
const LoopVectorizeHints *Hints, bool OptForSize)
- : TTI(TTI), Legal(Legal), TheLoop(TheLoop), F(F), PSE(PSE), ORE(ORE),
- Hints(Hints),
+ : TTI(TTI), Legal(Legal), TheLoop(TheLoop), F(F), PSE(PSE), DB(DB),
+ ORE(ORE), Hints(Hints),
CostKind(F.hasMinSize() ? TTI::TCK_CodeSize : TTI::TCK_RecipThroughput),
OptForSize(OptForSize) {
initializeVScaleForTuning();
@@ -689,6 +699,11 @@ class VFSelectionContext {
/// Check whether vectorization would require runtime checks. When optimizing
/// for size, returning true here aborts vectorization.
bool runtimeChecksRequired();
+
+ /// \returns The smallest bitwidth each instruction can be represented with.
+ /// The vector equivalents of these instructions should be truncated to this
+ /// type.
+ const MapVector<Instruction *, uint64_t> &getMinimalBitwidths();
};
/// Planner drives the vectorization process after having passed
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 3d33c46075b05..1f4a6c905ffc2 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -819,16 +819,18 @@ class LoopVectorizationCostModel {
friend class LoopVectorizationPlanner;
public:
- LoopVectorizationCostModel(
- EpilogueLowering SEL, Loop *L, PredicatedScalarEvolution &PSE,
- LoopInfo *LI, LoopVectorizationLegality *Legal,
- const TargetTransformInfo &TTI, const TargetLibraryInfo *TLI,
- DemandedBits *DB, AssumptionCache *AC, OptimizationRemarkEmitter *ORE,
- std::function<BlockFrequencyInfo &()> GetBFI, const Function *F,
- const LoopVectorizeHints *Hints, InterleavedAccessInfo &IAI,
- VFSelectionContext &Config)
+ LoopVectorizationCostModel(EpilogueLowering SEL, Loop *L,
+ PredicatedScalarEvolution &PSE, LoopInfo *LI,
+ LoopVectorizationLegality *Legal,
+ const TargetTransformInfo &TTI,
+ const TargetLibraryInfo *TLI, AssumptionCache *AC,
+ OptimizationRemarkEmitter *ORE,
+ std::function<BlockFrequencyInfo &()> GetBFI,
+ const Function *F, const LoopVectorizeHints *Hints,
+ InterleavedAccessInfo &IAI,
+ VFSelectionContext &Config)
: Config(Config), EpilogueLoweringStatus(SEL), TheLoop(L), PSE(PSE),
- LI(LI), Legal(Legal), TTI(TTI), TLI(TLI), DB(DB), AC(AC), ORE(ORE),
+ LI(LI), Legal(Legal), TTI(TTI), TLI(TLI), AC(AC), ORE(ORE),
GetBFI(GetBFI), TheFunction(F), Hints(Hints), InterleaveInfo(IAI) {}
/// \return An upper bound for the vectorization factors (both fixed and
@@ -855,13 +857,6 @@ class LoopVectorizationCostModel {
/// Collect values we want to ignore in the cost model.
void collectValuesToIgnore();
- /// \returns The smallest bitwidth each instruction can be represented with.
- /// The vector equivalents of these instructions should be truncated to this
- /// type.
- const MapVector<Instruction *, uint64_t> &getMinimalBitwidths() const {
- return MinBWs;
- }
-
/// \returns True if it is more profitable to scalarize instruction \p I for
/// vectorization factor \p VF.
bool isProfitableToScalarize(Instruction *I, ElementCount VF) const {
@@ -915,6 +910,7 @@ class LoopVectorizationCostModel {
/// \returns True if instruction \p I can be truncated to a smaller bitwidth
/// for vectorization factor \p VF.
bool canTruncateToMinimalBitwidth(Instruction *I, ElementCount VF) const {
+ const auto &MinBWs = Config.getMinimalBitwidths();
// Truncs must truncate at most to their destination type.
if (isa_and_nonnull<TruncInst>(I) && MinBWs.contains(I) &&
I->getType()->getScalarSizeInBits() < MinBWs.lookup(I))
@@ -1351,11 +1347,6 @@ class LoopVectorizationCostModel {
InstructionCost getScalarizationOverhead(Instruction *I,
ElementCount VF) const;
- /// Map of scalar integer values to the smallest bitwidth they can be legally
- /// represented as. The vector equivalents of these values should be truncated
- /// to this type.
- MapVector<Instruction *, uint64_t> MinBWs;
-
/// A type representing the costs for instructions if they were to be
/// scalarized rather than vectorized. The entries are Instruction-Cost
/// pairs.
@@ -1491,9 +1482,6 @@ class LoopVectorizationCostModel {
/// Target Library Info.
const TargetLibraryInfo *TLI;
- /// Demanded bits analysis.
- DemandedBits *DB;
-
/// Assumption cache.
AssumptionCache *AC;
@@ -3019,8 +3007,6 @@ LoopVectorizationCostModel::computeMaxVF(ElementCount UserVF, unsigned UserIC) {
Uniforms.empty() && Scalars.empty() &&
"No cost-modeling decisions should have been taken at this point");
- MinBWs = computeMinimumValueSizes(TheLoop->getBlocks(), *DB, &TTI);
-
switch (EpilogueLoweringStatus) {
case CM_EpilogueAllowed:
return Config.computeFeasibleMaxVF(MaxTC, UserVF, UserIC, false,
@@ -5223,9 +5209,11 @@ LoopVectorizationCostModel::getInstructionCost(Instruction *I,
VF.getKnownMinValue();
}
+ const auto &MinBWs = Config.getMinimalBitwidths();
+ uint64_t InstrMinBWs = MinBWs.lookup(I);
Type *RetTy = I->getType();
if (canTruncateToMinimalBitwidth(I, VF))
- RetTy = IntegerType::get(RetTy->getContext(), MinBWs[I]);
+ RetTy = IntegerType::get(RetTy->getContext(), InstrMinBWs);
auto *SE = PSE.getSE();
Type *VectorTy;
@@ -5507,10 +5495,10 @@ LoopVectorizationCostModel::getInstructionCost(Instruction *I,
[[maybe_unused]] Instruction *Op0AsInstruction =
dyn_cast<Instruction>(I->getOperand(0));
assert((!canTruncateToMinimalBitwidth(Op0AsInstruction, VF) ||
- MinBWs[I] == MinBWs[Op0AsInstruction]) &&
+ InstrMinBWs == MinBWs.lookup(Op0AsInstruction)) &&
"if both the operand and the compare are marked for "
"truncation, they must have the same bitwidth");
- ValTy = IntegerType::get(ValTy->getContext(), MinBWs[I]);
+ ValTy = IntegerType::get(ValTy->getContext(), InstrMinBWs);
}
VectorTy = toVectorTy(ValTy, VF);
@@ -5610,8 +5598,8 @@ LoopVectorizationCostModel::getInstructionCost(Instruction *I,
Type *SrcScalarTy = I->getOperand(0)->getType();
Instruction *Op0AsInstruction = dyn_cast<Instruction>(I->getOperand(0));
if (canTruncateToMinimalBitwidth(Op0AsInstruction, VF))
- SrcScalarTy =
- IntegerType::get(SrcScalarTy->getContext(), MinBWs[Op0AsInstruction]);
+ SrcScalarTy = IntegerType::get(SrcScalarTy->getContext(),
+ MinBWs.lookup(Op0AsInstruction));
Type *SrcVecTy =
VectorTy->isVectorTy() ? toVectorTy(SrcScalarTy, VF) : SrcScalarTy;
@@ -6983,7 +6971,7 @@ void LoopVectorizationPlanner::buildVPlansWithVPRecipes(ElementCount MinVF,
VPlanTransforms::hoistPredicatedLoads(*Plan, PSE, OrigLoop);
VPlanTransforms::sinkPredicatedStores(*Plan, PSE, OrigLoop);
RUN_VPLAN_PASS(VPlanTransforms::truncateToMinimalBitwidths, *Plan,
- CM.getMinimalBitwidths());
+ Config.getMinimalBitwidths());
RUN_VPLAN_PASS(VPlanTransforms::optimize, *Plan);
// TODO: try to put addExplicitVectorLength close to addActiveLaneMask
if (CM.foldTailWithEVL()) {
@@ -7579,8 +7567,8 @@ static bool processLoopInVPlanNativePath(
EpilogueLowering SEL =
getEpilogueLowering(F, L, Hints, OptForSize, TTI, TLI, *LVL, &IAI);
- VFSelectionContext Config(*TTI, LVL, L, *F, PSE, ORE, &Hints, OptForSize);
- LoopVectorizationCostModel CM(SEL, L, PSE, LI, LVL, *TTI, TLI, DB, AC, ORE,
+ VFSelectionContext Config(*TTI, LVL, L, *F, PSE, DB, ORE, &Hints, OptForSize);
+ LoopVectorizationCostModel CM(SEL, L, PSE, LI, LVL, *TTI, TLI, AC, ORE,
GetBFI, F, &Hints, IAI, Config);
// Use the planner for outer loop vectorization.
// TODO: CM is not used at this point inside the planner. Turn CM into an
@@ -8412,8 +8400,9 @@ bool LoopVectorizePass::processLoop(Loop *L) {
}
// Use the cost model.
- VFSelectionContext Config(*TTI, &LVL, L, *F, PSE, ORE, &Hints, OptForSize);
- LoopVectorizationCostModel CM(SEL, L, PSE, LI, &LVL, *TTI, TLI, DB, AC, ORE,
+ VFSelectionContext Config(*TTI, &LVL, L, *F, PSE, DB, ORE, &Hints,
+ OptForSize);
+ LoopVectorizationCostModel CM(SEL, L, PSE, LI, &LVL, *TTI, TLI, AC, ORE,
GetBFI, F, &Hints, IAI, Config);
// Use the planner for vectorization.
LoopVectorizationPlanner LVP(L, LI, DT, TLI, *TTI, &LVL, CM, Config, IAI, PSE,
>From 0f46f4abdf9ac2e65c63eb04ddaa77aecf372413 Mon Sep 17 00:00:00 2001
From: Hassnaa Hamdi <hassnaa.hamdi at arm.com>
Date: Wed, 29 Apr 2026 14:46:29 +0000
Subject: [PATCH 2/2] resolve review comments - collect BitWidth at beginning
of planning
---
.../Transforms/Vectorize/LoopVectorizationPlanner.cpp | 10 +++++-----
.../Transforms/Vectorize/LoopVectorizationPlanner.h | 8 +++-----
llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 1 +
3 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.cpp
index 58a0fb029357d..c2986f478ff8b 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.cpp
@@ -563,12 +563,12 @@ bool VFSelectionContext::runtimeChecksRequired() {
return false;
}
+void VFSelectionContext::computeMinimalBitwidths() {
+ MinBWs = computeMinimumValueSizes(TheLoop->getBlocks(), *DB, &TTI);
+}
+
const MapVector<Instruction *, uint64_t> &
-VFSelectionContext::getMinimalBitwidths() {
- if (!MinBWsComputed) {
- MinBWs = computeMinimumValueSizes(TheLoop->getBlocks(), *DB, &TTI);
- MinBWsComputed = true;
- }
+VFSelectionContext::getMinimalBitwidths() const {
return MinBWs;
}
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h
index 635fbdf2d4e73..fe58ba5cc1b3b 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h
@@ -553,7 +553,6 @@ class VFSelectionContext {
const Loop *TheLoop;
const Function &F;
PredicatedScalarEvolution &PSE;
- /// Demanded bits analysis.
DemandedBits *DB;
OptimizationRemarkEmitter *ORE;
const LoopVectorizeHints *Hints;
@@ -593,9 +592,6 @@ class VFSelectionContext {
/// to this type.
MapVector<Instruction *, uint64_t> MinBWs;
- /// Whether MinBWs has been computed.
- bool MinBWsComputed = false;
-
public:
/// The kind of cost that we are calculating.
const TTI::TargetCostKind CostKind;
@@ -700,10 +696,12 @@ class VFSelectionContext {
/// for size, returning true here aborts vectorization.
bool runtimeChecksRequired();
+ void computeMinimalBitwidths();
+
/// \returns The smallest bitwidth each instruction can be represented with.
/// The vector equivalents of these instructions should be truncated to this
/// type.
- const MapVector<Instruction *, uint64_t> &getMinimalBitwidths();
+ const MapVector<Instruction *, uint64_t> &getMinimalBitwidths() const;
};
/// Planner drives the vectorization process after having passed
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 1f4a6c905ffc2..3ddb9d519b7bc 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -5847,6 +5847,7 @@ void LoopVectorizationPlanner::plan(ElementCount UserVF, unsigned UserIC) {
assert(OrigLoop->isInnermost() && "Inner loop expected.");
CM.collectValuesToIgnore();
Config.collectElementTypesForWidening(&CM.ValuesToIgnore);
+ Config.computeMinimalBitwidths();
FixedScalableVFPair MaxFactors = CM.computeMaxVF(UserVF, UserIC);
if (!MaxFactors) // Cases that should not to be vectorized nor interleaved.
More information about the llvm-commits
mailing list