@@ -1816,314 +1816,6 @@ def Tensor_SplatOp : Tensor_Op<"splat", [
1816
1816
let hasVerifier = 1;
1817
1817
}
1818
1818
1819
- //===----------------------------------------------------------------------===//
1820
- // RelayoutOp
1821
- //===----------------------------------------------------------------------===//
1822
-
1823
- class Tensor_RelayoutOp<string mnemonic, list<Trait> traits = []> :
1824
- Tensor_Op<mnemonic, !listconcat(traits, [
1825
- DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>,
1826
- DestinationStyleOpInterface,
1827
- ConditionallySpeculatable, NoMemoryEffect,
1828
- DeclareOpInterfaceMethods<ReifyRankedShapedTypeOpInterface>,
1829
- TypesMatchWith<"result type matches type of dest",
1830
- "dest", "result",
1831
- "$_self">])> {
1832
-
1833
- code commonExtraClassDeclaration = [{
1834
- size_t getSourceRank() { return getSourceType().getRank(); };
1835
- size_t getDestRank() { return getDestType().getRank(); };
1836
- RankedTensorType getSourceType() {
1837
- return ::llvm::cast<RankedTensorType>(getSource().getType()); };
1838
- RankedTensorType getDestType() {
1839
- return ::llvm::cast<RankedTensorType>(getDest().getType()); };
1840
-
1841
- MutableOperandRange getDpsInitsMutable() { return getDestMutable(); }
1842
-
1843
- /// Interface method for ConditionallySpeculatable.
1844
- Speculation::Speculatability getSpeculatability();
1845
-
1846
- /// Return a mapping from positions `inner_dims_pos` to their
1847
- /// tile factors.
1848
- DenseMap<int64_t, OpFoldResult> getDimAndTileMapping();
1849
-
1850
- /// Return the tile sizes as OpFoldResult.
1851
- SmallVector<OpFoldResult> getMixedTiles();
1852
-
1853
- /// Return the tile sizes as `int64_t`. If a tile size is dynamic
1854
- /// a sentinel `kDynamic` is introduced at that position in
1855
- /// the returned vector.
1856
- SmallVector<int64_t> getStaticTiles();
1857
-
1858
- /// Retrieve all outer dims for this Pack/UnPack Op, i.e. all the leading
1859
- /// dims excluding the trailing dims corresponding to `innerTiles`. Note
1860
- /// that this will include both tiled and non-tiled dimensions. The order
1861
- /// of the output dimensions is consistent with the shape of the packed
1862
- /// tensor.
1863
- ArrayRef<int64_t> getAllOuterDims();
1864
-
1865
- /// Similar to `getAllOuterDims`, but only retrieve the outer dims that
1866
- /// have been tiled. Also, the order of the output dimensions is consistent
1867
- /// with `inner_dims_pos` rather than the packed tensor.
1868
- SmallVector<int64_t> getTiledOuterDims();
1869
- }];
1870
-
1871
- let hasVerifier = 1;
1872
- }
1873
-
1874
- //===----------------------------------------------------------------------===//
1875
- // PackOp
1876
- //===----------------------------------------------------------------------===//
1877
-
1878
- def Tensor_PackOp : Tensor_RelayoutOp<"pack", [
1879
- AttrSizedOperandSegments]> {
1880
- let summary = "tensor pack operation";
1881
- let description = [{
1882
- The "pack" operation converts a source tensor of rank `n` into a result
1883
- tensor of rank `n + k` with a tiled and packed layout (maybe with padding)
1884
- and optionally transposes the tiled source tensor dimensions.
1885
-
1886
- `inner_dims_pos` (mandatory) specifies `k` source tensor dimensions that are
1887
- being tiled, where `0 < k <= n`. The order of the dimensions matters:
1888
- - The tiled dimensions (of size `inner_tiles`) are added to the end of the result
1889
- tensor in the order in which they appear in `inner_dims_pos`.
1890
- - `inner_dims_pos[i]` specifies the source tensor dimension tiled by
1891
- `inner_tiles[i]`.
1892
-
1893
- `inner_tiles` (mandatory) specifies `k` tile sizes. These tile sizes
1894
- correspond to the least significant ("inner") result tensor dimension sizes,
1895
- in the same order. Tile sizes can be static or dynamic.
1896
-
1897
- Example: If `inner_tiles = [16, 32]`, the result tensor has a shape of
1898
- `...x16x32`. If `inner_dims_pos = [0, 1]`, the 0th source dimension is tiled
1899
- by 16 and the 1st source dimension is tiled by 32. Other source dimensions
1900
- (if any) are not tiled. If `inner_dims_pos = [1, 0]`, the 1st dimension is
1901
- tiled by 16 and the 0th dimension is tiled by 32.
1902
-
1903
- Example:
1904
- ```mlir
1905
- // NC to NCnc
1906
- %0 = tensor.pack %source inner_dims_pos = [0, 1] inner_tiles = [8, 32]
1907
- into %dest : tensor<128x256xf32> -> tensor<16x8 x 8x32 xf32>
1908
- // \ / \ /
1909
- // outer dims inner dims
1910
- ```
1911
-
1912
- `outer_dims_perm` (optional) specifies a permutation for the outer
1913
- dimensions. If specified, it must have `n` elements.
1914
-
1915
- Example:
1916
- ```mlir
1917
- // CK to KCck
1918
- %0 = tensor.pack %source outer_dims_perm = [1, 0] inner_dims_pos = [0, 1]
1919
- inner_tiles = [8, 32] into %dest
1920
- : tensor<128x256xf32> -> tensor<8x16 x 8x32 xf32>
1921
- // \ /
1922
- // compare with "NC to NCnc": outer dims are transposed
1923
- ```
1924
-
1925
- `padding_value` specifies a padding value at the boundary on non-perfectly
1926
- divisible dimensions. Padding is optional:
1927
- - If absent, it is UB if the tile does not perfectly divide the dimension.
1928
- - If present, it will pad along high dimensions (high-padding) to make the
1929
- tile complete.
1930
-
1931
- Example:
1932
- ```mlir
1933
- %0 = tensor.pack %arg0 padding_value(%pad : f32) outer_dims_perm = [2, 1, 0]
1934
- inner_dims_pos = [1] inner_tiles = [2] into %arg1
1935
- : tensor<200x127x256xf32> -> tensor<256x64x200x2xf32>
1936
- // \
1937
- // padded and tiled dim
1938
- //
1939
- // Source dimension 1 is tiled. 64 does not divide 127 evenly, so 1 padded
1940
- // element is added at the end.
1941
- //
1942
- // Note: Only tiled dimensions can be padded.
1943
- ```
1944
- }];
1945
- let arguments = (ins AnyRankedTensor:$source,
1946
- AnyRankedTensor:$dest,
1947
- Optional<AnyType>:$padding_value,
1948
- DefaultValuedOptionalAttr<DenseI64ArrayAttr, "{}">:$outer_dims_perm,
1949
- DenseI64ArrayAttr:$inner_dims_pos,
1950
- Variadic<Index>:$inner_tiles,
1951
- DenseI64ArrayAttr:$static_inner_tiles);
1952
- let results = (outs AnyRankedTensor:$result);
1953
- let assemblyFormat = [{
1954
- $source
1955
- (`padding_value` `(` $padding_value^ `:` type($padding_value) `)`)?
1956
- (`outer_dims_perm` `=` $outer_dims_perm^)?
1957
- `inner_dims_pos` `=` $inner_dims_pos
1958
- `inner_tiles` `=`
1959
- custom<DynamicIndexList>($inner_tiles, $static_inner_tiles)
1960
- `into` $dest attr-dict `:` type($source) `->` type($dest)
1961
- }];
1962
-
1963
- let builders = [
1964
- OpBuilder<(ins "Value":$source, "Value":$dest,
1965
- "ArrayRef<int64_t>":$innerDimsPos,
1966
- "ArrayRef<OpFoldResult>":$innerTiles,
1967
- CArg<"std::optional<Value>", "std::nullopt">:$paddingValue,
1968
- CArg<"ArrayRef<int64_t>", "{}">:$outerDimsPerm)>
1969
- ];
1970
-
1971
- let extraClassDeclaration = commonExtraClassDeclaration # [{
1972
- // Method to get the shape of the result as `SmallVector<OpFoldResult>`.
1973
- // This is a static method to allow getting the shape of the destination
1974
- // expected while creating a `pack` op.
1975
- static SmallVector<OpFoldResult> getResultShape(OpBuilder &builder,
1976
- Location loc, ArrayRef<OpFoldResult> sourceDims,
1977
- ArrayRef<OpFoldResult> innerTileDims, ArrayRef<int64_t> innerDimsPos,
1978
- ArrayRef<int64_t> outerDimsPerm = {});
1979
-
1980
- // Method to get the `RankedTensorType` of the result based on the inner
1981
- // tiles, position of the inner tiles (innerDimsPos) and interchange vector
1982
- // of outer loops (outerDimsPerm).
1983
- static RankedTensorType inferPackedType(RankedTensorType sourceType,
1984
- ArrayRef<int64_t> innerTileSizes, ArrayRef<int64_t> innerDimsPos,
1985
- ArrayRef<int64_t> outerDimsPerm = {});
1986
-
1987
- // Returns true if we have enough static information to catch undefined
1988
- // behavior when the tile size does not divide perfectly the dimension of
1989
- // the input tensor. Detecting UB requires that the input size and either
1990
- // corresponding tile or output size are static.
1991
- static bool requirePaddingValue(ArrayRef<int64_t> inputShape,
1992
- ArrayRef<int64_t> innerDimsPos,
1993
- ArrayRef<int64_t> outputShape,
1994
- ArrayRef<int64_t> outerDimsPerm,
1995
- ArrayRef<OpFoldResult> innerTiles);
1996
-
1997
- static Value createDestinationTensor(OpBuilder &b, Location loc,
1998
- Value source, ArrayRef<OpFoldResult> innerTileSizes,
1999
- ArrayRef<int64_t> innerDimsPos, ArrayRef<int64_t> outerDimsPerm);
2000
-
2001
- /// Build and return a new PackOp that is a clone of the current PackOp with
2002
- /// (innerDimsPos, innerTiles) (resp. outerDimsPerm) are permuted by
2003
- /// innerPermutation (resp. outerPermutation).
2004
- /// A new `tensor.empty` of the proper shape is built in the process.
2005
- /// Asserts that:
2006
- /// - At least one of innerPermutation or outerPermutation is non-empty.
2007
- /// - If not empty, innerPermutation is a valid permutation of size
2008
- /// matching innerDimPos.
2009
- /// - If not empty, outerPermutation is a valid permutation of size
2010
- /// matching outerDimsPerm.
2011
- PackOp createTransposedClone(OpBuilder &b,
2012
- Location loc,
2013
- ArrayRef<int64_t> innerPermutation,
2014
- ArrayRef<int64_t> outerPermutation);
2015
-
2016
- /// Check if this PackOp is like a simple pad operation.
2017
- /// In other words, this operation:
2018
- /// 1. adds useless dimensions (dimension of size 1),
2019
- /// 2. pads the other ones, and
2020
- /// 3. doesn't shuffle the dimensions
2021
- bool isLikePad();
2022
- }];
2023
-
2024
- let hasCanonicalizeMethod = 1;
2025
-
2026
- let hasFolder = 1;
2027
- }
2028
-
2029
- //===----------------------------------------------------------------------===//
2030
- // UnPackOp
2031
- //===----------------------------------------------------------------------===//
2032
-
2033
- def Tensor_UnPackOp : Tensor_RelayoutOp<"unpack"> {
2034
- let summary = "tensor unpack operation";
2035
- let description = [{
2036
- The "unpack" operation converts a source tensor of rank `n` with a tiled and
2037
- packed layout to a result tensor of rank `n - k`.
2038
-
2039
- `inner_dims_pos` (mandatory) specifies `k` source tensor dimensions with
2040
- which the last `k` source tensor dimensions are combined, where
2041
- `0 < k <= n/2`. Each `inner_dims_pos` element must be `>= 0` and `< n - k`.
2042
- The order of the dimensions in `inner_dims_pos` matters: dimension
2043
- `inner_dims_pos[i]` is combined with dimension `n - k + i` (assuming that
2044
- `outer_dims_perm` is not specified).
2045
-
2046
- `inner_tiles` (mandatory) specifies `k` tile sizes. These tile sizes
2047
- correspond to the least significant ("inner") source tensor dimension sizes.
2048
- The behavior of this op is undefined if:
2049
- - `inner_tiles` do not exactly match with the corresponding source tensor
2050
- dimension sizes.
2051
- - Or, `inner_tiles[i]` does not divide the size of dimension
2052
- `inner_dims_pos[i]` (assuming that `outer_dims_perm` is not specified)
2053
- evenly.
2054
-
2055
- `outer_dims_perm` (optional) specifies a permutation for the outer
2056
- dimensions. If specified, it must have `n - k` elements. If specified, this
2057
- permutation is applied before combining any dimensions.
2058
-
2059
- Example:
2060
-
2061
- ```mlir
2062
- // NCnc to NC:
2063
- %0 = tensor.unpack %source inner_dims_pos = [0, 1] inner_tiles = [8, 32]
2064
- into %dest : tensor<16x8x8x32xf32> -> tensor<128x256xf32>
2065
-
2066
- // CK to KCck:
2067
- %0 = tensor.unpack %source outer_dims_perm = [1, 0] inner_dims_pos = [0, 1]
2068
- inner_tiles = [8, 32] into %dest
2069
- : tensor<8x16x8x32xf32> -> tensor<128x256xf32>
2070
- ```
2071
- }];
2072
- let arguments = (ins AnyRankedTensor:$source,
2073
- AnyRankedTensor:$dest,
2074
- DefaultValuedOptionalAttr<DenseI64ArrayAttr, "{}">:$outer_dims_perm,
2075
- DenseI64ArrayAttr:$inner_dims_pos,
2076
- Variadic<Index>:$inner_tiles,
2077
- DenseI64ArrayAttr:$static_inner_tiles);
2078
- let results = (outs AnyRankedTensor:$result);
2079
- let assemblyFormat = [{
2080
- $source
2081
- (`outer_dims_perm` `=` $outer_dims_perm^)?
2082
- `inner_dims_pos` `=` $inner_dims_pos
2083
- `inner_tiles` `=`
2084
- custom<DynamicIndexList>($inner_tiles, $static_inner_tiles)
2085
- `into` $dest attr-dict `:` type($source) `->` type($dest)
2086
- }];
2087
-
2088
- let builders = [
2089
- OpBuilder<(ins "Value":$source, "Value":$dest,
2090
- "ArrayRef<int64_t>":$innerDimsPos,
2091
- "ArrayRef<OpFoldResult>":$innerTiles,
2092
- CArg<"ArrayRef<int64_t>", "{}">:$outerDimsPerm)>
2093
- ];
2094
-
2095
- let extraClassDeclaration = commonExtraClassDeclaration # [{
2096
- static Value createDestinationTensor(OpBuilder &b, Location loc,
2097
- Value source, ArrayRef<OpFoldResult> innerTileSizes,
2098
- ArrayRef<int64_t> innerDimsPos, ArrayRef<int64_t> outerDimsPerm);
2099
-
2100
- /// Build and return a new UnPackOp that is a clone of the current UnPackOp
2101
- /// with (innerDimsPos, innerTiles) (resp. outerDimsPerm) are permuted by
2102
- /// innerPermutation (resp. outerPermutation).
2103
- /// Asserts that:
2104
- /// - At least one of innerPermutation or outerPermutation is non-empty.
2105
- /// - If not empty, innerPermutation is a valid permutation of size
2106
- /// matching innerDimPos.
2107
- /// - If not empty, outerPermutation is a valid permutation of size
2108
- /// matching outerDimsPerm.
2109
- UnPackOp createTransposedClone(OpBuilder &b,
2110
- Location loc,
2111
- Value transposedSource,
2112
- ArrayRef<int64_t> innerPermutation,
2113
- ArrayRef<int64_t> outerPermutation);
2114
-
2115
- /// Check if this UnPackOp is like a simple unpad operation.
2116
- /// In other words, this operation:
2117
- /// 1. drops useless dimensions (dimension of size 1), and
2118
- /// 2. reduces dimensions in place (i.e., no transpose.)
2119
- bool isLikeUnPad();
2120
- }];
2121
-
2122
- let hasCanonicalizeMethod = 1;
2123
-
2124
- let hasFolder = 1;
2125
- }
2126
-
2127
1819
//===----------------------------------------------------------------------===//
2128
1820
// YieldOp
2129
1821
//===----------------------------------------------------------------------===//
0 commit comments