This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] canonicalize urem as cmp+select
ClosedPublic

Authored by Allen on Feb 13 2023, 12:36 AM.

Diff Detail

Event Timeline

Allen created this revision.Feb 13 2023, 12:36 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 13 2023, 12:36 AM
Allen requested review of this revision.Feb 13 2023, 12:36 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 13 2023, 12:36 AM
nikic requested changes to this revision.Feb 14 2023, 12:39 AM

Needs more tests for preconditions, e.g. what happens if the constant is not 1?

Note that there is also a more general form of this fold, see https://github.com/llvm/llvm-project/blob/697a162fa63df328ec9ca334636c5e85390b2bf0/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp#L806. The tricky bit here is that we would nee X < 2*Y, which is hard to establish as a precondition in this context.

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
1791

Why the nuw requirement? Seems to be fine without it? https://alive2.llvm.org/ce/z/uo7HMz

1792

Why is this specific to assumes? Can we do a generic simplifyICmp? (If we do so, Op0 needs to be frozen.)

This revision now requires changes to proceed.Feb 14 2023, 12:39 AM
Allen updated this revision to Diff 497631.EditedFeb 15 2023, 4:23 AM

Address comments:
a) check the assume with more generate API simplifyICmpInst
b) Add 3 test cases, including some Negative tests
c) Fix the checking and only do this when the return value is isOneValue()
d) Add the logic of frozen

Allen marked 2 inline comments as done.Feb 15 2023, 4:26 AM
Allen added inline comments.
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
1791

Thanks, Both of them are added in test cases.

1792

Apply your comment, thanks

RKSimon added inline comments.Feb 15 2023, 4:49 AM
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
1792

Would this be better? I always hate to see isa<> + cast<> pairs - it feels like we're duplicating work.

if (auto *CVal = dyn_cast_or_null<Constant>(Val)) {
  if (CVal->isOneValue()) {
  }
}
Allen updated this revision to Diff 497851.Feb 15 2023, 5:14 PM
Allen marked 2 inline comments as done.

update to use dyn_cast_or_null according comment

Allen marked an inline comment as done.Feb 15 2023, 5:18 PM
Allen added inline comments.
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
1792

Apply your review, thanks for your detailed example.

nikic added inline comments.Feb 15 2023, 11:52 PM
llvm/include/llvm/Analysis/InstructionSimplify.h
244 ↗(On Diff #497851)

Why the new parameter? You can use SQ.withInstruction(I) to change the context instruction.

Allen updated this revision to Diff 497921.Feb 16 2023, 1:03 AM
Allen marked an inline comment as done.

use SQ.getWithInstruction(&I) to to change the context instruction

Allen marked an inline comment as done.Feb 16 2023, 1:05 AM
Allen added inline comments.
llvm/include/llvm/Analysis/InstructionSimplify.h
244 ↗(On Diff #497851)

Thanks your review, I update with SQ.getWithInstruction(&I).

nikic added inline comments.Feb 16 2023, 4:09 AM
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
1793–1794

Use match(Val, m_One()) instead?

llvm/test/Transforms/InstCombine/urem-via-cmp-select.ll
24

Drop noundef attributes

77

Missing tests where add constant is not 1.

It would be good to also have a test that is not based on assume, where %x < %n is known through some other way instead.

Allen updated this revision to Diff 497963.Feb 16 2023, 4:39 AM
Allen marked an inline comment as done.

Address comments

  • use match(Val, m_One()) to replace CVal->isOneValue()
  • Drop the attribute noundef of function urem_assume_without_nuw, then it will see freeze
  • Add a new negative case urem_assume_with_unexpected_const
spatel added inline comments.Feb 16 2023, 5:59 AM
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
1789

This comment doesn't match the code.
Should it be:

// For "(X + 1) % Op1" and if (X u< Op1) => (X + 1) == Op1 ? 0 : X + 1
1794

This is called FrozenX, but it is freezing Op0. Should it freeze X directly as the name suggests?

llvm/test/Transforms/InstCombine/urem-via-cmp-select.ll
77

Still no tests with no "assume" call. There should be a way to show the transform using math or bitwise logic ops and/or using a dominating condition?

Allen updated this revision to Diff 498208.Feb 16 2023, 5:40 PM

Address comments:
a) Adding a new case urem_without_assume
b) Update the code comment to match the code
c) Rename the FreezeX to FreezeOp0 as the name suggests

Allen updated this revision to Diff 498225.Feb 16 2023, 6:09 PM
Allen marked 3 inline comments as done.

Add a new case urem_with_dominating_condition

Allen marked 3 inline comments as done.Feb 16 2023, 6:10 PM
Allen added inline comments.
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
1789

Thanks, apply it.

llvm/test/Transforms/InstCombine/urem-via-cmp-select.ll
77

Add a case urem_with_dominating_condition, but now it is not supported, need a following patch to fix

nikic added inline comments.Feb 17 2023, 6:51 AM
llvm/test/Transforms/InstCombine/urem-via-cmp-select.ll
5

Should also drop noundef here and on the return values.

105

%cmp is a dead instruction here. The request wasn't to just drop the assume, but to establish the %x < %n precondition without using one. It's a bit tricky to do this without also triggering other folds, but maybe this would work?

define i64 @test(i64 %arg) {
  %x = shl nuw i64 1, %arg
  %n = shl nuw i64 3, %arg
  %add = add i64 %x, 1
  %out = urem i64 %add, %n
  ret i64 %out
}

Unfortunately this example still doesn't show the need for freeze (https://alive2.llvm.org/ce/z/FJCdt4) ... I'm pretty sure it's needed in the general case, but I'm not sure how to come up with an example.

spatel added inline comments.Feb 17 2023, 7:07 AM
llvm/test/Transforms/InstCombine/urem-via-cmp-select.ll
43

If it's not changing behavior of the optimization (and it is not in any cases here from what I see), use i8 or possibly even narrower type widths. This makes it more likely that Alive2 can run quickly on all tests to verify correctness.

efriedma added inline comments.Feb 17 2023, 11:19 AM
llvm/test/Transforms/InstCombine/urem-via-cmp-select.ll
105

If I'm understanding your question correctly, the following demonstrates the need for freeze.

define i8 @src(i8 %arg, i8 %arg2) {
  %x = urem i8 %arg, %arg2
  %add = add i8 %x, 1
  %out = urem i8 %add, %arg2
  ret i8 %out
}

define i8 @tgt(i8 %arg, i8 %arg2) {
  %xx = urem i8 %arg, %arg2
  %x = freeze i8 %xx
  %add = add i8 %x, 1
  %cmp = icmp eq i8 %add, %arg2
  %out = select i1 %cmp, i8 0, i8 %add
  ret i8 %out
}
nikic added inline comments.Feb 17 2023, 11:42 AM
llvm/test/Transforms/InstCombine/urem-via-cmp-select.ll
105

Thanks, that's exactly what I was looking for!

Allen updated this revision to Diff 498535.Feb 17 2023, 5:47 PM

Address comments:
a) Drop all the attribute noundef on the argument and return value
b) Change all the value type to i8 as Alive2 can run quickly on all tests to verify correctness
c) Update case urem_without_assume

Allen marked 5 inline comments as done.Feb 17 2023, 5:50 PM
Allen added inline comments.
llvm/test/Transforms/InstCombine/urem-via-cmp-select.ll
5

Thanks, delete all the noundef.

43

Thanks, I adapt all the value type into i8.

105

Thanks @nikic and @efriedma for your test case.

nikic accepted this revision.Feb 18 2023, 5:41 AM

LGTM, but please pre-commit tests.

This revision is now accepted and ready to land.Feb 18 2023, 5:41 AM
Allen updated this revision to Diff 498775.Feb 20 2023, 2:46 AM
Allen marked 3 inline comments as done.

update as precommit test in D144372 according review.

This revision was landed with ongoing or failed builds.Feb 20 2023, 7:53 AM
This revision was automatically updated to reflect the committed changes.