[Mlir-commits] [mlir] [mlir][memref] Support reducing copied dims to non-unit in reinterpret_cast elision (PR #209536)

ioana ghiban llvmlistbot at llvm.org
Wed Jul 15 02:02:50 PDT 2026


https://github.com/ioghiban updated https://github.com/llvm/llvm-project/pull/209536

>From 5905cd319ad0a104d1316e05f53d4a40eff839b3 Mon Sep 17 00:00:00 2001
From: Ioana Ghiban <ioana.ghiban at arm.com>
Date: Tue, 14 Jul 2026 17:43:06 +0200
Subject: [PATCH 1/2] [memref] Support reducing copied dims to non-unit in
 reinterpret_cast elision

---
 .../Transforms/ElideReinterpretCast.cpp       | 62 ++++++-------
 .../MemRef/elide-reinterpret-cast.mlir        | 86 ++++++++++++++++---
 2 files changed, 108 insertions(+), 40 deletions(-)

diff --git a/mlir/lib/Dialect/MemRef/Transforms/ElideReinterpretCast.cpp b/mlir/lib/Dialect/MemRef/Transforms/ElideReinterpretCast.cpp
index a24a0ccaa3d67..eb5d673c27a70 100644
--- a/mlir/lib/Dialect/MemRef/Transforms/ElideReinterpretCast.cpp
+++ b/mlir/lib/Dialect/MemRef/Transforms/ElideReinterpretCast.cpp
@@ -84,7 +84,7 @@ delinearizeStaticRCOffset(memref::ReinterpretCastOp rc) {
   return offsetIdxs;
 }
 
-static bool hasExactlyOneCollapsedNonUnitDim(memref::ReinterpretCastOp rc) {
+static bool hasExactlyOneReducedNonUnitDim(memref::ReinterpretCastOp rc) {
   MemRefType srcType = dyn_cast<MemRefType>(rc.getSource().getType());
   MemRefType resType = dyn_cast<MemRefType>(rc.getType());
   assert(srcType.hasStaticShape() && resType.hasStaticShape() &&
@@ -92,25 +92,26 @@ static bool hasExactlyOneCollapsedNonUnitDim(memref::ReinterpretCastOp rc) {
   assert(srcType.getRank() == resType.getRank() &&
          "expected rank-preserving reinterpret_cast");
 
-  unsigned collapsedDims = 0;
+  unsigned reducedDims = 0;
 
   for (auto [srcSize, resSize] :
        llvm::zip_equal(srcType.getShape(), resType.getShape())) {
     if (srcSize == resSize)
       continue;
 
-    // Only allow collapsing one non-unit source dim to a unit result dim.
-    if (srcSize != 1 && resSize == 1) {
-      ++collapsedDims;
+    // Only one non-unit source dimension may be reduced.
+    if (srcSize != 1 && resSize < srcSize) {
+      ++reducedDims;
       continue;
     }
 
-    // The sizes differ and both of them are non-unit - ATM not supported.
+    // The size change is not a supported single non-unit source dimension
+    // reduction.
     return false;
   }
 
-  // Make sure there is only one collapsed dimension.
-  return collapsedDims == 1;
+  // Make sure there is only one reduced dimension.
+  return reducedDims == 1;
 }
 
 /// Returns the unique non-unit dim or nullopt if # non-unit-dims != 1.
@@ -134,21 +135,19 @@ static std::optional<unsigned> getSingleNonUnitDim(MemRefType type) {
 /// offsets, delinearized offset.
 ///
 /// Supports ranked, static-shape, rank-preserving reinterpret_casts from
-/// identity-layout sources. In addition:
-///     identical to the source identity strides, and exactly one non-unit
-///     source
-///  * Non-scalar results must have static offsets, static result strides
-///     dimension collapsed to unit size
-/// Scalar-shaped results may have arbitrary result strides (i.e. for scalars,
-/// strides are effectively irrelevant).
+/// identity-layout sources.
+/// * Scalar-shaped results may have arbitrary result strides.
+/// * Non-scalar results must have static offsets, static result strides
+///   identical to the source identity strides, and exactly one non-unit
+///   source dimension size reduced.
 ///
-/// Returns nullopt for unsupported
-/// reinterpret_casts.
+/// Returns nullopt for unsupported reinterpret_casts.
 ///
 /// Examples that return info:
 ///
 ///   reinterpret_cast memref<1xMxNxf32, identity-layout>
-///     to memref<1xMx1xf32, strided<[M*N, N, 1], offset: OFF>>
+///     to memref<1xMxKxf32, strided<[M*N, N, 1], offset: OFF>>
+///     where K < N
 ///
 ///   reinterpret_cast memref<1xMxf32, identity-layout>
 ///     to memref<1x1xf32, strided<[?, ?], offset: ?>>
@@ -156,10 +155,11 @@ static std::optional<unsigned> getSingleNonUnitDim(MemRefType type) {
 /// Examples that return no info:
 ///
 ///   reinterpret_cast memref<1xMxNxf32, identity-layout>
-///     to memref<1xMx1xf32, strided<[?, N, 1]>>
+///     to memref<1xMxKxf32, strided<[?, N, 1]>>
 ///
 ///   reinterpret_cast memref<1xMxNxf32, identity-layout>
-///     to memref<1xKx1xf32, strided<[M*N, N, 1], offset: OFF>>
+///     to memref<1xNxPxf32, strided<[M*N, N, 1], offset: OFF>>
+///     where M != N && N != P
 static std::optional<ResultNonUnitDimsAndOffsetsForRC>
 getResultNonUnitDimsAndOffsetsForRC(memref::ReinterpretCastOp rc) {
   MemRefType srcType = dyn_cast<MemRefType>(rc.getSource().getType());
@@ -221,7 +221,7 @@ getResultNonUnitDimsAndOffsetsForRC(memref::ReinterpretCastOp rc) {
                       }))
       return std::nullopt;
 
-    if (!hasExactlyOneCollapsedNonUnitDim(rc))
+    if (!hasExactlyOneReducedNonUnitDim(rc))
       return std::nullopt;
   }
 
@@ -255,9 +255,9 @@ getResultNonUnitDimsAndOffsetsForRC(memref::ReinterpretCastOp rc) {
 ///      the store index is derived from the reinterpret_cast offset.
 ///
 ///   2. Non-scalar reinterpret_cast results that preserve all non-unit source
-///      dimensions except one collapsed-to-unit dimension. Result strides must
-///      be static and identical to the identity strides of the source, and the
-///      static offset selects the collapsed dimension.
+///      dimensions sizes except one. Result
+///      strides must be static and identical to the identity strides of the
+///      source, and the offset must be static.
 ///
 ///   // BEFORE (scalar-shaped result)
 ///   %strided = memref.reinterpret_cast %dst
@@ -268,18 +268,20 @@ getResultNonUnitDimsAndOffsetsForRC(memref::ReinterpretCastOp rc) {
 ///   %v = memref.load %src[0, ..., 0]
 ///   memref.store %v, %dst[delinearized(OFF)]
 ///
-///   // BEFORE (one collapsed non-unit dimension)
+///   // BEFORE (same-dimension static slice)
 ///   %strided = memref.reinterpret_cast %dst
-///     to offset: [OFF], sizes: [1, M, 1], strides: [M*N, N, 1]
+///     to offset: [OFF], sizes: [1, M, K], strides: [M*N, N, 1]
 ///     : memref<1xMxNxf32>
-///       to memref<1xMx1xf32, strided<[M*N, N, 1], offset: OFF>>
+///       to memref<1xMxKxf32, strided<[M*N, N, 1], offset: OFF>>
 ///   memref.copy %src, %strided
 ///
 ///   // AFTER
-///   // Assuming OFF delinearizes to [0, 0, OFF]:
+///   // Assuming OFF delinearizes to [0, 0, j]:
 ///   scf.for %i = 0 to M step 1 {
-///     %v = memref.load %src[0, %i, 0]
-///     memref.store %v, %dst[0, %i, OFF]
+///     scf.for %k = 0 to K step 1 {
+///       %v = memref.load %src[0, %i, %k]
+///       memref.store %v, %dst[0, %i, j + %k]
+///     }
 ///   }
 struct CopyToLoadAndStore : public OpRewritePattern<memref::CopyOp> {
 public:
diff --git a/mlir/test/Dialect/MemRef/elide-reinterpret-cast.mlir b/mlir/test/Dialect/MemRef/elide-reinterpret-cast.mlir
index 0955d9638f093..1145c7b010ff1 100644
--- a/mlir/test/Dialect/MemRef/elide-reinterpret-cast.mlir
+++ b/mlir/test/Dialect/MemRef/elide-reinterpret-cast.mlir
@@ -262,20 +262,27 @@ func.func private @negative_copy_scalar_into_2D_strided_dynamic_offset(
 // Non-scalar (ND) copy
 //===----------------------------------------------------------------------===//
 
-/// The result of collapsing dimensions is not a unit dimension.
-// CHECK-LABEL: func.func private @negative_copy_1D_into_1D_strided(
-func.func private @negative_copy_1D_into_1D_strided(
+// CHECK-LABEL: func.func private @copy_1D_into_1D_strided_zero_offset(
+// CHECK-SAME:   %[[SRC:.*]]: memref<4xf32>
+// CHECK-SAME:   %[[DST:.*]]: memref<108xf32>
+func.func private @copy_1D_into_1D_strided_zero_offset(
   %src : memref<4xf32>, %dst : memref<108xf32>) {
-  // CHECK:      %reinterpret_cast = memref.reinterpret_cast %arg1
+  // CHECK-NOT:  memref.reinterpret_cast
   %rc = memref.reinterpret_cast %dst
     to offset: [0], sizes: [4], strides: [1]
     : memref<108xf32> to memref<4xf32, strided<[1]>>
 
-  // CHECK:      memref.copy %arg0, %reinterpret_cast
-  // CHECK-NOT:  memref.load
-  // CHECK-NOT:  memref.store
+  // CHECK-NOT:  memref.copy
+  // CHECK-DAG:  %[[C0:.*]] = arith.constant 0 : index
+  // CHECK-DAG:  %[[C1:.*]] = arith.constant 1 : index
+  // CHECK-DAG:  %[[UB:.*]] = arith.constant 4 : index
+  // CHECK:      scf.for %[[IDX:.*]] = %[[C0]] to %[[UB]] step %[[C1]] {
+  // CHECK:        %[[VAL:.*]] = memref.load %[[SRC]][%[[IDX]]] : memref<4xf32>
+  // CHECK:        memref.store %[[VAL]], %[[DST]][%[[IDX]]] : memref<108xf32>
+  // CHECK:      }
   memref.copy %src, %rc
     : memref<4xf32> to memref<4xf32, strided<[1]>>
+  // CHECK-NOT:  memref.copy
   return
 }
 
@@ -418,9 +425,8 @@ func.func private @negative_copy_1D_into_2D_strided_zero_offset_dynamic_stride(%
   return
 }
 
-/// 4 is collapsed to a non-unit dimension.
-// CHECK-LABEL: func.func private @negative_copy_1D_into_2D_strided_diff_dim_sizes(
-func.func private @negative_copy_1D_into_2D_strided_diff_dim_sizes(
+// CHECK-LABEL: func.func private @negative_copy_1D_into_2D_more_reduced_dims(
+func.func private @negative_copy_1D_into_2D_more_reduced_dims(
   %src : memref<1x3x1xf32>, %dst : memref<1x4x11xf32>) {
   // CHECK:      %reinterpret_cast = memref.reinterpret_cast %arg1
   %rc = memref.reinterpret_cast %dst
@@ -437,6 +443,66 @@ func.func private @negative_copy_1D_into_2D_strided_diff_dim_sizes(
   return
 }
 
+// CHECK-LABEL: func.func private @copy_2D_into_2D_strided_zero_offset(
+// CHECK-SAME:   %[[SRC:.*]]: memref<1x3x4xf32>
+// CHECK-SAME:   %[[DST:.*]]: memref<1x3x11xf32>
+func.func private @copy_2D_into_2D_strided_zero_offset(
+  %src : memref<1x3x4xf32>, %dst : memref<1x3x11xf32>) {
+  // CHECK-NOT:  memref.reinterpret_cast
+  %rc = memref.reinterpret_cast %dst
+    to offset: [0], sizes: [1, 3, 4], strides: [33, 11, 1]
+    : memref<1x3x11xf32>
+      to memref<1x3x4xf32, strided<[33, 11, 1]>>
+
+  // CHECK-NOT:  memref.copy
+  // CHECK-DAG:  %[[C0:.*]] = arith.constant 0 : index
+  // CHECK-DAG:  %[[C1:.*]] = arith.constant 1 : index
+  // CHECK-DAG:  %[[UB0:.*]] = arith.constant 3 : index
+  // CHECK-DAG:  %[[UB1:.*]] = arith.constant 4 : index
+  // CHECK:      scf.for %[[IDX0:.*]] = %[[C0]] to %[[UB0]] step %[[C1]] {
+  // CHECK:        scf.for %[[IDX1:.*]] = %[[C0]] to %[[UB1]] step %[[C1]] {
+  // CHECK:          %[[VAL:.*]] = memref.load %[[SRC]][%[[C0]], %[[IDX0]], %[[IDX1]]] : memref<1x3x4xf32>
+  // CHECK:          memref.store %[[VAL]], %[[DST]][%[[C0]], %[[IDX0]], %[[IDX1]]] : memref<1x3x11xf32>
+  // CHECK:        }
+  // CHECK:      }
+  memref.copy %src, %rc
+    : memref<1x3x4xf32>
+      to memref<1x3x4xf32, strided<[33, 11, 1]>>
+  // CHECK-NOT:  memref.copy
+  return
+}
+
+// CHECK-LABEL: func.func private @copy_2D_into_2D_strided_nonzero_offset(
+// CHECK-SAME:   %[[SRC:.*]]: memref<1x3x4xf32>
+// CHECK-SAME:   %[[DST:.*]]: memref<1x3x11xf32>
+func.func private @copy_2D_into_2D_strided_nonzero_offset(
+  %src : memref<1x3x4xf32>, %dst : memref<1x3x11xf32>) {
+  // CHECK-NOT:  memref.reinterpret_cast
+  %rc = memref.reinterpret_cast %dst
+    to offset: [6], sizes: [1, 3, 4], strides: [33, 11, 1]
+    : memref<1x3x11xf32>
+      to memref<1x3x4xf32, strided<[33, 11, 1], offset: 6>>
+
+  // CHECK-NOT:  memref.copy
+  // CHECK-DAG:  %[[C0:.*]] = arith.constant 0 : index
+  // CHECK-DAG:  %[[C1:.*]] = arith.constant 1 : index
+  // CHECK-DAG:  %[[UB0:.*]] = arith.constant 3 : index
+  // CHECK-DAG:  %[[UB1:.*]] = arith.constant 4 : index
+  // CHECK-DAG:  %[[OFF:.*]] = arith.constant 6 : index
+  // CHECK:      scf.for %[[IDX0:.*]] = %[[C0]] to %[[UB0]] step %[[C1]] {
+  // CHECK:        scf.for %[[IDX1:.*]] = %[[C0]] to %[[UB1]] step %[[C1]] {
+  // CHECK:          %[[DST_IDX:.*]] = arith.addi %[[OFF]], %[[IDX1]] : index
+  // CHECK:          %[[VAL:.*]] = memref.load %[[SRC]][%[[C0]], %[[IDX0]], %[[IDX1]]] : memref<1x3x4xf32>
+  // CHECK:          memref.store %[[VAL]], %[[DST]][%[[C0]], %[[IDX0]], %[[DST_IDX]]] : memref<1x3x11xf32>
+  // CHECK:        }
+  // CHECK:      }
+  memref.copy %src, %rc
+    : memref<1x3x4xf32>
+      to memref<1x3x4xf32, strided<[33, 11, 1], offset: 6>>
+  // CHECK-NOT:  memref.copy
+  return
+}
+
 // CHECK-LABEL: func.func private @copy_2D_into_3D_strided_zero_offset(
 // CHECK-SAME:   %[[SRC:.*]]: memref<3x1x4x1xf32>
 // CHECK-SAME:   %[[DST:.*]]: memref<3x1x4x11xf32>

>From c96967b11aa5c6fbecdbd1fd4021c8285c8f62aa Mon Sep 17 00:00:00 2001
From: Ioana Ghiban <ioana.ghiban at arm.com>
Date: Wed, 15 Jul 2026 11:01:41 +0200
Subject: [PATCH 2/2] Address comments

---
 .../Transforms/ElideReinterpretCast.cpp       | 22 ++++----
 .../MemRef/elide-reinterpret-cast.mlir        | 55 +++++++++++++++++--
 2 files changed, 62 insertions(+), 15 deletions(-)

diff --git a/mlir/lib/Dialect/MemRef/Transforms/ElideReinterpretCast.cpp b/mlir/lib/Dialect/MemRef/Transforms/ElideReinterpretCast.cpp
index eb5d673c27a70..47180db268d78 100644
--- a/mlir/lib/Dialect/MemRef/Transforms/ElideReinterpretCast.cpp
+++ b/mlir/lib/Dialect/MemRef/Transforms/ElideReinterpretCast.cpp
@@ -84,7 +84,7 @@ delinearizeStaticRCOffset(memref::ReinterpretCastOp rc) {
   return offsetIdxs;
 }
 
-static bool hasExactlyOneReducedNonUnitDim(memref::ReinterpretCastOp rc) {
+static bool hasExactlyOneTruncatedNonUnitDim(memref::ReinterpretCastOp rc) {
   MemRefType srcType = dyn_cast<MemRefType>(rc.getSource().getType());
   MemRefType resType = dyn_cast<MemRefType>(rc.getType());
   assert(srcType.hasStaticShape() && resType.hasStaticShape() &&
@@ -92,16 +92,16 @@ static bool hasExactlyOneReducedNonUnitDim(memref::ReinterpretCastOp rc) {
   assert(srcType.getRank() == resType.getRank() &&
          "expected rank-preserving reinterpret_cast");
 
-  unsigned reducedDims = 0;
+  unsigned truncatedDims = 0;
 
   for (auto [srcSize, resSize] :
        llvm::zip_equal(srcType.getShape(), resType.getShape())) {
     if (srcSize == resSize)
       continue;
 
-    // Only one non-unit source dimension may be reduced.
+    // Only one non-unit source dimension may be truncated.
     if (srcSize != 1 && resSize < srcSize) {
-      ++reducedDims;
+      ++truncatedDims;
       continue;
     }
 
@@ -110,8 +110,8 @@ static bool hasExactlyOneReducedNonUnitDim(memref::ReinterpretCastOp rc) {
     return false;
   }
 
-  // Make sure there is only one reduced dimension.
-  return reducedDims == 1;
+  // Make sure there is only one truncated dimension.
+  return truncatedDims == 1;
 }
 
 /// Returns the unique non-unit dim or nullopt if # non-unit-dims != 1.
@@ -139,7 +139,7 @@ static std::optional<unsigned> getSingleNonUnitDim(MemRefType type) {
 /// * Scalar-shaped results may have arbitrary result strides.
 /// * Non-scalar results must have static offsets, static result strides
 ///   identical to the source identity strides, and exactly one non-unit
-///   source dimension size reduced.
+///   source dimension size truncated.
 ///
 /// Returns nullopt for unsupported reinterpret_casts.
 ///
@@ -221,7 +221,7 @@ getResultNonUnitDimsAndOffsetsForRC(memref::ReinterpretCastOp rc) {
                       }))
       return std::nullopt;
 
-    if (!hasExactlyOneReducedNonUnitDim(rc))
+    if (!hasExactlyOneTruncatedNonUnitDim(rc))
       return std::nullopt;
   }
 
@@ -268,7 +268,7 @@ getResultNonUnitDimsAndOffsetsForRC(memref::ReinterpretCastOp rc) {
 ///   %v = memref.load %src[0, ..., 0]
 ///   memref.store %v, %dst[delinearized(OFF)]
 ///
-///   // BEFORE (same-dimension static slice)
+///   // BEFORE (one truncated non-unit dimension)
 ///   %strided = memref.reinterpret_cast %dst
 ///     to offset: [OFF], sizes: [1, M, K], strides: [M*N, N, 1]
 ///     : memref<1xMxNxf32>
@@ -276,11 +276,11 @@ getResultNonUnitDimsAndOffsetsForRC(memref::ReinterpretCastOp rc) {
 ///   memref.copy %src, %strided
 ///
 ///   // AFTER
-///   // Assuming OFF delinearizes to [0, 0, j]:
+///   // Assuming OFF delinearizes to [0, 0, OFF]:
 ///   scf.for %i = 0 to M step 1 {
 ///     scf.for %k = 0 to K step 1 {
 ///       %v = memref.load %src[0, %i, %k]
-///       memref.store %v, %dst[0, %i, j + %k]
+///       memref.store %v, %dst[0, %i, OFF + %k]
 ///     }
 ///   }
 struct CopyToLoadAndStore : public OpRewritePattern<memref::CopyOp> {
diff --git a/mlir/test/Dialect/MemRef/elide-reinterpret-cast.mlir b/mlir/test/Dialect/MemRef/elide-reinterpret-cast.mlir
index 1145c7b010ff1..f305de1ccd0d8 100644
--- a/mlir/test/Dialect/MemRef/elide-reinterpret-cast.mlir
+++ b/mlir/test/Dialect/MemRef/elide-reinterpret-cast.mlir
@@ -425,8 +425,8 @@ func.func private @negative_copy_1D_into_2D_strided_zero_offset_dynamic_stride(%
   return
 }
 
-// CHECK-LABEL: func.func private @negative_copy_1D_into_2D_more_reduced_dims(
-func.func private @negative_copy_1D_into_2D_more_reduced_dims(
+// CHECK-LABEL: func.func private @negative_copy_1D_into_2D_multiple_truncated_dims(
+func.func private @negative_copy_1D_into_2D_multiple_truncated_dims(
   %src : memref<1x3x1xf32>, %dst : memref<1x4x11xf32>) {
   // CHECK:      %reinterpret_cast = memref.reinterpret_cast %arg1
   %rc = memref.reinterpret_cast %dst
@@ -443,6 +443,22 @@ func.func private @negative_copy_1D_into_2D_more_reduced_dims(
   return
 }
 
+// CHECK-LABEL: func.func private @negative_copy_into_strided_no_truncated_dims(
+func.func private @negative_copy_into_strided_no_truncated_dims(%src : memref<3x4xf32>,
+  %dst : memref<3x4xf32>) {
+  // CHECK:      %reinterpret_cast = memref.reinterpret_cast %arg1
+  %rc = memref.reinterpret_cast %dst
+    to offset: [0], sizes: [3, 4], strides: [12, 1]
+    : memref<3x4xf32> to memref<3x4xf32, strided<[12, 1]>>
+
+  // CHECK:      memref.copy %arg0, %reinterpret_cast
+  // CHECK-NOT:  memref.load
+  // CHECK-NOT:  memref.store
+  memref.copy %src, %rc
+    : memref<3x4xf32> to memref<3x4xf32, strided<[12, 1]>>
+  return
+}
+
 // CHECK-LABEL: func.func private @copy_2D_into_2D_strided_zero_offset(
 // CHECK-SAME:   %[[SRC:.*]]: memref<1x3x4xf32>
 // CHECK-SAME:   %[[DST:.*]]: memref<1x3x11xf32>
@@ -472,10 +488,10 @@ func.func private @copy_2D_into_2D_strided_zero_offset(
   return
 }
 
-// CHECK-LABEL: func.func private @copy_2D_into_2D_strided_nonzero_offset(
+// CHECK-LABEL: func.func private @copy_2D_into_2D_strided_nonzero_offset_delinearized_v1(
 // CHECK-SAME:   %[[SRC:.*]]: memref<1x3x4xf32>
 // CHECK-SAME:   %[[DST:.*]]: memref<1x3x11xf32>
-func.func private @copy_2D_into_2D_strided_nonzero_offset(
+func.func private @copy_2D_into_2D_strided_nonzero_offset_delinearized_v1(
   %src : memref<1x3x4xf32>, %dst : memref<1x3x11xf32>) {
   // CHECK-NOT:  memref.reinterpret_cast
   %rc = memref.reinterpret_cast %dst
@@ -503,6 +519,37 @@ func.func private @copy_2D_into_2D_strided_nonzero_offset(
   return
 }
 
+// CHECK-LABEL: func.func private @copy_2D_into_2D_strided_nonzero_offset_delinearized_v2(
+// CHECK-SAME:   %[[SRC:.*]]: memref<1x3x11xf32>
+// CHECK-SAME:   %[[DST:.*]]: memref<1x10x11xf32>
+func.func private @copy_2D_into_2D_strided_nonzero_offset_delinearized_v2(
+  %src : memref<1x3x11xf32>, %dst : memref<1x10x11xf32>) {
+  // CHECK-NOT:  memref.reinterpret_cast
+  %rc = memref.reinterpret_cast %dst
+    to offset: [44], sizes: [1, 3, 11], strides: [110, 11, 1]
+    : memref<1x10x11xf32>
+      to memref<1x3x11xf32, strided<[110, 11, 1], offset: 44>>
+
+  // CHECK-NOT:  memref.copy
+  // CHECK-DAG:  %[[C0:.*]] = arith.constant 0 : index
+  // CHECK-DAG:  %[[C1:.*]] = arith.constant 1 : index
+  // CHECK-DAG:  %[[UB0:.*]] = arith.constant 3 : index
+  // CHECK-DAG:  %[[UB1:.*]] = arith.constant 11 : index
+  // CHECK-DAG:  %[[OFF:.*]] = arith.constant 4 : index
+  // CHECK:      scf.for %[[IDX0:.*]] = %[[C0]] to %[[UB0]] step %[[C1]] {
+  // CHECK:        %[[DST_IDX:.*]] = arith.addi %[[OFF]], %[[IDX0]] : index
+  // CHECK:        scf.for %[[IDX1:.*]] = %[[C0]] to %[[UB1]] step %[[C1]] {
+  // CHECK:          %[[VAL:.*]] = memref.load %[[SRC]][%[[C0]], %[[IDX0]], %[[IDX1]]] : memref<1x3x11xf32>
+  // CHECK:          memref.store %[[VAL]], %[[DST]][%[[C0]], %[[DST_IDX]], %[[IDX1]]] : memref<1x10x11xf32>
+  // CHECK:        }
+  // CHECK:      }
+  memref.copy %src, %rc
+    : memref<1x3x11xf32>
+      to memref<1x3x11xf32, strided<[110, 11, 1], offset: 44>>
+  // CHECK-NOT:  memref.copy
+  return
+}
+
 // CHECK-LABEL: func.func private @copy_2D_into_3D_strided_zero_offset(
 // CHECK-SAME:   %[[SRC:.*]]: memref<3x1x4x1xf32>
 // CHECK-SAME:   %[[DST:.*]]: memref<3x1x4x11xf32>



More information about the Mlir-commits mailing list