Skip to content

[NativeAOT] Usages of generic EqualityComparer.Default have cctor init checks for primitives #81592

@neon-sunset

Description

@neon-sunset

Description

It appears that static initialization of Default instances of EqualityComparer for primitives is not folded in compile-time.
I'm not sure if it's intended behavior but I do remember NativeAOT having somewhat similar capability to pre-initialize cctors under certain conditions.

Consider the following type:

readonly record struct Report(
    ulong Successful,
    ulong Failed,
    float MegabytesPerSecond,
    float RPS);

and its generated GetHashCode() implementation

[CompilerGenerated]
public override int GetHashCode()
{
    return ((
        EqualityComparer<ulong>.Default.GetHashCode(<Successful>k__BackingField) * -1521134295 +
        EqualityComparer<ulong>.Default.GetHashCode(<Failed>k__BackingField)) * -1521134295 +
        EqualityComparer<float>.Default.GetHashCode(<MegabytesPerSecond>k__BackingField)) * -1521134295 +
        EqualityComparer<float>.Default.GetHashCode(<RPS>k__BackingField);
}

Configuration

.NET SDK:
 Version:   8.0.100-preview.2.23102.11
 Commit:    5c7737d740

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  13.2
 OS Platform: Darwin
 RID:         osx.13-arm64
 Base Path:   /usr/local/share/dotnet/sdk/8.0.100-preview.2.23102.11/

Host:
  Version:      8.0.0-alpha.1.23080.2
  Architecture: arm64
  Commit:       9529803ae2

<IlcOptimizationPreference>Speed</IlcOptimizationPreference>
Disassembled with Ghidra 10.2.2 with aggressive instruction finder and relocs resolver turned on (maybe there's a less roundabout option for NativeAOT?).

Analysis

Given the above code, the produced assembly code ends up as below:

        _fram0_http_bench_Report__GetHashCode           XREF[2]:     Entry Point(*), 
        _http_bench_Report__GetHashCode                              _unbox_http_bench_Report__GetHas
       100092a60 fd 7b bc a9     stp        x29,x30,[sp, #local_40]!
       100092a64 f3 53 02 a9     stp        x19,x20,[sp, #local_20]
       100092a68 f5 5b 03 a9     stp        x21,x22,[sp, #local_10]
       100092a6c fd 03 00 91     mov        x29,sp
       100092a70 f3 03 00 aa     mov        x19,x0
       100092a74 40 36 00 f0     adrp       x0,___GCSTATICSS_P_CoreLib_System_Buffers_TlsO   = 0000E01400127BDBh
       100092a78 00 20 2b 91     add        x0,x0,#0xac8
       100092a7c 14 00 40 f9     ldr        x20,[x0]=>___GCSTATICSS_P_CoreLib_System_Colle   = 0000000000127089h
       100092a80 80 06 40 f9     ldr        x0,[x20, #0x8]=>DAT_00127091
       100092a84 40 00 00 b5     cbnz       x0,LAB_100092a8c
       100092a88 2a dc 0a 94     bl         _S_P_CoreLib_System_Collections_Generic_Equali   undefined _S_P_CoreLib_System_Co
                             LAB_100092a8c                                   XREF[1]:     100092a84(j)  
       100092a8c 60 02 40 f9     ldr        x0,[x19]
       100092a90 01 fc 60 d3     lsr        x1,x0,#0x20
       100092a94 00 00 01 4a     eor        w0,w0,w1
       100092a98 35 a5 8a 52     mov        w21,#0x5529
       100092a9c b5 aa b4 72     movk       w21,#0xa555, LSL #16
       100092aa0 16 7c 15 1b     mul        w22,w0,w21
       100092aa4 80 06 40 f9     ldr        x0,[x20, #0x8]=>DAT_00127091
       100092aa8 40 00 00 b5     cbnz       x0,LAB_100092ab0
       100092aac 21 dc 0a 94     bl         _S_P_CoreLib_System_Collections_Generic_Equali   undefined _S_P_CoreLib_System_Co
                             LAB_100092ab0                                   XREF[1]:     100092aa8(j)  
       100092ab0 60 06 40 f9     ldr        x0,[x19, #0x8]
       100092ab4 01 fc 60 d3     lsr        x1,x0,#0x20
       100092ab8 00 00 01 4a     eor        w0,w0,w1
       100092abc 00 00 16 0b     add        w0,w0,w22
       100092ac0 14 7c 15 1b     mul        w20,w0,w21
       100092ac4 40 36 00 f0     adrp       x0,___GCSTATICSS_P_CoreLib_System_Buffers_TlsO   = 0000E01400127BDBh
       100092ac8 00 c0 29 91     add        x0,x0,#0xa70
       100092acc 16 00 40 f9     ldr        x22,[x0]=>___GCSTATICSS_P_CoreLib_System_Colle   = 00000000001270E1h
       100092ad0 c0 06 40 f9     ldr        x0,[x22, #0x8]=>DAT_001270e9
       100092ad4 40 00 00 b5     cbnz       x0,LAB_100092adc
       100092ad8 be d3 0a 94     bl         _S_P_CoreLib_System_Collections_Generic_Equali   undefined _S_P_CoreLib_System_Co
                             LAB_100092adc                                   XREF[1]:     100092ad4(j)  
       100092adc 70 12 40 bd     ldr        s16,[x19, #0x10]
       100092ae0 b0 1f 00 bd     str        s16,[x29, #local_24]
       100092ae4 a0 1f 40 b9     ldr        w0,[x29, #local_24]
       100092ae8 01 04 00 51     sub        w1,w0,#0x1
       100092aec 21 78 00 12     and        w1,w1,#0x7fffffff
       100092af0 02 f0 af 52     mov        w2,#0x7f800000
       100092af4 03 1c 09 12     and        w3,w0,#0x7f800000
       100092af8 3f 00 02 6b     cmp        w1,w2
       100092afc 60 a0 80 1a     csel       w0,w3,w0,ge
       100092b00 80 02 00 0b     add        w0,w20,w0
       100092b04 14 7c 15 1b     mul        w20,w0,w21
       100092b08 c0 06 40 f9     ldr        x0,[x22, #0x8]=>DAT_001270e9
       100092b0c 40 00 00 b5     cbnz       x0,LAB_100092b14
       100092b10 b0 d3 0a 94     bl         _S_P_CoreLib_System_Collections_Generic_Equali   undefined _S_P_CoreLib_System_Co
                             LAB_100092b14                                   XREF[1]:     100092b0c(j)  
       100092b14 70 16 40 bd     ldr        s16,[x19, #0x14]
       100092b18 b0 1b 00 bd     str        s16,[x29, #local_28]
       100092b1c a0 1b 40 b9     ldr        w0,[x29, #local_28]
       100092b20 01 04 00 51     sub        w1,w0,#0x1
       100092b24 21 78 00 12     and        w1,w1,#0x7fffffff
       100092b28 02 f0 af 52     mov        w2,#0x7f800000
       100092b2c 03 1c 09 12     and        w3,w0,#0x7f800000
       100092b30 3f 00 02 6b     cmp        w1,w2
       100092b34 60 a0 80 1a     csel       w0,w3,w0,ge
       100092b38 80 02 00 0b     add        w0,w20,w0
       100092b3c f5 5b 43 a9     ldp        x21,x22,[sp, #local_10]
       100092b40 f3 53 42 a9     ldp        x19,x20,[sp, #local_20]
       100092b44 fd 7b c4 a8     ldp        x29=>local_40,x30,[sp], #0x40
       100092b48 c0 03 5f d6     ret
       100092b4c 00 00 00 00     align      align(4)

I can't claim to understand everything that's going on, especially why there's a reference to ArrayPool (Ghidra's demangling and relocs resolving?), but cctor checks do seem to be apparent and make sense.

At the same time, for JIT the following assembly is emitted:

; Assembly listing for method Report:GetHashCode():int:this
; Emitting BLENDED_CODE for generic ARM64 CPU - MacOS
; Tier-1 compilation
; optimized code
; optimized using profile data
; fp based frame
; partially interruptible
; with Dynamic PGO: edge weights are valid, and fgCalledCount is 4999
; 6 inlinees with PGO data; 10 single block inlinees; 0 inlinees without PGO data

G_M000_IG01:                ;; offset=0000H
        A9BE7BFD          stp     fp, lr, [sp, #-0x20]!
        910003FD          mov     fp, sp
 
G_M000_IG02:                ;; offset=0008H
        F9400001          ldr     x1, [x0]
        D360FC22          lsr     x2, x1, #32
        4A020021          eor     w1, w1, w2
        528AA522          movz    w2, #0x5529
        72B4AAA2          movk    w2, #0xA555 LSL #16
        1B027C21          mul     w1, w1, w2
        F9400403          ldr     x3, [x0, #0x08]
        D360FC64          lsr     x4, x3, #32
        4A040063          eor     w3, w3, w4
        1B020461          madd    w1, w3, w2, w1
        BD401010          ldr     s16, [x0, #0x10]
        BD001FB0          str     s16, [fp, #0x1C]
        B9401FA3          ldr     w3, [fp, #0x1C]
        51000464          sub     w4, w3, #1
        12007884          and     w4, w4, #0x7FFFFFFF
        52AFF005          mov     w5, #0x7F800000
        12091C66          and     w6, w3, #0x7F800000
        6B05009F          cmp     w4, w5
        1A83A0C3          csel    w3, w6, w3, ge
        1B020461          madd    w1, w3, w2, w1
        BD401410          ldr     s16, [x0, #0x14]
        BD001BB0          str     s16, [fp, #0x18]
        B9401BA0          ldr     w0, [fp, #0x18]
        51000402          sub     w2, w0, #1
        12007842          and     w2, w2, #0x7FFFFFFF
        12091C03          and     w3, w0, #0x7F800000
        6B05005F          cmp     w2, w5
        1A80A060          csel    w0, w3, w0, ge
        0B000020          add     w0, w1, w0
 
G_M000_IG03:                ;; offset=007CH
        A8C27BFD          ldp     fp, lr, [sp], #0x20
        D65F03C0          ret     lr
 
; Total bytes of code 132

Regression?

No. Maybe vs JIT?

Notes

Can compiler-generated methods have special-cased handling for commonly used types in records? Does it make sense to submit an issue for this?

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

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions