Skip to content

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

Closed

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.

Activity

  1. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Feb 28, 2024
  2. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    S-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issue
    C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing such
    and removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Feb 28, 2024
  3. ZhennanWu commented on Feb 28, 2024

    @ZhennanWu
    Author

    @jieyouxu Please add regression label as rust 1.64 can optimize this code. Rust 1.64 even managed to produce idiomatic code for my project with 11 complex enum variants.

  4. added
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on Feb 28, 2024
  5. dianqk commented on Feb 28, 2024

    @dianqk
    Member

    #121665 might fix this issue.

  6. erikdesjardins commented on Feb 28, 2024

    @erikdesjardins
    Contributor

    Indeed it does, added a test in 4016510

  7. apiraino commented on Feb 28, 2024

    @apiraino
    Contributor

    WG-prioritization assigning priority (Zulip discussion).

    @rustbot label -I-prioritize +P-medium +I-slow

  8. added
    I-slowIssue: Problems and improvements with respect to performance of generated code.
    and removed
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on Feb 28, 2024
  9. added 2 commits that reference this issue on Mar 2, 2024
    d2ac066
    70aa0b8
  10. added a commit that references this issue on Mar 5, 2024
    1abbf61
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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