[Mlir-commits] [mlir] [mlir][linalg] Fix crash in FoldTensorCastUnPackOp with dynamic non-constant tile size (PR #189071)

Mehdi Amini llvmlistbot at llvm.org
Thu Apr 9 02:54:47 PDT 2026


https://github.com/joker-eph updated https://github.com/llvm/llvm-project/pull/189071

>From 78d86686d214c37ce74eeb21c8f9619b8b960451 Mon Sep 17 00:00:00 2001
From: Mehdi Amini <joker.eph at gmail.com>
Date: Fri, 27 Mar 2026 10:46:30 -0700
Subject: [PATCH] [mlir][linalg] Fix crash in FoldTensorCastUnPackOp with
 dynamic non-constant tile size

`getNewMixedTileSizes` was calling `getConstantIntValue(tile).value()`
unconditionally when a tile OpFoldResult was a dynamic SSA Value (not an
Attribute). When the tile is a runtime-dynamic Value that is not a
compile-time constant, `getConstantIntValue` returns `std::nullopt` and
`.value()` aborts with `bad_optional_access`.

The fix replaces the assertion with the correct behavior: when the packed
type statically provides `dimSize`, we can use that value directly as the
new tile size, regardless of whether the original tile Value happens to be
constant.

Fixes #187975

Assisted-by: Claude Code
---
 mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp   |  6 +-
 mlir/test/Dialect/Linalg/canonicalize.mlir | 65 ++++++++++++++++++++++
 2 files changed, 68 insertions(+), 3 deletions(-)

diff --git a/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp b/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
index f9c8589683ba7..8b588a97b4363 100644
--- a/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
+++ b/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
@@ -5037,10 +5037,10 @@ getNewMixedTileSizes(PatternRewriter &rewriter, Type newPackedTy,
       // Already a constant
       newMixedTileSizes.push_back(tile);
     } else {
-      assert(getConstantIntValue(tile).value() == dimSize &&
-             "tile size and dim size don't match!");
+      // The tile is a dynamic Value. Since the packed type tells us the
+      // dimension is statically dimSize, we can use that static value directly.
       newMixedTileSizes.push_back(
-          (rewriter.getIntegerAttr(rewriter.getIndexType(), dimSize)));
+          rewriter.getIntegerAttr(rewriter.getIndexType(), dimSize));
     }
   }
 
diff --git a/mlir/test/Dialect/Linalg/canonicalize.mlir b/mlir/test/Dialect/Linalg/canonicalize.mlir
index 0c5a1c6108ae3..ae74bb2ed9e30 100644
--- a/mlir/test/Dialect/Linalg/canonicalize.mlir
+++ b/mlir/test/Dialect/Linalg/canonicalize.mlir
@@ -1952,6 +1952,71 @@ func.func @fold_cast_unpack_dynamic_tile_size(
 
 // -----
 
+// Regression test: FoldTensorCastUnPackOp must not crash when a tile size is a
+// dynamic (non-constant) SSA value and the cast makes the packed dim static.
+// The static dim value from the cast should be used as the new tile size.
+// CHECK-LABEL: func.func @fold_cast_unpack_nonconstant_dynamic_tile(
+// CHECK-SAME:     %[[SRC:.*]]: tensor<1x3x8x1xi32>,
+// CHECK-SAME:     %[[TILE:.*]]: index,
+// CHECK-SAME:     %[[DEST:.*]]: tensor<7x3xi32>) -> tensor<7x3xi32> {
+// CHECK:          %[[RES:.*]] = linalg.unpack %[[SRC]] inner_dims_pos = [0, 1] inner_tiles = [8, 1] into %[[DEST]] : tensor<1x3x8x1xi32> -> tensor<7x3xi32>
+// CHECK:          return %[[RES]] : tensor<7x3xi32>
+func.func @fold_cast_unpack_nonconstant_dynamic_tile(
+  %src: tensor<1x3x8x1xi32>,
+  %tile_size: index,
+  %dest: tensor<7x3xi32>) -> tensor<7x3xi32> {
+    %cast = tensor.cast %src : tensor<1x3x8x1xi32> to tensor<?x3x?x1xi32>
+    %unpack = linalg.unpack %cast
+      inner_dims_pos = [0, 1]
+      inner_tiles = [%tile_size, 1]
+      into %dest : tensor<?x3x?x1xi32> -> tensor<7x3xi32>
+    return %unpack : tensor<7x3xi32>
+}
+
+// -----
+
+// When the cast reveals a static dim but the tile is a constant SSA value that
+// doesn't match.
+// CHECK-LABEL: func.func @fold_cast_unpack_constant_tile_mismatch(
+// CHECK:          linalg.unpack %[[CAST]] inner_dims_pos = [0, 1] inner_tiles = [8, 1]
+func.func @fold_cast_unpack_constant_tile_mismatch(
+  %src: tensor<1x3x8x1xi32>,
+  %dest: tensor<7x3xi32>) -> tensor<7x3xi32> {
+    %cast = tensor.cast %src : tensor<1x3x8x1xi32> to tensor<?x3x?x1xi32>
+    %c4 = arith.constant 4 : index
+    %unpack = linalg.unpack %cast
+      inner_dims_pos = [0, 1]
+      inner_tiles = [%c4, 1]
+      into %dest : tensor<?x3x?x1xi32> -> tensor<7x3xi32>
+    return %unpack : tensor<7x3xi32>
+}
+
+// -----
+
+// Regression test: FoldTensorCastPackOp must not crash when a tile size is a
+// dynamic (non-constant) SSA value and the cast makes the packed dim static.
+// The static dim value from the cast should be used as the new tile size.
+// CHECK-LABEL: func.func @fold_cast_pack_nonconstant_dynamic_tile(
+// CHECK-SAME:     %[[SRC:.*]]: tensor<8x3xi32>,
+// CHECK-SAME:     %[[TILE:.*]]: index,
+// CHECK-SAME:     %[[DEST:.*]]: tensor<1x3x8x1xi32>) -> tensor<1x3x8x1xi32> {
+// CHECK:          %[[RES:.*]] = linalg.pack %[[SRC]] inner_dims_pos = [0, 1] inner_tiles = [8, 1] into %[[DEST]] : tensor<8x3xi32> -> tensor<1x3x8x1xi32>
+// CHECK:          return %[[RES]] : tensor<1x3x8x1xi32>
+func.func @fold_cast_pack_nonconstant_dynamic_tile(
+  %src: tensor<8x3xi32>,
+  %tile_size: index,
+  %dest: tensor<1x3x8x1xi32>) -> tensor<1x3x8x1xi32> {
+    %cast = tensor.cast %dest : tensor<1x3x8x1xi32> to tensor<?x3x?x1xi32>
+    %pack = linalg.pack %src
+      inner_dims_pos = [0, 1]
+      inner_tiles = [%tile_size, 1]
+      into %cast : tensor<8x3xi32> -> tensor<?x3x?x1xi32>
+    %res = tensor.cast %pack : tensor<?x3x?x1xi32> to tensor<1x3x8x1xi32>
+    return %res : tensor<1x3x8x1xi32>
+}
+
+// -----
+
 //===----------------------------------------------------------------------===//
 // linalg.unpack + tensor.extract_slice
 //===----------------------------------------------------------------------===//



More information about the Mlir-commits mailing list