Skip to content

Promote (scalar replace) structs with more than 4 fields #6534

Description

@AndreyAkinshin

Let's look at the following code (based on this StackOverflow question):

publicstructCards3{publicbyteC0,C1,C2;}publicstructCards8{publicbyteC0,C1,C2,C3,C4,C5,C6,C7;}classProgram{staticvoidMain(){Run3();Run8();}privatestaticCards3[]cards3=newCards3[1];privatestaticCards8[]cards8=newCards8[1];[MethodImpl(MethodImplOptions.NoInlining)]publicstaticintRun3(){varc=cards3[0];returnc.C0-c.C1;}[MethodImpl(MethodImplOptions.NoInlining)]publicstaticintRun8(){varc=cards8[0];returnc.C0-c.C1;}}

Now let's look at the asm code (Windows 10, .NET Framework 4.6.1 (4.0.30319.42000), clrjit-v4.6.1080.0):

; Run3  var c = cards3[0]; 00007FFEDF0A4752 inal,dx00007FFEDF0A4753 sub byte ptr [rax-48h],cl00007FFEDF0A4756 add byte ptr [rax],0B0h00007FFEDF0A4759 out72h,al00007FFEDF0A475B addal,byte ptr [rax]00007FFEDF0A475D add byte ptr [rax-75h],cl00007FFEDF0A4760 add byte ptr [rbx+76000878h],al00007FFEDF0A4766 adcal,48h00007FFEDF0A4768 addeax,10h00007FFEDF0A476B movzxedx,byte ptr [rax] ; !!!00007FFEDF0A476E movzxeax,byte ptr [rax+1] ; !!! return c.C0 - c.C1; 00007FFEDF0A4772 subedx,eax ; !!!00007FFEDF0A4774 moveax,edx ; !!!00007FFEDF0A4776 addrsp,28h00007FFEDF0A477A ret00007FFEDF0A477B call 00007FFF3EB57BE0 00007FFEDF0A4780 int3; Run8  var c = cards8[0]; 00007FFEDF0B49A2 inal,dx00007FFEDF0B49A3 sub byte ptr [rbx],dh00007FFEDF0B49A5 ror byte ptr [rax-77h],44h00007FFEDF0B49A9 andal,20h00007FFEDF0B49AB movrax,202902D0088h00007FFEDF0B49B5 movrax,qword ptr [rax]00007FFEDF0B49B8 cmp dword ptr [rax+8],000007FFEDF0B49BC jbe 00007FFEDF0B49D8 00007FFEDF0B49BE movrax,qword ptr [rax+10h] ; !!!00007FFEDF0B49C2 mov qword ptr [rsp+20h],rax ; !!! return c.C0 - c.C1; 00007FFEDF0B49C7 movzxeax,byte ptr [rsp+20h] ; !!!00007FFEDF0B49CC movzxedx,byte ptr [rsp+21h] ; !!!00007FFEDF0B49D1 subeax,edx00007FFEDF0B49D3 addrsp,28h00007FFEDF0B49D7 ret00007FFEDF0B49D8 call 00007FFF3EB57BE0 00007FFEDF0B49DD int3

As you can see, in the Run3 case, RyuJIT keeps the target bytes (C0, C1) in the edx, eax registers; in the Run8 case, RyuJIT keeps them on stack (qword ptr [rsp+20h]). Why? This may slightly degrade the performance of an application (see these benchmarks).

category:cq
theme:structs
skill-level:expert
cost:large
impact:large

Metadata

Metadata

Assignees

Labels

Priority:2Work that is important, but not critical for the releasearea-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIenhancementProduct code improvement that does NOT require public API changes/additionsoptimizationtenet-performancePerformance related issue

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions