rust-lang / rust-lang/rust

Generated assembly contains a jump to the next instruction

Open
#127,640 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-LLVM C-bug I-heavy
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

I tried this code in Godbolt:

#[inline(never)]
pub fn next_back_1(len: &mut u8, bits: &mut u16) -> Option<u8> {
    if *len == 0 {
        None
    } else {
        *len -= 1;
        let result = *bits as u8 & 1;
        *bits >>= 1;
        Some(result)
    }
}

I expected to see this happen: Generated assembly doesn't include jumps to the next instruction.

Instead, this happened: Generated assembly does include a jump to the next instruction.

On x86_64-unknown-linux-gnu (with command line flag -O), notice that the jmp .LBB0_3 line is just above the .LBB0_3 label, and so that instruction can be removed, reducing code size:

example::next_back_1::h48bde1edbc0e4b8a:
        movzx   eax, byte ptr [rdi]
        test    al, al
        je      .LBB0_1
        lea     ecx, [rax - 1]
        mov     byte ptr [rdi], cl
        movzx   ecx, word ptr [rsi]
        mov     edx, ecx
        and     dl, 1
        shr     ecx
        mov     word ptr [rsi], cx
        jmp     .LBB0_3
.LBB0_1:
.LBB0_3:
        test    al, al
        setne   al
        ret

On aarch64-apple-darwin (with command line flags -O --target=aarch64-apple-darwin), the same thing occurs with the b LBB0_3 instruction:

__ZN7example11next_back_117ha5e5b29a87ac44fdE:
        ldrb    w8, [x0]
        cbz     w8, LBB0_2
        sub     w9, w8, #1
        strb    w9, [x0]
        ldrh    w9, [x1]
        mov     x10, x1
        and     w1, w9, #0x1
        lsr     w9, w9, #1
        strh    w9, [x10]
        b       LBB0_3
LBB0_2:
LBB0_3:
        cmp     w8, #0
        cset    w0, ne
        ret
Meta
rustc --version --verbose
rustc 1.79.0 (129f3b996 2024-06-10)
binary: rustc
commit-hash: 129f3b9964af4d4a709d1383930ade12dfe7c081
commit-date: 2024-06-10
host: x86_64-unknown-linux-gnu
release: 1.79.0
LLVM version: 18.1.7
rustc 1.80.0-beta.4 (64a1fe671 2024-06-21)
binary: rustc
commit-hash: 64a1fe67112931359c7c9a222f08fd206255c2b5
commit-date: 2024-06-21
host: x86_64-unknown-linux-gnu
release: 1.80.0-beta.4
LLVM version: 18.1.7
rustc 1.81.0-nightly (0c81f94b9 2024-07-10)
binary: rustc
commit-hash: 0c81f94b9a6207fb1fc080caa83584dea2d71fc6
commit-date: 2024-07-10
host: x86_64-unknown-linux-gnu
release: 1.81.0-nightly
LLVM version: 18.1.7
Note that I can't reproduce this on my own machine, but I get another bug there (#127641).

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 compiling the provided next_back_1 reproducer with -O for x86_64-unknown-linux-gnu and aarch64-apple-darwin, then compare the emitted assembly with the examples in the report. Investigate the compiler code-generation path involved and check issue #127641 for related behavior. Done means the redundant jump is no longer emitted on the affected targets, with a regression test covering the reproducer.

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
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.