Skip to content

Match blocks generate inefficient assembly compared to if/else chain since rust 1.65.0 #110737

Open
@mqudsi

Description

@mqudsi

I would assume that the following two snippets of code would compile to identical assembly

pub fn convert_hex(d: char) -> Option<u32> {
    if ('0'..='9').contains(&d) {
        Some(u32::from(d) - u32::from('0'))
    } else if ('A'..='Z').contains(&d) {
        Some(10 + u32::from(d) - u32::from('A'))
    } else {
        None
    }
}

pub fn convert_hex2(c: char) -> Option<u32> {
    match c {
        '0'..='9' => Some(u32::from(c) - u32::from('0')),
        'A'..='Z' => Some(10 + u32::from(c) - u32::from('A')),
        _ => None,
    }
}

However, as of rustc 1.65.0 convert_hex2 with the match blocks generates suboptimal code that is approximately 30% slower in a microbenchmark. Godbolt link showing asm comparison between 1.64.0 vs 1.69.0.

I don't think it's an LLVM regression since the emitted IR differs between 1.64 and 1.65: https://rust.godbolt.org/z/7b3EbGfj3

Version it worked on

It most recently worked on: 1.64.0

Version with regression

1.65.0 - nightly (as of 1.69.0)

@rustbot modify labels: +regression-from-stable-to-stable -regression-untriaged +A-codegen +C-bug +T-compiler +I-slow

I'll try to bisect the commit behind the change.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-codegenArea: Code generationC-bugCategory: This is a bug.I-slowIssue: Problems and improvements with respect to performance of generated code.P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions