Support ARM64 HVAs in Crossgen2 (#35576)
authorAnton Lapounov <antonl@microsoft.com>
Sat, 2 May 2020 02:55:58 +0000 (19:55 -0700)
committerGitHub <noreply@github.com>
Sat, 2 May 2020 02:55:58 +0000 (19:55 -0700)
•  Change FieldLayoutAlgorithm.ComputeValueTypeShapeCharacteristics method to compute the homogeneous aggregate element type and cache it in the existing field. That allows to remove all ComputeHomogeneousFloatAggregateElementType methods.
•  Change MetadataFieldLayoutAlgorithm.ComputeHomogeneousAggregateCharacteristic to compute HVAs in addition to HFAs.
•  Change CorInfoImpl.getHFAType JIT callback to handle HVAs. Note that returning ELEMENT_TYPE_VALUETYPE indicates the TYP_SIMD16 type (see Compiler::GetHfaType).
•  Change TypeFixupSignature.EncodeTypeLayout to handle HVAs.
•  Support HVAs in the ArgIterator class.
•  Fix TransitionBlock.OffsetFromGCRefMapPos for ARM64. R2RDump used to dump incorrect offsets.
•  Use TransitionBlock.OffsetFromGCRefMapPos in GCRefMapBuilder.GetCallRefMap to simplify logic.
•  Remove ARM64 .NET Native-specific code from TransitionBlock.cs and ArgIterator.cs files.

Minor:
•  Remove a redundant GetVectorSize check in MethodTable::GetHFAType.
•  Improve an assertion in Compiler::raUpdateRegStateForArg.
•  Fix comments in JIT code.

18 files changed:
src/coreclr/src/jit/lclvars.cpp
src/coreclr/src/jit/regalloc.cpp
src/coreclr/src/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs
src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs
src/coreclr/src/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs
src/coreclr/src/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs
src/coreclr/src/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
src/coreclr/src/tools/Common/TypeSystem/Common/TargetDetails.cs
src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs
src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs
src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs
src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs
src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs
src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs
src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/SystemObjectFieldLayoutAlgorithm.cs
src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/TransitionBlock.cs
src/coreclr/src/vm/callingconvention.h
src/coreclr/src/vm/class.cpp

index f65a062..68490d0 100644 (file)
@@ -625,7 +625,7 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo)
             // If the argType is a struct, then check if it is an HFA
             if (varTypeIsStruct(argType))
             {
-                // hfaType is set to float, double or SIMD type if it is an HFA, otherwise TYP_UNDEF.
+                // hfaType is set to float, double, or SIMD type if it is an HFA, otherwise TYP_UNDEF
                 hfaType  = GetHfaType(typeHnd);
                 isHfaArg = varTypeIsValidHfaType(hfaType);
             }
@@ -644,9 +644,9 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo)
 
         if (isHfaArg)
         {
-            // We have an HFA argument, so from here on out treat the type as a float, double or vector.
-            // The orginal struct type is available by using origArgType
-            // We also update the cSlots to be the number of float/double fields in the HFA
+            // We have an HFA argument, so from here on out treat the type as a float, double, or vector.
+            // The orginal struct type is available by using origArgType.
+            // We also update the cSlots to be the number of float/double/vector fields in the HFA.
             argType = hfaType;
             varDsc->SetHfaType(hfaType);
             cSlots = varDsc->lvHfaSlots();
@@ -2615,10 +2615,11 @@ void Compiler::lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool
             }
 #endif // FEATURE_SIMD
 #ifdef FEATURE_HFA
-            // for structs that are small enough, we check and set lvIsHfa and lvHfaTypeIsFloat
+            // For structs that are small enough, we check and set HFA element type
             if (varDsc->lvExactSize <= MAX_PASS_MULTIREG_BYTES)
             {
-                var_types hfaType = GetHfaType(typeHnd); // set to float or double if it is an HFA, otherwise TYP_UNDEF
+                // hfaType is set to float, double or SIMD type if it is an HFA, otherwise TYP_UNDEF
+                var_types hfaType = GetHfaType(typeHnd);
                 if (varTypeIsValidHfaType(hfaType))
                 {
                     varDsc->SetHfaType(hfaType);
index 73c2816..367eb81 100644 (file)
@@ -175,6 +175,7 @@ regNumber Compiler::raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc
         }
         else
         {
+            assert(!regState->rsIsFloat);
             unsigned cSlots = argDsc->lvSize() / TARGET_POINTER_SIZE;
             for (unsigned i = 1; i < cSlots; i++)
             {
@@ -183,7 +184,6 @@ regNumber Compiler::raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc
                 {
                     break;
                 }
-                assert(regState->rsIsFloat == false);
                 regState->rsCalleeRegArgMaskLiveIn |= genRegMask(nextArgReg);
             }
         }
index 981eef3..5d3697c 100644 (file)
@@ -90,12 +90,17 @@ namespace ILCompiler
 
         public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type)
         {
-            return _fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type);
-        }
-
-        public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type)
-        {
-            return _fallbackAlgorithm.ComputeHomogeneousFloatAggregateElementType(type);
+            if (type.Context.Target.Architecture == TargetArchitecture.ARM64)
+            {
+                return type.InstanceFieldSize.AsInt switch
+                {
+                    8 => ValueTypeShapeCharacteristics.Vector64Aggregate,
+                    16 => ValueTypeShapeCharacteristics.Vector128Aggregate,
+                    32 => ValueTypeShapeCharacteristics.Vector256Aggregate,
+                    _ => ValueTypeShapeCharacteristics.None
+                };
+            }
+            return ValueTypeShapeCharacteristics.None;
         }
 
         public static bool IsVectorType(DefType type)
@@ -104,7 +109,8 @@ namespace ILCompiler
                 type.Namespace == "System.Runtime.Intrinsics" &&
                 (type.Name == "Vector64`1" ||
                 type.Name == "Vector128`1" ||
-                type.Name == "Vector256`1");
+                type.Name == "Vector256`1") &&
+                type.Instantiation[0].IsPrimitive;
         }
     }
 }
index 0e80e6c..aeef11e 100644 (file)
@@ -59,10 +59,10 @@ namespace Internal.JitInterface
 
         private ExceptionDispatchInfo _lastException;
 
-        [DllImport(JitLibrary, CallingConvention=CallingConvention.StdCall)] // stdcall in CoreCLR!
+        [DllImport(JitLibrary, CallingConvention = CallingConvention.StdCall)] // stdcall in CoreCLR!
         private extern static IntPtr jitStartup(IntPtr host);
 
-        [DllImport(JitLibrary, CallingConvention=CallingConvention.StdCall)]
+        [DllImport(JitLibrary, CallingConvention = CallingConvention.StdCall)]
         private extern static IntPtr getJit();
 
         [DllImport(JitSupportLibrary)]
@@ -1689,7 +1689,7 @@ namespace Internal.JitInterface
                 // This optimization may cause static fields in reference types to be accessed without cctor being triggered
                 // for NULL "this" object. It does not conform with what the spec says. However, we have been historically
                 // doing it for perf reasons.
-                if (!typeToInit.IsValueType && ! typeToInit.IsInterface && !typeToInit.IsBeforeFieldInit)
+                if (!typeToInit.IsValueType && !typeToInit.IsInterface && !typeToInit.IsBeforeFieldInit)
                 {
                     if (typeToInit == typeFromContext(context) || typeToInit == MethodBeingCompiled.OwningType)
                     {
@@ -2013,7 +2013,7 @@ namespace Internal.JitInterface
         {
             var td = HandleToObject(cls) as ArrayType;
             Debug.Assert(td != null);
-            return (uint) td.Rank;
+            return (uint)td.Rank;
         }
 
         private void* getArrayInitializationData(CORINFO_FIELD_STRUCT_* field, uint size)
@@ -2203,7 +2203,19 @@ namespace Internal.JitInterface
         private CorInfoType getHFAType(CORINFO_CLASS_STRUCT_* hClass)
         {
             var type = (DefType)HandleToObject(hClass);
-            return type.IsHfa ? asCorInfoType(type.HfaElementType) : CorInfoType.CORINFO_TYPE_UNDEF;
+
+            // For 8-byte vectors return CORINFO_TYPE_DOUBLE, which is mapped by JIT to SIMD8.
+            // Otherwise, return CORINFO_TYPE_VALUECLASS, which is mapped by JIT to SIMD16.
+            // See MethodTable::GetHFAType and Compiler::GetHfaType.
+            return (type.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) switch
+            {
+                ValueTypeShapeCharacteristics.Float32Aggregate => CorInfoType.CORINFO_TYPE_FLOAT,
+                ValueTypeShapeCharacteristics.Float64Aggregate => CorInfoType.CORINFO_TYPE_DOUBLE,
+                ValueTypeShapeCharacteristics.Vector64Aggregate => CorInfoType.CORINFO_TYPE_DOUBLE,
+                ValueTypeShapeCharacteristics.Vector128Aggregate => CorInfoType.CORINFO_TYPE_VALUECLASS,
+                ValueTypeShapeCharacteristics.Vector256Aggregate => CorInfoType.CORINFO_TYPE_VALUECLASS,
+                _ => CorInfoType.CORINFO_TYPE_UNDEF
+            };
         }
 
         private HRESULT GetErrorHRESULT(_EXCEPTION_POINTERS* pExceptionPointers)
index e1b1bee..22b03fb 100644 (file)
@@ -281,10 +281,7 @@ namespace Internal.TypeSystem
             }
         }
 
-        /// <summary>
-        /// Gets a value indicating whether the fields of the type satisfy the Homogeneous Float Aggregate classification.
-        /// </summary>
-        public bool IsHfa
+        public ValueTypeShapeCharacteristics ValueTypeShapeCharacteristics
         {
             get
             {
@@ -292,41 +289,43 @@ namespace Internal.TypeSystem
                 {
                     ComputeValueTypeShapeCharacteristics();
                 }
-                return (_valueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.HomogenousFloatAggregate) != 0;
+                return _valueTypeShapeCharacteristics;
             }
         }
 
-        internal ValueTypeShapeCharacteristics ValueTypeShapeCharacteristics
+        private void ComputeValueTypeShapeCharacteristics()
         {
-            get
-            {
-                if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics))
-                {
-                    ComputeValueTypeShapeCharacteristics();
-                }
-                return _valueTypeShapeCharacteristics;
-            }
+            _valueTypeShapeCharacteristics = this.Context.GetLayoutAlgorithmForType(this).ComputeValueTypeShapeCharacteristics(this);
+            _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics);
         }
 
         /// <summary>
-        /// Get the Homogeneous Float Aggregate element type if this is a HFA type (<see cref="IsHfa"/> is true).
+        /// Gets a value indicating whether the type is a homogeneous floating-point or short-vector aggregate.
         /// </summary>
-        public DefType HfaElementType
+        public bool IsHomogeneousAggregate
         {
             get
             {
-                // We are not caching this because this is rare and not worth wasting space in DefType.
-                return this.Context.GetLayoutAlgorithmForType(this).ComputeHomogeneousFloatAggregateElementType(this);
+                return (ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) != 0;
             }
         }
 
-        private void ComputeValueTypeShapeCharacteristics()
+        /// <summary>
+        /// If the type is a homogeneous floating-point or short-vector aggregate, returns its element size.
+        /// </summary>
+        public int GetHomogeneousAggregateElementSize()
         {
-            _valueTypeShapeCharacteristics = this.Context.GetLayoutAlgorithmForType(this).ComputeValueTypeShapeCharacteristics(this);
-            _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics);
+            return (ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) switch
+            {
+                ValueTypeShapeCharacteristics.Float32Aggregate => 4,
+                ValueTypeShapeCharacteristics.Float64Aggregate => 8,
+                ValueTypeShapeCharacteristics.Vector64Aggregate => 8,
+                ValueTypeShapeCharacteristics.Vector128Aggregate => 16,
+                ValueTypeShapeCharacteristics.Vector256Aggregate => 16,
+                _ => throw new InvalidOperationException()
+            };
         }
 
-
         public void ComputeInstanceLayout(InstanceLayoutKind layoutKind)
         {
             if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeFieldsLayout | FieldLayoutFlags.ComputedInstanceTypeLayout))
index 720c80a..7cda8ce 100644 (file)
@@ -33,16 +33,10 @@ namespace Internal.TypeSystem
         public abstract bool ComputeContainsGCPointers(DefType type);
 
         /// <summary>
-        /// Compute the shape of a valuetype. The shape information is used to control code generation and allocation
-        /// (such as vectorization, passing the valuetype by value across method calls, or boxing alignment).
+        /// Compute the shape of a value type. The shape information is used to control code generation and allocation
+        /// (such as vectorization, passing the value type by value across method calls, or boxing alignment).
         /// </summary>
         public abstract ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type);
-
-        /// <summary>
-        /// If the type has <see cref="ValueTypeShapeCharacteristics.HomogenousFloatAggregate"/> characteristic, returns
-        /// the element type of the homogenous float aggregate. This will either be System.Double or System.Float.
-        /// </summary>
-        public abstract DefType ComputeHomogeneousFloatAggregateElementType(DefType type);
     }
 
     /// <summary>
@@ -119,8 +113,43 @@ namespace Internal.TypeSystem
         None = 0x00,
 
         /// <summary>
-        /// The structure is an aggregate of floating point values of the same type.
+        /// The type is an aggregate of 32-bit floating-point values.
+        /// </summary>
+        Float32Aggregate = 0x01,
+
+        /// <summary>
+        /// The type is an aggregate of 64-bit floating-point values.
+        /// </summary>
+        Float64Aggregate = 0x02,
+
+        /// <summary>
+        /// The type is an aggregate of 64-bit short-vector values.
+        /// </summary>
+        Vector64Aggregate = 0x04,
+
+        /// <summary>
+        /// The type is an aggregate of 128-bit short-vector values.
+        /// </summary>
+        Vector128Aggregate = 0x08,
+
+        /// <summary>
+        /// The type is an aggregate of 256-bit short-vector values.
+        /// </summary>
+        Vector256Aggregate = 0x10,
+
+        /// <summary>
+        /// The mask for homogeneous aggregates of floating-point values.
+        /// </summary>
+        FloatingPointAggregateMask = Float32Aggregate | Float64Aggregate,
+
+        /// <summary>
+        /// The mask for homogeneous aggregates of short-vector values.
+        /// </summary>
+        ShortVectorAggregateMask = Vector64Aggregate | Vector128Aggregate | Vector256Aggregate,
+
+        /// <summary>
+        /// The mask for homogeneous aggregates.
         /// </summary>
-        HomogenousFloatAggregate = 0x01,
+        AggregateMask = FloatingPointAggregateMask | ShortVectorAggregateMask,
     }
 }
index 6c211ed..729620e 100644 (file)
@@ -830,132 +830,103 @@ namespace Internal.TypeSystem
             if (!type.IsValueType)
                 return ValueTypeShapeCharacteristics.None;
 
-            ValueTypeShapeCharacteristics result = ComputeHomogeneousFloatAggregateCharacteristic(type);
+            ValueTypeShapeCharacteristics result = ComputeHomogeneousAggregateCharacteristic(type);
 
             // TODO: System V AMD64 characteristics (https://github.com/dotnet/corert/issues/158)
 
             return result;
         }
 
-        private ValueTypeShapeCharacteristics ComputeHomogeneousFloatAggregateCharacteristic(DefType type)
+        private ValueTypeShapeCharacteristics ComputeHomogeneousAggregateCharacteristic(DefType type)
         {
+            // Use this constant to make the code below more laconic
+            const ValueTypeShapeCharacteristics NotHA = ValueTypeShapeCharacteristics.None;
+
             Debug.Assert(type.IsValueType);
 
-            MetadataType metadataType = (MetadataType)type;
+            TargetArchitecture targetArch = type.Context.Target.Architecture;
+            if ((targetArch != TargetArchitecture.ARM) && (targetArch != TargetArchitecture.ARM64))
+                return NotHA;
 
-            if (type.Context.Target.Architecture != TargetArchitecture.ARM && type.Context.Target.Architecture != TargetArchitecture.ARM64)
-                return ValueTypeShapeCharacteristics.None;
+            MetadataType metadataType = (MetadataType)type;
 
-            // No HFAs with explicit layout. There may be cases where explicit layout may be still
-            // eligible for HFA, but it is hard to tell the real intent. Make it simple and just 
-            // unconditionally disable HFAs for explicit layout.
+            // No HAs with explicit layout. There may be cases where explicit layout may be still
+            // eligible for HA, but it is hard to tell the real intent. Make it simple and just 
+            // unconditionally disable HAs for explicit layout.
             if (metadataType.IsExplicitLayout)
-                return ValueTypeShapeCharacteristics.None;
+                return NotHA;
 
             switch (metadataType.Category)
             {
+                // These are the primitive types that constitute a HFA type
                 case TypeFlags.Single:
+                    return ValueTypeShapeCharacteristics.Float32Aggregate;
                 case TypeFlags.Double:
-                    // These are the primitive types that constitute a HFA type.
-                    return ValueTypeShapeCharacteristics.HomogenousFloatAggregate;
+                    return ValueTypeShapeCharacteristics.Float64Aggregate;
 
                 case TypeFlags.ValueType:
-                    DefType expectedElementType = null;
+                    // Find the common HA element type if any
+                    ValueTypeShapeCharacteristics haResultType = NotHA;
 
                     foreach (FieldDesc field in metadataType.GetFields())
                     {
                         if (field.IsStatic)
                             continue;
 
-                        // If a field isn't a DefType, then this type cannot be an HFA type
-                        // If a field isn't a HFA type, then this type cannot be an HFA type
-                        DefType fieldType = field.FieldType as DefType;
-                        if (fieldType == null || !fieldType.IsHfa)
-                            return ValueTypeShapeCharacteristics.None;
+                        // If a field isn't a DefType, then this type cannot be a HA type
+                        if (!(field.FieldType is DefType fieldType))
+                            return NotHA;
+
+                        // If a field isn't a HA type, then this type cannot be a HA type
+                        ValueTypeShapeCharacteristics haFieldType = fieldType.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask;
+                        if (haFieldType == NotHA)
+                            return NotHA;
 
-                        if (expectedElementType == null)
+                        if (haResultType == NotHA)
                         {
-                            // If we hadn't yet figured out what form of HFA this type might be, we've
-                            // now found one case.
-                            expectedElementType = fieldType.HfaElementType;
-                            Debug.Assert(expectedElementType != null);
+                            // If we hadn't yet figured out what form of HA this type might be, we've now found one case
+                            haResultType = haFieldType;
                         }
-                        else if (expectedElementType != fieldType.HfaElementType)
+                        else if (haResultType != haFieldType)
                         {
-                            // If we had already determined the possible HFA type of the current type, but
+                            // If we had already determined the possible HA type of the current type, but
                             // the field we've encountered is not of that type, then the current type cannot
-                            // be an HFA type.
-                            return ValueTypeShapeCharacteristics.None;
+                            // be a HA type.
+                            return NotHA;
                         }
                     }
 
-                    // No fields means this is not HFA.
-                    if (expectedElementType == null)
-                        return ValueTypeShapeCharacteristics.None;
+                    // If there are no instance fields, this is not a HA type
+                    if (haResultType == NotHA)
+                        return NotHA;
 
-                    // Types which are indeterminate in field size are not considered to be HFA
-                    if (expectedElementType.InstanceFieldSize.IsIndeterminate)
-                        return ValueTypeShapeCharacteristics.None;
+                    int haElementSize = haResultType switch
+                    {
+                        ValueTypeShapeCharacteristics.Float32Aggregate => 4,
+                        ValueTypeShapeCharacteristics.Float64Aggregate => 8,
+                        ValueTypeShapeCharacteristics.Vector64Aggregate => 8,
+                        ValueTypeShapeCharacteristics.Vector128Aggregate => 16,
+                        ValueTypeShapeCharacteristics.Vector256Aggregate => 32,
+                        _ => throw new ArgumentOutOfRangeException()
+                    };
 
-                    // Types which are indeterminate in field size are not considered to be HFA
+                    // Types which are indeterminate in field size are not considered to be HA
                     if (type.InstanceFieldSize.IsIndeterminate)
-                        return ValueTypeShapeCharacteristics.None;
+                        return NotHA;
 
                     // Note that we check the total size, but do not perform any checks on number of fields:
-                    // - Type of fields can be HFA valuetype itself
-                    // - Managed C++ HFA valuetypes have just one <alignment member> of type float to signal that 
-                    //   the valuetype is HFA and explicitly specified size
-                    int maxSize = expectedElementType.InstanceFieldSize.AsInt * expectedElementType.Context.Target.MaximumHfaElementCount;
+                    // - Type of fields can be HA valuetype itself.
+                    // - Managed C++ HA valuetypes have just one <alignment member> of type float to signal that
+                    //   the valuetype is HA and explicitly specified size.
+                    int maxSize = haElementSize * type.Context.Target.MaxHomogeneousAggregateElementCount;
                     if (type.InstanceFieldSize.AsInt > maxSize)
-                        return ValueTypeShapeCharacteristics.None;
+                        return NotHA;
 
-                    // All the tests passed. This is an HFA type.
-                    return ValueTypeShapeCharacteristics.HomogenousFloatAggregate;
+                    // All the tests passed. This is a HA type.
+                    return haResultType;
             }
 
-            return ValueTypeShapeCharacteristics.None;
-        }
-
-        public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type)
-        {
-            if (!type.IsHfa)
-                return null;
-
-            if (type.IsWellKnownType(WellKnownType.Double) || type.IsWellKnownType(WellKnownType.Single))
-                return type;
-
-            for (; ; )
-            {
-                Debug.Assert(type.IsValueType);
-
-                // All HFA fields have to be of the same HFA type, so we can just return the type of the first field
-                TypeDesc firstFieldType = null;
-                foreach (var field in type.GetFields())
-                {
-                    if (field.IsStatic)
-                        continue;
-
-                    firstFieldType = field.FieldType;
-                    break;
-                }
-                Debug.Assert(firstFieldType != null, "Why is IsHfa true on this type?");
-
-                switch (firstFieldType.Category)
-                {
-                    case TypeFlags.Single:
-                    case TypeFlags.Double:
-                        return (DefType)firstFieldType;
-
-                    case TypeFlags.ValueType:
-                        // Drill into the struct and find the type of its first field
-                        type = (DefType)firstFieldType;
-                        break;
-
-                    default:
-                        Debug.Fail("Why is IsHfa true on this type?");
-                        return null;
-                }
-            }
+            return NotHA;
         }
 
         private struct SizeAndAlignment
index 8f910dd..162df18 100644 (file)
@@ -316,14 +316,15 @@ namespace Internal.TypeSystem
         }
 
         /// <summary>
-        /// Maximum number of elements in a HFA type.
+        /// Maximum number of elements in a homogeneous aggregate type.
         /// </summary>
-        public int MaximumHfaElementCount
+        public int MaxHomogeneousAggregateElementCount
         {
             get
             {
-                // There is a hard limit of 4 elements on an HFA type, see
+                // There is a hard limit of 4 elements on an HFA/HVA type, see
                 // https://devblogs.microsoft.com/cppblog/introducing-vector-calling-convention/
+                // and Procedure Call Standard for the Arm 64-bit Architecture.
                 Debug.Assert(Architecture == TargetArchitecture.ARM ||
                     Architecture == TargetArchitecture.ARM64 ||
                     Architecture == TargetArchitecture.X64 ||
index 91c3d9e..7006d95 100644 (file)
@@ -58,13 +58,5 @@ namespace Internal.TypeSystem
 
             return canonicalType.ValueTypeShapeCharacteristics;
         }
-
-        public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type)
-        {
-            RuntimeDeterminedType runtimeDeterminedType = (RuntimeDeterminedType)type;
-            DefType canonicalType = runtimeDeterminedType.CanonicalType;
-
-            return canonicalType.HfaElementType;
-        }
     }
 }
index abc9039..cc70462 100644 (file)
@@ -85,10 +85,11 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
             }
             return _type.RequiresAlign8();
         }
-        public bool IsHFA()
+
+        public bool IsHomogeneousAggregate()
         {
-            if (_type.Context.Target.Architecture != TargetArchitecture.ARM &&
-                _type.Context.Target.Architecture != TargetArchitecture.ARM64)
+            TargetArchitecture targetArch = _type.Context.Target.Architecture;
+            if ((targetArch != TargetArchitecture.ARM) && (targetArch != TargetArchitecture.ARM64))
             {
                 return false;
             }
@@ -96,29 +97,21 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
             {
                 return false;
             }
-            return _type is DefType defType && defType.IsHfa;
+            return _type is DefType defType && defType.IsHomogeneousAggregate;
         }
 
-        public CorElementType GetHFAType()
+        public int GetHomogeneousAggregateElementSize()
         {
-            Debug.Assert(IsHFA());
+            Debug.Assert(IsHomogeneousAggregate());
             switch (_type.Context.Target.Architecture)
             {
                 case TargetArchitecture.ARM:
-                    if (RequiresAlign8())
-                    {
-                        return CorElementType.ELEMENT_TYPE_R8;
-                    }
-                    break;
+                    return RequiresAlign8() ? 8 : 4;
 
                 case TargetArchitecture.ARM64:
-                    if (_type is DefType defType && defType.InstanceFieldAlignment.Equals(new LayoutInt(_type.Context.Target.PointerSize)))
-                    {
-                        return CorElementType.ELEMENT_TYPE_R8;
-                    }
-                    break;
+                    return ((DefType)_type).GetHomogeneousAggregateElementSize();
             }
-            return CorElementType.ELEMENT_TYPE_R4;
+            throw new InvalidOperationException();
         }
 
         public CorElementType GetCorElementType()
@@ -235,7 +228,6 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
         public int m_idxGenReg;    // First general register used (or -1)
         public short m_cGenReg;      // Count of general registers used (or 0)
 
-        public bool m_isSinglePrecision; // ARM64 - For determining if HFA is single or double precision
         public bool m_fRequires64BitAlignment;  // ARM - True if the argument should always be aligned (in registers or on the stack
 
         public int m_idxStack;     // First stack slot used (or -1)
@@ -251,7 +243,6 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
             m_idxStack = -1;
             m_cStack = 0;
 
-            m_isSinglePrecision = false;
             m_fRequires64BitAlignment = false;
         }
     };
@@ -286,8 +277,8 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
             frame[_offset + delta] = interior ? CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_INTERIOR : CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_REF;
         }
 
-        // Returns true if the ArgDestination represents an HFA struct
-        bool IsHFA()
+        // Returns true if the ArgDestination represents a homogeneous aggregate struct
+        bool IsHomogeneousAggregate()
         {
             return _argLocDescForStructInRegs.HasValue;
         }
@@ -615,18 +606,17 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
             {
                 switch (_transitionBlock.Architecture)
                 {
-
                     case TargetArchitecture.X64:
                         return _transitionBlock.IsArgPassedByRef(_argSize);
                     case TargetArchitecture.ARM64:
                         if (_argType == CorElementType.ELEMENT_TYPE_VALUETYPE)
                         {
                             Debug.Assert(!_argTypeHandle.IsNull());
-                            return ((_argSize > _transitionBlock.EnregisteredParamTypeMaxSize) && (!_argTypeHandle.IsHFA() || IsVarArg));
+                            return ((_argSize > _transitionBlock.EnregisteredParamTypeMaxSize) && (!_argTypeHandle.IsHomogeneousAggregate() || IsVarArg));
                         }
                         return false;
                     default:
-                        throw new NotImplementedException(_transitionBlock.Architecture.ToString());
+                        throw new NotImplementedException();
                 }
             }
             else
@@ -830,7 +820,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                         break;
 
                     default:
-                        throw new NotImplementedException(_transitionBlock.Architecture.ToString());
+                        throw new NotImplementedException();
                 }
 
                 _argNum = (_skipFirstArg ? 1 : 0);
@@ -849,21 +839,6 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
 
             int argSize = TypeHandle.GetElemSize(argType, _argTypeHandle);
 
-            bool processingFloatsAsDoublesFromTransitionBlock = false;
-            if (_transitionBlock.IsARM64)
-            {
-                // NOT DESKTOP BEHAVIOR: The S and D registers overlap, and the UniversalTransitionThunk copies D registers to the transition blocks. We'll need
-                // to work with the D registers here as well.
-                if (argType == CorElementType.ELEMENT_TYPE_VALUETYPE && _argTypeHandle.IsHFA() && _argTypeHandle.GetHFAType() == CorElementType.ELEMENT_TYPE_R4)
-                {
-                    if ((argSize / sizeof(float)) + _arm64IdxFPReg <= 8)
-                    {
-                        argSize *= 2;
-                        processingFloatsAsDoublesFromTransitionBlock = true;
-                    }
-                }
-            }
-
             _argType = argType;
             _argSize = argSize;
 
@@ -1069,7 +1044,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
 
                                     // Handle HFAs: packed structures of 1-4 floats or doubles that are passed in FP argument
                                     // registers if possible.
