1//===- TransformOps.td - Transform dialect operations ------*- 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_TRANSFORM_IR_TRANSFORMOPS 10#define MLIR_DIALECT_TRANSFORM_IR_TRANSFORMOPS 11 12include "mlir/Interfaces/ControlFlowInterfaces.td" 13include "mlir/IR/OpAsmInterface.td" 14include "mlir/IR/SymbolInterfaces.td" 15include "mlir/Dialect/PDL/IR/PDLTypes.td" 16include "mlir/Dialect/Transform/IR/TransformDialect.td" 17include "mlir/Dialect/Transform/IR/TransformEffects.td" 18include "mlir/Dialect/Transform/IR/TransformInterfaces.td" 19 20def AlternativesOp : TransformDialectOp<"alternatives", 21 [DeclareOpInterfaceMethods<RegionBranchOpInterface, 22 ["getSuccessorEntryOperands", "getSuccessorRegions", 23 "getRegionInvocationBounds"]>, 24 DeclareOpInterfaceMethods<TransformOpInterface>, 25 FunctionalStyleTransformOpTrait, MemoryEffectsOpInterface, 26 IsolatedFromAbove, PossibleTopLevelTransformOpTrait, 27 SingleBlockImplicitTerminator<"::mlir::transform::YieldOp">]> { 28 let summary = "Attempts sequences of transforms until one succeeds"; 29 let description = [{ 30 This op may have an arbitrary number of regions, each of which represents a 31 sequence of transform operations to be applied to the same payload IR. The 32 regions are visited in order of appearance, and transforms in them are 33 applied in their respective order of appearance. If one of these transforms 34 fails to apply, the remaining ops in the same region are skipped an the next 35 region is attempted. If all transformations in a region succeed, the 36 remaining regions are skipped and the entire "alternatives" transformation 37 succeeds. If all regions contained a failing transformation, the entire 38 "alternatives" transformation fails. 39 40 It is up to the nested operations to define which errors are "recoverable" 41 (or "silenceable") and allow another alternatives to be attempted, and which 42 errors should be propagated without attempting the other alternatives. 43 44 The single operand of this operation is the scope in which the alternative 45 transformation sequences are attempted, that is, an operation in the payload 46 IR that contains all the other operations that may be modified by the 47 transformations. The scope operation must be isolated from above. There is 48 no check that the transforms are indeed scoped as their "apply" methods can 49 be arbitrarily complex. Therefore it is the responsibility of the user to 50 ensure that the transforms are scoped correctly, or to produce an 51 irrecoverable error and thus abort the execution without attempting the 52 remaining alternatives. Note that the payload IR outside of the given scope 53 is not necessarily in the valid state, or even accessible to the 54 transformation. 55 56 The changes to the IR within the scope performed by transforms in the failed 57 alternative region are reverted before attempting the next region. 58 Practically, this is achieved by cloning the scope. Therefore it is advised 59 to limit the scope as much as possible and place the most likely 60 alternatives early in the region list. The operation is also isolated from 61 above and requires rediscovering the operations within the given scope to 62 avoid additional handle invalidation. The latter restriction may be lifted 63 in the future. 64 65 Each of the regions may yield transform IR handles. The handles of the first 66 successful alternative region are returned as the results of the 67 "alternatives" op. Therefore, each alternative region must yield the same 68 number of results, which should also match the number and the types of the 69 "alternatives" op results. 70 71 Remark: this op allows one to implement a simple "try" construct as follows: 72 73 ```mlir 74 %result = transform.alternatives %scope { 75 ^bb0(%arg0: !pdl.operation): 76 // Try a fallible transformation. 77 %0 = transform.fallible %arg0 // ... 78 // If succeeded, yield the the result of the transformation. 79 transform.yield %0 : !pdl.operation 80 }, { 81 ^bb0(%arg0: !pdl.operation): 82 // Otherwise, the second alternative is tried and it always succeeds by 83 // returning the original handle. 84 transform.yield %arg0 : !pdl.operation 85 } 86 ``` 87 }]; 88 89 let arguments = (ins Optional<PDL_Operation>:$scope); 90 let results = (outs Variadic<AnyType>:$results); 91 let regions = (region VariadicRegion<SizedRegion<1>>:$alternatives); 92 93 let assemblyFormat = 94 "($scope^)? (`->` type($results)^)? attr-dict-with-keyword regions"; 95 let hasVerifier = 1; 96} 97 98def ForeachOp : TransformDialectOp<"foreach", 99 [DeclareOpInterfaceMethods<TransformOpInterface>, 100 DeclareOpInterfaceMethods<MemoryEffectsOpInterface>, 101 DeclareOpInterfaceMethods<RegionBranchOpInterface, [ 102 "getSuccessorRegions", "getSuccessorEntryOperands"]>, 103 SingleBlockImplicitTerminator<"::mlir::transform::YieldOp"> 104 ]> { 105 let summary = "Executes the body for each payload op"; 106 let description = [{ 107 This op has exactly one region with exactly one block ("body"). The body is 108 executed for each payload op that is associated to the target operand in an 109 unbatched fashion. I.e., the block argument ("iteration variable") is always 110 mapped to exactly one payload op. 111 112 This op always reads the target handle. Furthermore, it consumes the handle 113 if there is a transform op in the body that consumes the iteration variable. 114 This op does not return anything. 115 116 The transformations inside the body are applied in order of their 117 appearance. During application, if any transformation in the sequence fails, 118 the entire sequence fails immediately leaving the payload IR in potentially 119 invalid state, i.e., this operation offers no transformation rollback 120 capabilities. 121 }]; 122 123 let arguments = (ins PDL_Operation:$target); 124 let results = (outs); 125 let regions = (region SizedRegion<1>:$body); 126 let assemblyFormat = "$target $body attr-dict"; 127 128 let extraClassDeclaration = [{ 129 /// Allow the dialect prefix to be omitted. 130 static StringRef getDefaultDialect() { return "transform"; } 131 132 BlockArgument getIterationVariable() { 133 return getBody().front().getArgument(0); 134 } 135 }]; 136} 137 138def GetClosestIsolatedParentOp : TransformDialectOp<"get_closest_isolated_parent", 139 [DeclareOpInterfaceMethods<TransformOpInterface>, 140 NavigationTransformOpTrait, MemoryEffectsOpInterface]> { 141 let summary = "Gets handles to the closest isolated-from-above parents"; 142 let description = [{ 143 The handles defined by this Transform op correspond to the closest isolated 144 from above ancestor of the Payload IR operations associated with its 145 operand. If any of the given Payload IR ops has no such parent (unlikely as 146 there usually is a top-level ModuleOp), the transformation is considered to 147 have failed. 148 149 Ancestor ops follow the same order as the ops associated with the 150 operand, except for potential duplicates (multiple Payload IR ops associated 151 with the operand have the same parent) for which the ancestor will only be 152 listed once for the first time it occurs. For example, given the list 153 "(childof(A), childof(B), childof(B), childof(A), childof(B))", the 154 resulting list will be just "(A, B)". Note that no other semantic ordering 155 is applied, e.g., "B" may itself be a parent of "A". This may have an impact 156 on the further transformation applied to the handle produced here. 157 }]; 158 159 let arguments = (ins PDL_Operation:$target); 160 let results = (outs PDL_Operation:$parent); 161 let assemblyFormat = "$target attr-dict"; 162} 163 164def MergeHandlesOp : TransformDialectOp<"merge_handles", 165 [DeclareOpInterfaceMethods<TransformOpInterface>, 166 DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> { 167 let summary = "Merges handles into one pointing to the union of payload ops"; 168 let description = [{ 169 Creates a new Transform IR handle value that points to the same Payload IR 170 operations as the operand handles. The Payload IR operations are listed 171 in the same order as they are in the operand handles, grouped by operand 172 handle, e.g., all Payload IR operations associated with the first handle 173 come first, then all Payload IR operations associated with the second handle 174 and so on. If `deduplicate` is set, do not add the given Payload IR 175 operation more than once to the final list regardless of it coming from the 176 same or different handles. Consumes the operands and produces a new handle. 177 }]; 178 179 let arguments = (ins Variadic<PDL_Operation>:$handles, 180 UnitAttr:$deduplicate); 181 let results = (outs PDL_Operation:$result); 182 let assemblyFormat = "($deduplicate^)? $handles attr-dict"; 183 let hasFolder = 1; 184} 185 186def PDLMatchOp : TransformDialectOp<"pdl_match", 187 [DeclareOpInterfaceMethods<TransformOpInterface>]> { 188 let summary = "Finds ops that match the named PDL pattern"; 189 let description = [{ 190 Find Payload IR ops nested within the Payload IR op associated with the 191 operand that match the PDL pattern identified by its name. The pattern is 192 expected to be defined in the closest surrounding `WithPDLPatternsOp`. 193 194 Produces a Transform IR value associated with the list of Payload IR ops 195 that matched the pattern. The order of results in the list is that of the 196 Operation::walk, clients are advised not to rely on a specific order though. 197 If the operand is associated with multiple Payload IR ops, finds matching 198 ops nested within each of those and produces a single list containing all 199 of the matched ops. 200 201 The transformation is considered successful regardless of whether some 202 Payload IR ops actually matched the pattern and only fails if the pattern 203 could not be looked up or compiled. 204 }]; 205 206 let arguments = (ins 207 Arg<PDL_Operation, "Payload IR scope to match within", 208 [TransformMappingRead, PayloadIRRead]>:$root, 209 SymbolRefAttr:$pattern_name); 210 let results = (outs 211 Res<PDL_Operation, "Handle to the matched Payload IR ops", 212 [TransformMappingAlloc, TransformMappingWrite]>:$matched); 213 214 let assemblyFormat = "$pattern_name `in` $root attr-dict"; 215} 216 217def ReplicateOp : TransformDialectOp<"replicate", 218 [DeclareOpInterfaceMethods<TransformOpInterface>, 219 DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> { 220 let summary = "Lists payload ops multiple times in the new handle"; 221 let description = [{ 222 Produces a new handle associated with a list of payload IR ops that is 223 computed by repeating the list of payload IR ops associated with the 224 operand handle as many times as the "pattern" handle has associated 225 operations. For example, if pattern is associated with [op1, op2] and the 226 operand handle is associated with [op3, op4, op5], the resulting handle 227 will be associated with [op3, op4, op5, op3, op4, op5]. 228 229 This transformation is useful to "align" the sizes of payload IR lists 230 before a transformation that expects, e.g., identically-sized lists. For 231 example, a transformation may be parameterized by same notional per-target 232 size computed at runtime and supplied as another handle, the replication 233 allows this size to be computed only once and used for every target instead 234 of replicating the computation itself. 235 236 Note that it is undesirable to pass a handle with duplicate operations to 237 an operation that consumes the handle. Handle consumption often indicates 238 that the associated payload IR ops are destroyed, so having the same op 239 listed more than once will lead to double-free. Single-operand 240 MergeHandlesOp may be used to deduplicate the associated list of payload IR 241 ops when necessary. Furthermore, a combination of ReplicateOp and 242 MergeHandlesOp can be used to construct arbitrary lists with repetitions. 243 }]; 244 245 let arguments = (ins PDL_Operation:$pattern, 246 Variadic<PDL_Operation>:$handles); 247 let results = (outs Variadic<PDL_Operation>:$replicated); 248 let assemblyFormat = 249 "`num` `(` $pattern `)` $handles " 250 "custom<PDLOpTypedResults>(type($replicated), ref($handles)) attr-dict"; 251} 252 253def SequenceOp : TransformDialectOp<"sequence", 254 [DeclareOpInterfaceMethods<RegionBranchOpInterface, 255 ["getSuccessorEntryOperands", "getSuccessorRegions", 256 "getRegionInvocationBounds"]>, 257 DeclareOpInterfaceMethods<TransformOpInterface>, 258 DeclareOpInterfaceMethods<MemoryEffectsOpInterface>, 259 OpAsmOpInterface, PossibleTopLevelTransformOpTrait, 260 SingleBlockImplicitTerminator<"::mlir::transform::YieldOp">]> { 261 let summary = "Contains a sequence of other transform ops to apply"; 262 let description = [{ 263 The transformations indicated by the sequence are applied in order of their 264 appearance. Each value produced by a transformation within the sequence 265 corresponds to an operation or a group of operations in the payload IR. 266 During application, if any transformation in the sequence fails, the entire 267 sequence fails immediately leaving the payload IR in potentially invalid 268 state, i.e., this operation offers no transformation rollback capabilities. 269 270 The entry block of this operation has a single argument that maps to either 271 the operand if provided or the top-level container operation of the payload 272 IR, typically the root operation of the pass interpreting the transform 273 dialect. Operand omission is only allowed for sequences not contained in 274 another sequence. 275 }]; 276 277 let arguments = (ins Optional<PDL_Operation>:$root); 278 let results = (outs Variadic<AnyType>:$results); 279 let regions = (region SizedRegion<1>:$body); 280 281 let assemblyFormat = 282 "($root^)? attr-dict-with-keyword regions (`:` type($results)^)?"; 283 284 let extraClassDeclaration = [{ 285 /// Allow the dialect prefix to be omitted. 286 static StringRef getDefaultDialect() { return "transform"; } 287 }]; 288 289 let hasVerifier = 1; 290} 291 292def WithPDLPatternsOp : TransformDialectOp<"with_pdl_patterns", 293 [DeclareOpInterfaceMethods<TransformOpInterface>, NoTerminator, 294 OpAsmOpInterface, PossibleTopLevelTransformOpTrait, RecursiveSideEffects, 295 SymbolTable]> { 296 let summary = "Contains PDL patterns available for use in transforms"; 297 let description = [{ 298 This op contains a set of named PDL patterns that are available for the 299 Transform dialect operations to be used for pattern matching. For example, 300 PDLMatchOp can be used to produce a Transform IR value associated with all 301 Payload IR operations that match the pattern as follows: 302 303 ```mlir 304 transform.with_pdl_patterns { 305 ^bb0(%arg0: !pdl.operation): 306 pdl.pattern @my_pattern : benefit(1) { 307 %0 = pdl.operation //... 308 // Regular PDL goes here. 309 pdl.rewrite %0 with "transform.dialect" 310 } 311 312 sequence %arg0 { 313 ^bb0(%arg1: !pdl.operation): 314 %1 = pdl_match @my_pattern in %arg1 315 // Use %1 as handle 316 } 317 } 318 ``` 319 320 Note that the pattern is expected to finish with a `pdl.rewrite` terminator 321 that points to the custom rewriter named "transform.dialect". The rewriter 322 actually does nothing, but the transform application will keep track of the 323 operations that matched the pattern. 324 325 This op is expected to contain `pdl.pattern` operations and exactly one 326 another Transform dialect operation that gets executed with all patterns 327 available. This op is a possible top-level Transform IR op, the argument of 328 its entry block corresponds to either the root op of the payload IR or the 329 ops associated with its operand when provided. 330 }]; 331 332 let arguments = (ins 333 Arg<Optional<PDL_Operation>, "Root operation of the Payload IR", 334 [TransformMappingRead]>:$root); 335 let regions = (region SizedRegion<1>:$body); 336 let assemblyFormat = "($root^)? attr-dict-with-keyword regions"; 337 338 let hasVerifier = 1; 339 340 let extraClassDeclaration = [{ 341 /// Allow the dialect prefix to be omitted. 342 static StringRef getDefaultDialect() { return "transform"; } 343 }]; 344} 345 346def YieldOp : TransformDialectOp<"yield", [Terminator]> { 347 let summary = "Yields operation handles from a transform IR region"; 348 let description = [{ 349 This terminator operation yields operation handles from regions of the 350 transform IR ops back to the containing op. It is not itself associated with 351 any transformation on the payload IR and is used for flow purposes only. 352 }]; 353 354 let arguments = (ins 355 Arg<Variadic<AnyType>, "Operation handles yielded back to the parent", 356 [TransformMappingRead]>:$operands); 357 let assemblyFormat = "operands attr-dict (`:` type($operands)^)?"; 358 359 let builders = [ 360 OpBuilder<(ins), [{ 361 return build($_builder, $_state, ::mlir::ValueRange()); 362 }]> 363 ]; 364} 365 366#endif // MLIR_DIALECT_TRANSFORM_IR_TRANSFORMOPS 367