This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] Shift amount reassociation in bittest (PR42399)
ClosedPublic

Authored by lebedev.ri on Jun 26 2019, 10:57 AM.

Details

Summary

Given pattern:
icmp eq/ne (and ((x shift Q), (y oppositeshift K))), 0
we should move shifts to the same hand of 'and', i.e. rewrite as
icmp eq/ne (and (x shift (Q+K)), y), 0 iff (Q+K) u< bitwidth(x)

It might be tempting to not restrict this to situations where we know
we'd fold two shifts together, but i'm not sure what rules should there be
to avoid endless combine loops.

We pick the same shift that was originally used to shift the variable we picked to shift:
https://rise4fun.com/Alive/6x1v

Should fix PR42399.

Diff Detail

Repository
rL LLVM

Event Timeline

To answer the obvious question, no, i don't believe we can preserve nuw/nsw/exact flags here.

spatel added inline comments.Jun 30 2019, 7:05 AM
lib/Transforms/InstCombine/InstCombineCompares.cpp
3267–3277

This would be easier to read for me if we did the simple icmp checks first:

if (!I.isEquality() || !match(I.getOperand(1), m_Zero()))
  return nullptr;

And then do a mega-match on only I.getOperand(0).

...although that match raises a question if the one-use checks are balanced:
Do we prefer to shift left or right?
https://rise4fun.com/Alive/

%t0 = lshr i32 %x, 2
%t1 = and i32 %t0, %y
%t3 = icmp ne i32 %t1, 0
  =>
%v0 = shl i32 %y, 2
%v1 = and i32 %v0, %x
%t3 = icmp ne i32 %v1, 0
spatel added inline comments.Jun 30 2019, 7:08 AM
lib/Transforms/InstCombine/InstCombineCompares.cpp
3267–3277

Incomplete Alive link in previous comment:
https://rise4fun.com/Alive/9Kp

Thanks for taking a look, will post updated patch in a bit.

lib/Transforms/InstCombine/InstCombineCompares.cpp
3267–3277

...although that match raises a question if the one-use checks are balanced:

I think they are currently.
We will produce 3 instructions: icmp + and + shift.
Therefore we need to get rid of 2 instructions (since the root icmp is always good to go).
Given the nature of the pattern the icmp is comparing and with 0, so and must go.
And thus we only need to get rid of one more instruction.
We know that both hands of an and are shifts.
Since the pattern is bi-directional, we don't really care which one of these two shifts
will be left, only one of those 2 shifts *has* to be one-use.
And that's what is currently enforced via m_OneUse().

Do we prefer to shift left or right?

I'm not sure we can answer that here.
If we can do this fold as per one-use checks - we should.
Do you have anything specific in mind here?
I'd say this should be a separate fold.

lebedev.ri marked 3 inline comments as done.

Tidy code up a bit.

spatel accepted this revision.Jul 1 2019, 6:43 AM

LGTM - but see inline comment. It might simplify the code here if we implement the other fold first.

lib/Transforms/InstCombine/InstCombineCompares.cpp
3267–3277

Yes, I agree that choosing the shift op is a separate fold. My guess is that 'lshr' gives us better analysis because it clears the sign bit, but that's just a hunch - would have to try it and see what breaks. :)

If we make that decision first, then we could adjust this patch to go directly to the preferred form. As it stands now, we're arbitrarily choosing the shift opcode based on operand ordering (when both sides have one use).

This revision is now accepted and ready to land.Jul 1 2019, 6:43 AM
lebedev.ri added inline comments.Jul 1 2019, 7:13 AM
lib/Transforms/InstCombine/InstCombineCompares.cpp
3267–3277

I agree. I *think* lshr will indeed be the correct choice.
At least that would be my choice based on the pattern in question i'm seeing in my code.

Thank you for the review!

lebedev.ri updated this revision to Diff 207302.Jul 1 2019, 7:30 AM

NFC, test coverage.

lebedev.ri updated this revision to Diff 207324.Jul 1 2019, 8:15 AM
lebedev.ri marked 2 inline comments as done.

Prefer to create lshr if possible.

Filed https://bugs.llvm.org/show_bug.cgi?id=42466 to track the shift direction question.

This revision was automatically updated to reflect the committed changes.
lebedev.ri marked an inline comment as done.Jul 1 2019, 11:58 AM
lebedev.ri added inline comments.
lib/Transforms/InstCombine/InstCombineCompares.cpp
3267–3277

Apparently only 2 tests break:

LLVM :: Transforms/InstCombine/shl-and-negC-icmpeq-zero.ll
LLVM :: Transforms/InstCombine/shl-and-signbit-icmpeq-zero.ll

D62818 is related, but failures there are not limited to sign-bit constants.