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