Fix crc32 issues found in #62692 (#73005)
authorEgor Bogatov <egorbo@gmail.com>
Fri, 29 Jul 2022 20:20:04 +0000 (22:20 +0200)
committerGitHub <noreply@github.com>
Fri, 29 Jul 2022 20:20:04 +0000 (22:20 +0200)
src/coreclr/jit/hwintrinsiccodegenxarch.cpp
src/coreclr/jit/lower.h
src/tests/JIT/Regression/JitBlue/Runtime_62692/Runtime_62692.cs [new file with mode: 0644]
src/tests/JIT/Regression/JitBlue/Runtime_62692/Runtime_62692_r.csproj [new file with mode: 0644]
src/tests/JIT/Regression/JitBlue/Runtime_62692/Runtime_62692_ro.csproj [new file with mode: 0644]

index df8cc01..107705f 100644 (file)
@@ -1425,7 +1425,6 @@ void CodeGen::genSSE42Intrinsic(GenTreeHWIntrinsic* node)
             }
             else
             {
-                assert(op1->TypeGet() == op2->TypeGet());
                 assert((targetType == TYP_INT) || (targetType == TYP_LONG));
                 genHWIntrinsic_R_RM(node, INS_crc32, emitTypeSize(targetType), targetReg, op2);
             }
index 46e1acc..b8b5686 100644 (file)
@@ -377,17 +377,36 @@ private:
     //     Otherwise, it returns the underlying operation that was being casted
     GenTree* TryRemoveCastIfPresent(var_types expectedType, GenTree* op)
     {
-        if (!op->OperIs(GT_CAST))
+        if (!op->OperIs(GT_CAST) || !comp->opts.OptimizationEnabled())
         {
             return op;
         }
 
-        GenTree* castOp = op->AsCast()->CastOp();
+        GenTreeCast* cast = op->AsCast();
 
-        if (genTypeSize(castOp->gtType) >= genTypeSize(expectedType))
+        // FP <-> INT casts should be kept
+        if (varTypeIsFloating(cast->CastFromType()) ^ varTypeIsFloating(expectedType))
         {
+            return op;
+        }
+
+        // Keep casts which can overflow
+        if (cast->gtOverflow())
+        {
+            return op;
+        }
+
+        if (genTypeSize(cast->CastToType()) >= genTypeSize(expectedType))
+        {
+#ifndef TARGET_64BIT
+            // Don't expose TYP_LONG on 32bit
+            if (varTypeIsLong(cast->CastFromType()))
+            {
+                return op;
+            }
+#endif
             BlockRange().Remove(op);
-            return castOp;
+            return cast->CastOp();
         }
 
         return op;
diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_62692/Runtime_62692.cs b/src/tests/JIT/Regression/JitBlue/Runtime_62692/Runtime_62692.cs
new file mode 100644 (file)
index 0000000..aec577d
--- /dev/null
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.CompilerServices;
+using System;
+using System.Runtime.Intrinsics.X86;
+
+public unsafe class Runtime_62692
+{
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static uint Problem1(byte* pSrc, uint data) => Sse42.Crc32(*pSrc, data);
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static uint Problem2(uint crc, ulong data) => Sse42.Crc32(crc, (uint)(data >> 16));
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static uint Problem3(uint crc, uint data) => Sse42.Crc32(crc, (uint)(byte)data);
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static uint Problem4(uint crc, ulong data) => Sse42.Crc32(crc, (uint)(data >> 16));
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static uint Problem5(uint crc, double data) => Sse42.Crc32(crc, (uint)data);
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static uint Problem6(uint crc, float data) => Sse42.Crc32(crc, (uint)data);
+
+    static int Main()
+    {
+        if (Sse42.IsSupported)
+        {
+            long a = long.MaxValue;
+            AssertEqual(Problem1((byte*)&a, 111), 3150215170);
+            a = 333;
+            AssertEqual(Problem1((byte*)&a, 44), 2714165716);
+            AssertEqual(Problem2(uint.MaxValue, 42), 3080238136);
+            AssertEqual(Problem2(1111, 0xFFFF_FFFF_0000_0001), 3414328792);
+            AssertEqual(Problem3(1, 0xFFFF_0001), 0);
+            AssertEqual(Problem4(1111, 0xFFFF_FFFF_0000_0001), 3414328792);
+            AssertEqual(Problem5(1111, double.MaxValue), 3307008522);
+            AssertEqual(Problem6(1111, float.MaxValue), 3307008522);
+            AssertEqual(Problem5(1111, double.MinValue), 3307008522);
+            AssertEqual(Problem6(1111, float.MinValue), 3307008522);
+            AssertEqual(Problem5(1111, -0.0), 3307008522);
+            AssertEqual(Problem6(1111, -0.0f), 3307008522);
+        }
+
+        Console.WriteLine(retCode);
+        return retCode;
+    }
+
+    static int retCode = 100;
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static void AssertEqual(uint a, uint b, [CallerLineNumber] int line = 0)
+    {
+        if (a != b)
+        {
+            Console.WriteLine($"{a} != {b}, Line:{line}");
+            retCode++;
+        }
+    }
+}
diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_62692/Runtime_62692_r.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_62692/Runtime_62692_r.csproj
new file mode 100644 (file)
index 0000000..cff31f0
--- /dev/null
@@ -0,0 +1,10 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <Optimize>False</Optimize>
+    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="Runtime_62692.cs" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_62692/Runtime_62692_ro.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_62692/Runtime_62692_ro.csproj
new file mode 100644 (file)
index 0000000..83ea5c0
--- /dev/null
@@ -0,0 +1,10 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <Optimize>True</Optimize>
+    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="Runtime_62692.cs" />
+  </ItemGroup>
+</Project>
\ No newline at end of file