@@ -1859,11 +1859,11 @@ def SubViewOp : MemRef_OpWithOffsetSizesAndStrides<"subview", [
18591859 ]> {
18601860 let summary = "memref subview operation";
18611861 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.
18651865
1866- The `subview` operation supports the following arguments:
1866+ The SubView operation supports the following arguments:
18671867
18681868 * source: the "base" memref on which to create a "view" memref.
18691869 * offsets: memref-rank number of offsets into the "base" memref at which to
@@ -1876,73 +1876,118 @@ def SubViewOp : MemRef_OpWithOffsetSizesAndStrides<"subview", [
18761876 The representation based on offsets, sizes and strides support a
18771877 partially-static specification via attributes specified through the
18781878 `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.
18811881
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.
18981884
18991885 Example 1:
19001886
19011887 ```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)>>
19071895 ```
19081896
19091897 Example 2:
19101898
19111899 ```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,
19131903 // 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)>>
19161913 ```
19171914
19181915 Example 3:
19191916
19201917 ```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)>>
19261924 ```
19271925
19281926 Example 4:
19291927
19301928 ```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.
19361973 ```
19371974
19381975 Example 5:
19391976
19401977 ```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>>
19441990 ```
1945-
19461991 }];
19471992
19481993 let arguments = (ins AnyMemRef:$source,
0 commit comments