fix BSWAP16 intrinsic handling of signed values (#22666)
authorClinton Ingram <clinton.ingram@outlook.com>
Sat, 23 Feb 2019 17:06:16 +0000 (09:06 -0800)
committerAndy Ayers <andya@microsoft.com>
Sat, 23 Feb 2019 17:06:16 +0000 (09:06 -0800)
src/jit/importer.cpp
tests/src/JIT/Intrinsics/BinaryPrimitivesReverseEndianness.cs

index 5d3a82e..6f19213 100644 (file)
@@ -4068,7 +4068,8 @@ GenTree* Compiler::impIntrinsic(GenTree*                newobjThis,
                 {
                     case CorInfoType::CORINFO_TYPE_SHORT:
                     case CorInfoType::CORINFO_TYPE_USHORT:
-                        retNode = gtNewOperNode(GT_BSWAP16, callType, impPopStack().val);
+                        retNode = gtNewCastNode(TYP_INT, gtNewOperNode(GT_BSWAP16, TYP_INT, impPopStack().val), false,
+                                                callType);
                         break;
 
                     case CorInfoType::CORINFO_TYPE_INT:
index b650fc8..a1a2f74 100644 (file)
@@ -5,6 +5,7 @@
 
 using System;
 using System.Buffers.Binary;
+using System.Runtime.InteropServices;
 using Internal;
 
 namespace BinaryPrimitivesReverseEndianness
@@ -23,6 +24,8 @@ namespace BinaryPrimitivesReverseEndianness
         private const ulong ConstantUInt64Input = 0xfedcba9876543210;
         private const ulong ConstantUInt64Expected = 0x1032547698badcfe;
 
+        private static readonly byte[] s_bufferLE = new byte[] { 0x32, 0x54, 0x76, 0x98 };
+        private static readonly byte[] s_bufferBE = new byte[] { 0x98, 0x76, 0x54, 0x32 };
 
         static int Main(string[] args)
         {
@@ -33,28 +36,42 @@ namespace BinaryPrimitivesReverseEndianness
             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}");
+                ReportError("const UInt16", ConstantUInt16Input, swappedUInt16, ConstantUInt16Expected);
+                return Fail;
             }
 
             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}");
+                ReportError("const UInt32", ConstantUInt32Input, swappedUInt32, ConstantUInt32Expected);
+                return Fail;
             }
 
             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}");
+                ReportError("const UInt64", ConstantUInt64Input, swappedUInt64, ConstantUInt64Expected);
+                return Fail;
+            }
+
+            /*
+             * SIGN-EXTENDED VALUE TESTS
+             */
+
+            Span<byte> spanInt16 = BitConverter.IsLittleEndian ? s_bufferLE.AsSpan().Slice(2) : s_bufferBE;
+            short swappedInt16 = BinaryPrimitives.ReverseEndianness(MemoryMarshal.Read<short>(spanInt16));
+            if (swappedInt16 != ConstantUInt16Expected)
+            {
+                ReportError("sign-extended Int16", ConstantUInt16Input, (int)swappedInt16, ConstantUInt16Expected);
+                return Fail;
+            }
+
+            Span<byte> spanInt32 = BitConverter.IsLittleEndian ? s_bufferLE : s_bufferBE;
+            int swappedInt32 = BinaryPrimitives.ReverseEndianness(MemoryMarshal.Read<int>(spanInt32));
+            if (swappedInt32 != ConstantUInt32Expected)
+            {
+                ReportError("sign-extended Int32", ConstantUInt32Input, (long)swappedInt32, ConstantUInt32Expected);
+                return Fail;
             }
 
             /*
@@ -66,10 +83,8 @@ namespace BinaryPrimitivesReverseEndianness
             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}");
+                ReportError("non-const UInt16", nonConstUInt16Input, nonConstUInt16Output, nonConstUInt16Expected);
+                return Fail;
             }
 
             uint nonConstUInt32Input = (uint)DateTime.UtcNow.Ticks;
@@ -77,10 +92,8 @@ namespace BinaryPrimitivesReverseEndianness
             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}");
+                ReportError("non-const UInt32", nonConstUInt32Input, nonConstUInt32Output, nonConstUInt32Expected);
+                return Fail;
             }
 
             ulong nonConstUInt64Input = (ulong)DateTime.UtcNow.Ticks;
@@ -88,10 +101,8 @@ namespace BinaryPrimitivesReverseEndianness
             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}");
+                ReportError("non-const UInt64", nonConstUInt64Input, nonConstUInt64Output, nonConstUInt64Expected);
+                return Fail;
             }
 
             return Pass;
@@ -132,5 +143,32 @@ namespace BinaryPrimitivesReverseEndianness
 
             return retVal;
         }
+
+        private static string GetHexString<T>(T value)
+        {
+            if (typeof(T) == typeof(short))
+                return ((short)(object)value).ToString("X4");
+            if (typeof(T) == typeof(ushort))
+                return ((ushort)(object)value).ToString("X4");
+            if (typeof(T) == typeof(int))
+                return ((int)(object)value).ToString("X8");
+            if (typeof(T) == typeof(uint))
+                return ((uint)(object)value).ToString("X8");
+            if (typeof(T) == typeof(long))
+                return ((long)(object)value).ToString("X16");
+            if (typeof(T) == typeof(ulong))
+                return ((ulong)(object)value).ToString("X16");
+
+            throw new NotSupportedException();
+        }
+
+        private static void ReportError<T>(string testName, T input, T output, T expected)
+        {
+            Console.WriteLine($"BinaryPrimitives.ReverseEndianness({testName}) failed.");
+            Console.WriteLine($"Input:    0x{GetHexString(input)}");
+            Console.WriteLine($"Output:   0x{GetHexString(output)}");
+            Console.WriteLine($"Expected: 0x{GetHexString(expected)}");
+        }
+
     }
 }