rust-lang / rust-lang/rust

Bad codegen for aarch64 when using one `else if` instead of two

Open
#162,074 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-codegen C-bug needs-triage O-AArch64
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.