-                                    if (_argTypeHandle.IsHFA())
+                                    if (_argTypeHandle.IsHomogeneousAggregate())
                                         fFloatingPoint = true;
 
                                     break;
@@ -1215,19 +1190,26 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
 
                             case CorElementType.ELEMENT_TYPE_VALUETYPE:
                                 {
-                                    // Handle HFAs: packed structures of 2-4 floats or doubles that are passed in FP argument
-                                    // registers if possible.
-                                    if (_argTypeHandle.IsHFA())
+                                    // Handle HAs: packed structures of 1-4 floats, doubles, or short vectors
+                                    // that are passed in FP argument registers if possible.
+                                    if (_argTypeHandle.IsHomogeneousAggregate())
                                     {
-                                        CorElementType type = _argTypeHandle.GetHFAType();
-                                        if (processingFloatsAsDoublesFromTransitionBlock)
-                                            cFPRegs = argSize / sizeof(double);
-                                        else
-                                            cFPRegs = (type == CorElementType.ELEMENT_TYPE_R4) ? (argSize / sizeof(float)) : (argSize / sizeof(double));
+                                        _argLocDescForStructInRegs = new ArgLocDesc();
+                                        _argLocDescForStructInRegs.m_idxFloatReg = _arm64IdxFPReg;
+
+                                        int haElementSize = _argTypeHandle.GetHomogeneousAggregateElementSize();
+                                        cFPRegs = argSize / haElementSize;
+                                        _argLocDescForStructInRegs.m_cFloatReg = cFPRegs;
+
+                                        // Check if we have enough registers available for the HA passing
+                                        if (cFPRegs + _arm64IdxFPReg <= 8)
+                                        {
+                                            _hasArgLocDescForStructInRegs = true;
+                                        }
                                     }
                                     else
                                     {
-                                        // Composite greater than 16bytes should be passed by reference
+                                        // Composite greater than 16 bytes should be passed by reference
                                         if (argSize > _transitionBlock.EnregisteredParamTypeMaxSize)
                                         {
                                             argSize = _transitionBlock.PointerSize;
@@ -1248,7 +1230,8 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                         {
                             if (cFPRegs + _arm64IdxFPReg <= 8)
                             {
-                                int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _arm64IdxFPReg * 8;
+                                // Each floating point register in the argument area is 16 bytes.
+                                int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _arm64IdxFPReg * 16;
                                 _arm64IdxFPReg += cFPRegs;
                                 return argOfsInner;
                             }
@@ -1259,14 +1242,33 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                         }
                         else
                         {
+                            // Only x0-x7 are valid argument registers (x8 is always the return buffer)
                             if (_arm64IdxGenReg + cArgSlots <= 8)
                             {
+                                // The entirety of the arg fits in the register slots.
                                 int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _arm64IdxGenReg * 8;
                                 _arm64IdxGenReg += cArgSlots;
                                 return argOfsInner;
                             }
+                            else if (_context.Target.IsWindows && IsVarArg && (_arm64IdxGenReg < 8))
+                            {
+                                // Address the Windows ARM64 varargs case where an arg is split between regs and stack.
+                                // This can happen in the varargs case because the first 64 bytes of the stack are loaded
+                                // into x0-x7, and any remaining stack arguments are placed normally.
+                                int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _arm64IdxGenReg * 8;
+
+                                // Increase m_idxStack to account for the space used for the remainder of the arg after
+                                // register slots are filled.
+                                _arm64IdxStack += (_arm64IdxGenReg + cArgSlots - 8);
+
+                                // We used up the remaining reg slots.
+                                _arm64IdxGenReg = 8;
+
+                                return argOfsInner;
+                            }
                             else
                             {
+                                // Don't use reg slots for this. It will be passed purely on the stack arg space.
                                 _arm64IdxGenReg = 8;
                             }
                         }
@@ -1277,7 +1279,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                     }
 
                 default:
-                    throw new NotImplementedException(_transitionBlock.Architecture.ToString());
+                    throw new NotImplementedException();
             }
         }
 
@@ -1513,17 +1515,13 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
 
                         if (_transitionBlock.IsFloatArgumentRegisterOffset(argOffset))
                         {
-                            // Dividing by 8 as size of each register in FloatArgumentRegisters is 8 bytes.
-                            pLoc.m_idxFloatReg = (argOffset - _transitionBlock.OffsetOfFloatArgumentRegisters) / 8;
+                            // Dividing by 16 as size of each register in FloatArgumentRegisters is 16 bytes.
+                            pLoc.m_idxFloatReg = (argOffset - _transitionBlock.OffsetOfFloatArgumentRegisters) / 16;
 
-                            if (!_argTypeHandle.IsNull() && _argTypeHandle.IsHFA())
+                            if (!_argTypeHandle.IsNull() && _argTypeHandle.IsHomogeneousAggregate())
                             {
-                                CorElementType type = _argTypeHandle.GetHFAType();
-                                bool isFloatType = (type == CorElementType.ELEMENT_TYPE_R4);
-
-                                // DESKTOP BEHAVIOR pLoc->m_cFloatReg = isFloatType ? GetArgSize() / sizeof(float) : GetArgSize() / sizeof(double);
-                                pLoc.m_cFloatReg = GetArgSize() / sizeof(double);
-                                pLoc.m_isSinglePrecision = isFloatType;
+                                int haElementSize = _argTypeHandle.GetHomogeneousAggregateElementSize();
+                                pLoc.m_cFloatReg = GetArgSize() / haElementSize;
                             }
                             else
                             {
@@ -1605,7 +1603,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                     return null;
 
                 default:
-                    throw new NotImplementedException(_transitionBlock.Architecture.ToString());
+                    throw new NotImplementedException();
             }
         }
 
