Bad codegen for aarch64 when using one `else if` instead of two
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
I tried this code:
https://rust.godbolt.org/z/crjez3j19
use std::num::NonZero;
#[unsafe(no_mangle)]
pub fn mul_div_i64(value: i64, numerator: i64, denom: NonZero<i64>) -> i64 {
if denom.get() == 24_000_000 {
mul_div_i64_inner(value, numerator, denom)
//} else if denom.get() == 10_000_000 {
// mul_div_i64_inner(value, numerator, denom)
} else {
mul_div_i64_inner(value, numerator, denom)
}
}
pub fn mul_div_i64_inner(value: i64, numerator: i64, denom: NonZero<i64>) -> i64 {
let denom = denom.get();
unsafe { std::hint::assert_unchecked(denom > 0) };
unsafe { std::hint::assert_unchecked(numerator == 1_000_000_000) };
let q = value / denom;
let r = value % denom;
q * numerator + r * numerator / denom
}
I got this assembly:
"@feat.00" = 0
mul_div_i64:
sdiv x8, x0, x2
mov x9, #36083
mov w12, #51712
movk x9, #38032, lsl #16
movk w12, #15258, lsl #16
movk x9, #64519, lsl #32
movk x9, #45812, lsl #48
smulh x10, x0, x9
add x10, x10, x0
asr x13, x10, #24
add x10, x13, x10, lsr #63
mov w13, #13824
movk w13, #366, lsl #16
msub x13, x10, x13, x0
msub x11, x8, x2, x0
mul x13, x13, x12
mul x11, x11, x12
smulh x9, x13, x9
sdiv x11, x11, x2
add x9, x9, x13
madd x8, x8, x12, x11
asr x11, x9, #24
add x9, x11, x9, lsr #63
madd x9, x10, x12, x9
mov w10, #13824
movk w10, #366, lsl #16
cmp x2, x10
csel x0, x8, x9, ne
ret
If I uncomment the other else if branch then the codegen improves:
mul_div_i64:
sub x8, x2, #2441, lsl #12
cmp x8, #1664
b.eq .LBB0_3
mov w8, #13824
movk w8, #366, lsl #16
cmp x2, x8
mov w8, #51712
movk w8, #15258, lsl #16
b.ne .LBB0_4
mov x9, #36083
movk x9, #38032, lsl #16
movk x9, #64519, lsl #32
movk x9, #45812, lsl #48
smulh x10, x0, x9
add x10, x10, x0
asr x11, x10, #24
add x10, x11, x10, lsr #63
mov w11, #13824
movk w11, #366, lsl #16
msub x11, x10, x11, x0
mul x11, x11, x8
smulh x9, x11, x9
add x9, x9, x11
asr x11, x9, #24
add x9, x11, x9, lsr #63
madd x0, x10, x8, x9
ret
.LBB0_3:
mov w8, #100
mul x0, x0, x8
ret
.LBB0_4:
sdiv x9, x0, x2
msub x10, x9, x2, x0
mul x10, x10, x8
sdiv x10, x10, x2
madd x0, x9, x8, x10
ret
If I remove the branching entirely then it looks like this:
mul_div_i64:
sdiv x8, x0, x2
mov w10, #51712
movk w10, #15258, lsl #16
msub x9, x8, x2, x0
mul x9, x9, x10
sdiv x9, x9, x2
madd x0, x8, x10, x9
ret
Meta
Targetting aarch64.
rustc --version --verbose:
rustc 1.100.0-nightly (908501772 2026-08-30)
binary: rustc
commit-hash: 90850177249efe0321573c569aec5d12b257f8d6
commit-date: 2026-08-30
host: x86_64-unknown-linux-gnu
release: 1.100.0-nightly
LLVM version: 23.1.0
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the Rust Compiler Explorer example for the aarch64 target and compare the three generated assembly variants shown in the issue. Trace the compiler's handling of the conditional branches and code generation for the arithmetic, then verify that the one-branch form no longer produces the inefficient select-based assembly while preserving the improved behavior of the other forms.
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
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100