[Mlir-commits] [mlir] 55ddad1 - [mlir][memref] Fix runtime verification of expand_shape (#206125)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sat Jun 27 02:25:29 PDT 2026


Author: Longsheng Mou
Date: 2026-06-27T17:25:25+08:00
New Revision: 55ddad13a6009ec61b91ae40df1dc78be9fb1c64

URL: https://github.com/llvm/llvm-project/commit/55ddad13a6009ec61b91ae40df1dc78be9fb1c64
DIFF: https://github.com/llvm/llvm-project/commit/55ddad13a6009ec61b91ae40df1dc78be9fb1c64.diff

LOG: [mlir][memref] Fix runtime verification of expand_shape (#206125)

The original runtime verification only multiplied static output
dimensions per reassociation group and checked `srcDim % staticProduct`
== 0, which failed to catch invalid dynamic dimension values.
The new verification uses getMixedOutputShape() to get all output
dimensions (static and dynamic), computes their product, and asserts
`product == srcDim`. Fixes #205981.

Assisted-by: MiMo-V2.5-Pro

Added: 
    mlir/test/Integration/Dialect/MemRef/expand-shape-runtime-verification.mlir

Modified: 
    mlir/lib/Dialect/MemRef/Transforms/RuntimeOpVerification.cpp
    mlir/test/Dialect/MemRef/runtime-verification.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/lib/Dialect/MemRef/Transforms/RuntimeOpVerification.cpp b/mlir/lib/Dialect/MemRef/Transforms/RuntimeOpVerification.cpp
index d7fdedce415d9..8f49ed471fbf7 100644
--- a/mlir/lib/Dialect/MemRef/Transforms/RuntimeOpVerification.cpp
+++ b/mlir/lib/Dialect/MemRef/Transforms/RuntimeOpVerification.cpp
@@ -362,37 +362,27 @@ struct ExpandShapeOpInterface
                                   generateErrorMessage) const {
     auto expandShapeOp = cast<ExpandShapeOp>(op);
 
-    // Verify that the expanded dim sizes are a product of the collapsed dim
-    // size.
+    SmallVector<OpFoldResult> outputShape = expandShapeOp.getMixedOutputShape();
+
+    // Verify that the product of output dim sizes in each reassociation group
+    // equals the corresponding input dim size.
     for (const auto &it :
          llvm::enumerate(expandShapeOp.getReassociationIndices())) {
       Value srcDimSz =
           DimOp::create(builder, loc, expandShapeOp.getSrc(), it.index());
-      int64_t groupSz = 1;
-      bool foundDynamicDim = false;
-      for (int64_t resultDim : it.value()) {
-        if (expandShapeOp.getResultType().isDynamicDim(resultDim)) {
-          // Keep this assert here in case the op is extended in the future.
-          assert(!foundDynamicDim &&
-                 "more than one dynamic dim found in reassoc group");
-          (void)foundDynamicDim;
-          foundDynamicDim = true;
-          continue;
-        }
-        groupSz *= expandShapeOp.getResultType().getDimSize(resultDim);
+      Value groupProduct = getValueOrCreateConstantIndexOp(
+          builder, loc, outputShape[it.value().front()]);
+      for (int64_t resultDim : llvm::drop_begin(it.value())) {
+        Value dimSz = getValueOrCreateConstantIndexOp(builder, loc,
+                                                      outputShape[resultDim]);
+        groupProduct = arith::MulIOp::create(builder, loc, groupProduct, dimSz);
       }
-      Value staticResultDimSz =
-          arith::ConstantIndexOp::create(builder, loc, groupSz);
-      // staticResultDimSz must divide srcDimSz evenly.
-      Value mod =
-          arith::RemSIOp::create(builder, loc, srcDimSz, staticResultDimSz);
-      Value isModZero = arith::CmpIOp::create(
-          builder, loc, arith::CmpIPredicate::eq, mod,
-          arith::ConstantIndexOp::create(builder, loc, 0));
+      Value isEqual = arith::CmpIOp::create(
+          builder, loc, arith::CmpIPredicate::eq, groupProduct, srcDimSz);
       cf::AssertOp::create(
-          builder, loc, isModZero,
-          generateErrorMessage(op, "static result dims in reassoc group do not "
-                                   "divide src dim evenly"));
+          builder, loc, isEqual,
+          generateErrorMessage(op, "product of output dims in reassoc group "
+                                   "does not equal input dim"));
     }
   }
 };

diff  --git a/mlir/test/Dialect/MemRef/runtime-verification.mlir b/mlir/test/Dialect/MemRef/runtime-verification.mlir
index 2198f0032aff5..f449ac6e3b30c 100644
--- a/mlir/test/Dialect/MemRef/runtime-verification.mlir
+++ b/mlir/test/Dialect/MemRef/runtime-verification.mlir
@@ -2,12 +2,12 @@
 
 // CHECK-LABEL: func @expand_shape(
 //  CHECK-SAME:     %[[m:.*]]: memref<?xf32>
-//  CHECK-SAME:     %[[sz0:.*]]: index 
-//   CHECK-DAG:   %[[c0:.*]] = arith.constant 0 : index
-//   CHECK-DAG:   %[[c5:.*]] = arith.constant 5 : index
-//   CHECK-DAG:   %[[dim:.*]] = memref.dim %[[m]], %[[c0]]
-//       CHECK:   %[[mod:.*]] = arith.remsi %[[dim]], %[[c5]]
-//       CHECK:   %[[cmpi:.*]] = arith.cmpi eq, %[[mod]], %[[c0]]
+//  CHECK-SAME:     %[[sz0:.*]]: index
+//       CHECK:   %[[c0:.*]] = arith.constant 0 : index
+//       CHECK:   %[[dim:.*]] = memref.dim %[[m]], %[[c0]]
+//       CHECK:   %[[c5:.*]] = arith.constant 5 : index
+//       CHECK:   %[[prod:.*]] = arith.muli %[[sz0]], %[[c5]]
+//       CHECK:   %[[cmpi:.*]] = arith.cmpi eq, %[[prod]], %[[dim]]
 //       CHECK:   cf.assert %[[cmpi]], "ERROR: Runtime op verification failed
 func.func @expand_shape(%m: memref<?xf32>, %sz0: index) -> memref<?x5xf32> {
   %0 = memref.expand_shape %m [[0, 1]] output_shape [%sz0, 5] : memref<?xf32> into memref<?x5xf32>

diff  --git a/mlir/test/Integration/Dialect/MemRef/expand-shape-runtime-verification.mlir b/mlir/test/Integration/Dialect/MemRef/expand-shape-runtime-verification.mlir
new file mode 100644
index 0000000000000..805a416a01a52
--- /dev/null
+++ b/mlir/test/Integration/Dialect/MemRef/expand-shape-runtime-verification.mlir
@@ -0,0 +1,84 @@
+// RUN: mlir-opt %s -generate-runtime-verification \
+// RUN:     -expand-strided-metadata \
+// RUN:     -test-cf-assert \
+// RUN:     -convert-to-llvm | \
+// RUN: mlir-runner -e main -entry-point-result=void \
+// RUN:     -shared-libs=%mlir_runner_utils 2>&1 | \
+// RUN: FileCheck %s
+
+// RUN: mlir-opt %s -generate-runtime-verification \
+// RUN:     -expand-strided-metadata \
+// RUN:     -test-cf-assert \
+// RUN:     -convert-to-llvm="allow-pattern-rollback=0" \
+// RUN:     -reconcile-unrealized-casts | \
+// RUN: mlir-runner -e main -entry-point-result=void \
+// RUN:     -shared-libs=%mlir_runner_utils 2>&1 | \
+// RUN: FileCheck %s
+
+// Dynamic source into dynamic target.
+func.func @expand_shape_dynamic(%m: memref<?xf32>, %sz0: index, %sz1: index) {
+  %0 = memref.expand_shape %m [[0, 1]] output_shape [%sz0, %sz1]
+      : memref<?xf32> into memref<?x?xf32>
+  return
+}
+
+// Dynamic source into mixed static/dynamic target.
+func.func @expand_shape_mixed(%m: memref<?xf32>, %sz0: index) {
+  %0 = memref.expand_shape %m [[0, 1]] output_shape [%sz0, 5]
+      : memref<?xf32> into memref<?x5xf32>
+  return
+}
+
+// Multiple reassociation groups: 2D -> 3D.
+func.func @expand_shape_multi_group(%m: memref<?x?xf32>, %sz0: index, %sz1: index) {
+  %0 = memref.expand_shape %m [[0], [1, 2]] output_shape [%sz0, %sz1, 4]
+      : memref<?x?xf32> into memref<?x?x4xf32>
+  return
+}
+
+func.func @main() {
+  %alloca_10 = memref.alloca() : memref<10xf32>
+  %alloca_10_dyn = memref.cast %alloca_10 : memref<10xf32> to memref<?xf32>
+
+  %alloca_3x20 = memref.alloca() : memref<3x20xf32>
+  %alloca_3x20_dyn = memref.cast %alloca_3x20 : memref<3x20xf32> to memref<?x?xf32>
+
+  %2 = arith.constant 2 : index
+  %3 = arith.constant 3 : index
+  %4 = arith.constant 4 : index
+  %5 = arith.constant 5 : index
+
+  // Product 3*5=15 does not equal input dim 10.
+  //      CHECK: ERROR: Runtime op verification failed
+  // CHECK-NEXT: memref.expand_shape %{{.*}} {{\[}}[0, 1]{{\]}} output_shape [%{{.*}}, %{{.*}}] : memref<?xf32> into memref<?x?xf32>
+  // CHECK-NEXT: ^ product of output dims in reassoc group does not equal input dim
+  // CHECK-NEXT: Location: loc({{.*}})
+  func.call @expand_shape_dynamic(%alloca_10_dyn, %3, %5)
+      : (memref<?xf32>, index, index) -> ()
+
+  // Product 4*5=20 does not equal input dim 10.
+  //      CHECK: ERROR: Runtime op verification failed
+  // CHECK-NEXT: memref.expand_shape %{{.*}} {{\[}}[0, 1]{{\]}} output_shape [%{{.*}}, 5] : memref<?xf32> into memref<?x5xf32>
+  // CHECK-NEXT: ^ product of output dims in reassoc group does not equal input dim
+  // CHECK-NEXT: Location: loc({{.*}})
+  func.call @expand_shape_mixed(%alloca_10_dyn, %4)
+      : (memref<?xf32>, index) -> ()
+
+  // Product 2*5=10 equals input dim 10. No error.
+  // CHECK-NOT: ERROR: Runtime op verification failed
+  func.call @expand_shape_dynamic(%alloca_10_dyn, %2, %5)
+      : (memref<?xf32>, index, index) -> ()
+
+  // Product 2*5=10 equals input dim 10. No error.
+  // CHECK-NOT: ERROR: Runtime op verification failed
+  func.call @expand_shape_mixed(%alloca_10_dyn, %2)
+      : (memref<?xf32>, index) -> ()
+
+  // Group 0: dim 0 -> [dim 0] product 3, input dim 0 = 3 -> OK.
+  // Group 1: dim 1 -> [dim 1, dim 2] product 5*4=20, input dim 1 = 20 -> OK.
+  // CHECK-NOT: ERROR: Runtime op verification failed
+  func.call @expand_shape_multi_group(%alloca_3x20_dyn, %3, %5)
+      : (memref<?x?xf32>, index, index) -> ()
+
+  return
+}


        


More information about the Mlir-commits mailing list