From 6b9c7904c4eb3550daa5bf7269cd9e850d36179a Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 28 Feb 2024 18:39:53 +0100 Subject: [PATCH 1/3] Special case Mono --- .../System.Private.CoreLib/src/System/Span.cs | 9 +++++++ .../src/System/SpanHelpers.ByteMemOps.cs | 24 +++++++++---------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Span.cs b/src/libraries/System.Private.CoreLib/src/System/Span.cs index 1c66a341b0fde1..d8fbb261e4f381 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Span.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Span.cs @@ -300,6 +300,15 @@ public unsafe void Clear() [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void Fill(T value) { + // Mono works faster with Unsafe.InitBlockUnaligned +#if MONO + if (sizeof(T) == 1) + { + Unsafe.InitBlockUnaligned(ref Unsafe.As(ref _reference), *(byte*)&value, (uint)_length); + return; + } +#endif + SpanHelpers.Fill(ref _reference, (uint)_length, value); } diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs index 54294592099256..4228aa0f3b4318 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs @@ -254,6 +254,13 @@ public static unsafe void ClearWithoutReferences(ref byte dest, nuint len) if (len == 0) return; + // Mono works faster with Unsafe.InitBlockUnaligned +#if MONO + if (len > 768) + goto PInvoke; + Unsafe.InitBlockUnaligned(ref dest, 0, (uint)len); + return; +#else ref byte destEnd = ref Unsafe.Add(ref dest, len); if (len <= 16) @@ -427,6 +434,7 @@ public static unsafe void ClearWithoutReferences(ref byte dest, nuint len) Unsafe.WriteUnaligned(ref Unsafe.Add(ref destEnd, -4), 0); #endif return; +#endif // MONO PInvoke: // Implicit nullchecks @@ -498,24 +506,16 @@ internal static void Fill(ref byte dest, byte value, nuint len) nuint stopLoopAtOffset = len & ~(nuint)7; do { - Unsafe.Add(ref dest, (nint)i + 0) = value; - Unsafe.Add(ref dest, (nint)i + 1) = value; - Unsafe.Add(ref dest, (nint)i + 2) = value; - Unsafe.Add(ref dest, (nint)i + 3) = value; - Unsafe.Add(ref dest, (nint)i + 4) = value; - Unsafe.Add(ref dest, (nint)i + 5) = value; - Unsafe.Add(ref dest, (nint)i + 6) = value; - Unsafe.Add(ref dest, (nint)i + 7) = value; + // broadcast the value to all 8 bytes of the ulong and write it to memory + Unsafe.WriteUnaligned(ref Unsafe.Add(ref dest, i), value * 0x101010101010101ul); } while ((i += 8) < stopLoopAtOffset); } // Write next 4 elements if needed if ((len & 4) != 0) { - Unsafe.Add(ref dest, (nint)i + 0) = value; - Unsafe.Add(ref dest, (nint)i + 1) = value; - Unsafe.Add(ref dest, (nint)i + 2) = value; - Unsafe.Add(ref dest, (nint)i + 3) = value; + // broadcast the value to all 4 bytes of the uint and write it to memory + Unsafe.WriteUnaligned(ref Unsafe.Add(ref dest, i), value * 0x1010101u); i += 4; } From 8d785731c716725895ad1530405ea179996eb5e8 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 28 Feb 2024 19:26:27 +0100 Subject: [PATCH 2/3] Update SpanHelpers.ByteMemOps.cs --- .../System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs index 4228aa0f3b4318..7876e748ac2cc2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs @@ -22,7 +22,9 @@ internal static partial class SpanHelpers // .ByteMemOps #else private const nuint MemmoveNativeThreshold = 2048; #endif +#if !MONO private const nuint ZeroMemoryNativeThreshold = 1024; +#endif #if HAS_CUSTOM_BLOCKS From b1a1bf2b3185f260fb0e55e07c7b5c81e565da9b Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 28 Feb 2024 19:27:50 +0100 Subject: [PATCH 3/3] Update SpanHelpers.ByteMemOps.cs --- .../src/System/SpanHelpers.ByteMemOps.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs index 7876e748ac2cc2..2a47b9437ecec2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs @@ -22,9 +22,7 @@ internal static partial class SpanHelpers // .ByteMemOps #else private const nuint MemmoveNativeThreshold = 2048; #endif -#if !MONO private const nuint ZeroMemoryNativeThreshold = 1024; -#endif #if HAS_CUSTOM_BLOCKS @@ -258,7 +256,7 @@ public static unsafe void ClearWithoutReferences(ref byte dest, nuint len) // Mono works faster with Unsafe.InitBlockUnaligned #if MONO - if (len > 768) + if (len > ZeroMemoryNativeThreshold) goto PInvoke; Unsafe.InitBlockUnaligned(ref dest, 0, (uint)len); return;