@@ -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 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.
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.
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,118 +1876,73 @@ 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 has
1880- a dynamic value.
1879+ sentinel value ` ShapedType::kDynamic` encodes that the corresponding entry
1880+ has a dynamic value.
18811881
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.
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.
18841898
18851899 Example 1:
18861900
18871901 ```mlir
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)>>
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>>
18951907 ```
18961908
18971909 Example 2:
18981910
18991911 ```mlir
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,
1912+ // Subview of static memref with identity layout at dynamic offsets, sizes
19031913 // and strides.
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)>>
1914+ %1 = memref.subview %0[%off0, %off1][%sz0, %sz1][%str0, %str1]
1915+ : memref<64x4xf32> to memref<?x?xf32, strided<[?, ?], offset: ?>>
19131916 ```
19141917
19151918 Example 3:
19161919
19171920 ```mlir
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)>>
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: ?>>
19241926 ```
19251927
19261928 Example 4:
19271929
19281930 ```mlir
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.
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>>
19731936 ```
19741937
19751938 Example 5:
19761939
19771940 ```mlir
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>>
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>
19901944 ```
1945+
19911946 }];
19921947
19931948 let arguments = (ins AnyMemRef:$source,
0 commit comments