Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -1416,8 +1416,9 @@ class CodeGen final : public CodeGenInterface
regNumber dstReg,
regNumber srcReg,
bool canSkip,
emitAttr size = EA_UNKNOWN,
insFlags flags = INS_FLAGS_DONT_CARE);
emitAttr size = EA_UNKNOWN,
insFlags flags = INS_FLAGS_DONT_CARE,
var_types dstType = TYP_UNKNOWN);

void inst_RV_RV(instruction ins,
regNumber reg1,
Expand Down Expand Up @@ -1637,7 +1638,7 @@ class CodeGen final : public CodeGenInterface
bool arm_Valid_Imm_For_Add_SP(target_ssize_t imm);
#endif

instruction ins_Move_Extend(var_types srcType, bool srcInReg);
instruction ins_Move_Extend(var_types srcType, bool srcInReg, var_types dstType = TYP_UNKNOWN);

instruction ins_Copy(var_types dstType);
instruction ins_Copy(regNumber srcReg, var_types dstType);
Expand Down
25 changes: 14 additions & 11 deletions src/coreclr/jit/instr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -790,9 +790,10 @@ void CodeGen::inst_Mov_Extend(var_types srcType,
regNumber srcReg,
bool canSkip,
emitAttr size,
insFlags flags /* = INS_FLAGS_DONT_CARE */)
insFlags flags /* = INS_FLAGS_DONT_CARE */,
var_types dstType /* = TYP_UNKNOWN */)
{
instruction ins = ins_Move_Extend(srcType, srcInReg);
instruction ins = ins_Move_Extend(srcType, srcInReg, dstType);

if (size == EA_UNKNOWN)
{
Expand Down Expand Up @@ -1920,9 +1921,17 @@ bool CodeGenInterface::validImmForBL(ssize_t addr)
* Parameters
* srcType - source type
* srcInReg - whether source is in a register
* dstType - type the value will be consumed as; defaults to srcType. Must share srcType's
* actual type, as genuine widening (e.g. int -> long) must use a cast instead.
*/
instruction CodeGen::ins_Move_Extend(var_types srcType, bool srcInReg)
instruction CodeGen::ins_Move_Extend(var_types srcType, bool srcInReg, var_types dstType /* = TYP_UNKNOWN */)
{
if (dstType == TYP_UNKNOWN)
{
dstType = srcType;
}
assert(genActualType(srcType) == genActualType(dstType));

if (varTypeUsesIntReg(srcType))
{
instruction ins = INS_invalid;
Expand Down Expand Up @@ -2005,14 +2014,8 @@ instruction CodeGen::ins_Move_Extend(var_types srcType, bool srcInReg)
}
else
{
if (srcType == TYP_INT)
{
ins = INS_sxtw;
}
else
{
ins = INS_mov;
}
// A TYP_INT value only needs its low 32 bits; mov Wd, Wn zero extends the rest.
ins = INS_mov;
}
}
}
Expand Down
78 changes: 78 additions & 0 deletions src/tests/JIT/opt/InstructionCombining/IntMoveNoSignExtend.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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;
using Xunit;

namespace TestIntMoveNoSignExtend
{
public class Program
{
static int s_value = 7;

[MethodImpl(MethodImplOptions.NoInlining)]
static int GetInt() => s_value;

[MethodImpl(MethodImplOptions.NoInlining)]
static void Sink(int x) => s_value ^= x;

// A reg-to-reg move of a TYP_INT value (here the call result kept in a callee-saved register
// across the following call) must not be sign extended to 64 bits: the upper bits are never
// observed for an int, so a plain 'mov Wd, Wn' suffices instead of 'sxtw Wd, Wn'.
[MethodImpl(MethodImplOptions.NoInlining)]
static int IntMove()
{
//ARM64-NOT: sxtw {{w[0-9]+}}, {{w[0-9]+}}
int a = GetInt();
Sink(0);
return a + GetInt();
}

// A genuine int -> long widening must still sign extend with 'sxtw Xd, Wn'.
[MethodImpl(MethodImplOptions.NoInlining)]
static long Widen(int x)
{
//ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}}
return x;
}

[Fact]
public static int TestEntryPoint()
{
int result = 100;

s_value = 7;
if (IntMove() != 14)
{
result = -1;
}

// Negative values must round-trip correctly through the move.
s_value = -123456;
if (IntMove() != -246912)
{
result = -1;
}

s_value = int.MinValue;
// int.MinValue + int.MinValue overflows to 0 in unchecked int arithmetic.
if (IntMove() != 0)
{
result = -1;
}

// Genuine widening must preserve the sign.
if (Widen(-7) != -7L)
{
result = -1;
}
if (Widen(int.MinValue) != int.MinValue)
{
result = -1;
}

return result;
}
}
}
17 changes: 17 additions & 0 deletions src/tests/JIT/opt/InstructionCombining/IntMoveNoSignExtend.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Needed for CLRTestEnvironmentVariable -->
<RequiresProcessIsolation>true</RequiresProcessIsolation>
</PropertyGroup>
<PropertyGroup>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="IntMoveNoSignExtend.cs">
<HasDisasmCheck>true</HasDisasmCheck>
</Compile>
<CLRTestEnvironmentVariable Include="DOTNET_TieredCompilation" Value="0" />
<CLRTestEnvironmentVariable Include="DOTNET_JITMinOpts" Value="0" />
</ItemGroup>
</Project>
Loading