You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Remove JIT-workaround for eliminating bound check #67044
#62864 taught the JIT to recognize more pattern to eliminate bound checks for array and span indexing. Thus the workarounds like the uint-casts aren't needed anymore, and could be undone.
When working on this issue, the found patterns should be validated manually that excpected codegen happens. If not an issue should be filed, so it can be addressed.
When working on this issue, the found patterns should be validated manually that excpected codegen happens. If not an issue should be filed, so it can be addressed.
Thanks for the summary!
It's probably simpler to blindly change all the patterns which satisfy the conditions above ^ and run jit-diffs, let me know if you need a step-by-step instruction how to do it
Since it looks like this work was made possible by a change to the JIT in net7.0 be careful that your changes won't impact assemblies used on older frameworks.
It looks like (uint)idx < span.Length-pattern doesn't elide the bound-check.
Tested with SDK download from today (7.0.100-preview.4.22181.7) which is based on cbf3f9c, so the work should be in according #67044 (comment) (point 4)
```assembly; Bench.Length_Cmp_Uint_Read()subrsp,28movrax,[rcx+8]testrax,raxje short M00_L02leardx,[rax+10]movr8d,[rax+8]M00_L00:moveax,[rcx+10]movecx,eaxmovsxdr9,r8dcmprcx,r9jge short M00_L01cmpeax,r8djae short M00_L03moveax,eaxmoveax,[rdx+rax*4]addrsp,28retM00_L01:xoreax,eaxaddrsp,28retM00_L02:xoredx,edxxorr8d,r8djmp short M00_L00M00_L03:call CORINFO_HELP_RNGCHKFAILint3; Total bytes of code 69; Bench.Length_Uint_Cmp_Uint_Read()movrax,[rcx+8]testrax,raxje short M00_L02leardx,[rax+10]movr8d,[rax+8]M00_L00:moveax,[rcx+10]cmpeax,r8djae short M00_L01moveax,eaxmoveax,[rdx+rax*4]retM00_L01:xoreax,eaxretM00_L02:xoredx,edxxorr8d,r8djmp short M00_L00; Total bytes of code 41;------------------------------------------------------------------------------; Bench.Length_cmp_Uint_Write()subrsp,28movrax,[rcx+8]testrax,raxje short M00_L02leardx,[rax+10]moveax,[rax+8]M00_L00:movr8d,[rcx+10]movr9d,r8dmovsxdr10,eaxcmpr9,r10jge short M00_L01cmpr8d,eaxjae short M00_L03moveax,r8dmovecx,[rcx+14]mov[rdx+rax*4],ecxM00_L01:addrsp,28retM00_L02:xoredx,edxxoreax,eaxjmp short M00_L00M00_L03:call CORINFO_HELP_RNGCHKFAILint3; Total bytes of code 66; Bench.Length_Uint_cmp_Uint_Write()movrax,[rcx+8]testrax,raxje short M00_L02leardx,[rax+10]moveax,[rax+8]M00_L00:movr8d,[rcx+10]cmpr8d,eaxjae short M00_L01movecx,[rcx+14]moveax,r8dmov[rdx+rax*4],ecxM00_L01:retM00_L02:xoredx,edxxoreax,eaxjmp short M00_L00; Total bytes of code 41
With an array instead of span, the bound check gets elided as expected.
It looks like (uint)idx < span.Length-pattern doesn't elide the bound-check. Tested with SDK download from today (7.0.100-preview.4.22181.7) which is based on cbf3f9c, so the work should be in according #67044 (comment) (point 4)
Activity
gfoidl commentedon Mar 23, 2022
I can look into this issue next week.
EgorBo commentedon Mar 23, 2022
Quick summary:
uintcast is not needed for:array.Length cmp ConstantValue(not sure about cases where cmp is == or !=)array.Length cmp XwhereXis unsignedX <= array.Length && X >= 0- where we explicitly state that X is never negative via two expressions(uint)index < (uint)array.Length-uintcast for array.Length is not necessary (but it is necessary in .NET 6.0)NOTE: array is either Array or [ReadOnly]Span
for the rest cases where we don't tell jit that X is never negative we have to use
uintcast for it - and we can't do anything with it 🤷♂️gfoidl commentedon Mar 23, 2022
When working on this issue, the found patterns should be validated manually that excpected codegen happens. If not an issue should be filed, so it can be addressed.
Thanks for the summary!
EgorBo commentedon Mar 23, 2022
It's probably simpler to blindly change all the patterns which satisfy the conditions above ^ and run jit-diffs, let me know if you need a step-by-step instruction how to do it
gfoidl commentedon Mar 23, 2022
Ah, good to know. Will reach out to you when I need some help on the jit-diffs.
ericstj commentedon Mar 29, 2022
Since it looks like this work was made possible by a change to the JIT in
net7.0be careful that your changes won't impact assemblies used on older frameworks.gfoidl commentedon Mar 30, 2022
I'll do it in CoreLib first, then in a "second iteration" on other libs that are .NET 7 only.
Hoping to start tommorrow with this issue.
gfoidl commentedon Mar 31, 2022
It looks like
(uint)idx < span.Length-pattern doesn't elide the bound-check.Tested with SDK download from today (7.0.100-preview.4.22181.7) which is based on cbf3f9c, so the work should be in according #67044 (comment) (point 4)
C# repro
machine code (x64)
With an array instead of span, the bound check gets elided as expected.
EgorBo commentedon Apr 1, 2022
@gfoidl yes, I forgot to warn you about it, but the fix shouldn't be difficult - I'll file a PR
xtqqczze commentedon Sep 22, 2025
Elided in .NET 9: https://csharp.godbolt.org/z/xn6Yjnqbc