[Expirement] intrinsify span.slice#128298
Conversation
EgorBo
commented
May 17, 2026
Co-authored-by: Copilot <[email protected]>
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
There was a problem hiding this comment.
Pull request overview
Experimental change that intrinsifies the single-argument Span<T>.Slice(int) / ReadOnlySpan<T>.Slice(int) in the JIT. Instead of inlining the managed body, the importer now emits an explicit GT_BOUNDS_CHECK(start, length + 1) plus direct field writes for the resulting span, which produces tighter codegen and — combined with new VN/range-check normalization — lets range-check elimination see through Slice inside hand-vectorized loops (the motivating loop in the description loses one bounds check and one branch).
Changes:
- Add
NI_System_Span_Slice/NI_System_ReadOnlySpan_Sliceintrinsics, recognized only for the 1-arg overload, and expand them inimpIntrinsicinto a bounds check + byref offset + new length, writing into a fresh span temp. - Adjust VN (
fgValueNumberTree) andRangeCheck::MergeEdgeAssertionsWorkerto treat alength + 1bound as equivalent tolengthfor assertion/range-check purposes (the form produced by the new Slice expansion). - Tag
Span.Slice(int)/ReadOnlySpan.Slice(int)with[Intrinsic], exclude them fromCALLEE_INTRINSICinline scoring infgFindJumpTargets, and remove theDebug.Assert(length >= 0)from the internal span constructors.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/System.Private.CoreLib/src/System/Span.cs | Marks Slice(int) [Intrinsic]; removes Debug.Assert(length >= 0) from internal ctor (unexplained). |
| src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs | Same as above for ReadOnlySpan<T>. |
| src/coreclr/jit/namedintrinsiclist.h | New NI_System_Span_Slice / NI_System_ReadOnlySpan_Slice enum entries. |
| src/coreclr/jit/importercalls.cpp | Recognizes only the 1-arg Slice overload and expands it into bounds-check + byref-offset + length-write into a span temp. |
| src/coreclr/jit/fgbasic.cpp | Excludes the new Slice intrinsics from CALLEE_INTRINSIC inline observation so caller heuristics are unchanged. |
| src/coreclr/jit/valuenum.cpp | Registers the inner X as a checked bound when a bound is of the form X + 1, enabling RCE on the Slice-emitted shape. |
| src/coreclr/jit/rangecheck.cpp | Normalizes assertion limits whose bound VN differs from preferredBoundVN by +1 so TightenLimit prefers the tighter asserted limit. |
| @@ -130,8 +130,6 @@ public Span(ref T reference) | |||
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
| internal Span(ref T reference, int length) | |||
| { | |||
| break; | ||
| } | ||
|
|
||
| case NI_System_Span_Slice: |