This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] Fold '(-1 u/ %x) u< %y' to '@llvm.umul.with.overflow' + overflow bit extraction
ClosedPublic

Authored by lebedev.ri on Jul 23 2019, 6:59 AM.

Details

Summary

(-1 u/ %x) u< %y is one of (3?) common ways to check that
some unsigned multiplication (will not) overflow.
Currently, we don't catch it. We could:

----------------------------------------
Name: no overflow
  %o0 = udiv i4 -1, %x
  %r = icmp ult i4 %o0, %y
=>
  %o0 = udiv i4 -1, %x
  %n0 = umul_overflow i4 %x, %y
  %r = extractvalue {i4, i1} %n0, 1

Done: 1
Optimization is correct!

----------------------------------------
Name: no overflow, swapped
  %o0 = udiv i4 -1, %x
  %r = icmp ugt i4 %y, %o0
=>
  %o0 = udiv i4 -1, %x
  %n0 = umul_overflow i4 %x, %y
  %r = extractvalue {i4, i1} %n0, 1

Done: 1
Optimization is correct!

----------------------------------------
Name: overflow
  %o0 = udiv i4 -1, %x
  %r = icmp uge i4 %o0, %y
=>
  %o0 = udiv i4 -1, %x
  %n0 = umul_overflow i4 %x, %y
  %n1 = extractvalue {i4, i1} %n0, 1
  %r = xor %n1, -1

Done: 1
Optimization is correct!

----------------------------------------
Name: overflow
  %o0 = udiv i4 -1, %x
  %r = icmp ule i4 %y, %o0
=>
  %o0 = udiv i4 -1, %x
  %n0 = umul_overflow i4 %x, %y
  %n1 = extractvalue {i4, i1} %n0, 1
  %r = xor %n1, -1

Done: 1
Optimization is correct!

As it can be observed from tests, while simply forming the @llvm.umul.with.overflow
is easy, if we were looking for the inverted answer, then more work needs to be done
to cleanup the now-pointless control-flow that was guarding against division-by-zero.
This is being addressed in follow-up patches.

Diff Detail

Repository
rL LLVM

Event Timeline

lebedev.ri created this revision.Jul 23 2019, 6:59 AM
xbolva00 added inline comments.Jul 23 2019, 7:14 AM
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
3333 ↗(On Diff #211286)

Just ‘x’ instead of ‘%x’ in the comments?

3351 ↗(On Diff #211286)

“.. whether overflow happens or not” ?

3363 ↗(On Diff #211286)

Early return maybe better?

lebedev.ri added inline comments.Jul 23 2019, 7:54 AM
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
3363 ↗(On Diff #211286)

Then the diff in the very next patch (D65144) will have to re-indent, i wonder if this is more readable as-is..

lebedev.ri marked 3 inline comments as done.

NFC, improve comments.

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
3351 ↗(On Diff #211286)

Non-native english here, i think the current variant is more correct.
We obviously are checking whether or not the overflow happens,
so the suggested comment isn't wrong.
But the question here is whether we are asking "if this overflows return 1 else return 0"
or "if this overflows return 0 else return 1", and i wouldn't say i'd infer it from suggested wording.

xbolva00 added inline comments.Jul 23 2019, 8:46 AM
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
3363 ↗(On Diff #211286)

Oh yea, +1

lebedev.ri marked 3 inline comments as done.Jul 23 2019, 8:47 AM
nikic accepted this revision.Jul 27 2019, 1:00 PM

LGTM

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
3349 ↗(On Diff #211305)

Side note: This seems pretty awkward and potentially bug prone. Having looked through the relatively few uses of this matcher, most cases either don't care (because they handle equalities) or would benefit from returning the swapped predicate. I think we should change the semantics to remove this potential footgun...

3370 ↗(On Diff #211305)

Technically increases instruction count, but that seems justified here, especially as not's will usually be folded.

This revision is now accepted and ready to land.Jul 27 2019, 1:00 PM
lebedev.ri marked 3 inline comments as done.Jul 27 2019, 11:22 PM

Thank you for the review.

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
3349 ↗(On Diff #211305)

... i.e. you suggest that m_c_ICmp() should swap predicate as needed?

3370 ↗(On Diff #211305)

Yes, i think this is a very rare case where this is ok.

lebedev.ri marked an inline comment as done.

NFC, added a comment about increasing instruction count.

nikic added inline comments.Jul 28 2019, 1:59 AM
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
3349 ↗(On Diff #211305)

Yes. m_c_ICmp(Pred, X, Y) should match X Pred Y or an equivalent commutative form, which is Y SwappedPred X, not Y Pred X (apart from the degenerate case of equality). At least that's what I would intuitively expect and what would be useful in practice (such as here).

lebedev.ri marked 3 inline comments as done.Jul 28 2019, 2:05 AM
lebedev.ri added inline comments.
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
3349 ↗(On Diff #211305)

Got it.
Looks like right now there is only 20 uses of m_c_ICmp() so it seems doable.
Filed https://bugs.llvm.org/show_bug.cgi?id=42801

xbolva00 accepted this revision.Aug 11 2019, 11:30 AM
lebedev.ri marked an inline comment as done.

Rebased, NFC.