Skip to content

Synthesize Static PGO for NativeAOT (Delegates) #118505

@EgorBo

Description

@EgorBo

Today, CoreCLR heavily relies on Dynamic PGO to inline delegates even when in theory it doesn't need any profile when the target is known. Since normally NativeAOT doesn't have any profile, it basically almost never inlines delegates. We can workaround it by synthesizing a fake static pgo data during ILC compilation where for every delegate invocation site we try to detect if there is only one (or a few) address-taken methods exist with the same signature, so then ILC can create such a fake static profile and JIT will use its existing infrastructure to perform a GDV-based inlining for delegates.

Example:

[MethodImpl(MethodImplOptions.NoInlining)]
static void Test() => Invoke(() => new Program());

static void Invoke(Func<Program> func) => func(); // only one method matches this delegate invoke

CoreCLR with Dynamic PGO:

G_M24707_IG01:  ;; offset=0x0000
       push     rbx
       sub      rsp, 32
G_M24707_IG02:
       mov      rcx, 0x26622C001F8 
       mov      rax, gword ptr [rcx]
       test     rax, rax
       je       SHORT G_M24707_IG05
G_M24707_IG03:
       mov      rcx, 0x7FFA8B7F0948 
       cmp      qword ptr [rax+0x18], rcx
       jne      SHORT G_M24707_IG06
G_M24707_IG04:
       add      rsp, 32
       pop      rbx
       ret      

G_M24707_IG05:
       <cold section>

(The delegate was inlined and the new Program allocation was optimized out as unused)
PS: Presumably for this specific case we don't even need the GDV check, but that is irrelevant to the issue.

NativeAOT codegen:

G_M24707_IG01:  ;; offset=0x0000
       push     rbx
       sub      rsp, 32
G_M24707_IG02:  ;; offset=0x0005
       mov      rcx, qword ptr [(reloc 0x4000000000420b10)]
       mov      rax, gword ptr [rcx+0x10]
       test     rax, rax
       jne      SHORT G_M24707_IG04
G_M24707_IG03:  ;; offset=0x0015
       lea      rcx, [(reloc 0x4000000000420b80)]      ; System.Func`1[Program]
       call     CORINFO_HELP_NEWSFAST
       mov      rbx, rax
       mov      rcx, rbx
       lea      rdx, gword ptr [(reloc 0x4000000000420b40)]      ; 'Frozen Program.<>c object'
       call     CORINFO_HELP_READYTORUN_DELEGATE_CTOR
       mov      rcx, qword ptr [(reloc 0x4000000000420b10)]
       lea      rcx, [rcx+0x10]
       mov      rdx, rbx
       call     CORINFO_HELP_ASSIGN_REF
       mov      rax, rbx
G_M24707_IG04:  ;; offset=0x0049
       mov      rcx, gword ptr [rax+0x08]
       call     [rax+0x20]System.Func`1[System.__Canon]:Invoke():System.__Canon:this
       nop      
G_M24707_IG05:  ;; offset=0x0051
       add      rsp, 32
       pop      rbx
       ret 

Not inlined, the non-inlined target allocates since the return value escapes.

cc @dotnet/ilc-contrib

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    No status

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions