@@ -1816,314 +1816,6 @@ def Tensor_SplatOp : Tensor_Op<"splat", [
18161816 let hasVerifier = 1;
18171817}
18181818
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-
21271819//===----------------------------------------------------------------------===//
21281820// YieldOp
21291821//===----------------------------------------------------------------------===//
0 commit comments