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;
--- /dev/null
+// 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));
+ }
+ }
+}
+
--- /dev/null
+<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>