Using MemoryMarshal.CreateSpan to create a Span<T> from a single struct instance T causes RyuJIT to emit code to zero the stack twice.
Here is a simple example:
usingSystem.Runtime.InteropServices;publicclassC{[StructLayout(LayoutKind.Sequential,Size=20)]publicstructBuffer{publiculongField1;publiculongField2;publicuintField3;}publicvoidM(){varbuf=newBuffer();varspan=MemoryMarshal.CreateSpan(refbuf,1);span[0].Field1=1;}}This code has the following codegen on Core CLR v4.700.19.51502:
C.M() L0000: subrsp,0x18 L0004: xoreax,eax L0006: mov[rsp],rax L000a: mov[rsp+0x8],rax L000f: mov[rsp+0x10],rax L0014: xoreax,eax L0016: mov[rsp],rax L001a: mov[rsp+0x8],rax L001f: mov[rsp+0x10],eax L0023: learax,[rsp] L0027: mov qword [rax],0x1 L002e: addrsp,0x18 L0032: ret
Interestingly, specifying a fixed struct size using the StructLayout attribute (in the previous example, 20) causes the JIT to emit "less optimal" code. An example without the fixed struct size:
usingSystem.Runtime.InteropServices;publicclassC{[StructLayout(LayoutKind.Sequential)]publicstructBuffer{publiculongField1;publiculongField2;publicuintField3;}publicvoidM(){varbuf=newBuffer();varspan=MemoryMarshal.CreateSpan(refbuf,1);span[0].Field1=1;}}C.M() L0000: subrsp,0x18 L0004: vzeroupper L0007: xoreax,eax L0009: mov[rsp],rax L000d: mov[rsp+0x8],rax L0012: mov[rsp+0x10],rax L0017: xoreax,eax L0019: leardx,[rsp] L001d: vxorps xmm0,xmm0,xmm0 L0021: vmovdqu [rdx],xmm0 L0025: mov[rdx+0x10],rax L0029: learax,[rsp] L002d: mov qword [rax],0x1 L0034: addrsp,0x18 L0038: ret
Without the fixed struct size, RyuJIT attempts to zero the stack the second time around using vector instructions. In this particular example, it doesn't gain much in performance (due to the small struct size), however you could imagine a larger struct would have a bigger performance benefit using this code gen over the naive approach.
category:cq
theme:prolog-epilog
skill-level:expert
cost:medium
Using
MemoryMarshal.CreateSpanto create aSpan<T>from a single struct instanceTcauses RyuJIT to emit code to zero the stack twice.Here is a simple example:
This code has the following codegen on
Core CLR v4.700.19.51502:Interestingly, specifying a fixed struct size using the
StructLayoutattribute (in the previous example, 20) causes the JIT to emit "less optimal" code. An example without the fixed struct size:Without the fixed struct size, RyuJIT attempts to zero the stack the second time around using vector instructions. In this particular example, it doesn't gain much in performance (due to the small struct size), however you could imagine a larger struct would have a bigger performance benefit using this code gen over the naive approach.
category:cq
theme:prolog-epilog
skill-level:expert
cost:medium