Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion src/coreclr/jit/hwintrinsicxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,7 @@ GenTree* Compiler::impNonConstFallback(NamedIntrinsic intrinsic, var_types simdT
GenTree* op2 = impPopStack().val;
GenTree* op1 = impSIMDPopStack();

GenTree* tmpOp = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, op2, CORINFO_TYPE_INT, 16);
GenTree* tmpOp = gtNewSimdCreateScalarNode(TYP_SIMD16, op2, CORINFO_TYPE_INT, 16);
return gtNewSimdHWIntrinsicNode(simdType, op1, tmpOp, intrinsic, simdBaseJitType, genTypeSize(simdType));
}

Expand Down
54 changes: 51 additions & 3 deletions src/coreclr/jit/simd.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,23 @@ void EvaluateUnarySimd(genTreeOps oper, bool scalar, var_types baseType, TSimd*
template <typename TBase>
TBase EvaluateBinaryScalarRSZ(TBase arg0, TBase arg1)
{
return arg0 >> (arg1 & ((sizeof(TBase) * 8) - 1));
#if defined(TARGET_XARCH)
if ((arg1 < 0) || (arg1 >= (sizeof(TBase) * 8)))
{
// For SIMD, xarch allows overshifting and treats
// it as zeroing. So ensure we do the same here.
//
// The xplat APIs ensure the shiftAmount is masked
// to be within range, so we can't hit this for them.

return static_cast<TBase>(0);
}
#else
// Other platforms enforce masking in their encoding
assert((arg1 >= 0) && (arg1 < (sizeof(TBase) * 8)));
#endif

return arg0 >> arg1;
}

template <>
Expand Down Expand Up @@ -513,7 +529,22 @@ TBase EvaluateBinaryScalarSpecialized(genTreeOps oper, TBase arg0, TBase arg1)

case GT_LSH:
{
return arg0 << (arg1 & ((sizeof(TBase) * 8) - 1));
#if defined(TARGET_XARCH)
if ((arg1 < 0) || (arg1 >= (sizeof(TBase) * 8)))
{
// For SIMD, xarch allows overshifting and treats
// it as zeroing. So ensure we do the same here.
//
// The xplat APIs ensure the shiftAmount is masked
// to be within range, so we can't hit this for them.

return static_cast<TBase>(0);
}
#else
// Other platforms enforce masking in their encoding
assert((arg1 >= 0) && (arg1 < (sizeof(TBase) * 8)));
#endif
return arg0 << arg1;
}

case GT_OR:
Expand All @@ -535,7 +566,24 @@ TBase EvaluateBinaryScalarSpecialized(genTreeOps oper, TBase arg0, TBase arg1)

case GT_RSH:
{
return arg0 >> (arg1 & ((sizeof(TBase) * 8) - 1));
#if defined(TARGET_XARCH)
if ((arg1 < 0) || (arg1 >= (sizeof(TBase) * 8)))
{
// For SIMD, xarch allows overshifting and treats
// it as propagating the sign bit (returning Zero
// or AllBitsSet). So ensure we do the same here.
//
// The xplat APIs ensure the shiftAmount is masked
// to be within range, so we can't hit this for them.

arg0 >>= ((sizeof(TBase) * 8) - 1);
arg1 = static_cast<TBase>(1);
}
#else
// Other platforms enforce masking in their encoding
assert((arg1 >= 0) && (arg1 < (sizeof(TBase) * 8)));
#endif
return arg0 >> arg1;
}

case GT_RSZ:
Expand Down
75 changes: 75 additions & 0 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7518,6 +7518,31 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary(var_types type,
case NI_AVX512BW_ShiftLeftLogical:
#endif
{
#ifdef TARGET_XARCH
if (TypeOfVN(arg1VN) == TYP_SIMD16)
{
// The xarch shift instructions support taking the shift amount as
// a simd16, in which case they take the shift amount from the lower
// 64-bits.

uint64_t shiftAmount = GetConstantSimd16(arg1VN).u64[0];

if (genTypeSize(baseType) != 8)
{
if (shiftAmount > INT_MAX)
{
// Ensure we don't lose track the the amount is an overshift
shiftAmount = -1;
}
arg1VN = VNForIntCon(static_cast<int32_t>(shiftAmount));
}
else
{
arg1VN = VNForLongCon(static_cast<int64_t>(shiftAmount));
}
}
#endif // TARGET_XARCH

return EvaluateBinarySimd(this, GT_LSH, /* scalar */ false, type, baseType, arg0VN, arg1VN);
}

Expand All @@ -7531,6 +7556,31 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary(var_types type,
case NI_AVX512BW_ShiftRightArithmetic:
#endif
{
#ifdef TARGET_XARCH
if (TypeOfVN(arg1VN) == TYP_SIMD16)
{
// The xarch shift instructions support taking the shift amount as
// a simd16, in which case they take the shift amount from the lower
// 64-bits.

uint64_t shiftAmount = GetConstantSimd16(arg1VN).u64[0];

if (genTypeSize(baseType) != 8)
{
if (shiftAmount > INT_MAX)
{
// Ensure we don't lose track the the amount is an overshift
shiftAmount = -1;
}
arg1VN = VNForIntCon(static_cast<int32_t>(shiftAmount));
}
else
{
arg1VN = VNForLongCon(static_cast<int64_t>(shiftAmount));
}
}
#endif // TARGET_XARCH

return EvaluateBinarySimd(this, GT_RSH, /* scalar */ false, type, baseType, arg0VN, arg1VN);
}

Expand All @@ -7543,6 +7593,31 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary(var_types type,
case NI_AVX512BW_ShiftRightLogical:
#endif
{
#ifdef TARGET_XARCH
if (TypeOfVN(arg1VN) == TYP_SIMD16)
{
// The xarch shift instructions support taking the shift amount as
// a simd16, in which case they take the shift amount from the lower
// 64-bits.

uint64_t shiftAmount = GetConstantSimd16(arg1VN).u64[0];

if (genTypeSize(baseType) != 8)
{
if (shiftAmount > INT_MAX)
{
// Ensure we don't lose track the the amount is an overshift
shiftAmount = -1;
}
arg1VN = VNForIntCon(static_cast<int32_t>(shiftAmount));
}
else
{
arg1VN = VNForLongCon(static_cast<int64_t>(shiftAmount));
}
}
#endif // TARGET_XARCH

return EvaluateBinarySimd(this, GT_RSZ, /* scalar */ false, type, baseType, arg0VN, arg1VN);
}

Expand Down
49 changes: 49 additions & 0 deletions src/tests/JIT/Regression/JitBlue/Runtime_93698/Runtime_93698.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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.Intrinsics;
using System.Runtime.Intrinsics.X86;
using Xunit;

public static class Runtime_93698
{
[Fact]
public static void TestShiftLeftLogicalOvershift()
{
if (Sse2.IsSupported)
{
var result1 = Sse2.ShiftLeftLogical(Vector128.Create(-1, +2, -3, +4), 32);
Assert.Equal(Vector128<int>.Zero, result1);

var result2 = Sse2.ShiftLeftLogical(Vector128.Create(-5, +6, -7, +8), Vector128.Create(0, 32, 0, 0));
Assert.Equal(Vector128<int>.Zero, result2);
}
}

[Fact]
public static void TestShiftRightLogicalOvershift()
{
if (Sse2.IsSupported)
{
var result1 = Sse2.ShiftRightLogical(Vector128.Create(-1, +2, -3, +4), 32);
Assert.Equal(Vector128<int>.Zero, result1);

var result2 = Sse2.ShiftRightLogical(Vector128.Create(-5, +6, -7, +8), Vector128.Create(0, 32, 0, 0));
Assert.Equal(Vector128<int>.Zero, result2);
}
}

[Fact]
public static void TestShiftRightArithmeticOvershift()
{
if (Sse2.IsSupported)
{
var result1 = Sse2.ShiftRightArithmetic(Vector128.Create(-1, +2, -3, +4), 32);
Assert.Equal(Vector128.Create(-1, 0, -1, 0), result1);

var result2 = Sse2.ShiftRightArithmetic(Vector128.Create(-5, +6, -7, +8), Vector128.Create(0, 32, 0, 0));
Assert.Equal(Vector128.Create(-1, 0, -1, 0), result2);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
</Project>