Skip to content

Commit b00ee46

Browse files
[mlir][bufferize][NFC] Implement BufferizableOpInterface on bufferization ops directly
No longer go through an external model. Also put BufferizableOpInterface into the same build target as the BufferizationDialect. This allows for some code reuse between BufferizationOps canonicalizers and BufferizableOpInterface implementations. Differential Revision: https://reviews.llvm.org/D117987
1 parent b8c7cdc commit b00ee46

File tree

17 files changed

+198
-286
lines changed

17 files changed

+198
-286
lines changed

mlir/include/mlir/Dialect/Bufferization/IR/Bufferization.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define MLIR_DIALECT_BUFFERIZATION_IR_BUFFERIZATION_H_
1111

1212
#include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.h"
13+
#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
1314
#include "mlir/Dialect/MemRef/IR/MemRef.h"
1415
#include "mlir/Dialect/Tensor/IR/Tensor.h"
1516

mlir/include/mlir/Dialect/Bufferization/IR/BufferizationInterfaceImpl.h

Lines changed: 0 additions & 25 deletions
This file was deleted.

mlir/include/mlir/Dialect/Bufferization/IR/BufferizationOps.td

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define BUFFERIZATION_OPS
1111

1212
include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.td"
13+
include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.td"
1314
include "mlir/Dialect/Bufferization/IR/BufferizationBase.td"
1415
include "mlir/Interfaces/SideEffectInterfaces.td"
1516
include "mlir/Interfaces/CopyOpInterface.td"
@@ -64,11 +65,14 @@ def Bufferization_CloneOp : Bufferization_Op<"clone", [
6465
// ToTensorOp
6566
//===----------------------------------------------------------------------===//
6667

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+
]> {
7276
let summary = "memref to tensor operation";
7377
let description = [{
7478
Create a tensor from a memref, making an independent copy of the element
@@ -110,6 +114,35 @@ def Bufferization_ToTensorOp : Bufferization_Op<"to_tensor",
110114
return resultType.cast<TensorType>();
111115
return {};
112116
}
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+
}
113146
}];
114147

115148
let assemblyFormat = "$memref attr-dict `:` type($memref)";
@@ -123,11 +156,15 @@ def Bufferization_ToTensorOp : Bufferization_Op<"to_tensor",
123156
// ToMemrefOp
124157
//===----------------------------------------------------------------------===//
125158

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+
]> {
131168
let summary = "tensor to memref cast operation";
132169
let description = [{
133170
Casts a tensor to a memref.
@@ -150,6 +187,44 @@ def Bufferization_ToMemrefOp : Bufferization_Op<"to_memref",
150187
// This op is fully verified by traits.
151188
let verifier = ?;
152189

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+
153228
let assemblyFormat = "$tensor attr-dict `:` type($memref)";
154229

155230
let hasFolder = 1;

mlir/lib/Dialect/Bufferization/IR/BufferizationInterfaceImpl.cpp

Lines changed: 0 additions & 127 deletions
This file was deleted.

0 commit comments

Comments
 (0)