llvm / llvm/llvm-project

Clang 22 and trunk emit unnecessary cmp/setae when the input is trivially 0 or 1 already

Open
#194,216 1 comment 0 reactions 0 assignees View on GitHub
missed-optimization
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.