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