[mlir][memref] Fix invalid folds in ReinterpretCastOpConstantFolder for negative constants#189237
Conversation
|
@llvm/pr-subscribers-mlir-memref Author: Mehdi Amini (joker-eph) Changes
Fix by skipping the fold when any constant size is negative. Fixes #188407 Assisted-by: Claude Code Full diff: https://github.com/llvm/llvm-project/pull/189237.diff 2 Files Affected:
diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
index 404b2aacf1450..5354c628ae6db 100644
--- a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
+++ b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
@@ -2291,6 +2291,14 @@ struct ReinterpretCastOpConstantFolder
[](OpFoldResult ofr) { return isa<Attribute>(ofr); }))
return failure();
+ // Do not fold if any size is a negative constant; MemRefType::get asserts
+ // non-negative static sizes.
+ for (OpFoldResult sizeOfr : sizes)
+ if (auto cst = getConstantIntValue(sizeOfr))
+ if (*cst < 0)
+ return rewriter.notifyMatchFailure(
+ op, "negative constant size is invalid");
+
auto newReinterpretCast = ReinterpretCastOp::create(
rewriter, op->getLoc(), op.getSource(), offsets[0], sizes, strides);
diff --git a/mlir/test/Dialect/MemRef/canonicalize.mlir b/mlir/test/Dialect/MemRef/canonicalize.mlir
index 92754dc919695..604da0592c93a 100644
--- a/mlir/test/Dialect/MemRef/canonicalize.mlir
+++ b/mlir/test/Dialect/MemRef/canonicalize.mlir
@@ -1287,6 +1287,27 @@ func.func @reinterpret_of_extract_strided_metadata_w_different_offset(%arg0 : me
// -----
+// Check that reinterpret_cast with a negative constant size is not folded.
+// Folding would attempt to create a MemRefType with a negative static dimension,
+// which triggers an assertion in MemRefType::get (issue #188407).
+// CHECK-LABEL: func @reinterpret_cast_no_fold_negative_size
+// CHECK-SAME: (%[[ARG:.*]]: memref<2x3xf32>)
+// CHECK: %[[C0:.*]] = arith.constant 0 : index
+// CHECK: %[[C1:.*]] = arith.constant 1 : index
+// CHECK: %[[SZ:.*]] = arith.constant -1 : index
+// CHECK: memref.reinterpret_cast %[[ARG]] to offset: [%[[C0]]], sizes: [%[[C1]], %[[SZ]]], strides: [%[[SZ]], %[[C1]]]
+func.func @reinterpret_cast_no_fold_negative_size(%arg0: memref<2x3xf32>) -> memref<?x?xf32, strided<[?, ?], offset: ?>> {
+ %c0 = arith.constant 0 : index
+ %c1 = arith.constant 1 : index
+ %sz = arith.constant -1 : index
+ %output = memref.reinterpret_cast %arg0 to
+ offset: [%c0], sizes: [%c1, %sz], strides: [%sz, %c1]
+ : memref<2x3xf32> to memref<?x?xf32, strided<[?, ?], offset: ?>>
+ return %output : memref<?x?xf32, strided<[?, ?], offset: ?>>
+}
+
+// -----
+
func.func @canonicalize_rank_reduced_subview(%arg0 : memref<8x?xf32>,
%arg1 : index) -> memref<?xf32, strided<[?], offset: ?>> {
%c0 = arith.constant 0 : index
|
|
@llvm/pr-subscribers-mlir Author: Mehdi Amini (joker-eph) Changes
Fix by skipping the fold when any constant size is negative. Fixes #188407 Assisted-by: Claude Code Full diff: https://github.com/llvm/llvm-project/pull/189237.diff 2 Files Affected:
diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
index 404b2aacf1450..5354c628ae6db 100644
--- a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
+++ b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
@@ -2291,6 +2291,14 @@ struct ReinterpretCastOpConstantFolder
[](OpFoldResult ofr) { return isa<Attribute>(ofr); }))
return failure();
+ // Do not fold if any size is a negative constant; MemRefType::get asserts
+ // non-negative static sizes.
+ for (OpFoldResult sizeOfr : sizes)
+ if (auto cst = getConstantIntValue(sizeOfr))
+ if (*cst < 0)
+ return rewriter.notifyMatchFailure(
+ op, "negative constant size is invalid");
+
auto newReinterpretCast = ReinterpretCastOp::create(
rewriter, op->getLoc(), op.getSource(), offsets[0], sizes, strides);
diff --git a/mlir/test/Dialect/MemRef/canonicalize.mlir b/mlir/test/Dialect/MemRef/canonicalize.mlir
index 92754dc919695..604da0592c93a 100644
--- a/mlir/test/Dialect/MemRef/canonicalize.mlir
+++ b/mlir/test/Dialect/MemRef/canonicalize.mlir
@@ -1287,6 +1287,27 @@ func.func @reinterpret_of_extract_strided_metadata_w_different_offset(%arg0 : me
// -----
+// Check that reinterpret_cast with a negative constant size is not folded.
+// Folding would attempt to create a MemRefType with a negative static dimension,
+// which triggers an assertion in MemRefType::get (issue #188407).
+// CHECK-LABEL: func @reinterpret_cast_no_fold_negative_size
+// CHECK-SAME: (%[[ARG:.*]]: memref<2x3xf32>)
+// CHECK: %[[C0:.*]] = arith.constant 0 : index
+// CHECK: %[[C1:.*]] = arith.constant 1 : index
+// CHECK: %[[SZ:.*]] = arith.constant -1 : index
+// CHECK: memref.reinterpret_cast %[[ARG]] to offset: [%[[C0]]], sizes: [%[[C1]], %[[SZ]]], strides: [%[[SZ]], %[[C1]]]
+func.func @reinterpret_cast_no_fold_negative_size(%arg0: memref<2x3xf32>) -> memref<?x?xf32, strided<[?, ?], offset: ?>> {
+ %c0 = arith.constant 0 : index
+ %c1 = arith.constant 1 : index
+ %sz = arith.constant -1 : index
+ %output = memref.reinterpret_cast %arg0 to
+ offset: [%c0], sizes: [%c1, %sz], strides: [%sz, %c1]
+ : memref<2x3xf32> to memref<?x?xf32, strided<[?, ?], offset: ?>>
+ return %output : memref<?x?xf32, strided<[?, ?], offset: ?>>
+}
+
+// -----
+
func.func @canonicalize_rank_reduced_subview(%arg0 : memref<8x?xf32>,
%arg1 : index) -> memref<?xf32, strided<[?], offset: ?>> {
%c0 = arith.constant 0 : index
|
|
The size of a memref cannot be negative, the verifier should reject I suspect memref should treat the shape size variable as an unsigned integer, where "-1" represents the maximum unsigned value. |
|
These aren't attributes but dynamic values, the verifier cannot check across def-use chains: https://mlir.llvm.org/getting_started/DeveloperGuide/#ir-verifier |
matthias-springer
left a comment
There was a problem hiding this comment.
Do we want the same check for negative offsets and strides?
…or negative constants
`ReinterpretCastOpConstantFolder` could fold `memref.reinterpret_cast`
ops whose offset or sizes contain negative constants (e.g. `-1 : index`).
- A negative constant size passed into `ReinterpretCastOp::create` reaches
`MemRefType::get`, which asserts that all static dimension sizes are
non-negative, causing a crash.
- A negative constant offset produces an op with a static negative offset,
which the `ViewLikeInterface` verifier then rejects ("expected offsets to
be non-negative").
Fix by skipping the fold when any constant size or the offset is negative.
Negative strides are intentionally left foldable: they are valid in
strided MemRef layouts (e.g. for reverse iteration) and neither
`MemRefType::get` nor `ViewLikeInterface` places a non-negativity
constraint on strides.
Fixes llvm#188407
Assisted-by: Claude Code
aa2ea85 to
cbcbbb2
Compare
|
offsets had the same problem, added fix/test for this. Negative Strides are legit I believe. |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/157/builds/45560 Here is the relevant piece of the build log for the reference |
ReinterpretCastOpConstantFoldercould foldmemref.reinterpret_castops whose offset or sizes contain negative constants (e.g.
-1 : index).A negative constant size passed into
ReinterpretCastOp::createreachesMemRefType::get, which asserts that all static dimension sizes arenon-negative, causing a crash.
A negative constant offset produces an op with a static negative offset,
which the
ViewLikeInterfaceverifier then rejects ("expected offsets tobe non-negative").
Fix by skipping the fold when any constant size or the offset is negative.
Negative strides are intentionally left foldable: they are valid in
strided MemRef layouts (e.g. for reverse iteration) and neither
MemRefType::getnorViewLikeInterfaceplaces a non-negativityconstraint on strides.
Fixes #188407
Assisted-by: Claude Code