- 
                Notifications
    You must be signed in to change notification settings 
- Fork 5.2k
Open
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Milestone
Description
Repro:
internal ref struct Foo
{
    private readonly Span<int> _span;
    internal Foo(Span<int> span) => _span = span;
    internal void Set(int index)
    {
        if ((uint)index < (uint)_span.Length)
        {
            _span[index] = 42;
        }
    }
}Codegen (x64):
       sub       rsp,38
       xor       eax,eax
       mov       [rsp+28],rax
       mov       [rsp+30],rax
       mov       rax,[rcx+8]
       test      rax,rax
       je        short M00_L02
       lea       rdx,[rax+10]
       mov       eax,[rax+8]
M00_L00:
       lea       rcx,[rsp+28]
       mov       [rcx],rdx
       mov       [rcx+8],eax
       cmp       dword ptr [rsp+30],3
       jbe       short M00_L01
       lea       rdx,[rsp+28]
       cmp       dword ptr [rdx+8],3        ; redundant check for bound-check -- should be elided
       jbe       short M00_L03
       mov       rax,[rdx]
       mov       dword ptr [rax+0C],2A
M00_L01:
       add       rsp,38
       ret
M00_L02:
       xor       edx,edx
       xor       eax,eax
       jmp       short M00_L00
M00_L03:
       call      CORINFO_HELP_RNGCHKFAIL
       int       3
; Total bytes of code 88Workaround: fetch the span to a local.
+Span<int> span = _span;
-if ((uint)index < (uint)_span.Length)
+if ((uint)index < (uint)span.Length)
{
-   _span[index] = 42;
+   span[index] = 42;
}When the index is not constant (here 3), the same issue occurs.
Complete listing of code (C#)
using BenchmarkDotNet.Attributes;
BenchmarkDotNet.Running.BenchmarkRunner.Run<Bench>();
[DisassemblyDiagnoser]
[ShortRunJob]
public class Bench
{
    private readonly int[] _array = new int[100];
    [Benchmark]
    public void NoLocalSpan()
    {
        Foo foo = new(_array);
        foo.Set(3);
    }
    [Benchmark]
    public void LocalSpan()
    {
        Foo1 foo = new(_array);
        foo.Set(3);
    }
}
internal ref struct Foo
{
    private readonly Span<int> _span;
    internal Foo(Span<int> span) => _span = span;
    internal void Set(int index)
    {
        if ((uint)index < (uint)_span.Length)
        {
            _span[index] = 42;
        }
    }
}
internal ref struct Foo1
{
    private readonly Span<int> _span;
    internal Foo1(Span<int> span) => _span = span;
    internal void Set(int index)
    {
        Span<int> span = _span;
        if ((uint)index < (uint)span.Length)
        {
            span[index] = 42;
        }
    }
}Complete listing of generated code
; Bench.NoLocalSpan()
       sub       rsp,38
       xor       eax,eax
       mov       [rsp+28],rax
       mov       [rsp+30],rax
       mov       rax,[rcx+8]
       test      rax,rax
       je        short M00_L02
       lea       rdx,[rax+10]
       mov       eax,[rax+8]
M00_L00:
       lea       rcx,[rsp+28]
       mov       [rcx],rdx
       mov       [rcx+8],eax
       cmp       dword ptr [rsp+30],3
       jbe       short M00_L01
       lea       rdx,[rsp+28]
       cmp       dword ptr [rdx+8],3
       jbe       short M00_L03
       mov       rax,[rdx]
       mov       dword ptr [rax+0C],2A
M00_L01:
       add       rsp,38
       ret
M00_L02:
       xor       edx,edx
       xor       eax,eax
       jmp       short M00_L00
M00_L03:
       call      CORINFO_HELP_RNGCHKFAIL
       int       3
; Total bytes of code 88
; Bench.LocalSpan()
       sub       rsp,18
       xor       eax,eax
       mov       [rsp+8],rax
       mov       [rsp+10],rax
       mov       rax,[rcx+8]
       test      rax,rax
       je        short M00_L02
       lea       rdx,[rax+10]
       mov       eax,[rax+8]
M00_L00:
       lea       rcx,[rsp+8]
       mov       [rcx],rdx
       mov       [rcx+8],eax
       lea       rdx,[rsp+8]
       mov       rax,[rdx]
       mov       edx,[rdx+8]
       cmp       edx,3
       jbe       short M00_L01
       mov       dword ptr [rax+0C],2A
M00_L01:
       add       rsp,18
       ret
M00_L02:
       xor       edx,edx
       xor       eax,eax
       jmp       short M00_L00
; Total bytes of code 77Cf. #67448 (comment)
category:cq
theme:bounds-checks
skill-level:intermediate
cost:small
impact:small
pentp, ReubenBond, 0xfeeddeadbeef and PaulusParssinen
Metadata
Metadata
Assignees
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI