Skip to content

Pattern matching on enum creates unecessary jump table #115742

Closed
@Kmeakin

Description

I tried this code:
Say we define an AST type for expressions, each carrying a span to give its position in the original source code:

pub type ByteSpan = (u32, u32);

pub enum Expr<'core> {
    Error(ByteSpan),
    Int(ByteSpan, u64),
    Array(ByteSpan, &'core [Self]),
    Call(ByteSpan, &'core Self, &'core [Self]),
}

pub fn span(expr: &Expr) -> ByteSpan {
    match expr {
        Expr::Error(span, ..)
        | Expr::Int(span, ..)
        | Expr::Array(span, ..)
        | Expr::Call(span, ..) => *span,
    }
}

I expected to see this happen:
The ByteSpan is placed at the same offset for every variant of the enum, so the final assembly for span should be:

example::span:
        mov     eax, dword ptr [rdi + 4]
        mov     edx, dword ptr [rdi + 8]
        ret

Instead, this happened:
A jump table is generated, even though every entry in the jump table is identical (godbolt):

example::span:
        mov     eax, dword ptr [rdi]
        lea     rcx, [rip + .LJTI0_0]
        movsxd  rax, dword ptr [rcx + 4*rax]
        add     rax, rcx
        jmp     rax
.LBB0_1:
        lea     rcx, [rdi + 4]
        mov     eax, dword ptr [rdi + 4]
        mov     edx, dword ptr [rcx + 4]
        ret
.LJTI0_0:
        .long   .LBB0_1-.LJTI0_0
        .long   .LBB0_1-.LJTI0_0
        .long   .LBB0_1-.LJTI0_0
        .long   .LBB0_1-.LJTI0_0

If the last 2 variants are removed, the optimal code is produced. If only the last variant is removed, the code is better, but still suboptimal:

example::span:
        mov     eax, dword ptr [rdi]
        test    rax, rax
        je      .LBB0_2
        cmp     eax, 1
.LBB0_2:
        lea     rcx, [rdi + 4]
        mov     eax, dword ptr [rdi + 4]
        mov     edx, dword ptr [rcx + 4]
        ret

Meta

rustc --version --verbose:

rustc 1.74.0-nightly (1e746d774 2023-09-07)
binary: rustc
commit-hash: 1e746d7741d44551e9378daf13b8797322aa0b74
commit-date: 2023-09-07
host: x86_64-unknown-linux-gnu
release: 1.74.0-nightly
LLVM version: 17.0.0
Compiler returned: 0

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-bugCategory: This is a bug.I-slowIssue: Problems and improvements with respect to performance of generated code.llvm-fixed-upstreamIssue expected to be fixed by the next major LLVM upgrade, or backported fixes

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions