Uh oh!
There was an error while loading. Please reload this page.
Unify unroll limits in a single entry point - #83274
Conversation
ghost
commented
Mar 10, 2023
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch, @kunalspathak Issue Detailsnull
|
jakobbotsch
commented
Mar 10, 2023
Fixes #82529? |
Ah, didn't see this one. Yeah, it does. It zeroes xoreax,eax vxorps ymm0,ymm0 vmovdqu ymmword ptr[rdx],ymm0 vmovdqu ymmword ptr[rdx+20H],ymm0 vmovdqu ymmword ptr[rdx+40H],ymm0 vmovdqu ymmword ptr[rdx+60H],ymm0 vmovdqu ymmword ptr[rdx+80H],ymm0mov qword ptr [rdx+A0H],raxbut only with AVX or on arm64 |
Bencmarks: MemsetpublicunsafeclassMemsetBenchmarks{privatestaticreadonlybyte[]Data1=newbyte[1024];[Benchmark]publicvoidMemset8()=>Unsafe.InitBlockUnaligned(refData1[0],0,8);[Benchmark]publicvoidMemset10()=>Unsafe.InitBlockUnaligned(refData1[0],0,10);[Benchmark]publicvoidMemset14()=>Unsafe.InitBlockUnaligned(refData1[0],0,14);[Benchmark]publicvoidMemset16()=>Unsafe.InitBlockUnaligned(refData1[0],0,16);[Benchmark]publicvoidMemset17()=>Unsafe.InitBlockUnaligned(refData1[0],0,17);[Benchmark]publicvoidMemset20()=>Unsafe.InitBlockUnaligned(refData1[0],0,20);[Benchmark]publicvoidMemset32()=>Unsafe.InitBlockUnaligned(refData1[0],0,32);[Benchmark]publicvoidMemset33()=>Unsafe.InitBlockUnaligned(refData1[0],0,33);[Benchmark]publicvoidMemset40()=>Unsafe.InitBlockUnaligned(refData1[0],0,40);[Benchmark]publicvoidMemset50()=>Unsafe.InitBlockUnaligned(refData1[0],0,50);[Benchmark]publicvoidMemset64()=>Unsafe.InitBlockUnaligned(refData1[0],0,64);[Benchmark]publicvoidMemset65()=>Unsafe.InitBlockUnaligned(refData1[0],0,65);[Benchmark]publicvoidMemset80()=>Unsafe.InitBlockUnaligned(refData1[0],0,80);[Benchmark]publicvoidMemset90()=>Unsafe.InitBlockUnaligned(refData1[0],0,90);[Benchmark]publicvoidMemset110()=>Unsafe.InitBlockUnaligned(refData1[0],0,110);[Benchmark]publicvoidMemset128()=>Unsafe.InitBlockUnaligned(refData1[0],0,128);[Benchmark]publicvoidMemset129()=>Unsafe.InitBlockUnaligned(refData1[0],0,129);[Benchmark]publicvoidMemset200()=>Unsafe.InitBlockUnaligned(refData1[0],0,200);[Benchmark]publicvoidMemset256()=>Unsafe.InitBlockUnaligned(refData1[0],0,256);[Benchmark]publicvoidMemset257()=>Unsafe.InitBlockUnaligned(refData1[0],0,257);[Benchmark]publicvoidMemset300()=>Unsafe.InitBlockUnaligned(refData1[0],0,300);[Benchmark]publicvoidMemset400()=>Unsafe.InitBlockUnaligned(refData1[0],0,400);[Benchmark]publicvoidMemset512()=>Unsafe.InitBlockUnaligned(refData1[0],0,512);}MemcpypublicunsafeclassMemcpyBenchmarks{privatestaticreadonlybyte[]Data1=newbyte[1024];privatestaticreadonlybyte[]Data2=newbyte[1024];[Benchmark]publicvoidMemcpy8()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],8);[Benchmark]publicvoidMemcpy10()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],10);[Benchmark]publicvoidMemcpy14()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],14);[Benchmark]publicvoidMemcpy16()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],16);[Benchmark]publicvoidMemcpy17()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],17);[Benchmark]publicvoidMemcpy20()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],20);[Benchmark]publicvoidMemcpy32()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],32);[Benchmark]publicvoidMemcpy33()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],33);[Benchmark]publicvoidMemcpy40()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],40);[Benchmark]publicvoidMemcpy50()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],50);[Benchmark]publicvoidMemcpy64()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],64);[Benchmark]publicvoidMemcpy65()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],65);[Benchmark]publicvoidMemcpy80()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],80);[Benchmark]publicvoidMemcpy90()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],90);[Benchmark]publicvoidMemcpy110()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],110);[Benchmark]publicvoidMemcpy128()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],128);[Benchmark]publicvoidMemcpy129()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],129);[Benchmark]publicvoidMemcpy200()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],200);[Benchmark]publicvoidMemcpy256()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],256);[Benchmark]publicvoidMemcpy257()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],257);[Benchmark]publicvoidMemcpy300()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],300);[Benchmark]publicvoidMemcpy400()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],400);[Benchmark]publicvoidMemcpy512()=>Unsafe.CopyBlockUnaligned(refData1[0],refData2[0],512);}Verified on: Core i7 8700k, Core i9 9980HK, planning to test on Ryzen 7950X |
Uh oh!
There was an error while loading. Please reload this page.
@dotnet/jit-contrib PTAL Visible things this PR fixes:
Diffs are not too big outside of coreclr_tests collection - around +2k-3k for libraries.pmi: diffs To improve some of them I filed:
A typical size regression looks like this: mov qword ptr [rbp-C8H], rdx
mov rdx, bword ptr [rbp+18H]
; byrRegs +[rdx]
- lea rcx, bword ptr [rbp-B8H]- ; byrRegs +[rcx]- mov r8d, 80- call CORINFO_HELP_MEMCPY- ; byrRegs -[rcx rdx]+ vmovdqu ymm0, ymmword ptr[rdx]+ vmovdqu ymmword ptr[rbp-B8H], ymm0+ vmovdqu ymm0, ymmword ptr[rdx+20H]+ vmovdqu ymmword ptr[rbp-98H], ymm0+ vmovdqu xmm0, xmmword ptr [rdx+40H]+ vmovdqu xmmword ptr [rbp-78H], xmm0
mov rdx, qword ptr [rbp-C0H]
+ ; byrRegs -[rdx]
mov r8, qword ptr [rbp-C8H]
lea r9, [rbp-B8H]
lea rcx, [rbp-40H]which is 2x faster on all machines I tested. There are several cases where unrolling produces more compact code than Diffs are mostly negative for ARM64, e.g.: |
Uh oh!
There was an error while loading. Please reload this page.
EgorBo
commented
Mar 13, 2023
@tannergooding @dotnet/jit-contrib PTAL |




The current limits were a bit odd, e.g. hard limit of 128 bytes on x64 no matter if it supports AVX or not (2x less instructions).
Also, the new limits overall match whatever native compilers do for memset/memcpy unroll in -Os (size-aware): https://godbolt.org/z/dW1qqaP9a
Closes#82529