-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[mlir][bufferization] Empty tensor elimination for materialize_in_destination #65468
[mlir][bufferization] Empty tensor elimination for materialize_in_destination #65468
Conversation
%buffer = tensor.empty(%sz) : tensor<?xf32> | ||
// CHECK: bufferization.materialize_in_destination | ||
// CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]} | ||
%r = bufferization.materialize_in_destination %buffer in %buffer : tensor<?xf32> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might be missing the point of this test, but why is %buffer
both src and dst here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point of the test is that no OpOperand of this op should bufferize out-of-place. In that case, we would end up with 2 memcpy, when in fact there should be no memcpys (because source and destination are the same).
This is essentially a test for the BufferizableOpInterface
implementation of MaterializeInDestinationOp
. (Ops that read and write two tensors via separate are usually seen as a RaW conflict and bufferize out-of-place.)
mlir/include/mlir/Dialect/Bufferization/IR/InferDestinationOpInterface.td
Outdated
Show resolved
Hide resolved
mlir/include/mlir/Dialect/Bufferization/IR/InferDestinationOpInterface.td
Outdated
Show resolved
Hide resolved
let description = [{ | ||
This interface can be implemented by ops that read data from an "input" | ||
tensor and store the result into an "output"/"init" tensor (i.e., the | ||
"destination" tensor). It drives the empty tensor elimination pass. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would you say the tensor elimination pass would be the only use for this interface? Or do you think this will have other uses later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original version of this interface was used only for empty tensor elimination. The new SubsetOpInterface is also used by One-Shot Analysis. In the future, it could also be used by the tiling infrastructure (and then move to mlir/Interfaces
).
42cf0d2
to
cd1eaae
Compare
I rewrote large parts of this stack of commits. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
most of my questions/comments are about isEquivalentSubset
. Obviously I'm having a hard time understanding the structure for this, so I'm hoping to get some clarity on it
mlir/include/mlir/Dialect/Bufferization/IR/SubsetOpInterface.td
Outdated
Show resolved
Hide resolved
/*methodName=*/"isEquivalentSubset", | ||
/*args=*/(ins | ||
"::mlir::Value":$candidate, | ||
"::llvm::function_ref<bool(Value, Value)>":$equivalenceFn) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you explain what equivalenceFn
is in the description. It's unclear to me whether the main logic for determining equivalent subset should be in equivalenceFn
or isEquivalentSubset
. Maybe I'm just missing something, but seems awkward to have both
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I expanded the description in #65619. equivalenceFn
returns "true" if two values are equivalent. When used in One-Shot Bufferize, I use AnalysisState::areEquivalentBufferizedValues
as equivalenceFn
. I didn't want to make this interface dependent on other bufferization stuff (such as AnalysisState
), so that it can be moved to mlir/Interfaces
in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there's context I'm missing since I'm new to some of this stuff, so I won't harp on this much longer. But I guess I still don't see the need for the hook. Why can't isEquivalentSubset
be implemented without it? For example, the default could be
bool isEquivalentSubset(Value candidate) {
return getSubset() == candidate;
}
(sorry if this is a naive question)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would work for bufferization.materialize_in_destination
because the subset is simply the destination tensor. But getSubset
may build new IR. E.g., for tensor.insert_slice
, it will build a new tensor.extract_slice
op and return that one. I'm going to rename getSubset
to buildSubset
.
bool isSameSubset(OpResult candidate) { | ||
return cast<::mlir::bufferization::SubsetOpInterface>(getOperation()) | ||
.isEquivalentSubset(candidate, | ||
[](Value v1, Value v2) { return v1 == v2; }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems a little clunky to solely use isEquivalentSubset
for determining if "same". I understand that two subsets are "same" only if they are equivalent, so it makes sense to use isEquivalentSubset
as part of the logic for this function. But it seems like you're trying to shove the extra logic for "same" into the equivalencFn
hook. Although I may be getting this wrong as I'm not entirely sure of the purpose of the hook (see comment above).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to make equivalenceFn
optional with [](Value v1, Value v2) { return v1 == v2; }
as as default value for the parameter. But interface methods cannot have optional parameters, so I had to add another function. (Note this is not an InterfaceMethod and cannot be implemented.)
v1 == v2
is the simplest kind of equivalence function. isSameSubset
can be used when no equivalence information (e.g., in the form of an AnalysisState
) is available.
} | ||
} // namespace | ||
|
||
struct InsertSliceOpSubsetOpInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this is used to attach an interface to InsertSliceOp
, which I admit I'm unfamiliar with attaching interfaces. So this is probably a dumb question, but why not just add the SubsetOpInterface
trait to the InsertSliceOp
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is so that the MLIRTensorDialect
build target does not have to depend on MLIRBufferizationDialect
. That's also why the BufferizableOpInterface
implementations in this file are implemented as external models. It also keeps TensorOps.cpp
and TensorOps.td
a bit simpler.
cd1eaae
to
e3cabda
Compare
mlir/include/mlir/Dialect/Bufferization/IR/InferDestinationOpInterface.td
Outdated
Show resolved
Hide resolved
…tination This revision adds support for empty tensor elimination to "bufferization.materialize_in_destination" by implementing the `InferDestinationOpInterface`. Furthermore, the One-Shot Bufferize conflict detection is improved for "bufferization.materialize_in_destination".
e3cabda
to
ebaf883
Compare
…tination (llvm#65468) This revision adds support for empty tensor elimination to "bufferization.materialize_in_destination" by implementing the `SubsetInsertionOpInterface`. Furthermore, the One-Shot Bufferize conflict detection is improved for "bufferization.materialize_in_destination".
…tination (llvm#65468) This revision adds support for empty tensor elimination to "bufferization.materialize_in_destination" by implementing the `SubsetInsertionOpInterface`. Furthermore, the One-Shot Bufferize conflict detection is improved for "bufferization.materialize_in_destination".
…tination (llvm#65468) This revision adds support for empty tensor elimination to "bufferization.materialize_in_destination" by implementing the `SubsetInsertionOpInterface`. Furthermore, the One-Shot Bufferize conflict detection is improved for "bufferization.materialize_in_destination".
This revision adds support for empty tensor elimination to "bufferization.materialize_in_destination" by implementing the
SubsetOpInterface
.Furthermore, the One-Shot Bufferize conflict detection is improved for "bufferization.materialize_in_destination".