-
Notifications
You must be signed in to change notification settings - Fork 3.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
[IR][SIBuilder] #14574
[IR][SIBuilder] #14574
Conversation
chunit-quic
commented
Apr 11, 2023
- Add SIBuilder to handle the span propagation between passes
- Add SequentialSpan for multiple source expressions conversion between passes
- Add test cases for SIBuilder and SequentialSpan
Thanks for contributing to TVM! Please refer to the contributing guidelines https://tvm.apache.org/docs/contribute/ for useful information and tips. Please request code reviews from Reviewers by @-ing them in a comment.
Generated by tvm-bot |
Hi community, This is third part of TVM Explorer infrastructures. Based on this patch, we can tag source To give you more context, we briefly describe what have been done below in this PR. Here is the
You can reference to preRFC for more details. Thanks! :D For your reference, here is the related links. |
I wonder if it's relay specific. If so, could you please move it under relay's namespace |
Hi @Hzfengsy, |
Hi @Hzfengsy, |
Sorry, I'm not an expert on |
* \brief SIBuilder provides helper APIs for filling spans, | ||
* particularly useful for one-to-many, many-to-one and many-to-many pass transformations. | ||
*/ | ||
class SIBuilder { |
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 document what "SI" stands for
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.
Will add to comments. It stands for source information builder.
include/tvm/ir/si_builder.h
Outdated
|
||
/*! | ||
* \brief SIBuilder provides helper APIs for filling spans, | ||
* particularly useful for one-to-many, many-to-one and many-to-many pass transformations. |
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.
pass transformations -> IR transformations?
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.
Will change
src/ir/si_builder.cc
Outdated
public: | ||
explicit RelayCollapse(const RelayExprSet& inputs = {}) : inputs_(inputs) {} | ||
|
||
Span Collapse(const relay::Expr& entry); |
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 document what Collapse
and Fill
mean in this file
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 CollectSpans
will be a more descriptive name for Collapse
?
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 a lot for the naming suggestion!
CollectSpans is more straightforward.
Will add documentations and change the name.
include/tvm/ir/si_builder.h
Outdated
SIBuilder& operator=(const SIBuilder&) = delete; | ||
|
||
/*! | ||
* \brief create new source info based on the given span or subgraph. |
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 description doesn't seem to match the signature
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.
Sorry for the ambiguous naming. Would it be better if we change function name and comments as following?
/*!
* \brief build a span of source information, which is based on the given span or subgraph.
*
* \return the built span
*/
Span Build() const;
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.
yes looks good
python/tvm/ir/base.py
Outdated
@@ -69,6 +69,20 @@ def __init__(self, source_name, line, end_line, column, end_column): | |||
) | |||
|
|||
|
|||
@register_object("SequentialSpan") | |||
class SequentialSpan(Object): | |||
"""Specifies a location in a source program. |
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 this doc, since it refers to only a single span.
Does this class need to be exposed to Python? If it is used only by c++ code, no need to define a python class.
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.
No problem, will update the description.
About being exposed to Python side, it would be quite helpful in the following situations:
- Writing relay passes tests cases in ${tvm}/tests/python/relay/test_pass*.
- User can set a span to their custom python passes for their own many-to-one expression transformations.
src/ir/si_builder.cc
Outdated
public: | ||
explicit RelayCollapse(const RelayExprSet& inputs = {}) : inputs_(inputs) {} | ||
|
||
Span Collapse(const relay::Expr& entry); |
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 CollectSpans
will be a more descriptive name for Collapse
?
src/ir/si_builder.cc
Outdated
} | ||
|
||
std::unique_ptr<SIBuilder::Impl> SIBuilder::CreateImpl(const Span& span) { | ||
struct NullImpl : public SIBuilder::Impl { |
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 class and the base class SIBuilder::Impl
don't seem to be necessary. If SI collection is not enabled, there is no need to collect spans or create the impl object. We should check enable_si_builder
condition much earlier.
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 pointing out! In case I misunderstand what you said. Please allow me to briefly describe what we going to do, and feel free to correct me if any. :D
- Delete base (virtual) class
SIBuilder::Impl
- Use the NullImpl as the parent(default) class for SIBuilder::Impl
- Create a class with functional implementations, which is derived from NullImpl class
- When
enable_si_builder
is not enable, use the NullImpl as _Impl driectly. otherwise assign the functional one to the _impl.
We can remove some redundant codes by doing so.
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 I meant was, if si collection is not enabled, we don't have to call CreateImpl
at all. What you described still sounds too complicated for its purpose.
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. I agree this implementation seems to be a bit too complicated in this case.
Basically we had two strategies to enable/disable the functionalities of SIBuilder. May you
tell us which one you prefer more or please kindly give us some advices? :D
In the following, I take a real case from one of our upcoming pass transformation PR for example,
I will list pro and con of our two strategies for you.
The use case of SIBuilder
Here we uses SimplifyReshape
in ${tvm}/src/relay/transforms/simplify_expr.cc
for example. It is
a many-to-one transformation. The SIBuilder will be invoked like following block:
class SimplifyReshape : public DFPatternRewrite {
public:
SimplifyReshape() {
x_ = IsWildcard();
auto reshape1 = IsOp("reshape") || IsOp("contrib_reverse_reshape");
auto reshape2 = IsOp("reshape") || IsOp("contrib_reverse_reshape");
pattern_ = reshape1({reshape2({x_})});
}
Expr Callback(const Expr& pre, const Expr& post,
const Map<DFPattern, Array<Expr>>& node_map) const override {
//...
if (const_shape) {
auto x = node_map[x_][0];
auto ret = MakeReshape(x, newshape);
SIBuilder si_builder(/* entry */ node_map[pattern_][0], /* inputs */ {x});
ret->span = si_builder.Build();
return ret;
}
return post;
}
//..
};
In above case the si_builder is initialized by a sub graph, and invokes its member function to
build a new span. To make its functionalities enabled/disabled, we have 2 proposals
Proposals
-
Null implementation
Just like what we have now. The pro is, we checkenable_si_builder
in a place(CreateImpl) only.
The con is obviously, it seems to be complicated in this case. -
Embed
enable_si_builder
checking in each place
Another way is we can embedenable_si_builder
checking at the beginning constructors or functions.
Take RecursivelyFillSpan an example, we can add the checking like this:
template <>
void SIBuilder::RecursivelyFillSpan(const relay::Expr& entry, const RelayExprSet& inputs) const {
if (enabled) {
RecursivelyFillSpan(entry, inputs);
}
}
The pro is, the codes are very straightforward now. The con is the duplicated checking of
enable_si_builder
will be added to multiple constructors and functions. It might seem to be a bit
redundant.
Currently we use the first proposal because we can reduce the checking to a place only, though it
is a bit complicated. Yet we are good to use the proposal 2. Or perhaps may you kindly point out
some strategies we might miss out?
Thank you for reading this long rely. We will get back to you soon. :D
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.
Yes, 2. is what I meant by "checking early". If that ends up with too-much repetitive check, I'm ok with your solution of making NullImpl
a base class.
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 very much for clarifying and understanding. :D
We would like to keep this NullImpl. Because we made many constructors to serve both Relay and TIR, the second proposal will lead us to add quite a lot number of checking (perhaps more than ten).
We will fix the the codes based your comments and push it once we finished.
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.
Hi @masahi,
Sorry for late reply and thank you very much for reviewing our codes!
Based on the comments we have done changes. Yet we would like to check with you some details of them before push a new patch.
Any comment is appreciated. Thank you :D
python/tvm/ir/base.py
Outdated
@@ -69,6 +69,20 @@ def __init__(self, source_name, line, end_line, column, end_column): | |||
) | |||
|
|||
|
|||
@register_object("SequentialSpan") | |||
class SequentialSpan(Object): | |||
"""Specifies a location in a source program. |
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.
No problem, will update the description.
About being exposed to Python side, it would be quite helpful in the following situations:
- Writing relay passes tests cases in ${tvm}/tests/python/relay/test_pass*.
- User can set a span to their custom python passes for their own many-to-one expression transformations.
src/ir/si_builder.cc
Outdated
public: | ||
explicit RelayCollapse(const RelayExprSet& inputs = {}) : inputs_(inputs) {} | ||
|
||
Span Collapse(const relay::Expr& entry); |
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 a lot for the naming suggestion!
CollectSpans is more straightforward.
Will add documentations and change the name.
include/tvm/ir/si_builder.h
Outdated
|
||
/*! | ||
* \brief SIBuilder provides helper APIs for filling spans, | ||
* particularly useful for one-to-many, many-to-one and many-to-many pass transformations. |
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.
Will change
* \brief SIBuilder provides helper APIs for filling spans, | ||
* particularly useful for one-to-many, many-to-one and many-to-many pass transformations. | ||
*/ | ||
class SIBuilder { |
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.
Will add to comments. It stands for source information builder.
include/tvm/ir/si_builder.h
Outdated
SIBuilder& operator=(const SIBuilder&) = delete; | ||
|
||
/*! | ||
* \brief create new source info based on the given span or subgraph. |
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.
Sorry for the ambiguous naming. Would it be better if we change function name and comments as following?
/*!
* \brief build a span of source information, which is based on the given span or subgraph.
*
* \return the built span
*/
Span Build() const;
src/ir/si_builder.cc
Outdated
} | ||
|
||
std::unique_ptr<SIBuilder::Impl> SIBuilder::CreateImpl(const Span& span) { | ||
struct NullImpl : public SIBuilder::Impl { |
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 pointing out! In case I misunderstand what you said. Please allow me to briefly describe what we going to do, and feel free to correct me if any. :D
- Delete base (virtual) class
SIBuilder::Impl
- Use the NullImpl as the parent(default) class for SIBuilder::Impl
- Create a class with functional implementations, which is derived from NullImpl class
- When
enable_si_builder
is not enable, use the NullImpl as _Impl driectly. otherwise assign the functional one to the _impl.
We can remove some redundant codes by doing so.
4334cb2
to
f2c9c0b
Compare
- Add SIBuilder to handle the span propagation between passes - Add SequentialSpan for multiple source expressions conversion between passes - Add test cases for SIBuilder and SequentialSpan
- Make null implementation as base class - Add comments and change naming based on reviewing
* [IR][SIBuilder] - Add SIBuilder to handle the span propagation between passes - Add SequentialSpan for multiple source expressions conversion between passes - Add test cases for SIBuilder and SequentialSpan * [IR][SIBuilder] - Make null implementation as base class - Add comments and change naming based on reviewing --------- Co-authored-by: Joey Tsai <chunit@qti.qualcomm.com>
This PR introduces a potential issue as suggested by clang, which we might want to patch:
|