index 5f2767c..cfe4056 100644 (file)
@@ -120,20 +120,8 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
 
             for (uint pos = 0; pos < nStackSlots; pos++)
             {
-                int ofs;
-
-                if (_target.Architecture == TargetArchitecture.X86)
-                {
-                    ofs = (int)(pos < _transitionBlock.NumArgumentRegisters ?
-                        _transitionBlock.OffsetOfArgumentRegisters + _transitionBlock.SizeOfArgumentRegisters - (pos + 1) * _target.PointerSize :
-                        _transitionBlock.OffsetOfArgs + (pos - _transitionBlock.NumArgumentRegisters) * _target.PointerSize);
-                }
-                else
-                {
-                    ofs = (int)(_transitionBlock.OffsetOfFirstGCRefMapSlot + pos * _target.PointerSize);
-                }
-
-                CORCOMPILE_GCREFMAP_TOKENS token = fakeStack[ofs];
+                int offset = _transitionBlock.OffsetFromGCRefMapPos(checked((int)pos));
+                CORCOMPILE_GCREFMAP_TOKENS token = fakeStack[offset];
 
                 if (token != CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_SKIP)
                 {
index 70f7c4a..218999b 100644 (file)
@@ -77,7 +77,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
         public abstract int OffsetOfArgumentRegisters { get; }
 
         /// <summary>
-        /// Only overridden on ARM64 to return offset of the X8 register.
+        /// The offset of the first slot in a GC ref map. Overridden on ARM64 to return the offset of the X8 register.
         /// </summary>
         public virtual int OffsetOfFirstGCRefMapSlot => OffsetOfArgumentRegisters;
 
@@ -105,11 +105,9 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
         /// Recalculate pos in GC ref map to actual offset. This is the default implementation for all architectures
         /// except for X86 where it's overridden to supply a more complex algorithm.
         /// </summary>
-        /// <param name="pos"></param>
-        /// <returns></returns>
         public virtual int OffsetFromGCRefMapPos(int pos)
         {
-            return OffsetOfArgumentRegisters + pos * PointerSize;
+            return OffsetOfFirstGCRefMapSlot + pos * PointerSize;
         }
 
         /// <summary>
@@ -277,12 +275,15 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                                 {
                                     if (descriptor.eightByteClassifications0 == SystemVClassificationType.SystemVClassificationTypeSSE)
                                     {
+                                        // Structs occupying just one eightbyte are treated as int / double
                                         fpReturnSize = sizeof(double);
                                     }
                                 }
                                 else
                                 {
+                                    // Size of the struct is 16 bytes
                                     fpReturnSize = 16;
+                                    // The lowest two bits of the size encode the order of the int and SSE fields
                                     if (descriptor.eightByteClassifications0 == SystemVClassificationType.SystemVClassificationTypeSSE)
                                     {
                                         fpReturnSize += 1;
@@ -299,28 +300,10 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                         }
                         else
                         {
-                            if (thRetType.IsHFA() && !isVarArgMethod)
+                            if (thRetType.IsHomogeneousAggregate() && !isVarArgMethod)
                             {
-                                CorElementType hfaType = thRetType.GetHFAType();
-
-                                switch (Architecture)
-                                {
-                                    case TargetArchitecture.ARM:
-                                        fpReturnSize = (hfaType == CorElementType.ELEMENT_TYPE_R4) ?
-                                            (4 * (uint)sizeof(float)) :
-                                            (4 * (uint)sizeof(double));
-                                        break;
-
-                                    case TargetArchitecture.ARM64:
-                                        // DESKTOP BEHAVIOR fpReturnSize = (hfaType == CorElementType.ELEMENT_TYPE_R4) ? (4 * (uint)sizeof(float)) : (4 * (uint)sizeof(double));
-                                        // S and D registers overlap. Since we copy D registers in the UniversalTransitionThunk, we'll
-                                        // treat floats like doubles during copying.
-                                        fpReturnSize = 4 * (uint)sizeof(double);
-                                        break;
-
-                                    default:
-                                        throw new NotImplementedException();
-                                }
+                                int haElementSize = thRetType.GetHomogeneousAggregateElementSize();
+                                fpReturnSize = 4 * (uint)haElementSize;
                                 break;
                             }
 
@@ -481,8 +464,6 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
         {
             public static TransitionBlock Instance = new Arm64TransitionBlock();
 
-            private int OffsetOfX8Register => OffsetOfArgumentRegisters - PointerSize;
-
             public override TargetArchitecture Architecture => TargetArchitecture.ARM64;
             public override int PointerSize => 8;
             // X0 .. X7
@@ -492,6 +473,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
             // Callee-saves, padding, m_x8RetBuffReg, argument registers
             public override int SizeOfTransitionBlock => SizeOfCalleeSavedRegisters + 2 * PointerSize + SizeOfArgumentRegisters;
             public override int OffsetOfArgumentRegisters => SizeOfCalleeSavedRegisters + 2 * PointerSize;
+            private int OffsetOfX8Register => OffsetOfArgumentRegisters - PointerSize;
             public override int OffsetOfFirstGCRefMapSlot => OffsetOfX8Register;
 
             // D0..D7
@@ -505,12 +487,12 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                 Debug.Assert(th.IsValueType());
 
                 // Composites greater than 16 bytes are passed by reference
-                return (th.GetSize() > EnregisteredParamTypeMaxSize) && !th.IsHFA();
+                return (th.GetSize() > EnregisteredParamTypeMaxSize) && !th.IsHomogeneousAggregate();
             }
 
             public override int GetRetBuffArgOffset(bool hasThis) => OffsetOfX8Register;
 
             public override bool IsRetBuffPassedAsFirstArg => true;
         }
-    };
+    }
 }
index 359d141..5113b41 100644 (file)
@@ -71,7 +71,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                 flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout_Empty;
             }
 
-            if (defType.IsHfa)
+            if (defType.IsHomogeneousAggregate)
             {
                 flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_HFA;
             }
@@ -79,17 +79,19 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
             dataBuilder.EmitUInt((uint)flags);
             dataBuilder.EmitUInt((uint)size);
 
