This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] Implement "A & (~A | B) --> A & B" like transforms for boolean based selects.
ClosedPublic

Authored by paulwalker-arm on Mar 2 2023, 6:21 AM.

Details

Summary

Alive2 links for "A & (~A | B) --> A & B":
https://alive2.llvm.org/ce/z/oKiodu (scalar)
https://alive2.llvm.org/ce/z/8yn8GL (vector)

Alive2 links for "A | (~A & B) --> A | B"
https://alive2.llvm.org/ce/z/v5GEKu (scalar)
https://alive2.llvm.org/ce/z/wvtJsj (vector)

NOTE: The commutative variants of these transforms, for example: "(~A | B) & A --> A & B" are already handled by simplifying the underlying selects to normal logical operations due to that combination having simpler poison semantics.

Diff Detail

Event Timeline

paulwalker-arm created this revision.Mar 2 2023, 6:21 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 2 2023, 6:21 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
paulwalker-arm requested review of this revision.Mar 2 2023, 6:21 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 2 2023, 6:21 AM
paulwalker-arm planned changes to this revision.Mar 2 2023, 6:46 AM

Need to be more strict with the handling of poison.

Updated to include correct handling of poison.

nikic added a reviewer: nikic.Mar 2 2023, 7:57 AM
nikic added a subscriber: nikic.

Missing scalar test coverage. Please also add relevant proofs to patch description (e.g. https://alive2.llvm.org/ce/z/oKiodu). What about the de Morgan conjugate?

spatel added inline comments.Mar 2 2023, 9:01 AM
llvm/test/Transforms/InstCombine/logical-select.ll
1135

This isn't doing what we wanted - the not will get commuted to operand 0.
To keep it as operand 1, we need something like this:

declare i1 @gen()

define i1 @and_commute1(i1 %a) {
  %b = call i1 @gen()
  %nota = xor i1 %a, 1
  %or = or i1 %b, %nota
  %and = select i1 %a, i1 %or, i1 0
  ret i1 %and
}

We also need matching and tests for patterns where the "or-not" is the condition value of the select?

paulwalker-arm added inline comments.Mar 2 2023, 9:52 AM
llvm/test/Transforms/InstCombine/logical-select.ll
1135

The "or-not is the condition" case already works, whereby it's converted to an "and" (See https://alive2.llvm.org/ce/z/bxZ37W). I'm not sure why that case doesn't have the same poison issues that my case has.

Add scalar test cases and fixed switch operand test.

paulwalker-arm retitled this revision from [InstCombine] Implement "A & (~A | B) --> A & B" for boolean vectors. to [InstCombine] Implement "A & (~A | B) --> A & B" like transform for boolean vectors..Mar 2 2023, 10:03 AM
paulwalker-arm edited the summary of this revision. (Show Details)
paulwalker-arm edited the summary of this revision. (Show Details)

Missing scalar test coverage. Please also add relevant proofs to patch description (e.g. https://alive2.llvm.org/ce/z/oKiodu). What about the de Morgan conjugate?

@nikic Can you be more specific as to the meaning of "de Morgan conjugate"? Do you mean switching the operands as @spatel mentioned (which already works) or had you something else in mind.

nikic added a comment.Mar 2 2023, 10:12 AM

Missing scalar test coverage. Please also add relevant proofs to patch description (e.g. https://alive2.llvm.org/ce/z/oKiodu). What about the de Morgan conjugate?

@nikic Can you be more specific as to the meaning of "de Morgan conjugate"? Do you mean switching the operands as @spatel mentioned (which already works) or had you something else in mind.

The conjugate is A | (~A & B) -> A | B (https://alive2.llvm.org/ce/z/v5GEKu).

Thanks for the education @nikic. I'll implement that transformation as well.

spatel added inline comments.Mar 2 2023, 10:48 AM
llvm/test/Transforms/InstCombine/logical-select.ll
1135

Ah, I see now. We get the commuted case where or is the condition because we use impliesPoison() to convert the select into a regular bitwise logic and, and the fold is handled by matching regular bitwise logic ops.

When the or is the true value of the select, we can't do that. That's because if %b is poison, then the select can prevent it from leaking to the final result value:
https://alive2.llvm.org/ce/z/H-HKdz

Add matching combine for "A | (~A & B) --> A | B".

paulwalker-arm retitled this revision from [InstCombine] Implement "A & (~A | B) --> A & B" like transform for boolean vectors. to [InstCombine] Implement "A & (~A | B) --> A & B" like transforms for boolean based selects..Mar 3 2023, 5:11 AM
paulwalker-arm edited the summary of this revision. (Show Details)
paulwalker-arm edited the summary of this revision. (Show Details)
spatel added a comment.Mar 3 2023, 5:39 AM

This looks close to me, but see inline comments on the tests, and please pre-commit those with the baseline CHECK lines, so we'll just show test diffs in this patch.

llvm/test/Transforms/InstCombine/logical-select.ll
1153

The test name is a bit misleading here - it's not a commute variation; it's replacing a bitwise 'or' with a 'logical-or'.

1165

Instead of repeating the test with a vector type (which we already verified works in the 2nd test), this test would provide better coverage if it included extra uses of the intermediate logic ops. That shows that the transform is still valid and intentional regardless of other uses.

1176

It would be better to keep this formula synchronized with the test (and the comment on the next line), so commute:
"A & (B | ~A)"

1191

Same comments for this set of tests as above, but a couple of additional potential tests:

  1. Include a poison element in the vector constant to show that works too.
  2. Add a negative test where 'not %a' is replaced by an arbitary value to show that the transform only works when we have a specific value match.

Rebase after updating and precommiting the tests.

spatel accepted this revision.Mar 5 2023, 8:04 AM

LGTM

llvm/test/Transforms/InstCombine/logical-select.ll
1143–1144

Nit: the code comments describe what the tests are checking, so that's good, but we still prefer that tests have a more meaningful name vs. generic "testN". I'd call all of the tests in this set something like "logical_and_or_with_common_not_op" or something like that.
Then the conjugated logic set that ends in or would be "logical_or_and_with_common_not_op".

This revision is now accepted and ready to land.Mar 5 2023, 8:04 AM