Closed
Description
I tried this code:
pub unsafe fn cannot_elide_bounds_check(s: &[u8]) -> u8 {
let a = *s.get_unchecked(1);
a + s[0]
}
pub unsafe fn can_elide_bounds_check(s: &[u8]) -> u8 {
let a = *s.get(1).unwrap_unchecked();
a + s[0]
}
Compile with -Copt-level=3
on godbolt.org (godbolt link)
I expected to see this happen: Both functions should compile to approximately the same thing, with no bounds check on the s[0]
since the optimizer should be able to see that the slice is at least of length 2 due to the previous unchecked indexing.
example::can_elide_bounds_check:
movzx eax, byte ptr [rdi]
add al, byte ptr [rdi + 1]
ret
Instead, this happened: cannot_elide_bounds_check
contains a bounds check (only can_elide_bounds_check
does not contain a bounds check).
example::cannot_elide_bounds_check:
test rsi, rsi
je .LBB0_2
movzx eax, byte ptr [rdi]
add al, byte ptr [rdi + 1]
ret
.LBB0_2:
push rax
lea rdx, [rip + .L__unnamed_1]
xor edi, edi
xor esi, esi
call qword ptr [rip + core::panicking::panic_bounds_check@GOTPCREL]
ud2
Meta
rustc stable (1.73.0), nightly (2023-10-17), and 1.58.0 (when Option::unwrap_unchecked
was stabilized) all have approximately the same codegen.
rustc --version --verbose
:
rustc 1.75.0-nightly (09df6108c 2023-10-17)
binary: rustc
commit-hash: 09df6108c84fdec400043d99d9ee232336fd5a9f
commit-date: 2023-10-17
host: x86_64-unknown-linux-gnu
release: 1.75.0-nightly
LLVM version: 17.0.2
(no backtrace)
@rustbot label +C-optimization -C-bug