From f72025c8b6d8a4fc3b4e22e2a3b6e1afeaef15ff Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Mon, 5 Nov 2018 16:06:32 -0800 Subject: Add support for BSWAP intrinsic (#18398) With this change, the JIT will recognize a call to BinaryPrimitives.ReverseEndianness and will emit a bswap instruction. This logic is currently only hooked up for x86 and x64; ARM still uses fallback logic. If the JIT can't emit a bswap instruction (for example, trying to emit a 64-bit bswap in a 32-bit process), it will fall back to a software implementation, so the APIs will work across all architectures. --- .../BinaryPrimitivesReverseEndianness.cs | 136 +++++++++++++++++++++ .../BinaryPrimitivesReverseEndianness_r.csproj | 35 ++++++ .../BinaryPrimitivesReverseEndianness_ro.csproj | 35 ++++++ 3 files changed, 206 insertions(+) create mode 100644 tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness.cs create mode 100644 tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness_r.csproj create mode 100644 tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness_ro.csproj (limited to 'tests/src/JIT') diff --git a/tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness.cs b/tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness.cs new file mode 100644 index 0000000000..b650fc8982 --- /dev/null +++ b/tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness.cs @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Buffers.Binary; +using Internal; + +namespace BinaryPrimitivesReverseEndianness +{ + class Program + { + public const int Pass = 100; + public const int Fail = 0; + + private const ushort ConstantUInt16Input = 0x9876; + private const ushort ConstantUInt16Expected = 0x7698; + + private const uint ConstantUInt32Input = 0x98765432; + private const uint ConstantUInt32Expected = 0x32547698; + + private const ulong ConstantUInt64Input = 0xfedcba9876543210; + private const ulong ConstantUInt64Expected = 0x1032547698badcfe; + + + static int Main(string[] args) + { + /* + * CONST VALUE TESTS + */ + + ushort swappedUInt16 = BinaryPrimitives.ReverseEndianness(ConstantUInt16Input); + if (swappedUInt16 != ConstantUInt16Expected) + { + Console.WriteLine($"BinaryPrimitives.ReverseEndianness(const UInt16) failed."); + Console.WriteLine($"Input: 0x{ConstantUInt16Input:X4}"); + Console.WriteLine($"Output: 0x{swappedUInt16:X4}"); + Console.WriteLine($"Expected: 0x{ConstantUInt16Expected:X4}"); + } + + uint swappedUInt32 = BinaryPrimitives.ReverseEndianness(ConstantUInt32Input); + if (swappedUInt32 != ConstantUInt32Expected) + { + Console.WriteLine($"BinaryPrimitives.ReverseEndianness(const UInt32) failed."); + Console.WriteLine($"Input: 0x{ConstantUInt32Input:X8}"); + Console.WriteLine($"Output: 0x{swappedUInt32:X8}"); + Console.WriteLine($"Expected: 0x{ConstantUInt32Expected:X8}"); + } + + ulong swappedUInt64 = BinaryPrimitives.ReverseEndianness(ConstantUInt64Input); + if (swappedUInt64 != ConstantUInt64Expected) + { + Console.WriteLine($"BinaryPrimitives.ReverseEndianness(const UInt32) failed."); + Console.WriteLine($"Input: 0x{ConstantUInt64Input:X16}"); + Console.WriteLine($"Output: 0x{swappedUInt64:X16}"); + Console.WriteLine($"Expected: 0x{ConstantUInt64Expected:X16}"); + } + + /* + * NON-CONST VALUE TESTS + */ + + ushort nonConstUInt16Input = (ushort)DateTime.UtcNow.Ticks; + ushort nonConstUInt16Output = BinaryPrimitives.ReverseEndianness(nonConstUInt16Input); + ushort nonConstUInt16Expected = ByteSwapUInt16_Control(nonConstUInt16Input); + if (nonConstUInt16Output != nonConstUInt16Expected) + { + Console.WriteLine($"BinaryPrimitives.ReverseEndianness(non-const UInt16) failed."); + Console.WriteLine($"Input: 0x{nonConstUInt16Input:X4}"); + Console.WriteLine($"Output: 0x{nonConstUInt16Output:X4}"); + Console.WriteLine($"Expected: 0x{nonConstUInt16Expected:X4}"); + } + + uint nonConstUInt32Input = (uint)DateTime.UtcNow.Ticks; + uint nonConstUInt32Output = BinaryPrimitives.ReverseEndianness(nonConstUInt32Input); + uint nonConstUInt32Expected = ByteSwapUInt32_Control(nonConstUInt32Input); + if (nonConstUInt32Output != nonConstUInt32Expected) + { + Console.WriteLine($"BinaryPrimitives.ReverseEndianness(non-const UInt32) failed."); + Console.WriteLine($"Input: 0x{nonConstUInt32Input:X8}"); + Console.WriteLine($"Output: 0x{nonConstUInt32Output:X8}"); + Console.WriteLine($"Expected: 0x{nonConstUInt32Expected:X8}"); + } + + ulong nonConstUInt64Input = (ulong)DateTime.UtcNow.Ticks; + ulong nonConstUInt64Output = BinaryPrimitives.ReverseEndianness(nonConstUInt64Input); + ulong nonConstUInt64Expected = ByteSwapUInt64_Control(nonConstUInt64Input); + if (nonConstUInt64Output != nonConstUInt64Expected) + { + Console.WriteLine($"BinaryPrimitives.ReverseEndianness(non-const UInt64) failed."); + Console.WriteLine($"Input: 0x{nonConstUInt64Input:X16}"); + Console.WriteLine($"Output: 0x{nonConstUInt64Output:X16}"); + Console.WriteLine($"Expected: 0x{nonConstUInt64Expected:X16}"); + } + + return Pass; + } + + private static ushort ByteSwapUInt16_Control(ushort value) + { + return (ushort)ByteSwapUnsigned_General(value, sizeof(ushort)); + } + + private static uint ByteSwapUInt32_Control(uint value) + { + return (uint)ByteSwapUnsigned_General(value, sizeof(uint)); + } + + private static ulong ByteSwapUInt64_Control(ulong value) + { + return (ulong)ByteSwapUnsigned_General(value, sizeof(ulong)); + } + + private static ulong ByteSwapUnsigned_General(ulong value, int width) + { + // A naive byte swap routine that works on integers of any arbitrary width. + // Width is specified in bytes. + + ulong retVal = 0; + do + { + retVal = retVal << 8 | (byte)value; + value >>= 8; + } while (--width > 0); + + if (value != 0) + { + // All bits of value should've been shifted out at this point. + throw new Exception("Unexpected data width specified - error in test program?"); + } + + return retVal; + } + } +} diff --git a/tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness_r.csproj b/tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness_r.csproj new file mode 100644 index 0000000000..32ddef9c5a --- /dev/null +++ b/tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness_r.csproj @@ -0,0 +1,35 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + true + None + + + + + + + + + + + diff --git a/tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness_ro.csproj b/tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness_ro.csproj new file mode 100644 index 0000000000..ca7ce2184e --- /dev/null +++ b/tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness_ro.csproj @@ -0,0 +1,35 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + true + None + True + + + + + + + + + + -- cgit v1.2.3