[X86] llvm.scmp(X, 0)) generates suboptimal code
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Take this rust code:
```rust
#[unsafe(no_mangle)]
pub fn signum(num: i128) -> i8 {
num.signum() as i8
}
```
(signum returns -1, 0, 1) based on the sign of the number. This lowers into llvm.scmp:
```llvm
define noundef range(i8 -1, 2) i8 @signum(i128 noundef %num) unnamed_addr {
start:
%_3 = tail call i8 @llvm.scmp.i8.i128(i128 %num, i128 0)
ret i8 %_3
}
```
However the asm we get is this:
```asm
signum:
xor eax, eax
neg rdi
sbb rax, rsi
setl al
test rsi, rsi
sets cl
sub al, cl
ret
```
However this can be this:
```asm
signum:
or rdi, rsi
setne al
sar rsi, 63
or al, sil
ret
```
This seems to be the case regardless of the return type:
```rust
#[unsafe(no_mangle)]
pub fn signum(num: i128) -> i128 {
num.signum()
}
```
```llvm
define noundef range(i128 -1, 2) i128 @signum(i128 noundef %num) unnamed_addr {
start:
%_2 = tail call i8 @llvm.scmp.i8.i128(i128 %num, i128 0)
%_0 = sext i8 %_2 to i128
ret i128 %_0
```
Emits this:
```asm
signum:
xor eax, eax
neg rdi
sbb rax, rsi
setl al
test rsi, rsi
sets cl
sub al, cl
movsx rax, al
mov rdx, rax
sar rdx, 63
ret
```
When this should suffice
```asm
signum:
mov rdx, rsi
sar rdx, 63
xor eax, eax
or rsi, rdi
setne al
or rax, rdx
ret
```
I believe this is because expandCMP lowers scmp(X, 0) poorly, going through sub(IsGT, IsLT) when it doesn't need to.
Contributor guide
Research direction
Start by tracing the x86 lowering of llvm.scmp(X, 0) through expandCMP, comparing the generated instructions with the Rust signum reproducer and the proposed assembly. Check the existing compiler tests covering scmp and x86 comparisons, then add coverage showing that signum produces the improved sequence without changing its -1, 0, 1 results.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100