rust-lang / rust-lang/rust

u128 manual byte-reading is not optimized, in contrast to u64

Open
#135,980 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-LLVM C-optimization I-slow T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Code

https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=7e184ab3e02960b05e214be4d73d84e8

use std::hint::black_box;
use std::array::from_fn;

#[inline(never)]
fn test_u64() {
    let n: u64 = black_box(137_777);
    let a: [u8; 8] = black_box(from_fn(|i| ((n >> (i*8)) & 255) as u8));
    let b: [u8; 8] = black_box(n.to_le_bytes());
}

#[inline(never)]
fn test_u128() {
    let n: u128 = black_box(137_777_u128);
    let a: [u8; 16] = black_box(from_fn(|i| ((n >> (i*8)) & 255) as u8));
    let b: [u8; 16] = black_box(n.to_le_bytes());
}

fn main() {
    test_u64();
    test_u128();
}

Expected behavior

In both functions, same LLVM IR and same assembly is generated to evaluate a and b.

Current behavior

u64 byte-by-byte read is optimized so that it just reads a pointer. (The optimization seems to happen at MIR -> LLVM IR level.)

playground::test_u64:
	movq	$137777, -24(%rsp)
	leaq	-24(%rsp), %rax
	#APP
	#NO_APP
	movq	-24(%rsp), %rax
	movq	%rax, -16(%rsp)
	leaq	-16(%rsp), %rax
	#APP
	#NO_APP
	movq	-24(%rsp), %rax
	movq	%rax, -8(%rsp)
	leaq	-8(%rsp), %rax
	#APP
	#NO_APP
	retq

u128 read, however, is not optimized in the same way, and seems to use a whole lot of registers.

playground::test_u128:
	movq	$0, -48(%rsp)
	movq	$137777, -56(%rsp)
	leaq	-56(%rsp), %rax
	#APP
	#NO_APP
	movq	-48(%rsp), %rax
	movq	%rax, %rcx
	shrq	$56, %rcx
	movd	%ecx, %xmm0
	movq	%rax, %rcx
	shrq	$48, %rcx
	movd	%ecx, %xmm1
	movq	%rax, %rcx
	shrq	$40, %rcx
	movd	%ecx, %xmm4
	movq	%rax, %rcx
	shrq	$32, %rcx
	movd	%ecx, %xmm3
	movl	%eax, %ecx
	shrl	$24, %ecx
	movd	%ecx, %xmm5
	movl	%eax, %ecx
	shrl	$16, %ecx
	movd	%ecx, %xmm6
	movq	-56(%rsp), %rcx
	movd	%eax, %xmm2
	shrl	$8, %eax
	movd	%eax, %xmm7
	movq	%rcx, %rax
	shrq	$56, %rax
	movd	%eax, %xmm9
	movq	%rcx, %rax
	shrq	$48, %rax
	movd	%eax, %xmm10
	movq	%rcx, %rax
	shrq	$40, %rax
	movd	%eax, %xmm11
	movq	%rcx, %rax
	shrq	$32, %rax
	movd	%eax, %xmm8
	movl	%ecx, %eax
	shrl	$24, %eax
	movd	%eax, %xmm12
	movl	%ecx, %eax
	shrl	$16, %eax
	movd	%eax, %xmm13
	punpcklbw	%xmm0, %xmm1
	punpcklbw	%xmm4, %xmm3
	punpcklwd	%xmm1, %xmm3
	punpcklbw	%xmm5, %xmm6
	punpcklbw	%xmm7, %xmm2
	punpcklwd	%xmm6, %xmm2
	punpckldq	%xmm3, %xmm2
	punpcklbw	%xmm9, %xmm10
	punpcklbw	%xmm11, %xmm8
	punpcklwd	%xmm10, %xmm8
	movd	%ecx, %xmm0
	movl	%ecx, %eax
	shrl	$8, %eax
	punpcklbw	%xmm12, %xmm13
	movd	%eax, %xmm1
	punpcklbw	%xmm1, %xmm0
	punpcklwd	%xmm13, %xmm0
	punpckldq	%xmm8, %xmm0
	punpcklqdq	%xmm2, %xmm0
	movdqa	%xmm0, -40(%rsp)
	leaq	-40(%rsp), %rax
	#APP
	#NO_APP
	movaps	-56(%rsp), %xmm0
	movaps	%xmm0, -24(%rsp)
	leaq	-24(%rsp), %rax
	#APP
	#NO_APP
	retq

@rustbot labels +C-optimization

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the Rust Playground reproducer in the issue and compare the generated MIR, LLVM IR, and assembly for the u64 and u128 functions. Investigate why the manual u128 byte reads are not lowered like to_le_bytes; done means both forms generate equivalent optimized output.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.