Poor optimization combining slice::strip_prefix and array::try_from
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
In the playground, this code
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct Id(u64);
impl Id {
// Carefully chosen to be eight bytes so it can be loaded all at once and compared using a
// normal integer register.
const PREFIX: &[u8; 8] = b"prefix::";
pub fn extract(contents: &[u8]) -> Option<Self> {
let contents = contents.strip_prefix(Self::PREFIX)?;
let raw_id = u64::from_be_bytes(contents.try_into().ok()?);
Some(Self(raw_id))
}
}
produces this assembly
playground::Id::extract:
cmpq $8, %rsi
jb .LBB0_5
movabsq $4195798396933862000, %rax
xorl %ecx, %ecx
cmpq %rax, (%rdi)
setne %dl
xorl %eax, %eax
cmpq $16, %rsi
jne .LBB0_6
movb %dl, %cl
testl %ecx, %ecx
jne .LBB0_4
movq 8(%rdi), %rdx
bswapq %rdx
movl $1, %eax
.LBB0_4:
retq
.LBB0_5:
xorl %eax, %eax
.LBB0_6:
retq
which is weird in several ways:
- Multiple exit point labels (not actually harmful, as currently structured both
retqinstructions are needed, but still odd) cmpq $8/jbfollowed by latercmpq $16/jneeven though the function will return None either way.- Clearing of
ecxonly to be overwritten later - Use of
setneto avoid a branch, only to branch on it later.
I realize most of these are probably LLVM-level issues, but I figured I'd start here in case the Rust->LLVM layer is involved.
Meta
Playground using Rust stable 1.89.0.
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 linked Rust Playground reproducer on stable 1.89.0 and inspect the emitted assembly for Id::extract. Compare stable, beta, and nightly as suggested by the issue, then determine whether the redundant checks and exits originate in the Rust-to-LLVM layer or later. Done means identifying the responsible stage and improving or documenting the generated code with a focused regression test if the project supports one.
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