[Mlir-commits] [mlir] cd116ee - Add examples for reinterpret_cast and subview operators to show their behavior in relation to their input memref underlying memory and view (#135244)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Apr 28 12:58:50 PDT 2025


Author: ivangarcia44
Date: 2025-04-28T15:58:47-04:00
New Revision: cd116ee29e3f9e449f544de73769c0d8b8c0da94

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

LOG: Add examples for reinterpret_cast and subview operators to show their behavior in relation to their input memref underlying memory and view (#135244)

While working on #134845 I was trying to understand the difference of
how the reinterpret_cast and subview operators see the input memref, but
it was not clear to me.

I did a couple of experiments in which I learned that the subview takes
into account the view of the input memref to create the view of the
output memref, while the reinterpret_cast just uses the underlying
memory of the input memref.

I thought it would help future readers to see these two experiements as
examples in the documentation to quickly figure out the difference
between these two operators.

@matthias-springer
@joker-eph
@sahas3
@Hanumanth04
@dixinzhou
@rafaelubalmw

---------

Co-authored-by: Ivan Garcia <igarcia at vdi-ah2ddp-178.dhcp.mathworks.com>

Added: 
    

Modified: 
    mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
index 0cea19964f5f4..d6d8161d3117b 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
@@ -1331,7 +1331,79 @@ def MemRef_ReinterpretCastOp
   let description = [{
     Modify offset, sizes and strides of an unranked/ranked memref.
 
-    Example:
+    Example 1:
+
+    Consecutive `reinterpret_cast` operations on memref's with static
+    dimensions.
+
+    We distinguish between *underlying memory* — the sequence of elements as
+    they appear in the contiguous memory of the memref — and the
+    *strided memref*, which refers to the underlying memory interpreted
+    according to specified offsets, sizes, and strides.
+
+    ```mlir
+    %result1 = memref.reinterpret_cast %arg0 to 
+      offset: [9],
+      sizes: [4, 4],
+      strides: [16, 2]
+    : memref<8x8xf32, strided<[8, 1], offset: 0>> to
+      memref<4x4xf32, strided<[16, 2], offset: 9>>
+
+    %result2 = memref.reinterpret_cast %result1 to 
+      offset: [0],
+      sizes: [2, 2],
+      strides: [4, 2]
+    : memref<4x4xf32, strided<[16, 2], offset: 9>> to
+      memref<2x2xf32, strided<[4, 2], offset: 0>>
+    ```
+
+    The underlying memory of `%arg0` consists of a linear sequence of integers
+    from 1 to 64. Its memref has the following 8x8 elements:
+
+    ```mlir
+    [[1,  2,  3,  4,  5,  6,  7,  8],
+    [9,  10, 11, 12, 13, 14, 15, 16],
+    [17, 18, 19, 20, 21, 22, 23, 24],
+    [25, 26, 27, 28, 29, 30, 31, 32],
+    [33, 34, 35, 36, 37, 38, 39, 40],
+    [41, 42, 43, 44, 45, 46, 47, 48],
+    [49, 50, 51, 52, 53, 54, 55, 56],
+    [57, 58, 59, 60, 61, 62, 63, 64]]
+    ```
+
+    Following the first `reinterpret_cast`, the strided memref elements
+    of `%result1` are:
+
+    ```mlir
+    [[10, 12, 14, 16],
+    [26, 28, 30, 32],
+    [42, 44, 46, 48],
+    [58, 60, 62, 64]]
+    ```
+
+    Note: The offset and strides are relative to the underlying memory of
+    `%arg0`.
+
+    The second `reinterpret_cast` results in the following strided memref
+    for `%result2`:
+
+    ```mlir
+    [[1, 3],
+    [5, 7]]
+    ```
+
+    Notice that it does not matter if you use %result1 or %arg0 as a source
+    for the second `reinterpret_cast` operation. Only the underlying memory
+    pointers will be reused.
+
+    The offset and stride are relative to the base underlying memory of the
+    memref, starting at 1, not at 10 as seen in the output of `%result1`.
+    This behavior contrasts with the `subview` operator, where values are
+    relative to the strided memref (refer to `subview` examples).
+    Consequently, the second `reinterpret_cast` behaves as if `%arg0` were
+    passed directly as its argument.
+
+    Example 2:
     ```mlir
     memref.reinterpret_cast %ranked to
       offset: [0],
@@ -1898,6 +1970,64 @@ def SubViewOp : MemRef_OpWithOffsetSizesAndStrides<"subview", [
 
     Example 1:
 
+    Consecutive `subview` operations on memref's with static dimensions.
+
+    We distinguish between *underlying memory* — the sequence of elements as
+    they appear in the contiguous memory of the memref — and the
+    *strided memref*, which refers to the underlying memory interpreted
+    according to specified offsets, sizes, and strides.
+
+    ```mlir
+    %result1 = memref.subview %arg0[1, 1][4, 4][2, 2]
+    : memref<8x8xf32, strided<[8, 1], offset: 0>> to
+      memref<4x4xf32, strided<[16, 2], offset: 9>>
+
+    %result2 = memref.subview %result1[1, 1][2, 2][2, 2]
+    : memref<4x4xf32, strided<[16, 2], offset: 9>> to
+      memref<2x2xf32, strided<[32, 4], offset: 27>>
+    ```
+
+    The underlying memory of `%arg0` consists of a linear sequence of integers
+    from 1 to 64. Its memref has the following 8x8 elements:
+
+    ```mlir
+    [[1,  2,  3,  4,  5,  6,  7,  8],
+    [9,  10, 11, 12, 13, 14, 15, 16],
+    [17, 18, 19, 20, 21, 22, 23, 24],
+    [25, 26, 27, 28, 29, 30, 31, 32],
+    [33, 34, 35, 36, 37, 38, 39, 40],
+    [41, 42, 43, 44, 45, 46, 47, 48],
+    [49, 50, 51, 52, 53, 54, 55, 56],
+    [57, 58, 59, 60, 61, 62, 63, 64]]
+    ```
+
+    Following the first `subview`, the strided memref elements of `%result1`
+    are:
+
+    ```mlir
+    [[10, 12, 14, 16],
+    [26, 28, 30, 32],
+    [42, 44, 46, 48],
+    [58, 60, 62, 64]]
+    ```
+
+    Note: The offset and strides are relative to the strided memref of `%arg0`
+    (compare to the corresponding `reinterpret_cast` example).
+
+    The second `subview` results in the following strided memref for
+    `%result2`:
+
+    ```mlir
+    [[28, 32],
+    [60, 64]]
+    ```
+
+    Unlike the `reinterpret_cast`, the values are relative to the strided
+    memref of the input (`%result1` in this case) and not its
+    underlying memory.
+    
+    Example 2:
+
     ```mlir
     // Subview of static memref with strided layout at static offsets, sizes
     // and strides.
@@ -1906,7 +2036,7 @@ def SubViewOp : MemRef_OpWithOffsetSizesAndStrides<"subview", [
           memref<8x2xf32, strided<[21, 18], offset: 137>>
     ```
 
-    Example 2:
+    Example 3:
 
     ```mlir
     // Subview of static memref with identity layout at dynamic offsets, sizes
@@ -1915,7 +2045,7 @@ def SubViewOp : MemRef_OpWithOffsetSizesAndStrides<"subview", [
         : memref<64x4xf32> to memref<?x?xf32, strided<[?, ?], offset: ?>>
     ```
 
-    Example 3:
+    Example 4:
 
     ```mlir
     // Subview of dynamic memref with strided layout at dynamic offsets and
@@ -1925,7 +2055,7 @@ def SubViewOp : MemRef_OpWithOffsetSizesAndStrides<"subview", [
           memref<4x4xf32, strided<[?, ?], offset: ?>>
     ```
 
-    Example 4:
+    Example 5:
 
     ```mlir
     // Rank-reducing subviews.
@@ -1935,14 +2065,13 @@ def SubViewOp : MemRef_OpWithOffsetSizesAndStrides<"subview", [
         : memref<8x16x4xf32> to memref<6x3xf32, strided<[4, 1], offset: 210>>
     ```
 
-    Example 5:
+    Example 6:
 
     ```mlir
     // Identity subview. The subview is the full source memref.
     %1 = memref.subview %0[0, 0, 0] [8, 16, 4] [1, 1, 1]
         : memref<8x16x4xf32> to memref<8x16x4xf32>
     ```
-
   }];
 
   let arguments = (ins AnyMemRef:$source,


        


More information about the Mlir-commits mailing list