Do not fold away double negation if the tree is a CSE candidate (#50373)
authorSingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
Tue, 30 Mar 2021 01:14:17 +0000 (04:14 +0300)
committerGitHub <noreply@github.com>
Tue, 30 Mar 2021 01:14:17 +0000 (18:14 -0700)
* Do not morph away double negation if it is a CSE candidate

* Added a test verifying that double negation is not removed for CSEs

* Bump the test's priority to zero

src/coreclr/jit/morph.cpp
src/tests/JIT/opt/CSE/CSEWithDoubleNegation.cs [new file with mode: 0644]
src/tests/JIT/opt/CSE/CSEWithDoubleNegation.csproj [new file with mode: 0644]

index 433750b..8fbce8a 100644 (file)
@@ -14411,8 +14411,12 @@ DONE_MORPHING_CHILDREN:
 
         case GT_NOT:
         case GT_NEG:
-            // Remove double negation/not
-            if (op1->OperIs(oper) && opts.OptimizationEnabled())
+            // Remove double negation/not.
+            // Note: this is not a safe tranformation if "tree" is a CSE candidate.
+            // Consider for example the following expression: NEG(NEG(OP)), where the top-level
+            // NEG is a CSE candidate. Were we to morph this to just OP, CSE would fail to find
+            // the original NEG in the statement.
+            if (op1->OperIs(oper) && opts.OptimizationEnabled() && !gtIsActiveCSE_Candidate(tree))
             {
                 GenTree* child = op1->AsOp()->gtGetOp1();
                 return child;
diff --git a/src/tests/JIT/opt/CSE/CSEWithDoubleNegation.cs b/src/tests/JIT/opt/CSE/CSEWithDoubleNegation.cs
new file mode 100644 (file)
index 0000000..d157d14
--- /dev/null
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.CompilerServices;
+
+namespace CSEWithDoubleNegation
+{
+    class DoNotMorphAwayCSEThatRepresentsDoubleNegation
+    {
+        private static int _static = 0;
+
+        static int Main(string[] args)
+        {
+            if (DoubleNeg() != 22)
+            {
+                Console.WriteLine("DoubleNeg() failed to return the expected value of 22");
+                return -1;
+            }
+
+            return 100;
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private static int DoubleNeg()
+        {
+            var a = 21;
+            _static = 42;
+
+            return 43 - (0 - (a - _static));
+        }
+    }
+}
+
diff --git a/src/tests/JIT/opt/CSE/CSEWithDoubleNegation.csproj b/src/tests/JIT/opt/CSE/CSEWithDoubleNegation.csproj
new file mode 100644 (file)
index 0000000..0750011
--- /dev/null
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+  </PropertyGroup>
+  <PropertyGroup>
+    <DebugType>None</DebugType>
+    <Optimize>True</Optimize>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="CSEWithDoubleNegation.cs" />
+  </ItemGroup>
+</Project>