Skip to content

Missed optimization: concatenating fixed-size arrays #70439

Closed
@moxian

Description

@moxian

The following three functions are the same semantically - they pack two u64s into 16 bytes in big-endian order, but produce different assembly:

// Naive, and, I assume, idiomatic implementation. Bad assembly with several needless moves.
pub fn test(tup: (u64, u64)) -> [u8; 16] {
    let first = (tup.0).to_be_bytes();
    let second = (tup.1).to_be_bytes();
    let mut key = [0u8; 16];
    key[..8].copy_from_slice(&first[..]);
    key[8..].copy_from_slice(&second[..]);
    key
}

// Unsafe implementation. Good assembly .
pub fn test2(tup: (u64, u64)) -> [u8; 16] {
    let first: [u8; 8] = (tup.0).to_be_bytes();
    let second: [u8; 8] = (tup.1).to_be_bytes();
    let packed: [[u8;8]; 2] = [first, second];
    let key = unsafe { std::mem::transmute(packed) } ;
    key
}

// No unsafe, good assembly .
pub fn test3(tup: (u64, u64)) -> [u8; 16] {
    let first = (tup.0).to_be_bytes();
    let second = (tup.1).to_be_bytes();
    let mut key = [0u8; 16];
    let (f, s) = key.split_at_mut(8);
    f.copy_from_slice(&first[..]);
    s.copy_from_slice(&second[..]);
    key
}

Credits to @memoryruins for coming up with test3.

Godbolt link: https://godbolt.org/z/4QaBp4

It is surprising that naive implementation (test1) produces worse assembly than the other two. I was told I should report this here as a bug.

Meta

rustc 1.42.0 (as reported by godbolt)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-codegenArea: Code generationC-enhancementCategory: An issue proposing an enhancement or a PR with one.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