Skip to content

core: make str::split_at_unchecked() inline #143907

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 15, 2025

Conversation

Kijewski
Copy link
Contributor

@Kijewski Kijewski commented Jul 13, 2025

This PR adds #[inline] to the method str::split_at_unchecked(). This is done for two reasons:

  1. The method is tiny, e.g. on AMD-64 (https://godbolt.org/z/ba68fdfxn):

    movq    %rdi, %rax
    subq    %rcx, %rdx
    movq    %rsi, (%rdi)
    addq    %rcx, %rsi
    movq    %rcx, 8(%rdi)
    movq    %rsi, 16(%rdi)
    movq    %rdx, 24(%rdi)
    retq
  2. More importantly, inlining the method enables further automatic optimizations. E.g. if you split at index 3, then in the compiler (rustc, llvm or both) knows that this code cannot fail, and the panicking path is omitted in the generated code:

    pub fn punctuation(i: &str) -> Result<(), ()> {
        const THREE_CHARS: &[[u8; 3]] = &[*b"<<=", *b">>=", *b"...", *b"..="];
    
        if let Some((head, _)) = i.split_at_checked(3)
            && THREE_CHARS.contains(&head.as_bytes().try_into().unwrap())
        {
            Ok(())
        } else {
            Err(())
        }
    }
    Without PR

    https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=0234de8158f467eebd73286f20d6e27a

    playground::punctuation:
            subq    $40, %rsp
            movq    %rsi, %rdx
            movq    %rdi, %rsi
            movb    $1, %al
            cmpq    $3, %rdx
            ja      .LBB2_2
            je      .LBB2_3
    .LBB2_11:
            addq    $40, %rsp
            retq
    .LBB2_2:
            cmpb    $-64, 3(%rsi)
            jl      .LBB2_11
    .LBB2_3:
            leaq    8(%rsp), %rdi
            movl    $3, %ecx
            callq   *core::str::<impl str>::split_at_unchecked@GOTPCREL(%rip)
            movq    8(%rsp), %rcx
            movb    $1, %al
            testq   %rcx, %rcx
            je      .LBB2_11
            cmpq    $3, 16(%rsp)
            jne     .LBB2_12
            movzwl  (%rcx), %edx
            movzbl  2(%rcx), %ecx
            shll    $16, %ecx
            orl     %edx, %ecx
            cmpl    $4013115, %ecx
            jg      .LBB2_8
            cmpl    $3026478, %ecx
            je      .LBB2_10
            cmpl    $4009518, %ecx
            je      .LBB2_10
            jmp     .LBB2_11
    .LBB2_8:
            cmpl    $4013630, %ecx
            je      .LBB2_10
            cmpl    $4013116, %ecx
            jne     .LBB2_11
    .LBB2_10:
            xorl    %eax, %eax
            addq    $40, %rsp
            retq
    .LBB2_12:
            leaq    .Lanon.d98a7fbb86d10a97c24516e267466134.2(%rip), %rdi
            leaq    .Lanon.d98a7fbb86d10a97c24516e267466134.1(%rip), %rcx
            leaq    .Lanon.d98a7fbb86d10a97c24516e267466134.6(%rip), %r8
            leaq    7(%rsp), %rdx
            movl    $43, %esi
            callq   *core::result::unwrap_failed@GOTPCREL(%rip)
    With PR

    https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=5d4058c79ce0f6cb1a434190427d2055

    playground::punctuation:
            movb    $1, %al
            cmpq    $3, %rsi
            ja      .LBB0_2
            je      .LBB0_3
    .LBB0_9:
            retq
    .LBB0_2:
            cmpb    $-64, 3(%rdi)
            jl      .LBB0_9
    .LBB0_3:
            movzwl  (%rdi), %eax
            movzbl  2(%rdi), %ecx
            shll    $16, %ecx
            orl     %eax, %ecx
            movb    $1, %al
            cmpl    $4013115, %ecx
            jg      .LBB0_6
            cmpl    $3026478, %ecx
            je      .LBB0_8
            cmpl    $4009518, %ecx
            je      .LBB0_8
            jmp     .LBB0_9
    .LBB0_6:
            cmpl    $4013630, %ecx
            je      .LBB0_8
            cmpl    $4013116, %ecx
            jne     .LBB0_9
    .LBB0_8:
            xorl    %eax, %eax
            retq

This PR adds `#[inline]` to the method `str::split_at_unchecked()`.
This is done for two reasons:

1. The method is tiny, e.g. on AMD-64 (<https://godbolt.org/z/ba68fdfxn>):

   ```asm
   movq    %rdi, %rax
   subq    %rcx, %rdx
   movq    %rsi, (%rdi)
   addq    %rcx, %rsi
   movq    %rcx, 8(%rdi)
   movq    %rsi, 16(%rdi)
   movq    %rdx, 24(%rdi)
   retq
   ```

2. More importantly, inlining the method enables further automatic
   optimizations. E.g. if you split at index 3, then in the compiler
   (rustc, llvm or both) knows that this code cannot fail, and the
   panicking path is omitted in the generated code:

   ```rust
   pub fn punctuation(i: &str) -> Result<(), ()> {
       const THREE_CHARS: &[[u8; 3]] = &[*b"<<=", *b">>=", *b"...", *b"..="];

       if let Some((head, _)) = i.split_at_checked(3)
           && THREE_CHARS.contains(&head.as_bytes().try_into().unwrap())
       {
           Ok(())
       } else {
           Err(())
       }
   }
   ```

   <details>
   <summary>Without PR</summary>

   <https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=0234de8158f467eebd73286f20d6e27a>

   ```asm
   playground::punctuation:
           subq    $40, %rsp
           movq    %rsi, %rdx
           movq    %rdi, %rsi
           movb    $1, %al
           cmpq    $3, %rdx
           ja      .LBB2_2
           je      .LBB2_3
   .LBB2_11:
           addq    $40, %rsp
           retq
   .LBB2_2:
           cmpb    $-64, 3(%rsi)
           jl      .LBB2_11
   .LBB2_3:
           leaq    8(%rsp), %rdi
           movl    $3, %ecx
           callq   *core::str::<impl str>::split_at_unchecked@GOTPCREL(%rip)
           movq    8(%rsp), %rcx
           movb    $1, %al
           testq   %rcx, %rcx
           je      .LBB2_11
           cmpq    $3, 16(%rsp)
           jne     .LBB2_12
           movzwl  (%rcx), %edx
           movzbl  2(%rcx), %ecx
           shll    $16, %ecx
           orl     %edx, %ecx
           cmpl    $4013115, %ecx
           jg      .LBB2_8
           cmpl    $3026478, %ecx
           je      .LBB2_10
           cmpl    $4009518, %ecx
           je      .LBB2_10
           jmp     .LBB2_11
   .LBB2_8:
           cmpl    $4013630, %ecx
           je      .LBB2_10
           cmpl    $4013116, %ecx
           jne     .LBB2_11
   .LBB2_10:
           xorl    %eax, %eax
           addq    $40, %rsp
           retq
   .LBB2_12:
           leaq    .Lanon.d98a7fbb86d10a97c24516e267466134.2(%rip), %rdi
           leaq    .Lanon.d98a7fbb86d10a97c24516e267466134.1(%rip), %rcx
           leaq    .Lanon.d98a7fbb86d10a97c24516e267466134.6(%rip), %r8
           leaq    7(%rsp), %rdx
           movl    $43, %esi
           callq   *core::result::unwrap_failed@GOTPCREL(%rip)
   ```
   </details>

   <details>
   <summary>With PR</summary>

   <https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=5d4058c79ce0f6cb1a434190427d2055>

   ```asm
   playground::punctuation:
           movb    $1, %al
           cmpq    $3, %rsi
           ja      .LBB0_2
           je      .LBB0_3
   .LBB0_9:
           retq
   .LBB0_2:
           cmpb    $-64, 3(%rdi)
           jl      .LBB0_9
   .LBB0_3:
           movzwl  (%rdi), %eax
           movzbl  2(%rdi), %ecx
           shll    $16, %ecx
           orl     %eax, %ecx
           movb    $1, %al
           cmpl    $4013115, %ecx
           jg      .LBB0_6
           cmpl    $3026478, %ecx
           je      .LBB0_8
           cmpl    $4009518, %ecx
           je      .LBB0_8
           jmp     .LBB0_9
   .LBB0_6:
           cmpl    $4013630, %ecx
           je      .LBB0_8
           cmpl    $4013116, %ecx
           jne     .LBB0_9
   .LBB0_8:
           xorl    %eax, %eax
           retq
   ```
   </details>
@rustbot
Copy link
Collaborator

rustbot commented Jul 13, 2025

r? @Mark-Simulacrum

rustbot has assigned @Mark-Simulacrum.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jul 13, 2025
@Mark-Simulacrum
Copy link
Member

@bors r+

@bors
Copy link
Collaborator

bors commented Jul 15, 2025

📌 Commit 6760cd2 has been approved by Mark-Simulacrum

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 15, 2025
jhpratt added a commit to jhpratt/rust that referenced this pull request Jul 15, 2025
…ked, r=Mark-Simulacrum

core: make `str::split_at_unchecked()` inline

This PR adds `#[inline]` to the method `str::split_at_unchecked()`. This is done for two reasons:

1. The method is tiny, e.g. on AMD-64 (<https://godbolt.org/z/ba68fdfxn>):

   ```asm
   movq    %rdi, %rax
   subq    %rcx, %rdx
   movq    %rsi, (%rdi)
   addq    %rcx, %rsi
   movq    %rcx, 8(%rdi)
   movq    %rsi, 16(%rdi)
   movq    %rdx, 24(%rdi)
   retq
   ```

2. More importantly, inlining the method enables further automatic optimizations. E.g. if you split at index 3, then in the compiler (rustc, llvm or both) knows that this code cannot fail, and the panicking path is omitted in the generated code:

   ```rust
   pub fn punctuation(i: &str) -> Result<(), ()> {
       const THREE_CHARS: &[[u8; 3]] = &[*b"<<=", *b">>=", *b"...", *b"..="];

       if let Some((head, _)) = i.split_at_checked(3)
           && THREE_CHARS.contains(&head.as_bytes().try_into().unwrap())
       {
           Ok(())
       } else {
           Err(())
       }
   }
   ```

   <details>
   <summary>Without PR</summary>

   <https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=0234de8158f467eebd73286f20d6e27a>

   ```asm
   playground::punctuation:
           subq    $40, %rsp
           movq    %rsi, %rdx
           movq    %rdi, %rsi
           movb    $1, %al
           cmpq    $3, %rdx
           ja      .LBB2_2
           je      .LBB2_3
   .LBB2_11:
           addq    $40, %rsp
           retq
   .LBB2_2:
           cmpb    $-64, 3(%rsi)
           jl      .LBB2_11
   .LBB2_3:
           leaq    8(%rsp), %rdi
           movl    $3, %ecx
           callq   *core::str::<impl str>::split_at_unchecked@GOTPCREL(%rip)
           movq    8(%rsp), %rcx
           movb    $1, %al
           testq   %rcx, %rcx
           je      .LBB2_11
           cmpq    $3, 16(%rsp)
           jne     .LBB2_12
           movzwl  (%rcx), %edx
           movzbl  2(%rcx), %ecx
           shll    $16, %ecx
           orl     %edx, %ecx
           cmpl    $4013115, %ecx
           jg      .LBB2_8
           cmpl    $3026478, %ecx
           je      .LBB2_10
           cmpl    $4009518, %ecx
           je      .LBB2_10
           jmp     .LBB2_11
   .LBB2_8:
           cmpl    $4013630, %ecx
           je      .LBB2_10
           cmpl    $4013116, %ecx
           jne     .LBB2_11
   .LBB2_10:
           xorl    %eax, %eax
           addq    $40, %rsp
           retq
   .LBB2_12:
           leaq    .Lanon.d98a7fbb86d10a97c24516e267466134.2(%rip), %rdi
           leaq    .Lanon.d98a7fbb86d10a97c24516e267466134.1(%rip), %rcx
           leaq    .Lanon.d98a7fbb86d10a97c24516e267466134.6(%rip), %r8
           leaq    7(%rsp), %rdx
           movl    $43, %esi
           callq   *core::result::unwrap_failed@GOTPCREL(%rip)
   ```
   </details>

   <details>
   <summary>With PR</summary>

   <https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=5d4058c79ce0f6cb1a434190427d2055>

   ```asm
   playground::punctuation:
           movb    $1, %al
           cmpq    $3, %rsi
           ja      .LBB0_2
           je      .LBB0_3
   .LBB0_9:
           retq
   .LBB0_2:
           cmpb    $-64, 3(%rdi)
           jl      .LBB0_9
   .LBB0_3:
           movzwl  (%rdi), %eax
           movzbl  2(%rdi), %ecx
           shll    $16, %ecx
           orl     %eax, %ecx
           movb    $1, %al
           cmpl    $4013115, %ecx
           jg      .LBB0_6
           cmpl    $3026478, %ecx
           je      .LBB0_8
           cmpl    $4009518, %ecx
           je      .LBB0_8
           jmp     .LBB0_9
   .LBB0_6:
           cmpl    $4013630, %ecx
           je      .LBB0_8
           cmpl    $4013116, %ecx
           jne     .LBB0_9
   .LBB0_8:
           xorl    %eax, %eax
           retq
   ```
   </details>
bors added a commit that referenced this pull request Jul 15, 2025
Rollup of 16 pull requests

Successful merges:

 - #142301 (tests: Fix duplicated-path-in-error fail with musl)
 - #142936 (rustdoc-json: Structured attributes)
 - #143355 (wrapping shift: remove first bitmask and table)
 - #143630 (Drop `./x suggest`)
 - #143738 (Move several float tests to floats/mod.rs)
 - #143752 (Don't panic if WASI_SDK_PATH not set when detecting compiler)
 - #143820 (Fixed a core crate compilation failure when enabling the `optimize_for_size` feature on some targets)
 - #143837 (Adjust `run_make_support::symbols` helpers)
 - #143878 (Port `#[pointee]` to the new attribute parsing infrastructure)
 - #143907 (core: make `str::split_at_unchecked()` inline)
 - #143910 (Add experimental `backtrace-trace-only` std feature)
 - #143927 (Preserve constness in trait objects up to hir ty lowering)
 - #143935 (rustc_type_ir/walk: move docstring to `TypeWalker` itself)
 - #143938 (Update books)
 - #143941 (update `cfg_select!` documentation)
 - #143948 (Update mdbook to 0.4.52)

Failed merges:

 - #143926 (Remove deprecated fields in bootstrap)

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit that referenced this pull request Jul 15, 2025
Rollup of 16 pull requests

Successful merges:

 - #142301 (tests: Fix duplicated-path-in-error fail with musl)
 - #142936 (rustdoc-json: Structured attributes)
 - #143355 (wrapping shift: remove first bitmask and table)
 - #143630 (Drop `./x suggest`)
 - #143738 (Move several float tests to floats/mod.rs)
 - #143752 (Don't panic if WASI_SDK_PATH not set when detecting compiler)
 - #143820 (Fixed a core crate compilation failure when enabling the `optimize_for_size` feature on some targets)
 - #143837 (Adjust `run_make_support::symbols` helpers)
 - #143878 (Port `#[pointee]` to the new attribute parsing infrastructure)
 - #143907 (core: make `str::split_at_unchecked()` inline)
 - #143910 (Add experimental `backtrace-trace-only` std feature)
 - #143927 (Preserve constness in trait objects up to hir ty lowering)
 - #143935 (rustc_type_ir/walk: move docstring to `TypeWalker` itself)
 - #143938 (Update books)
 - #143941 (update `cfg_select!` documentation)
 - #143948 (Update mdbook to 0.4.52)

Failed merges:

 - #143926 (Remove deprecated fields in bootstrap)

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit that referenced this pull request Jul 15, 2025
Rollup of 13 pull requests

Successful merges:

 - #142301 (tests: Fix duplicated-path-in-error fail with musl)
 - #143630 (Drop `./x suggest`)
 - #143736 (Give all bytes of TypeId provenance)
 - #143752 (Don't panic if WASI_SDK_PATH not set when detecting compiler)
 - #143837 (Adjust `run_make_support::symbols` helpers)
 - #143878 (Port `#[pointee]` to the new attribute parsing infrastructure)
 - #143905 (Recover and suggest to use `;` to construct array type)
 - #143907 (core: make `str::split_at_unchecked()` inline)
 - #143910 (Add experimental `backtrace-trace-only` std feature)
 - #143927 (Preserve constness in trait objects up to hir ty lowering)
 - #143935 (rustc_type_ir/walk: move docstring to `TypeWalker` itself)
 - #143938 (Update books)
 - #143941 (update `cfg_select!` documentation)

Failed merges:

 - #143926 (Remove deprecated fields in bootstrap)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 460a627 into rust-lang:master Jul 15, 2025
11 checks passed
@rustbot rustbot added this to the 1.90.0 milestone Jul 15, 2025
rust-timer added a commit that referenced this pull request Jul 15, 2025
Rollup merge of #143907 - Kijewski:pr-inline-split_at_unchecked, r=Mark-Simulacrum

core: make `str::split_at_unchecked()` inline

This PR adds `#[inline]` to the method `str::split_at_unchecked()`. This is done for two reasons:

1. The method is tiny, e.g. on AMD-64 (<https://godbolt.org/z/ba68fdfxn>):

   ```asm
   movq    %rdi, %rax
   subq    %rcx, %rdx
   movq    %rsi, (%rdi)
   addq    %rcx, %rsi
   movq    %rcx, 8(%rdi)
   movq    %rsi, 16(%rdi)
   movq    %rdx, 24(%rdi)
   retq
   ```

2. More importantly, inlining the method enables further automatic optimizations. E.g. if you split at index 3, then in the compiler (rustc, llvm or both) knows that this code cannot fail, and the panicking path is omitted in the generated code:

   ```rust
   pub fn punctuation(i: &str) -> Result<(), ()> {
       const THREE_CHARS: &[[u8; 3]] = &[*b"<<=", *b">>=", *b"...", *b"..="];

       if let Some((head, _)) = i.split_at_checked(3)
           && THREE_CHARS.contains(&head.as_bytes().try_into().unwrap())
       {
           Ok(())
       } else {
           Err(())
       }
   }
   ```

   <details>
   <summary>Without PR</summary>

   <https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=0234de8158f467eebd73286f20d6e27a>

   ```asm
   playground::punctuation:
           subq    $40, %rsp
           movq    %rsi, %rdx
           movq    %rdi, %rsi
           movb    $1, %al
           cmpq    $3, %rdx
           ja      .LBB2_2
           je      .LBB2_3
   .LBB2_11:
           addq    $40, %rsp
           retq
   .LBB2_2:
           cmpb    $-64, 3(%rsi)
           jl      .LBB2_11
   .LBB2_3:
           leaq    8(%rsp), %rdi
           movl    $3, %ecx
           callq   *core::str::<impl str>::split_at_unchecked@GOTPCREL(%rip)
           movq    8(%rsp), %rcx
           movb    $1, %al
           testq   %rcx, %rcx
           je      .LBB2_11
           cmpq    $3, 16(%rsp)
           jne     .LBB2_12
           movzwl  (%rcx), %edx
           movzbl  2(%rcx), %ecx
           shll    $16, %ecx
           orl     %edx, %ecx
           cmpl    $4013115, %ecx
           jg      .LBB2_8
           cmpl    $3026478, %ecx
           je      .LBB2_10
           cmpl    $4009518, %ecx
           je      .LBB2_10
           jmp     .LBB2_11
   .LBB2_8:
           cmpl    $4013630, %ecx
           je      .LBB2_10
           cmpl    $4013116, %ecx
           jne     .LBB2_11
   .LBB2_10:
           xorl    %eax, %eax
           addq    $40, %rsp
           retq
   .LBB2_12:
           leaq    .Lanon.d98a7fbb86d10a97c24516e267466134.2(%rip), %rdi
           leaq    .Lanon.d98a7fbb86d10a97c24516e267466134.1(%rip), %rcx
           leaq    .Lanon.d98a7fbb86d10a97c24516e267466134.6(%rip), %r8
           leaq    7(%rsp), %rdx
           movl    $43, %esi
           callq   *core::result::unwrap_failed@GOTPCREL(%rip)
   ```
   </details>

   <details>
   <summary>With PR</summary>

   <https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=5d4058c79ce0f6cb1a434190427d2055>

   ```asm
   playground::punctuation:
           movb    $1, %al
           cmpq    $3, %rsi
           ja      .LBB0_2
           je      .LBB0_3
   .LBB0_9:
           retq
   .LBB0_2:
           cmpb    $-64, 3(%rdi)
           jl      .LBB0_9
   .LBB0_3:
           movzwl  (%rdi), %eax
           movzbl  2(%rdi), %ecx
           shll    $16, %ecx
           orl     %eax, %ecx
           movb    $1, %al
           cmpl    $4013115, %ecx
           jg      .LBB0_6
           cmpl    $3026478, %ecx
           je      .LBB0_8
           cmpl    $4009518, %ecx
           je      .LBB0_8
           jmp     .LBB0_9
   .LBB0_6:
           cmpl    $4013630, %ecx
           je      .LBB0_8
           cmpl    $4013116, %ecx
           jne     .LBB0_9
   .LBB0_8:
           xorl    %eax, %eax
           retq
   ```
   </details>
@Kijewski Kijewski deleted the pr-inline-split_at_unchecked branch July 15, 2025 15:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants