-
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
[ARITH] Revamp IntSet #3272
[ARITH] Revamp IntSet #3272
Conversation
hello there.. |
ping reviewers |
src/arithmetic/analyzer.cc
Outdated
@@ -77,6 +78,7 @@ bool Analyzer::CanProveGreaterEqual(const Expr& expr, int64_t lower_bound) { | |||
return ptr->value > lower_bound; | |||
} | |||
auto bd = this->const_int_bound(this->rewrite_simplify(expr)); | |||
LOG(INFO) << bd; |
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.
remove it or make it more informative.
src/arithmetic/int_set.cc
Outdated
Expr max_value = min(a->max_value, b->max_value); | ||
Expr min_value = max(a->min_value, b->min_value); | ||
if ((max_value.type().is_int() || max_value.type().is_uint()) && | ||
(min_value.type().is_int() || max_value.type().is_uint()) && |
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.
(min_value.type().is_int() || max_value.type().is_uint()) && | |
(min_value.type().is_int() || min_value.type().is_uint()) && |
src/arithmetic/int_set.cc
Outdated
if (a->IsEmpty()) return a; | ||
if (b->IsEmpty()) return b; | ||
if (a->IsSinglePoint()) { | ||
// assert !b->IsSinglePoint(); |
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.
remove comment
Thanks, @wweic for catching the problems. @sgrechanik-h @kazum @sxjscience please take another look if you have time |
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.
lgtm. just some typos.
Co-Authored-By: Wei Chen <[email protected]>
Co-Authored-By: Wei Chen <[email protected]>
Co-Authored-By: Wei Chen <[email protected]>
Co-Authored-By: Wei Chen <[email protected]>
src/arithmetic/int_set.cc
Outdated
return IntervalSet::make(e2, e1); | ||
} else if (a.is_bounded()) { | ||
if (b->IsSinglePoint()) { | ||
if (is_zero(b->min_value)) return IntervalSet::SinglePoint(b->min_value); |
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.
Maybe just return b
since it is {0}
?
if (is_zero(divisor)) { | ||
LOG(FATAL) << "Modular by zero in CombineInterval Mod"; | ||
} | ||
return IntervalSet::make(make_zero(divisor.type()), divisor - 1); | ||
if (analyzer->CanProveGreaterEqual(divisor, 0)) { | ||
return IntervalSet(make_zero(divisor.type()), divisor - 1); |
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.
For truncated division a % b
may be negative when b > 0
if a < 0
, so I guess additional condition on a
is required.
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.
@tqchen I understand that this may be quite difficult to fix right now, but I think that at least some kind of warning must be issued when a
cannot be proved to be non-negative, like this:
LOG(WARNING) << "The expression " << a << " is assumed to be non-negative";
src/arithmetic/int_set.cc
Outdated
IntervalSet a, | ||
IntervalSet b) { | ||
if (a->IsSinglePoint() && b->IsSinglePoint()) { | ||
return IntervalSet::SinglePoint(a->min_value % b->min_value); |
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.
%
-> max
src/arithmetic/int_set.cc
Outdated
IntervalSet a, | ||
IntervalSet b) { | ||
if (a->IsSinglePoint() && b->IsSinglePoint()) { | ||
return IntervalSet::SinglePoint(a->min_value % b->min_value); |
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.
%
-> min
IntSet false_set = this->Eval(op->false_value); | ||
return Union({false_set, true_set}); | ||
|
||
IntervalSet VisitExpr_(const Select* op) final { |
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.
Do we need the same thing for if_then_else
?
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.
unlikely we will use if_then_else for indices
src/arithmetic/int_set.h
Outdated
* \brief Symbolic interval set. | ||
* | ||
* \note We intentionally keep the internal of IntSet private, | ||
as we anticipate that |
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 comment looks unfinished
/*! \return whether interval represent nothing */ | ||
bool IsEmpty() const { | ||
// during computations, either extreme could occur. | ||
return is_pos_inf(min_value) || is_neg_inf(max_value); |
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.
Shouldn't we also try something like CanProve(min_value > max_value)
?
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.
Was handled in the simplification logic of intersect, but could debate where we should add it
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.
Such an empty set may also be created directly with a constructor, so it may be worth adding the check into the constructor. However this may be a rare case, so I don't insist.
LOG(WARNING) << "Return Everything in CombineInterval Mul"; | ||
return IntSet::everything(); | ||
DLOG(WARNING) << "Return Everything in CombineInterval Mul"; | ||
return IntervalSet::Everything(); |
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.
Seems to me that we are not handling this case: b
is not a single point but we can still prove it's always non-negative or always non-positive.
The same statement applies to Combine<Div>
and possibly Combine<Mod>
below.
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.
true, pushing for this direction might involve more thoughts(and related use-cases) let us do it in a follow up
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.
fine with me to do it a follow-up. Regarding use-cases: It's sometimes hard to come up with a realistic use-case. On the other hand, when there is a missed opt opportunity, it will be time-consuming to find out that it was because of a missed rule in some fundamental infra like this.
In summary, I suggest to do it in a follow-up without worrying about a real use-case.
|
||
IntervalSet VisitExpr_(const Select* op) final { | ||
IntervalSet true_set = this->Eval(op->true_value); | ||
IntervalSet false_set = this->Eval(op->false_value); |
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.
Is it possible to evaluate op->true_value
and op->false_value
under the contexts of op->condition
and NOT op->condition
respectively?
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 might, but need to put more thoughts into this, and check if there is any particular usecase of interest
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 can think of this use case: message passing during InferBound where we have Select or if_then_else in the lambda expression (e.g., padding in conv, maxpool, etc.)
Thanks, @sgrechanik-h @derisavi for helpful comments! please take another look when you have time. |
|
||
// Range related code | ||
inline bool ProveEqual(Expr lhs, Expr rhs) { | ||
return is_zero(ir::Simplify(lhs - rhs)); |
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.
By the way, I guess ir::Simplify
is the Halide simplifier. Can it be replaced we the new rewrite or canonical simplifiers 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.
will do that in a follow up PR
Thanks, @derisavi @sgrechanik-h @wweic @Hzfengsy . this PR is now merged. Let us address the remaining comments in the subsequent PRs |
Part of #2588
This PR revamps IntSet infrastructure to use the new Analyzer API.