Suboptimal register allocation across loops
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
This is inspired from https://github.com/rust-lang/rustc-hash/pull/34.
When several loops (or I guess conditionals) modify a common 1-word variable one after the other, this variable gets written too much to memory.
A MRE is
#[no_mangle]
pub fn foo(x: &mut u64, y: u64, z: &[u64]) {
*x *= y;
for &z in z {
*x *= z;
}
}
which is codegened (on nightly) to
foo:
imul rsi, qword ptr [rdi]
mov qword ptr [rdi], rsi
test rcx, rcx
je .LBB2_4
shl rcx, 3
xor eax, eax
.LBB2_2:
imul rsi, qword ptr [rdx + rax]
add rax, 8
cmp rcx, rax
jne .LBB2_2
mov qword ptr [rdi], rsi
.LBB2_4:
ret
where both mov qword ptr [rdi], rsi could be replaced by a single one right before the ret.
On the other hand, this code forces the x to be kept in a register.
#[no_mangle]
pub fn bar(x: &mut u64, y: u64, z: &[u64]) {
let mut xx = *x;
xx *= y;
for &z in z {
xx *= z;
}
*x = xx
}
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 MREs foo and bar, then compare their generated assembly, focusing on the loop and the stores through x. Investigate the compiler's register-allocation behavior across the loop boundary. Done means the foo codegen avoids the redundant intermediate memory writes while preserving the observed 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
- 35/100