Skip to content

Pattern matching on enum creates unecessary jump table #115742

@Kmeakin

Description

@Kmeakin

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

Metadata

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions