This enables partial bufferization that includes function signatures.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
mlir/lib/Dialect/StandardOps/Transforms/FuncBufferize.cpp | ||
---|---|---|
34 | FuncOpTypeConversionPattern will change the type of block arguments, which requires that all predecessor successor args are converted with a pattern like you have for ReturnOp. See the rationale here: https://github.com/llvm/llvm-project/blob/25777080549bb62b6e46a1809f93257969f5dd53/mlir/include/mlir/Dialect/StandardOps/Transforms/Passes.td#L37 You will need to add a pattern that generically converts all BranchOpInterface ops and set up legality so that if we have a terminator that doesn't implement BranchOpInterface then conversion fails. Once we do that, I think we can change func-bufferize to be a partial bufferization only, and have a "finalizing-bufferize" that just folds tensor_load/tensor_to_memref. |
mlir/lib/Dialect/StandardOps/Transforms/FuncBufferize.cpp | ||
---|---|---|
34 | (This is actually how I wanted to originally design it (and it is a better design IMO), but I was too lazy / couldnt't figure out how to do the BranchOpInterface rewrite / legality; in retrospect I shouldn't have taken that shortcut) |
mlir/include/mlir/Dialect/StandardOps/Transforms/Passes.td | ||
---|---|---|
41 | I was never happy with this "just documented" restriction. Using the design I described below, we can improve this situation, because then the finalizing bufferize is just folding tensor_to_memref/tensor_load which we can do while ensuring that no invalid IR is created! |
PTAL.
mlir/lib/Dialect/StandardOps/Transforms/FuncBufferize.cpp | ||
---|---|---|
34 | How about this version? If this works for you, I'll fix the documentation and add another test. Just wanted to get your opinion pre-thanksgiving so that I can go ahead with this (and unblock some other work). We might still want to keep the tests and pass for the finalizing version (to make sure that use case works, as well) as many users might bufferize that way. | |
mlir/lib/Dialect/StandardOps/Transforms/FuncConversions.cpp | ||
88 | A cleanup would be to implement the interfaces or have a new one for "end of list" terminators. That's more a cleanup to generalize this, though. |
I'm okay to submit this if you make func-bufferize only be a partial conversion (never a finalizing conversion), and add a separate finalizing-bufferize pass which folds away tensor_load/tensor_to_memref and emits an error if any remain.
Note that in that new world, mlir-opt -func-bufferize -finalizing-bufferize will reproduce the behavior of the current func-bufferize, so it is trivial for users to update; also, I wrote all the current users of func-bufferize so there is no need to worry about any other users ;)
mlir/lib/Dialect/StandardOps/Transforms/FuncConversions.cpp | ||
---|---|---|
91 | This should just return failure() (or rewriter.notifyMatchFailure(op, "terminator does not implement required interfaces")) The reason is that patterns should not take an opinion on emitting errors in cases like these. The errors should naturally come from how the conversion has the legality set up. For example, if a dialect conversion pass also adds a special pattern for a specific terminator, we don't want to be emitting errors from this pattern. | |
mlir/lib/Transforms/Bufferize.cpp | ||
20 | would prefer to call it materializeTensorLoad and for it to be a local variable in BufferizeTypeConverter::BufferizeTypeConverter just so it is closer to where it is used. | |
mlir/test/Dialect/Standard/func-bufferize-partial.mlir | ||
2 | nit: is --debug-only needed for the test? |
Frederik, can you take a look? Sean was happy for this to move forward with his comments addressed, which I did.
mlir/lib/Transforms/Bufferize.cpp | ||
---|---|---|
20 | It is beyond my C++ voodoo skills to make that happen. If I use a local variable then the compiler complains ERROR: third_party/llvm/llvm-project/llvm/include/llvm/ADT/STLExtras.h:118:59 type '(lambda at third_party/llvm/llvm-project/mlir/lib/Transforms/Bufferize.cpp:32:32) &' cannot be used prior to '::' because it has no members struct function_traits : public function_traits<decltype(&T::operator())> {}; Using a static fixes this :) |
Sorry, I saw this only now.
Thank you!
mlir/lib/Dialect/StandardOps/Transforms/FuncBufferize.cpp | ||
---|---|---|
41–42 | I've seen this a couple of times now. Maybe it is worth moving this to the type converter. | |
56 | nit: trivial braces | |
mlir/test/Dialect/Standard/func-bufferize-partial.mlir | ||
17 | nit: // ----- missing? | |
mlir/test/Dialect/Standard/func-bufferize.mlir | ||
1 | nit: Some are -, some are -- |
mlir/lib/Dialect/StandardOps/Transforms/FuncBufferize.cpp | ||
---|---|---|
41–42 | It already exists, just pass the op itself. |
Thanks for the reviews!
mlir/lib/Dialect/StandardOps/Transforms/FuncBufferize.cpp | ||
---|---|---|
54 | This does not work for unknown operations. I have changed it now to first check isKnownNonTerminator to handle known operations efficiently and then also check for whether it is the last op in the block to handle unknown operations. | |
mlir/test/Dialect/Standard/func-bufferize-partial.mlir | ||
17 | It is not required, only for the last one as it will abort the conversion. |
mlir/lib/Dialect/StandardOps/Transforms/FuncBufferize.cpp | ||
---|---|---|
54 | !isKnownTerminator? |
mlir/lib/Dialect/StandardOps/Transforms/FuncBufferize.cpp | ||
---|---|---|
54 | If I use !isKnownTerminator then this would declare unknown operations in terminator position as legal. But I want to fail the lowering if there is a block with an unknown terminator. |
I realized that we cannot rewrite all ReturnLike operations, as they require rewriting of their parent which cannot be done generically. PTAL the changes.
I was never happy with this "just documented" restriction. Using the design I described below, we can improve this situation, because then the finalizing bufferize is just folding tensor_to_memref/tensor_load which we can do while ensuring that no invalid IR is created!