[JIT] X64 - Peephole optimization to skip emitting `movsxd` (#81721)
authorWill Smith <lol.tihan@gmail.com>
Thu, 9 Feb 2023 17:45:54 +0000 (09:45 -0800)
committerGitHub <noreply@github.com>
Thu, 9 Feb 2023 17:45:54 +0000 (09:45 -0800)
* Allow GT_CAST for long to small types on 64bit

* Check unsigned

* Minor cleanup

* Added AreUpper32BitsSigned for peephole optimization

* Renamed to AreUpper32BitsFFFF. Simplified check.

* comments

* Formatting::

* Feedback. Added disasm test.

src/coreclr/jit/codegenxarch.cpp
src/coreclr/jit/emitxarch.cpp
src/coreclr/jit/emitxarch.h
src/tests/JIT/opt/Casts/IntCast.cs [new file with mode: 0644]
src/tests/JIT/opt/Casts/IntCast.csproj [new file with mode: 0644]

index 5c30a83..a468033 100644 (file)
@@ -7008,6 +7008,7 @@ void CodeGen::genIntToIntCast(GenTreeCast* cast)
         case GenIntCastDesc::LOAD_SIGN_EXTEND_INT:
             ins     = INS_movsxd;
             insSize = 4;
+            canSkip = compiler->opts.OptimizationEnabled() && emit->AreUpper32BitsSignExtended(srcReg);
             break;
 #endif
         case GenIntCastDesc::COPY:
index 90c681d..86ad832 100644 (file)
@@ -619,6 +619,54 @@ bool emitter::AreUpper32BitsZero(regNumber reg)
 }
 
 //------------------------------------------------------------------------
+// AreUpper32BitsSignExtended: check if some previously emitted
+//     instruction sign-extended the upper 32 bits.
+//
+// Arguments:
+//    reg - register of interest
+//
+// Return Value:
+//    true if previous instruction upper 32 bits are sign-extended.
+//    false if it did not, or if we can't safely determine.
+bool emitter::AreUpper32BitsSignExtended(regNumber reg)
+{
+    // Only allow GPRs.
+    // If not a valid register, then return false.
+    if (!genIsValidIntReg(reg))
+        return false;
+
+    // Only consider if safe
+    //
+    if (!emitCanPeepholeLastIns())
+    {
+        return false;
+    }
+
+    instrDesc* id = emitLastIns;
+
+    if (id->idReg1() != reg)
+    {
+        return false;
+    }
+
+    // movsx always sign extends to 8 bytes. W-bit is set.
+    if (id->idIns() == INS_movsx)
+    {
+        return true;
+    }
+
+#ifdef TARGET_AMD64
+    // movsxd is always an 8 byte operation. W-bit is set.
+    if (id->idIns() == INS_movsxd)
+    {
+        return true;
+    }
+#endif
+
+    return false;
+}
+
+//------------------------------------------------------------------------
 // AreFlagsSetToZeroCmp: Checks if the previous instruction set the SZ, and optionally OC, flags to
 //                       the same values as if there were a compare to 0
 //
index 6741676..64c7147 100644 (file)
@@ -128,6 +128,7 @@ static bool IsJccInstruction(instruction ins);
 static bool IsJmpInstruction(instruction ins);
 
 bool AreUpper32BitsZero(regNumber reg);
+bool AreUpper32BitsSignExtended(regNumber reg);
 
 bool AreFlagsSetToZeroCmp(regNumber reg, emitAttr opSize, genTreeOps treeOps);
 bool AreFlagsSetForSignJumpOpt(regNumber reg, emitAttr opSize, GenTree* tree);
diff --git a/src/tests/JIT/opt/Casts/IntCast.cs b/src/tests/JIT/opt/Casts/IntCast.cs
new file mode 100644 (file)
index 0000000..1b360f0
--- /dev/null
@@ -0,0 +1,40 @@
+// 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 CodeGenTests
+{
+    class IntCast
+    {
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        static long Cast_Short_To_Long(short value)
+        {
+            // X64-NOT: cdqe
+            return (long)value;
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        static long Cast_Short_To_Long_Add(short value1, short value2)
+        {
+            // X64:     movsx
+            // X64-NOT: cdqe
+            // X64:     movsx
+            // X64-NOT: movsxd
+
+            return (long)value1 + (long)value2;
+        }
+
+        static int Main()
+        {
+            if (Cast_Short_To_Long(Int16.MaxValue) != 32767)
+                return 0;
+
+            if (Cast_Short_To_Long_Add(Int16.MaxValue, Int16.MaxValue) != 65534)
+                return 0;
+
+            return 100;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/tests/JIT/opt/Casts/IntCast.csproj b/src/tests/JIT/opt/Casts/IntCast.csproj
new file mode 100644 (file)
index 0000000..42a89c8
--- /dev/null
@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+  </PropertyGroup>
+  <PropertyGroup>
+    <DebugType>None</DebugType>
+    <Optimize>True</Optimize>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs">
+      <HasDisasmCheck>true</HasDisasmCheck>
+    </Compile>
+
+    <CLRTestEnvironmentVariable Include="DOTNET_TieredCompilation" Value="0" />
+    <CLRTestEnvironmentVariable Include="DOTNET_JITMinOpts" Value="0" />
+  </ItemGroup>
+</Project>