xref: /llvm-project/mlir/include/mlir/Dialect/Bufferization/TransformOps/BufferizationTransformOps.td (revision d58637219463924185614f18911c5f01a1c20aa9)
1//===- BufferizationTransformOps.td - Buff. transf. ops ----*- 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 BUFFERIZATION_TRANSFORM_OPS
10#define BUFFERIZATION_TRANSFORM_OPS
11
12include "mlir/Dialect/Bufferization/IR/BufferizationEnums.td"
13include "mlir/Dialect/Transform/IR/TransformDialect.td"
14include "mlir/Dialect/Transform/Interfaces/TransformInterfaces.td"
15include "mlir/Dialect/Transform/IR/TransformTypes.td"
16include "mlir/Interfaces/SideEffectInterfaces.td"
17include "mlir/IR/OpBase.td"
18
19def Transform_EmptyOp : Transform_ConcreteOpType<"tensor.empty">;
20def Transform_AllocTensorOp : Transform_ConcreteOpType<"bufferization.alloc_tensor">;
21
22//===----------------------------------------------------------------------===//
23// BufferLoopHoistingOp
24//===----------------------------------------------------------------------===//
25
26def BufferLoopHoistingOp
27    : Op<Transform_Dialect, "bufferization.buffer_loop_hoisting",
28        [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
29         TransformEachOpTrait, TransformOpInterface]> {
30  let description = [{
31    Hoist buffer allocations ("memref.alloc" and "memref.alloca") from loops
32    within the targeted op. This transform assumes that there are no buffer
33    deallocation ops in the IR.
34
35    This transform reads the `target` handle and modifies the payload.
36  }];
37
38  let arguments = (ins TransformHandleTypeInterface:$target);
39  let results = (outs);
40  let assemblyFormat = "$target attr-dict `:` type($target)";
41
42  let extraClassDeclaration = [{
43    ::mlir::DiagnosedSilenceableFailure applyToOne(
44        ::mlir::transform::TransformRewriter &rewriter,
45        ::mlir::Operation *target,
46        ::mlir::transform::ApplyToEachResultList &results,
47        ::mlir::transform::TransformState &state);
48  }];
49}
50
51//===----------------------------------------------------------------------===//
52// OneShotBufferizeOp
53//===----------------------------------------------------------------------===//
54
55def OneShotBufferizeOp
56    : Op<Transform_Dialect, "bufferization.one_shot_bufferize",
57        [FunctionalStyleTransformOpTrait, MemoryEffectsOpInterface,
58         DeclareOpInterfaceMethods<TransformOpInterface>]> {
59  let description = [{
60    Indicates that the given `target` op should be bufferized with One-Shot
61    Bufferize. The bufferization can be configured with various attributes that
62    corresponding to options in `BufferizationOptions` and the
63    `one-shot-bufferize` pass. More information can be found in the pass
64    documentation.
65
66    The targeted ops must be modules or functions. This is because there is
67    always a single, bufferized replacement op for such targets.
68
69    Note: Only ops that implement `BufferizableOpInterface` are bufferized. All
70    other ops are ignored if `allow_unknown_ops`. If `allow_unknown_ops` is
71    unset, this transform fails when an unknown/non-bufferizable op is found.
72    Many ops implement `BufferizableOpInterface` via an external model. These
73    external models must be registered when applying this transform op;
74    otherwise, said ops would be considered non-bufferizable.
75
76    #### Return modes
77
78    This operation consumes the `target` handle and produces the `transformed`
79    handle.
80  }];
81
82  let arguments = (
83      ins TransformHandleTypeInterface:$target,
84      OptionalAttr<LayoutMapOption>:$function_boundary_type_conversion,
85      DefaultValuedAttr<BoolAttr, "false">:$allow_return_allocs_from_loops,
86      DefaultValuedAttr<BoolAttr, "false">:$allow_unknown_ops,
87      DefaultValuedAttr<BoolAttr, "false">:$bufferize_function_boundaries,
88      DefaultValuedAttr<BoolAttr, "false">:$dump_alias_sets,
89      DefaultValuedAttr<BoolAttr, "false">:$test_analysis_only,
90      DefaultValuedAttr<BoolAttr, "false">:$print_conflicts,
91      DefaultValuedAttr<BoolAttr, "true">:$check_parallel_regions,
92      DefaultValuedAttr<StrAttr, "\"memref.copy\"">:$memcpy_op);
93
94  let results = (outs TransformHandleTypeInterface:$transformed);
95
96  let hasVerifier = 1;
97  let assemblyFormat = [{
98    (`layout` `{` $function_boundary_type_conversion^ `}`)?
99    $target attr-dict `:` functional-type($target, results)
100  }];
101}
102
103//===----------------------------------------------------------------------===//
104// EliminateEmptyTensorsOp
105//===----------------------------------------------------------------------===//
106
107def EliminateEmptyTensorsOp
108    : Op<Transform_Dialect, "bufferization.eliminate_empty_tensors",
109        [DeclareOpInterfaceMethods<TransformOpInterface>,
110         DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
111  let description = [{
112    Try to eliminate all `tensor.empty` ops within the targeted op by replacing
113    them with another destination tensor.
114
115    "tensor.empty" ops cannot be bufferized. They can either be converted to
116    "bufferization.alloc_tensor" or replaced with another tensor (via this
117    transform). "tensor.empty" does not specify the contents of the returned
118    tensor so their results can be replaced with arbitrary tensor values as long
119    as the dimensions match.
120
121    This transformation looks for subset ops that insert a tensor that
122    originates from a "tensor.empty" (as per the reverse use-def chain). Such
123    "tensor.empty" ops are replaced with the destination subset.
124
125    Example:
126
127    ```
128    %0 = tensor.empty() : tensor<5xf32>
129    %1 = linalg.fill ... outs(%0)
130    %2 = tensor.insert_slice %1 into %t[1][5][1]
131    ```
132
133    Is rewritten with:
134    ```
135    %0 = tensor.extract_slice %t[1][5][1]
136    %1 = linalg.fill ... outs(%0)
137    %2 = tensor.insert_slice %1 into %t[1][5][1]
138    ```
139
140    In the above example, the subset op is "tensor.insert_slice". When tracing
141    back the reverse use-def chain of a the source, we end up at a
142    "tensor.empty" op.
143
144    The above example can bufferize without an allocation (in the absence of
145    other conflicts) because there is no longer a `tensor.empty` op.
146
147    See `-eliminate-empty-tensors` for more details.
148
149    #### Return modes
150
151    This transform reads the target handle and modifies the payload. It does
152    not produce any handle.
153  }];
154
155  let arguments = (ins TransformHandleTypeInterface:$target);
156
157  let results = (outs);
158
159  let assemblyFormat = "$target attr-dict `:` type($target)";
160}
161
162//===----------------------------------------------------------------------===//
163// EmptyTensorToAllocTensorOp
164//===----------------------------------------------------------------------===//
165
166def EmptyTensorToAllocTensorOp
167    : Op<Transform_Dialect, "bufferization.empty_tensor_to_alloc_tensor",
168        [FunctionalStyleTransformOpTrait,
169         MemoryEffectsOpInterface,
170         TransformOpInterface,
171         TransformEachOpTrait]> {
172  let description = [{
173    Replace a tensor.empty with a bufferization.tensor_alloc.
174
175    #### Return modes
176
177    This operation consumes the `target` handle and produces the `transformed`
178    handle. `target` is expected to be a `tensor.empty` operation. The transform
179    always succeeds.
180  }];
181
182  let arguments = (ins Transform_EmptyOp:$target);
183  let results = (outs Transform_AllocTensorOp:$transformed);
184
185  let assemblyFormat = "$target attr-dict `:` functional-type(operands, results)";
186
187  let extraClassDeclaration = [{
188    ::mlir::DiagnosedSilenceableFailure applyToOne(
189        ::mlir::transform::TransformRewriter &rewriter,
190        ::mlir::tensor::EmptyOp target,
191        ::mlir::transform::ApplyToEachResultList &results,
192        ::mlir::transform::TransformState &state);
193  }];
194}
195
196#endif // BUFFERIZATION_TRANSFORM_OPS
197