Skip to content
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

It is impossible to implement a span-like container where JIT would elide a custom bounds check #109043

Open
neon-sunset opened this issue Oct 19, 2024 · 1 comment
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI tenet-performance Performance related issue untriaged New issue has not been triaged by the area owner

Comments

@neon-sunset
Copy link
Contributor

Description

Given a custom span-like container Slice<T> and a for loop that iterates over it:

static void For(Slice<int> slice) {
    var sum = 0;
    for (nuint i = 0; i < slice.Length; i++) {
        sum += slice[i];
    }
    Console.WriteLine(sum);
}

unsafe readonly struct Slice<T>(T* ptr, nuint length)
where T: unmanaged {
    public nuint Length => length;

    public T this[nuint index] {
        get {
            ArgumentOutOfRangeException
                .ThrowIfGreaterThanOrEqual(index, length);
            return ptr[index];
        }
    }
}

The For method compiles to

G_M000_IG01:                ;; offset=0x0000
       push     rsi
       push     rbx
       sub      rsp, 40
G_M000_IG02:                ;; offset=0x0006
       mov      rax, qword ptr [rcx]
       mov      rbx, qword ptr [rcx+0x08]
       xor      ecx, ecx
       xor      esi, esi
       test     rbx, rbx
       je       SHORT G_M000_IG04
       align    [10 bytes for IG03]
G_M000_IG03:                ;; offset=0x0020
       cmp      rsi, rbx
       jae      SHORT G_M000_IG06
       add      ecx, dword ptr [rax+4*rsi]
       inc      rsi
       cmp      rsi, rbx
       jb       SHORT G_M000_IG03
G_M000_IG04:                ;; offset=0x0030
       call     [System.Console:WriteLine(int)]
       nop      
G_M000_IG05:                ;; offset=0x0037
       add      rsp, 40
       pop      rbx
       pop      rsi
       ret      
G_M000_IG06:                ;; offset=0x003E
       mov      ecx, 1
       mov      rdx, 0x7FFF9C99D780
       call     CORINFO_HELP_STRCNS
       mov      r8, rax
       mov      rdx, rbx
       mov      rcx, rsi
       call     [System.ArgumentOutOfRangeException:ThrowGreaterEqual[ulong](ulong,ulong,System.String)]
       int3     

Analysis

It appears that no matter the implementation, it is impossible to write the code in a way where the bounds check is elided.
E.g. none of these changes work:

  • writing custom check and throw helper
  • matching loop conditional with bounds check with !(index >= slice.Length)
  • making Length a field
  • using signed and plain int-based indexer and length

Configuration

.NET SDK:
 Version:           9.0.100-rtm.24512.1
 Commit:            5b9d9d4677
 Workload version:  9.0.100-manifests.87287131
 MSBuild version:   17.12.3+4ae11fa8e

Regression?

No

@neon-sunset neon-sunset added the tenet-performance Performance related issue label Oct 19, 2024
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Oct 19, 2024
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Oct 19, 2024
Copy link
Contributor

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

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 tenet-performance Performance related issue untriaged New issue has not been triaged by the area owner
Projects
None yet
Development

No branches or pull requests

1 participant