[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