[llvm] [LV][NFC] Fix "vectorization is possible but not beneficial" message (PR #228024)
David Sherwood via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 2 04:59:51 PDT 2026
https://github.com/david-arm updated https://github.com/llvm/llvm-project/pull/228024
>From 5f2c915d8223f8cb359f688a2c5674e77151707b Mon Sep 17 00:00:00 2001
From: David Sherwood <david.sherwood at arm.com>
Date: Thu, 1 Oct 2026 10:26:08 +0000
Subject: [PATCH 1/4] [LV][NFC] Fix "vectorization is possible but not
beneficial" message
---
llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h | 5 +++++
llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 7 ++++++-
.../Transforms/LoopVectorize/AArch64/early_exit_costs.ll | 2 +-
3 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h
index 733b8647a06e34..2a38d125e68d96 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h
@@ -946,6 +946,11 @@ class LoopVectorizationPlanner {
/// Destroy the cost model.
void clearCostModel();
+ bool hasVectorPlan() const {
+ return any_of(
+ VPlans, [&](const VPlanPtr &Plan) { return !Plan->hasScalarVFOnly(); });
+ }
+
/// Build VPlans for the specified \p UserVF and \p UserIC if they are
/// non-zero or all applicable candidate VFs otherwise. If vectorization and
/// interleaving should be avoided up-front, no plans are generated.
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 69e367e62129d0..45a7acc21167dc 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -7954,7 +7954,12 @@ bool LoopVectorizePass::processLoop(Loop *L) {
std::pair<StringRef, std::string> VecDiagMsg, IntDiagMsg;
bool VectorizeLoop = true, InterleaveLoop = true;
if (VF.Width.isScalar()) {
- LLVM_DEBUG(dbgs() << "LV: Vectorization is possible but not beneficial.\n");
+ if (LVP.hasVectorPlan())
+ LLVM_DEBUG(dbgs() << "LV: Vectorization is not possible. Failed to "
+ "create any vector vplans.\n");
+ else
+ LLVM_DEBUG(
+ dbgs() << "LV: Vectorization is possible but not beneficial.\n");
VecDiagMsg = {
"VectorizationNotBeneficial",
"the cost-model indicates that vectorization is not beneficial"};
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/early_exit_costs.ll b/llvm/test/Transforms/LoopVectorize/AArch64/early_exit_costs.ll
index 8dd7ca89717247..1a33b66c3e5779 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/early_exit_costs.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/early_exit_costs.ll
@@ -91,7 +91,7 @@ loop.end:
define i64 @vectorization_not_profitable_due_to_trunc(ptr dereferenceable(800) %src) {
; CHECK-LABEL: LV: Checking a loop in 'vectorization_not_profitable_due_to_trunc'
; CHECK: LV: Selecting VF: 1.
-; CHECK: LV: Vectorization is possible but not beneficial.
+; CHECK: LV: Vectorization is not possible. Failed to create any vector vplans.
entry:
br label %loop.header
>From 5ebd6457e333c1cad8cf9630b0bfc08d8885a0c2 Mon Sep 17 00:00:00 2001
From: David Sherwood <david.sherwood at arm.com>
Date: Thu, 1 Oct 2026 11:51:58 +0000
Subject: [PATCH 2/4] Fix silly mistake with ordering
---
llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 7 +++----
.../Transforms/LoopVectorize/AArch64/early_exit_costs.ll | 2 +-
.../Transforms/LoopVectorize/early_exit_store_legality.ll | 2 +-
3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 45a7acc21167dc..35155831ba53ec 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -5342,7 +5342,6 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
void LoopVectorizationPlanner::plan(ElementCount UserVF, unsigned UserIC) {
CM->collectValuesToIgnore();
Config.collectElementTypesForWidening(&CM->ValuesToIgnore);
-
FixedScalableVFPair MaxFactors = CM->computeMaxVF(UserVF, UserIC);
if (!MaxFactors) // Cases that should not to be vectorized nor interleaved.
return;
@@ -7955,11 +7954,11 @@ bool LoopVectorizePass::processLoop(Loop *L) {
bool VectorizeLoop = true, InterleaveLoop = true;
if (VF.Width.isScalar()) {
if (LVP.hasVectorPlan())
- LLVM_DEBUG(dbgs() << "LV: Vectorization is not possible. Failed to "
- "create any vector vplans.\n");
- else
LLVM_DEBUG(
dbgs() << "LV: Vectorization is possible but not beneficial.\n");
+ else
+ LLVM_DEBUG(dbgs() << "LV: Vectorization is not possible. Failed to "
+ "create any vector vplans.\n");
VecDiagMsg = {
"VectorizationNotBeneficial",
"the cost-model indicates that vectorization is not beneficial"};
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/early_exit_costs.ll b/llvm/test/Transforms/LoopVectorize/AArch64/early_exit_costs.ll
index 1a33b66c3e5779..8dd7ca89717247 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/early_exit_costs.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/early_exit_costs.ll
@@ -91,7 +91,7 @@ loop.end:
define i64 @vectorization_not_profitable_due_to_trunc(ptr dereferenceable(800) %src) {
; CHECK-LABEL: LV: Checking a loop in 'vectorization_not_profitable_due_to_trunc'
; CHECK: LV: Selecting VF: 1.
-; CHECK: LV: Vectorization is not possible. Failed to create any vector vplans.
+; CHECK: LV: Vectorization is possible but not beneficial.
entry:
br label %loop.header
diff --git a/llvm/test/Transforms/LoopVectorize/early_exit_store_legality.ll b/llvm/test/Transforms/LoopVectorize/early_exit_store_legality.ll
index 714f172d08fbff..8a7e140aa04e18 100644
--- a/llvm/test/Transforms/LoopVectorize/early_exit_store_legality.ll
+++ b/llvm/test/Transforms/LoopVectorize/early_exit_store_legality.ll
@@ -895,7 +895,7 @@ define i32 @uncountable_exit_with_masked_ldst_separate_condition(ptr dereference
; CHECK-DEBUG-LABEL: LV: Checking a loop in 'uncountable_exit_with_masked_ldst_separate_condition'
; CHECK-DEBUG: LV: Loop passed LoopVectorizationLegality checks!
; CHECK-DEBUG: LV: Not vectorizing: Early exit loop with side effects contains unsupported conditional memory operations
-; CHECK-DEBUG: LV: Vectorization is possible but not beneficial.
+; CHECK-DEBUG: LV: Vectorization is not possible. Failed to create any vector vplans.
; CHECK-REMARK: foo.c:290:3: loop not vectorized: Early exit loop with side effects contains unsupported conditional memory operations
entry:
br label %for.body, !dbg !67
>From 0310dcbf3bc1d6a56989511249bfe3dc0ad5d654 Mon Sep 17 00:00:00 2001
From: David Sherwood <david.sherwood at arm.com>
Date: Thu, 1 Oct 2026 14:11:22 +0000
Subject: [PATCH 3/4] Address review comments
---
.../Transforms/Vectorize/LoopVectorize.cpp | 3 +-
.../Vectorize/VPlanConstruction.cpp | 8 +++-
.../Transforms/Vectorize/VPlanTransforms.h | 2 +-
.../LoopVectorize/fail_vectorise_no_vplans.ll | 48 +++++++++++++++++++
4 files changed, 57 insertions(+), 4 deletions(-)
create mode 100644 llvm/test/Transforms/LoopVectorize/fail_vectorise_no_vplans.ll
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 35155831ba53ec..86f398e4931e50 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -5342,6 +5342,7 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
void LoopVectorizationPlanner::plan(ElementCount UserVF, unsigned UserIC) {
CM->collectValuesToIgnore();
Config.collectElementTypesForWidening(&CM->ValuesToIgnore);
+
FixedScalableVFPair MaxFactors = CM->computeMaxVF(UserVF, UserIC);
if (!MaxFactors) // Cases that should not to be vectorized nor interleaved.
return;
@@ -6419,7 +6420,7 @@ VPlanPtr LoopVectorizationPlanner::tryToBuildVPlan1() {
// Create recipes for header phis. For outer loops, reductions, recurrences
// and in-loop reductions are empty since legality doesn't detect them.
if (!RUN_VPLAN_PASS(
- VPlanTransforms::createHeaderPhiRecipes, *VPlan0, PSE, *OrigLoop,
+ VPlanTransforms::createHeaderPhiRecipes, *VPlan0, PSE, *OrigLoop, ORE,
VPDT, Legal->getInductionVars(), Legal->getReductionVars(),
Legal->getFixedOrderRecurrences(), Config.getInLoopReductions(),
Config.getHints().allowReordering())) {
diff --git a/llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp b/llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp
index 43bd85513ce251..9b393a1270d79f 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp
@@ -937,7 +937,7 @@ static bool tryToSinkOrHoistRecurrenceUsers(VPBasicBlock *HeaderVPBB,
bool VPlanTransforms::createHeaderPhiRecipes(
VPlan &Plan, PredicatedScalarEvolution &PSE, Loop &OrigLoop,
- const VPDominatorTree &VPDT,
+ OptimizationRemarkEmitter *ORE, const VPDominatorTree &VPDT,
const MapVector<PHINode *, InductionDescriptor> &Inductions,
const MapVector<PHINode *, RecurrenceDescriptor> &Reductions,
const SmallPtrSetImpl<const PHINode *> &FixedOrderRecurrences,
@@ -997,8 +997,12 @@ bool VPlanTransforms::createHeaderPhiRecipes(
PhiR->eraseFromParent();
}
- if (!tryToSinkOrHoistRecurrenceUsers(HeaderVPBB, VPDT))
+ if (!tryToSinkOrHoistRecurrenceUsers(HeaderVPBB, VPDT)) {
+ reportVectorizationFailure(
+ "Failed to sink or hoist user of first-order recurrence",
+ "CannotSinkHoistFORUser", ORE, &OrigLoop);
return false;
+ }
// Skip renaming resume phi recipes, if any header phi has been removed.
if (range_size(HeaderVPBB->phis()) !=
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
index 30d584ab8f589c..07f1f8563ee76a 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
@@ -172,7 +172,7 @@ struct VPlanTransforms {
/// recurrence cannot be handled.
LLVM_ABI_FOR_TEST static bool createHeaderPhiRecipes(
VPlan &Plan, PredicatedScalarEvolution &PSE, Loop &OrigLoop,
- const VPDominatorTree &VPDT,
+ OptimizationRemarkEmitter *ORE, const VPDominatorTree &VPDT,
const MapVector<PHINode *, InductionDescriptor> &Inductions,
const MapVector<PHINode *, RecurrenceDescriptor> &Reductions,
const SmallPtrSetImpl<const PHINode *> &FixedOrderRecurrences,
diff --git a/llvm/test/Transforms/LoopVectorize/fail_vectorise_no_vplans.ll b/llvm/test/Transforms/LoopVectorize/fail_vectorise_no_vplans.ll
new file mode 100644
index 00000000000000..1962ba32fa4f50
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/fail_vectorise_no_vplans.ll
@@ -0,0 +1,48 @@
+; REQUIRES: asserts
+; RUN: opt -passes=loop-vectorize -force-vector-width=4 -force-vector-interleave=1 -S -disable-output \
+; RUN: -debug-only=loop-vectorize %s 2>&1 | FileCheck %s
+
+; This is testing that we emit more accurate debug messages when we
+; fail to vectorize because we didn't create any vector vplans. Essentially,
+; we are doing legalisation in vplan more often for things that used to
+; happen in LoopVectorizationLegality.
+define void @fail_vplan_bad_users_of_for(ptr noalias %A, ptr noalias %B, ptr noalias %C, i64 %n) {
+; CHECK: Checking a loop in 'fail_vplan_bad_users_of_for'
+; CHECK: LV: Not vectorizing: Failed to sink or hoist user of first-order recurrence.
+; CHECK-NEXT: LV: Vectorization is not possible. Failed to create any vector vplans.
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
+ %for.1 = phi i32 [ 0, %entry ], [ %prev, %loop.latch ]
+ %for.2 = phi i32 [ 0, %entry ], [ %or, %loop.latch ]
+ %or = or i32 %for.1, 3
+ %t = trunc i64 %iv to i32
+ %gep.c = getelementptr inbounds i32, ptr %C, i64 %iv
+ %c = load i32, ptr %gep.c, align 4
+ %cmp = icmp sgt i32 %c, 0
+ br i1 %cmp, label %then, label %else
+
+then:
+ %gep.a = getelementptr inbounds i32, ptr %A, i64 %iv
+ store i32 %for.2, ptr %gep.a, align 4
+ br label %merge
+
+else:
+ %gep.b = getelementptr inbounds i32, ptr %B, i64 %iv
+ store i32 %for.2, ptr %gep.b, align 4
+ br label %merge
+
+merge:
+ %prev = mul i32 %t, %t
+ br label %loop.latch
+
+loop.latch:
+ %iv.next = add i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
>From d0be623640e4e1a31d18c85ea3080b425586feb0 Mon Sep 17 00:00:00 2001
From: David Sherwood <david.sherwood at arm.com>
Date: Fri, 2 Oct 2026 11:59:00 +0000
Subject: [PATCH 4/4] Fix build failures
---
llvm/unittests/Transforms/Vectorize/VPlanTestBase.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h b/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
index 6f6200e8e20745..63bcc3ca24910a 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
@@ -89,6 +89,7 @@ class VPlanTestIRBase : public testing::Test {
L, *LI, IntegerType::get(*Ctx, 64), PSE, /*LVer=*/nullptr,
[this]() -> const BranchProbabilityInfo & { return *BPI; });
+ OptimizationRemarkEmitter ORE(&F);
if (Style) {
Inductions.clear();
// handleUncountableEarlyExits requires induction phi recipes.
@@ -99,17 +100,16 @@ class VPlanTestIRBase : public testing::Test {
}
VPDominatorTree VPDT(*Plan);
VPlanTransforms::createHeaderPhiRecipes(
- *Plan, PSE, *L, VPDT, Inductions,
+ *Plan, PSE, *L, &ORE, VPDT, Inductions,
MapVector<PHINode *, RecurrenceDescriptor>(),
SmallPtrSet<const PHINode *, 1>(), SmallPtrSet<PHINode *, 1>(),
/*AllowReordering=*/false);
}
- if (Style) {
- OptimizationRemarkEmitter ORE(&F);
+ if (Style)
VPlanTransforms::handleUncountableEarlyExits(*Plan, &ORE, L, PSE, *DT,
AC.get(), *Style);
- } else
+ else
VPlanTransforms::handleCountableEarlyExits(*Plan);
VPlanTransforms::addMiddleCheck(*Plan);
More information about the llvm-commits
mailing list