I tried this code:
pub fn test_assert(arr: &[u32], j: usize)->u32{
assert!(j < arr.len() / 2);
arr[j]
}
I expected to see this happen: Since for any nonnegative integer i / 2 < i, j < i / 2 implies that j < i so we should not have bounds check here at indexing.
Instead, this happened: Function checks j twice: first for len / 2 then for len, and generates all code for panics.
example::test_assert:
push rax
mov rax, rsi
shr rax
cmp rax, rdx
jbe .LBB0_3
cmp rdx, rsi
jae .LBB0_2
mov eax, dword ptr [rdi + 4*rdx]
pop rcx
ret
.LBB0_2:
lea rax, [rip + .L__unnamed_1]
mov rdi, rdx
mov rdx, rax
call qword ptr [rip + core::panicking::panic_bounds_check@GOTPCREL]
ud2
.LBB0_3:
lea rdi, [rip + .L__unnamed_2]
lea rdx, [rip + .L__unnamed_3]
mov esi, 35
call qword ptr [rip + core::panicking::panic@GOTPCREL]
ud2
I noticed, that if we shorten slice first, it can remove bounds checks. E.g. this code doesn't generate any bounds checks:
pub fn test_unreachable2(arr: &[u32], j: usize)->u32{
let arr = &arr[..arr.len() / 2];
if j >= arr.len() {
unsafe {
unreachable_unchecked();
}
}
arr[j]
}
example::test_unreachable2:
mov eax, dword ptr [rdi + 4*rdx]
ret
Meta
rustc --version --verbose:
rustc 1.69.0 (84c898d65 2023-04-16)
binary: rustc
commit-hash: 84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc
commit-date: 2023-04-16
host: x86_64-unknown-linux-gnu
release: 1.69.0
LLVM version: 15.0.7
Godbolt link.
I tried this code:
I expected to see this happen: Since for any nonnegative integer
i / 2 < i,j < i / 2implies thatj < iso we should not have bounds check here at indexing.Instead, this happened: Function checks j twice: first for
len / 2then forlen, and generates all code for panics.I noticed, that if we shorten slice first, it can remove bounds checks. E.g. this code doesn't generate any bounds checks:
Meta
rustc --version --verbose:Godbolt link.