[Mlir-commits] [mlir] [mlir][vector] reject negative strides for `vector.load`/`vector.store` (PR #204611)

Federico Bruzzone llvmlistbot at llvm.org
Fri Jun 19 04:22:00 PDT 2026


https://github.com/FedericoBruzzone updated https://github.com/llvm/llvm-project/pull/204611

>From 88ac273ce2865cd4890a5d59635f6b75013f477f Mon Sep 17 00:00:00 2001
From: Federico Bruzzone <federico.bruzzone.i at gmail.com>
Date: Thu, 18 Jun 2026 16:18:08 +0200
Subject: [PATCH 1/4] [mlir][vector] reject negative strides

Signed-off-by: Federico Bruzzone <federico.bruzzone.i at gmail.com>
---
 .../mlir/Dialect/Vector/IR/VectorOps.td       |  6 +++++
 mlir/lib/Dialect/Vector/IR/VectorOps.cpp      | 14 +++++++++++
 .../Vector/load-store-negative-strides.mlir   | 25 +++++++++++++++++++
 3 files changed, 45 insertions(+)
 create mode 100644 mlir/test/Dialect/Vector/load-store-negative-strides.mlir

diff --git a/mlir/include/mlir/Dialect/Vector/IR/VectorOps.td b/mlir/include/mlir/Dialect/Vector/IR/VectorOps.td
index 7578ce78a0f00..24442a6336090 100644
--- a/mlir/include/mlir/Dialect/Vector/IR/VectorOps.td
+++ b/mlir/include/mlir/Dialect/Vector/IR/VectorOps.td
@@ -1717,6 +1717,9 @@ def Vector_LoadOp : Vector_Op<"load", [
     %result = vector.load %memref[%i, %j] : memref<200x100xvector<4x8xf32>>, vector<4x8xf32>
     ```
 
+    The memref must have non-negative strides. Negative strides are not supported
+    and will trigger a verification error.
+
     Representation-wise, the 'vector.load' operation permits out-of-bounds
     reads. Support and implementation of out-of-bounds vector loads is
     target-specific. No assumptions should be made on the value of elements
@@ -1835,6 +1838,9 @@ def Vector_StoreOp : Vector_Op<"store", [
     vector.store %valueToStore, %memref[%i, %j] : memref<200x100xvector<4x8xf32>>, vector<4x8xf32>
     ```
 
+    The memref must have non-negative strides. Negative strides are not supported
+    and will trigger a verification error.
+
     Representation-wise, the 'vector.store' operation permits out-of-bounds
     writes. Support and implementation of out-of-bounds vector stores are
     target-specific. No assumptions should be made on the memory written out of
diff --git a/mlir/lib/Dialect/Vector/IR/VectorOps.cpp b/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
index 67c31730f4b65..651f75dc2498d 100644
--- a/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
+++ b/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
@@ -6194,6 +6194,13 @@ LogicalResult vector::LoadOp::verify() {
   if (failed(verifyLoadStoreMemRefLayout(*this, resVecTy, memRefTy)))
     return failure();
 
+  // Negative strides are not supported on vector.load.
+  auto [strides, offset] = memRefTy.getStridesAndOffset();
+  for (int64_t stride : strides) {
+    if (!ShapedType::isDynamic(stride) && stride < 0)
+      return emitOpError("memref strides must be non-negative");
+  }
+
   if (memRefTy.getRank() < resVecTy.getRank())
     return emitOpError(
         "destination memref has lower rank than the result vector");
@@ -6240,6 +6247,13 @@ LogicalResult vector::StoreOp::verify() {
   if (failed(verifyLoadStoreMemRefLayout(*this, valueVecTy, memRefTy)))
     return failure();
 
+  // Negative strides are not supported on vector.store.
+  auto [strides, offset] = memRefTy.getStridesAndOffset();
+  for (int64_t stride : strides) {
+    if (!ShapedType::isDynamic(stride) && stride < 0)
+      return emitOpError("memref strides must be non-negative");
+  }
+
   if (memRefTy.getRank() < valueVecTy.getRank())
     return emitOpError("source memref has lower rank than the vector to store");
 
diff --git a/mlir/test/Dialect/Vector/load-store-negative-strides.mlir b/mlir/test/Dialect/Vector/load-store-negative-strides.mlir
new file mode 100644
index 0000000000000..777053fd632d2
--- /dev/null
+++ b/mlir/test/Dialect/Vector/load-store-negative-strides.mlir
@@ -0,0 +1,25 @@
+// RUN: mlir-opt %s -split-input-file -verify-diagnostics
+
+// -----
+
+func.func @load_negative_stride(%base: memref<100x100xf32>) -> vector<8xf32> {
+  // expected-error @+5 {{'vector.load' op memref strides must be non-negative}}
+  %flip = memref.reinterpret_cast %base to
+      offset: [0], sizes: [100, 100], strides: [-100, 1]
+      : memref<100x100xf32> to memref<100x100xf32, strided<[-100, 1]>>
+  %c0 = arith.constant 0 : index
+  %v = vector.load %flip[%c0, %c0] : memref<100x100xf32, strided<[-100, 1]>>, vector<8xf32>
+  return %v : vector<8xf32>
+}
+
+// -----
+
+func.func @store_negative_stride(%base: memref<100x100xf32>, %val: vector<4xf32>) {
+  // expected-error @+5 {{'vector.store' op memref strides must be non-negative}}
+  %flip = memref.reinterpret_cast %base to
+      offset: [0], sizes: [100, 100], strides: [-100, 1]
+      : memref<100x100xf32> to memref<100x100xf32, strided<[-100, 1]>>
+  %c0 = arith.constant 0 : index
+  vector.store %val, %flip[%c0, %c0] : memref<100x100xf32, strided<[-100, 1]>>, vector<4xf32>
+  return
+}

>From 7d86db3f4ea3ecc478a78ad1776140115cfb5a82 Mon Sep 17 00:00:00 2001
From: Federico Bruzzone <federico.bruzzone.i at gmail.com>
Date: Fri, 19 Jun 2026 07:44:28 +0200
Subject: [PATCH 2/4] Address comments

Signed-off-by: Federico Bruzzone <federico.bruzzone.i at gmail.com>
---
 mlir/lib/Dialect/Vector/IR/VectorOps.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mlir/lib/Dialect/Vector/IR/VectorOps.cpp b/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
index 651f75dc2498d..35f9c4ecbf319 100644
--- a/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
+++ b/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
@@ -6197,7 +6197,7 @@ LogicalResult vector::LoadOp::verify() {
   // Negative strides are not supported on vector.load.
   auto [strides, offset] = memRefTy.getStridesAndOffset();
   for (int64_t stride : strides) {
-    if (!ShapedType::isDynamic(stride) && stride < 0)
+    if (ShapedType::isStatic(stride) && stride < 0)
       return emitOpError("memref strides must be non-negative");
   }
 
@@ -6250,7 +6250,7 @@ LogicalResult vector::StoreOp::verify() {
   // Negative strides are not supported on vector.store.
   auto [strides, offset] = memRefTy.getStridesAndOffset();
   for (int64_t stride : strides) {
-    if (!ShapedType::isDynamic(stride) && stride < 0)
+    if (ShapedType::isStatic(stride) && stride < 0)
       return emitOpError("memref strides must be non-negative");
   }
 

>From b7393436e179e5ad5221cbfb774b7c6e68aa517a Mon Sep 17 00:00:00 2001
From: Federico Bruzzone <federico.bruzzone.i at gmail.com>
Date: Fri, 19 Jun 2026 11:33:36 +0200
Subject: [PATCH 3/4] Use existing `invalid.mlir` file for verifier tests

Signed-off-by: Federico Bruzzone <federico.bruzzone.i at gmail.com>
---
 mlir/test/Dialect/Vector/invalid.mlir         | 18 +++++++++++++
 .../Vector/load-store-negative-strides.mlir   | 25 -------------------
 2 files changed, 18 insertions(+), 25 deletions(-)
 delete mode 100644 mlir/test/Dialect/Vector/load-store-negative-strides.mlir

diff --git a/mlir/test/Dialect/Vector/invalid.mlir b/mlir/test/Dialect/Vector/invalid.mlir
index 2fed3002596a3..bc035964a6af6 100644
--- a/mlir/test/Dialect/Vector/invalid.mlir
+++ b/mlir/test/Dialect/Vector/invalid.mlir
@@ -2145,6 +2145,24 @@ func.func @store_non_unit_stride(%src : memref<?xi8, strided<[2], offset:?>>,%va
 
 // -----
 
+func.func @load_negative_stride(%flip: memref<100x100xf32, strided<[-100, 1]>>) -> vector<8xf32> {
+  // expected-error @+2 {{'vector.load' op memref strides must be non-negative}}
+  %c0 = arith.constant 0 : index
+  %v = vector.load %flip[%c0, %c0] : memref<100x100xf32, strided<[-100, 1]>>, vector<8xf32>
+  return %v : vector<8xf32>
+}
+
+// -----
+
+func.func @store_negative_stride(%flip: memref<100x100xf32, strided<[-100, 1]>>, %val: vector<4xf32>) {
+  // expected-error @+2 {{'vector.store' op memref strides must be non-negative}}
+  %c0 = arith.constant 0 : index
+  vector.store %val, %flip[%c0, %c0] : memref<100x100xf32, strided<[-100, 1]>>, vector<4xf32>
+  return
+}
+
+// -----
+
 // Verify that vector.bitcast rejects vectors with i0 (zero-bitwidth) element type.
 func.func @bitcast_i0(%a: vector<4xi0>) -> vector<4xi0> {
   // expected-error @+1 {{'vector.bitcast' op operand #0 must be vector of non-zero-bitwidth type values, but got 'vector<4xi0>'}}
diff --git a/mlir/test/Dialect/Vector/load-store-negative-strides.mlir b/mlir/test/Dialect/Vector/load-store-negative-strides.mlir
deleted file mode 100644
index 777053fd632d2..0000000000000
--- a/mlir/test/Dialect/Vector/load-store-negative-strides.mlir
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: mlir-opt %s -split-input-file -verify-diagnostics
-
-// -----
-
-func.func @load_negative_stride(%base: memref<100x100xf32>) -> vector<8xf32> {
-  // expected-error @+5 {{'vector.load' op memref strides must be non-negative}}
-  %flip = memref.reinterpret_cast %base to
-      offset: [0], sizes: [100, 100], strides: [-100, 1]
-      : memref<100x100xf32> to memref<100x100xf32, strided<[-100, 1]>>
-  %c0 = arith.constant 0 : index
-  %v = vector.load %flip[%c0, %c0] : memref<100x100xf32, strided<[-100, 1]>>, vector<8xf32>
-  return %v : vector<8xf32>
-}
-
-// -----
-
-func.func @store_negative_stride(%base: memref<100x100xf32>, %val: vector<4xf32>) {
-  // expected-error @+5 {{'vector.store' op memref strides must be non-negative}}
-  %flip = memref.reinterpret_cast %base to
-      offset: [0], sizes: [100, 100], strides: [-100, 1]
-      : memref<100x100xf32> to memref<100x100xf32, strided<[-100, 1]>>
-  %c0 = arith.constant 0 : index
-  vector.store %val, %flip[%c0, %c0] : memref<100x100xf32, strided<[-100, 1]>>, vector<4xf32>
-  return
-}

>From f7bda130d7f6712a200020e39c9a0831ee9f701a Mon Sep 17 00:00:00 2001
From: Federico Bruzzone <federico.bruzzone.i at gmail.com>
Date: Fri, 19 Jun 2026 13:21:50 +0200
Subject: [PATCH 4/4] Update mlir/test/Dialect/Vector/invalid.mlir
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Andrzej WarzyƄski <andrzej.warzynski at gmail.com>
---
 mlir/test/Dialect/Vector/invalid.mlir | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mlir/test/Dialect/Vector/invalid.mlir b/mlir/test/Dialect/Vector/invalid.mlir
index bc035964a6af6..edd8dadabaa68 100644
--- a/mlir/test/Dialect/Vector/invalid.mlir
+++ b/mlir/test/Dialect/Vector/invalid.mlir
@@ -2145,7 +2145,7 @@ func.func @store_non_unit_stride(%src : memref<?xi8, strided<[2], offset:?>>,%va
 
 // -----
 
-func.func @load_negative_stride(%flip: memref<100x100xf32, strided<[-100, 1]>>) -> vector<8xf32> {
+func.func @load_negative_stride(%src: memref<100x100xf32, strided<[-100, 1]>>) -> vector<8xf32> {
   // expected-error @+2 {{'vector.load' op memref strides must be non-negative}}
   %c0 = arith.constant 0 : index
   %v = vector.load %flip[%c0, %c0] : memref<100x100xf32, strided<[-100, 1]>>, vector<8xf32>



More information about the Mlir-commits mailing list