rust-lang / rust-lang/rust

Poor optimization combining slice::strip_prefix and array::try_from

Open
#145,942 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-LLVM C-optimization T-compiler
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 retq instructions are needed, but still odd)
  • cmpq $8 / jb followed by later cmpq $16 / jne even though the function will return None either way.
  • Clearing of ecx only to be overwritten later
  • Use of setne to 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

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 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.