-            if (defType.IsHfa)
+            if (defType.IsHomogeneousAggregate)
             {
-                switch (defType.HfaElementType.Category)
+                CorElementType elementType = (defType.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) switch
                 {
-                    case TypeFlags.Single:
-                        dataBuilder.EmitUInt((uint)CorElementType.ELEMENT_TYPE_R4);
-                        break;
-                    case TypeFlags.Double:
-                        dataBuilder.EmitUInt((uint)CorElementType.ELEMENT_TYPE_R8);
-                        break;
-                }
+                    ValueTypeShapeCharacteristics.Float32Aggregate => CorElementType.ELEMENT_TYPE_R4,
+                    ValueTypeShapeCharacteristics.Float64Aggregate => CorElementType.ELEMENT_TYPE_R8,
+                    ValueTypeShapeCharacteristics.Vector64Aggregate => CorElementType.ELEMENT_TYPE_R8,
+                    // See MethodTable::GetHFAType
+                    ValueTypeShapeCharacteristics.Vector128Aggregate => CorElementType.ELEMENT_TYPE_VALUETYPE,
+                    ValueTypeShapeCharacteristics.Vector256Aggregate => CorElementType.ELEMENT_TYPE_VALUETYPE,
+                    _ => CorElementType.Invalid
+                };
+                dataBuilder.EmitUInt((uint)elementType);
             }
             
             if (alignment != pointerSize)
index 5f2d166..bbe1274 100644 (file)
@@ -139,11 +139,6 @@ namespace ILCompiler
             return false;
         }
 
-        public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type)
-        {
-            return _fallbackAlgorithm.ComputeHomogeneousFloatAggregateElementType(type);
-        }
-
         public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind)
         {
             DefType similarSpecifiedVector = GetSimilarVector(type);
@@ -202,7 +197,15 @@ namespace ILCompiler
 
         public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type)
         {
-            return _fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type);
+            if (type.Context.Target.Architecture == TargetArchitecture.ARM64)
+            {
+                return type.InstanceFieldSize.AsInt switch
+                {
+                    16 => ValueTypeShapeCharacteristics.Vector128Aggregate,
+                    _ => ValueTypeShapeCharacteristics.None
+                };
+            }
+            return ValueTypeShapeCharacteristics.None;
         }
 
         public static bool IsVectorOfTType(DefType type)
index 769ed2d..8cdacd9 100644 (file)
@@ -54,11 +54,5 @@ namespace ILCompiler
         {
             return _fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type);
         }
-
-        public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type)
-        {
-            return _fallbackAlgorithm.ComputeHomogeneousFloatAggregateElementType(type);
-        }
-
     }
 }
index 6cebfa7..5cfef64 100644 (file)
@@ -50,14 +50,17 @@ namespace ILCompiler.Reflection.ReadyToRun
         public abstract int OffsetOfArgumentRegisters { get; }
 
         /// <summary>
+        /// The offset of the first slot in a GC ref map. Overridden on ARM64 to return the offset of the X8 register.
+        /// </summary>
+        public virtual int OffsetOfFirstGCRefMapSlot => OffsetOfArgumentRegisters;
+
+        /// <summary>
         /// Recalculate pos in GC ref map to actual offset. This is the default implementation for all architectures
         /// except for X86 where it's overridden to supply a more complex algorithm.
         /// </summary>
-        /// <param name="pos"></param>
-        /// <returns></returns>
         public virtual int OffsetFromGCRefMapPos(int pos)
         {
-            return OffsetOfArgumentRegisters + pos * PointerSize;
+            return OffsetOfFirstGCRefMapSlot + pos * PointerSize;
         }
 
         /// <summary>
@@ -144,8 +147,8 @@ namespace ILCompiler.Reflection.ReadyToRun
             // Callee-saves, padding, m_x8RetBuffReg, argument registers
             public override int SizeOfTransitionBlock => SizeOfCalleeSavedRegisters + 2 * PointerSize + SizeOfArgumentRegisters;
             public override int OffsetOfArgumentRegisters => SizeOfCalleeSavedRegisters + 2 * PointerSize;
+            private int OffsetOfX8Register => OffsetOfArgumentRegisters - PointerSize;
+            public override int OffsetOfFirstGCRefMapSlot => OffsetOfX8Register;
         }
     }
-
 }
-
index 8845a35..6cd90b4 100644 (file)
@@ -638,7 +638,7 @@ public:
 
         int cSlots = (GetArgSize() + 7)/ 8;
 
-        // Composites greater than 16bytes are passed by reference
+        // Composites greater than 16 bytes are passed by reference
         if (GetArgType() == ELEMENT_TYPE_VALUETYPE && GetArgSize() > ENREGISTERED_PARAMTYPE_MAXSIZE)
         {
             cSlots = 1;
@@ -1346,8 +1346,8 @@ int ArgIteratorTemplate<ARGITERATOR_BASE>::GetNextOffset()
 
     case ELEMENT_TYPE_VALUETYPE:
     {
-        // Handle HFAs: packed structures of 2-4 floats or doubles that are passed in FP argument
-        // registers if possible.
+        // Handle HFAs: packed structures of 1-4 floats, doubles, or short vectors
+        // that are passed in FP argument registers if possible.
         if (thValueType.IsHFA())
         {
             CorElementType type = thValueType.GetHFAType();
index 41a1a63..b0976b4 100644 (file)
@@ -1253,11 +1253,6 @@ CorElementType MethodTable::GetHFAType()
         {
         case ELEMENT_TYPE_VALUETYPE:
             pMT = pFirstField->LookupApproxFieldTypeHandle().GetMethodTable();
-            vectorSize = pMT->GetVectorSize();
-            if (vectorSize != 0)
-            {
-                return (vectorSize == 8) ? ELEMENT_TYPE_R8 : ELEMENT_TYPE_VALUETYPE;
-            }
             break;
 
         case ELEMENT_TYPE_R4: