-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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 poor codegen for calculating field offsets of structs #40021
Comments
Yeah it's quite confusing, but "master" on sharplab means "master version of Roslyn + .NET Core 3.1 x86 JIT" (not even x64) I'd recommend to either use BenchmarkDotNet's disasm + .NET 5 or use |
I did check it with my local copy of the runtime too 😄 , just can't do it on a freshly pulled copy right now because I am having some issues building it edit: fixed the build issue and rechecked. There is no change in codegen except the JIT optimises the part which throws an NRE from |
@john-h-k thanks. Is this representative of something you've run into somewhere, or just something you happened to notice? Marking this as future as we're battening down the hatches for 5.0. |
no problem 😄. Ran into it in a marshalling scenario where I have to relatively frequently offset some pointers based off of a field offset |
Actually marking as future. |
I ran into pretty much the same thing in #9791 - we can probably merge these issues because they look similar. The workaround with null is nice. I'll probably use that. |
While implementing the G_M11044_IG01:
;; bbWeight=1 PerfScore 0.00
G_M11044_IG02:
B804000000 mov eax, 4
;; bbWeight=1 PerfScore 0.25
G_M11044_IG03:
C3 ret
;; bbWeight=1 PerfScore 1.00``` |
Both
Presumably this pattern could be recognized and folded if it's common enough to warrant. The |
Both during local morph and during VN. Fix #40021 Saves 3 KB on BasicMinimalApi after #84095 (there's 1111 __GetFieldHelper functions). About 0.04%. There's still a null check kept for each offset computation, which we cannot really get rid of, but NAOT could maybe emit the IL such that there is a dominating null check so that only one is emitted. Example: Base: ``` .managed:0000000140347CC0 loc_140347CC0: ; CODE XREF: S_P_CoreLib_System_Collections_Generic_KeyValuePair_2_System_Net_Security_System_Net_Security_SslSessionsCache_SslCredKey__System___Canon_____GetFieldHelper+23↑j .managed:0000000140347CC0 ; DATA XREF: .rdata:__readonlydata_S_P_CoreLib_System_Collections_Generic_KeyValuePair_2_System_Net_Security_System_Net_Security_SslSessionsCache_SslCredKey__System___Canon_____GetFieldHelper↓o .managed:0000000140347CC0 lea rax, ??_7Boxed_System_Net_Security_System_Net_Security_SslSessionsCache_SslCredKey@@6b@ ; jumptable 0000000140347CB3 case 0 .managed:0000000140347CC7 mov [r9], rax .managed:0000000140347CCA cmp [rcx], cl .managed:0000000140347CCC lea rax, [rcx+8] .managed:0000000140347CD0 sub rax, rcx .managed:0000000140347CD3 add rsp, 8 .managed:0000000140347CD7 retn ``` Diff: ``` .managed:0000000140347AA0 loc_140347AA0: ; CODE XREF: S_P_CoreLib_System_Collections_Generic_KeyValuePair_2_System_Net_Security_System_Net_Security_SslSessionsCache_SslCredKey__System___Canon_____GetFieldHelper+23↑j .managed:0000000140347AA0 ; DATA XREF: .rdata:__readonlydata_S_P_CoreLib_System_Collections_Generic_KeyValuePair_2_System_Net_Security_System_Net_Security_SslSessionsCache_SslCredKey__System___Canon_____GetFieldHelper↓o .managed:0000000140347AA0 lea rax, ??_7Boxed_System_Net_Security_System_Net_Security_SslSessionsCache_SslCredKey@@6b@ ; jumptable 0000000140347A93 case 0 .managed:0000000140347AA7 mov [r9], rax .managed:0000000140347AAA cmp [rcx], cl .managed:0000000140347AAC mov eax, 8 .managed:0000000140347AB1 add rsp, 8 .managed:0000000140347AB5 retn ``` Local morph changes handle the pattern for local structs -- VN changes handle the pattern for classes (and more complicated struct cases, like storing them in locals, which there are a few examples of in #40021).
Description
The JIT doesn't generate good assembly when calculating (what should be) constant fields offsets.
Example sharplab
Configuration
.NET 5, master branch on sharplab and I repro'd it locally with what i believe is a reasonably up to date copy of the runtime (i don't think it is more than a week old)
Analysis
I'm aware the JIT has to throw for null in the first null case, but they show it has the ability to resolve it to a constant (it emits it as a constant load of
4
there, although right after throwing an NRE). It doesn't seem to succeed doing this with either a local (even whenSkipLocalsInit
is enabled) or just with a pointer (where I would expect identical codegen to the null case, except comparing the pointer fornull
rather than immediately NREing).generates
category:cq
theme:basic-cq
skill-level:intermediate
cost:medium
impact:small
The text was updated successfully, but these errors were encountered: