[ValueTracking] Missing nonzero inference from assumed 2*x != 0 to x != 0
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
For the following LLVM IR:
```llvm
define i1 @src(i8 %x) {
entry:
%twice = add i8 %x, %x
%twice.nz = icmp ne i8 %twice, 0
call void @llvm.assume(i1 %twice.nz)
%dec = add i8 %x, -1
%r = icmp ult i8 %dec, 7
ret i1 %r
}
```
On current LLVM trunk, `opt -O3` keeps the decrement (godbolt: https://godbolt.org/z/GPe6x4rx1):
```llvm
define i1 @src(i8 %x) {
entry:
%twice.mask = and i8 %x, 127
%twice.nz = icmp ne i8 %twice.mask, 0
tail call void @llvm.assume(i1 %twice.nz)
%dec = add i8 %x, -1
%r = icmp ult i8 %dec, 7
ret i1 %r
}
```
`2*x != 0` implies `x != 0` for modular integers. Thus the `add` could be removed with icmp 7 -> 8 (alive2: https://alive2.llvm.org/ce/z/hAPKjv):
```llvm
%r = icmp ult i8 %x, 8
ret i1 %r
```
LLVM performs the expected fold when the implied fact is stated directly (check the third one in godbolt: https://godbolt.org/z/GPe6x4rx1):
```llvm
%x.nz = icmp ne i8 %x, 0
call void @llvm.assume(i1 %x.nz)
%dec = add i8 %x, -1 ;; removed
%r = icmp ult i8 %dec, 7 ;; 7 -> 8
ret i1 %r
```
The problem appears to be in contextual nonzero reasoning. `isKnownNonZero()` does consult KnownBits for operator-defined values, but `%x` is an argument here, so that generic operator fallback is not reached. Its direct-assumption path only recognizes comparisons whose operand is `%x` itself and therefore does not propagate nonzero information backward from either `%twice` or `%twice.mask`.
After InstCombine canonicalizes `2*x != 0` to `(x & 127) != 0`, AssumptionCache can associate the condition with `%x`. The KnownBits fallback proves nonzero by checking whether `Known.One` is nonempty. Here the condition only says that one of the low seven bits is one; the position of that one bit is indefinite, so `Known.One` remains empty.
Contributor guide
Assessment
This issue has not been assessed yet.