Skip to content

ptr::read() is slower than directly dereferencing #73258

Closed

Description

@jrmuizel
#[derive(Clone, Copy)]
pub enum Foo {
    A, B, C, D,
}

pub fn foo(v: *const Foo) -> Foo {
    let k: Option<Foo> = unsafe { Some(*v) };
    return k.unwrap();
}

compiles to

example::foo:
        mov     al, byte ptr [rdi]
        ret

but replacing *v with v.read()

#[derive(Clone, Copy)]
pub enum Foo {
    A, B, C, D,
}

pub fn foo(v: *const Foo) -> Foo {
    let k: Option<Foo> = unsafe { Some(v.read()) };
    return k.unwrap();
}

compiles to:

example::foo:
        push    rax
        mov     al, byte ptr [rdi]
        cmp     al, 4
        je      .LBB0_1
        pop     rcx
        ret
.LBB0_1:
        lea     rdi, [rip + .L__unnamed_1]
        lea     rdx, [rip + .L__unnamed_2]
        mov     esi, 43
        call    qword ptr [rip + core::panicking::panic@GOTPCREL]
        ud2

This came up from #71257

Activity

  1. alex commented on Jun 11, 2020

    @alex
    Member

    godbolt for the bad version here: https://rust.godbolt.org/z/CWboVo

    took me a second, but the panic is from the unwrap, suggesting that the discriminant range isn't propagated correctly

  2. added
    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.
    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.
    A-codegenArea: Code generation
    on Jun 11, 2020
  3. jrmuizel commented on Jun 13, 2020

    @jrmuizel
    ContributorAuthor

    This is presumably because the copy_nonoverlapping in the implementation of ptr::read() does not emit range metadata.

  4. hanna-kruppe commented on Jun 14, 2020

    @hanna-kruppe
    Contributor

    This matches my impression from skimming over -print-after-all output, though I'll add that the call to ptr::read() does have the range metadata, so if that metadata got propagated before or during inlining, we'd probably be in a better position. But a simpler solution in the short term might be to implement ptr::read with a compiler intrinsic instead of the current MaybeUninit+copy_nonoverlapping contraption.

  5. scottmcm commented on Mar 12, 2023

    @scottmcm
    Member

    LLVM-IR diff: https://rust.godbolt.org/z/vMex9ooxq

    Looks like the root cause is that read doesn't get !range metadata:

    -  %_3 = load i8, ptr %v, align 1, !dbg !11, !range !13, !noundef !10
    +  %tmp.0.copyload = load i8, ptr %v, align 1, !dbg !11

    Will hopefully be fixed by #109035

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-codegenArea: Code generationC-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