dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.84k stars 4.62k forks source link

JIT: cmp + jump + jump #101160

Open EgorBo opened 4 months ago

EgorBo commented 4 months ago

From: https://github.com/dotnet/runtime/pull/101153

[MethodImpl(MethodImplOptions.NoInlining)]
static void Foo<T>() => Bar<T>();

[MethodImpl(MethodImplOptions.NoInlining)]
static void Bar<T>() { }

Codegen for Foo<_Canon> in Tier1:

; Assembly listing for method Prog:Foo[System.__Canon]() (FullOpts)
; FullOpts code
       sub      rsp, 40
       mov      qword ptr [rsp+0x20], rcx
       mov      rdx, qword ptr [rcx+0x38]
       mov      rdx, qword ptr [rdx+0x10]
       test     rdx, rdx
       je       SHORT G_M2381_IG04
       jmp      SHORT G_M2381_IG05
G_M2381_IG04:
       mov      rdx, 0x7FFE1F42D630 
       call     CORINFO_HELP_RUNTIMEHANDLE_METHOD
       mov      rdx, rax
G_M2381_IG05:
       mov      rcx, rdx
       call     [Prog:Bar[System.__Canon]()]
       nop      
       add      rsp, 40
       ret      

this block:

       test     rdx, rdx
       je       SHORT G_M2381_IG04
       jmp      SHORT G_M2381_IG05
G_M2381_IG04:

seems like it's better to be re-ordered to:

       test     rdx, rdx
       jne       SHORT G_M2381_IG05
G_M2381_IG04:

@amanasifkhalid something you might find interesting to take a look since it's block re-ordering. cc @dotnet/jit-contrib

dotnet-policy-service[bot] commented 4 months ago

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

jkotas commented 4 months ago

The existing code works well for static branch prediction: forward branches are statically predicted to fall-through.

The best block re-ordering would be:

      sub      rsp, 40
       mov      qword ptr [rsp+0x20], rcx
       mov      rdx, qword ptr [rcx+0x38]
       mov      rdx, qword ptr [rdx+0x10]
       test     rdx, rdx
       je       SHORT G_M2381_IG04
G_M2381_IG05:
       mov      rcx, rdx
       call     [Prog:Bar[System.__Canon]()]
       nop      
       add      rsp, 40
       ret      

G_M2381_IG04:
       mov      rdx, 0x7FFE1F42D630 
       call     CORINFO_HELP_RUNTIMEHANDLE_METHOD
       mov      rdx, rax
       jmp      SHORT G_M2381_IG05
EgorBo commented 4 months ago

The best block re-ordering would be:

This can be easily done, I just remember we discussed that the helper call path is always invoked at least once so marking it as cold might slightly regress startup

jkotas commented 4 months ago

This is the previous discussion for reference: https://github.com/dotnet/runtime/pull/83911#discussion_r1148172248