rust-lang / rust-lang/rust

Missed optimization: big immutable locals are not promoted to constants

Open
#136,218 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-codegen A-constant-promotion A-LLVM C-optimization I-slow T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

I tried this code, on riscv32i-unknown-none-elf (this code is originally from #136216):

#![no_std]

pub enum Idx { _0, _1, _2, _3 }

#[no_mangle]
pub unsafe fn lookup_local(x: Idx) -> u8 {
    [0xEF, 0x0E, 0x0D, 0xBD][x as usize]
}

#[no_mangle]
pub unsafe fn lookup_const(x: Idx) -> u8 {
    (const { [0xEF, 0x0E, 0x0D, 0xBD] })[x as usize]
}

I expected to see this happen: compiler outputs identical asm for both functions.

Instead, this happened: the asm for lookup_local is suboptimal (godbolt):

lookup_local:
        addi    sp, sp, -16
        li      a1, -17
        sb      a1, 12(sp)
        li      a1, 14
        sb      a1, 13(sp)
        li      a1, 13
        sb      a1, 14(sp)
        li      a1, 189
        sb      a1, 15(sp)
        addi    a1, sp, 12
        add     a0, a1, a0
        lbu     a0, 0(a0)
        addi    sp, sp, 16
        ret

lookup_const:
        lui     a1, %hi(.L__unnamed_1)
        addi    a1, a1, %lo(.L__unnamed_1)
        add     a0, a1, a0
        lbu     a0, 0(a0)
        ret

.L__unnamed_1:
        .ascii  "\357\016\r\275"

Instead of a using constant, lookup_local constructs the array on the stack.

This might be a missed optimization in the LLVM, but we could also potentially handle it in rustc (and personally I feel like the latter might be easier).

Meta

rustc --version --verbose:

rustc 1.86.0-nightly (2f348cb7c 2025-01-27)
binary: rustc
commit-hash: 2f348cb7ce4063fa4eb40038e6ada3c5214717bd
commit-date: 2025-01-27
host: x86_64-unknown-linux-gnu
release: 1.86.0-nightly
LLVM version: 19.1.7
above is the code from godbolt, locally I get slightly different output

rustc +nightly ./t.rs --target riscv32i-unknown-none-elf -Copt-level=3 -Zexport-executable-symbols, objdump --disassemble t

#![no_std]
#![no_main]

pub enum Idx {
    _0,
    _1,
    _2,
    _3,
}

#[no_mangle]
#[inline(never)]
pub unsafe fn lookup_local(x: Idx) -> u8 {
    [0xEF, 0x0E, 0x0D, 0xBD][x as usize]
}

#[inline(never)]
#[no_mangle]
pub unsafe fn lookup_const(x: Idx) -> u8 {
    (const { [0xEF, 0x0E, 0x0D, 0xBD] })[x as usize]
}

#[panic_handler]
fn disco_loop(_: &core::panic::PanicInfo) -> ! {
    loop {}
}
000110d8 <lookup_local>:
   110d8: ff010113     	addi	sp, sp, -0x10
   110dc: fef00593     	li	a1, -0x11
   110e0: 00b10623     	sb	a1, 0xc(sp)
   110e4: 00e00593     	li	a1, 0xe
   110e8: 00b106a3     	sb	a1, 0xd(sp)
   110ec: 00d00593     	li	a1, 0xd
   110f0: 00b10723     	sb	a1, 0xe(sp)
   110f4: 0bd00593     	li	a1, 0xbd
   110f8: 00b107a3     	sb	a1, 0xf(sp)
   110fc: 00c10593     	addi	a1, sp, 0xc
   11100: 00a58533     	add	a0, a1, a0
   11104: 00054503     	lbu	a0, 0x0(a0)
   11108: 01010113     	addi	sp, sp, 0x10
   1110c: 00008067     	ret

00011110 <lookup_const>:
   11110: 000105b7     	lui	a1, 0x10
   11114: 0d458593     	addi	a1, a1, 0xd4
   11118: 00a58533     	add	a0, a1, a0
   1111c: 00054503     	lbu	a0, 0x0(a0)
   11120: 00008067     	ret

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

Reproduce the lookup_local and lookup_const functions from the report with rustc at -Copt-level=3 for riscv32i-unknown-none-elf, then inspect the output with objdump --disassemble. Compare the generated assembly and trace the compiler or LLVM optimization path responsible; done means the local immutable array no longer gets constructed on the stack and matches the constant case.

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
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.