Repository navigation
JIT: Improve last-use copy omission for implicit byrefs #76069
Copy link
Copy link
Closed
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Milestone
Description
Consider:
[MethodImpl(MethodImplOptions.NoInlining)]
public static int Test(Span<int> s)
{
return s.Length + Test2(s);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static int Test2(Span<int> s)
{
return s.Length;
}Today we generate the following on win-x64:
; Assembly listing for method Program:Test(System.Span`1[int]):int
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; 0 inlinees with PGO data; 1 single block inlinees; 0 inlinees without PGO data
; Final local variable assignments
;
; V00 arg0 [V00,T00] ( 4, 8 ) byref -> rcx ld-addr-op single-def
; V01 OutArgs [V01 ] ( 1, 1 ) lclBlk (32) [rsp+00H] "OutgoingArgSpace"
;* V02 tmp1 [V02 ] ( 0, 0 ) int -> zero-ref "non-inline candidate call"
;* V03 tmp2 [V03 ] ( 0, 0 ) byref -> zero-ref V05._reference(offs=0x00) P-INDEP "field V00._reference (fldOffset=0x0)"
;* V04 tmp3 [V04 ] ( 0, 0 ) int -> zero-ref V05._length(offs=0x08) P-INDEP "field V00._length (fldOffset=0x8)"
;* V05 tmp4 [V05 ] ( 0, 0 ) struct (16) zero-ref "Promoted implicit byref"
; V06 tmp5 [V06 ] ( 2, 4 ) struct (16) [rsp+20H] do-not-enreg[XS] addr-exposed "by-value struct argument"
;
; Lcl frame size = 48
G_M62473_IG01: ;; offset=0000H
56 push rsi
4883EC30 sub rsp, 48
C5F877 vzeroupper
;; size=8 bbWeight=1 PerfScore 2.25
G_M62473_IG02: ;; offset=0008H
8B7108 mov esi, dword ptr [rcx+08H]
;; size=3 bbWeight=1 PerfScore 2.00
G_M62473_IG03: ;; offset=000BH
C5FA6F01 vmovdqu xmm0, xmmword ptr [rcx] ; unnecessary
C5FA7F442420 vmovdqu xmmword ptr [rsp+20H], xmm0 ; unnecessary
;; size=10 bbWeight=1 PerfScore 5.00
G_M62473_IG04: ;; offset=0015H
488D4C2420 lea rcx, [rsp+20H] ; unnecessary
FF15C86B1C00 call [Program:Test2(System.Span`1[int]):int]
03C6 add eax, esi
;; size=13 bbWeight=1 PerfScore 3.75
G_M62473_IG05: ;; offset=0022H
4883C430 add rsp, 48
5E pop rsi
C3 ret
;; size=6 bbWeight=1 PerfScore 1.75
; Total bytes of code 40, prolog size 8, PerfScore 18.95, instruction count 12, allocated bytes for code 42 (MethodHash=e5250bf6) for method Program:Test(System.Span`1[int]):int
; ============================================================We would probably need an early pass of (struct) liveness to get rid of some of these copies in a general fashion.
Some simple ad-hoc pattern matching during codegen (code) shows roughly 24k instances of this over libraries.crossgen and 3.2k over benchmarks.run. These are cases where we create a copy from a non-address exposed GTF_VAR_DEATH marked struct local.
We expect that this liveness pass may eventually be useful (necessary, even) for generalized promotion as well, and perhaps for forward sub too. Thus the pass will need to run early enough to be useful for these purposes. The likely best fit is right after local address visitor.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Activity
jakobbotsch commentedon Sep 23, 2022
cc @dotnet/jit-contrib
jakobbotsch commentedon Oct 12, 2022
Another possibility is to home by-value structs that are last used by a call directly in the outgoing arg area. Of course this is only possible if there are no interfering calls.
jakobbotsch commentedon Dec 16, 2022
With #79346 we generate:
JIT: Add a pass of early liveness and use it for forward sub and last…