Clang 22 and trunk emit unnecessary cmp/setae when the input is trivially 0 or 1 already
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Consider this snippet ([Compiler Explorer](https://godbolt.org/z/so9zve9sT)).
```c
int f(int x) {
return (x & 1) ? 1 : -1;
}
int g(int x) {
return ((x & 1) * 2) - 1;
}
```
`f` and `g` are trivially equivalent, but:
```asm
f:
and edi, 1
xor eax, eax
cmp edi, 1
setae al
lea eax, [2*rax - 1]
ret
g:
and edi, 1
lea eax, [2*rdi - 1]
ret
```
Clearly, clang knows that `f` cold be folded to use the `*2 - 1` trick, but something makes it miss that we already have `& 1` and emits the `cmp`/`setae` awkwardness.
Reported by Test\_User (`hax[xor]` on irc.runxiyu.org).
I'm unfamiliar with the architecture of Clang and LLVM and this is my first time interacting here.
Also, for the IR, trimmed:
```llvm
f:
%2 = and i32 %0, 1
%3 = icmp eq i32 %2, 0
%4 = select i1 %3, i32 -1, i32 1
g:
%2 = shl i32 %0, 1
%3 = and i32 %2, 2
%4 = add nsw i32 %3, -1
```
Contributor guide
Research direction
Start by reproducing the Compiler Explorer case and comparing the trimmed LLVM IR for f and g. Trace how the select from (x & 1) is lowered; done means the generated code avoids the unnecessary cmp/setae sequence and a regression test covers this input. No source file or test is named in the issue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- compilers, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100