xref: /llvm-project/mlir/include/mlir/Dialect/Transform/IR/TransformOps.td (revision 35e89897a4086f5adbab10b4b90aa63ef5b35514)
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/CallInterfaces.td"
13include "mlir/Interfaces/CastInterfaces.td"
14include "mlir/Interfaces/ControlFlowInterfaces.td"
15include "mlir/Interfaces/InferTypeOpInterface.td"
16include "mlir/Interfaces/SideEffectInterfaces.td"
17include "mlir/Interfaces/FunctionInterfaces.td"
18include "mlir/IR/OpAsmInterface.td"
19include "mlir/IR/RegionKindInterface.td"
20include "mlir/IR/SymbolInterfaces.td"
21include "mlir/Dialect/Transform/Interfaces/MatchInterfaces.td"
22include "mlir/Dialect/Transform/IR/TransformAttrs.td"
23include "mlir/Dialect/Transform/IR/TransformDialect.td"
24include "mlir/Dialect/Transform/Interfaces/TransformInterfaces.td"
25
26def AlternativesOp : TransformDialectOp<"alternatives",
27    [DeclareOpInterfaceMethods<RegionBranchOpInterface,
28        ["getEntrySuccessorOperands", "getSuccessorRegions",
29         "getRegionInvocationBounds"]>,
30     DeclareOpInterfaceMethods<TransformOpInterface>,
31     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
32     IsolatedFromAbove, PossibleTopLevelTransformOpTrait,
33     SingleBlockImplicitTerminator<"::mlir::transform::YieldOp">]> {
34  let summary = "Attempts sequences of transforms until one succeeds";
35  let description = [{
36    This op may have an arbitrary number of regions, each of which represents a
37    sequence of transform operations to be applied to the same payload IR. The
38    regions are visited in order of appearance, and transforms in them are
39    applied in their respective order of appearance. If one of these transforms
40    fails to apply, the remaining ops in the same region are skipped an the next
41    region is attempted. If all transformations in a region succeed, the
42    remaining regions are skipped and the entire "alternatives" transformation
43    succeeds. If all regions contained a failing transformation, the entire
44    "alternatives" transformation fails.
45
46    It is up to the nested operations to define which errors are "recoverable"
47    (or "silenceable") and allow another alternatives to be attempted, and which
48    errors should be propagated without attempting the other alternatives.
49
50    The single operand of this operation is the scope in which the alternative
51    transformation sequences are attempted, that is, an operation in the payload
52    IR that contains all the other operations that may be modified by the
53    transformations. The scope operation must be isolated from above. There is
54    no check that the transforms are indeed scoped as their "apply" methods can
55    be arbitrarily complex. Therefore it is the responsibility of the user to
56    ensure that the transforms are scoped correctly, or to produce an
57    irrecoverable error and thus abort the execution without attempting the
58    remaining alternatives. Note that the payload IR outside of the given scope
59    is not necessarily in the valid state, or even accessible to the
60    transformation.
61
62    The changes to the IR within the scope performed by transforms in the failed
63    alternative region are reverted before attempting the next region.
64    Practically, this is achieved by cloning the scope. Therefore it is advised
65    to limit the scope as much as possible and place the most likely
66    alternatives early in the region list. The operation is also isolated from
67    above and requires rediscovering the operations within the given scope to
68    avoid additional handle invalidation. The latter restriction may be lifted
69    in the future.
70
71    Each of the regions may yield transform IR handles. The handles of the first
72    successful alternative region are returned as the results of the
73    "alternatives" op. Therefore, each alternative region must yield the same
74    number of results, which should also match the number and the types of the
75    "alternatives" op results.
76
77    Remark: this op allows one to implement a simple "try" construct as follows:
78
79    ```mlir
80    %result = transform.alternatives %scope {
81    ^bb0(%arg0: !transform.any_op):
82      // Try a fallible transformation.
83      %0 = transform.fallible %arg0 // ...
84      // If succeeded, yield the the result of the transformation.
85      transform.yield %0 : !transform.any_op
86    }, {
87    ^bb0(%arg0: !transform.any_op):
88      // Otherwise, the second alternative is tried and it always succeeds by
89      // returning the original handle.
90      transform.yield %arg0 : !transform.any_op
91    }
92    ```
93  }];
94
95  let arguments = (ins Optional<TransformHandleTypeInterface>:$scope);
96  let results = (outs Variadic<TransformHandleTypeInterface>:$results);
97  let regions = (region VariadicRegion<SizedRegion<1>>:$alternatives);
98
99  let assemblyFormat =
100    "($scope^ `:` type($scope))? (`->` type($results)^)? "
101    "attr-dict-with-keyword regions";
102  let hasVerifier = 1;
103}
104
105def AnnotateOp : TransformDialectOp<"annotate",
106    [DeclareOpInterfaceMethods<TransformOpInterface>,
107     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
108  let summary = "Annotates the target operation with an attribute by name";
109  let description = [{
110    Adds an attribute with the given `name` to the `target` operation. An
111    optional `param` handle can be provided to give the attribute a specific
112    value, else a UnitAttr is added. A single attribute will be broadcasted to
113    all target operations, otherwise the attributes will be mapped 1:1 based on
114    the order within the handles.
115
116    Produces a silenceable failure if the length of the parameter payload does
117    not match the length of the target payload. Does not consume the provided
118    handles.
119  }];
120
121  let arguments = (ins TransformHandleTypeInterface:$target,
122                       StrAttr:$name,
123                       Optional<TransformParamTypeInterface>:$param);
124  let results = (outs);
125
126  let assemblyFormat =
127    "$target $name attr-dict (`=` $param^)?"
128    "`:` type($target) (`,` type($param)^)?";
129}
130
131def ApplyCommonSubexpressionEliminationOp : TransformDialectOp<"apply_cse",
132    [TransformOpInterface, TransformEachOpTrait,
133     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
134     ReportTrackingListenerFailuresOpTrait]> {
135  let summary = "Eliminate common subexpressions in the body of the target op";
136  let description = [{
137    This transform applies common subexpression elimination (CSE) to the body
138    of the targeted op.
139
140    This transform reads the target handle and modifies the payload. Existing
141    handles to operations inside of the targeted op are retained and updated if
142    necessary. Note that this can lead to situations where a handle, that was
143    previously mapped to multiple distinct (but equivalent) operations, is now
144    mapped to the same operation multiple times.
145  }];
146
147  let arguments = (ins TransformHandleTypeInterface:$target);
148  let results = (outs);
149  let assemblyFormat = "`to` $target attr-dict `:` type($target)";
150
151  let extraClassDeclaration = [{
152    ::mlir::DiagnosedSilenceableFailure applyToOne(
153      ::mlir::transform::TransformRewriter &rewriter,
154      ::mlir::Operation *target,
155      ::mlir::transform::ApplyToEachResultList &results,
156      ::mlir::transform::TransformState &state);
157  }];
158}
159
160def ApplyConversionPatternsOp : TransformDialectOp<"apply_conversion_patterns",
161    [DeclareOpInterfaceMethods<TransformOpInterface>,
162     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
163     ReportTrackingListenerFailuresOpTrait]
164        # GraphRegionNoTerminator.traits> {
165  let summary = "Applies conversion patterns to the body of the targeted op";
166  let description = [{
167    This transform applies the specified conversion patterns to the targeted op
168    and all nested ops. By default, this transform applies a "full" dialect
169    conversion. If the `partial_conversion` unit attribute is present, this
170    transform applies a partial dialect conversion.
171
172    The patterns that should be applied are specified in the first graph region
173    of this op. They must implement the
174    `ConversionPatternDescriptorOpInterface`. The order in which patterns are
175    applied is unspecified; i.e., the ordering of ops in the region of this op
176    is irrelevant.
177
178    The second, optional graph region contains exactly one op that specifies
179    default type converter that should be used with this dialect conversion. If
180    provided, this op must implement the `TypeConverterBuilderOpInterface`.
181    Type converters are a property of conversion patterns: each conversion
182    pattern stores the type converter that should be used in its C++ class. Each
183    conversion pattern descriptor can optionally specify a type converter in its
184    `getTypeConverter` interface method. If no type converter is specified in
185    this method, the default type converter of the dialect conversion is used.
186    Default type converters are useful if the same type converter should be used
187    for multiple sets of conversion patterns. (Patterns that should not use this
188    default type converter specify their own type converter.)
189
190    The `legal_ops`, `illegal_ops`, `legal_dialects`, `illegal_dialects`
191    attributes specify the conversion target.
192
193    This transform modifies the payload. By default, it consumes the `target`
194    handle. It does not produce any handles.
195
196    If the `preserve_handles` attribute is set, this transform does not consume
197    the `target` handle and instead updates handles based on notifications from
198    a tracking listener that is attached to the dialect conversion, similar to
199    `transform.apply_patterns`. Only replacements via `RewriterBase::replaceOp`
200    or `replaceOpWithNewOp` are considered "payload op replacements". In
201    contrast to `transform.apply_patterns`, we allow replacement ops even if the
202    op name has changed. This is because conversion patterns are expected to
203    lower ops to different ops (from a different dialect). More details can be
204    found at the documentation site of `TrackingListener`.
205
206    This transform produces a silenceable failure if the dialect conversion was
207    unsuccessful or the tracking listener failed to find a replacement op.
208  }];
209
210  let arguments = (ins TransformHandleTypeInterface:$target,
211                       OptionalAttr<StrArrayAttr>:$legal_ops,
212                       OptionalAttr<StrArrayAttr>:$illegal_ops,
213                       OptionalAttr<StrArrayAttr>:$legal_dialects,
214                       OptionalAttr<StrArrayAttr>:$illegal_dialects,
215                       UnitAttr:$partial_conversion,
216                       UnitAttr:$preserve_handles);
217  let results = (outs);
218  let regions = (region
219      MaxSizedRegion<1>:$patterns,
220      VariadicRegion<MaxSizedRegion<1>>:$default_type_converter_region);
221
222  let assemblyFormat = [{
223    `to` $target $patterns
224    (`with` `type_converter` $default_type_converter_region^)?
225    attr-dict `:` type($target)
226  }];
227  let hasVerifier = 1;
228
229  let skipDefaultBuilders = 1;
230  let builders = [
231    OpBuilder<(ins
232        "Value":$target,
233        CArg<"function_ref<void(OpBuilder &, Location)>", "nullptr">:
234            $patternsBodyBuilder,
235        CArg<"function_ref<void(OpBuilder &, Location)>", "nullptr">:
236            $typeConverterBodyBuilder)>,
237  ];
238
239  let extraClassDeclaration = [{
240    ::mlir::transform::TypeConverterBuilderOpInterface getDefaultTypeConverter() {
241      if (getDefaultTypeConverterRegion().size() == 0)
242        return {};
243      return ::llvm::cast<::mlir::transform::TypeConverterBuilderOpInterface>(
244          &getDefaultTypeConverterRegion()[0].front().front());
245    }
246  }];
247}
248
249def ApplyToLLVMConversionPatternsOp : Op<Transform_Dialect,
250    "apply_conversion_patterns.dialect_to_llvm",
251    [DeclareOpInterfaceMethods<ConversionPatternDescriptorOpInterface,
252                               ["verifyTypeConverter"]>]> {
253  let description = [{
254    Collects patterns that convert ops from the specified dialect to LLVM
255    dialect ops. These patterns require an "LLVMTypeConverter".
256
257    Note: Only dialects that implement the `ConvertToLLVMPatternInterface` are
258    supported. Any conversion target modifications by interface implementations
259    are currently ignored. The conversion target is fully specified by the
260    enclosing "apply_conversion_patterns" op.
261  }];
262
263  let arguments = (ins StrAttr:$dialect_name);
264  let assemblyFormat = "$dialect_name attr-dict";
265  let hasVerifier = 1;
266}
267
268def ApplyDeadCodeEliminationOp : TransformDialectOp<"apply_dce",
269    [TransformOpInterface, TransformEachOpTrait,
270     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
271     ReportTrackingListenerFailuresOpTrait]> {
272  let summary = "Eliminate dead operations in the body of the target op";
273  let description = [{
274    This transform applies dead code elimination (DCE) to the body of the
275    targeted op.
276
277    Note: "transform.apply_patterns" with an empty region can also be used to
278    remove dead ops. However, that op applies additional simplifications such as
279    op folding and region simplification.
280
281    This transform reads the target handle and modifies the payload. Note that
282    this transform may silently remove payload ops from handles.
283  }];
284
285  let arguments = (ins TransformHandleTypeInterface:$target);
286  let results = (outs);
287  let assemblyFormat = "`to` $target attr-dict `:` type($target)";
288
289  let extraClassDeclaration = [{
290    ::mlir::DiagnosedSilenceableFailure applyToOne(
291      ::mlir::transform::TransformRewriter &rewriter,
292      ::mlir::Operation *target,
293      ::mlir::transform::ApplyToEachResultList &results,
294      ::mlir::transform::TransformState &state);
295  }];
296}
297
298def ApplyPatternsOp : TransformDialectOp<"apply_patterns",
299    [TransformOpInterface, TransformEachOpTrait,
300     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
301     ReportTrackingListenerFailuresOpTrait]
302        # GraphRegionNoTerminator.traits> {
303  let summary = "Greedily applies patterns to the body of the targeted op";
304  let description = [{
305    This transform greedily applies the specified patterns to the body of the
306    targeted op until a fixpoint was reached. Patterns are not applied to the
307    targeted op itself.
308
309    The patterns that should be applied are specified in the graph region of
310    this op. They must implement the `PatternDescriptorOpInterface`. The order
311    in which patterns are applied is unspecified; i.e., the ordering of ops in
312    the region of this op is irrelevant.
313
314    If `apple_cse` is set, the greedy pattern rewrite is interleaved with
315    common subexpression elimination (CSE): both are repeated until a fixpoint
316    is reached.
317
318    This transform only reads the target handle and modifies the payload. If a
319    pattern erases or replaces a tracked op, the mapping is updated accordingly.
320
321    Only replacements via `RewriterBase::replaceOp` or `replaceOpWithNewOp` are
322    considered "payload op replacements". Furthermore, only if the replacement
323    values are defined by the same op and that op has the same type as the
324    original op, the mapping is updated. Otherwise, this transform produces a
325    silenceable failure. More details can be found at the documentation site of
326    `TrackingListener`.
327
328    This transform also produces a silenceable failure if the pattern
329    application did not converge within the default number of
330    iterations/rewrites of the greedy pattern rewrite driver.
331  }];
332
333  let arguments = (ins
334    TransformHandleTypeInterface:$target,
335    UnitAttr:$apply_cse,
336    DefaultValuedAttr<I64Attr, "static_cast<uint64_t>(-1)">:$max_iterations,
337    DefaultValuedAttr<I64Attr, "static_cast<uint64_t>(-1)">:$max_num_rewrites);
338  let results = (outs);
339  let regions = (region MaxSizedRegion<1>:$patterns);
340
341  let assemblyFormat = "`to` $target $patterns attr-dict `:` type($target)";
342  let hasVerifier = 1;
343
344  let skipDefaultBuilders = 1;
345  let builders = [
346    OpBuilder<(ins
347        "Value":$target,
348        CArg<"function_ref<void(OpBuilder &, Location)>", "nullptr">:
349            $bodyBuilder)>,
350  ];
351
352  let extraClassDeclaration = [{
353    ::mlir::DiagnosedSilenceableFailure applyToOne(
354      ::mlir::transform::TransformRewriter &rewriter,
355      ::mlir::Operation *target,
356      ::mlir::transform::ApplyToEachResultList &results,
357      ::mlir::transform::TransformState &state);
358  }];
359}
360
361def ApplyCanonicalizationPatternsOp
362    : TransformDialectOp<"apply_patterns.canonicalization",
363        [DeclareOpInterfaceMethods<PatternDescriptorOpInterface>]> {
364  let summary = "Populates canonicalization patterns";
365  let description = [{
366    This op populates all canonicalization patterns of all loaded dialects in
367    an `apply_patterns` transform.
368  }];
369  let assemblyFormat = "attr-dict";
370}
371
372def ApplyLoopInvariantCodeMotionOp : TransformDialectOp<"apply_licm",
373    [TransformOpInterface, TransformEachOpTrait,
374     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
375     ReportTrackingListenerFailuresOpTrait]> {
376  let summary = "Move loop-invariant code out of a loop-like op";
377  let description = [{
378    This transform moves side-effect free, loop invariant code out of the
379    targeted loop-like op. The targeted op must implement the
380    `LoopLikeOpInterface`.
381
382    Note: To move invariant ops from a loop nest, this transform must be applied
383    to each loop of the loop nest, starting with the inner-most loop.
384
385    This transform reads the target handle and modifies the payload.
386  }];
387
388  let arguments = (ins TransformHandleTypeInterface:$target);
389  let results = (outs);
390  let assemblyFormat = "`to` $target attr-dict `:` type($target)";
391
392  let extraClassDeclaration = [{
393    ::mlir::DiagnosedSilenceableFailure applyToOne(
394      ::mlir::transform::TransformRewriter &rewriter,
395      ::mlir::LoopLikeOpInterface target,
396      ::mlir::transform::ApplyToEachResultList &results,
397      ::mlir::transform::TransformState &state);
398  }];
399}
400
401def ApplyRegisteredPassOp : TransformDialectOp<"apply_registered_pass",
402    [TransformOpInterface, TransformEachOpTrait,
403     FunctionalStyleTransformOpTrait, MemoryEffectsOpInterface]> {
404  let summary = "Applies the specified registered pass or pass pipeline";
405  let description = [{
406    This transform applies the specified pass or pass pipeline to the targeted
407    ops. The name of the pass/pipeline is specified as a string attribute, as
408    set during pass/pipeline registration. Optionally, pass options may be
409    specified as a string attribute. The pass options syntax is identical to the
410    one used with "mlir-opt".
411
412    This op first looks for a pass pipeline with the specified name. If no such
413    pipeline exists, it looks for a pass with the specified name. If no such
414    pass exists either, this op fails definitely.
415
416    This transform consumes the target handle and produces a new handle that is
417    mapped to the same op. Passes are not allowed to remove/modify the operation
418    that they operate on, so the target op is guaranteed to still exist. The
419    target handle is invalidated because a pass may arbitrarily modify the body
420    of targeted ops.
421  }];
422
423  let arguments = (ins TransformHandleTypeInterface:$target,
424                       StrAttr:$pass_name,
425                       DefaultValuedAttr<StrAttr, "\"\"">:$options);
426  let results = (outs TransformHandleTypeInterface:$result);
427  let assemblyFormat = [{
428    $pass_name `to` $target attr-dict `:` functional-type(operands, results)
429  }];
430
431  let extraClassDeclaration = [{
432    ::mlir::DiagnosedSilenceableFailure applyToOne(
433      ::mlir::transform::TransformRewriter &rewriter,
434      ::mlir::Operation *target,
435      ::mlir::transform::ApplyToEachResultList &results,
436      ::mlir::transform::TransformState &state);
437  }];
438}
439
440def CastOp : TransformDialectOp<"cast",
441    [TransformOpInterface, TransformEachOpTrait,
442     DeclareOpInterfaceMethods<CastOpInterface>,
443     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
444  let arguments = (ins TransformHandleTypeInterface:$input);
445  let results = (outs TransformHandleTypeInterface:$output);
446  let assemblyFormat = "$input attr-dict `:` type($input) `to` type($output)";
447
448  let extraClassDeclaration = [{
449    ::mlir::DiagnosedSilenceableFailure applyToOne(
450      ::mlir::transform::TransformRewriter &rewriter,
451      ::mlir::Operation *target,
452      ::mlir::transform::ApplyToEachResultList &results,
453      ::mlir::transform::TransformState &state);
454  }];
455}
456
457def NumAssociationsOp : TransformDialectOp<"num_associations",
458    [MemoryEffectsOpInterface, ParamProducerTransformOpTrait,
459     DeclareOpInterfaceMethods<TransformOpInterface>,
460     MatchOpInterface]> {
461  let summary =
462    "Returns the number of payload objects associated with the argument";
463  let description = [{
464    Given an argument, handle or parameter, returns a new parameter associated
465    with a single 64-bit number that corresponds to the number of payload
466    objects (operations or values for a handle, attributes for a parameter)
467    associated with the argument.
468
469    Always succeeds.
470  }];
471  let arguments = (ins Transform_AnyHandleOrParamType:$handle);
472  let results = (outs TransformParamTypeInterface:$num);
473  let assemblyFormat = [{
474    $handle attr-dict `:` functional-type(operands, results)
475  }];
476  let hasVerifier = 1;
477}
478
479def CollectMatchingOp : TransformDialectOp<"collect_matching", [
480    DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
481    DeclareOpInterfaceMethods<SymbolUserOpInterface>,
482    DeclareOpInterfaceMethods<TransformOpInterface>]> {
483  let summary = "Collects all payload ops that match the given named matcher";
484  let description = [{
485    Collects operations or other payload IR objects nested under `root`
486    (inclusive) that match the given matcher expressed as a named sequence. The
487    matcher sequence must accept exactly one argument that it is not allowed to
488    modify. It must yield as many values as this op has results. Each of the
489    yielded values must be associated with exactly one payload object. If any
490    operation in the matcher sequence produces a silenceable failure, the
491    matcher advances to the next payload operation in the walk order without
492    finishing the sequence.
493
494    The i-th result of this operation is constructed by concatenating the i-th
495    yielded payload IR objects of all successful matcher sequence applications.
496    All results are guaranteed to be mapped to the same number of payload IR
497    objects.
498
499    The operation succeeds unless the matcher sequence produced a definite
500    failure for any invocation.
501  }];
502
503  let arguments = (ins TransformHandleTypeInterface:$root,
504                       SymbolRefAttr:$matcher);
505  let results = (outs Variadic<Transform_AnyHandleOrParamType>:$results);
506
507  let assemblyFormat = [{
508    $matcher `in` $root attr-dict `:` functional-type($root, $results)
509  }];
510}
511
512def ForeachMatchOp : TransformDialectOp<"foreach_match", [
513    DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
514    DeclareOpInterfaceMethods<SymbolUserOpInterface>,
515    DeclareOpInterfaceMethods<TransformOpInterface,
516                              ["allowsRepeatedHandleOperands"]>,
517    DeclareOpInterfaceMethods<OpAsmOpInterface,
518                              ["getAsmResultNames"]>]> {
519  let summary = "Applies named sequences when a named matcher succeeds";
520  let description = [{
521    Given a pair of co-indexed lists of transform dialect symbols (such as
522    `transform.named_sequence`), walks the payload IR associated with the root
523    handle and interprets the symbols as matcher/action pairs by applying the
524    body of the corresponding symbol definition. The symbol from the first list
525    is the matcher part: if it results in a silenceable error, the error is
526    silenced and the next matcher is attempted. Definite failures from any
527    matcher stop the application immediately and are propagated unconditionally.
528    If none of the matchers succeeds, the next payload operation in walk order
529    (post-order at the moment of writing, double check `Operation::walk`) is
530    matched. If a matcher succeeds, the co-indexed action symbol is applied and
531    the following matchers are not applied to the same payload operation. If the
532    action succeeds, the next payload operation in walk order is matched. If it
533    fails, both silenceable and definite errors are propagated as the result of
534    this op; propagation of silenceable errors is postponed until the end of the
535    walk.
536
537    The matcher symbol must take at least one operand of a type that implements
538    the same transform dialect interface as the `root` operand (a check is
539    performed at application time to see if the associated payload satisfies the
540    constraints of the actual type), and may take additional operands with a
541    similar type requirement. It must not consume operands as multiple matchers
542    may be applied. The matcher may produce any number of results. The action
543    symbol paired with the matcher must take the same number of arguments as the
544    matcher has results, and these arguments must implement the same transform
545    dialect interfaces, but not necessarily have the exact same type (again, a
546    check is performed at application time to see if the associated payload
547    satisfies the constraints of actual types on both sides).
548
549    The action symbol may have results that are accumulated from all actions and
550    returned from the `foreach_match` operation on success. Unless the
551    `flatten_results` attribute is present, each action result must be
552    associated with exactly one payload entity. The actions are expected to only
553    modify payload operations nested in the `root` payload operations associated
554    with the operand of this transform operation. Furthermore, the actions may
555    not modify operations outside of the currently matched payload operation,
556    e.g., they may not modify sibling or parent operations. If such behavior is
557    desired, the parent must be matched first and the nested operations obtained
558    by traversing the IR from the parent. This is due to the matching being
559    performed as a post-order IR walk.
560
561    This operation consumes the operand and produces a new handle associated
562    with the same payload. This is necessary to trigger invalidation of handles
563    to any of the payload operations nested in the payload operations associated
564    with the operand, as those are likely to be modified by actions.
565
566    By default, the root payload operation associated with the operand is not
567    matched. This is to support the conservative case where applied actions may
568    invalidate the root payload operation. If the optional `restrict_root`
569    attribute is set, the root operand is guaranteed to not be invalidated by any
570    of the applied actions. In such cases, the root payload operation is also
571    matched. This is useful because matching the root payload operation is a
572    common idiom, when e.g. matching a func.func directly and operations nested
573    under it.
574
575    The operation succeeds if none of the matchers produced a definite failure
576    during application and if all of the applied actions produced success. Note
577    that it also succeeds if all the matchers failed on all payload operations,
578    i.e. failure to apply is not an error. The operation produces a silenceable
579    failure if any applied action produced a silenceable failure. In this case,
580    the resulting handle is associated with an empty payload. The operation
581    produces a definite failure if any of the applied matchers or actions
582    produced a definite failure.
583  }];
584
585  let arguments =
586      (ins TransformHandleTypeInterface:$root,
587           Variadic<Transform_AnyHandleOrParamType>:$forwarded_inputs,
588           UnitAttr:$restrict_root,
589           UnitAttr:$flatten_results,
590           SymbolRefArrayAttr:$matchers,
591           SymbolRefArrayAttr:$actions);
592  let results =
593      (outs TransformHandleTypeInterface:$updated,
594            Variadic<Transform_AnyHandleOrParamType>:$forwarded_outputs);
595
596  let assemblyFormat = [{
597    oilist( `restrict_root` $restrict_root
598          | `flatten_results` $flatten_results
599          )
600    `in`
601    $root (`,` $forwarded_inputs^)?
602    custom<ForeachMatchSymbols>($matchers, $actions)
603    attr-dict
604    `:` functional-type(operands, results)
605  }];
606
607  let hasVerifier = 1;
608}
609
610def ForeachOp : TransformDialectOp<"foreach",
611    [DeclareOpInterfaceMethods<TransformOpInterface>,
612     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
613     DeclareOpInterfaceMethods<RegionBranchOpInterface, [
614         "getSuccessorRegions", "getEntrySuccessorOperands"]>,
615     SingleBlockImplicitTerminator<"::mlir::transform::YieldOp">
616    ]> {
617  let summary = "Executes the body for each element of the payload";
618  let description = [{
619    Execute the op's body - its single region block - exactly once per
620    element of the payload associated to a target handle. The body's
621    transformations are applied in order of appearance until reaching the
622    (implicit) YieldOp terminator.
623
624    Each iteration gets executed by co-indexing the payloads of the arguments
625    and mapping the body's arguments to these tuples, as though iterating over
626    the zipped together `targets`. As such, in each iteration, the size of the
627    payload of each of the body's block arguments is exactly one. The attribute
628    `zip_shortest` can be used if the targets vary in their number of payloads;
629    this will limit the iterations to only the number of payloads found in the
630    shortest target.
631
632    This op always reads the target handles. Furthermore, it consumes a handle
633    if there is a transform op in the body that consumes the corresponding
634    block argument. Handles can point to ops, values, or parameters.
635
636    #### Return Modes
637
638    This op produces as many result handles as the body's terminating YieldOp
639    has operands. For each result, the payloads of the corresponding YieldOp
640    operand are merged and mapped to the same resulting handle.
641
642    If the target handles do not associate payloads of the same size, a
643    silencable failure will be generated.
644
645    During application, if any transformation in the sequence fails, the entire
646    sequence fails immediately with the same failure, leaving the payload IR in
647    a potentially invalid state, i.e., this operation offers no transformation
648    rollback capabilities.
649  }];
650
651  let arguments = (ins Variadic<Transform_AnyHandleOrParamType>:$targets,
652                       UnitAttr:$with_zip_shortest);
653  let results = (outs Variadic<Transform_AnyHandleOrParamType>:$results);
654  let regions = (region SizedRegion<1>:$body);
655  let assemblyFormat =
656    "$targets oilist(`with_zip_shortest` $with_zip_shortest) `:` "
657    "type($targets) (`->` type($results)^)? $body attr-dict";
658  let hasVerifier = 1;
659
660  let extraClassDeclaration = [{
661    /// Allow the dialect prefix to be omitted.
662    static StringRef getDefaultDialect() { return "transform"; }
663
664    transform::YieldOp getYieldOp();
665  }];
666}
667
668def GetConsumersOfResult : TransformDialectOp<"get_consumers_of_result",
669    [DeclareOpInterfaceMethods<TransformOpInterface>,
670     NavigationTransformOpTrait, MemoryEffectsOpInterface]> {
671  let summary = "Get handle to the consumers of this operation's result number";
672  let description = [{
673    The handle defined by this Transform op corresponds to all operations that
674    consume the SSA value defined by the `target` and `result_number`
675    arguments.
676    This operation applies to a single payload operation, otherwise it produces
677    a definite failure.
678    The return handle points to the consuming operations operations, which can
679    be empty.
680  }];
681
682  let arguments = (ins TransformHandleTypeInterface:$target,
683                       I64Attr:$result_number);
684  let results = (outs TransformHandleTypeInterface:$consumers);
685  let assemblyFormat = "$target `[` $result_number `]` attr-dict `:` "
686                       "functional-type(operands, results)";
687}
688
689def GetDefiningOp : TransformDialectOp<"get_defining_op",
690    [DeclareOpInterfaceMethods<TransformOpInterface>,
691     MatchOpInterface,
692     NavigationTransformOpTrait, MemoryEffectsOpInterface]> {
693  let summary = "Get handle to the defining op of a value";
694  let description = [{
695    The handle defined by this Transform op corresponds to the defining op of
696    the targeted value.
697
698    This transform produces a silenceable failure if the targeted value is a
699    block argument.
700  }];
701
702  let arguments = (ins TransformValueHandleTypeInterface:$target);
703  let results = (outs TransformHandleTypeInterface:$result);
704  let assemblyFormat = "$target attr-dict `:` "
705                       "functional-type(operands, results)";
706}
707
708def GetParentOp : TransformDialectOp<"get_parent_op",
709    [DeclareOpInterfaceMethods<TransformOpInterface>,
710     MatchOpInterface,
711     NavigationTransformOpTrait, MemoryEffectsOpInterface]> {
712  let summary = "Gets handles to the closest parent ops";
713  let description = [{
714    The handle defined by this Transform op corresponds to the parents of the
715    targeted payload ops (in the same order).
716
717    Requirements that parent ops must fulfill can be optionally specified. In
718    that case for each target op, the closest parent op that fulfills all
719    requirements, is returned.
720    - `isolated_from_above`: the parent op must be isolated from above
721    - `allow_empty_results`: get_parent_op is allowed to return an empty list
722      and still succeeds. In such a case, if `get_parent_op` fails for any
723      operation in the list, the entire transform returns an empty handle.
724    - `op_name`: the parent op must have the specified name
725    - `nth_parent`: get the n-th parent of that satisfies the above requirements
726
727    If `deduplicate` is set, the result handle does not contain any duplicate
728    ops. For example, given the list
729    "(childof(A), childof(B), childof(B), childof(A), childof(B))", the
730    resulting list will be just "(A, B)". Note that no other semantic ordering
731    is applied, e.g., "B" may itself be a parent of "A". This may have an impact
732    on the further transformation applied to the handle produced here.
733
734    If any of the given Payload IR ops has no such suitable parent, then:
735      - if `allow_empty_results` is set, the result handle is empty
736      - otherwise, the transformation produces a silenceable failure.
737  }];
738
739  let arguments = (ins TransformHandleTypeInterface:$target,
740                       UnitAttr:$isolated_from_above,
741                       UnitAttr:$allow_empty_results,
742                       OptionalAttr<StrAttr>:$op_name,
743                       UnitAttr:$deduplicate,
744                       DefaultValuedAttr<ConfinedAttr<I64Attr, [IntPositive]>,
745                                         "1">:$nth_parent);
746  let results = (outs TransformHandleTypeInterface:$parent);
747  let assemblyFormat =
748    "$target attr-dict `:` functional-type(operands, results)";
749}
750
751def GetProducerOfOperand : TransformDialectOp<"get_producer_of_operand",
752    [DeclareOpInterfaceMethods<TransformOpInterface>,
753     NavigationTransformOpTrait, MatchOpInterface, MemoryEffectsOpInterface]> {
754  let summary = "Get handle to the producer of this operation's operand number";
755  let description = [{
756    The handle defined by this Transform op corresponds to operation that
757    produces the SSA value defined by the `target` and `operand_number`
758    arguments. If the origin of the SSA value is not an operations (i.e. it is
759    a block argument), the transform produces a silenceable failure.
760    The return handle points to only the subset of successfully produced
761    computational operations, which can be empty.
762  }];
763
764  let arguments = (ins TransformHandleTypeInterface:$target,
765                       I64Attr:$operand_number);
766  let results = (outs TransformHandleTypeInterface:$producer);
767  let assemblyFormat = "$target `[` $operand_number `]` attr-dict `:` "
768                       "functional-type(operands, results)";
769}
770
771def GetOperandOp : TransformDialectOp<"get_operand",
772    [DeclareOpInterfaceMethods<TransformOpInterface>,
773     NavigationTransformOpTrait, MatchOpInterface, MemoryEffectsOpInterface]> {
774  let summary = "Get a handle to the operand(s) of the targeted op";
775  let description = [{
776    The handle defined by this Transform op corresponds to the operands of the
777    given `target` operation specified by the given set of positions. There are
778    three possible modes:
779
780     - Position list directly, i.e. `%target[0, 1, 2]`. This will return the
781       operands at the specified positions.
782     - Inverted position list, i.e. `%target[except(0, 1, 2)]`. This will return
783       all operands except those at the given positions.
784     - All, i.e. `%target[all]`. This will return all operands of the operation.
785
786    This transform produces a silenceable failure if any of the operand indices
787    exceeds the number of operands in the target. It reads the target handle and
788    produces the result handle.
789  }];
790
791  let arguments = (ins TransformHandleTypeInterface:$target,
792                       DenseI64ArrayAttr:$raw_position_list,
793                       UnitAttr:$is_inverted,
794                       UnitAttr:$is_all);
795  let results = (outs TransformValueHandleTypeInterface:$result);
796  let assemblyFormat =
797      "$target `[`"
798      "custom<TransformMatchDims>($raw_position_list, $is_inverted, $is_all)"
799      "`]` attr-dict `:` functional-type(operands, results)";
800  let hasVerifier = 1;
801}
802
803def GetResultOp : TransformDialectOp<"get_result",
804    [DeclareOpInterfaceMethods<TransformOpInterface>,
805     NavigationTransformOpTrait, MemoryEffectsOpInterface]> {
806  let summary = "Get a handle to the result(s) of the targeted op";
807  let description = [{
808    The handle defined by this Transform op correspond to the OpResults of the
809    given `target` operation. Optionally `result_number` can be specified to
810    select a specific result.
811
812    This transform fails silently if the targeted operation does not have enough
813    results. It reads the target handle and produces the result handle.
814
815    The handle defined by this Transform op corresponds to the results of the
816    given `target` operation specified by the given set of positions. There are
817    three possible modes:
818
819     - Position list directly, i.e. `%target[0, 1, 2]`. This will return the
820       results at the specified positions.
821     - Inverted position list, i.e. `%target[except(0, 1, 2)]`. This will return
822       all results except those at the given positions.
823     - All, i.e. `%target[all]`. This will return all results of the operation.
824
825    This transform produces a silenceable failure if any of the result indices
826    exceeds the number of results returned by the target. It reads the target
827    handle and produces the result handle.
828  }];
829
830  let arguments = (ins TransformHandleTypeInterface:$target,
831                       DenseI64ArrayAttr:$raw_position_list,
832                       UnitAttr:$is_inverted,
833                       UnitAttr:$is_all);
834  let results = (outs TransformValueHandleTypeInterface:$result);
835  let assemblyFormat =
836      "$target `[`"
837      "custom<TransformMatchDims>($raw_position_list, $is_inverted, $is_all)"
838      "`]` attr-dict `:` functional-type(operands, results)";
839  let hasVerifier = 1;
840}
841
842def GetTypeOp : TransformDialectOp<"get_type",
843    [DeclareOpInterfaceMethods<TransformOpInterface>,
844     MatchOpInterface,
845     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
846  let summary = "Get a parameter containing the type of the given value";
847  let description = [{
848    This operation creates a new Transform parameter containing the
849    type(s) of the value(s) associated with the operand handle.
850
851    This transform never fails.
852  }];
853
854  let arguments = (ins TransformValueHandleTypeInterface:$value,
855                       UnitAttr:$elemental);
856  let results = (outs TransformParamTypeInterface:$type_param);
857  let assemblyFormat = "(`elemental` $elemental^)? $value attr-dict `:`"
858                       "functional-type(operands, results)";
859}
860
861def IncludeOp : TransformDialectOp<"include",
862    [CallOpInterface,
863     MatchOpInterface,
864     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
865     DeclareOpInterfaceMethods<SymbolUserOpInterface>,
866     DeclareOpInterfaceMethods<TransformOpInterface>]> {
867  let summary = "Includes a named transform sequence";
868  let description = [{
869    The application of this transform operation is equivalent to applying the
870    operations contained in the named transform sequence with operands being
871    remapped to block arguments. The behavior of the operation when a
872    transformation in the included named sequence produces a silenceable error
873    is controlled by the `failure_propagation_mode` attribute. When set to
874    `propagate`, the failure of any nested transformation in the sequence
875    implies immediate failure of the entire sequence with a silenceable error,
876    and no further transformation is attempted. When set to `suppress`,
877    silenceable errors in nested operations are ignored and further
878    transformations are applied. Beware that even silenceable errors may leave
879    the payload IR in a state unsuitable for further transformations. It is the
880    responsibility of the user to ensure the following transformations are
881    robust enough when errors are suppressed. Definite errors are propagated
882    immediately regardless of the mode. The objects associated with the results
883    of this operation are the same as those associated with the operands of the
884    `transform.yield` in the referenced named sequence.
885  }];
886
887  let arguments = (ins SymbolRefAttr:$target,
888                       FailurePropagationMode:$failure_propagation_mode,
889                       Variadic<Transform_AnyHandleOrParamType>:$operands);
890  let results = (outs Variadic<Transform_AnyHandleOrParamType>:$results);
891
892  let assemblyFormat =
893      "$target `failures` `(` $failure_propagation_mode `)`"
894      "`(` $operands `)` attr-dict `:` functional-type($operands, $results)";
895
896  let extraClassDeclaration = [{
897    ::mlir::CallInterfaceCallable getCallableForCallee() {
898      return getTarget();
899    }
900
901    void setCalleeFromCallable(::mlir::CallInterfaceCallable callee) {
902      setTargetAttr(cast<SymbolRefAttr>(callee));
903    }
904
905    ::mlir::Operation::operand_range getArgOperands() {
906      return getOperands();
907    }
908
909    ::mlir::MutableOperandRange getArgOperandsMutable() {
910      return getOperandsMutable();
911    }
912  }];
913}
914
915def MatchOperationEmptyOp : Op<Transform_Dialect, "match.operation_empty", [
916    AtMostOneOpMatcher,
917    MatchOpInterface,
918    MemoryEffectsOpInterface]> {
919  let summary =
920    "Matches if the handle is not associated to any op";
921  let description = [{
922    Succeeds if the handle is not associated to any op.
923  }];
924  let arguments = (ins TransformHandleTypeInterface:$operand_handle);
925  let assemblyFormat =
926      "$operand_handle attr-dict `:` type($operand_handle)";
927  let extraClassDeclaration = AtMostOneOpMatcher.extraDeclaration;
928}
929
930def MatchOperationNameOp : TransformDialectOp<"match.operation_name",
931    [SingleOpMatcher,
932     MatchOpInterface,
933     MemoryEffectsOpInterface]> {
934  let summary = "Matches a single operation of one of the given kinds";
935  let description = [{
936    Succeeds if the operation associated with the operand handle has one of the
937    given operation names. Produces a silenceable failure otherwise.
938
939    If more than one payload operation is associated with the operand handle,
940    produces a definite failure.
941  }];
942
943  let arguments = (ins TransformHandleTypeInterface:$operand_handle,
944                       StrArrayAttr:$op_names);
945  let assemblyFormat =
946      "$operand_handle $op_names attr-dict `:` type($operand_handle)";
947  let extraClassDeclaration = SingleOpMatcher.extraDeclaration;
948}
949
950def MatchParamCmpIOp : Op<Transform_Dialect, "match.param.cmpi", [
951    DeclareOpInterfaceMethods<TransformOpInterface>,
952    MatchOpInterface,
953    DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
954    SameTypeOperands]> {
955  let summary =
956    "Matches if two parameter lists are associated with the same value";
957  let description = [{
958    Succeeds if all of the co-indexed values associated with the given
959    parameters relate as specified by the predicate (greater than, less than,
960    equal to, or their combinations). Comparison treats all values as signed.
961    Produces a silenceable failure otherwise.
962  }];
963  let arguments = (ins TransformParamTypeInterface:$param,
964                       TransformParamTypeInterface:$reference,
965                       MatchCmpIPredicateAttr:$predicate);
966  let assemblyFormat =
967      "$predicate $param `,` $reference attr-dict `:` type($param)";
968}
969
970def MergeHandlesOp : TransformDialectOp<"merge_handles",
971    [DeclareOpInterfaceMethods<TransformOpInterface, ["allowsRepeatedHandleOperands"]>,
972     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
973     MatchOpInterface, SameOperandsAndResultType]> {
974  let summary = "Merges handles into one pointing to the union of payload ops";
975  let description = [{
976    Creates a new Transform IR handle value that points to the same Payload IR
977    operations/values/parameters as the operand handles. The Payload IR elements
978    are listed in the same order as they are in the operand handles, grouped by
979    operand handle, e.g., all Payload IR associated with the first handle comes
980    first, then all Payload IR associated with the second handle and so on. If
981    `deduplicate` is set, do not add the given Payload IR operation, value, or
982    parameter more than once to the final list regardless of it coming from the
983    same or different handles. Consumes the operands and produces a new handle.
984  }];
985
986  let arguments = (ins Variadic<Transform_AnyHandleOrParamType>:$handles,
987                       UnitAttr:$deduplicate);
988  let results = (outs Transform_AnyHandleOrParamType:$result);
989  let assemblyFormat = "(`deduplicate` $deduplicate^)? $handles attr-dict `:` type($result)";
990  let hasFolder = 1;
991}
992
993def NamedSequenceOp : TransformDialectOp<"named_sequence",
994    [FunctionOpInterface,
995     IsolatedFromAbove,
996     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
997     DeclareOpInterfaceMethods<TransformOpInterface>]> {
998  let summary = "Named transform sequence that can be included elsewhere";
999  let description = [{
1000    Defines a named (callable, function-like) sequence of other Transform
1001    dialect operations that can be included using `transform.include` as part of
1002    another Transform dialect construct. This sequence is not processed
1003    immediately but rather dispatched to when the inclusion is processed. The
1004    arguments and results can be used to communicate a subset of mapping into
1005    the named sequence. The sequence must consist of a single block and end with
1006    a `transform.yield` terminator. The operands of the terminator become the
1007    results of the `transform.include`.
1008
1009    When dispatched to, the operations in the named sequence are executed one by
1010    one, similarly to the regular unnamed sequence. The failure propagation mode
1011    is specified on the `transform.include`. Different inclusions may use
1012    different failure propagation modes. This transform operation always
1013    succeeds by itself, but the inclusion may fail if any of the operations
1014    fail.
1015
1016    Named sequences can only appear at the top-level of the Transform dialect
1017    nesting structure. That is, they cannot be nested in other Transform dialect
1018    operations. Furthermore, one of the ancestors must have the `SymbolTable`
1019    trait and have the `transform.with_named_sequence` attribute attached.
1020
1021    Named sequences may include other named sequences via `transform.include`,
1022    but recursion is *not* allowed.
1023  }];
1024
1025  let arguments = (ins
1026    SymbolNameAttr:$sym_name,
1027    TypeAttrBase<"::mlir::FunctionType",
1028                 "function type attribute">:$function_type,
1029    OptionalAttr<StrAttr>:$sym_visibility,
1030    OptionalAttr<DictArrayAttr>:$arg_attrs,
1031    OptionalAttr<DictArrayAttr>:$res_attrs);
1032  let regions = (region MaxSizedRegion<1>:$body);
1033
1034  let hasCustomAssemblyFormat = 1;
1035  let hasVerifier = 1;
1036
1037  let builders = [
1038    // Build a named sequence.
1039    OpBuilder<(ins
1040      "StringRef":$symName,
1041      "Type":$rootType,
1042      "TypeRange":$resultType,
1043      "SequenceBodyBuilderFn":$bodyBuilder,
1044      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs,
1045      CArg<"ArrayRef<DictionaryAttr>", "{}">:$argAttrs)>
1046  ];
1047
1048  let extraClassDeclaration = [{
1049    ::llvm::ArrayRef<::mlir::Type> getArgumentTypes() {
1050      return getFunctionType().getInputs();
1051    }
1052    ::llvm::ArrayRef<::mlir::Type> getResultTypes() {
1053      return getFunctionType().getResults();
1054    }
1055    ::mlir::Region *getCallableRegion() {
1056      return &getBody();
1057    }
1058  }];
1059}
1060
1061def SplitHandleOp : TransformDialectOp<"split_handle",
1062    [FunctionalStyleTransformOpTrait,
1063     DeclareOpInterfaceMethods<TransformOpInterface>,
1064     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
1065  let summary = "Splits a handle or parameter into multiple values";
1066  let description = [{
1067    Splits `handle` into one or multiple handles, as specified by the number
1068    of results of this operation. `handle` should be mapped to as many payload
1069    ops, values or parameteres as there are results. Otherwise, this transform
1070    will fail producing a silenceable failure by default. Each result handle
1071    is mapped to exactly one payload unless specified otherwise by attributes
1072    described below. The order of the payloads is preserved,  i.e., the i-th
1073    payload is mapped to the i-th result handle.
1074
1075    This operation is useful for ensuring a statically known number of
1076    payloads are tracked by the source `handle` and to extract them into
1077    individual handles that can be further manipulated in isolation.
1078
1079    If there are more payloads than results, the remaining payloads are mapped to
1080    the result with index `overflow_result`. If no `overflow_result` is
1081    specified, the transform produces a silenceable failure.
1082
1083    If there are fewer payload ops than results, the transform produces a
1084    silenceable failure if `fail_on_payload_too_small` is set to "true".
1085    Otherwise, it succeeds and the remaining result handles are not mapped to
1086    anything. It also succeeds if `handle` is empty and
1087    `pass_through_empty_handle` is set to "true", regardless of
1088    `fail_on_payload_too_small`.
1089  }];
1090
1091  let arguments = (ins Transform_AnyHandleOrParamType:$handle,
1092                       DefaultValuedAttr<BoolAttr, "true">:$pass_through_empty_handle,
1093                       DefaultValuedAttr<BoolAttr, "true">:$fail_on_payload_too_small,
1094                       OptionalAttr<I64Attr>:$overflow_result);
1095  let results = (outs Variadic<Transform_AnyHandleOrParamType>:$results);
1096  let hasVerifier = 1;
1097
1098  let builders = [
1099    OpBuilder<(ins "Value":$handle, "int64_t":$numResultHandles)>
1100  ];
1101
1102  let assemblyFormat = [{
1103    $handle attr-dict `:` functional-type(operands, results)
1104  }];
1105}
1106
1107def ParamConstantOp : Op<Transform_Dialect, "param.constant", [
1108    MatchOpInterface,
1109    DeclareOpInterfaceMethods<TransformOpInterface>,
1110    MemoryEffectsOpInterface,
1111    ParamProducerTransformOpTrait]> {
1112  let summary = "Produces a new transform dialect parameter value associated "
1113                "with the given attribute";
1114  let description = [{
1115    Produces a new transform dialect parameter associated with the singleton
1116    list containing the given attribute. The operation itself always succeeds,
1117    but the general association check may fail if the parameter type does not
1118    accept the given kind of attribute as valid.
1119  }];
1120  let arguments = (ins AnyAttr:$value);
1121  let results = (outs TransformParamTypeInterface:$param);
1122  let assemblyFormat = "$value attr-dict `->` type($param)";
1123}
1124
1125def PrintOp : TransformDialectOp<"print",
1126    [DeclareOpInterfaceMethods<TransformOpInterface>,
1127     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
1128     MatchOpInterface]> {
1129  let summary = "Dump each payload op";
1130  let description = [{
1131    Prints each payload op that is associated with the `target` operand to
1132    `stdout`. It also prints the `name` string attribute. If no target is
1133    specified, the top-level op is dumped.
1134
1135    This op is useful for printf-style debugging.
1136
1137    Supported printing flag attributes:
1138    * `assume_verified` -- skips verification when the unit attribute is
1139      specified. This improves performace but may lead to crashes and
1140      unexpected behavior when the printed payload op is invalid.
1141    * `use_local_scope` -- prints in local scope when the unit attribute is
1142      specified. This improves performance but may not be identical to
1143      printing within the full module.
1144    * `skip_regions` -- does not print regions of operations when the unit
1145      attribute is specified.
1146  }];
1147
1148  let arguments = (ins Optional<TransformHandleTypeInterface>:$target,
1149                       OptionalAttr<StrAttr>:$name,
1150                       OptionalAttr<UnitAttr>:$assume_verified,
1151                       OptionalAttr<UnitAttr>:$use_local_scope,
1152                       OptionalAttr<UnitAttr>:$skip_regions);
1153  let results = (outs);
1154
1155  let builders = [
1156    OpBuilder<(ins CArg<"StringRef", "StringRef()">:$name)>,
1157    OpBuilder<(ins "Value":$target, CArg<"StringRef", "StringRef()">:$name)>
1158  ];
1159
1160  let assemblyFormat = "$target attr-dict (`:` type($target)^)?";
1161}
1162
1163def ReplicateOp : TransformDialectOp<"replicate",
1164    [DeclareOpInterfaceMethods<TransformOpInterface>,
1165     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
1166     AllTypesMatch<["handles", "replicated"]>]> {
1167  let summary = "Lists payload ops multiple times in the new handle";
1168  let description = [{
1169    Produces a new handle associated with a list of payload IR ops that is
1170    computed by repeating the list of payload IR ops associated with the
1171    operand handle as many times as the "pattern" handle has associated
1172    operations. For example, if pattern is associated with [op1, op2] and the
1173    operand handle is associated with [op3, op4, op5], the resulting handle
1174    will be associated with [op3, op4, op5, op3, op4, op5].
1175
1176    This transformation is useful to "align" the sizes of payload IR lists
1177    before a transformation that expects, e.g., identically-sized lists. For
1178    example, a transformation may be parameterized by same notional per-target
1179    size computed at runtime and supplied as another handle, the replication
1180    allows this size to be computed only once and used for every target instead
1181    of replicating the computation itself.
1182
1183    Note that it is undesirable to pass a handle with duplicate operations to
1184    an operation that consumes the handle. Handle consumption often indicates
1185    that the associated payload IR ops are destroyed, so having the same op
1186    listed more than once will lead to double-free. Single-operand
1187    MergeHandlesOp may be used to deduplicate the associated list of payload IR
1188    ops when necessary. Furthermore, a combination of ReplicateOp and
1189    MergeHandlesOp can be used to construct arbitrary lists with repetitions.
1190  }];
1191
1192  let arguments = (ins TransformHandleTypeInterface:$pattern,
1193                       Variadic<Transform_AnyHandleOrParamType>:$handles);
1194  let results = (outs Variadic<Transform_AnyHandleOrParamType>:$replicated);
1195  let assemblyFormat = "`num` `(` $pattern `)` $handles attr-dict `:` "
1196                       "type($pattern) `,` type($handles)";
1197}
1198
1199def SelectOp : TransformDialectOp<"select",
1200    [DeclareOpInterfaceMethods<TransformOpInterface>,
1201     NavigationTransformOpTrait, MemoryEffectsOpInterface]> {
1202  let summary = "Select payload ops by name";
1203  let description = [{
1204    The handle defined by this Transform op corresponds to all operations among
1205    `target` that have the specified properties. Currently the following
1206    properties are supported:
1207
1208    - `op_name`: The op must have the specified name.
1209
1210    The result payload ops are in the same relative order as the targeted ops.
1211    This transform op reads the `target` handle and produces the `result`
1212    handle. It reads the payload, but does not modify it.
1213  }];
1214
1215  let arguments = (ins TransformHandleTypeInterface:$target,
1216                       StrAttr:$op_name);
1217  let results = (outs TransformHandleTypeInterface:$result);
1218  let assemblyFormat = [{
1219    $op_name `in` $target attr-dict `:` functional-type(operands, results)
1220  }];
1221}
1222
1223def SequenceOp : TransformDialectOp<"sequence",
1224    [DeclareOpInterfaceMethods<RegionBranchOpInterface,
1225        ["getEntrySuccessorOperands", "getSuccessorRegions",
1226         "getRegionInvocationBounds"]>,
1227     MatchOpInterface,
1228     DeclareOpInterfaceMethods<TransformOpInterface>,
1229     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
1230     OpAsmOpInterface, PossibleTopLevelTransformOpTrait,
1231     SingleBlockImplicitTerminator<"::mlir::transform::YieldOp">,
1232     AttrSizedOperandSegments]> {
1233  let summary = "Contains a sequence of other transform ops to apply";
1234  let description = [{
1235    The transformations indicated by the sequence are applied in order of their
1236    appearance. Each value produced by a transformation within the sequence
1237    corresponds to a group of operations or values in the payload IR, or to a
1238    group of parameters, depending on the type of the value. The behavior of the
1239    operation when a nested transformation produces a silenceable error is
1240    controlled by the `failure_propagation_mode` attribute. When set to
1241    `propagate`, the failure of any nested transformation in the sequence
1242    implies immediate failure of the entire sequence with a silenceable error,
1243    and no further transformation is attempted. When set to `suppress`,
1244    silenceable errors in nested operations are ignored and further
1245    transformations are applied. Beware that even silenceable errors may leave
1246    the payload IR in a state unsuitable for further transformations. It is the
1247    responsibility of the caller to ensure the following transformations are
1248    robust enough when errors are suppressed. Definite errors reported by nested
1249    transformations abort the sequence regardless of the propagation mode. The
1250    set of modes may be extended in the future, e.g., to collect silenceable
1251    errors and report them after attempting all transformations in the sequence.
1252
1253    The entry block of this operation has a single argument that maps to either
1254    the operand if provided or the top-level container operation of the payload
1255    IR, typically the root operation of the pass interpreting the transform
1256    dialect. Operand omission is only allowed for sequences not contained in
1257    another sequence.
1258
1259    The type of the block argument must match the type of the operand. If the
1260    sequence is a top-level transform (without an operand), it can be used for
1261    matching operations if the specified type within the top-level container
1262    payload IR (including the container op itself). E.g.:
1263
1264    ```mlir
1265    transform.sequence failures(propagate) {
1266    ^bb1(%arg1: !transform.any_op):
1267      // %arg1 is mapped to the top-level container of the payload IR, which is
1268      // typically a module
1269    }
1270
1271    transform.sequence failures(propagate) {
1272    ^bb1(%arg1: !transform.op<"func.func>"):
1273      // %arg1 is mapped to all "func.func" ops within and including the
1274      // top-level container of the payload IR. Nested operations that have the
1275      // specified op type are not included.
1276    }
1277    ```
1278
1279    The body of the sequence terminates with an implicit or explicit
1280    `transform.yield` op. The operands of the terminator are returned as the
1281    results of the sequence op.
1282  }];
1283
1284  let arguments = (ins FailurePropagationMode:$failure_propagation_mode,
1285                       Optional<TransformHandleTypeInterface>:$root,
1286                       Variadic<Transform_AnyHandleOrParamType>:$extra_bindings);
1287  let results = (outs Variadic<TransformHandleTypeInterface>:$results);
1288  let regions = (region SizedRegion<1>:$body);
1289
1290  let assemblyFormat =
1291    "custom<SequenceOpOperands>($root, type($root), $extra_bindings, type($extra_bindings))"
1292    " (`->` type($results)^)? `failures` `(` "
1293    "$failure_propagation_mode `)` attr-dict-with-keyword regions";
1294
1295  let builders = [
1296    // Build a sequence with a root.
1297    OpBuilder<(ins
1298        "::mlir::TypeRange":$resultTypes,
1299        "::mlir::transform::FailurePropagationMode":$failure_propagation_mode,
1300        "::mlir::Value":$root, "SequenceBodyBuilderFn":$bodyBuilder)>,
1301
1302    // Build a sequence with a root and additional arguments.
1303    OpBuilder<(ins
1304        "::mlir::TypeRange":$resultTypes,
1305        "::mlir::transform::FailurePropagationMode":$failure_propagation_mode,
1306        "::mlir::Value":$root, "::mlir::ValueRange":$extraBindings,
1307        "SequenceBodyBuilderArgsFn":$bodyBuilder)>,
1308
1309    // Build a top-level sequence (no root).
1310    OpBuilder<(ins
1311        "::mlir::TypeRange":$resultTypes,
1312        "::mlir::transform::FailurePropagationMode":$failure_propagation_mode,
1313        "::mlir::Type":$bbArgType, "SequenceBodyBuilderFn":$bodyBuilder)>,
1314
1315    // Build a top-level sequence (no root) with extra arguments.
1316    OpBuilder<(ins
1317        "::mlir::TypeRange":$resultTypes,
1318        "::mlir::transform::FailurePropagationMode":$failure_propagation_mode,
1319        "::mlir::Type":$bbArgType, "::mlir::TypeRange":$extraBindingTypes,
1320        "SequenceBodyBuilderArgsFn":$bodyBuilder)>
1321  ];
1322
1323  let extraClassDeclaration = [{
1324    /// Allow the dialect prefix to be omitted.
1325    static StringRef getDefaultDialect() { return "transform"; }
1326  }];
1327
1328  let hasVerifier = 1;
1329}
1330
1331def VerifyOp : TransformDialectOp<"verify",
1332    [TransformOpInterface, TransformEachOpTrait,
1333     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
1334     ReportTrackingListenerFailuresOpTrait]> {
1335  let summary = "Verifies the targeted ops";
1336  let description = [{
1337    This transform verifies the targeted ops. If at least one op fails to
1338    verify, the transform produces a definite failure.
1339
1340    Note: This op was designed for debugging purposes and should be used like an
1341    assertion. It is intentional that this op produces a definite failure and
1342    not a silenceable one. Correctness of the program should not depend on this
1343    op.
1344
1345    This transform reads the target handle.
1346  }];
1347
1348  let arguments = (ins TransformHandleTypeInterface:$target);
1349  let results = (outs);
1350  let assemblyFormat = "$target attr-dict `:` type($target)";
1351
1352  let extraClassDeclaration = [{
1353    ::mlir::DiagnosedSilenceableFailure applyToOne(
1354      ::mlir::transform::TransformRewriter &rewriter,
1355      ::mlir::Operation *target,
1356      ::mlir::transform::ApplyToEachResultList &results,
1357      ::mlir::transform::TransformState &state);
1358  }];
1359}
1360
1361def YieldOp : TransformDialectOp<"yield",
1362    [Terminator, DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
1363  let summary = "Yields operation handles from a transform IR region";
1364  let description = [{
1365    This terminator operation yields operation handles from regions of the
1366    transform IR ops back to the containing op. It is not itself associated with
1367    any transformation on the payload IR and is used for flow purposes only.
1368  }];
1369
1370  let arguments = (ins
1371    Arg<Variadic<Transform_AnyHandleOrParamType>,
1372        "Transform values yielded back to the parent"
1373        >:$operands);
1374  let assemblyFormat = "operands attr-dict (`:` type($operands)^)?";
1375
1376  let builders = [
1377    OpBuilder<(ins), [{
1378      return build($_builder, $_state, ::mlir::ValueRange());
1379    }]>
1380  ];
1381}
1382
1383#endif // MLIR_DIALECT_TRANSFORM_IR_TRANSFORMOPS
1384