Skip to content

Common branch folding for enum types fails when there are more than three enum variants. #121719

Closed
@ZhennanWu

Description

@ZhennanWu

I tried this code:
https://godbolt.org/z/Yh7Px49jh

#[repr(C)]
pub struct A {
    x: f64,
    y: u64,
}
#[repr(C)]
pub struct B {
    x: f64,
    y: u32,
}
#[repr(C)]
pub struct C {
    x: f64,
    y: u16,
}
#[repr(C)]
pub struct D {
    x: f64,
    y: u8,
}

pub enum E {
    A(A),
    B(B),
    C(C),
    D(D),
}

impl E {
    #[inline(never)]
    pub fn x(&self) -> &f64 {
        match self {
            E::A(A { x, .. }) | E::B(B { x, .. }) | E::C(C { x, .. }) | E::D(D { x, .. }) => x,
        }
    }
}

I expected to see this happen:

The E::x function gets optimized into a single add instruction since all the field has the same offset

Instead, this happened:

When the enum has four or more variants, the asm generated is

example::E::x:
        mov     rax, rdi
        mov     rcx, qword ptr [rdi]
        lea     rdx, [rip + .LJTI0_0]
        movsxd  rcx, dword ptr [rdx + 4*rcx]
        add     rcx, rdx
        jmp     rcx
.LBB0_1:
        add     rax, 8
        ret
.LJTI0_0:
        .long   .LBB0_1-.LJTI0_0
        .long   .LBB0_1-.LJTI0_0
        .long   .LBB0_1-.LJTI0_0
        .long   .LBB0_1-.LJTI0_0

When the enum has three variants, the folding took effects but still generates strange stuff

example::E::x:
        mov     rax, rdi
        mov     rcx, qword ptr [rdi]
        test    rcx, rcx
        je      .LBB0_2
        cmp     ecx, 1
.LBB0_2:
        add     rax, 8
        ret

When it has two variants, it finally produces idiomatic code

example::E::x:
        lea     rax, [rdi + 8]
        ret

Interestingly, rustc will generate idiomatic code when:

  1. Enum variants not exceeding three
  2. Enum variants share the same layout. As in the demo the field y is used to disrupt the layout.
  3. (Edit) Rustc version <=1.64.

Meta

godbold rustc 1.76.0 with -C opt-level=3 -C target-cpu=x86-64-v3

Edit: Tried more godbolt settings. This is a regression introduced sometime between rust 1.64 and rust 1.65.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchI-slowIssue: Problems and improvements with respect to performance of generated code.P-mediumMedium priorityS-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-untriagedUntriaged performance or correctness regression.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions