Skip to content

Missed optimization when removing intermediate #116150

Open
@ojeda

Description

@ojeda

Using Rust 1.72.0:

pub fn f(err: i32) -> Result<u16, i32> {
    if err < 0 {
        return Err(err);
    }
    
    Ok(err as u16)
}

compiles to:

example::f:
        mov     ecx, edi
        shl     ecx, 16
        xor     eax, eax
        test    edi, edi
        cmovns  eax, ecx
        mov     ecx, edi
        shr     ecx, 31
        shl     rdi, 32
        or      rax, rdi
        or      rax, rcx
        ret

But adding an intermediate before the conditional appears to help:

pub fn f(err: i32) -> Result<u16, i32> {
    let ok = err as u16;

    if err < 0 {
        return Err(err);
    };
    
    Ok(ok)
}

compiles to:

example::f:
        mov     ecx, edi
        shr     ecx, 31
        mov     rax, rdi
        shl     rax, 32
        shl     edi, 16
        or      rax, rdi
        or      rax, rcx
        ret

https://godbolt.org/z/bf6jW9d3c

This intermediate could be an argument in a call, which is in fact how I originally noticed it, i.e. this:

fn to_result_ok<T>(err: i32, ok: T) -> Result<T, i32> {
    if err < 0 {
        return Err(err);
    }
    
    Ok(ok)
}

pub fn f(ret: i32) -> Result<u16, i32> {
    to_result_ok(ret, ret as u16)
}

compiles better than:

pub fn f(ret: i32) -> Result<u16, i32> {
    if ret < 0 {
        return Err(ret);
    }

    Ok(ret as u16)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchI-slowIssue: Problems and improvements with respect to performance of generated code.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions