diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 071d5337897da3..acbf063ada8c5b 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2671,6 +2671,39 @@ private uint getClassNumInstanceFields(CORINFO_CLASS_STRUCT_* cls) throw new InvalidOperationException(); } + //------------------------------------------------------------------------ + // IsSimdIntrinsicType: Check whether a type is one of the SIMD types that the + // JIT considers to be a primitive. + // + // Arguments: + // type - The type to check. + // + // Return Value: + // True if the type is a SIMD type; otherwise false. + // + // Remarks: + // This is an explicit allow list mirroring the types recognized by + // Compiler::getBaseTypeAndSizeOfSIMDType. The other intrinsic types in these + // namespaces (Decimal32/Decimal64/Decimal128, Matrix3x2/Matrix4x4) are laid + // out like any other struct, so the JIT needs their fields reported. + // + private static bool IsSimdIntrinsicType(MetadataType type) + { + if (VectorFieldLayoutAlgorithm.IsVectorType(type) || VectorOfTFieldLayoutAlgorithm.IsVectorOfTType(type)) + { + return true; + } + + if (!type.IsIntrinsic || type.Namespace != "System.Numerics"u8) + { + return false; + } + + Utf8Span name = type.Name; + return name == "Vector2"u8 || name == "Vector3"u8 || name == "Vector4"u8 || + name == "Quaternion"u8 || name == "Plane"u8; + } + private GetTypeLayoutResult GetTypeLayoutHelper(MetadataType type, uint parentIndex, uint baseOffs, FieldDesc field, CORINFO_TYPE_LAYOUT_NODE* treeNodes, nuint maxTreeNodes, nuint* numTreeNodes) { if (*numTreeNodes >= maxTreeNodes) @@ -2711,37 +2744,31 @@ private GetTypeLayoutResult GetTypeLayoutHelper(MetadataType type, uint parentIn #endif // The intrinsic SIMD/HW SIMD types have a lot of fields that the JIT does - // not care about since they are considered primitives by the JIT. The IEEE 754 - // decimal floating-point types are the System.Numerics intrinsics that are not - // SIMD, so the JIT lays them out like any other struct and needs their fields. - if (type.IsIntrinsic && !type.IsDecimalFloatingPointOrHasDecimalFloatingPointFields) + // not care about since they are considered primitives by the JIT. + if (IsSimdIntrinsicType(type)) { - Utf8Span ns = type.Namespace; - if (ns == "System.Runtime.Intrinsics"u8 || ns == "System.Numerics"u8) + parNode->simdTypeHnd = ObjectToHandle(type); + if (parentIndex != uint.MaxValue) { - parNode->simdTypeHnd = ObjectToHandle(type); - if (parentIndex != uint.MaxValue) - { #if READYTORUN - if (NeedsTypeLayoutCheck(type)) - { - // We cannot allow the JIT to call getClassSize for - // arbitrary types of fields as it will insert a fixup - // that we may not be able to encode. We could skip the - // field, but that will make prejit promotion different - // from the runtime promotion. We could also change the - // JIT to avoid calling getClassSize and just use the - // size from the returned node, but for that we would - // need to be sure that the type layout check fixup - // added in getTypeLayout is sufficient to guarantee - // the size of all these intrinsically handled SIMD - // types. - return GetTypeLayoutResult.Failure; - } + if (NeedsTypeLayoutCheck(type)) + { + // We cannot allow the JIT to call getClassSize for + // arbitrary types of fields as it will insert a fixup + // that we may not be able to encode. We could skip the + // field, but that will make prejit promotion different + // from the runtime promotion. We could also change the + // JIT to avoid calling getClassSize and just use the + // size from the returned node, but for that we would + // need to be sure that the type layout check fixup + // added in getTypeLayout is sufficient to guarantee + // the size of all these intrinsically handled SIMD + // types. + return GetTypeLayoutResult.Failure; + } #endif - return GetTypeLayoutResult.Success; - } + return GetTypeLayoutResult.Success; } } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index deb4470546740f..c8ffc31b0d3583 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1993,6 +1993,62 @@ CEEInfo::getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num) return result; } +//------------------------------------------------------------------------ +// IsSimdIntrinsicType: Check whether a type is one of the SIMD types that the +// JIT considers to be a primitive. +// +// Arguments: +// pMT - The type to check. +// +// Return Value: +// True if the type is a SIMD type; otherwise false. +// +// Remarks: +// This is an explicit allow list mirroring the types recognized by +// Compiler::getBaseTypeAndSizeOfSIMDType. The other intrinsic types in these +// namespaces (Decimal32/Decimal64/Decimal128, Matrix3x2/Matrix4x4) are laid +// out like any other struct, so the JIT needs their fields reported. +// +static bool IsSimdIntrinsicType(MethodTable* pMT) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + FORBID_FAULT; + } + CONTRACTL_END; + + if (!pMT->IsIntrinsicType()) + { + return false; + } + + LPCUTF8 nsName; + LPCUTF8 className = pMT->GetFullyQualifiedNameInfo(&nsName); + + // GetFullyQualifiedNameInfo returns NULL on failure and can legitimately report a NULL namespace. + if ((className == NULL) || (nsName == NULL)) + { + return false; + } + + if (strcmp(nsName, "System.Runtime.Intrinsics") == 0) + { + return (strcmp(className, "Vector128`1") == 0) || (strcmp(className, "Vector64`1") == 0) || + (strcmp(className, "Vector256`1") == 0) || (strcmp(className, "Vector512`1") == 0); + } + + if (strcmp(nsName, "System.Numerics") == 0) + { + return (strcmp(className, "Vector`1") == 0) || (strcmp(className, "Vector2") == 0) || + (strcmp(className, "Vector3") == 0) || (strcmp(className, "Vector4") == 0) || + (strcmp(className, "Quaternion") == 0) || (strcmp(className, "Plane") == 0); + } + + return false; +} + static GetTypeLayoutResult GetTypeLayoutHelper( MethodTable* pMT, unsigned parentIndex, @@ -2023,22 +2079,13 @@ static GetTypeLayoutResult GetTypeLayoutHelper( parNode.hasSignificantPadding = pClass->HasExplicitFieldOffsetLayout() || pClass->HasExplicitSize(); // The intrinsic SIMD/HW SIMD types have a lot of fields that the JIT does - // not care about since they are considered primitives by the JIT. The IEEE 754 - // decimal floating-point types are the System.Numerics intrinsics that are not - // SIMD, so the JIT lays them out like any other struct and needs their fields. - if (pMT->IsIntrinsicType() && !pMT->IsDecimalFloatingPointOrHasDecimalFloatingPointFields()) + // not care about since they are considered primitives by the JIT. + if (IsSimdIntrinsicType(pMT)) { - const char* nsName; - pMT->GetFullyQualifiedNameInfo(&nsName); - - if ((strcmp(nsName, "System.Runtime.Intrinsics") == 0) || - (strcmp(nsName, "System.Numerics") == 0)) + parNode.simdTypeHnd = CORINFO_CLASS_HANDLE(pMT); + if (parentIndex != UINT32_MAX) { - parNode.simdTypeHnd = CORINFO_CLASS_HANDLE(pMT); - if (parentIndex != UINT32_MAX) - { - return GetTypeLayoutResult::Success; - } + return GetTypeLayoutResult::Success; } }