1# Transform Dialect 2 3Fine-grain transformation control dialect. See [tutorial](../Tutorials/transform) for more introductory information. 4 5[TOC] 6 7## Overview 8 9This dialect provides operations that can be used to control transformation 10of the IR using a different portion of the IR. It refers to the IR being 11transformed as payload IR, and to the IR guiding the transformation as 12transform IR. 13 14The main use case for this dialect is orchestrating fine-grain transformations 15on individual IR objects (operations or values) or sets thereof. For example, it 16may involve finding loop-like operations with specific properties (e.g., large 17size) in the payload IR, applying loop tiling to those and only those 18operations, and then applying loop unrolling to the inner loops produced by the 19previous transformations. As such, it is not intended as a replacement for the 20pass infrastructure, nor for the pattern rewriting infrastructure. In the most 21common case, the transform IR will be processed and applied to the payload IR by 22a pass. Transformations expressed by the Transform dialect may be implemented 23using the pattern infrastructure or any other relevant MLIR component. 24 25The following IR gives a rough idea of what the operations in this dialect 26may look like without using actually existing operations: 27 28```mlir 29%0 = transform.loop.find { size > 42 } : !transform.interface<tileable> 30%1 = transform.compute_trailing_tile_size %0 : !transform.param<index> 31%2:2 = transform.loop.tile %0 tile_sizes(1, 4, %1) 32 : (!transform.interface<tileable>) 33 -> (!transform.op<loop>, !transform.op<loop>) 34%3 = transform.get_op_result [0] %2#0 : !transform.any_value 35transform.assign_to_fast_memory %3 36transform.loop.unroll %1#1 : !transform.op<loop> 37``` 38 39The values used in the Transform dialect may correspond to: 40 41 * sets of operations in the payload IR; 42 43 * sets of values in the payload IR; 44 45 * sets of parameters (attributes) known at the execution time of the 46 transform dialect. 47 48The former two kinds of values are also referred to as operation and value 49*handles*, respectively. In the example above, `%0` corresponds to the set of 50loops found in the payload IR that satisfy the condition, and `%2` correspond to 51groups of outer and inner loops, respectively, produced by the tiling 52transformation. `%3` corresponds to a set of values that are produced by the 53outer loops after tiling. `%1` corresponds to a list of tile sizes selected for 54each of the operations that `%0` corresponds to. 55 56An operation handle such as `%0` may be associated with multiple payload 57operations. This is conceptually a set of operations and no assumptions should 58be made about the order of ops unless specified otherwise by the operation. 59Similarly, a value handle such as `%3` may be associated with a set of payload 60IR values. Transform dialect operations may take as operands and produce an 61arbitrary combination of values representing handles and parameters. Most 62Transform IR ops support operand values that are mapped to multiple payload 63objects. They usually apply the respective transformation for every mapped 64object ("batched execution"). Deviations from this convention are described in 65the documentation of Transform IR ops. 66 67Parameters, such as `%1` in the above example, have two logical roles in 68transform IR. In parameter based control, they carry the values needed to 69execute the explicit control defined by the transforms, for example: 70 71```mlir 72%0 = transform.match.structured.rank %linalg_op_handle : !transform.param<index> 73%1 = transform.param.constant 3 : i32 -> !transform.param<index> 74transform.execute_if_cmpi eq %0, %1 : !transform.param<index>, !transform.param<index> 75// Some nested body of transform ops 76``` 77 78Alternatively, parameters can associate with the payload IR where the specific 79value at execution time has no bearing on the execution of the transform IR. In 80other words, parameters can either associate with the transform IR or the 81payload IR. Note that it is generally discouraged to use parameters containing 82arbitrary attributes within transform control. Parameter based control should 83try to be explicitly typed when possible. 84 85The transform IR values have transform IR types, which should implement exactly one of: 86 87 * [TransformHandleTypeInterface](#transformhandletypeinterface-transformhandletypeinterface), 88 89 * [TransformValueHandleTypeInterface](#transformvaluehandletypeinterface-transformvaluehandletypeinterface), 90 91 * [TransformParamTypeInterface](#transformparamtypeinterface-transformparamtypeinterface). 92 93The goal of these type interfaces, beyond providing a common base for accepted 94types, is to verify the properties of the associated objects. For example, a 95handle type interface implementation may check whether all associated payload IR 96operations implement the "TileableOp" interface or have a specific "loop" kind. 97Similarly, a value handle type interface implementation may check if the 98associated payload IR values are block arguments or have a specific type, or a 99parameter type interface may check whether the associated attributes contain 100non-negative integer values. These properties are used to statically indicate 101 pre- and post-conditions of a transformation connected to a Transform dialect 102operation. The conditions are verified when payload objects operations are first 103associated with a transform handle. By convention, Transform dialect operations 104are expected to indicate narrow preconditions for their operands by enforcing 105operand type constraints in the their definitions and verifiers. On the 106contrary, operations are expected to have few constraints on their results. 107Specific instances of a transform operation can then be created with a more 108restricted result type than the constraint in the operation (e.g., the "find" 109operation only constrains the result type to be a transform IR type while its 110concrete instance can have a type with stricter constraints such as implementing 111the "tilable" interface). The verification will then happen at transform 112execution time. This approach allows one to capture payload IR operation 113properties in the transform IR without resorting to excessive use of type casts 114or coupling dialect extensions between themselves. It is a trade-off between 115verbosity/complexity and static hardening, which can be revised in the future. 116 117Overall, Transform IR ops are expected to be contained in a single top-level 118op. Such top-level ops specify how to apply the transformations described 119by the operations they contain, e.g., `transform.sequence` executes 120transformations one by one and fails if any of them fails. Such ops are 121expected to have the `PossibleTopLevelTransformOpTrait` and may be used 122without arguments. 123 124A program transformation expressed using the Transform dialect can be 125programmatically triggered by calling: 126 127```c++ 128LogicalResult transform::applyTransforms( 129 Operation *payloadRoot, 130 const RaggedArray<transform::MappedValue> &extraMappings, 131 TransformOpInterface transform, 132 const TransformOptions &options); 133``` 134 135that applies the transformations specified by the top-level `transform` to 136payload IR contained in `payloadRoot`. The payload root operation will be 137associated with the first argument of the entry block of the top-level transform 138op. This block may have additional arguments, handles or parameters. They will 139be associated with values provided as `extraMappings`. The call will report an 140error and return if the wrong number of mappings is provided. 141 142## Dialect Extension Mechanism 143 144This dialect is designed to be extensible, that is, clients of this dialect 145are allowed to inject additional operations into this dialect using the 146`TransformDialectExtension` mechanism. This allows the dialect to avoid a 147dependency on the implementation of the transformation as well as to avoid 148introducing dialect-specific transform dialects. In the example above, 149the operations may have been injected by a notional `loop` dialect rather 150than defined in this dialect, hence the common prefix. 151 152It is recommended to prefix injected operations with one or several 153dot-separated words that indicate which extension adds them. For 154dialect-specific transformations, the prefix is naturally the name of the 155dialect, e.g., `transform.affine.reschedule`. For dialect-agnostic 156transformations (typically implemented using interfaces), the prefix may 157be derived from the interface name or from a common concept, e.g., 158`transform.loop.tile` may apply to any loop-like operation that implements 159`TileableOpInterface`. The C++ classes for the dialect extension should 160include the prefix in their name, e.g., `AffineTransformDialectExtension` or 161`LoopTransformDialectExtension` in the cases above. Unprefixed operation 162names are reserved for ops defined directly in the Transform dialect. 163 164Operations injected into the dialect must: 165 166 * Implement the `TransformOpInterface` to execute the corresponding 167 transformation on the payload IR. 168 169 * Implement the `MemoryEffectsOpInterface` to annotate the effects of 170 the transform IR operation on the payload IR as well as on the mapping 171 between transform IR values and payload IR operations. See below for 172 the description of available effects. 173 174The presence of interface implementations is checked at runtime when the 175dialect is loaded to allow for those implementations to be supplied by 176separate dialect extensions if desired. 177 178Similarly to operations, additional types can be injected into the dialect using 179the same extension mechanism. The types must: 180 181 * Implement exactly one of `TransformHandleTypeInterface`, 182 `TransformValueHandleTypeInterface`, `TransformParamTypeInterface`. 183 184## Side Effects 185 186The Transform dialect relies on MLIR side effect modelling to enable 187optimization of the transform IR. More specifically, it provides several 188side effect resource objects and expects operations to describe their 189effects on these resources. 190 191 * `TransformMappingResource` - side effect resource corresponding to the 192 mapping between transform IR values and payload IR operations. 193 194 - An `Allocate` effect from this resource means creating a new mapping 195 entry, it is always accompanied by a `Write` effect. 196 197 - A `Read` effect from this resource means accessing the mapping. 198 199 - A `Free` effect on this resource indicates the removal of the mapping 200 entry, typically after a transformation that modifies the payload IR 201 operations associated with one of the transform IR operation's 202 operands. It is always accompanied by a `Read` effect. 203 204 * `PayloadIRResource` - side effect resource corresponding to the payload 205 IR itself. 206 207 - A `Read` effect from this resource means accessing the payload IR. 208 209 - A `Write` effect on this resource means mutating the payload IR. It is 210 almost always accompanied by a `Read`. 211 212The typical flow of values in the transform IR is as follows. Most 213operations produce new transform IR values and immediately associate them 214with a list of payload IR operations. This corresponds to `Allocate` and 215`Write` effects on the `TransformMappingResource`, and often requires at 216least a `Read` effect on the `PayloadIRResource`. Transform operations that 217only inspect the payload IR to produce new handles are usually limited to 218these effects on their operands. Transform operations that mutate the 219payload IR are thought to _consume_ the handles provided as operands, that 220is have the `Read` and `Free` effects on them. As with the usual memory 221effects, using a value after it was freed is incorrect. In case of the 222transform IR, this value is likely associated with payload IR operations 223that were modified or even removed by the transformation, so it is 224meaningless to refer to them. When further transformations are desired, the 225transform operations can return _new_ handles that can be read or consumed 226by subsequent operations. 227 228## Execution Model 229 230The transformation starts at the user-specified top-level transform IR 231operation and applies to some user-specified payload IR scope, identified by 232the payload IR op that contains the IR to transform. It is the 233responsibility of the user to properly select the scope and/or to avoid the 234transformations to modify the IR outside of the given scope. The top-level 235transform IR operation may contain further transform operations and execute 236them in the desired order. 237 238Transformation application functions produce a tri-state status: 239 240- success; 241- recoverable (silenceable) failure; 242- irrecoverable failure. 243 244Transformation container operations may intercept recoverable failures and 245perform the required recovery steps thus succeeding themselves. On 246the other hand, they must propagate irrecoverable failures. For such 247failures, the diagnostics are emitted immediately whereas their emission is 248postponed for recoverable failures. Transformation container operations may 249also fail to recover from a theoretically recoverable failure, in which case 250they can either propagate it to their parent or emit the diagnostic and turn 251the failure into an irrecoverable one. A recoverable failure produced by 252applying the top-level transform IR operation is considered irrecoverable. 253 254Transformation container operations are allowed to "step over" some nested 255operations if the application of some previous operation produced a failure. 256This can be conceptually thought of as having a global "recoverable error 257register" that is read/write accessed by each transform operation as a side 258effect. The transformation is skipped if the register already contains an 259error description, and the control flow proceeds to the following operation. 260 261Note that a silenceable failure, if emitted, is a compiler _error_ rather 262than a warning. Transformations are expected to produce silenceable failures 263if they haven't yet modified the payload IR, i.e. when reporting a 264precondition failure, and an irrecoverable failure when they modified the IR 265in a way that is contrary to the semantics of the transform operation or 266would fail a postcondition. Some "navigation" operations that identify 267payload IR targets for the following transformation may have a conceptual 268"failure to match" that is considered a successful execution in the 269execution model but results in handles associated with empty payload IR 270operation lists. 271 272## Handle Invalidation 273 274The execution model of the Transform dialect allows a payload IR operation to be 275associated with _multiple_ handles as well as nested payload IR operations to be 276associated with different handles. Similarly, a payload IR value may be 277associated with multiple transform IR value handles. When a transform IR 278operation consumes a handle, it usually indicates that the corresponding payload 279IR object was destroyed and should no longer be referenced. Transform IR handles 280that _may_ be pointing to an erased payload IR object are _invalidated_. The 281mere presence of an invalidated handle in the transform IR is not a problem, but 282_using_ it results in undefined behavior. Invalidated handles can be thought of 283as dangling pointers. Note that the _entire_ handle is invalidated, even if some 284of the payload IR objects associated with it remain live. 285 286The following handle invalidation rules apply. 287 288 * When an operation handle is consumed, are invalidated: 289 290 - operation handles associated with one of the payload operations that the 291 consumed handle is associated with; 292 293 - operation handles associated with one of the operations _nested_ in the 294 payload operations described above; 295 296 - value handles associated with any result of any operation described above; 297 298 - value handles associated with any argument of a block contained in a 299 region attached to any operation described above. 300 301 * When a value handle is consumed, are invalidated: 302 303 - operation handles associated with payload operations that produce as 304 result any value associated with the consumed handle (when the associated 305 is an operation result); 306 307 - operation handles associated with payload operations _nested_ in the 308 payload operations described above; 309 310 - operation handles associated with payload operations (recursively) 311 _contained_ in the block that defines as argument any value associated 312 with the consumed handle (when the associated value is a block argument); 313 note that the adjacent blocks are not affected; 314 315 - value handles associated with any result of any operation described above, 316 including all results of the operation defining as result the value 317 associated with the consumed handle; 318 319 - value handles associated with any argument of a block contained in a 320 region attached to any operation described above. 321 322More intuitively, consuming a handle invalidates any handle that may be pointing 323to an object defined or contained in the payload IR subtree rooted at the 324closest operation or block. 325 326The Transform dialect infrastructure has the capability of checking whether 327the transform IR op operand is invalidated before applying the 328transformation. However, such a check is computationally expensive and 329must be enabled explicitly through `TransformOptions`. Additionally, the 330`transform-dialect-check-uses` pass emits warnings when a handle may be used 331after it has been consumed, but does so abstractly, without processing the 332payload IR. 333 334Values associated with parameters (non-handles) cannot be invalidated. 335 336## Intended Use and Integrations 337 338The transformation control infrastructure provided by this dialect is 339positioned roughly between rewrite patterns and passes. A transformation 340that is executed by a transform operation is likely to be sufficiently 341complex to require at least a set of patterns to be implemented. It is also 342expected to be more focused than a pass: a pass typically applies identical 343transformations everywhere in the IR, a transform dialect-controlled 344transformation would apply to a small subset of operations selected, e.g., 345by a pattern-matching operation or generated by a previous transformation. 346It is discouraged, although technically possible, to run a pass pipeline as 347part of the transform op implementation. 348 349One of the main scenarios for using this dialect is fine-grain chaining of 350transformations. For example, a loop-like operation may see its iteration 351domain split into two parts, implemented as separate loops (transformation 352known as index-set splitting), each of which is then transformed differently 353(e.g., the first loop is tiled and the second unrolled) with the necessary 354enabling and cleanup patterns around the main transformation: 355 356```mlir 357// <generate %loop, e.g., by pattern-matching> 358// ... 359%parts:2 = transform.loop.split %loop { upper_bound_divisible_by = 8 } 360transform.loop.tile %parts#0 { tile_sizes = [8] } 361transform.loop.unroll %parts#1 { full } 362``` 363 364This composition would have been difficult to implement as separate passes 365since the hypothetical "tiling" and "unrolling" pass would need to somehow 366differentiate between the parts of the loop produced by the previous pass 367(both are the same operation, and it is likely undesirable to pollute the 368operation with pass-specific information). Implementing passes that run the 369combined transformation would have run into the combinatorial explosion 370issue due to multiple possible transform compositions or into the need for 371deep pass parameterization, the ultimate form of which is an ad-hoc dialect 372to specify which transformations the pass should run. The transform dialect 373provides a uniform, extensible mechanism for controlling transformations in 374such cases. 375 376The Transform dialect is supposed to be consumed by an "interpreter" pass 377that drives the application of transformations. To ensure extensibility and 378composability, this pass is not expected to actually perform the 379transformations specified by the ops. Instead, the transformations are 380implemented by the transform ops themselves via `TransformOpInterface`. The 381pass serves as the entry point, handles the flow of transform operations and 382takes care of bookkeeping. As such, the Transform dialect does not provide 383the interpreter pass. Instead, it provides a set of utilities that can be 384used by clients to define their own interpreter passes or as part of a more 385complex pass. For example, the mapping between values in the transform IR 386and operations in the payload IR, or the function that applies the 387transformations specified by ops in the given block sequentially. Note that 388a transform op may have regions with further transform ops in them, with 389the op itself guiding how to dispatch the transformation control flow to 390those regions. This approach allows clients to decide on the relative 391location of the transform IR in their input (e.g., nested modules, separate 392modules, optional regions to certain operations, etc.), register additional 393transform operations and perform client-specific bookkeeping. 394 395## Effects on the Infrastructure 396 397Although scoped to a single dialect, this functionality conceptually belongs 398to the MLIR infrastructure. It aims to be minimally intrusive and opt-in. 399 400Some infrastructural components may grow extra functionality to support the 401transform dialect. In particular, the pattern infrastructure may add extra 402hooks to identify the "main results" of a transformation or to notify 403external observers about changes made to certain operations. These are not 404expected to affect the existing uses of the infrastructure. 405 406For the sake of reusability, transformations should be implemented as 407utility functions that are called from the interface methods of transform 408ops rather than having the methods directly act on the payload IR. 409 410## Type Definitions 411 412[include "Dialects/TransformTypes.md"] 413 414## Core Operations 415 416[include "Dialects/TransformOps.md"] 417 418## Affine Transform Operations 419 420[include "Dialects/AffineLoopTransformOps.md"] 421 422## Bufferization Transform Operations 423 424[include "Dialects/BufferizationTransformOps.md"] 425 426## Debug Transform Operations 427 428[include "Dialects/DebugExtensionOps.md"] 429 430## DLTI Transform Operations 431 432[include "Dialects/DLTITransformOps.md"] 433 434## IRDL (extension) Transform Operations 435 436[include "Dialects/IRDLExtensionOps.md"] 437 438## Func Transform Operations 439 440[include "Dialects/FuncTransformOps.md"] 441 442## GPU Transform Operations 443 444[include "Dialects/GPUTransformOps.md"] 445 446## Loop (extension) Transform Operations 447 448[include "Dialects/LoopExtensionOps.md"] 449 450## Loop (SCF) Transform Operations 451 452[include "Dialects/SCFLoopTransformOps.md"] 453 454## MemRef Transform Operations 455 456[include "Dialects/MemRefTransformOps.md"] 457 458## PDL (extension) Transform Operations 459 460[include "Dialects/PDLExtensionOps.md"] 461 462## Structured (Linalg) Match Operations 463 464[include "Dialects/LinalgStructuredMatchOps.md"] 465 466## Structured (Linalg) Transform Operations 467 468[include "Dialects/LinalgStructuredTransformOps.md"] 469 470## Tensor Transform Operations 471 472[include "Dialects/TensorTransformOps.md"] 473 474## Vector Transform Operations 475 476[include "Dialects/VectorTransformOps.md"] 477 478[include "Dialects/TransformTypeInterfaces.md"] 479 480[include "Dialects/TransformOpInterfaces.md"] 481