From ab4f699cef72204b96919447a3c5ca7034fcf567 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sun, 21 Jan 2018 19:35:47 -0800 Subject: Updating the VM to properly pack the SIMD hardware intrinsic types. --- src/vm/classnames.h | 9 ++++ src/vm/fieldmarshaler.cpp | 12 +++-- src/vm/fieldmarshaler.h | 2 +- src/vm/methodtablebuilder.cpp | 118 ++++++++++++++++++++++++++++++++++-------- src/vm/namespace.h | 2 + 5 files changed, 117 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/vm/classnames.h b/src/vm/classnames.h index 6af229e546..08286f8013 100644 --- a/src/vm/classnames.h +++ b/src/vm/classnames.h @@ -72,6 +72,15 @@ #define g_DecimalClassName "System.Decimal" #define g_DecimalName "Decimal" +#define g_Vector64ClassName "System.Runtime.Intrinsics.Vector64`1" +#define g_Vector64Name "Vector64`1" + +#define g_Vector128ClassName "System.Runtime.Intrinsics.Vector128`1" +#define g_Vector128Name "Vector128`1" + +#define g_Vector256ClassName "System.Runtime.Intrinsics.Vector256`1" +#define g_Vector256Name "Vector256`1" + #ifdef FEATURE_COMINTEROP #define g_WindowsFoundationActivatableAttributeClassName "Windows.Foundation.Metadata.ActivatableAttribute" diff --git a/src/vm/fieldmarshaler.cpp b/src/vm/fieldmarshaler.cpp index 0685093483..b1a4a8b9b5 100644 --- a/src/vm/fieldmarshaler.cpp +++ b/src/vm/fieldmarshaler.cpp @@ -1669,7 +1669,9 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( if (!(alignmentRequirement == 1 || alignmentRequirement == 2 || alignmentRequirement == 4 || - alignmentRequirement == 8)) + alignmentRequirement == 8 || + alignmentRequirement == 16 || + alignmentRequirement == 32)) { COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT); } @@ -1680,7 +1682,7 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( // This assert means I forgot to special-case some NFT in the // above switch. - _ASSERTE(alignmentRequirement <= 8); + _ASSERTE(alignmentRequirement <= 32); // Check if this field is overlapped with other(s) pfwalk->m_fIsOverlapped = FALSE; @@ -1806,7 +1808,9 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( if (!(alignmentRequirement == 1 || alignmentRequirement == 2 || alignmentRequirement == 4 || - alignmentRequirement == 8)) + alignmentRequirement == 8 || + alignmentRequirement == 16 || + alignmentRequirement == 32)) { COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT); } @@ -1815,7 +1819,7 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement); - _ASSERTE(alignmentRequirement <= 8); + _ASSERTE(alignmentRequirement <= 32); // Insert enough padding to align the current data member. while (cbCurOffset % alignmentRequirement) diff --git a/src/vm/fieldmarshaler.h b/src/vm/fieldmarshaler.h index 2d11068f15..8c1f8fe1ac 100644 --- a/src/vm/fieldmarshaler.h +++ b/src/vm/fieldmarshaler.h @@ -88,7 +88,7 @@ enum NStructFieldType // Currently we set this to the packing size of the largest supported // fundamental type and let the field marshaller downsize where needed. //======================================================================= -#define DEFAULT_PACKING_SIZE 8 +#define DEFAULT_PACKING_SIZE 32 //======================================================================= diff --git a/src/vm/methodtablebuilder.cpp b/src/vm/methodtablebuilder.cpp index f48e2a7b71..f309fbc40f 100644 --- a/src/vm/methodtablebuilder.cpp +++ b/src/vm/methodtablebuilder.cpp @@ -9535,42 +9535,118 @@ void MethodTableBuilder::CheckForSystemTypes() { STANDARD_VM_CONTRACT; + LPCUTF8 name, nameSpace; + MethodTable * pMT = GetHalfBakedMethodTable(); EEClass * pClass = GetHalfBakedClass(); // We can exit early for generic types - there are just a few cases to check for. - if (bmtGenerics->HasInstantiation() && g_pNullableClass != NULL) + if (bmtGenerics->HasInstantiation()) { - _ASSERTE(g_pByReferenceClass != NULL); - _ASSERTE(g_pByReferenceClass->IsByRefLike()); - -#ifdef _TARGET_X86_ - if (GetCl() == g_pByReferenceClass->GetCl()) + if (pClass->HasLayout()) { - // x86 by default treats the type of ByReference as the actual type of its IntPtr field, see calls to - // ComputeInternalCorElementTypeForValueType in this file. This is a special case where the struct needs to be - // treated as a value type so that its field can be considered as a by-ref pointer. - _ASSERTE(pMT->GetFlag(MethodTable::enum_flag_Category_Mask) == MethodTable::enum_flag_Category_PrimitiveValueType); - pMT->ClearFlag(MethodTable::enum_flag_Category_Mask); - pMT->SetInternalCorElementType(ELEMENT_TYPE_VALUETYPE); - return; + if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace))) + { + BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT); + } + + if (strcmp(nameSpace, g_IntrinsicsNS) == 0) + { + EEClassLayoutInfo * pLayout = pClass->GetLayoutInfo(); + + // The SIMD Hardware Intrinsic types correspond to fundamental data types in the underlying ABIs: + // * Vector64: __m64 + // * Vector128: __m128 + // * Vector256: __m256 + + // These __m128 and __m256 types, among other requirements, are special in that they must always + // be aligned properly. + + if (strcmp(name, g_Vector64Name) == 0) + { + // The System V ABI for i386 defaults to 8-byte alignment for __m64, except for parameter passing, + // where it has an alignment of 4. + + pLayout->m_LargestAlignmentRequirementOfAllMembers = 8; // sizeof(__m64) + pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8; // sizeof(__m64) + } + else if (strcmp(name, g_Vector128Name) == 0) + { + #ifdef _TARGET_ARM_ + // The Procedure Call Standard for ARM defaults to 8-byte alignment for __m128 + + pLayout->m_LargestAlignmentRequirementOfAllMembers = 8; + pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8; + #else + pLayout->m_LargestAlignmentRequirementOfAllMembers = 16; // sizeof(__m128) + pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; // sizeof(__m128) + #endif // _TARGET_ARM_ + } + else if (strcmp(name, g_Vector256Name) == 0) + { + #ifdef _TARGET_ARM_ + // No such type exists for the Procedure Call Standard for ARM. We will default + // to the same alignment as __m128, which is supported by the ABI. + + pLayout->m_LargestAlignmentRequirementOfAllMembers = 8; + pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8; + #elif defined(_TARGET_ARM64_) + // The Procedure Call Standard for ARM 64-bit (with SVE support) defaults to + // 16-byte alignment for __m256. + + pLayout->m_LargestAlignmentRequirementOfAllMembers = 16; + pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; + #else + pLayout->m_LargestAlignmentRequirementOfAllMembers = 32; // sizeof(__m256) + pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 32; // sizeof(__m256) + #endif // _TARGET_ARM_ elif _TARGET_ARM64_ + } + else + { + // These types should be handled or explicitly skipped below to ensure that we don't + // miss adding required ABI support for future types. + + _ASSERTE_MSG((strcmp(name, "Vector64DebugView`1") == 0) || + (strcmp(name, "Vector128DebugView`1") == 0) || + (strcmp(name, "Vector256DebugView`1") == 0), + "Unhandled Hardware Intrinsic Type."); + } + + return; + } } + + if (g_pNullableClass != NULL) + { + _ASSERTE(g_pByReferenceClass != NULL); + _ASSERTE(g_pByReferenceClass->IsByRefLike()); + +#ifdef _TARGET_X86_ + if (GetCl() == g_pByReferenceClass->GetCl()) + { + // x86 by default treats the type of ByReference as the actual type of its IntPtr field, see calls to + // ComputeInternalCorElementTypeForValueType in this file. This is a special case where the struct needs to be + // treated as a value type so that its field can be considered as a by-ref pointer. + _ASSERTE(pMT->GetFlag(MethodTable::enum_flag_Category_Mask) == MethodTable::enum_flag_Category_PrimitiveValueType); + pMT->ClearFlag(MethodTable::enum_flag_Category_Mask); + pMT->SetInternalCorElementType(ELEMENT_TYPE_VALUETYPE); + return; + } #endif - _ASSERTE(g_pNullableClass->IsNullable()); + _ASSERTE(g_pNullableClass->IsNullable()); - // Pre-compute whether the class is a Nullable so that code:Nullable::IsNullableType is efficient - // This is useful to the performance of boxing/unboxing a Nullable - if (GetCl() == g_pNullableClass->GetCl()) - pMT->SetIsNullable(); + // Pre-compute whether the class is a Nullable so that code:Nullable::IsNullableType is efficient + // This is useful to the performance of boxing/unboxing a Nullable + if (GetCl() == g_pNullableClass->GetCl()) + pMT->SetIsNullable(); - return; + return; + } } if (IsNested() || IsEnum()) return; - - LPCUTF8 name, nameSpace; if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace))) { diff --git a/src/vm/namespace.h b/src/vm/namespace.h index fbcdfd630a..4395071559 100644 --- a/src/vm/namespace.h +++ b/src/vm/namespace.h @@ -33,6 +33,8 @@ #define g_WinRTNS g_InteropNS ".WindowsRuntime" #endif // FEATURE_COMINTEROP +#define g_IntrinsicsNS g_RuntimeNS ".Intrinsics" + #define g_InternalCompilerServicesNS "Internal.Runtime.CompilerServices" #define g_CompilerServicesNS g_RuntimeNS ".CompilerServices" -- cgit v1.2.3