Skip to content

Suboptimal codegen when using unwrap_or_else with unreachable_unchecked #98468

Closed
@james7132

Description

@james7132

I tried this code:

pub struct Foo {
    i: Vec<usize>,
    v: Vec<usize>,
}

impl Foo {
    fn get(&self, i: usize) -> Option<&usize> {
        let index = self.i.get(i)?;
        self.v.get(*index)
    }

    unsafe fn get_unchecked(&self, i: usize) -> &usize {
        let index = self.i.get_unchecked(i);
        self.v.get_unchecked(*index)
    }
}

pub unsafe fn get_unchecked(f: &Foo, idx: usize) -> &usize {
    f.get_unchecked(idx)
}

pub unsafe fn get_unwrap_checked_unreachable(f: &Foo, idx: usize) -> &usize {
    f.get(idx).unwrap_or_else(|| std::hint::unreachable_unchecked())
}

pub fn get(f: &Foo, idx: usize) -> Option<&usize> {
    f.get(idx)
}

I expected to see this happen: The unwrap_or_else case generates branch-free assembly.

Instead, this happened:

This was the generated assembly (opt-level 3):

example::get_unchecked:
        mov     rax, qword ptr [rdi]
        mov     rax, qword ptr [rax + 8*rsi]
        shl     rax, 3
        add     rax, qword ptr [rdi + 24]
        ret

example::get_unwrap_checked_unreachable:
        xor     eax, eax
        cmp     qword ptr [rdi + 16], rsi
        jbe     .LBB1_3
        mov     rcx, qword ptr [rdi]
        test    rcx, rcx
        je      .LBB1_3
        mov     rcx, qword ptr [rcx + 8*rsi]
        lea     rdx, [8*rcx]
        add     rdx, qword ptr [rdi + 24]
        xor     eax, eax
        cmp     rcx, qword ptr [rdi + 40]
        cmovb   rax, rdx
.LBB1_3:
        ret

example::get:
        xor     eax, eax
        cmp     qword ptr [rdi + 16], rsi
        jbe     .LBB2_3
        mov     rcx, qword ptr [rdi]
        test    rcx, rcx
        je      .LBB2_3
        mov     rcx, qword ptr [rcx + 8*rsi]
        lea     rdx, [8*rcx]
        add     rdx, qword ptr [rdi + 24]
        xor     eax, eax
        cmp     rcx, qword ptr [rdi + 40]
        cmovb   rax, rdx
.LBB2_3:
        ret

Meta

Rust version rustc 1.61.0 (fe5b13d 2022-05-18) (on Compiler Explorer)

rustc --version --verbose:

TODO

(not at my home machine right now, will fill in these details soon)

Context

The primary use case is to have an alternative version of std::hint::unreachable_unchecked that is checked in debug builds via unreachable!(), but unchecked in release builds.

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.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