From e3c98344b3cb1681982427142f2def16b36035b8 Mon Sep 17 00:00:00 2001 From: Brant Burnett Date: Fri, 10 Mar 2023 23:22:08 -0500 Subject: [PATCH] Switch several arrays to static data references (#72) Motivation ---------- Avoid static constructors and allocating static data on the heap. Modifications ------------- Where possible, reference static data directly. --- Snappier/Internal/CopyHelpers.cs | 39 +++++++++++++++++++++----------- Snappier/Internal/Helpers.cs | 2 +- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/Snappier/Internal/CopyHelpers.cs b/Snappier/Internal/CopyHelpers.cs index 02b3910..e668bdc 100644 --- a/Snappier/Internal/CopyHelpers.cs +++ b/Snappier/Internal/CopyHelpers.cs @@ -2,9 +2,9 @@ using System.Diagnostics; using System.Runtime.CompilerServices; #if NET6_0_OR_GREATER +using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -using static System.Runtime.Intrinsics.X86.Sse2; using static System.Runtime.Intrinsics.X86.Ssse3; #endif @@ -12,28 +12,41 @@ namespace Snappier.Internal { internal class CopyHelpers { - #if NET6_0_OR_GREATER +#if NET6_0_OR_GREATER + + // Raw bytes for PshufbFillPatterns. This syntax returns a ReadOnlySpan that references + // directly to the static data within the DLL. This is only supported with bytes due to things + // like byte-ordering on various architectures, so we can reference Vector128 directly. + // It is however safe to convert to Vector128 so we'll do that below with some casts + // that are elided by JIT. + private static ReadOnlySpan PshufbFillPatternsAsBytes => new byte[] { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Never referenced, here for padding + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, + 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, + 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, + 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, + 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1 + }; /// /// This is a table of shuffle control masks that can be used as the source /// operand for PSHUFB to permute the contents of the destination XMM register /// into a repeating byte pattern. /// - private static readonly Vector128[] PshufbFillPatterns = { - Vector128.Zero, // Never referenced, here for padding - Vector128.Create((byte) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - Vector128.Create((byte) 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1), - Vector128.Create((byte) 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0), - Vector128.Create((byte) 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3), - Vector128.Create((byte) 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0), - Vector128.Create((byte) 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3), - Vector128.Create((byte) 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1) - }; + private static ReadOnlySpan> PshufbFillPatterns + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => MemoryMarshal.CreateReadOnlySpan( + reference: ref Unsafe.As>(ref MemoryMarshal.GetReference(PshufbFillPatternsAsBytes)), + length: 8); + } /// /// j * (16 / j) for all j from 0 to 7. 0 is not actually used. /// - private static readonly byte[] PatternSizeTable = {0, 16, 16, 15, 16, 15, 12, 14}; + private static ReadOnlySpan PatternSizeTable => new byte[] {0, 16, 16, 15, 16, 15, 12, 14}; #endif diff --git a/Snappier/Internal/Helpers.cs b/Snappier/Internal/Helpers.cs index 2ce4d3b..e04e8ab 100644 --- a/Snappier/Internal/Helpers.cs +++ b/Snappier/Internal/Helpers.cs @@ -45,7 +45,7 @@ public static int MaxCompressedLength(int sourceBytes) return 32 + sourceBytes + sourceBytes / 6 + 1; } - private static readonly byte[] LeftShiftOverflowsMasks = + private static ReadOnlySpan LeftShiftOverflowsMasks => new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,