Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fold static readonly struct X = <zero> to a jit-time const, e.g. Guid.Empty #77354

Merged
merged 6 commits into from
Oct 25, 2022

Conversation

EgorBo
Copy link
Member

@EgorBo EgorBo commented Oct 23, 2022

This PR does two things:

  1. Imports all static readonly <struct> = 0 as ASG(struct, 0) - it's mostly for Guid.Empty (and e.g. decimal.Zero)
  2. Adds AggressiveInlining to Guid.EqualsCore

Overall jit-diff (-f -cctors) is negative (-28473 bytes) so no significant size regressions due to AggressiveInlining.

Benchmark:

[Benchmark]
[ArgumentsSource(nameof(TestData1))]
public bool GuidIsEmpty(Guid g) => g == Guid.Empty; // test effect from AggressiveInling + .Empty folding

[Benchmark]
[ArgumentsSource(nameof(TestData2))]
public bool GuidsEqual(Guid g1, Guid g2) => g1 == g2; // test effect from AggressiveInling 

// Test data:

public static IEnumerable<Guid> TestData1()
{
    yield return Guid.Empty;
    yield return new Guid("503AA73D-DA86-4A7D-A369-192A1766DFA2");
}

public static IEnumerable<object[]> TestData2()
{
    yield return new object[]
    {
        new Guid("503AA73D-DA86-4A7D-A369-192A1766DFA2"), 
        Guid.Empty
    };
    yield return new object[]
    { 
        new Guid("503AA73D-DA86-4A7D-A369-192A1766DFA2"), 
        new Guid("503AA73D-DA86-4A7D-A369-192A1766DFA2")
    };
}
Method Toolchain Mean
GuidIsEmpty \Core_Root\corerun.exe 0.3040 ns
GuidIsEmpty \Core_Root_base\corerun.exe 1.0961 ns
GuidIsEmpty \Core_Root\corerun.exe 0.3286 ns
GuidIsEmpty \Core_Root_base\corerun.exe 1.0916 ns
GuidsEqual \Core_Root\corerun.exe 0.4003 ns
GuidsEqual \Core_Root_base\corerun.exe 0.9250 ns
GuidsEqual \Core_Root\corerun.exe 0.4378 ns
GuidsEqual \Core_Root_base\corerun.exe 0.9272 ns

Codegen diff

static bool IsEmpty(Guid g) => g == Guid.Empty;

Was:

; Assembly listing for method Program:IsEmpty(System.Guid):bool
G_M000_IG01:                ;; offset=0000H
       4883EC48             sub      rsp, 72
       C5F877               vzeroupper 
G_M000_IG02:                ;; offset=0007H
       C5F91001             vmovupd  xmm0, xmmword ptr [rcx]
       C5F911442438         vmovupd  xmmword ptr [rsp+38H], xmm0
       48B9980280E1FA010000 mov      rcx, 0x1FAE1800298 ;; boxed static Guid.Empty
       488B09               mov      rcx, gword ptr [rcx]
       C5F9104108           vmovupd  xmm0, xmmword ptr [rcx+08H]
       C5F911442428         vmovupd  xmmword ptr [rsp+28H], xmm0
       488D4C2438           lea      rcx, [rsp+38H]
       488D542428           lea      rdx, [rsp+28H]
       FF15AFB50E00         call     [System.Guid:EqualsCore(byref,byref):bool]
       90                   nop      
G_M000_IG03:                ;; offset=003AH
       4883C448             add      rsp, 72
       C3                   ret      
; Total bytes of code 63

Now:

; Assembly listing for method Program:IsEmpty(System.Guid):bool
G_M8154_IG01:              ;; offset=0000H
       4883EC28             sub      rsp, 40
       C5F877               vzeroupper 
G_M8154_IG02:              ;; offset=0007H
       C5F91001             vmovupd  xmm0, xmmword ptr [rcx]
       C5F911442418         vmovupd  xmmword ptr [rsp+18H], xmm0
       C5F857C0             vxorps   xmm0, xmm0, xmm0
       C5F911442408         vmovupd  xmmword ptr [rsp+08H], xmm0  ;; TODO: remove this spill
       C5FA6F442418         vmovdqu  xmm0, xmmword ptr [rsp+18H]
       C5F974442408         vpcmpeqb xmm0, xmm0, xmmword ptr [rsp+08H]
       C5F9D7C0             vpmovmskb eax, xmm0
       3DFFFF0000           cmp      eax, 0xFFFF
       0F94C0               sete     al
       0FB6C0               movzx    rax, al
G_M8154_IG03:              ;; offset=0036H
       4883C428             add      rsp, 40
       C3                   ret      
; Total bytes of code 59

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Oct 23, 2022
@ghost ghost assigned EgorBo Oct 23, 2022
@ghost
Copy link

ghost commented Oct 23, 2022

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Issue Details

This PR does two things:

  1. Imports all static readonly <struct> = 0 as ASG(struct, 0) - it's mostly for Guid.Empty
  2. Adds AggressiveInlining to Guid.EqualsCore

Overall jit-diff (-f -cctors) is negative (-28473 bytes) so no significant size regressions due to AggressiveInlining.

Benchmark:

[Benchmark]
[ArgumentsSource(nameof(TestData1))]
public bool GuidIsEmpty(Guid g) => g == Guid.Empty;

[Benchmark]
[ArgumentsSource(nameof(TestData2))]
public bool GuidsEqual(Guid g1, Guid g2) => g1 == g2;

// Test data:

public static IEnumerable<Guid> TestData1()
{
    yield return Guid.Empty;
    yield return new Guid("503AA73D-DA86-4A7D-A369-192A1766DFA2");
}

public static IEnumerable<object[]> TestData2()
{
    yield return new object[]
    {
        new Guid("503AA73D-DA86-4A7D-A369-192A1766DFA2"), 
        Guid.Empty
    };
    yield return new object[]
    { 
        new Guid("503AA73D-DA86-4A7D-A369-192A1766DFA2"), 
        new Guid("503AA73D-DA86-4A7D-A369-192A1766DFA2")
    };
}
Method Toolchain Mean
GuidIsEmpty \Core_Root\corerun.exe 0.3040 ns
GuidIsEmpty \Core_Root_base\corerun.exe 1.0961 ns
GuidIsEmpty \Core_Root\corerun.exe 0.3286 ns
GuidIsEmpty \Core_Root_base\corerun.exe 1.0916 ns
GuidsEqual \Core_Root\corerun.exe 0.4003 ns
GuidsEqual \Core_Root_base\corerun.exe 0.9250 ns
GuidsEqual \Core_Root\corerun.exe 0.4378 ns
GuidsEqual \Core_Root_base\corerun.exe 0.9272 ns

Codegen diff

static bool IsEmpty(Guid g) => g == Guid.Empty;

Was:

; Assembly listing for method Program:IsEmpty(System.Guid):bool
G_M000_IG01:                ;; offset=0000H
       4883EC48             sub      rsp, 72
       C5F877               vzeroupper 
G_M000_IG02:                ;; offset=0007H
       C5F91001             vmovupd  xmm0, xmmword ptr [rcx]
       C5F911442438         vmovupd  xmmword ptr [rsp+38H], xmm0
       48B9980280E1FA010000 mov      rcx, 0x1FAE1800298
       488B09               mov      rcx, gword ptr [rcx]
       C5F9104108           vmovupd  xmm0, xmmword ptr [rcx+08H]
       C5F911442428         vmovupd  xmmword ptr [rsp+28H], xmm0
       488D4C2438           lea      rcx, [rsp+38H]
       488D542428           lea      rdx, [rsp+28H]
       FF15AFB50E00         call     [System.Guid:EqualsCore(byref,byref):bool]
       90                   nop      
G_M000_IG03:                ;; offset=003AH
       4883C448             add      rsp, 72
       C3                   ret      
; Total bytes of code 63

Now:

; Assembly listing for method Program:IsEmpty(System.Guid):bool
G_M8154_IG01:              ;; offset=0000H
       4883EC28             sub      rsp, 40
       C5F877               vzeroupper 
G_M8154_IG02:              ;; offset=0007H
       C5F91001             vmovupd  xmm0, xmmword ptr [rcx]
       C5F911442418         vmovupd  xmmword ptr [rsp+18H], xmm0
       C5F857C0             vxorps   xmm0, xmm0, xmm0
       C5F911442408         vmovupd  xmmword ptr [rsp+08H], xmm0  ;; TODO: remove this spill
       C5FA6F442418         vmovdqu  xmm0, xmmword ptr [rsp+18H]
       C5F974442408         vpcmpeqb xmm0, xmm0, xmmword ptr [rsp+08H]
       C5F9D7C0             vpmovmskb eax, xmm0
       3DFFFF0000           cmp      eax, 0xFFFF
       0F94C0               sete     al
       0FB6C0               movzx    rax, al
G_M8154_IG03:              ;; offset=0036H
       4883C428             add      rsp, 40
       C3                   ret      
; Total bytes of code 59
Author: EgorBo
Assignees: -
Labels:

area-CodeGen-coreclr

Milestone: -

@EgorBo
Copy link
Member Author

EgorBo commented Oct 23, 2022

static decimal Test() => decimal.Zero;

Codegen diff:

; Assembly listing for method Program:Test():System.Decimal
       C5F877               vzeroupper 
-      48B86000C07FC0020000 mov      rax, 0x2C07FC00060
-      488B00               mov      rax, gword ptr [rax]
-      C5F9104008           vmovupd  xmm0, xmmword ptr [rax+08H]
+      C5F857C0             vxorps   xmm0, xmm0
       C5F91101             vmovupd  xmmword ptr [rcx], xmm0
       488BC1               mov      rax, rcx
       C3                   ret      
; Total bytes of code 29

@EgorBo EgorBo changed the title Optimize comparisons against Guid.Empty Fold static readonly struct X = <zero> to a jit-time const, e.g. Guid.Empty Oct 23, 2022
@EgorBo
Copy link
Member Author

EgorBo commented Oct 23, 2022

it's ready for review: @dotnet/jit-contrib @AndyAyersMS @SingleAccretion PTAL

@EgorBo
Copy link
Member Author

EgorBo commented Oct 25, 2022

@jakobbotsch @AndyAyersMS PTAL

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants