[Mlir-commits] [mlir] [mlir][memref] Compute subview dropped dims from inferred result type (PR #235093)
Prakhar Dixit
llvmlistbot at llvm.org
Fri Oct 23 13:50:17 PDT 2026
https://github.com/Prakhar-Dixit created https://github.com/llvm/llvm-project/pull/235093
A rank-reducing subview with several unit dims and non-unit strides makes `getDroppedDims` drop the wrong dim. `expand-strided-metadata` then asserts or, with dynamic strides, silently returns wrong sizes and strides.
`getDroppedDims` passes the source type to `computeMemRefRankReductionMask`, which uses strides to tell which unit dims were dropped. With non-unit subview strides, the source strides differ from the result strides (source stride * subview stride), so it picks the wrong dim. The verifier (#79865) and
`inferRankReducedResultType` already use the inferred non-rank-reduced type, which is also what the helper's documentation expects.
Use the same inferred type as the verifier. Add tests for static and variable strides.
Fixes #232662
Fixes #231815
>From 63b286d47c6f164687d68acfc9746eb2c7d13609 Mon Sep 17 00:00:00 2001
From: Prakhar Dixit <dixitprakhar11 at gmail.com>
Date: Sat, 24 Oct 2026 01:50:18 +0530
Subject: [PATCH] [mlir][memref] Compute subview dropped dims from inferred
result type
A rank-reducing subview with several unit dims and non-unit strides
makes `getDroppedDims` drop the wrong dim. `expand-strided-metadata`
then asserts or, with dynamic strides, silently returns wrong sizes and
strides.
`getDroppedDims` passes the source type to
`computeMemRefRankReductionMask`, which uses strides to tell which unit
dims were dropped. With non-unit subview strides, the source strides
differ from the result strides (source stride * subview stride), so it
picks the wrong dim. The verifier (#79865) and
`inferRankReducedResultType` already use the inferred non-rank-reduced
type, which is also what the helper's documentation expects.
Use the same inferred type as the verifier. Add tests for static and
variable strides.
Fixes #232662
Fixes #231815
---
mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp | 9 +-
.../MemRef/expand-strided-metadata.mlir | 93 +++++++++++++++++++
2 files changed, 100 insertions(+), 2 deletions(-)
diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
index 288eeb9cc1a8d8..f3ca398469999c 100644
--- a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
+++ b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
@@ -1103,10 +1103,15 @@ computeMemRefRankReductionMask(MemRefType originalType, MemRefType reducedType,
}
llvm::SmallBitVector SubViewOp::getDroppedDims() {
- MemRefType sourceType = getSourceType();
+ // Compute the dropped dims the same way as the verifier: from the
+ // non-rank-reduced result type, whose strides are the source strides
+ // multiplied by the subview strides.
+ MemRefType expectedType =
+ SubViewOp::inferResultType(getSourceType(), getStaticOffsets(),
+ getStaticSizes(), getStaticStrides());
MemRefType resultType = getType();
FailureOr<llvm::SmallBitVector> unusedDims =
- computeMemRefRankReductionMask(sourceType, resultType, getMixedSizes());
+ computeMemRefRankReductionMask(expectedType, resultType, getMixedSizes());
assert(succeeded(unusedDims) && "unable to find unused dims of subview");
return *unusedDims;
}
diff --git a/mlir/test/Dialect/MemRef/expand-strided-metadata.mlir b/mlir/test/Dialect/MemRef/expand-strided-metadata.mlir
index 85ef1b9b515c66..080d4d6a4e032b 100644
--- a/mlir/test/Dialect/MemRef/expand-strided-metadata.mlir
+++ b/mlir/test/Dialect/MemRef/expand-strided-metadata.mlir
@@ -281,6 +281,99 @@ func.func @extract_strided_metadata_of_rank_reduced_subview_w_variable_strides(
// -----
+// Check that we simplify extract_strided_metadata of subview properly when the
+// subview drops one of several unit dimensions and uses non-unit strides. The
+// dropped dimension must be inferred from the result strides (source stride *
+// subview stride), not from the source strides: both dimensions have size 1,
+// and the result stride 2 can only come from dimension 1 (1 * 2), so
+// dimension 0 is the dropped one.
+//
+// Orig strides: [4, 1]
+// Sub strides: [1, 2]
+// => New strides: [4, 2]
+// Final strides == filterOutReducedDim(new strides, 0) == [2]
+//
+// Orig offset: 0
+// Sub offsets: [0, %offset]
+// => Final offset: 0 * 4 + %offset * 1 + 0 == %offset
+//
+// Final sizes == filterOutReducedDim(subview sizes, 0) == [1]
+//
+// CHECK-LABEL: func @extract_strided_metadata_of_rank_reduced_subview_w_non_unit_strides
+// CHECK-SAME: (%[[ARG:.*]]: memref<2x4xf32>,
+// CHECK-SAME: %[[DYN_OFFSET:.*]]: index)
+//
+// CHECK-DAG: %[[C1:.*]] = arith.constant 1 : index
+// CHECK-DAG: %[[C2:.*]] = arith.constant 2 : index
+//
+// CHECK-DAG: %[[BASE:.*]], %[[OFFSET:.*]], %[[SIZES:.*]]:2, %[[STRIDES:.*]]:2 = memref.extract_strided_metadata %[[ARG]]
+//
+// CHECK: return %[[BASE]], %[[DYN_OFFSET]], %[[C1]], %[[C2]]
+func.func @extract_strided_metadata_of_rank_reduced_subview_w_non_unit_strides(
+ %base: memref<2x4xf32>, %offset: index)
+ -> (memref<f32>, index, index, index) {
+
+ %subview = memref.subview %base[0, %offset][1, 1][1, 2] :
+ memref<2x4xf32> to memref<1xf32, strided<[2], offset: ?>>
+
+ %base_buffer, %new_offset, %size, %stride = memref.extract_strided_metadata %subview :
+ memref<1xf32, strided<[2], offset: ?>>
+ -> memref<f32>, index, index, index
+
+ return %base_buffer, %new_offset, %size, %stride :
+ memref<f32>, index, index, index
+}
+
+// -----
+
+// Same check as above with a dynamic source layout and a variable subview
+// stride. Dimensions 0 and 2 both have size 1. The result stride 4 can only
+// come from dimension 2 (2 * 2), so dimension 0 is the dropped one.
+//
+// Orig strides: [s0, 32, 2]
+// Sub strides: [1, %stride, 2]
+// => New strides: [s0, 32 * %stride, 4]
+// Final strides == filterOutReducedDim(new strides, 0) == [32 * %stride, 4]
+//
+// Orig offset: origOff
+// Sub offsets: [0, 1, 4]
+// => Final offset: 0 * s0 + 1 * 32 + 4 * 2 + origOff == origOff + 40
+//
+// Final sizes == filterOutReducedDim(subview sizes, 0) == [3, 1]
+//
+// CHECK-DAG: #[[$STRIDE1_MAP:.*]] = affine_map<()[s0] -> (s0 * 32)>
+// CHECK-DAG: #[[$OFFSET_MAP:.*]] = affine_map<()[s0] -> (s0 + 40)>
+// CHECK-LABEL: func @extract_strided_metadata_of_rank_reduced_subview_w_variable_and_non_unit_strides
+// CHECK-SAME: (%[[ARG:.*]]: memref<1x5x?xi32, strided<[?, 32, 2], offset: ?>>,
+// CHECK-SAME: %[[DYN_STRIDE:.*]]: index)
+//
+// CHECK-DAG: %[[C3:.*]] = arith.constant 3 : index
+// CHECK-DAG: %[[C1:.*]] = arith.constant 1 : index
+// CHECK-DAG: %[[C4:.*]] = arith.constant 4 : index
+//
+// CHECK-DAG: %[[BASE:.*]], %[[OFFSET:.*]], %[[SIZES:.*]]:3, %[[STRIDES:.*]]:3 = memref.extract_strided_metadata %[[ARG]]
+//
+// CHECK-DAG: %[[DIM1_STRIDE:.*]] = affine.apply #[[$STRIDE1_MAP]]()[%[[DYN_STRIDE]]]
+// CHECK-DAG: %[[FINAL_OFFSET:.*]] = affine.apply #[[$OFFSET_MAP]]()[%[[OFFSET]]]
+//
+// CHECK: return %[[BASE]], %[[FINAL_OFFSET]], %[[C3]], %[[C1]], %[[DIM1_STRIDE]], %[[C4]]
+func.func @extract_strided_metadata_of_rank_reduced_subview_w_variable_and_non_unit_strides(
+ %base: memref<1x5x?xi32, strided<[?, 32, 2], offset: ?>>, %stride: index)
+ -> (memref<i32>, index, index, index, index, index) {
+
+ %subview = memref.subview %base[0, 1, 4][1, 3, 1][1, %stride, 2] :
+ memref<1x5x?xi32, strided<[?, 32, 2], offset: ?>> to memref<3x1xi32, strided<[?, 4], offset: ?>>
+
+ %base_buffer, %offset, %sizes:2, %strides:2 = memref.extract_strided_metadata %subview :
+ memref<3x1xi32, strided<[?, 4], offset: ?>>
+ -> memref<i32>, index, index, index, index, index
+
+ return %base_buffer, %offset, %sizes#0, %sizes#1, %strides#0, %strides#1 :
+ memref<i32>, index, index, index, index, index
+}
+
+// -----
+
// Check that we simplify extract_strided_metadata of subview properly
// when the subview uses variable offsets.
// See extract_strided_metadata_of_subview for an explanation of the actual
More information about the Mlir-commits
mailing list