xref: /llvm-project/mlir/include/mlir/Dialect/Linalg/Passes.td (revision 3efac5c68ac3117e8488a7fa247e45951e52936f)
1//===-- Passes.td - Linalg pass definition file ------------*- tablegen -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef MLIR_DIALECT_LINALG_PASSES
10#define MLIR_DIALECT_LINALG_PASSES
11
12include "mlir/Pass/PassBase.td"
13
14def ConvertElementwiseToLinalgPass : Pass<"convert-elementwise-to-linalg", ""> {
15  let summary = "Convert ElementwiseMappable ops to linalg";
16  let description = [{
17    Convert ops with the `ElementwiseMappable` trait to linalg parallel loops.
18
19    This pass only converts ops that operate on ranked tensors. It can be
20    run on op which contains linalg ops (most commonly a
21    FunctionOpInterface op).
22  }];
23  let dependentDialects = ["linalg::LinalgDialect", "memref::MemRefDialect"];
24}
25
26def ConvertLinalgToAffineLoopsPass : Pass<"convert-linalg-to-affine-loops"> {
27  let summary = "Lower the operations from the linalg dialect into affine "
28                "loops";
29  let dependentDialects = [
30    "affine::AffineDialect", "linalg::LinalgDialect", "memref::MemRefDialect"];
31}
32
33def ConvertLinalgToLoopsPass : Pass<"convert-linalg-to-loops"> {
34  let summary = "Lower the operations from the linalg dialect into loops";
35  let description = [{
36    Lowers the `linalg` ops to loop nests using `scf.for`.
37
38    Pre-condition: the operands used by the `linalg` ops have buffer semantics,
39    i.e., tensor operands and results must be converted to memrefs via
40    bufferization.
41  }];
42  let dependentDialects = [
43    "linalg::LinalgDialect",
44    "scf::SCFDialect",
45    "affine::AffineDialect"
46  ];
47}
48
49def ConvertLinalgToParallelLoopsPass
50    : Pass<"convert-linalg-to-parallel-loops"> {
51  let summary = "Lower the operations from the linalg dialect into parallel "
52                "loops";
53  let dependentDialects = [
54    "affine::AffineDialect",
55    "linalg::LinalgDialect",
56    "memref::MemRefDialect",
57    "scf::SCFDialect"
58  ];
59}
60
61def LinalgFoldUnitExtentDimsPass : Pass<"linalg-fold-unit-extent-dims", ""> {
62  let summary = "Remove unit-extent dimension in Linalg ops on tensors";
63  let options = [
64    Option<"useRankReducingSlices", "use-rank-reducing-slices", "bool",
65           /*default=*/"false",
66           "Generate rank-reducing slices instead of reassociative reshapes">
67  ];
68  let dependentDialects = [
69    "linalg::LinalgDialect", "affine::AffineDialect", "memref::MemRefDialect"
70  ];
71}
72
73def LinalgElementwiseOpFusionPass : Pass<"linalg-fuse-elementwise-ops"> {
74  let summary = "Fuse elementwise operations on tensors";
75  let dependentDialects = [
76    "affine::AffineDialect", "linalg::LinalgDialect", "memref::MemRefDialect"
77  ];
78}
79
80def LinalgNamedOpConversionPass: Pass<"linalg-named-op-conversion"> {
81  let summary = "Convert from one named linalg op to another.";
82  let dependentDialects = ["linalg::LinalgDialect", "tensor::TensorDialect"];
83}
84
85def LinalgInlineScalarOperandsPass : Pass<"linalg-inline-scalar-operands"> {
86  let summary = "Inline scalar operands into linalg generic ops";
87  let dependentDialects = [
88    "linalg::LinalgDialect"
89  ];
90}
91
92def LinalgGeneralizeNamedOpsPass : Pass<"linalg-generalize-named-ops"> {
93  let summary = "Convert named ops into generic ops";
94  let dependentDialects = ["linalg::LinalgDialect"];
95}
96
97def LinalgSpecializeGenericOpsPass : Pass<"linalg-specialize-generic-ops"> {
98  let summary = "Convert generic ops back to named ops";
99  let dependentDialects = ["linalg::LinalgDialect"];
100}
101
102def LinalgDetensorizePass : InterfacePass<"linalg-detensorize", "FunctionOpInterface"> {
103  let summary = "Detensorize linalg ops";
104  let dependentDialects = [];
105
106  let description = [{
107    Detensoring is the process through which a tensor value is converted to one
108    or potentially more primitive value(s). During this process, operations with
109    such detensored operands are also converted to an equivalent form that works
110    on primitives.
111
112    The detensoring process is driven by linalg-on-tensor ops. In particular, a
113    linalg-on-tensor op is checked to see whether *all* its operands can be
114    detensored. If so, those operands are converted to their primitive
115    counterparts and the linalg op is replaced by an equivalent op that takes
116    those new primitive values as operands. Therefore, detensoring an op can be
117    divided into 2 main logical phases:
118
119    1. Detect/match an op that can be detensored.
120    2. Detensor the operands of the op and replace it with a primitive
121       equivalent.
122
123    In addition to detensoring individual ops, this pass detensors internal
124    control flow inside a function. All blocks except for the entry block are
125    detensored by converting their arguments whenever possible.
126
127    This can be run on any FunctionOpInterface op and must not be
128    run on others. This is because it performs specific legalization of the
129    blocks that make up the body, which it assumes has is a FunctionOpInterface.
130  }];
131  let options = [
132    Option<"aggressiveMode", "aggressive-mode", "bool", /*default=*/"false",
133           "Detensorize all ops that qualify for detensoring along with branch"
134           " operands and basic-block arguments.">
135
136  ];
137}
138
139def LinalgBlockPackMatmul : Pass<"linalg-block-pack-matmul"> {
140  let summary = "Convert linalg matmul ops to block layout and back";
141  let description = [{
142    Pack a matmul operation into blocked layout with two levels of subdivision:
143    - major 2D blocks - outer dimensions, consist of minor blocks
144    - minor 2D blocks - inner dimensions, consist of scalar elements
145
146    A 2D matmul MxNxK gets reshaped into blocked 4D representation
147    as: [MB][NB][mb][nb] += [MB][KB][mb][kb] * [NB][KB][nb][kb]
148    where the (MB, NB, KB) dimensions represent the major blocks,
149    and the (mb, nb, kb) are the minor blocks of their respective
150    original 2D dimensions (M, N, K).
151
152    Depending on the initial operands' data layout and the specified
153    packing options, the major blocks dimensions might get transposed
154    e.g., [MB][KB] -> [KB][MB]. The minor blocks can also be transposed
155    e.g., [mb][kb] -> [kb][mb].
156    Any present batch dimensions remain unchanged.
157    The final result is unpacked back to the original shape.
158
159    For example, given a matmul operation:
160    ```mlir
161      %res = linalg.matmul ins(%A, %B) outs(%C)
162    ```
163    the default transformation result can be represented as:
164    ```mlir
165      %A_packed = pack %A : 2D <MxK> -> 4D <MBxKBxmbxkb>
166      %B_packed = pack %B : 2D <KxN> -> 4D <NBxKBxnbxkb>
167      %C_packed = pack %C : 2D <MxN> -> 4D <MBxNBxmbxnb>
168      %res_packed = linalg.mmt4d ins(%A_packed, %B_packed) outs(%C_packed)
169      %res = unpack %res_packed : 4D <MBxNBxmbxnb> -> 2D <MxN>
170    ```
171  }];
172  let dependentDialects = ["linalg::LinalgDialect", "tensor::TensorDialect"];
173  let options = [
174    ListOption<"blockFactors", "block-factors", "int64_t",
175               "Block factors (mb, nb, kb) for relayout">,
176    Option<"allowPadding", "allow-padding", "bool",
177           /*default=*/"true",
178           "Allow packing padding">,
179    ListOption<"mnkPaddedSizesNextMultipleOf", "mnk-padded-multiples", "int64_t",
180               "Next multiples of the packing sizes">,
181    ListOption<"mnkOrder", "mnk-order", "int64_t",
182               "Permutation of matmul (M, N, K) dimensions order">,
183    Option<"lhsTransposeOuterBlocks", "lhs-transpose-outer-blocks", "bool",
184           /*default=*/"false",
185           "Transpose LHS outer block layout [MB][KB] -> [KB][MB]">,
186    Option<"lhsTransposeInnerBlocks", "lhs-transpose-inner-blocks", "bool",
187           /*default=*/"false",
188           "Transpose LHS inner block layout [mb][kb] -> [kb][mb]">,
189    Option<"rhsTransposeOuterBlocks", "rhs-transpose-outer-blocks", "bool",
190           /*default=*/"true",
191           "Transpose RHS outer block layout [KB][NB] -> [NB][KB]">,
192    Option<"rhsTransposeInnerBlocks", "rhs-transpose-inner-blocks", "bool",
193           /*default=*/"true",
194           "Transpose RHS inner block layout [kb][nb] -> [nb][kb]">
195  ];
196}
197
198#endif // MLIR_DIALECT_LINALG_PASSES
199