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