Suboptimal codegen for match from enum to almost-same-value usize (unnecessary table lookups)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
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))
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the convert_len and convert_len_optimal examples and compare their generated assembly on Compiler Explorer or a nightly compiler. Trace whether the unnecessary switch tables originate in rustc or LLVM. Done means the enum-to-Option<usize> match no longer emits the identity table and produces code comparable to the manual version.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100