10
10
#define BUFFERIZATION_OPS
11
11
12
12
include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.td"
13
+ include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.td"
13
14
include "mlir/Dialect/Bufferization/IR/BufferizationBase.td"
14
15
include "mlir/Interfaces/SideEffectInterfaces.td"
15
16
include "mlir/Interfaces/CopyOpInterface.td"
@@ -64,11 +65,14 @@ def Bufferization_CloneOp : Bufferization_Op<"clone", [
64
65
// ToTensorOp
65
66
//===----------------------------------------------------------------------===//
66
67
67
- def Bufferization_ToTensorOp : Bufferization_Op<"to_tensor",
68
- [SameOperandsAndResultShape, SameOperandsAndResultElementType,
69
- TypesMatchWith<"result type matches tensor equivalent of 'memref'",
70
- "memref", "result",
71
- "memref::getTensorTypeFromMemRefType($_self)">]> {
68
+ def Bufferization_ToTensorOp : Bufferization_Op<"to_tensor", [
69
+ BufferizableOpInterface,
70
+ SameOperandsAndResultShape,
71
+ SameOperandsAndResultElementType,
72
+ TypesMatchWith<"result type matches tensor equivalent of 'memref'",
73
+ "memref", "result",
74
+ "memref::getTensorTypeFromMemRefType($_self)">
75
+ ]> {
72
76
let summary = "memref to tensor operation";
73
77
let description = [{
74
78
Create a tensor from a memref, making an independent copy of the element
@@ -110,6 +114,35 @@ def Bufferization_ToTensorOp : Bufferization_Op<"to_tensor",
110
114
return resultType.cast<TensorType>();
111
115
return {};
112
116
}
117
+
118
+ //===------------------------------------------------------------------===//
119
+ // BufferizableOpInterface implementation
120
+ //===------------------------------------------------------------------===//
121
+
122
+ // ToTensorOp conceptually loads a tensor from a memory location. The
123
+ // One-Shot analysis has no information about the memref that is loaded from
124
+ // by ToTensorOp. We have to assume that the loaded tensor may after
125
+ // bufferization potentially alias with any other bufferized tensor. Since
126
+ // ToTensorOp and ToMemrefOp have no aliasing OpOperand/OpResult pairs, this
127
+ // cannot be encoded directly in the analysis. However, declaring ToTensorOp
128
+ // results as not writable enforces a buffer copy and has the same effect.
129
+
130
+ LogicalResult bufferize(RewriterBase &rewriter,
131
+ const BufferizationState &state) const {
132
+ // to_tensor cannot be bufferized. However, other ops that are using
133
+ // to_tensor's result will eventually be bufferized. At that point, they
134
+ // will start using to_tensor's memref operand. Once all users of
135
+ // to_tensor are bufferized, the op will not have any users anymore and
136
+ // DCE away. In case of partial bufferization, to_memref(to_tensor(x))
137
+ // constructs may be left over. These are folded by the canonicalizer or
138
+ // FinalizingBufferize.
139
+ return failure();
140
+ }
141
+
142
+ bool isWritable(Value value, const BufferizationState &state) const {
143
+ // It is unknown whether the memref operand is writable or not.
144
+ return false;
145
+ }
113
146
}];
114
147
115
148
let assemblyFormat = "$memref attr-dict `:` type($memref)";
@@ -123,11 +156,15 @@ def Bufferization_ToTensorOp : Bufferization_Op<"to_tensor",
123
156
// ToMemrefOp
124
157
//===----------------------------------------------------------------------===//
125
158
126
- def Bufferization_ToMemrefOp : Bufferization_Op<"to_memref",
127
- [SameOperandsAndResultShape, SameOperandsAndResultElementType, NoSideEffect,
128
- TypesMatchWith<"type of 'tensor' is the tensor equivalent of 'memref'",
129
- "memref", "tensor",
130
- "memref::getTensorTypeFromMemRefType($_self)">]> {
159
+ def Bufferization_ToMemrefOp : Bufferization_Op<"to_memref", [
160
+ BufferizableOpInterface,
161
+ SameOperandsAndResultShape,
162
+ SameOperandsAndResultElementType,
163
+ NoSideEffect,
164
+ TypesMatchWith<"type of 'tensor' is the tensor equivalent of 'memref'",
165
+ "memref", "tensor",
166
+ "memref::getTensorTypeFromMemRefType($_self)">
167
+ ]> {
131
168
let summary = "tensor to memref cast operation";
132
169
let description = [{
133
170
Casts a tensor to a memref.
@@ -150,6 +187,44 @@ def Bufferization_ToMemrefOp : Bufferization_Op<"to_memref",
150
187
// This op is fully verified by traits.
151
188
let verifier = ?;
152
189
190
+ let extraClassDeclaration = [{
191
+ //===------------------------------------------------------------------===//
192
+ // BufferizableOpInterface implementation
193
+ //===------------------------------------------------------------------===//
194
+
195
+ // Note: ToMemrefOp / ToTensorOp are temporary ops that are inserted at the
196
+ // bufferization boundary. When One-Shot bufferization is complete, there
197
+ // should be no such ops left over. If `allowUnknownOps` (or after running a
198
+ // partial bufferization pass), such ops may be part of the resulting IR,
199
+ // but such IR may no longer be analyzable by One-Shot analysis.
200
+
201
+ bool bufferizesToMemoryRead(OpOperand &opOperand,
202
+ const BufferizationState &state) const {
203
+ // It is unknown whether the resulting memref will be read or not.
204
+ return true;
205
+ }
206
+
207
+ bool bufferizesToMemoryWrite(OpOperand &opOperand,
208
+ const BufferizationState &state) const {
209
+ // It is unknown whether the resulting MemRef will be written or not.
210
+ return true;
211
+ }
212
+
213
+ bool mustBufferizeInPlace(OpOperand &opOperand,
214
+ const BufferizationState &state) const {
215
+ // ToMemrefOps always bufferize inplace.
216
+ return true;
217
+ }
218
+
219
+ OpResult getAliasingOpResult(OpOperand &opOperand,
220
+ const BufferizationState &state) const {
221
+ return OpResult();
222
+ }
223
+
224
+ LogicalResult bufferize(RewriterBase &rewriter,
225
+ const BufferizationState &state);
226
+ }];
227
+
153
228
let assemblyFormat = "$tensor attr-dict `:` type($memref)";
154
229
155
230
let hasFolder = 1;
0 commit comments