Closed
Description
I tried this code:
pub struct Foo {
i: Vec<usize>,
v: Vec<usize>,
}
impl Foo {
fn get(&self, i: usize) -> Option<&usize> {
let index = self.i.get(i)?;
self.v.get(*index)
}
unsafe fn get_unchecked(&self, i: usize) -> &usize {
let index = self.i.get_unchecked(i);
self.v.get_unchecked(*index)
}
}
pub unsafe fn get_unchecked(f: &Foo, idx: usize) -> &usize {
f.get_unchecked(idx)
}
pub unsafe fn get_unwrap_checked_unreachable(f: &Foo, idx: usize) -> &usize {
f.get(idx).unwrap_or_else(|| std::hint::unreachable_unchecked())
}
pub fn get(f: &Foo, idx: usize) -> Option<&usize> {
f.get(idx)
}
I expected to see this happen: The unwrap_or_else
case generates branch-free assembly.
Instead, this happened:
This was the generated assembly (opt-level 3):
example::get_unchecked:
mov rax, qword ptr [rdi]
mov rax, qword ptr [rax + 8*rsi]
shl rax, 3
add rax, qword ptr [rdi + 24]
ret
example::get_unwrap_checked_unreachable:
xor eax, eax
cmp qword ptr [rdi + 16], rsi
jbe .LBB1_3
mov rcx, qword ptr [rdi]
test rcx, rcx
je .LBB1_3
mov rcx, qword ptr [rcx + 8*rsi]
lea rdx, [8*rcx]
add rdx, qword ptr [rdi + 24]
xor eax, eax
cmp rcx, qword ptr [rdi + 40]
cmovb rax, rdx
.LBB1_3:
ret
example::get:
xor eax, eax
cmp qword ptr [rdi + 16], rsi
jbe .LBB2_3
mov rcx, qword ptr [rdi]
test rcx, rcx
je .LBB2_3
mov rcx, qword ptr [rcx + 8*rsi]
lea rdx, [8*rcx]
add rdx, qword ptr [rdi + 24]
xor eax, eax
cmp rcx, qword ptr [rdi + 40]
cmovb rax, rdx
.LBB2_3:
ret
Meta
Rust version rustc 1.61.0 (fe5b13d 2022-05-18) (on Compiler Explorer)
rustc --version --verbose
:
TODO
(not at my home machine right now, will fill in these details soon)
Context
The primary use case is to have an alternative version of std::hint::unreachable_unchecked
that is checked in debug builds via unreachable!()
, but unchecked in release builds.