Missed optimization opportunity when trivially converting between tuple struct and field struct by field values
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Example code:
#[repr(C)]
pub struct Triple<'a>(&'a [u32], &'a [u32], &'a [u32]);
#[repr(C)]
pub struct ThreeFields<'a> {
a: &'a [u32],
b: &'a [u32],
c: &'a [u32],
}
#[inline(always)]
pub fn should_be_no_op(val: Triple) -> ThreeFields {
ThreeFields {
a: val.0,
b: val.1,
c: val.2,
}
}
pub fn sum_slices_1(val: ThreeFields) -> u32 {
sum(&val)
}
pub fn sum_slices_2(val: Triple) -> u32 {
let val = should_be_no_op(val);
sum(&val)
}
#[inline(never)]
pub fn sum(val: &ThreeFields) -> u32 {
val.a.iter().sum::<u32>() + val.b.iter().sum::<u32>() + val.c.iter().sum::<u32>()
}
In rustc 1.84 stable this generates a number of moves that I don't think need to be there, especially when inlining:
example::sum_slices_1::hc2a0527df8a4985d:
jmp qword ptr [rip + example::sum::h228167780f08fdbb@GOTPCREL]
example::sum_slices_2::hc5b364eabe45dc38:
sub rsp, 56
movups xmm0, xmmword ptr [rdi]
movups xmm1, xmmword ptr [rdi + 16]
movups xmm2, xmmword ptr [rdi + 32]
movups xmmword ptr [rsp + 8], xmm0
movups xmmword ptr [rsp + 24], xmm1
movups xmmword ptr [rsp + 40], xmm2
lea rdi, [rsp + 8]
call qword ptr [rip + example::sum::h228167780f08fdbb@GOTPCREL]
add rsp, 56
ret
See https://rust.godbolt.org/z/3sG9nz3oc
While this is a pretty pointless example, this comes up in situations where you might want to convert a tuple of slices into a struct of slices in order to assign names to the tuple members (I've been running into these issues working on gecs).
See also: https://github.com/rust-lang/rust/issues/107436 and https://github.com/rust-lang/rust/issues/135786
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
Reproduce the minimal Rust example from the issue in the linked Compiler Explorer and compare the generated assembly for sum_slices_1 and sum_slices_2. Read the related issues #107436 and #135786, then investigate the compiler optimization path responsible for the unnecessary struct moves; done means the conversion is optimized without changing the example's behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100