Skip to content

Commit

Permalink
Switch several arrays to static data references (#72)
Browse files Browse the repository at this point in the history
Motivation
----------
Avoid static constructors and allocating static data on the heap.

Modifications
-------------
Where possible, reference static data directly.
  • Loading branch information
brantburnett authored Mar 11, 2023
1 parent 1080310 commit e3c9834
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 14 deletions.
39 changes: 26 additions & 13 deletions Snappier/Internal/CopyHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,51 @@
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

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<byte> 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<byte> directly.
// It is however safe to convert to Vector128<byte> so we'll do that below with some casts
// that are elided by JIT.
private static ReadOnlySpan<byte> 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
};

/// <summary>
/// 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.
/// </summary>
private static readonly Vector128<byte>[] PshufbFillPatterns = {
Vector128<byte>.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<Vector128<byte>> PshufbFillPatterns
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => MemoryMarshal.CreateReadOnlySpan(
reference: ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(PshufbFillPatternsAsBytes)),
length: 8);
}

/// <summary>
/// j * (16 / j) for all j from 0 to 7. 0 is not actually used.
/// </summary>
private static readonly byte[] PatternSizeTable = {0, 16, 16, 15, 16, 15, 12, 14};
private static ReadOnlySpan<byte> PatternSizeTable => new byte[] {0, 16, 16, 15, 16, 15, 12, 14};

#endif

Expand Down
2 changes: 1 addition & 1 deletion Snappier/Internal/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static int MaxCompressedLength(int sourceBytes)
return 32 + sourceBytes + sourceBytes / 6 + 1;
}

private static readonly byte[] LeftShiftOverflowsMasks =
private static ReadOnlySpan<byte> LeftShiftOverflowsMasks => new byte[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Expand Down

0 comments on commit e3c9834

Please sign in to comment.