case GenIntCastDesc::LOAD_SIGN_EXTEND_INT:
ins = INS_movsxd;
insSize = 4;
+ canSkip = compiler->opts.OptimizationEnabled() && emit->AreUpper32BitsSignExtended(srcReg);
break;
#endif
case GenIntCastDesc::COPY:
}
//------------------------------------------------------------------------
+// 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
//
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);
--- /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 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
--- /dev/null
+<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>