-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[Jit] Redundant comparisons are not eliminated #35348
Comments
Specifically, if We might need to generalize the interaction of the above two methods as there could be many partially matching assertions and we might want to look at them all. Probably worth some prospecting to see what potential impact this has. |
If you are going there... Jit doesn't seem to pick up where the condition is reversed e.g. This is problematic as Roslyn seems to like reversing the conditionals so it can be hard to get the correct incantation to get them to match and eliminate one. |
We should be doing some amount of expression canoncalization to reduce diversity in the jit IR. At the very least, moving the variable part of compares to the LHS so we always see The handwavy proposal above would have us examine all the available assertions that involve
we'd have to check if we could determine the result of For single-variable sets of integer relations this comes down to interval math. Range prop does something similar already but it is too narrowly focused on loops and bounds checks. |
Related this offset++;
if ((uint)offset > (uint)value.Length)
{
// Consumed enitre string, move to next
break;
}
value = value.Slice(offset); generates G_M33915_IG28:
inc r8d
cmp r8d, edx
ja G_M33915_IG55
cmp r8d, edx
ja G_M33915_IG60 |
We do not support general relational assertions That being said, for exact redundancies like this, we might be able to do some custom processing by just looking at the predecessor block: if it branches on exactly the same condition as the current block (say the compares have the same value number) then we can optimize. Also probably worth prospecting. |
@benaadams do you have a more complete example for that "related" fragment? |
ParseConnection in https://gist.github.com/benaadams/02b56912b6174911f81ac1f5152fc593 G_M42236_IG28:
inc r8d
cmp r8d, edx
ja G_M42236_IG55
cmp r8d, edx
ja G_M42236_IG60 |
Fixed by #43811 |
Exactly redundant comparisons are fixed, but not implicated comparisons (as in the first example). So perhaps we should keep this one open? It should not be that hard to break down the dominating compare VNs to see if they are testing something similar, eg |
@AndyAyersMS Given that you suggested you might investigate, I'll mark this as 6.0 for now. |
Here's a bit of the screening code in action, on the parse connection example:
(looking for relop VNs with the same LHS vn, and either constant RHS vns or the same RHS vn). All this tells us is that the same VN is tested against some other constant or the same value higher up in the dominator tree. To be able to optimize we have to show (a) that there's a unique path from dominating test to dominated test, and that (b) the reaching dominating test outcome determines the dominated test outcome. There are about 7200 of these cases noted when crossgenning SPC. So it looks promising, but be aware many of these won't pan out, eg
We reach BB13 if V17 is not 32; that won't help us figure out if V17 NE 44. The case you noted above is
and here knowing that V119 is not less than 18 implies V119 must not be less than 8, so that second test is redundant. To implement the optimization there's a fair bit of logical calculus to handle all the possible relops one might see in both positions, especially if we want to handle the unsigned variants; likely GT_GT, GT_GE, GT_LT, GT_LE, GT_EQ, GT_NE, GT_UN_GT, GT_UN_GE, GT_UN_LT, GT_UN_LE -- so say 10 possibilities for each? Also we'd want to do two checks each time: given a dominating compare D (say known to be true) and a dominated compare T, does D imply T or does D imply !T? Note the outcomes are either
I don't know how to ballpark how many compares may end up being redundant without actually implementing all this. For the logic (and restricting to integral types) I'd be tempted to strongly normalize everything (say express all cases in terms of But in the short run we can perhaps only look for cases with the exact same relop, and see where that gets us. Note there's an even higher dominating compare in the case above
and it's possible to generalize the logic to consider the combination of all the known-value dominating predicates. |
I started in on a more general version of this (prototype: MoreRedundantBranches) but the combinatorics still look ugly. One thing this doesn't handle yet is that VNs don't obey the "constants on the right" rule. |
At one point I started working on the more general version, see #46257 (comment) |
RBO gets the first case now:
likely thanks to #95234 (dump message is a bit misleading, the VN operands are not the same here...). |
The following code
Generates a double comparison once against size 18; and a second against size 8 (which is already guaranteed by the size 18 check)
Method is
ParseConnection
in this gist https://gist.github.com/benaadams/2ac588cc3dd65088db2bb51f9e4a89e1Seen in dotnet/aspnetcore#21004
category:cq
theme:assertion-prop
skill-level:intermediate
cost:medium
impact:small
The text was updated successfully, but these errors were encountered: