-
Notifications
You must be signed in to change notification settings - Fork 78
[TIR] Adding BufferPointer node, used by BufferLoad and BufferStore #42
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
Conversation
Hzfengsy
left a comment
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.
Thanks for the RFC. IIUC, BufferPointer is somehow like the combination of Buffer and indices. It's good if we can have it, but my question is if it's necessary? As we are changing the core data structure, which is a breaking change, the cost is greater than the benefits in my opinion.
BTW, Could you please show some more design details? such as the data structure and the AST with BufferPointer? So that more people can join the discussion.
rfcs/0042-buffer-pointer.md
Outdated
| @@ -0,0 +1,116 @@ | |||
| - Feature Name: (fill me in with a unique identifier, `my_awesome_feature`) | |||
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 update the name
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.
Thank you, updating the name along with addressing the other points.
|
If we explicitly introduce a concept similar to
p = BufferPointer(A, [i, j], value_dtype="f32")then BufferPointer is merely an IR data structure that attaches to BufferLoad/BufferStore, which benefits the developer but doesn't bring additional expressiveness for the user.
|
Thank you, and that was the main concern that I had. This change would make the areas that I've been working on lately be much cleaner, but outside of that . The breakage was minimized by keeping the existing
Certainly. I won't be able to add them here until Monday, but I have a sample implementation at PR#9391.
The current implementation does expose it, though primarily for testing purposes. At the moment, none of the code-generators handle it explicitly, so the only current use is with BufferLoad/BufferStore. It might be able to replace the builtin
Agreed. I kept to having the same buffer/indices as |
|
I agree with @spectrometerHBH that changing the IR design may introduce problems. To reuse the code but BufferLoad/Store, we can introduce auxiliary functions or construct auxiliary data structure on the fly. The |
rfcs/0042-buffer-pointer.md
Outdated
| The `BufferLoad::pointer` and `BufferStore::pointer` could be generic | ||
| `PrimExpr`, instead of being `BufferPointer` objects. This would | ||
| require the datatype to be a handle, with an additional parameter to | ||
| indicate what is being stored. However, 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.
There is a truncated sentence at the end of the paragraph.
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.
Thank you for that catch, and updated. I tend to bounce between different sentences when editing, and I thought I had gone through it to catch all of these, but it looks like I missed one.
|
Thank you for the feedback. Summarizing, it seems the major issues are as follows. I have some follow-up questions for the different points, listed in the sub-bullets.
|
|
From @vinx13's suggestion on the TVM PR thread, quoting here for the discussion.
My concern there is for newcomers coming to the codebase. Utility functions are effective if somebody knows that the utility functions exist, but require that knowledge first. Making the preferred method to handle a specific task be the default way to do it, without requiring the utility function, is easier for somebody to find. That said, I agree that a utility function would be a good fallback if we don't want to change the TIR. |
|
Thank you eric for bringing up the discussion points. The primary reason for this discussion is because of the underlying tradeoffs:
So from a developer experience pov, it is hard to tell which way is clearly better. T0 would call for the introduction of BufferAccess, while T1 would favor the original AST where read/write are explicit. Given most goals of T0 can be implemented via a common util function, the gain of T0 may not be as large. From my personal pov, considering all the factors, the clarity of read/write relation(in T1) and simplicity of AST outweights the benefits in T0. I agree that IR change is certainly important even if it is just a developer win, as long as it is strictly better than the old design. However, because of the impact, we might need some more deliberations on the tradeoffs. This review process already helps us to uncover some of the hidden problems(such as the initial leaking issue into values by using a BufferPointer, which can be addressed by having BufferAccess as an object). I also agree that it is better to separate the TIR change from RFC0039, we just need more discussions about the design here. I am looking forward to build better designs together :) |
|
Good point on the tradeoffs, and I agree that this turned out to be a longer discussion that should be separate from the changes in RFC0039. For the T1 developer experience, I've been assuming that they would still be written using visitors of the |
|
Following a conversation with @vinx13, below are the overall points of discussions.
Overall, our conclusion was that since the ergonomics of |
|
A slight modification to the example of using a helper function to simplify implementation of the visitors for BufferLoad/BufferStore, using templated helper functionStmt VisitStmt_(const BufferStoreNode* op) final {
return ModifyBuffer(Downcast<BufferStore>(StmtExprMutator::VisitStmt_(op)));
}
PrimExpr VisitStmt_(const BufferLoadNode* op) final {
return ModifyBuffer(Downcast<BufferLoad>(StmtExprMutator::VisitExpr_(op)));
}
template<typename Node>
Node ModifyBuffer(Node node) {
auto it = buffer_map_.find(node->buffer);
if (it != buffer_map_.end()) {
auto writer = node.CopyOnWrite();
writer->buffer = it->second;
}
return node;
}(I think the original helper function could still work if |
|
cc @manupa-arm |
|
If there are no further comments, shall we conclude this? |
|
Agreed, closing both this and the implementation PR. |
This RFC introduces a
BufferPointernode, to be used byBufferLoadandBufferStorenodes.Rendered markdown link