Chained pattern matching not eliminating str/arr bounds check

Open
#119,508 3 comments 0 reactions 1 assignee View on GitHub

@EgorBo is already working on this.

Since Sep 10, 2025.

Assessment

This issue has not been assessed yet.

Description

area-CodeGen-coreclr tenet-performance

The pattern str is { Length: 1 } && str[0] is 'x' or 'y' does not eliminate bounds checks when accessing the first char of the string (or array).

Adding extra indirection with && (sdr[0] is char c) && c is 'x' or 'y' does.

If there is only a single match in the indexer call, e.g. str[0] is 'z' the range check is properly eliminated.

Reproduces on older versions of .NET as well.

class Program
{
    // range check
    public static bool IsFlagsFormat(string? format) => format is { Length: 1 } && format[0] is 'f' or 'F';
    public static bool IsFlagsFormat(char[]? format) => format is { Length: 1 } && format[0] is 'f' or 'F';

    // no range check
    public static bool IsFlagsFormat2(string? format) => format is { Length: 1 } && (format[0] is char c) && (c is 'f' or 'F');
    public static bool IsFlagsFormat2(char[]? format) => format is { Length: 1 } && (format[0] is char c) && (c is 'f' or 'F');
}

https://godbolt.org/z/rKfbffMqE

Program:IsFlagsFormat(System.String):bool (FullOpts):
       push     rbp
       mov      rbp, rsp
       test     rdi, rdi
       je       SHORT G_M36473_IG04
       xor      eax, eax
       cmp      dword ptr [rdi+0x08], 1
       sete     al
       jmp      SHORT G_M36473_IG05
G_M36473_IG04:  ;; offset=0x0014
       xor      eax, eax
G_M36473_IG05:  ;; offset=0x0016
       movzx    rax, al
       test     eax, eax
       je       SHORT G_M36473_IG09
       cmp      dword ptr [rdi+0x08], 0
       jbe      SHORT G_M36473_IG10
       movzx    rax, word  ptr [rdi+0x0C]
       cmp      eax, 70
       je       SHORT G_M36473_IG07
       cmp      eax, 102
       jne      SHORT G_M36473_IG08
G_M36473_IG07:  ;; offset=0x0031
       mov      eax, 1
       jmp      SHORT G_M36473_IG09
G_M36473_IG08:  ;; offset=0x0038
       xor      eax, eax
G_M36473_IG09:  ;; offset=0x003A
       pop      rbp
       ret      
G_M36473_IG10:  ;; offset=0x003C
       call     CORINFO_HELP_RNGCHKFAIL
       int3   
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from dotnet/runtime

All issues in dotnet/runtime

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.