u128 manual byte-reading is not optimized, in contrast to u64
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Code
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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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