Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplification Comparison for (a | b) ? (a ^ b) : (a & b) etc. (Clang13 vs Clang trunk) #71792

Closed
k-arrows opened this issue Nov 9, 2023 · 3 comments · Fixed by #73362
Closed

Comments

@k-arrows
Copy link

k-arrows commented Nov 9, 2023

Consider the following six functions.
https://godbolt.org/z/cTsd43jhh

bool test1(bool a, bool b)
{
    return (a | b) ? (a ^ b) : (a & b);
}

bool test2(bool a, bool b)
{
    return (a | b) ? (a & b) : (a ^ b);
}

bool test3(bool a, bool b)
{
    return (a & b) ? (a | b) : (a ^ b);
}

bool test4(bool a, bool b)
{
    return (a & b) ? (a ^ b) : (a | b);
}

bool test5(bool a, bool b)
{
    return (a ^ b) ? (a | b) : (a & b);
}

bool test6(bool a, bool b)
{
    return (a ^ b) ? (a & b) : (a | b);
}

Clang13 can simplify four of these, test1, test2, test3 and test4, while Clang trunk cannot. Neither Clang13 nor Clang trunk can simplify test5 and test6.

@github-actions github-actions bot added the clang Clang issues not falling into any other category label Nov 9, 2023
@k-arrows
Copy link
Author

k-arrows commented Nov 9, 2023

Sorry, maybe I should have made a comparison with Clang14.
https://godbolt.org/z/ec1TbovGb

@chfast chfast added regression missed-optimization llvm:instcombine and removed clang Clang issues not falling into any other category labels Nov 9, 2023
@ParkHanbum
Copy link
Contributor

ParkHanbum commented Nov 10, 2023

maybe this patch causes this.

f0071d4

But to me, the patch seems to have a clear purpose. There is a possibility that it can be solved by removing it, but it is questionable whether this is a desirable direction. if this issue not need to fix fast then I want to try.

ParkHanbum added a commit to ParkHanbum/llvm-project that referenced this issue Nov 21, 2023
- `(icmp eq (and/or (ext (A)), (ext (B)), 1)`
- `(icmp ne (and/or (ext (A)), (ext (B)), 0)`
     -> `(and/or A, B)`

- `(icmp eq (and/or (ext (A)), (ext (B)), 0)
- `(icmp ne (and/or (ext (A)), (ext (B)), 1)
     -> `!(and/or A, B)`

If A and B are of type i1, perform the above conversion.

Proofs: https://alive2.llvm.org/ce/z/c-nrLX

Fixes llvm#71792.
@ParkHanbum
Copy link
Contributor

ParkHanbum commented Nov 26, 2023

Unlike the cause of the issue, the way to solve it has become more complicated. reason is that LLVM has decided to no longer allow casting after operation if operator has two casted operand.

maybe this can solved one of followed way.

  1. Add WellKnown bit operation in gvn pass
  2. Add to select (icmp eq), true, false in InstCombine pass

first, assume that we got the ir like below

  %a = zext i1 %x to i32
  %b = zext i1 %y to i32
  %or = or i32 %a, %b
  %or0 = icmp eq i32 %or, 0
  br i1 %or0, label %cond.true, label %cond.false

cond.true:                                        ; preds = %entry
  %xor7 = xor i32 %a, %b
  br label %cond.end

cond.false:                                       ; preds = %entry
  %and6 = and i32 %a, %b
  br label %cond.end

cond.end:                                         ; preds = %cond.false, %cond.true
  %cond.in = phi i32 [ %xor7, %cond.true ], [ %and6, %cond.false ]
  %r = icmp eq i32 %cond.in, 0
  ret i1 %r
}

It will change as follows

  %a = zext i1 %x to i32
  %b = zext i1 %y to i32
  %or = or i32 %b, %a
  %or0 = icmp eq i32 %or, 0
  %xor7 = xor i32 %b, %a
  %and6 = and i32 %b, %a
  %cond.in = select i1 %or0, i32 %xor7, i32 %and6
  %r = icmp eq i32 %cond.in, 0
  ret i1 %r

we already know (X|B=0) when (X^Y)=0
so, we can transform first ir like this:

  %cond.in = phi i32 [ 0, %cond.true ], [ %and6, %cond.false ]

even if you change just this, the results will change.

  %and61 = and i1 %x, %y
  %0 = xor i1 %and61, true
  ret i1 %0

and apply same logic to select also has same result

  %cond = select i1 %tobool4.not, i32 0, i32 %xor
  %tobool131 = xor i1 %a, %b
  ret i1 %tobool131

as this way. this issue could be solved. IMO

ParkHanbum added a commit to ParkHanbum/llvm-project that referenced this issue Jan 10, 2024
- (X & Y) == 0 ? X | Y : X ^ Y   --> X ^ Y
- (X & Y) != 0 ? X | Y : X ^ Y   --> X | Y
- (X | Y) == 0 ? X & Y : X ^ Y   --> X ^ Y
- (X | Y) != 0 ? X & Y : X ^ Y   --> X & Y
- (X ^ Y) == 0 ? X | Y : X & Y   --> X & Y
- (X ^ Y) != 0 ? X | Y : X & Y   --> X | Y

certain combinations of bitwise operators can be simplified to
returning the value of the True or False clause.

Proofs : https://alive2.llvm.org/ce/z/HDSzm4

Fixed llvm#71792.
ParkHanbum added a commit to ParkHanbum/llvm-project that referenced this issue Jan 24, 2024
- (X & Y) == 0 ? X | Y : X ^ Y   --> X ^ Y
- (X & Y) != 0 ? X | Y : X ^ Y   --> X | Y
- (X | Y) == 0 ? X & Y : X ^ Y   --> X ^ Y
- (X | Y) != 0 ? X & Y : X ^ Y   --> X & Y
- (X ^ Y) == 0 ? X | Y : X & Y   --> X & Y
- (X ^ Y) != 0 ? X | Y : X & Y   --> X | Y

certain combinations of bitwise operators can be simplified to
returning the value of the True or False clause.

Proofs : https://alive2.llvm.org/ce/z/HDSzm4

Fixed llvm#71792.
ParkHanbum added a commit to ParkHanbum/llvm-project that referenced this issue Feb 12, 2024
`and/or/xor` operations can each be changed to sum of logical
operations including operators other than themselves.

 `x&y -> (x|y) ^ (x^y)`
 `x|y -> (x&y) | (x^y)`
 `x^y -> (x|y) ^ (x&y)`

if left of condition of `SelectInst` is `and/or/xor` logical
operation and right is equal to `0, -1`, or a `constant`, and
if `TrueVal` consist of `and/or/xor` logical operation then we
can optimize this case.

This patch implements this combination.

Proof: https://alive2.llvm.org/ce/z/WW8iRR

Fixed llvm#71792.
ParkHanbum added a commit to ParkHanbum/llvm-project that referenced this issue Feb 13, 2024
`and/or/xor` operations can each be changed to sum of logical
operations including operators other than themselves.

 `x&y -> (x|y) ^ (x^y)`
 `x|y -> (x&y) | (x^y)`
 `x^y -> (x|y) ^ (x&y)`

if left of condition of `SelectInst` is `and/or/xor` logical
operation and right is equal to `0, -1`, or a `constant`, and
if `TrueVal` consist of `and/or/xor` logical operation then we
can optimize this case.

This patch implements this combination.

Proof: https://alive2.llvm.org/ce/z/WW8iRR

Fixed llvm#71792.
ParkHanbum added a commit to ParkHanbum/llvm-project that referenced this issue Feb 14, 2024
`and/or/xor` operations can each be changed to sum of logical
operations including operators other than themselves.

 `x&y -> (x|y) ^ (x^y)`
 `x|y -> (x&y) | (x^y)`
 `x^y -> (x|y) ^ (x&y)`

if left of condition of `SelectInst` is `and/or/xor` logical
operation and right is equal to `0, -1`, or a `constant`, and
if `TrueVal` consist of `and/or/xor` logical operation then we
can optimize this case.

This patch implements this combination.

Proof: https://alive2.llvm.org/ce/z/WW8iRR

