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

JIT: refine arg types based on actual types when creating arg temps #8790

Closed
AndyAyersMS opened this issue Aug 22, 2017 · 2 comments
Closed
Assignees
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI enhancement Product code improvement that does NOT require public API changes/additions optimization
Milestone

Comments

@AndyAyersMS
Copy link
Member

The jit will sometimes evaluate inlining arg values to temps and use those for the args in the inlinee body. The type of the temp is chosen from the callee signature.

The jit then imports the body of the inlinee and considers devirtualizing calls within the body. So this evaluation uses the declared argument type.

Later on, when assigning the arg value to the temp to pass the argument, the jit may refine the type of the temp based on actual type of the argument. This refinement comes too late to trigger devirtualization within the body of the inlinee.

Instead the jit should look at the actual argument type when creating the temp. This will provide a sharper type when examining the inlinee body.

Note existing devirtualization cases like this that "work" today rely on constant or locals that can be directly substituted into the inlinee body, without using a temp, or take advantage of improved types "on the way out" as the call sites being devirtualized are outside of the inlinee body.

Example, thanks to @adamsitnik (and @JosephTremoulet for pointing this out)

using System;

public class J
{
    private Increment increment = new Increment();

    public int CallVirtualMethod() => increment.OperateTwice(10);

    public abstract class Operation  // abstract unary integer operation
    {
        public abstract int Operate(int input);

        public int OperateTwice(int input) => Operate(Operate(input)); // two virtual calls to Operate
    }

    public sealed class Increment : Operation // concrete, sealed operation: increment by fixed amount
    {
        public readonly int Amount;
        public Increment(int amount = 1) { Amount = amount; }

        public override int Operate(int input) => input + Amount;
    }

    public static int Main()
    {
        J j = new J();
        return j.CallVirtualMethod();     
    }
}

Should be relatively simple to fix.

@AndyAyersMS AndyAyersMS self-assigned this Aug 22, 2017
AndyAyersMS referenced this issue in AndyAyersMS/coreclr Aug 22, 2017
The jit will refine the types of temps used to pass arguments to inlinees
when it creates the assignments to these temps.

Unfortunately this is too late to drive devirtualization in the body of
the inlinee, as thes assignments are created after the inlinee body is
imported.

So, add similar refinement logic to the place where the temps are first
created.

Closes #13520.
@adamsitnik
Copy link
Member

Hi!

Thanks for the reference. Initially, I thought that it's a bug in my disassembler ;) Btw you can use it to check the performance diff and asm diff for different JITs, explanation

AndyAyersMS referenced this issue in dotnet/coreclr Aug 23, 2017
…#13530)

The jit will refine the types of temps used to pass arguments to inlinees
when it creates the assignments to these temps.

Unfortunately this is too late to drive devirtualization in the body of
the inlinee, as thes assignments are created after the inlinee body is
imported.

So, add similar refinement logic to the place where the temps are first
created.

Closes #13520.
@AndyAyersMS
Copy link
Member Author

Yes the disassembler looks very cool. Here's what it should show now that this fix in:

; Assembly listing for method J:CallVirtualMethod():int:this
; Emitting BLENDED_CODE for X64 CPU with AVX
; optimized code
; rsp based frame
; partially interruptible
; Final local variable assignments
;
;  V00 this         [V00,T03] (  3,  3   )     ref  ->  rcx         this class-hnd
;  V01 tmp0         [V01,T02] (  3,  6   )     ref  ->  rax         class-hnd
;  V02 tmp1         [V02,T00] (  4,  8   )     int  ->  rdx
;# V03 OutArgs      [V03    ] (  1,  1   )  lclBlk ( 0) [rsp+0x00]
;  V04 cse0         [V04,T01] (  6,  6   )     int  ->  rax
;
; Lcl frame size = 0

G_M45407_IG01:

G_M45407_IG02:
       488B4108             mov      rax, gword ptr [rcx+8]
       8B4008               mov      eax, dword ptr [rax+8]
       8D500A               lea      edx, [rax+10]
       03C2                 add      eax, edx

G_M45407_IG03:
       C3                   ret

; Total bytes of code 13, prolog size 0 for method J:CallVirtualMethod():int:this

@msftgits msftgits transferred this issue from dotnet/coreclr Jan 31, 2020
@msftgits msftgits added this to the 2.1.0 milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 20, 2020
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 enhancement Product code improvement that does NOT require public API changes/additions optimization
Projects
None yet
Development

No branches or pull requests

3 participants