diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 10466de77af15..9d3d95c4e2631 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -108,12 +108,11 @@ + + - - - - - + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/ReaderBigEndian.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.ReadBigEndian.cs similarity index 100% rename from src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/ReaderBigEndian.cs rename to src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.ReadBigEndian.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/ReaderLittleEndian.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.ReadLittleEndian.cs similarity index 100% rename from src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/ReaderLittleEndian.cs rename to src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.ReadLittleEndian.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.ReverseEndianness.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.ReverseEndianness.cs index 6f355d2089f83..c229efb2f3d38 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.ReverseEndianness.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.ReverseEndianness.cs @@ -2,14 +2,172 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; +#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types + +#if TARGET_64BIT +using nint_t = System.Int64; +using nuint_t = System.UInt64; +#else +using nint_t = System.Int32; +using nuint_t = System.UInt32; +#endif + namespace System.Buffers.Binary { public static partial class BinaryPrimitives { + /// + /// This is a no-op and added only for consistency. + /// This allows the caller to read a struct of numeric primitives and reverse each field + /// rather than having to skip sbyte fields. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static sbyte ReverseEndianness(sbyte value) => value; + + /// + /// Reverses a primitive value - performs an endianness swap + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ReverseEndianness(short value) => (short)ReverseEndianness((ushort)value); + + /// + /// Reverses a primitive value - performs an endianness swap + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReverseEndianness(int value) => (int)ReverseEndianness((uint)value); + + /// + /// Reverses a primitive value - performs an endianness swap + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ReverseEndianness(long value) => (long)ReverseEndianness((ulong)value); + + /// Reverses a primitive value by performing an endianness swap of the specified value. + /// The value to reverse. + /// The reversed value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static nint ReverseEndianness(nint value) => (nint)ReverseEndianness((nint_t)value); + + /// Reverses a primitive value by performing an endianness swap of the specified value. + /// The value to reverse. + /// The reversed value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Int128 ReverseEndianness(Int128 value) + { + return new Int128( + ReverseEndianness(value.Lower), + ReverseEndianness(value.Upper) + ); + } + + /// + /// This is a no-op and added only for consistency. + /// This allows the caller to read a struct of numeric primitives and reverse each field + /// rather than having to skip byte fields. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte ReverseEndianness(byte value) => value; + + /// + /// Reverses a primitive value - performs an endianness swap + /// + [CLSCompliant(false)] + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ReverseEndianness(ushort value) + { + // Don't need to AND with 0xFF00 or 0x00FF since the final + // cast back to ushort will clear out all bits above [ 15 .. 00 ]. + // This is normally implemented via "movzx eax, ax" on the return. + // Alternatively, the compiler could elide the movzx instruction + // entirely if it knows the caller is only going to access "ax" + // instead of "eax" / "rax" when the function returns. + + return (ushort)((value >> 8) + (value << 8)); + } + + /// + /// Reverses a 16-bit character value - performs an endianness swap + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static char ReverseEndianness(char value) => (char)ReverseEndianness((ushort)value); + + /// + /// Reverses a primitive value - performs an endianness swap + /// + [CLSCompliant(false)] + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ReverseEndianness(uint value) + { + // This takes advantage of the fact that the JIT can detect + // ROL32 / ROR32 patterns and output the correct intrinsic. + // + // Input: value = [ ww xx yy zz ] + // + // First line generates : [ ww xx yy zz ] + // & [ 00 FF 00 FF ] + // = [ 00 xx 00 zz ] + // ROR32(8) = [ zz 00 xx 00 ] + // + // Second line generates: [ ww xx yy zz ] + // & [ FF 00 FF 00 ] + // = [ ww 00 yy 00 ] + // ROL32(8) = [ 00 yy 00 ww ] + // + // (sum) = [ zz yy xx ww ] + // + // Testing shows that throughput increases if the AND + // is performed before the ROL / ROR. + + return BitOperations.RotateRight(value & 0x00FF00FFu, 8) // xx zz + + BitOperations.RotateLeft(value & 0xFF00FF00u, 8); // ww yy + } + + /// + /// Reverses a primitive value - performs an endianness swap + /// + [CLSCompliant(false)] + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ReverseEndianness(ulong value) + { + // Operations on 32-bit values have higher throughput than + // operations on 64-bit values, so decompose. + + return ((ulong)ReverseEndianness((uint)value) << 32) + + ReverseEndianness((uint)(value >> 32)); + } + + /// Reverses a primitive value by performing an endianness swap of the specified value. + /// The value to reverse. + /// The reversed value. + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static nuint ReverseEndianness(nuint value) => (nuint)ReverseEndianness((nuint_t)value); + + /// Reverses a primitive value by performing an endianness swap of the specified value. + /// The value to reverse. + /// The reversed value. + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static UInt128 ReverseEndianness(UInt128 value) + { + return new UInt128( + ReverseEndianness(value.Lower), + ReverseEndianness(value.Upper) + ); + } + /// Copies every primitive value from to , reversing each primitive by performing an endianness swap as part of writing each. /// The source span to copy. /// The destination to which the source elements should be copied. diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/WriterBigEndian.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.WriteBigEndian.cs similarity index 100% rename from src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/WriterBigEndian.cs rename to src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.WriteBigEndian.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/WriterLittleEndian.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.WriteLittleEndian.cs similarity index 100% rename from src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/WriterLittleEndian.cs rename to src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.WriteLittleEndian.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/Reader.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/Reader.cs deleted file mode 100644 index 540f8732b6859..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/Reader.cs +++ /dev/null @@ -1,175 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.Intrinsics; - -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types - -#if TARGET_64BIT -using nint_t = System.Int64; -using nuint_t = System.UInt64; -#else -using nint_t = System.Int32; -using nuint_t = System.UInt32; -#endif - -namespace System.Buffers.Binary -{ - /// - /// Reads bytes as primitives with specific endianness - /// - /// - /// Use these helpers when you need to read specific endianness. - /// - public static partial class BinaryPrimitives - { - /// - /// This is a no-op and added only for consistency. - /// This allows the caller to read a struct of numeric primitives and reverse each field - /// rather than having to skip sbyte fields. - /// - [CLSCompliant(false)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static sbyte ReverseEndianness(sbyte value) => value; - - /// - /// Reverses a primitive value - performs an endianness swap - /// - [Intrinsic] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static short ReverseEndianness(short value) => (short)ReverseEndianness((ushort)value); - - /// - /// Reverses a primitive value - performs an endianness swap - /// - [Intrinsic] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReverseEndianness(int value) => (int)ReverseEndianness((uint)value); - - /// - /// Reverses a primitive value - performs an endianness swap - /// - [Intrinsic] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long ReverseEndianness(long value) => (long)ReverseEndianness((ulong)value); - - /// Reverses a primitive value by performing an endianness swap of the specified value. - /// The value to reverse. - /// The reversed value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static nint ReverseEndianness(nint value) => (nint)ReverseEndianness((nint_t)value); - - /// Reverses a primitive value by performing an endianness swap of the specified value. - /// The value to reverse. - /// The reversed value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Int128 ReverseEndianness(Int128 value) - { - return new Int128( - ReverseEndianness(value.Lower), - ReverseEndianness(value.Upper) - ); - } - - /// - /// This is a no-op and added only for consistency. - /// This allows the caller to read a struct of numeric primitives and reverse each field - /// rather than having to skip byte fields. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte ReverseEndianness(byte value) => value; - - /// - /// Reverses a primitive value - performs an endianness swap - /// - [CLSCompliant(false)] - [Intrinsic] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ushort ReverseEndianness(ushort value) - { - // Don't need to AND with 0xFF00 or 0x00FF since the final - // cast back to ushort will clear out all bits above [ 15 .. 00 ]. - // This is normally implemented via "movzx eax, ax" on the return. - // Alternatively, the compiler could elide the movzx instruction - // entirely if it knows the caller is only going to access "ax" - // instead of "eax" / "rax" when the function returns. - - return (ushort)((value >> 8) + (value << 8)); - } - - /// - /// Reverses a 16-bit character value - performs an endianness swap - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static char ReverseEndianness(char value) => (char)ReverseEndianness((ushort)value); - - /// - /// Reverses a primitive value - performs an endianness swap - /// - [CLSCompliant(false)] - [Intrinsic] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint ReverseEndianness(uint value) - { - // This takes advantage of the fact that the JIT can detect - // ROL32 / ROR32 patterns and output the correct intrinsic. - // - // Input: value = [ ww xx yy zz ] - // - // First line generates : [ ww xx yy zz ] - // & [ 00 FF 00 FF ] - // = [ 00 xx 00 zz ] - // ROR32(8) = [ zz 00 xx 00 ] - // - // Second line generates: [ ww xx yy zz ] - // & [ FF 00 FF 00 ] - // = [ ww 00 yy 00 ] - // ROL32(8) = [ 00 yy 00 ww ] - // - // (sum) = [ zz yy xx ww ] - // - // Testing shows that throughput increases if the AND - // is performed before the ROL / ROR. - - return BitOperations.RotateRight(value & 0x00FF00FFu, 8) // xx zz - + BitOperations.RotateLeft(value & 0xFF00FF00u, 8); // ww yy - } - - /// - /// Reverses a primitive value - performs an endianness swap - /// - [CLSCompliant(false)] - [Intrinsic] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong ReverseEndianness(ulong value) - { - // Operations on 32-bit values have higher throughput than - // operations on 64-bit values, so decompose. - - return ((ulong)ReverseEndianness((uint)value) << 32) - + ReverseEndianness((uint)(value >> 32)); - } - - /// Reverses a primitive value by performing an endianness swap of the specified value. - /// The value to reverse. - /// The reversed value. - [CLSCompliant(false)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static nuint ReverseEndianness(nuint value) => (nuint)ReverseEndianness((nuint_t)value); - - /// Reverses a primitive value by performing an endianness swap of the specified value. - /// The value to reverse. - /// The reversed value. - [CLSCompliant(false)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static UInt128 ReverseEndianness(UInt128 value) - { - return new UInt128( - ReverseEndianness(value.Lower), - ReverseEndianness(value.Upper) - ); - } - } -}