[Mlir-commits] [mlir] [mlir][memref] Fix mem2reg crash on zero-extent alloca (PR #216851)

Alessandro Potenza llvmlistbot at llvm.org
Tue Aug 18 10:12:08 PDT 2026


https://github.com/alepot55 updated https://github.com/llvm/llvm-project/pull/216851

>From 3782460f038941fa618221cf84889f22c749747b Mon Sep 17 00:00:00 2001
From: Alessandro Potenza <ap.alessandro.potenza at gmail.com>
Date: Mon, 17 Aug 2026 22:56:39 +0200
Subject: [PATCH 1/5] [mlir][memref] Fix mem2reg crash on zero-extent alloca

`memref` allows an extent of 0, but vector types must have strictly
positive extents. When `memref::AllocaOp::getPromotableSlots` considers
whole-buffer promotion it builds a `VectorType` from the memref shape,
so a legal zero-extent alloca such as

  func.func @z() { %a = memref.alloca() : memref<0xf32>  return }

crashes `mlir-opt --mem2reg` inside `VectorType::get`. The alloca needs
no uses at all: `getPromotableSlots` runs before the `use_empty` filter
in `tryToPromoteMemorySlots`.

Bail out of whole-buffer promotion when the shape contains a zero
extent. Such a memref holds no elements, so there is nothing to promote.
Apply the same reasoning to the scalable path, where the extent comes
from a `vector.vscale * C` operand rather than the shape and `C` is only
known to be a constant: require it to be strictly positive.

The single-element scalar path is unaffected: a shape containing a zero
extent can never have exactly one element.
---
 .../Dialect/MemRef/IR/MemRefMemorySlot.cpp    | 10 +++++++--
 mlir/test/Dialect/MemRef/mem2reg.mlir         | 22 +++++++++++++++++++
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp
index a832b0c47809b..7a2bc0bbee0b8 100644
--- a/mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp
+++ b/mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp
@@ -103,15 +103,21 @@ SmallVector<MemorySlot> memref::AllocaOp::getPromotableSlots() {
   // is only ever accessed as a whole buffer (e.g. through whole-buffer
   // `vector.transfer_read`/`vector.transfer_write`).
   if (VectorType::isValidElementType(type.getElementType())) {
+    // Vector types require strictly positive extents, so a memref with a zero
+    // extent (which holds no elements) has nothing to promote.
+    if (llvm::is_contained(type.getShape(), 0))
+      return {};
+
     // Static shape: a fixed-size vector of the same extents.
     if (type.hasStaticShape())
       return {MemorySlot{getResult(), VectorType::get(type.getShape(),
                                                       type.getElementType())}};
 
     // A 1-D memref whose single dynamic extent is `vector.vscale * C` maps to a
-    // scalable `vector<[C]x...>` slot.
+    // scalable `vector<[C]x...>` slot, for a strictly positive `C`.
     if (type.getRank() == 1 && type.isDynamicDim(0)) {
-      if (std::optional<int64_t> c = matchVScaleMultiple(getDynamicSizes()[0]))
+      if (std::optional<int64_t> c = matchVScaleMultiple(getDynamicSizes()[0]);
+          c && *c > 0)
         return {
             MemorySlot{getResult(), VectorType::get({*c}, type.getElementType(),
                                                     /*scalableDims=*/{true})}};
diff --git a/mlir/test/Dialect/MemRef/mem2reg.mlir b/mlir/test/Dialect/MemRef/mem2reg.mlir
index 8f937c4efe75e..add6bc2e457f0 100644
--- a/mlir/test/Dialect/MemRef/mem2reg.mlir
+++ b/mlir/test/Dialect/MemRef/mem2reg.mlir
@@ -309,3 +309,25 @@ func.func @two_consecutive_merge_points(%cond1: i1, %cond2: i1) -> i32 {
   // CHECK: return %[[RESULT]] : i32
   return %result : i32
 }
+
+// -----
+
+// A memref with a zero extent holds no elements and cannot be promoted: the
+// vector type mem2reg would build for whole-buffer promotion requires strictly
+// positive extents.
+
+// CHECK-LABEL: func.func @zero_extent_alloca
+func.func @zero_extent_alloca() {
+  // CHECK: memref.alloca() : memref<0xf32>
+  %alloca = memref.alloca() : memref<0xf32>
+  return
+}
+
+// -----
+
+// CHECK-LABEL: func.func @zero_extent_alloca_multi_dim
+func.func @zero_extent_alloca_multi_dim() {
+  // CHECK: memref.alloca() : memref<2x0x3xf32>
+  %alloca = memref.alloca() : memref<2x0x3xf32>
+  return
+}

>From 5555bc092e8064ac2429339f488fcdf81896569f Mon Sep 17 00:00:00 2001
From: Alessandro Potenza <ap.alessandro.potenza at gmail.com>
Date: Tue, 18 Aug 2026 01:35:49 +0200
Subject: [PATCH 2/5] Add a test for the scalable path

vscale * 0 is a constant zero extent, so the scalable VectorType cannot be
built either. Unpatched mlir-opt aborts on this input.
---
 mlir/test/Dialect/MemRef/mem2reg.mlir | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/mlir/test/Dialect/MemRef/mem2reg.mlir b/mlir/test/Dialect/MemRef/mem2reg.mlir
index add6bc2e457f0..76b8a5fcf6a32 100644
--- a/mlir/test/Dialect/MemRef/mem2reg.mlir
+++ b/mlir/test/Dialect/MemRef/mem2reg.mlir
@@ -331,3 +331,18 @@ func.func @zero_extent_alloca_multi_dim() {
   %alloca = memref.alloca() : memref<2x0x3xf32>
   return
 }
+
+// -----
+
+// Same for the scalable path: the extent is `vector.vscale * 0`, a constant
+// zero, so the scalable vector type cannot be built either.
+
+// CHECK-LABEL: func.func @scalable_zero_extent_alloca
+func.func @scalable_zero_extent_alloca() {
+  %vscale = vector.vscale
+  %c0 = arith.constant 0 : index
+  %size = arith.muli %vscale, %c0 : index
+  // CHECK: memref.alloca(%{{.*}}) : memref<?xf32>
+  %alloca = memref.alloca(%size) : memref<?xf32>
+  return
+}

>From cc5b8309240ac5048727d58f3e6a7356d0abf58c Mon Sep 17 00:00:00 2001
From: Alessandro Potenza <ap.alessandro.potenza at gmail.com>
Date: Tue, 18 Aug 2026 01:43:51 +0200
Subject: [PATCH 3/5] Address review: shorten the comments, test the scalable
 path

---
 mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp | 2 +-
 mlir/test/Dialect/MemRef/mem2reg.mlir           | 4 +---
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp
index 7a2bc0bbee0b8..84b01eed4bc3a 100644
--- a/mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp
+++ b/mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp
@@ -104,7 +104,7 @@ SmallVector<MemorySlot> memref::AllocaOp::getPromotableSlots() {
   // `vector.transfer_read`/`vector.transfer_write`).
   if (VectorType::isValidElementType(type.getElementType())) {
     // Vector types require strictly positive extents, so a memref with a zero
-    // extent (which holds no elements) has nothing to promote.
+    // extent has nothing to promote.
     if (llvm::is_contained(type.getShape(), 0))
       return {};
 
diff --git a/mlir/test/Dialect/MemRef/mem2reg.mlir b/mlir/test/Dialect/MemRef/mem2reg.mlir
index 76b8a5fcf6a32..e2e204c807b20 100644
--- a/mlir/test/Dialect/MemRef/mem2reg.mlir
+++ b/mlir/test/Dialect/MemRef/mem2reg.mlir
@@ -312,9 +312,7 @@ func.func @two_consecutive_merge_points(%cond1: i1, %cond2: i1) -> i32 {
 
 // -----
 
-// A memref with a zero extent holds no elements and cannot be promoted: the
-// vector type mem2reg would build for whole-buffer promotion requires strictly
-// positive extents.
+// A memref with a zero extent holds no elements and cannot be promoted.
 
 // CHECK-LABEL: func.func @zero_extent_alloca
 func.func @zero_extent_alloca() {

>From 25bc8513861d6fba0bdc43c0d40e35b403c9b0d1 Mon Sep 17 00:00:00 2001
From: Alessandro Potenza <ap.alessandro.potenza at gmail.com>
Date: Tue, 18 Aug 2026 02:11:59 +0200
Subject: [PATCH 4/5] Address review: shorten the scalable-path test comment

---
 mlir/test/Dialect/MemRef/mem2reg.mlir | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/mlir/test/Dialect/MemRef/mem2reg.mlir b/mlir/test/Dialect/MemRef/mem2reg.mlir
index e2e204c807b20..ba26b5f984a27 100644
--- a/mlir/test/Dialect/MemRef/mem2reg.mlir
+++ b/mlir/test/Dialect/MemRef/mem2reg.mlir
@@ -332,8 +332,7 @@ func.func @zero_extent_alloca_multi_dim() {
 
 // -----
 
-// Same for the scalable path: the extent is `vector.vscale * 0`, a constant
-// zero, so the scalable vector type cannot be built either.
+// A memref with a `vector.vscale * 0` extent holds no elements and cannot be promoted.
 
 // CHECK-LABEL: func.func @scalable_zero_extent_alloca
 func.func @scalable_zero_extent_alloca() {

>From ab541fe1e711288e8b6176b6e7526d91cfd60210 Mon Sep 17 00:00:00 2001
From: Alessandro Potenza <ap.alessandro.potenza at gmail.com>
Date: Tue, 18 Aug 2026 19:11:53 +0200
Subject: [PATCH 5/5] Address review: rename the vscale multiple to 'multiple'

---
 mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp
index 84b01eed4bc3a..cfcca90b2b969 100644
--- a/mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp
+++ b/mlir/lib/Dialect/MemRef/IR/MemRefMemorySlot.cpp
@@ -113,14 +113,15 @@ SmallVector<MemorySlot> memref::AllocaOp::getPromotableSlots() {
       return {MemorySlot{getResult(), VectorType::get(type.getShape(),
                                                       type.getElementType())}};
 
-    // A 1-D memref whose single dynamic extent is `vector.vscale * C` maps to a
-    // scalable `vector<[C]x...>` slot, for a strictly positive `C`.
+    // A 1-D memref whose single dynamic extent is `vector.vscale * N` maps to a
+    // scalable `vector<[N]x...>` slot, for a strictly positive multiple `N`.
     if (type.getRank() == 1 && type.isDynamicDim(0)) {
-      if (std::optional<int64_t> c = matchVScaleMultiple(getDynamicSizes()[0]);
-          c && *c > 0)
-        return {
-            MemorySlot{getResult(), VectorType::get({*c}, type.getElementType(),
-                                                    /*scalableDims=*/{true})}};
+      if (std::optional<int64_t> multiple =
+              matchVScaleMultiple(getDynamicSizes()[0]);
+          multiple && *multiple > 0)
+        return {MemorySlot{getResult(),
+                           VectorType::get({*multiple}, type.getElementType(),
+                                           /*scalableDims=*/{true})}};
     }
   }
 



More information about the Mlir-commits mailing list