@@ -944,6 +944,14 @@ public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristi
944
944
return ComputeHomogeneousAggregateCharacteristic ( type ) ;
945
945
}
946
946
947
+ /// <summary>
948
+ /// Identify whether a given type is a homogeneous floating-point aggregate. This code must be
949
+ /// kept in sync with the CoreCLR runtime method EEClass::CheckForHFA, as of this change it
950
+ /// can be found at
951
+ /// https://github.com/dotnet/runtime/blob/1928cd2b65c04ebe6fe528d4ebb581e46f1fed47/src/coreclr/vm/class.cpp#L1567
952
+ /// </summary>
953
+ /// <param name="type">Type to analyze</param>
954
+ /// <returns>HFA classification of the type parameter</returns>
947
955
private static ValueTypeShapeCharacteristics ComputeHomogeneousAggregateCharacteristic ( DefType type )
948
956
{
949
957
// Use this constant to make the code below more laconic
@@ -959,12 +967,7 @@ private static ValueTypeShapeCharacteristics ComputeHomogeneousAggregateCharacte
959
967
return NotHA ;
960
968
961
969
MetadataType metadataType = ( MetadataType ) type ;
962
-
963
- // No HAs with explicit layout. There may be cases where explicit layout may be still
964
- // eligible for HA, but it is hard to tell the real intent. Make it simple and just
965
- // unconditionally disable HAs for explicit layout.
966
- if ( metadataType . IsExplicitLayout )
967
- return NotHA ;
970
+ int haElementSize = 0 ;
968
971
969
972
switch ( metadataType . Category )
970
973
{
@@ -977,12 +980,18 @@ private static ValueTypeShapeCharacteristics ComputeHomogeneousAggregateCharacte
977
980
case TypeFlags . ValueType :
978
981
// Find the common HA element type if any
979
982
ValueTypeShapeCharacteristics haResultType = NotHA ;
983
+ bool hasZeroOffsetField = false ;
980
984
981
985
foreach ( FieldDesc field in metadataType . GetFields ( ) )
982
986
{
983
987
if ( field . IsStatic )
984
988
continue ;
985
989
990
+ if ( field . Offset == LayoutInt . Zero )
991
+ {
992
+ hasZeroOffsetField = true ;
993
+ }
994
+
986
995
// If a field isn't a DefType, then this type cannot be a HA type
987
996
if ( ! ( field . FieldType is DefType fieldType ) )
988
997
return NotHA ;
@@ -996,6 +1005,15 @@ private static ValueTypeShapeCharacteristics ComputeHomogeneousAggregateCharacte
996
1005
{
997
1006
// If we hadn't yet figured out what form of HA this type might be, we've now found one case
998
1007
haResultType = haFieldType ;
1008
+
1009
+ haElementSize = haResultType switch
1010
+ {
1011
+ ValueTypeShapeCharacteristics . Float32Aggregate => 4 ,
1012
+ ValueTypeShapeCharacteristics . Float64Aggregate => 8 ,
1013
+ ValueTypeShapeCharacteristics . Vector64Aggregate => 8 ,
1014
+ ValueTypeShapeCharacteristics . Vector128Aggregate => 16 ,
1015
+ _ => throw new ArgumentOutOfRangeException ( )
1016
+ } ;
999
1017
}
1000
1018
else if ( haResultType != haFieldType )
1001
1019
{
@@ -1004,21 +1022,17 @@ private static ValueTypeShapeCharacteristics ComputeHomogeneousAggregateCharacte
1004
1022
// be a HA type.
1005
1023
return NotHA ;
1006
1024
}
1025
+
1026
+ if ( field . Offset . IsIndeterminate || field . Offset . AsInt % haElementSize != 0 )
1027
+ {
1028
+ return NotHA ;
1029
+ }
1007
1030
}
1008
1031
1009
- // If there are no instance fields, this is not a HA type
1010
- if ( haResultType == NotHA )
1032
+ // If the struct doesn't have a zero-offset field, it's not an HFA.
1033
+ if ( ! hasZeroOffsetField )
1011
1034
return NotHA ;
1012
1035
1013
- int haElementSize = haResultType switch
1014
- {
1015
- ValueTypeShapeCharacteristics . Float32Aggregate => 4 ,
1016
- ValueTypeShapeCharacteristics . Float64Aggregate => 8 ,
1017
- ValueTypeShapeCharacteristics . Vector64Aggregate => 8 ,
1018
- ValueTypeShapeCharacteristics . Vector128Aggregate => 16 ,
1019
- _ => throw new ArgumentOutOfRangeException ( )
1020
- } ;
1021
-
1022
1036
// Types which are indeterminate in field size are not considered to be HA
1023
1037
if ( type . InstanceFieldSize . IsIndeterminate )
1024
1038
return NotHA ;
@@ -1027,8 +1041,13 @@ private static ValueTypeShapeCharacteristics ComputeHomogeneousAggregateCharacte
1027
1041
// - Type of fields can be HA valuetype itself.
1028
1042
// - Managed C++ HA valuetypes have just one <alignment member> of type float to signal that
1029
1043
// the valuetype is HA and explicitly specified size.
1030
- int maxSize = haElementSize * type . Context . Target . MaxHomogeneousAggregateElementCount ;
1031
- if ( type . InstanceFieldSize . AsInt > maxSize )
1044
+ int totalSize = type . InstanceFieldSize . AsInt ;
1045
+
1046
+ if ( totalSize % haElementSize != 0 )
1047
+ return NotHA ;
1048
+
1049
+ // On ARM, HFAs can have a maximum of four fields regardless of whether those are float or double.
1050
+ if ( totalSize > haElementSize * type . Context . Target . MaxHomogeneousAggregateElementCount )
1032
1051
return NotHA ;
1033
1052
1034
1053
// All the tests passed. This is a HA type.
0 commit comments