-
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
Devirtualization issues in non-shared generics #37717
Comments
duplicates #10050 ? |
No, the issue you referenced is about shared generics. This one is about non-shared generics/value types. |
There are two versions of Looking at a variant of code the above, the jit fails to devirtualize initially because it doesn't see the comparer class as sealed/final (which it should be, if we have the right one):
but after inlining (and simulating what we'd see for Tier1 code), the jit can can devirt as it can see the type of the readonly static and so does not need to depend on finalness anymore:
we can't inline at this point, so the resulting code looks similar to what you'd see if we didn't devirtualize, but it should run a bit faster. |
Actually it's simpler than that, the
post-import IR:
In the non-virtual case there's just a constant there so no spilling happens:
So the root cause is that for a local of primitive typed |
If we aim to relax |
This looks fixed, codegen on main after tiering is now: ; Assembly listing for method C+Benchmark`1[long]:IsDefaultInlined(long):bool:this
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; Tier-1 compilation
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; 1 inlinees with PGO data; 2 single block inlinees; 0 inlinees without PGO data
; Final local variable assignments
;
;* V00 this [V00 ] ( 0, 0 ) ref -> zero-ref this class-hnd single-def
; V01 arg1 [V01,T00] ( 3, 3 ) long -> rdx single-def
;* V02 loc0 [V02 ] ( 0, 0 ) long -> zero-ref ld-addr-op
;# V03 OutArgs [V03 ] ( 1, 1 ) lclBlk ( 0) [rsp+00H] "OutgoingArgSpace"
;* V04 tmp1 [V04,T02] ( 0, 0 ) ref -> zero-ref class-hnd exact single-def "impAppendStmt"
; V05 tmp2 [V05,T01] ( 2, 2 ) bool -> rax single-def "Inline return value spill temp"
;* V06 tmp3 [V06 ] ( 0, 0 ) long -> zero-ref ld-addr-op "Inlining Arg"
;
; Lcl frame size = 0
G_M22461_IG01:
;; size=0 bbWeight=1 PerfScore 0.00
G_M22461_IG02:
xor eax, eax
test rdx, rdx
sete al
;; size=8 bbWeight=1 PerfScore 1.50
G_M22461_IG03:
ret
;; size=1 bbWeight=1 PerfScore 1.00
; Total bytes of code 9, prolog size 0, PerfScore 3.40, instruction count 4, allocated bytes for code 9 (MethodHash=87b5a842) for method C+Benchmark`1[long]:IsDefaultInlined(long):bool:this
; ============================================================ |
During benchmarking an optimization involving
EqualityComparer<T>.Default
I found an issue - if the comparer is used in a generic type devirtualization doesn't happen for some cases. In the example below onlydecimal
comparison is inlined well in case of generics, but not forlong
. At the same time the JIT heavily optimized the code forlong
comparison in a non-generic code.Generic
Int64Benchmark
DecimalBenchmark
Non generic
Int64BenchmarkNonGeneric
DecimalBenchmarkNonGeneric
/cc @AndyAyersMS
category:cq
theme:devirtualization
skill-level:expert
cost:large
The text was updated successfully, but these errors were encountered: