From cbbe45d39ca74bf2971b62dc57a56d37b4aa9f2f Mon Sep 17 00:00:00 2001 From: WinCPP Date: Tue, 18 Apr 2017 08:11:36 +0530 Subject: [PATCH] Issue #17118 Loop unrolling in Span.CopyTo slow path --- src/System.Memory/src/System/SpanHelpers.cs | 39 ++++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/System.Memory/src/System/SpanHelpers.cs b/src/System.Memory/src/System/SpanHelpers.cs index 1767772d96ff..42c341b78c83 100644 --- a/src/System.Memory/src/System/SpanHelpers.cs +++ b/src/System.Memory/src/System/SpanHelpers.cs @@ -61,22 +61,35 @@ ref Unsafe.Add(ref srcBytes, (IntPtr)index), } else { - if (srcGreaterThanDst) + int direction = srcGreaterThanDst ? 1 : -1; + int runCount = srcGreaterThanDst ? 0 : srcLength - 1; + + int loopCount = 0; + for (; loopCount < (srcLength & ~7); loopCount += 8) { - // Source address greater than or equal to destination address. Can do normal copy. - for (int i = 0; i < srcLength; i++) - { - Unsafe.Add(ref dst, i) = Unsafe.Add(ref src, i); - } + Unsafe.Add(ref dst, runCount + direction * 0) = Unsafe.Add(ref src, runCount + direction * 0); + Unsafe.Add(ref dst, runCount + direction * 1) = Unsafe.Add(ref src, runCount + direction * 1); + Unsafe.Add(ref dst, runCount + direction * 2) = Unsafe.Add(ref src, runCount + direction * 2); + Unsafe.Add(ref dst, runCount + direction * 3) = Unsafe.Add(ref src, runCount + direction * 3); + Unsafe.Add(ref dst, runCount + direction * 4) = Unsafe.Add(ref src, runCount + direction * 4); + Unsafe.Add(ref dst, runCount + direction * 5) = Unsafe.Add(ref src, runCount + direction * 5); + Unsafe.Add(ref dst, runCount + direction * 6) = Unsafe.Add(ref src, runCount + direction * 6); + Unsafe.Add(ref dst, runCount + direction * 7) = Unsafe.Add(ref src, runCount + direction * 7); + runCount += direction * 8; } - else + if (loopCount < (srcLength & ~3)) + { + Unsafe.Add(ref dst, runCount + direction * 0) = Unsafe.Add(ref src, runCount + direction * 0); + Unsafe.Add(ref dst, runCount + direction * 1) = Unsafe.Add(ref src, runCount + direction * 1); + Unsafe.Add(ref dst, runCount + direction * 2) = Unsafe.Add(ref src, runCount + direction * 2); + Unsafe.Add(ref dst, runCount + direction * 3) = Unsafe.Add(ref src, runCount + direction * 3); + runCount += direction * 4; + loopCount += 4; + } + for (; loopCount < srcLength; ++loopCount) { - // Source address less than destination address. Must do backward copy. - int i = srcLength; - while (i-- != 0) - { - Unsafe.Add(ref dst, i) = Unsafe.Add(ref src, i); - } + Unsafe.Add(ref dst, runCount) = Unsafe.Add(ref src, runCount); + runCount += direction; } } }