[llvm] [LV][NFC] Fix erroneous debug message emitted during legality checks (PR #226162)

David Sherwood via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 24 06:28:56 PDT 2026


https://github.com/david-arm created https://github.com/llvm/llvm-project/pull/226162

We erroneously state that we can vectorise the loop, since LoopVectorizationLegality is no longer the oracle in matters of legality. Many of the legality checks have been moved to vplan construction, such as when attempting to vectorise some early exit loops. It's very confusing to see debug output that says:

We can vectorize this loop.
Not vectorising the loop because of ...

I've updated the debug message to be more ambiguous.

After this patch I intend to follow up with another one to fix the equally incorrect

LV: Vectorization is possible but not beneficial.

debug message, which assumes the reason for choosing a scalar VF is because of the cost model. However, for some early exit loops we simply failed to create any vector vplans!

>From 5720ae31a99b1581435d0ab52499a30505d31069 Mon Sep 17 00:00:00 2001
From: David Sherwood <david.sherwood at arm.com>
Date: Thu, 24 Sep 2026 13:23:39 +0000
Subject: [PATCH] [LV][NFC] Fix erroneous debug message emitted during legality
 checks

We erroneously state that we can vectorise the loop, since
LoopVectorizationLegality is no longer the oracle in matters of
legality. Many of the legality checks have been moved to vplan
construction, such as when attempting to vectorise some early exit
loops. It's very confusing to see debug output that says:

We can vectorize this loop.
Not vectorising the loop because of ...

I've updated the debug message to be more ambiguous.

After this patch I intend to follow up with another one to fix the
equally incorrect

LV: Vectorization is possible but not beneficial.

debug message, which assumes the reason for choosing a scalar VF
is because of the cost model. However, for some early exit loops we
simply failed to create any vector vplans!
---
 .../Vectorize/LoopVectorizationLegality.cpp   |  2 +-
 .../Transforms/Vectorize/LoopVectorize.cpp    |  3 ++
 .../LoopVectorize/ARM/arm-ieee-vectorize.ll   | 24 ++++++++--------
 .../LoopVectorize/X86/already-vectorized.ll   |  2 +-
 .../LoopVectorize/early_exit_legality.ll      | 23 +++++++++------
 .../early_exit_store_legality.ll              | 28 ++++++++++++-------
 6 files changed, 50 insertions(+), 32 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index 953b1a41e9ee22..85d3cabc1feed1 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -1985,7 +1985,7 @@ bool LoopVectorizationLegality::canVectorize(bool UseVPlanNativePath) {
   }
 
   if (Result) {
-    LLVM_DEBUG(dbgs() << "LV: We can vectorize this loop"
+    LLVM_DEBUG(dbgs() << "LV: We may be able to vectorize this loop"
                       << (LAI->getRuntimePointerChecking()->Need
                               ? " (with a runtime bound check)"
                               : "")
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index d929af8afbd1da..3a3179baffc574 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -5369,6 +5369,9 @@ void LoopVectorizationPlanner::plan(ElementCount UserVF, unsigned UserIC) {
   if (!VPlan1)
     return;
 
+  LLVM_DEBUG(dbgs() << "LV: VPlan created successfully. Loop can be "
+                       "vectorized.\n");
+
   if (!OrigLoop->isInnermost()) {
     // For outer loops, computeMaxVF returns a single non-scalar VF; build a
     // plan for that VF only.
diff --git a/llvm/test/Transforms/LoopVectorize/ARM/arm-ieee-vectorize.ll b/llvm/test/Transforms/LoopVectorize/ARM/arm-ieee-vectorize.ll
index dcdbb0dcc0d753..dc2809fc1fc6c3 100644
--- a/llvm/test/Transforms/LoopVectorize/ARM/arm-ieee-vectorize.ll
+++ b/llvm/test/Transforms/LoopVectorize/ARM/arm-ieee-vectorize.ll
@@ -15,7 +15,7 @@ target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
 
 ; Integer loops are always vectorizeable
 ; CHECK: Checking a loop in 'sumi'
-; CHECK: We can vectorize this loop!
+; CHECK: We may be able to vectorize this loop!
 define void @sumi(ptr noalias nocapture readonly %A, ptr noalias nocapture readonly %B, ptr noalias nocapture %C, i32 %N) {
 entry:
   %cmp5 = icmp eq i32 %N, 0
@@ -48,9 +48,9 @@ for.end:
 ; LINUX: Checking a loop in 'sumf'
 ; LINUX: Potentially unsafe FP op prevents vectorization
 ; MVE: Checking a loop in 'sumf'
-; MVE: We can vectorize this loop!
+; MVE: We may be able to vectorize this loop!
 ; DARWIN: Checking a loop in 'sumf'
-; DARWIN: We can vectorize this loop!
+; DARWIN: We may be able to vectorize this loop!
 define void @sumf(ptr noalias nocapture readonly %A, ptr noalias nocapture readonly %B, ptr noalias nocapture %C, i32 %N) {
 entry:
   %cmp5 = icmp eq i32 %N, 0
@@ -81,7 +81,7 @@ for.end:
 
 ; Integer loops are always vectorizeable
 ; CHECK: Checking a loop in 'redi'
-; CHECK: We can vectorize this loop!
+; CHECK: We may be able to vectorize this loop!
 define i32 @redi(ptr noalias nocapture readonly %a, ptr noalias nocapture readonly %b, i32 %N) {
 entry:
   br label %for.body.preheader
@@ -114,9 +114,9 @@ for.end:
 ; LINUX: Checking a loop in 'redf'
 ; LINUX: Potentially unsafe FP op prevents vectorization
 ; MVE: Checking a loop in 'redf'
-; MVE: We can vectorize this loop!
+; MVE: We may be able to vectorize this loop!
 ; DARWIN: Checking a loop in 'redf'
-; DARWIN: We can vectorize this loop!
+; DARWIN: We may be able to vectorize this loop!
 define float @redf(ptr noalias nocapture readonly %a, ptr noalias nocapture readonly %b, i32 %N) {
 entry:
   br label %for.body.preheader
@@ -149,7 +149,7 @@ for.end:
 ; LINUX: Checking a loop in 'fabs'
 ; LINUX: Potentially unsafe FP op prevents vectorization
 ; DARWIN: Checking a loop in 'fabs'
-; DARWIN: We can vectorize this loop!
+; DARWIN: We may be able to vectorize this loop!
 define void @fabs(ptr noalias nocapture readonly %A, ptr noalias nocapture readonly %B, ptr noalias nocapture %C, i32 %N) {
 entry:
   %cmp10 = icmp eq i32 %N, 0
@@ -175,7 +175,7 @@ for.end:
 
 ; Integer loops are always vectorizeable
 ; CHECK: Checking a loop in 'sumi_fast'
-; CHECK: We can vectorize this loop!
+; CHECK: We may be able to vectorize this loop!
 define void @sumi_fast(ptr noalias nocapture readonly %A, ptr noalias nocapture readonly %B, ptr noalias nocapture %C, i32 %N) {
 entry:
   %cmp5 = icmp eq i32 %N, 0
@@ -206,7 +206,7 @@ for.end:
 
 ; Floating-point loops can be vectorizeable with fast-math
 ; CHECK: Checking a loop in 'sumf_fast'
-; CHECK: We can vectorize this loop!
+; CHECK: We may be able to vectorize this loop!
 define void @sumf_fast(ptr noalias nocapture readonly %A, ptr noalias nocapture readonly %B, ptr noalias nocapture %C, i32 %N) {
 entry:
   %cmp5 = icmp eq i32 %N, 0
@@ -237,7 +237,7 @@ for.end:
 
 ; Integer loops are always vectorizeable
 ; CHECK: Checking a loop in 'redi_fast'
-; CHECK: We can vectorize this loop!
+; CHECK: We may be able to vectorize this loop!
 define i32 @redi_fast(ptr noalias nocapture readonly %a, ptr noalias nocapture readonly %b, i32 %N) {
 entry:
   %cmp5 = icmp eq i32 %N, 0
@@ -270,7 +270,7 @@ for.end:
 
 ; Floating-point loops can be vectorizeable with fast-math
 ; CHECK: Checking a loop in 'redf_fast'
-; CHECK: We can vectorize this loop!
+; CHECK: We may be able to vectorize this loop!
 define float @redf_fast(ptr noalias nocapture readonly %a, ptr noalias nocapture readonly %b, i32 %N) {
 entry:
   br label %for.body.preheader
@@ -301,7 +301,7 @@ for.end:
 
 ; Make sure calls that turn into builtins are also covered
 ; CHECK: Checking a loop in 'fabs_fast'
-; CHECK: We can vectorize this loop!
+; CHECK: We may be able to vectorize this loop!
 define void @fabs_fast(ptr noalias nocapture readonly %A, ptr noalias nocapture readonly %B, ptr noalias nocapture %C, i32 %N) {
 entry:
   %cmp10 = icmp eq i32 %N, 0
diff --git a/llvm/test/Transforms/LoopVectorize/X86/already-vectorized.ll b/llvm/test/Transforms/LoopVectorize/X86/already-vectorized.ll
index 2d960ddaebac25..67494fb7bec2d0 100644
--- a/llvm/test/Transforms/LoopVectorize/X86/already-vectorized.ll
+++ b/llvm/test/Transforms/LoopVectorize/X86/already-vectorized.ll
@@ -19,7 +19,7 @@ entry:
 for.body:
 ; We need to make sure we did vectorize the loop
 ; CHECK: LV: Found a loop: for.body
-; CHECK: LV: We can vectorize this loop!
+; CHECK: LV: We may be able to vectorize this loop!
   %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
   %red.05 = phi i32 [ 0, %entry ], [ %add, %for.body ]
   %arrayidx = getelementptr inbounds [255 x i32], ptr @a, i64 0, i64 %indvars.iv
diff --git a/llvm/test/Transforms/LoopVectorize/early_exit_legality.ll b/llvm/test/Transforms/LoopVectorize/early_exit_legality.ll
index 4593cd30f63a4c..503657843f2c90 100644
--- a/llvm/test/Transforms/LoopVectorize/early_exit_legality.ll
+++ b/llvm/test/Transforms/LoopVectorize/early_exit_legality.ll
@@ -13,8 +13,9 @@ declare void @init_mem(ptr, i64) nofree
 define i32 @diff_exit_block_needs_scev_check(i32 %end) {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'diff_exit_block_needs_scev_check'
 ; CHECK-DEBUG:       Found an early exit loop with symbolic max backedge taken count: (-1 + (1 umax (zext i10 (trunc i32 %end to i10) to i32)))<nsw>
-; CHECK-DEBUG-NEXT:  LV: We can vectorize this loop!
+; CHECK-DEBUG-NEXT:  LV: We may be able to vectorize this loop!
 ; CHECK-DEBUG-NOT:   LV: Not vectorizing:
+; CHECK-DEBUG:       LV: VPlan created successfully. Loop can be vectorized.
 entry:
   %p1 = alloca [1024 x i32]
   %p2 = alloca [1024 x i32]
@@ -51,8 +52,9 @@ exit:
 define i64 @same_exit_block_pre_inc_use1() {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'same_exit_block_pre_inc_use1'
 ; CHECK-DEBUG:       LV: Found an early exit loop with symbolic max backedge taken count: 63
-; CHECK-DEBUG-NEXT:  LV: We can vectorize this loop!
+; CHECK-DEBUG-NEXT:  LV: We may be able to vectorize this loop!
 ; CHECK-DEBUG-NOT:   LV: Not vectorizing
+; CHECK-DEBUG:       LV: VPlan created successfully. Loop can be vectorized.
 entry:
   %p1 = alloca [1024 x i8]
   %p2 = alloca [1024 x i8]
@@ -83,7 +85,8 @@ loop.end:
 define i64 @loop_contains_safe_call() {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'loop_contains_safe_call'
 ; CHECK-DEBUG:       LV: Found an early exit loop with symbolic max backedge taken count: 63
-; CHECK-DEBUG-NEXT:  LV: We can vectorize this loop!
+; CHECK-DEBUG-NEXT:  LV: We may be able to vectorize this loop!
+; CHECK-DEBUG:       LV: VPlan created successfully. Loop can be vectorized.
 entry:
   %p1 = alloca [1024 x i8]
   %p2 = alloca [1024 x i8]
@@ -113,7 +116,8 @@ loop.end:
 define i64 @loop_contains_safe_div() {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'loop_contains_safe_div'
 ; CHECK-DEBUG:       LV: Found an early exit loop with symbolic max backedge taken count: 63
-; CHECK-DEBUG-NEXT:  LV: We can vectorize this loop!
+; CHECK-DEBUG-NEXT:  LV: We may be able to vectorize this loop!
+; CHECK-DEBUG:       LV: VPlan created successfully. Loop can be vectorized.
 entry:
   %p1 = alloca [1024 x i8]
   %p2 = alloca [1024 x i8]
@@ -143,8 +147,9 @@ loop.end:
 define i64 @loop_contains_load_after_early_exit(ptr dereferenceable(1024) align(8) %p2) {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'loop_contains_load_after_early_exit'
 ; CHECK-DEBUG:       LV: Found an early exit loop with symbolic max backedge taken count: 63
-; CHECK-DEBUG-NEXT:  LV: We can vectorize this loop!
+; CHECK-DEBUG-NEXT:  LV: We may be able to vectorize this loop!
 ; CHECK-DEBUG-NOT:   LV: Not vectorizing
+; CHECK-DEBUG:       LV: VPlan created successfully. Loop can be vectorized.
 entry:
   %p1 = alloca [1024 x i8]
   call void @init_mem(ptr %p1, i64 1024)
@@ -173,7 +178,7 @@ loop.end:
 define i64 @one_uncountable_two_countable_same_exit_phi_of_consts() !dbg !39 {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'one_uncountable_two_countable_same_exit_phi_of_consts'
 ; CHECK-DEBUG:       LV: Found an early exit loop with symbolic max backedge taken count: 61
-; CHECK-DEBUG-NEXT:  LV: We can vectorize this loop!
+; CHECK-DEBUG-NEXT:  LV: We may be able to vectorize this loop!
 ; CHECK-DEBUG-NEXT:  LV: Not vectorizing: Auto-vectorization of early exit loops requiring a scalar epilogue is unsupported.
 ; CHECK-REMARK:      foo.c:60:3: loop not vectorized: Auto-vectorization of early exit loops requiring a scalar epilogue is unsupported
 entry:
@@ -358,7 +363,8 @@ loop.end:
 ; Multiple uncountable early exits are now supported.
 define i64 @multiple_uncountable_exits() {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'multiple_uncountable_exits'
-; CHECK-DEBUG:       LV: We can vectorize this loop!
+; CHECK-DEBUG:       LV: We may be able to vectorize this loop!
+; CHECK-DEBUG:       LV: VPlan created successfully. Loop can be vectorized.
 entry:
   %p1 = alloca [1024 x i8]
   %p2 = alloca [1024 x i8]
@@ -612,7 +618,8 @@ loop.end:
 ; This is now supported with predicated early exits.
 define i64 @uncountable_exits_on_parallel_branches() {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'uncountable_exits_on_parallel_branches'
-; CHECK-DEBUG:       LV: We can vectorize this loop!
+; CHECK-DEBUG:       LV: We may be able to vectorize this loop!
+; CHECK-DEBUG:       LV: VPlan created successfully. Loop can be vectorized.
 entry:
   %p1 = alloca [1024 x i8]
   %p2 = alloca [1024 x i8]
diff --git a/llvm/test/Transforms/LoopVectorize/early_exit_store_legality.ll b/llvm/test/Transforms/LoopVectorize/early_exit_store_legality.ll
index 71650a4c365673..653121fa5f306d 100644
--- a/llvm/test/Transforms/LoopVectorize/early_exit_store_legality.ll
+++ b/llvm/test/Transforms/LoopVectorize/early_exit_store_legality.ll
@@ -34,7 +34,8 @@ loop.end:
 
 define void @loop_contains_store_condition_load_has_single_user(ptr dereferenceable(40) noalias %array, ptr align 2 dereferenceable(40) readonly %pred) {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'loop_contains_store_condition_load_has_single_user'
-; CHECK-DEBUG:       LV: We can vectorize this loop!
+; CHECK-DEBUG:       LV: We may be able to vectorize this loop!
+; CHECK-DEBUG:       LV: VPlan created successfully. Loop can be vectorized.
 entry:
   br label %for.body
 
@@ -88,7 +89,8 @@ exit:
 ;; Exit-condition load on the RHS of the icmp must still be accepted.
 define void @swapped_cmp_operands(ptr noalias %array, ptr %pred) {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'swapped_cmp_operands'
-; CHECK-DEBUG:       LV: We can vectorize this loop!
+; CHECK-DEBUG:       LV: We may be able to vectorize this loop!
+; CHECK-DEBUG:       LV: Not vectorizing: Early exit loop with side effects contains load used by the exit condition that may fault.
 entry:
   br label %loop
 
@@ -236,7 +238,8 @@ exit:
 ;; Alternatively, we could use masked.load.ff or vp.load.ff
 define void @loop_contains_store_assumed_bounds(ptr noalias %array, ptr readonly %pred, i64 %n) {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'loop_contains_store_assumed_bounds'
-; CHECK-DEBUG:       LV: We can vectorize this loop!
+; CHECK-DEBUG:       LV: We may be able to vectorize this loop!
+; CHECK-DEBUG:       LV: Not vectorizing: Early exit loop with side effects contains load used by the exit condition that may fault.
 entry:
   %n_bytes = mul nuw nsw i64 %n, 2
   call void @llvm.assume(i1 true) [ "align"(ptr %pred, i64 2), "dereferenceable"(ptr %pred, i64 %n_bytes) ]
@@ -264,7 +267,8 @@ exit:
 
 define void @loop_contains_store_to_pointer_with_no_deref_info(ptr align 2 dereferenceable(40) readonly %load.array, ptr align 2 noalias %array, ptr align 2 dereferenceable(40) readonly %pred) {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'loop_contains_store_to_pointer_with_no_deref_info'
-; CHECK-DEBUG:       LV: We can vectorize this loop!
+; CHECK-DEBUG:       LV: We may be able to vectorize this loop!
+; CHECK-DEBUG:       LV: VPlan created successfully. Loop can be vectorized.
 entry:
   br label %for.body
 
@@ -292,7 +296,8 @@ exit:
 ;; Vectorizeable, requires runtime checks and/or ff loads.
 define void @loop_contains_store_unknown_bounds(ptr align 2 dereferenceable(100) noalias %array, ptr align 2 dereferenceable(100) readonly %pred, i64 %n) {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'loop_contains_store_unknown_bounds'
-; CHECK-DEBUG:       LV: We can vectorize this loop!
+; CHECK-DEBUG:       LV: We may be able to vectorize this loop!
+; CHECK-DEBUG:       LV: Not vectorizing: Early exit loop with side effects contains load used by the exit condition that may fault.
 entry:
   br label %for.body
 
@@ -376,7 +381,8 @@ exit:
 
 define void @loop_contains_store_in_latch_block(ptr dereferenceable(40) noalias %array, ptr align 2 dereferenceable(40) readonly %pred) {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'loop_contains_store_in_latch_block'
-; CHECK-DEBUG:       LV: We can vectorize this loop!
+; CHECK-DEBUG:       LV: We may be able to vectorize this loop!
+; CHECK-DEBUG:       LV: VPlan created successfully. Loop can be vectorized.
 entry:
   br label %for.body
 
@@ -742,7 +748,8 @@ exit:
 
 define i16 @uncountable_exit_with_live_out(ptr dereferenceable(40) noalias %array, ptr align 2 dereferenceable(40) readonly %pred) {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'uncountable_exit_with_live_out'
-; CHECK-DEBUG:       LV: We can vectorize this loop!
+; CHECK-DEBUG:       LV: We may be able to vectorize this loop!
+; CHECK-DEBUG:       LV: VPlan created successfully. Loop can be vectorized.
 entry:
   br label %for.body
 
@@ -769,7 +776,7 @@ exit:
 ; Vectorizeable, requires improvements in dereferenceability checks
 define void @uncountable_exit_with_constant_nonunit_stride(ptr dereferenceable(4000) noalias %array, ptr align 2 dereferenceable(4000) readonly %pred) !dbg !60 {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'uncountable_exit_with_constant_nonunit_stride'
-; CHECK-DEBUG:       LV: We can vectorize this loop!
+; CHECK-DEBUG:       LV: We may be able to vectorize this loop!
 ; CHECK-DEBUG:       LV: Not vectorizing: unable to calculate the loop count due to complex control flow.
 ; CHECK-REMARK:      foo.c:260:3: loop not vectorized: unable to calculate the loop count due to complex control flow
 entry:
@@ -826,7 +833,8 @@ exit:
 
 define i32 @uncountable_exit_with_separate_exit_block(ptr dereferenceable(40) noalias %array, ptr align 2 dereferenceable(40) readonly %pred) {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'uncountable_exit_with_separate_exit_block'
-; CHECK-DEBUG:       LV: We can vectorize this loop!
+; CHECK-DEBUG:       LV: We may be able to vectorize this loop!
+; CHECK-DEBUG:       LV: VPlan created successfully. Loop can be vectorized.
 entry:
   br label %for.body
 
@@ -885,7 +893,7 @@ exit:
 
 define i32 @uncountable_exit_with_masked_ldst_separate_condition(ptr dereferenceable(40) noalias %array, ptr align 2 dereferenceable(40) readonly %pred, ptr align 2 readonly %st.pred) !dbg !66 {
 ; CHECK-DEBUG-LABEL: LV: Checking a loop in 'uncountable_exit_with_masked_ldst_separate_condition'
-; CHECK-DEBUG:       LV: We can vectorize this loop!
+; CHECK-DEBUG:       LV: We may be able to vectorize this loop!
 ; 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-REMARK:      foo.c:290:3: loop not vectorized: Early exit loop with side effects contains unsupported conditional memory operations



More information about the llvm-commits mailing list