Skip to content

Bounds check not elided for index that should be known to be in-bounds #139759

Open
@okaneco

Description

@okaneco

When calculating a new index with valid_index.saturating_sub(1), I expected the bounds check to be elided. Instead, get_unchecked must be used to eliminate the check.
https://rust.godbolt.org/z/3d8o81T5h

#[inline(never)]
pub fn src(s: &[i32], index: usize) -> i32 {
    if index < s.len() {
        let lower_bound = index.saturating_sub(1);
        s[lower_bound]
    } else {
        -1
    }
}

#[inline(never)]
pub fn tgt(s: &[i32], index: usize) -> i32 {
    if index < s.len() {
        let lower_bound = index.saturating_sub(1);

        // SAFETY: 0 <= lower_bound <= index < s.len()
        unsafe { *s.get_unchecked(lower_bound) }
    } else {
        -1
    }
}
Assembly
example::src::he0570b220ad4b59c:
        mov     eax, -1
        cmp     rdx, rsi
        jae     .LBB0_3
        xor     eax, eax
        sub     rdx, 1
        cmovae  rax, rdx
        cmp     rax, rsi
        jae     .LBB0_4
        mov     eax, dword ptr [rdi + 4*rax]
.LBB0_3:
        ret
.LBB0_4:
        push    rax
        lea     rdx, [rip + .Lanon.75debc62a0d2e1b3b01bdfb8cd64dd40.1]
        mov     rdi, rax
        call    qword ptr [rip + core::panicking::panic_bounds_check::hbc0e9d687b85ab6e@GOTPCREL]

.Lanon.75debc62a0d2e1b3b01bdfb8cd64dd40.0:
        .ascii  "/app/example.rs"

.Lanon.75debc62a0d2e1b3b01bdfb8cd64dd40.1:
        .quad   .Lanon.75debc62a0d2e1b3b01bdfb8cd64dd40.0
        .asciz  "\017\000\000\000\000\000\000\000\005\000\000\000\t\000\000"
example::tgt::h9b445c80275c4bef:
        mov     eax, -1
        cmp     rdx, rsi
        jae     .LBB0_2
        xor     eax, eax
        sub     rdx, 1
        cmovae  rax, rdx
        mov     eax, dword ptr [rdi + 4*rax]
.LBB0_2:
        ret

I came across this while starting to constify floor_char_boundary by rewriting it into a while loop.
https://rust.godbolt.org/z/zEYvEPG8v

Meta

rustc 1.88.0-nightly (0fe8f3454 2025-04-10)
binary: rustc
commit-hash: 0fe8f3454dbe9dda52a254991347e96bec579a6f
commit-date: 2025-04-10
host: x86_64-unknown-linux-gnu
release: 1.88.0-nightly
LLVM version: 20.1.2
Internal compiler ID: nightly

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchI-slowIssue: Problems and improvements with respect to performance of generated code.llvm-fixed-upstreamIssue expected to be fixed by the next major LLVM upgrade, or backported fixes

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions