llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.24k stars 12.07k forks source link

[InstCombine] Regression in and of masked comparison fold #110919

Open nikic opened 1 month ago

nikic commented 1 month ago

From https://github.com/rust-lang/rust/issues/131162:

const MASK: u8 = 1;

#[no_mangle]
pub fn test1(a1: u8, a2: u8) -> bool {
    (a1 & !MASK) == (a2 & !MASK) && (a1 & MASK) == (a2 & MASK)
}

https://llvm.godbolt.org/z/Pasonhe9d:

define i1 @test(i8 %a1, i8 %a2) {
  %xor = xor i8 %a1, %a2
  %cmp = icmp ult i8 %xor, 2
  %lobit = trunc i8 %xor to i1
  %lobit.inv = xor i1 %lobit, true
  %and = and i1 %cmp, %lobit.inv
  ret i1 %and
}

LLVM 18:

define i1 @test(i8 %a1, i8 %a2) {
  %and = icmp eq i8 %a1, %a2
  ret i1 %and
}

LLVM 19:

define i1 @test(i8 %a1, i8 %a2) {
  %xor = xor i8 %a1, %a2
  %cmp = icmp ult i8 %xor, 2
  %lobit = trunc i8 %xor to i1
  %lobit.inv = xor i1 %lobit, true
  %and = and i1 %cmp, %lobit.inv
  ret i1 %and
}

I believe this is fallout from removal of the trunc i1 canonicalization in https://github.com/llvm/llvm-project/pull/84628.

nikic commented 1 month ago

Inverse case: https://llvm.godbolt.org/z/qsq8cj9eK

Adding handling for this to foldEqOfParts() is not as straightforward as I'd like because it moves away from "and/or of icmps" and we're quite geared towards that right now. Like, it will no longer be automatically invoked for logical and/or, reassociated and/or, etc. This should probably be cleaned up first.