Skip to content

Eliminate bound checks for "% arr.Length" when possible#130156

Draft
henriquewr wants to merge 11 commits into
dotnet:mainfrom
henriquewr:boundCheckMod
Draft

Eliminate bound checks for "% arr.Length" when possible#130156
henriquewr wants to merge 11 commits into
dotnet:mainfrom
henriquewr:boundCheckMod

Conversation

@henriquewr

@henriquewr henriquewr commented Jul 3, 2026

Copy link
Copy Markdown

fixes #130155

Pattern [index % arr.Length]:

static int Test(int index, int len)
{
    if (index >= 0)
    {
        var arr = new int[len];

        return arr[index % arr.Length];
    }

    return 1234;
}

went from

; Method BoundCheckTests.Program:Test(int,int):int (FullOpts)
G_M000_IG01:                ;; offset=0x0000
       push     rbx
       sub      rsp, 32
       mov      ebx, ecx

G_M000_IG02:                ;; offset=0x0007
       test     ebx, ebx
       jge      SHORT G_M000_IG05

G_M000_IG03:                ;; offset=0x000B
       mov      eax, 0x4D2

G_M000_IG04:                ;; offset=0x0010
       add      rsp, 32
       pop      rbx
       ret      

G_M000_IG05:                ;; offset=0x0016
       movsxd   rdx, edx
       mov      rcx, 0x7FFD39B6A7D0
       call     CORINFO_HELP_NEWARR_1_VC
       mov      rcx, rax
       mov      r8d, dword ptr [rcx+0x08]
       mov      eax, ebx
       cdq      
       idiv     edx:eax, r8d
       cmp      edx, r8d
       jae      SHORT G_M000_IG07
       mov      eax, edx
       mov      eax, dword ptr [rcx+4*rax+0x10]

G_M000_IG06:                ;; offset=0x0040
       add      rsp, 32
       pop      rbx
       ret      

G_M000_IG07:                ;; offset=0x0046
       call     CORINFO_HELP_RNGCHKFAIL
       int3     
; Total bytes of code: 76

to

; Method BoundCheckTests.Program:Test(int,int):int (FullOpts)
G_M50457_IG01:  ;; offset=0x0000
       push     rbx
       sub      rsp, 32
       mov      ebx, ecx
						;; size=7 bbWeight=1 PerfScore 1.50

G_M50457_IG02:  ;; offset=0x0007
       test     ebx, ebx
       jge      SHORT G_M50457_IG05
						;; size=4 bbWeight=1 PerfScore 1.25

G_M50457_IG03:  ;; offset=0x000B
       mov      eax, 0x4D2
						;; size=5 bbWeight=0.50 PerfScore 0.12

G_M50457_IG04:  ;; offset=0x0010
       add      rsp, 32
       pop      rbx
       ret      
						;; size=6 bbWeight=0.50 PerfScore 0.88

G_M50457_IG05:  ;; offset=0x0016
       movsxd   rdx, edx
       mov      rcx, 0x7FFD2E8773C0      ; int[]
       call     CORINFO_HELP_NEWARR_1_VC
       mov      rcx, rax
       mov      r8d, dword ptr [rcx+0x08]
       mov      eax, ebx
       xor      edx, edx
       div      edx:eax, r8d
       mov      eax, edx
       mov      eax, dword ptr [rcx+4*rax+0x10]
						;; size=38 bbWeight=0.50 PerfScore 15.75

G_M50457_IG06:  ;; offset=0x003C
       add      rsp, 32
       pop      rbx
       ret      
						;; size=6 bbWeight=0.50 PerfScore 0.88
; Total bytes of code: 66

Pattern [arr.Length % index]:

(variants index < arr.Length, arr.Length > index, arr.Length >= works too)

static int Test(int index, int len)
{
    var arr = new int[len];

    if (arr.Length > 0 && index <= arr.Length)
    {
        return arr[arr.Length % index];
    }

    return 1234;
}

From:

; Method BoundCheckTests.Program:Test(int,int):int (FullOpts)
G_M000_IG01:                ;; offset=0x0000
       push     rbx
       sub      rsp, 32
       mov      ebx, ecx

G_M000_IG02:                ;; offset=0x0007
       movsxd   rdx, edx
       mov      rcx, 0x7FFD39B6A7D0
       call     CORINFO_HELP_NEWARR_1_VC
       mov      rcx, rax
       mov      r8d, dword ptr [rcx+0x08]
       test     r8d, r8d
       je       SHORT G_M000_IG04

G_M000_IG03:                ;; offset=0x0025
       cmp      r8d, ebx
       jge      SHORT G_M000_IG06

G_M000_IG04:                ;; offset=0x002A
       mov      eax, 0x4D2

G_M000_IG05:                ;; offset=0x002F
       add      rsp, 32
       pop      rbx
       ret      

G_M000_IG06:                ;; offset=0x0035
       mov      eax, r8d
       cdq      
       idiv     edx:eax, ebx
       cmp      edx, r8d
       jae      SHORT G_M000_IG08
       mov      eax, edx
       mov      eax, dword ptr [rcx+4*rax+0x10]

G_M000_IG07:                ;; offset=0x0046
       add      rsp, 32
       pop      rbx
       ret      

G_M000_IG08:                ;; offset=0x004C
       call     CORINFO_HELP_RNGCHKFAIL
       int3     
; Total bytes of code: 82

to

; Method BoundCheckTests.Program:Test(int,int):int (FullOpts)
G_M50457_IG01:  ;; offset=0x0000
       push     rbx
       sub      rsp, 32
       mov      ebx, ecx
						;; size=7 bbWeight=1 PerfScore 1.50

G_M50457_IG02:  ;; offset=0x0007
       movsxd   rdx, edx
       mov      rcx, 0x7FFD2E8573C0      ; int[]
       call     CORINFO_HELP_NEWARR_1_VC
       mov      rcx, rax
       mov      eax, dword ptr [rcx+0x08]
       test     eax, eax
       je       SHORT G_M50457_IG04
						;; size=28 bbWeight=1 PerfScore 5.00

G_M50457_IG03:  ;; offset=0x0023
       cmp      eax, ebx
       jge      SHORT G_M50457_IG06
						;; size=4 bbWeight=0.50 PerfScore 0.62

G_M50457_IG04:  ;; offset=0x0027
       mov      eax, 0x4D2
						;; size=5 bbWeight=0.50 PerfScore 0.12

G_M50457_IG05:  ;; offset=0x002C
       add      rsp, 32
       pop      rbx
       ret      
						;; size=6 bbWeight=0.50 PerfScore 0.88

G_M50457_IG06:  ;; offset=0x0032
       cdq      
       idiv     edx:eax, ebx
       mov      eax, edx
       mov      eax, dword ptr [rcx+4*rax+0x10]
						;; size=9 bbWeight=0.50 PerfScore 13.88

G_M50457_IG07:  ;; offset=0x003B
       add      rsp, 32
       pop      rbx
       ret      
						;; size=6 bbWeight=0.50 PerfScore 0.88
; Total bytes of code: 65

Pattern [(uint)arr.Length % (uint)index]:

static int Test(uint index, int len)
{
    var arr = new int[len];

    if (arr.Length > 0)
    {
        return arr[(uint)arr.Length % index];
    }

    return 1234;
}

From

To

@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 Jul 3, 2026
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Jul 3, 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.

@henriquewr henriquewr marked this pull request as draft July 3, 2026 01:18
@henriquewr henriquewr marked this pull request as ready for review July 3, 2026 02:38
Comment thread src/coreclr/jit/rangecheck.h Outdated
return Range(Limit(Limit::keConstant, 0), Limit(Limit::keConstant, rightLimit));
}

return Range(Limit(Limit::keConstant, 0), Limit(Limit::keUnknown));

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Is there a way of representing the maximum value possible? (limit is int32 in the ctor)
Im not sure how ranges above 32 bits are representable

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Rangecheck is 32bit limited.

@EgorBo

EgorBo commented Jul 3, 2026

Copy link
Copy Markdown
Member

CI failures are related

@EgorBo EgorBo marked this pull request as draft July 5, 2026 13:01
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 community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Eliminate bound checks for "% arr.Length" when possible

3 participants