Fixed llvm#71792.
ParkHanbum added a commit to ParkHanbum/llvm-project that referenced this issue Feb 14, 2024
`and/or/xor` operations can each be changed to sum of logical
operations including operators other than themselves.

 `x&y -> (x|y) ^ (x^y)`
 `x|y -> (x&y) | (x^y)`
 `x^y -> (x|y) ^ (x&y)`

if left of condition of `SelectInst` is `and/or/xor` logical
operation and right is equal to `0, -1`, or a `constant`, and
if `TrueVal` consist of `and/or/xor` logical operation then we
can optimize this case.

This patch implements this combination.

Proof: https://alive2.llvm.org/ce/z/WW8iRR

Fixed llvm#71792.
ParkHanbum added a commit to ParkHanbum/llvm-project that referenced this issue Feb 15, 2024
`and/or/xor` operations can each be changed to sum of logical
operations including operators other than themselves.

 `x&y -> (x|y) ^ (x^y)`
 `x|y -> (x&y) | (x^y)`
 `x^y -> (x|y) ^ (x&y)`

if left of condition of `SelectInst` is `and/or/xor` logical
operation and right is equal to `0, -1`, or a `constant`, and
if `TrueVal` consist of `and/or/xor` logical operation then we
can optimize this case.

This patch implements this combination.

Proof: https://alive2.llvm.org/ce/z/WW8iRR

Fixed llvm#71792.
ParkHanbum added a commit to ParkHanbum/llvm-project that referenced this issue Feb 16, 2024
`and/or/xor` operations can each be changed to sum of logical
operations including operators other than themselves.

 `x&y -> (x|y) ^ (x^y)`
 `x|y -> (x&y) | (x^y)`
 `x^y -> (x|y) ^ (x&y)`

if left of condition of `SelectInst` is `and/or/xor` logical
operation and right is equal to `0, -1`, or a `constant`, and
if `TrueVal` consist of `and/or/xor` logical operation then we
can optimize this case.

This patch implements this combination.

Proof: https://alive2.llvm.org/ce/z/WW8iRR

Fixed llvm#71792.
ParkHanbum added a commit to ParkHanbum/llvm-project that referenced this issue Mar 31, 2024
`and/or/xor` operations can each be changed to sum of logical
operations including operators other than themselves.

 `x&y -> (x|y) ^ (x^y)`
 `x|y -> (x&y) | (x^y)`
 `x^y -> (x|y) ^ (x&y)`

if left of condition of `SelectInst` is `and/or/xor` logical
operation and right is equal to `0, -1`, or a `constant`, and
if `TrueVal` consist of `and/or/xor` logical operation then we
can optimize this case.

This patch implements this combination.

Proof: https://alive2.llvm.org/ce/z/WW8iRR
ParkHanbum added a commit to ParkHanbum/llvm-project that referenced this issue Apr 1, 2024
`and/or/xor` operations can each be changed to sum of logical
operations including operators other than themselves.

 `x&y -> (x|y) ^ (x^y)`
 `x|y -> (x&y) | (x^y)`
 `x^y -> (x|y) ^ (x&y)`

if left of condition of `SelectInst` is `and/or/xor` logical
operation and right is equal to `0, -1`, or a `constant`, and
if `TrueVal` consist of `and/or/xor` logical operation then we
can optimize this case.

This patch implements this combination.

Proof: https://alive2.llvm.org/ce/z/WW8iRR
dtcxzyw pushed a commit that referenced this issue Apr 3, 2024
`and/or/xor` operations can each be changed to sum of logical
operations including operators other than themselves.

 `x&y -> (x|y) ^ (x^y)`
 `x|y -> (x&y) | (x^y)`
 `x^y -> (x|y) ^ (x&y)`

if left of condition of `SelectInst` is `and/or/xor` logical
operation and right is equal to `0, -1`, or a `constant`, and
if `TrueVal` consist of `and/or/xor` logical operation then we
can optimize this case.

This patch implements this combination.

Proof: https://alive2.llvm.org/ce/z/WW8iRR

Fixes #71792.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants