Open
Description
I tried this code:
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Len {
Zero = 0,
One,
Two,
Three,
}
#[no_mangle]
pub fn convert_len(len: &Len) -> Option<usize> {
match *len {
// Len::Zero => Some(0), // This produces optimal code.
Len::Zero => None, // This does not: two table lookups, one being identity table.
Len::One => Some(1),
Len::Two => Some(2),
Len::Three => Some(3),
}
}
// Manual optimal code.
#[no_mangle]
pub fn convert_len_optimal(len: &Len) -> Option<usize> {
match *len {
Len::Zero => None,
len => Some(unsafe { std::mem::transmute::<Len, u8>(len) } as usize),
}
}
It gives (Compiler explorer):
convert_len:
movzx eax, byte ptr [rdi]
shl eax, 3
lea rcx, [rip + .Lswitch.table.convert_len]
mov rdx, qword ptr [rax + rcx]
lea rcx, [rip + .Lswitch.table.convert_len.1]
mov rax, qword ptr [rax + rcx]
ret
convert_len_optimal:
movzx edx, byte ptr [rdi]
xor eax, eax
test rdx, rdx
setne al
ret
.Lswitch.table.convert_len:
.zero 8
.quad 1
.quad 2
.quad 3
.Lswitch.table.convert_len.1:
.quad 0
.quad 1
.quad 1
.quad 1
I expect convert_len
to generate code like convert_len_optimal
. No table lookup should be generated, especially not the first identity table. Though I don't expect performance to differ a lot when the cache is hot, but wasting cache on these trivial tables does not worth it.
I'm not sure if LLVM or rustc is to blame here.
Meta
Reproduced on compiler Explorer's 1.84, latest nightly, and local nightly (rustc 1.86.0-nightly (854f22563 2025-01-31)
)