llvm / llvm/llvm-project

[X86] llvm.scmp(X, 0)) generates suboptimal code

Open
#190,538 1 comment 0 reactions 0 assignees View on GitHub
backend:X86 missed-optimization
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

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.