This is an archive of the discontinued LLVM Phabricator instance.

[SCEV] Model (xor (shl x, C), (-1 << C)) as (shl (xor x, -1), C)
AbandonedPublic

Authored by bjope on Aug 14 2020, 5:41 AM.

Details

Summary

InstCombine may fold a left shift over a not (xor by -1).
This patch teaches ScalarEvolution to detect such patterns, creating
a SCEV based on the reverse fold. Without this patch the instcombine
rewrite could lead to missed oppurtunities later in the pipeline
due to not being able to calculate a SCEV for the xor.

An alternative solution could be to modify InstCombine (e.g. in
canShiftBinOpWithConstantRHS) to avoid the fold that creates the
xor that isn't recognized by ScalarEvolution.

Fixes: https://bugs.llvm.org/show_bug.cgi?id=47136

Diff Detail

Event Timeline

bjope created this revision.Aug 14 2020, 5:41 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 14 2020, 5:41 AM
bjope requested review of this revision.Aug 14 2020, 5:41 AM

I don't have much experience with SCEV either, but I think your draft change for instcombine made sense:
https://bugs.llvm.org/show_bug.cgi?id=47136#c8

As hinted there, that's the same direction as:
D32255 / rG23bd33c6acc4

So I'm not sure if we would consider this a worthwhile improvement independently and still make a change to SCEV or only change instcombine (or if there's some reason to *not* change instcombine, I'd like to understand that).

bjope added a comment.Aug 15 2020, 2:32 PM

I don't have much experience with SCEV either, but I think your draft change for instcombine made sense:
https://bugs.llvm.org/show_bug.cgi?id=47136#c8

As hinted there, that's the same direction as:
D32255 / rG23bd33c6acc4

So I'm not sure if we would consider this a worthwhile improvement independently and still make a change to SCEV or only change instcombine (or if there's some reason to *not* change instcombine, I'd like to understand that).

Well, I'm not exactly sure why instcombine is folding the shift over the operands of binary operators in the first place. Afaict it does that regardless of it being beneficial or not (e.g. triggering more combines). So maybe it is some kind of canonicalization?
If it is a canonicalization it seem weird to be assymetric and do different things depending on the value of the constant operand (and which binary operator that is used), isn't it?
If we decide that the canoncial form of (xor (shl x, C), (-1 << C)) should be (shl (xor x, -1), C), then I figure we need to inplement that reverse transform instead of the one present in instcombine today (specially considering that ScalarEvolution only undestand (shl (xor x, -1), C) without this patch).

So all-in-all, I figured that patching ScalarEvolution would be a more general solution (being a bit more independent on what instcombine and other passes are doing). However, it still depends on the shift being present directly as the xor operand, so it is still not perfect in that sense.

One more thing. I wrote PR47136 because of regressions in three test cases. This patch restore things to the old cycle counts. When testing the other patch from PR47136, simply avoiding some shift folding in instcombine, it also resolved the three regressions. But with the instcombine patch I got another regressions instead. So it seemed like that solution had other implications.

I don't have much experience with SCEV either, but I think your draft change for instcombine made sense:
https://bugs.llvm.org/show_bug.cgi?id=47136#c8

As hinted there, that's the same direction as:
D32255 / rG23bd33c6acc4

So I'm not sure if we would consider this a worthwhile improvement independently and still make a change to SCEV or only change instcombine (or if there's some reason to *not* change instcombine, I'd like to understand that).

Well, I'm not exactly sure why instcombine is folding the shift over the operands of binary operators in the first place. Afaict it does that regardless of it being beneficial or not (e.g. triggering more combines). So maybe it is some kind of canonicalization?

Yes, it looks like it is just a canonicalization, so we standardize on a single pattern. I don't think there's anything inherently better/worse about one form or the other. If we reverse the canonicalization, we may find regressions because we have come to expect the current patterns.

If it is a canonicalization it seem weird to be assymetric and do different things depending on the value of the constant operand (and which binary operator that is used), isn't it?

I agree with that in general, but 'not' is treated as a special-case in instcombine and other passes, so there's precedence to do that for this case too.

If we decide that the canoncial form of (xor (shl x, C), (-1 << C)) should be (shl (xor x, -1), C), then I figure we need to inplement that reverse transform instead of the one present in instcombine today (specially considering that ScalarEvolution only undestand (shl (xor x, -1), C) without this patch).

Yes, we should implement the reverse transform in instcombine to make things canonical - even if that form is not entirely consistent. :)

So all-in-all, I figured that patching ScalarEvolution would be a more general solution (being a bit more independent on what instcombine and other passes are doing). However, it still depends on the shift being present directly as the xor operand, so it is still not perfect in that sense.

One more thing. I wrote PR47136 because of regressions in three test cases. This patch restore things to the old cycle counts. When testing the other patch from PR47136, simply avoiding some shift folding in instcombine, it also resolved the three regressions. But with the instcombine patch I got another regressions instead. So it seemed like that solution had other implications.

Would that be resolved by adding the reverse canonicalization?

lebedev.ri requested changes to this revision.Aug 22 2020, 2:06 PM

Modelling this in SCEV is totally justifiable even if InstCombine knows how to fix the pattern,
iff having this complexity actually helps. E.g. InstCombine has one-use check, so it won't fix everything.

To find that out, add a STATISTIC() and prove that the code actually fires on some codebase.

Marking as reviewed for now.

llvm/lib/Analysis/ScalarEvolution.cpp
6229–6230

Add statistic here

This revision now requires changes to proceed.Aug 22 2020, 2:06 PM
bjope abandoned this revision.Aug 23 2020, 1:37 PM

Haven't seen any gains from this patch, after having rebased to https://reviews.llvm.org/rGec06b381304140b2553cfdfae5a063f39c5c59ff .
The test I ran included bunch of application code, compiled with -O3, for our OOT target.

So I have no plan to pursue landing this, at least not right now.