diff options
author | Tanner Gooding <tagoo@outlook.com> | 2019-01-07 16:57:34 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-07 16:57:34 -0800 |
commit | ccaf35e1e0dc6bbfb86e4fe6b8c24fe8fe346e55 (patch) | |
tree | 38b89a737ea572c515fce1fd910c368333eb96a2 /src/jit/lowerxarch.cpp | |
parent | c2ac0f95ae6d453634dbe42159ad1f740cbe0958 (diff) | |
download | coreclr-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.cpp | 120 |
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; } |