@@ -1859,11 +1859,11 @@ def SubViewOp : MemRef_OpWithOffsetSizesAndStrides<"subview", [
1859
1859
]> {
1860
1860
let summary = "memref subview operation";
1861
1861
let description = [{
1862
- The ` subview` operation converts a memref type to a memref type which
1863
- represents a reduced-size view of the original memref as specified by the
1864
- operation's offsets, sizes and strides arguments.
1862
+ The " subview" operation converts a memref type to another memref type
1863
+ which represents a reduced-size view of the original memref as specified by
1864
+ the operation's offsets, sizes and strides arguments.
1865
1865
1866
- The `subview` operation supports the following arguments:
1866
+ The SubView operation supports the following arguments:
1867
1867
1868
1868
* source: the "base" memref on which to create a "view" memref.
1869
1869
* offsets: memref-rank number of offsets into the "base" memref at which to
@@ -1876,73 +1876,118 @@ def SubViewOp : MemRef_OpWithOffsetSizesAndStrides<"subview", [
1876
1876
The representation based on offsets, sizes and strides support a
1877
1877
partially-static specification via attributes specified through the
1878
1878
`static_offsets`, `static_sizes` and `static_strides` arguments. A special
1879
- sentinel value ` ShapedType::kDynamic` encodes that the corresponding entry
1880
- has a dynamic value.
1879
+ sentinel value ShapedType::kDynamic encodes that the corresponding entry has
1880
+ a dynamic value.
1881
1881
1882
- A `subview` operation may additionally reduce the rank of the resulting
1883
- view by removing dimensions that are statically known to be of size 1.
1884
-
1885
- In the absence of rank reductions, the resulting memref type is computed
1886
- as follows:
1887
- ```
1888
- result_sizes[i] = size_operands[i]
1889
- result_strides[i] = src_strides[i] * stride_operands[i]
1890
- result_offset = src_offset + dot_product(offset_operands, src_strides)
1891
- ```
1892
-
1893
- The offset, size and stride operands must be in-bounds with respect to the
1894
- source memref. When possible, the static operation verifier will detect
1895
- out-of-bounds subviews. Subviews that cannot be confirmed to be in-bounds
1896
- or out-of-bounds based on compile-time information are valid. However,
1897
- performing an out-of-bounds subview at runtime is undefined behavior.
1882
+ A subview operation may additionally reduce the rank of the resulting view
1883
+ by removing dimensions that are statically known to be of size 1.
1898
1884
1899
1885
Example 1:
1900
1886
1901
1887
```mlir
1902
- // Subview of static memref with strided layout at static offsets, sizes
1903
- // and strides.
1904
- %1 = memref.subview %0[4, 2][8, 2][3, 2]
1905
- : memref<64x4xf32, strided<[7, 9], offset: 91>> to
1906
- memref<8x2xf32, strided<[21, 18], offset: 137>>
1888
+ %0 = memref.alloc() : memref<64x4xf32, affine_map<(d0, d1) -> (d0 * 4 + d1)>>
1889
+
1890
+ // Create a sub-view of "base" memref '%0' with offset arguments '%c0',
1891
+ // dynamic sizes for each dimension, and stride arguments '%c1'.
1892
+ %1 = memref.subview %0[%c0, %c0][%size0, %size1][%c1, %c1]
1893
+ : memref<64x4xf32, affine_map<(d0, d1) -> (d0 * 4 + d1)>> to
1894
+ memref<?x?xf32, affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + d1 + s0)>>
1907
1895
```
1908
1896
1909
1897
Example 2:
1910
1898
1911
1899
```mlir
1912
- // Subview of static memref with identity layout at dynamic offsets, sizes
1900
+ %0 = memref.alloc() : memref<8x16x4xf32, affine_map<(d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)>>
1901
+
1902
+ // Create a sub-view of "base" memref '%0' with dynamic offsets, sizes,
1913
1903
// and strides.
1914
- %1 = memref.subview %0[%off0, %off1][%sz0, %sz1][%str0, %str1]
1915
- : memref<64x4xf32> to memref<?x?xf32, strided<[?, ?], offset: ?>>
1904
+ // Note that dynamic offsets are represented by the linearized dynamic
1905
+ // offset symbol 's0' in the subview memref layout map, and that the
1906
+ // dynamic strides operands, after being applied to the base memref
1907
+ // strides in each dimension, are represented in the view memref layout
1908
+ // map as symbols 's1', 's2' and 's3'.
1909
+ %1 = memref.subview %0[%i, %j, %k][%size0, %size1, %size2][%x, %y, %z]
1910
+ : memref<8x16x4xf32, affine_map<(d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)>> to
1911
+ memref<?x?x?xf32,
1912
+ affine_map<(d0, d1, d2)[s0, s1, s2, s3] -> (d0 * s1 + d1 * s2 + d2 * s3 + s0)>>
1916
1913
```
1917
1914
1918
1915
Example 3:
1919
1916
1920
1917
```mlir
1921
- // Subview of dynamic memref with strided layout at dynamic offsets and
1922
- // strides, but static sizes.
1923
- %1 = memref.subview %0[%off0, %off1][4, 4][%str0, %str1]
1924
- : memref<?x?xf32, strided<[?, ?], offset: ?>> to
1925
- memref<4x4xf32, strided<[?, ?], offset: ?>>
1918
+ %0 = memref.alloc() : memref<8x16x4xf32, affine_map<(d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)>>
1919
+
1920
+ // Subview with constant offsets, sizes and strides.
1921
+ %1 = memref.subview %0[0, 2, 0][4, 4, 4][1, 1, 1]
1922
+ : memref<8x16x4xf32, affine_map<(d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)>> to
1923
+ memref<4x4x4xf32, affine_map<(d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2 + 8)>>
1926
1924
```
1927
1925
1928
1926
Example 4:
1929
1927
1930
1928
```mlir
1931
- // Rank-reducing subviews.
1932
- %1 = memref.subview %0[0, 0, 0][1, 16, 4][1, 1, 1]
1933
- : memref<8x16x4xf32> to memref<16x4xf32>
1934
- %3 = memref.subview %2[3, 4, 2][1, 6, 3][1, 1, 1]
1935
- : memref<8x16x4xf32> to memref<6x3xf32, strided<[4, 1], offset: 210>>
1929
+ %0 = memref.alloc(%arg0, %arg1) : memref<?x?xf32>
1930
+
1931
+ // Subview with constant size, but dynamic offsets and
1932
+ // strides. The resulting memref has a static shape, but if the
1933
+ // base memref has an affine map to describe the layout, the result
1934
+ // memref also uses an affine map to describe the layout. The
1935
+ // strides of the result memref is computed as follows:
1936
+ //
1937
+ // Let #map1 represents the layout of the base memref, and #map2
1938
+ // represents the layout of the result memref. A #mapsubview can be
1939
+ // constructed to map an index from the result memref to the base
1940
+ // memref (note that the description below uses more convenient
1941
+ // naming for symbols, while in affine maps, symbols are
1942
+ // represented as unsigned numbers that identify that symbol in the
1943
+ // given affine map.
1944
+ //
1945
+ // #mapsubview = (d0, d1)[o0, o1, t0, t1] -> (d0 * t0 + o0, d1 * t1 + o1)
1946
+ //
1947
+ // where, o0, o1, ... are offsets, and t0, t1, ... are strides. Then,
1948
+ //
1949
+ // #map2 = #map1.compose(#mapsubview)
1950
+ //
1951
+ // If the layout map is represented as
1952
+ //
1953
+ // #map1 = (d0, d1)[s0, s1, s2] -> (d0 * s1 + d1 * s2 + s0)
1954
+ //
1955
+ // then,
1956
+ //
1957
+ // #map2 = (d0, d1)[s0, s1, s2, o0, o1, t0, t1] ->
1958
+ // (d0 * s1 * t0 + d1 * s2 * t1 + o0 * s1 + o1 * s2 + s0)
1959
+ //
1960
+ // Representing this canonically
1961
+ //
1962
+ // #map2 = (d0, d1)[r0, r1, r2] -> (d0 * r1 + d1 * r2 + r0)
1963
+ //
1964
+ // where, r0 = o0 * s1 + o1 * s2 + s0, r1 = s1 * t0, r2 = s2 * t1.
1965
+ %1 = memref.subview %0[%i, %j][4, 4][%x, %y] :
1966
+ : memref<?x?xf32, affine_map<(d0, d1)[s0, s1, s2] -> (d0 * s1 + d1 * s2 + s0)>> to
1967
+ memref<4x4xf32, affine_map<(d0, d1)[r0, r1, r2] -> (d0 * r1 + d1 * r2 + r0)>>
1968
+
1969
+ // Note that the subview op does not guarantee that the result
1970
+ // memref is "inbounds" w.r.t to base memref. It is upto the client
1971
+ // to ensure that the subview is accessed in a manner that is
1972
+ // in-bounds.
1936
1973
```
1937
1974
1938
1975
Example 5:
1939
1976
1940
1977
```mlir
1941
- // Identity subview. The subview is the full source memref.
1942
- %1 = memref.subview %0[0, 0, 0] [8, 16, 4] [1, 1, 1]
1943
- : memref<8x16x4xf32> to memref<8x16x4xf32>
1978
+ // Rank-reducing subview.
1979
+ %1 = memref.subview %0[0, 0, 0][1, 16, 4][1, 1, 1] :
1980
+ memref<8x16x4xf32> to memref<16x4xf32>
1981
+
1982
+ // Original layout:
1983
+ // (d0, d1, d2) -> (64 * d0 + 16 * d1 + d2)
1984
+ // Subviewed layout:
1985
+ // (d0, d1, d2) -> (64 * (d0 + 3) + 4 * (d1 + 4) + d2 + 2) = (64 * d0 + 4 * d1 + d2 + 210)
1986
+ // After rank reducing:
1987
+ // (d0, d1) -> (4 * d0 + d1 + 210)
1988
+ %3 = memref.subview %2[3, 4, 2][1, 6, 3][1, 1, 1] :
1989
+ memref<8x16x4xf32> to memref<6x3xf32, strided<[4, 1], offset: 210>>
1944
1990
```
1945
-
1946
1991
}];
1947
1992
1948
1993
let arguments = (ins AnyMemRef:$source,
0 commit comments