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