Skip to content

JIT: eliminate redundant bounds checks for span.Slice(span.Length - cns)#127488

Merged
EgorBo merged 2 commits intodotnet:mainfrom
EgorBo:fix-127486-redundant-slice-bounds-checks
Apr 28, 2026
Merged

JIT: eliminate redundant bounds checks for span.Slice(span.Length - cns)#127488
EgorBo merged 2 commits intodotnet:mainfrom
EgorBo:fix-127486-redundant-slice-bounds-checks

Conversation

@EgorBo
Copy link
Copy Markdown
Member

@EgorBo EgorBo commented Apr 28, 2026

Closes #127486

For the snippet from the issue:

int Test(ReadOnlySpan<byte> span)
{
    if (span.Length >= sizeof(int))
    {
        return BinaryPrimitives.ReadInt32BigEndian(span.Slice(span.Length - sizeof(int)));
    }
    return -1;
}
-       sub      rsp, 40
-       mov      rcx, bword ptr [rdx]
-       mov      edx, dword ptr [rdx+0x08]
-       cmp      edx, 4
-       jge      SHORT G_M27777_IG05
+       mov      rax, bword ptr [rcx]
+       mov      ecx, dword ptr [rcx+0x08]
+       cmp      ecx, 4
+       jl       SHORT G_M6173_IG05
+       add      ecx, -4
+       add      rax, rcx
+       movbe    eax, dword ptr [rax]
+       ret
        mov      eax, -1
-       add      rsp, 40
        ret
-       lea      eax, [rdx-0x04]
-       cmp      eax, edx
-       ja       SHORT G_M27777_IG07
-       mov      r8d, eax
-       add      rcx, r8
-       sub      edx, eax
-       cmp      edx, 4
-       jl       SHORT G_M27777_IG08
-       movbe    eax, dword ptr [rcx]
-       add      rsp, 40
-       ret
-       call     [System.ThrowHelper:ThrowArgumentOutOfRangeException()]
-       int3
-       mov      ecx, 40
-       call     [System.ThrowHelper:ThrowArgumentOutOfRangeException(int)]
-       int3

Two changes:

  • VN: add identity x - (x + a) == -a so that length - (length - cns) value-numbers to cns. This eliminates the BinaryPrimitives.ReadInt32BigEndian length check after Slice.
  • RangeCheck: in GetRangeFromAssertionsWorker, recognize the correlated relop ADD(A, K) op A (constant K < 0) and fold it when A's lower bound is >= -K (so the add cannot wrap, signed or unsigned). This eliminates the Slice(start) (uint)start > (uint)_length check.

Copilot AI review requested due to automatic review settings April 28, 2026 01:35
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 28, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Two complementary changes:

* VN: add identity 'x - (x + a) == -a' so that 'length - (length - cns)' folds to 'cns', eliminating the BinaryPrimitives length check.

* RangeCheck: in GetRangeFromAssertionsWorker, recognize the correlated relop 'ADD(A, K) op A' (K constant < 0) and fold it when A's lower bound proves ADD(A, K) does not wrap, eliminating the Slice 'start > length' check.

Fixes dotnet#127486

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EgorBo EgorBo force-pushed the fix-127486-redundant-slice-bounds-checks branch from 366d859 to 490ce9b Compare April 28, 2026 01:38
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves CoreCLR JIT optimizations to eliminate redundant bounds checks in the common pattern span.Slice(span.Length - cns) by strengthening value numbering identities and range-check assertion reasoning, enabling subsequent checks (including in BinaryPrimitives.ReadInt32BigEndian) to fold away.

Changes:

  • Extend VN math identities to recognize x - (x + a) / x - (a + x) as -a (non-floating, non-overflowing case).
  • Enhance RangeCheck’s assertion-based relop folding by proving ADD(A, K) < A for negative K when A’s lower bound is high enough to prevent wraparound.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/coreclr/jit/valuenum.cpp Adds a new subtraction identity and cleans up ADD/SUB VNFunc usage to improve VN simplification for length - (length - cns) patterns.
src/coreclr/jit/rangecheck.cpp Adds correlated relop folding logic to eliminate the Slice(start) (uint)start > (uint)_length check when proven false via assertions.

Comment thread src/coreclr/jit/rangecheck.cpp Outdated
Comment thread src/coreclr/jit/rangecheck.cpp
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EgorBo
Copy link
Copy Markdown
Member Author

EgorBo commented Apr 28, 2026

PTAL @jakobbotsch @dotnet/jit-contrib Diffs

@EgorBo EgorBo requested a review from jakobbotsch April 28, 2026 08:54
@EgorBo
Copy link
Copy Markdown
Member Author

EgorBo commented Apr 28, 2026

/ba-g filed #127500 for ios/android failure (there are hits in other PRs)

@EgorBo EgorBo merged commit 4c86aad into dotnet:main Apr 28, 2026
131 of 137 checks passed
@EgorBo EgorBo deleted the fix-127486-redundant-slice-bounds-checks branch April 28, 2026 11:09
EgorBo added a commit that referenced this pull request Apr 28, 2026
…ns (#127485)

Replaces `Unsafe.ReadUnaligned` / `Unsafe.Add` /
`MemoryMarshal.GetReference` usage in
`IBinaryInteger<T>.TryReadBigEndian` (Byte, SByte, Char, Int16/UInt16,
Int32/UInt32, Int64/UInt64, IntPtr/UIntPtr, Int128/UInt128) with safe
equivalents (`BinaryPrimitives.ReadXxxBigEndian` and span indexing). The
JIT is expected to eliminate the resulting bounds checks given the
existing length gates.

> [!NOTE]
> This PR was authored with assistance from Copilot CLI.


---
~~UPD: blocked by #127486
(improved in JIT via #127488)

[Diffs](MihuBot/runtime-utils#1867)

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI reduce-unsafe

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Redundant bound checks around span.Slice(span.Length - CNS)

4 participants