Missed optimization: converting "equivalent" enums · Issue #116272 · rust-lang/rust (original) (raw)

With Rust 1.72.0:

#[repr(u32)] pub enum E1 { A = 0, B = 1, C = 255, }

pub enum E2 { A = 0, B = 1, C = 255, }

pub fn f(e: E1) -> E2 { match e { E1::A => E2::A, E1::B => E2::B, E1::C => E2::C, } }

pub fn g(e: E2) -> E1 { match e { E2::A => E1::A, E2::B => E1::B, E2::C => E1::C, } }

compiles to branches (f) and a table-based approach (g):

example::f: test edi, edi je .LBB0_1 cmp edi, 1 jne .LBB0_4 mov al, 1 ret .LBB0_1: xor eax, eax ret .LBB0_4: mov al, -1 ret

example::g: inc dil movsx rax, dil lea rcx, [rip + .Lswitch.table.example::g] mov eax, dword ptr [rcx + 4*rax] ret

.Lswitch.table.example::g: .long 255 .long 0 .long 1

However, they could simply be:

example::f: mov eax, edi ret

example::g: movzx eax, dil ret

https://godbolt.org/z/Ko5cKKojh

The compiler figures it out correctly if the values are contiguous (e.g. changing 255 above to 2), or if the sizes / repr is the same.

This sort of code may happen when one is safely wrapping an automatically generated Rust enum from (e.g. from C code) into a better enum (e.g. with a smaller layout, better docs or more idiomatic variant names).