-
Notifications
You must be signed in to change notification settings - Fork 17
[Transform] Only use gc runtime allocator for stack-like alloca ops #287
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
Changes from 1 commit
71e675b
bd4d269
2329aff
8a7f5c4
dda790d
cf4ad61
d2ed37f
2cf5dcf
d987fa2
6ff8ef8
87a51b1
3fdce87
9494fdc
6668da9
280ca6c
06a580e
5ba2a01
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -77,6 +77,7 @@ struct ConvertMemRefToCPURuntime | |
auto *ctx = &getContext(); | ||
// Create a local set to store operations that should not be transformed. | ||
llvm::SmallSet<Operation *, 16> noTransformOps; | ||
llvm::SmallVector<Operation *, 16> allocStack; | ||
|
||
// Walk through the module to find func::FuncOp instances. | ||
getOperation()->walk([&](func::FuncOp funcOp) { | ||
|
@@ -96,6 +97,26 @@ struct ConvertMemRefToCPURuntime | |
} | ||
} | ||
} | ||
} else if (isa<memref::AllocOp>(op)) { | ||
allocStack.push_back(op); | ||
} else if (isa<memref::DeallocOp>(op)) { | ||
// fallback alloc / dealloc not in FILO fashion | ||
Value deallocMemref = op->getOperands().front(); | ||
auto aliases = analysis.resolveReverse(deallocMemref); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really need the aliases for analyzing deallocMemref vs AllocMemref? They'll be exactly same, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we have such case when it is not stack-like? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This case is from Issue#279. After
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't think it's valid to dealloc/free the partial buffer by either There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for pointing out this reference. I will remove the alias. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ideally, all the separated memref.alloc within the same scope should be merged into a big chunk by memref-merge pass, this fallback can be a workaround before the memref-merge patch is pulled in or in case there'll be non FILO alloc/dealloc scenarios. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The alloc/free used to be FILO (stack like). Is there any recent optimization in upstream changing that?
The buffer-merge pass is an optimization and can be turned off at There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we are handling dynamic shaped buffers, the buffer-merge won't work and we still need many small allocations. I would suggest in our pass pipeline that if stack-like allocator is on, we should try to make sure |
||
Value topAllocMemref = allocStack.back()->getResults().front(); | ||
if (aliases.find(topAllocMemref) != aliases.end()) { | ||
allocStack.pop_back(); | ||
} else { | ||
noTransformOps.insert(op); | ||
for (int i = allocStack.size() - 1; i >= 0; --i) { | ||
Operation *curAlloc = allocStack[i]; | ||
if (aliases.find(curAlloc->getResults().front()) != | ||
aliases.end()) { | ||
noTransformOps.insert(curAlloc); | ||
allocStack.erase(allocStack.begin() + i); | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
}); | ||
|
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.
Please note that the
walk()
order may differ from the execution order. And what about the caseThe optimization still applies.
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.
Another topic is that, since we are going to handle general MLIR programs that may be hand-written by users, can your program handle this?
It looks like stack-like, but it is not.
I would suggest a stricter checking:
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.
Not sure if it's a valid case or not, as it will always result in memory leak?
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 we are targeting a general MLIR compiler, so any of the user input should be handled. Users can always write code like this. At least it will not produce wrong result - if they can live with memory leak.