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

(a & C0) != 0 || (a & C1) != 0 Doesn't Always Become (a & (C0 | C1)) != 0 #92333

Open
Geotale opened this issue May 16, 2024 · 2 comments
Open

Comments

@Geotale
Copy link

Geotale commented May 16, 2024

Example code:

#[no_mangle]
pub fn src(a: u8) -> u8 {
    1 + ((a & 4 != 0 || a & 1 != 0) as u8)
}

#[no_mangle]
pub fn tgt(a: u8) -> u8 {
    1 + ((a & 5 != 0) as u8)
}

Resulting in the IR:

define noundef i8 @src(i8 noundef %a) unnamed_addr {
start:
  %_4 = and i8 %a, 4
  %0 = icmp eq i8 %_4, 0
  %1 = and i8 %a, 1
  %2 = add nuw nsw i8 %1, 1
  %_3.sroa.0.0 = select i1 %0, i8 %2, i8 2
  ret i8 %_3.sroa.0.0
}

define noundef i8 @tgt(i8 noundef %a) unnamed_addr {
start:
  %_4 = and i8 %a, 5
  %_3.not = icmp eq i8 %_4, 0
  %_0 = select i1 %_3.not, i8 1, i8 2
  ret i8 %_0
}

This specific pattern is never caught, but the cause for it is due to the original comparisons lying on different branches which InstCombine didn't account for
In many situations, missing this optimization causes multiple unnecessary branches to occur (the code I was testing with did (a & !3) + 4 * ((a & 2 != 0 && (a & 4 != 0 || a & 1 != 0)) as u8), which similarly never gets the chance to optimize this away due to the separate branches, but they remain on different branches the entire time!!)

Tested with nightly Rustc on Godbolt
Godbolt: https://godbolt.org/z/K5GP5dGq1
Alive2: https://alive2.llvm.org/ce/z/evhsnx

@wangbyby
Copy link

Maybe the type cast caused the missing opt?
If code like this

#[no_mangle]
pub fn src(a: u8) -> bool {
    let b = (a & 4 != 0 || a & 1 != 0) ;
    b
}

#[no_mangle]
pub fn tgt(a: u8) -> bool {
    a & 5 != 0
}

Would resulting:

@tgt = unnamed_addr alias i1 (i8), ptr @src

define noundef zeroext i1 @src(i8 noundef %a) unnamed_addr {
start:
  %0 = and i8 %a, 5
  %b.0 = icmp ne i8 %0, 0
  ret i1 %b.0
}

Godbolt: https://godbolt.org/z/79YoYd1GE

@Geotale
Copy link
Author

Geotale commented May 17, 2024

With that change the same branching thing occurs, but it seems like the second run of InstCombine could catch the pattern of

  %_3 = and i8 %a, 4
  %0 = icmp eq i8 %_3, 0
  %1 = and i8 %a, 1
  %2 = icmp ne i8 %1, 0
  %b.sroa.0.0 = select i1 %0, i1 %2, i1 true
  ret i1 %b.sroa.0.0

but not the case using add instead :o

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

No branches or pull requests

3 participants