[llvm-branch-commits] [llvm] [LV] -scalable-vectorization=preferred should not override UserVF=1 (PR #226948)

Gaƫtan Bossu via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Sep 29 03:26:13 PDT 2026


https://github.com/gbossu updated https://github.com/llvm/llvm-project/pull/226948

>From 1e4754ca8cb7dba85f40613feec889ca09eac761 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Bossu?= <gaetan.bossu at arm.com>
Date: Mon, 28 Sep 2026 10:28:14 +0000
Subject: [PATCH 1/3] [LV] -scalable-vectorization=preferred should not
 override UserVF=1

For loops using #pragma clang loop vectorize(disable), one would expect
vectorisation to be disabled regardless of -scalable-vectorization
flags.

However, LV used to turn a UserVF=1 (vectorisation disabled) into
UserVF=vscale x 1 when -scalable-vectorization=preferred was passed.
---
 .../Vectorize/LoopVectorizationLegality.cpp   |  7 +++-
 .../disable-with-prefer-scalable.ll           | 37 +++++++++++++++++++
 2 files changed, 42 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/Transforms/LoopVectorize/disable-with-prefer-scalable.ll

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index 862470ce0de6d..fe68a03ca7e40 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -132,8 +132,11 @@ LoopVectorizeHints::LoopVectorizeHints(const Loop *L,
 
   // If the flag is set to force any use of scalable vectors, override the loop
   // hints.
-  if (ForceScalableVectorization.getValue() !=
-      LoopVectorizeHints::SK_Unspecified)
+  // However: A preference must not turn a UserVF of 1, used by e.g.
+  // vectorize(disable) pragmas, into a vscale x 1 VF.
+  if (ForceScalableVectorization.getValue() != SK_Unspecified &&
+      (Width.Value != 1 ||
+       ForceScalableVectorization.getValue() != SK_PreferScalable))
     Scalable = ForceScalableVectorization.getValue();
 
   // If force-vector-width is scalable, force scalable vectorization.
diff --git a/llvm/test/Transforms/LoopVectorize/disable-with-prefer-scalable.ll b/llvm/test/Transforms/LoopVectorize/disable-with-prefer-scalable.ll
new file mode 100644
index 0000000000000..084bebf4a1202
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/disable-with-prefer-scalable.ll
@@ -0,0 +1,37 @@
+; RUN: opt -force-target-supports-scalable-vectors -scalable-vectorization=preferred -passes=loop-vectorize -S %s | FileCheck %s
+;
+; Clang lowers "#pragma clang loop vectorize(disable) interleave_count(1)" to
+; width 1 and interleave count 1.
+
+; Ensure the scalable preference does not override the usual fixed-width meaning
+; of that width hint:
+;   A UserVF of 1 should disable vectorization.
+;   -scalable-vectorization=preferred should not yield a VF of vscale x 1.
+;
+; CHECK-LABEL: define void @repro(
+; CHECK-NOT: vector.body:
+define void @repro(ptr %out, ptr %in, i32 %tc) {
+entry:
+  %start = zext i32 %tc to i64
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %start, %entry ], [ %next, %loop ]
+  %in.ptr = getelementptr inbounds i8, ptr %in, i64 %iv
+  %value = load i8, ptr %in.ptr, align 1
+  %sum = add i8 %value, 10
+  %out.ptr = getelementptr inbounds i8, ptr %out, i64 %iv
+  store i8 %sum, ptr %out.ptr, align 1
+  %next = add nsw i64 %iv, -1
+  %next32 = and i64 %next, 4294967295
+  %done = icmp eq i64 %next32, 0
+  br i1 %done, label %exit, label %loop, !llvm.loop !0
+
+exit:
+  ret void
+}
+
+!0 = distinct !{!0, !1, !2, !3}
+!1 = !{!"llvm.loop.mustprogress"}
+!2 = !{!"llvm.loop.vectorize.width", i32 1}
+!3 = !{!"llvm.loop.interleave.count", i32 1}

>From 8d7a63a5b03e01c8eb24ab964e8187d9d104bd8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Bossu?= <gaetan.bossu at arm.com>
Date: Tue, 29 Sep 2026 09:47:14 +0000
Subject: [PATCH 2/3] -scalable-vectorization should not override !loop MD

---
 .../Vectorize/LoopVectorizationLegality.cpp   | 29 ++++++--------
 .../disable-with-prefer-scalable.ll           |  7 ++--
 .../scalable-width-one-with-off.ll            | 38 +++++++++++++++++++
 3 files changed, 53 insertions(+), 21 deletions(-)
 create mode 100644 llvm/test/Transforms/LoopVectorize/scalable-width-one-with-off.ll

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index fe68a03ca7e40..26f7e024ced78 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -112,32 +112,25 @@ LoopVectorizeHints::LoopVectorizeHints(const Loop *L,
   if (VectorizerParams::isInterleaveForced())
     Interleave.Value = VectorizerParams::VectorizationInterleave;
 
-  // If the metadata doesn't explicitly specify whether to enable scalable
-  // vectorization, then decide based on the following criteria (increasing
-  // level of priority):
-  //  - Target default
-  //  - Metadata width
-  //  - Force option (always overrides)
+  // Scalable vectorization is decided based on the following criteria
+  // (increasing level of priority):
+  //  1. Target TTI default
+  //  2. A UserVF (!loop or cl::opt) implies SK_FixedWidthOnly
+  //  3. -scalable-vectorization cl::opt
+  //  4. !loop.vectorize.scalable enable/disable metadata
+  //  5. A scalable -force-vector-width cl::opt implies SK_AlwaysScalable
   if ((LoopVectorizeHints::ScalableForceKind)Scalable == SK_Unspecified) {
     if (TTI)
       Scalable = TTI->enableScalableVectorization() ? SK_PreferScalable
                                                     : SK_FixedWidthOnly;
 
     if (Width.Value)
-      // If the width is set, but the metadata says nothing about the scalable
-      // property, then assume it concerns only a fixed-width UserVF.
-      // If width is not set, the flag takes precedence.
       Scalable = SK_FixedWidthOnly;
-  }
 
-  // If the flag is set to force any use of scalable vectors, override the loop
-  // hints.
-  // However: A preference must not turn a UserVF of 1, used by e.g.
-  // vectorize(disable) pragmas, into a vscale x 1 VF.
-  if (ForceScalableVectorization.getValue() != SK_Unspecified &&
-      (Width.Value != 1 ||
-       ForceScalableVectorization.getValue() != SK_PreferScalable))
-    Scalable = ForceScalableVectorization.getValue();
+    auto ForcedScalable = ForceScalableVectorization.getValue();
+    if (ForcedScalable != SK_Unspecified)
+      Scalable = ForcedScalable;
+  }
 
   // If force-vector-width is scalable, force scalable vectorization.
   if (VectorizerParams::VectorizationFactor.isScalable())
diff --git a/llvm/test/Transforms/LoopVectorize/disable-with-prefer-scalable.ll b/llvm/test/Transforms/LoopVectorize/disable-with-prefer-scalable.ll
index 084bebf4a1202..b11375da54b69 100644
--- a/llvm/test/Transforms/LoopVectorize/disable-with-prefer-scalable.ll
+++ b/llvm/test/Transforms/LoopVectorize/disable-with-prefer-scalable.ll
@@ -1,7 +1,7 @@
 ; RUN: opt -force-target-supports-scalable-vectors -scalable-vectorization=preferred -passes=loop-vectorize -S %s | FileCheck %s
 ;
 ; Clang lowers "#pragma clang loop vectorize(disable) interleave_count(1)" to
-; width 1 and interleave count 1.
+; width 1, scalable.disable and interleave count 1.
 
 ; Ensure the scalable preference does not override the usual fixed-width meaning
 ; of that width hint:
@@ -31,7 +31,8 @@ exit:
   ret void
 }
 
-!0 = distinct !{!0, !1, !2, !3}
+!0 = distinct !{!0, !1, !2, !3, !4}
 !1 = !{!"llvm.loop.mustprogress"}
 !2 = !{!"llvm.loop.vectorize.width", i32 1}
-!3 = !{!"llvm.loop.interleave.count", i32 1}
+!3 = !{!"llvm.loop.vectorize.scalable.disable"}
+!4 = !{!"llvm.loop.interleave.count", i32 1}
diff --git a/llvm/test/Transforms/LoopVectorize/scalable-width-one-with-off.ll b/llvm/test/Transforms/LoopVectorize/scalable-width-one-with-off.ll
new file mode 100644
index 0000000000000..7681748d61060
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/scalable-width-one-with-off.ll
@@ -0,0 +1,38 @@
+; RUN: opt -force-target-supports-scalable-vectors -scalable-vectorization=off -passes=loop-vectorize -S %s | FileCheck %s
+;
+; Clang lowers "#pragma clang loop vectorize_width(1, scalable)" and
+; "interleave_count(1)" to width 1, scalable.enable, and interleave count 1.
+; The explicit scalable width must remain vscale x 1 even with the global
+; scalable-vectorization option set to off.
+;
+; CHECK-LABEL: define void @repro(
+; CHECK: vector.body:
+; CHECK: load <vscale x 1 x i8>
+; CHECK: store <vscale x 1 x i8>
+
+define void @repro(ptr %out, ptr %in, i32 %tc) {
+entry:
+  %start = zext i32 %tc to i64
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %start, %entry ], [ %next, %loop ]
+  %in.ptr = getelementptr inbounds i8, ptr %in, i64 %iv
+  %value = load i8, ptr %in.ptr, align 1
+  %sum = add i8 %value, 10
+  %out.ptr = getelementptr inbounds i8, ptr %out, i64 %iv
+  store i8 %sum, ptr %out.ptr, align 1
+  %next = add nsw i64 %iv, -1
+  %next32 = and i64 %next, 4294967295
+  %done = icmp eq i64 %next32, 0
+  br i1 %done, label %exit, label %loop, !llvm.loop !0
+
+exit:
+  ret void
+}
+
+!0 = distinct !{!0, !1, !2, !3, !4}
+!1 = !{!"llvm.loop.mustprogress"}
+!2 = !{!"llvm.loop.vectorize.width", i32 1}
+!3 = !{!"llvm.loop.interleave.count", i32 1}
+!4 = !{!"llvm.loop.vectorize.scalable.enable"}

>From 6be4cf0ee8eafb52a03464ec7b4cce158a1f63ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Bossu?= <gaetan.bossu at arm.com>
Date: Tue, 29 Sep 2026 09:53:56 +0000
Subject: [PATCH 3/3] Also document precedence order for vector width and IC

---
 .../Vectorize/LoopVectorizationLegality.cpp           | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index 26f7e024ced78..9d2347602f411 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -108,7 +108,16 @@ LoopVectorizeHints::LoopVectorizeHints(const Loop *L,
   // Populate values with existing loop metadata.
   getHintsFromMetadata();
 
-  // force-vector-interleave overrides DisableInterleaving.
+  // The vector width is selected in increasing order of priority:
+  //  1. -force-vector-width
+  //  2. llvm.loop.vectorize.width metadata
+
+  // The interleave count is selected in increasing order of priority:
+  //  1. InterleaveOnlyWhenForced initializes IC to 1
+  //  2. llvm.loop.interleave.count metadata
+  //  3. -force-vector-interleave
+  // Note: If no IC is set, getInterleave() returns 1 when loop unrolling is
+  // disabled.
   if (VectorizerParams::isInterleaveForced())
     Interleave.Value = VectorizerParams::VectorizationInterleave;
 



More information about the llvm-branch-commits mailing list