-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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: inline shared generics with runtime lookups inside #99265
Conversation
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch Issue DetailsCloses #81432 This PR implements @jkotas's idea to inline shared generics which require runtime lookups. [MethodImpl(MethodImplOptions.NoInlining)]
bool Test<T>() => Callee<T>();
bool Callee<T>() => typeof(T).IsValueType; Codegen for ; Assembly listing for method Program:Test[System.__Canon]():bool:this
push rbx
sub rsp, 48
mov qword ptr [rsp+0x28], rdx
mov rbx, rcx
mov rcx, qword ptr [rdx+0x10]
mov rax, qword ptr [rcx+0x10]
test rax, rax
je SHORT G_M000_IG04
mov rdx, rax
jmp SHORT G_M000_IG05
G_M000_IG04:
mov rcx, rdx
mov rdx, 0x7FFCC5FE7088
call CORINFO_HELP_RUNTIMEHANDLE_METHOD
mov rdx, rax
G_M000_IG05:
mov rcx, rbx
call [Program:Callee[System.__Canon]():bool:this] ;;; <---- not inlined
nop
add rsp, 48
pop rbx
ret
; Total bytes of code 68 Codegen for ; Assembly listing for method Program:Test[System.__Canon]():ubyte:this
xor eax, eax
ret I think the JIT side is ok (I just need to double check various "this context load is invariant" places), but I am not sure I implemented the VM side (only CoreCLR for now) correctly.
|
d7e7396
to
5095668
Compare
/azp run runtime-coreclr outerloop, runtime-coreclr gcstress0x3-gcstress0xc |
Azure Pipelines successfully started running 2 pipeline(s). |
@jkotas one thing I struggle with currently is when I have |
It is not possible to tell from |
Current method as in the one we currently inline, right? not the |
Although, I am not sure I understand where should I pass it, ComputeRuntimeLookupForSharedGenericToken is not a direct jit-ee api.. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JIT side LGTM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ilc and crossgen2 (to the extent that I understand crossgen2) parts lgtm modulo the question.
@@ -827,7 +827,7 @@ public void CompileMethod(MethodWithGCInfo methodCodeNodeNeedingCode, Logger log | |||
} | |||
} | |||
|
|||
private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_LOOKUP_KIND pGenericLookupKind, CorInfoHelpFunc id, ref CORINFO_CONST_LOOKUP pLookup) | |||
private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_LOOKUP_KIND pGenericLookupKind, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_CONST_LOOKUP pLookup) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious why callerHandle
can be unused here (we use pResolvedToken.tokenContext
to get the context instead), but embedGenericHandle
and getCallInfo
need the callerHandle
and don't use context. Since the tests are passing, maybe callerHandle
is redundant with tokenContext
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched to callerHandle. From my understanding tokenContext could be a class here in case of inline - that's the whole reason why we propagated CallerHandle.
It's also a small size improvement for native AOT: MichalStrehovsky/rt-sz#2 (comment) |
|
I found two places I don't have a good understanding what they're needed for:
I might delete the 1st one but I think I'll need an SPMI collection for that so ideally after this PR is merged if you don't mind |
# Conflicts: # src/coreclr/inc/jiteeversionguid.h # src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs
It is fine with me to do it in a follow up PR. Note that deleting The second place is what enabled the limited shared generic inlining that should be superseded by your change. It checks for the happy path that the optimization was capable of handling. |
/azp run runtime-coreclr crossgen2 |
Azure Pipelines successfully started running 1 pipeline(s). |
@jkotas do you mean it should be just |
It should be
This would not work well - it would be a code quality regression. The context needs to be |
/azp run runtime-coreclr crossgen2, runtime-coreclr outerloop |
Azure Pipelines successfully started running 2 pipeline(s). |
@jkotas anything else (assuming CI passes)? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Thank you
Thanks for help! |
Found at least 80 benchmarks improved by 10% or more: https://gist.github.com/EgorBo/b6424f7118ff176682f63875d89fb52e |
Closes #81432
Closes #8662
Closes #65815
(probably more issues, need to check)
Based on #81635.
This PR implements @jkotas's idea to inline shared generics which require runtime lookups.
Example:
Codegen for
Test<string>
in Main:Codegen for
Test<string>
in this PR:I think the JIT side is ok (I just need to double check various "this context load is invariant" places), but I am not sure I implemented the VM side (only CoreCLR for now) correctly.