summaryrefslogtreecommitdiff
path: root/src/jit/lowerxarch.cpp
diff options
context:
space:
mode:
authorTanner Gooding <tagoo@outlook.com>2019-01-07 16:57:34 -0800
committerGitHub <noreply@github.com>2019-01-07 16:57:34 -0800
commitccaf35e1e0dc6bbfb86e4fe6b8c24fe8fe346e55 (patch)
tree38b89a737ea572c515fce1fd910c368333eb96a2 /src/jit/lowerxarch.cpp
parentc2ac0f95ae6d453634dbe42159ad1f740cbe0958 (diff)
downloadcoreclr-ccaf35e1e0dc6bbfb86e4fe6b8c24fe8fe346e55.tar.gz
coreclr-ccaf35e1e0dc6bbfb86e4fe6b8c24fe8fe346e55.tar.bz2
coreclr-ccaf35e1e0dc6bbfb86e4fe6b8c24fe8fe346e55.zip
Fixing ContainCheckHWIntrinsic to ensure that scalar integer operands are the appropriate size (#21641)
* Fixing ContainCheckHWIntrinsic to ensure that scalar integer operands are the appropriate size * Adding a regression test for issue 21625 * Fixing IsContainableHWIntrinsicOp to use the containing node type (rather than the simd base type) for Scalar intrinsics * Fixing the containment check for `Sse41.Insert(V128<float>, V128<float>, byte)` * Cleaning up the isContainableHWIntrinsicOp logic in lowerxarch.cpp * Restrict containment to genActualType(baseType) * Formatting * Removing some comments and simplifying the supportsContainment checks for various HWIntrinsics that take a scalar operand * Applying formatting patch
Diffstat (limited to 'src/jit/lowerxarch.cpp')
-rw-r--r--src/jit/lowerxarch.cpp120
1 files changed, 94 insertions, 26 deletions
diff --git a/src/jit/lowerxarch.cpp b/src/jit/lowerxarch.cpp
index cee84033cc..7eb7edf899 100644
--- a/src/jit/lowerxarch.cpp
+++ b/src/jit/lowerxarch.cpp
@@ -2457,6 +2457,8 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge
{
case HW_Category_SimpleSIMD:
{
+ // These intrinsics only expect 16 or 32-byte nodes for containment
+ assert((genTypeSize(node->TypeGet()) == 16) || (genTypeSize(node->TypeGet()) == 32));
assert(supportsSIMDScalarLoads == false);
supportsAlignedSIMDLoads =
@@ -2502,6 +2504,8 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge
case NI_AVX2_ShuffleHigh:
case NI_AVX2_ShuffleLow:
{
+ // These intrinsics only expect 16 or 32-byte nodes for containment
+ assert((genTypeSize(node->TypeGet()) == 16) || (genTypeSize(node->TypeGet()) == 32));
assert(supportsSIMDScalarLoads == false);
supportsAlignedSIMDLoads = !comp->canUseVexEncoding();
@@ -2511,15 +2515,30 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge
break;
}
+ case NI_SSE2_Insert:
case NI_SSE41_Insert:
case NI_SSE41_X64_Insert:
{
if (containingNode->gtSIMDBaseType == TYP_FLOAT)
{
+ assert(containingIntrinsicId == NI_SSE41_Insert);
+ assert(genTypeSize(node->TypeGet()) == 16);
+
+ // Sse41.Insert(V128<float>, V128<float>, byte) is a bit special
+ // in that it has different behavior depending on whether the
+ // second operand is coming from a register or memory. When coming
+ // from a register, all 4 elements of the vector can be used and it
+ // is effectively a regular `SimpleSIMD` operation; but when loading
+ // from memory, it only works with the lowest element and is effectively
+ // a `SIMDScalar`.
+
+ assert(supportsAlignedSIMDLoads == false);
+ assert(supportsUnalignedSIMDLoads == false);
+ assert(supportsGeneralLoads == false);
assert(supportsSIMDScalarLoads == false);
GenTree* op1 = containingNode->gtGetOp1();
- GenTree* op2 = containingNode->gtGetOp2();
+ GenTree* op2 = nullptr;
GenTree* op3 = nullptr;
assert(op1->OperIsList());
@@ -2548,41 +2567,36 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge
ssize_t ival = op3->AsIntCon()->IconValue();
assert((ival >= 0) && (ival <= 255));
- if (ival <= 0x3F)
- {
- supportsAlignedSIMDLoads = !comp->canUseVexEncoding();
- supportsUnalignedSIMDLoads = !supportsAlignedSIMDLoads;
- supportsGeneralLoads = supportsUnalignedSIMDLoads;
-
- break;
- }
+ supportsSIMDScalarLoads = (ival <= 0x3F);
+ supportsGeneralLoads = supportsSIMDScalarLoads;
}
-
- assert(supportsAlignedSIMDLoads == false);
- assert(supportsUnalignedSIMDLoads == false);
- assert(supportsGeneralLoads == false);
+ break;
}
- else
- {
- assert(supportsAlignedSIMDLoads == false);
- assert(supportsUnalignedSIMDLoads == false);
- supportsSIMDScalarLoads = true;
- supportsGeneralLoads = supportsSIMDScalarLoads;
- }
+ // We should only get here for integral nodes.
+ assert(varTypeIsIntegral(node->TypeGet()));
+
+ assert(supportsAlignedSIMDLoads == false);
+ assert(supportsUnalignedSIMDLoads == false);
+ assert(supportsSIMDScalarLoads == false);
+ const unsigned expectedSize = genTypeSize(containingNode->gtSIMDBaseType);
+ const unsigned operandSize = genTypeSize(node->TypeGet());
+
+ supportsGeneralLoads = (operandSize >= expectedSize);
break;
}
- case NI_SSE2_Insert:
case NI_AVX_CompareScalar:
{
+ // These intrinsics only expect 16 or 32-byte nodes for containment
+ assert((genTypeSize(node->TypeGet()) == 16) || (genTypeSize(node->TypeGet()) == 32));
+
assert(supportsAlignedSIMDLoads == false);
assert(supportsUnalignedSIMDLoads == false);
supportsSIMDScalarLoads = true;
supportsGeneralLoads = supportsSIMDScalarLoads;
-
break;
}
@@ -2603,19 +2617,73 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge
assert(supportsAlignedSIMDLoads == false);
assert(supportsUnalignedSIMDLoads == false);
- supportsSIMDScalarLoads = true;
- supportsGeneralLoads = supportsSIMDScalarLoads;
+ switch (containingIntrinsicId)
+ {
+ case NI_Base_Vector128_CreateScalarUnsafe:
+ case NI_Base_Vector256_CreateScalarUnsafe:
+ {
+ assert(supportsSIMDScalarLoads == false);
+
+ const unsigned expectedSize = genTypeSize(genActualType(containingNode->gtSIMDBaseType));
+ const unsigned operandSize = genTypeSize(node->TypeGet());
+
+ supportsGeneralLoads = (operandSize == expectedSize);
+ break;
+ }
+
+ case NI_SSE_ConvertScalarToVector128Single:
+ case NI_SSE2_ConvertScalarToVector128Double:
+ case NI_SSE2_ConvertScalarToVector128Int32:
+ case NI_SSE2_ConvertScalarToVector128UInt32:
+ case NI_SSE_X64_ConvertScalarToVector128Single:
+ case NI_SSE2_X64_ConvertScalarToVector128Double:
+ case NI_SSE2_X64_ConvertScalarToVector128Int64:
+ case NI_SSE2_X64_ConvertScalarToVector128UInt64:
+ {
+ if (!varTypeIsIntegral(node->TypeGet()))
+ {
+ // The floating-point overload doesn't require any special semantics
+ assert(containingIntrinsicId == NI_SSE2_ConvertScalarToVector128Double);
+ supportsSIMDScalarLoads = true;
+ supportsGeneralLoads = supportsSIMDScalarLoads;
+ break;
+ }
+
+ assert(supportsSIMDScalarLoads == false);
+
+ const unsigned expectedSize = genTypeSize(genActualType(containingNode->gtSIMDBaseType));
+ const unsigned operandSize = genTypeSize(node->TypeGet());
+ supportsGeneralLoads = (operandSize == expectedSize);
+ break;
+ }
+
+ default:
+ {
+ // These intrinsics only expect 16 or 32-byte nodes for containment
+ assert((genTypeSize(node->TypeGet()) == 16) || (genTypeSize(node->TypeGet()) == 32));
+
+ supportsSIMDScalarLoads = true;
+ supportsGeneralLoads = supportsSIMDScalarLoads;
+ break;
+ }
+ }
break;
}
case HW_Category_Scalar:
{
+ // We should only get here for integral nodes.
+ assert(varTypeIsIntegral(node->TypeGet()));
+
assert(supportsAlignedSIMDLoads == false);
- assert(supportsSIMDScalarLoads == false);
assert(supportsUnalignedSIMDLoads == false);
+ assert(supportsSIMDScalarLoads == false);
+
+ const unsigned expectedSize = genTypeSize(containingNode->TypeGet());
+ const unsigned operandSize = genTypeSize(node->TypeGet());
- supportsGeneralLoads = true;
+ supportsGeneralLoads = (operandSize >= expectedSize);
break;
}