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

Concrete type information does not propagate through struct fields #110290

Open
neon-sunset opened this issue Dec 1, 2024 · 2 comments
Open

Concrete type information does not propagate through struct fields #110290

neon-sunset opened this issue Dec 1, 2024 · 2 comments
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI tenet-performance Performance related issue
Milestone

Comments

@neon-sunset
Copy link
Contributor

Description

It appears that JIT is not able to propagate concrete type information through struct fields typed as the type's abstract parent.
The example below matches the shape of stateless FSharpFunc<T1...Tn> instantiations by F#.

Given reduced repro:

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkRunner.Run<Benchmarks>(args: args);

[ShortRunJob]
[DisassemblyDiagnoser]
public class Benchmarks {
    [Benchmark]
    public int Example() {
        var wrapper = default(Wrapper2<int, int>);
        wrapper.F1 = MyFuncImpl1.Instance;
        wrapper.F2 = MyFuncImpl2.Instance;

        var v1 = wrapper.F1.Invoke(42);
        var v2 = wrapper.F2.Invoke(v1);

        return v2 + 1;
    }
}

abstract class MyFunc<T, U> {
    public abstract U Invoke(T value);
}

sealed class MyFuncImpl1: MyFunc<int, int> {
    public static readonly MyFuncImpl1 Instance = new();
    public override int Invoke(int value) => value + 4;
}

sealed class MyFuncImpl2: MyFunc<int, int> {
    public static readonly MyFuncImpl2 Instance = new();
    public override int Invoke(int value) => value * 2;
}

struct Wrapper2<T, U> {
    public MyFunc<T, U> F1;
    public MyFunc<T, U> F2;
}

The Tier1-PGO compilation of Example() is

; Benchmarks.Dummy()
       push      rbx
       sub       rsp,20
       mov       rax,2907B8012E8
       mov       rcx,[rax]
       mov       rax,2907B8012F0
       mov       rbx,[rax]
       mov       rax,offset MT_MyFuncImpl1
       cmp       [rcx],rax
       jne       short M00_L01
       mov       edx,2E
       mov       rax,offset MT_MyFuncImpl2
       cmp       [rbx],rax
       jne       short M00_L02
       mov       eax,5C
M00_L00:
       inc       eax
       add       rsp,20
       pop       rbx
       ret
M00_L01:
       mov       edx,2A
       mov       rax,[rcx]
       mov       rax,[rax+40]
       call      qword ptr [rax+20]
       mov       edx,eax
M00_L02:
       mov       rcx,rbx
       mov       rax,[rbx]
       mov       rax,[rax+40]
       call      qword ptr [rax+20]
       jmp       short M00_L00
; Total bytes of code 111

It would be great if JIT could propagate the concrete type here through the field and not rely on DPGO to devirtualize the func types back. This also does not devirtualize on NativeAOT for more than single MyFunc implementation. Thanks!

Configuration

.NET SDK:
 Version:           9.0.100
 Commit:            59db016f11
 Workload version:  9.0.100-manifests.3068a692
 MSBuild version:   17.12.7+5b8665660

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22631
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\9.0.100\

Regression?

Not tested on .NET 8

@neon-sunset neon-sunset added the tenet-performance Performance related issue label Dec 1, 2024
@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 Dec 1, 2024
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Dec 1, 2024
Copy link
Contributor

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

@EgorBo
Copy link
Member

EgorBo commented Dec 1, 2024

Sadly, JIT is not smart enough in early phases (no SSA/VN info) so it can't look through structs (they're not promoted yet) for exact class info, so PGO+GDV sort of fixes it implicitly (GDV check is folded in a later phase). Not sure what would be the best fix here, perhaps, a bit "late" inlining? early SSA/VN/Struct promotion?

@EgorBo EgorBo added this to the Future milestone Dec 1, 2024
@EgorBo EgorBo removed the untriaged New issue has not been triaged by the area owner label Dec 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI tenet-performance Performance related issue
Projects
None yet
Development

No branches or pull requests

2 participants