Skip to content

Slicing a span with a list pattern produces unnecessary bounds check #120607

@neon-sunset

Description

@neon-sunset

Description

Given

static Span<byte> M(Span<byte> input) =>
    input switch {
        [_, ..var rest] => rest,
        _ => input
    };

Roslyn produces

static Span<byte> M(Span <byte> input)
{
  int length = input.Length;
  Span <byte> span;
  if (length >= 1)
    span = input.Slice(1, length - 1);
  else
    span = input;
  return span;
}

Which is then compiled to

// coreclr trunk-20251010+e572463b5706b0509fe0c524d9d09893e7e252da

Program:M(System.Span`1[byte]):System.Span`1[byte] (FullOpts):
       push     rbp
       mov      rbp, rsp
       test     esi, esi
       jg       SHORT G_M16130_IG04
       mov      rax, rdi
       mov      edx, esi
       jmp      SHORT G_M16130_IG05
G_M16130_IG04:  ;; offset=0x000F
       lea      edx, [rsi-0x01]
       mov      eax, edx
       inc      rax
       mov      ecx, esi
       cmp      rax, rcx
       ja       SHORT G_M16130_IG06
       lea      rax, bword ptr [rdi+0x01]
G_M16130_IG05:  ;; offset=0x0022
       pop      rbp
       ret      
G_M16130_IG06:  ;; offset=0x0024
       call     [System.ThrowHelper:ThrowArgumentOutOfRangeException()]
       int3     

Notably, rewriting it as

Span<byte> span;
if (input.Length >= 1)
    span = input.Slice(1, input.Length - 1);
else
    span = input;
return span;

results in the same output (also an issue with strings)

Configuration

.NET runtime main branch commit e572463

Regression?

No

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMItenet-performancePerformance related issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions