Skip to content

Inconsistent inlining of IndexOfAny vs IndexOfAnyExcept helpers #76843

Description

@MihaZupan

The (ReadOnlySpan<T> span, ReadOnlySpan<T> values) overloads of different IndexOfAny helpers have inconsistent inlining hints:

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOfAny<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> values) where T : IEquatable<T>?

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LastIndexOfAny<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> values) where T : IEquatable<T>?

vs.
/// </returns>
public static int IndexOfAnyExcept<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> values) where T : IEquatable<T>?

/// </returns>
public static int LastIndexOfAnyExcept<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> values) where T : IEquatable<T>?


From @stephentoub in #76740 (comment):

a) we should make these consistent, and b) we should seriously reconsider the aggressive inlining that's on there (or consider how IsKnownConstant could be used here). If the values passed is a constant, then the JIT can do a good job of trimming away all of these branches. But if it's not, it results in significant code bloat to the call site, e.g. this:

private static bool Contains(string text, string values) =>
    text.AsSpan().IndexOfAny(values) >= 0;

results in this:

; Assembly listing for method ConsoleApp15.Program:Contains(System.String,System.String):bool
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; 2 inlinees with PGO data; 23 single block inlinees; 1 inlinees without PGO data

G_M000_IG01:                ;; offset=0000H
       4883EC48             sub      rsp, 72
 
G_M000_IG02:                ;; offset=0004H
       4885C9               test     rcx, rcx
       7475                 je       SHORT G_M000_IG10
 
G_M000_IG03:                ;; offset=0009H
       4C8D410C             lea      r8, bword ptr [rcx+0CH]
       8B4908               mov      ecx, dword ptr [rcx+08H]
 
G_M000_IG04:                ;; offset=0010H
       8BC1                 mov      eax, ecx
       4885D2               test     rdx, rdx
       7442                 je       SHORT G_M000_IG08
 
G_M000_IG05:                ;; offset=0017H
       488D4A0C             lea      rcx, bword ptr [rdx+0CH]
       448B4A08             mov      r9d, dword ptr [rdx+08H]
 
G_M000_IG06:                ;; offset=001FH
       8BD0                 mov      edx, eax
       89542444             mov      dword ptr [rsp+44H], edx
       48894C2438           mov      bword ptr [rsp+38H], rcx
       4183F905             cmp      r9d, 5
       0F871B010000         ja       G_M000_IG15
       418BC1               mov      eax, r9d
       4C8D0D2A010000       lea      r9, [reloc @RWD00]
       458B0C81             mov      r9d, dword ptr [r9+4*rax]
       4C8D15BBFFFFFF       lea      r10, G_M000_IG02
       4D03CA               add      r9, r10
       41FFE1               jmp      r9
 
G_M000_IG07:                ;; offset=004FH
       B8FFFFFFFF           mov      eax, -1
       E904010000           jmp      G_M000_IG16
 
G_M000_IG08:                ;; offset=0059H
       33C9                 xor      rcx, rcx
       4533C9               xor      r9d, r9d
       EBBF                 jmp      SHORT G_M000_IG06
 
G_M000_IG09:                ;; offset=0060H
       488B4C2438           mov      rcx, bword ptr [rsp+38H]
       480FBF01             movsx    rax, word  ptr [rcx]
       498BC8               mov      rcx, r8
       8BD0                 mov      edx, eax
       448B442444           mov      r8d, dword ptr [rsp+44H]
       FF1587A32000         call     [System.SpanHelpers:IndexOfValueType[short,DontNegate`1[short]](byref,short,int):int]
       E9DF000000           jmp      G_M000_IG16
 
G_M000_IG10:                ;; offset=007EH
       33C9                 xor      rcx, rcx
       4533C0               xor      r8d, r8d
       4987C8               xchg     rcx, r8
       EB88                 jmp      SHORT G_M000_IG04
 
G_M000_IG11:                ;; offset=0088H
       488B4C2438           mov      rcx, bword ptr [rsp+38H]
       4C0FBF09             movsx    r9, word  ptr [rcx]
       480FBF4102           movsx    rax, word  ptr [rcx+02H]
       498BC8               mov      rcx, r8
       418BD1               mov      edx, r9d
       448BC0               mov      r8d, eax
       448B4C2444           mov      r9d, dword ptr [rsp+44H]
       FF15BEBE2000         call     [System.SpanHelpers:IndexOfAnyValueType[short,DontNegate`1[short]](byref,short,short,int):int]
       E9AE000000           jmp      G_M000_IG16
 
G_M000_IG12:                ;; offset=00AFH
       488B4C2438           mov      rcx, bword ptr [rsp+38H]
       4C0FBF09             movsx    r9, word  ptr [rcx]
       480FBF4102           movsx    rax, word  ptr [rcx+02H]
       4C0FBF5104           movsx    r10, word  ptr [rcx+04H]
       89542420             mov      dword ptr [rsp+20H], edx
       498BC8               mov      rcx, r8
       418BD1               mov      edx, r9d
       448BC0               mov      r8d, eax
       458BCA               mov      r9d, r10d
       FF1570C62000         call     [System.SpanHelpers:IndexOfAnyValueType[short,DontNegate`1[short]](byref,short,short,short,int):int]
       E980000000           jmp      G_M000_IG16
 
G_M000_IG13:                ;; offset=00DDH
       488B4C2438           mov      rcx, bword ptr [rsp+38H]
       4C0FBF09             movsx    r9, word  ptr [rcx]
       480FBF4102           movsx    rax, word  ptr [rcx+02H]
       4C0FBF5104           movsx    r10, word  ptr [rcx+04H]
       480FBF4906           movsx    rcx, word  ptr [rcx+06H]
       894C2420             mov      dword ptr [rsp+20H], ecx
       89542428             mov      dword ptr [rsp+28H], edx
       498BC8               mov      rcx, r8
       418BD1               mov      edx, r9d
       448BC0               mov      r8d, eax
       458BCA               mov      r9d, r10d
       FF1559DE2000         call     [System.SpanHelpers:IndexOfAnyValueType[short,DontNegate`1[short]](byref,short,short,short,short,int):int]
       EB4C                 jmp      SHORT G_M000_IG16
 
G_M000_IG14:                ;; offset=0111H
       488B4C2438           mov      rcx, bword ptr [rsp+38H]
       4C0FBF09             movsx    r9, word  ptr [rcx]
       480FBF4102           movsx    rax, word  ptr [rcx+02H]
       4C0FBF5104           movsx    r10, word  ptr [rcx+04H]
       4C0FBF5906           movsx    r11, word  ptr [rcx+06H]
       480FBF4908           movsx    rcx, word  ptr [rcx+08H]
       44895C2420           mov      dword ptr [rsp+20H], r11d
       894C2428             mov      dword ptr [rsp+28H], ecx
       89542430             mov      dword ptr [rsp+30H], edx
       498BC8               mov      rcx, r8
       418BD1               mov      edx, r9d
       448BC0               mov      r8d, eax
       458BCA               mov      r9d, r10d
       FF154B842000         call     [System.SpanHelpers:IndexOfAnyValueType[short](byref,short,short,short,short,short,int):int]
       EB0E                 jmp      SHORT G_M000_IG16
 
G_M000_IG15:                ;; offset=014FH
       498BC8               mov      rcx, r8
       4C8B442438           mov      r8, bword ptr [rsp+38H]
       FF15A3222000         call     [System.MemoryExtensions:IndexOfAnyProbabilistic(byref,int,byref,int):int]
 
G_M000_IG16:                ;; offset=015DH
       F7D0                 not      eax
       C1E81F               shr      eax, 31
 
G_M000_IG17:                ;; offset=0162H
       4883C448             add      rsp, 72
       C3                   ret      
 
RWD00  	dd	0000004Bh ; case G_M000_IG07
       	dd	0000005Ch ; case G_M000_IG09
       	dd	00000084h ; case G_M000_IG11
       	dd	000000ABh ; case G_M000_IG12
       	dd	000000D9h ; case G_M000_IG13
       	dd	0000010Dh ; case G_M000_IG14

; Total bytes of code 359

cc: @EgorBo

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions