[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