-
Notifications
You must be signed in to change notification settings - Fork 10.8k
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] Add deallocation option to remove existing dealloc operations, add option to specify the kind of alloc operations to consider #67556
base: main
Are you sure you want to change the base?
Conversation
…ction boundary ABI Inserting clones requires a lot of assumptions to hold on the input IR, e.g., all writes to a buffer need to dominate all reads. This is not guaranteed by one-shot bufferization and isn't easy to verify, thus it could quickly lead to incorrect results that are hard to debug. This commit changes the mechanism of how an ownership indicator is materialized when there is not already a unique ownership present. Additionally, we don't create copies of returned memrefs anymore when we don't have ownership. Instead, we insert assert operations to make sure we have ownership at runtime, or otherwise report to the user that correctness could not be guaranteed.
…loc operations, add option to specify the kind of alloc operations to consider
c2d180a
to
590efce
Compare
/// ownership will be set to 'false', i.e., it will be leaked. This is useful | ||
/// to support deallocation of multiple different kinds of allocation ops. | ||
DetectionFn isRelevantAllocOp = [](Operation *op) { | ||
return isa<memref::MemRefDialect, bufferization::BufferizationDialect>( |
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.
Why is the bufferization dialect in here? Can we just check for memref.alloc/memref.alloca in 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.
BufferizationDialect
is here because of bufferization.clone
which has an allocation side-effect as well.
@@ -106,6 +111,48 @@ struct DeallocationOptions { | |||
/// to, an error will already be emitted at compile time. This cannot be | |||
/// changed with this option. | |||
bool verifyFunctionBoundaryABI = true; | |||
|
|||
/// Given an allocation side-effect on the passed operation, determine whether |
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.
Given an operation with an allocation side effect
op->getDialect()); | ||
}; | ||
|
||
/// Given a free side-effect on the passed operation, determine whether this |
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.
Given an operation with a free side effect
PassOptions::Option<bool> removeExistingDeallocations{ | ||
*this, "remove-existing-deallocations", | ||
llvm::cl::desc("Removes all pre-existing memref.dealloc operations and " | ||
"insert all deallocations according to the buffer " |
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 think just Removes pre-existing memref.dealloc operations
should be enough.
@@ -233,6 +233,11 @@ def OwnershipBasedBufferDeallocation : Pass< | |||
"If it can be determined statically that the ABI is not adhered " | |||
"to, an error will already be emitted at compile time. This cannot " | |||
"be changed with this option.">, | |||
Option<"removeExistingDeallocations", "remove-existing-deallocations", | |||
"bool", /*default=*/"false", | |||
"Remove already existing MemRef deallocation operations and let the " |
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.
same here
} | ||
|
||
// Alloc operations from other dialects are expected to have matching | ||
// deallocation operations inserted by another 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.
inserted by a separate run of this pass
|
||
OpBuilder builder = OpBuilder::atBlockBegin(block); | ||
for (auto res : llvm::make_filter_range(op->getResults(), isMemref)) { | ||
auto allocEffect = op.getEffectOnValue<MemoryEffects::Allocate>(res); | ||
if (allocEffect.has_value()) { | ||
// Assuming that an alloc effect is interpreted as MUST and not MAY. | ||
state.resetOwnerships(res, block); |
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.
What is this doing?
|
||
WalkResult result = getOperation()->walk([&](FunctionOpInterface funcOp) { | ||
// Deallocate the `memref.alloc` operations. | ||
bufferization::DeallocationOptions options; |
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.
Add comment that by default the deallocation options are configured to look for memref.alloc/memref.dealloc only.
} | ||
return ValueRange{}; | ||
} | ||
return failure(); |
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 be llvm_unreachable("expected gpu.dealloc op")
? Then you could also make the gpuDealloc
a cast<DeallocOp>
and you won't need the "if" check.
Depends on #66626
Only review top commit.