You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Cranelift: egraphs: fix a few sources of exponential rewrite blowup. (#10579)
This arrived as a fuzzbug [1] with some very interesting optimization
behavior. The test case has sequences of `(select _ x x)` operators --
that is, conditional selects with both inputs the same -- that are
chained together sequentially. A few aspects of the egraph framework and
our optimization rules conspired to create exponential blowup:
- We have a rewrite rule for `(select _ x x) -> x`, but we do not
subsume; this means that we create an eclass for both. This in itself
is not a problem; however...
- We have some *other* rules that look through the inputs to the select
to detect other cases (e.g.: select between constants 1 and 0, or 0
and 0, or ...), so we traverse both inputs;
- And we also do nested rewrites, so when the rewrite rule for `(select
_ x x) -> x` fires, and the `x` is itself another select in a long
chain of selects, we traverse all possible paths (through first
or second args) to the roots. In effect we get an eclass that has the
ultimate root and then 2^n combinations of `select` nodes on top of
that.
This got worse with the recent change to canonicalize less (for
simpler/cheaper compilation), hence the fuzzbug timeouts.
This PR includes a few fixes, all complementary to each other:
- The `(select _ x x) -> x` rule now subsumes; this is another case
where we have a strictly better rewrite and so we should short-circuit
the eclass blowup.
- The rewrite runner sorts and dedups returned value numbers; in
debugging the above I noticed we were getting two rules producing the
same rewritten value and we were adding the same value twice with two
union nodes.
- The rewriter keeps a total eclass size per root and limits the total
eclass size to a fixed limit (currently 5). We thus now have limits in
three different axes: depth of eager rewrites (5); number of returned
matches (also 5); and total size of eclass (5). The first two don't
necessarily imply the third because we otherwise can keep unioning on
top of an eclass and (as seen above) see exponential blowup.
[1]: https://oss-fuzz.com/testcase-detail/4806924172591104
0 commit comments