diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 2276c5cdc9a7cc..960b2e8e8113b3 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1235,6 +1235,7 @@ public struct SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR // bit 5: `1` means the second field's size is 8. // // Note that bit 0 and 3 cannot both be set. + [Flags] public enum StructFloatFieldInfoFlags { STRUCT_NO_FLOAT_FIELD = 0x0, diff --git a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs b/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs index d6c820b8f904c9..fae694f8768fc9 100644 --- a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs +++ b/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs @@ -1,210 +1,127 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Diagnostics; using ILCompiler; using Internal.TypeSystem; +using static Internal.JitInterface.StructFloatFieldInfoFlags; namespace Internal.JitInterface { - internal static class RISCV64PassStructInRegister { - public static uint GetRISCV64PassStructInRegisterFlags(TypeDesc typeDesc) + private const int + ENREGISTERED_PARAMTYPE_MAXSIZE = 16, + TARGET_POINTER_SIZE = 8; + + private static bool HandleInlineArray(int elementTypeIndex, int nElements, Span types, ref int typeIndex) { - FieldDesc firstField = null; - uint floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; - int numIntroducedFields = 0; - foreach (FieldDesc field in typeDesc.GetFields()) + int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex; + if (nFlattenedFieldsPerElement == 0) + return true; + + Debug.Assert(nFlattenedFieldsPerElement == 1 || nFlattenedFieldsPerElement == 2); + + if (nElements > 2) + return false; + + if (nElements == 2) { - if (!field.IsStatic) - { - firstField ??= field; - numIntroducedFields++; - } + if (typeIndex + nFlattenedFieldsPerElement > 2) + return false; + + Debug.Assert(elementTypeIndex == 0); + Debug.Assert(typeIndex == 1); + types[typeIndex++] = types[elementTypeIndex]; // duplicate the array element type } + return true; + } - if ((numIntroducedFields == 0) || (numIntroducedFields > 2) || (typeDesc.GetElementSize().AsInt > 16)) + private static bool FlattenFieldTypes(TypeDesc td, Span types, ref int typeIndex) + { + IEnumerable fields = td.GetFields(); + int nFields = 0; + int elementTypeIndex = typeIndex; + FieldDesc prevField = null; + foreach (FieldDesc field in fields) { - return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; - } + if (field.IsStatic) + continue; + nFields++; - MetadataType mdType = typeDesc as MetadataType; - Debug.Assert(mdType != null); + if (prevField != null && prevField.Offset.AsInt + prevField.FieldType.GetElementSize().AsInt > field.Offset.AsInt) + return false; // overlapping fields - TypeDesc firstFieldElementType = firstField.FieldType; - int firstFieldSize = firstFieldElementType.GetElementSize().AsInt; - bool hasImpliedRepeatedFields = mdType.HasImpliedRepeatedFields(); + prevField = field; - if (hasImpliedRepeatedFields) - { - numIntroducedFields = typeDesc.GetElementSize().AsInt / firstFieldSize; - if (numIntroducedFields > 2) + TypeFlags category = field.FieldType.Category; + if (category == TypeFlags.ValueType) { - return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; + TypeDesc nested = field.FieldType; + if (!FlattenFieldTypes(nested, types, ref typeIndex)) + return false; } - } - - int fieldIndex = 0; - foreach (FieldDesc field in typeDesc.GetFields()) - { - if (fieldIndex > 1) + else if (field.FieldType.GetElementSize().AsInt <= TARGET_POINTER_SIZE) { - return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; + if (typeIndex >= 2) + return false; + + StructFloatFieldInfoFlags type = + (category is TypeFlags.Single or TypeFlags.Double ? STRUCT_FLOAT_FIELD_FIRST : (StructFloatFieldInfoFlags)0) | + (field.FieldType.GetElementSize().AsInt == TARGET_POINTER_SIZE ? STRUCT_FIRST_FIELD_SIZE_IS8 : (StructFloatFieldInfoFlags)0); + types[typeIndex++] = type; } - else if (field.IsStatic) + else { - continue; + return false; } + } - Debug.Assert(fieldIndex < numIntroducedFields); + if ((td as MetadataType).HasImpliedRepeatedFields()) + { + Debug.Assert(nFields == 1); + int nElements = td.GetElementSize().AsInt / prevField.FieldType.GetElementSize().AsInt; + if (!HandleInlineArray(elementTypeIndex, nElements, types, ref typeIndex)) + return false; + } + return true; + } - switch (field.FieldType.Category) - { - case TypeFlags.Double: - { - if (numIntroducedFields == 1) - { - floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE; - } - else if (fieldIndex == 0) - { - floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_DOUBLE; - } - else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST) != 0) - { - floatFieldFlags ^= (uint)StructFloatFieldInfoFlags.STRUCT_MERGE_FIRST_SECOND_8; - } - else - { - floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_DOUBLE; - } - - // Pass with two integer registers in `struct {int a, int b, float/double c}` cases - if (fieldIndex == 1 && - (floatFieldFlags | - (uint)StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8 | - (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND) == - floatFieldFlags) - { - floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; - } - } - break; - - case TypeFlags.Single: - { - if (numIntroducedFields == 1) - { - floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE; - } - else if (fieldIndex == 0) - { - floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST; - } - else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST) != 0) - { - floatFieldFlags ^= (uint)StructFloatFieldInfoFlags.STRUCT_MERGE_FIRST_SECOND; - } - else - { - floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND; - } - - // Pass with two integer registers in `struct {int a, int b, float/double c}` cases - if (fieldIndex == 1 && - (floatFieldFlags | - (uint)StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8 | - (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND) == - floatFieldFlags) - { - floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; - } - } - break; - - case TypeFlags.ValueType: - //case TypeFlags.Class: - //case TypeFlags.Array: - //case TypeFlags.SzArray: - { - uint floatFieldFlags2 = GetRISCV64PassStructInRegisterFlags(field.FieldType); - if (numIntroducedFields == 1) - { - floatFieldFlags = floatFieldFlags2; - } - else if (field.FieldType.GetElementSize().AsInt > 8) - { - return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; - } - else if (fieldIndex == 0) - { - if ((floatFieldFlags2 & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) - { - floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST; - } - if (field.FieldType.GetElementSize().AsInt == 8) - { - floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8; - } - } - else - { - Debug.Assert(fieldIndex == 1); - if ((floatFieldFlags2 & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) - { - floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_MERGE_FIRST_SECOND; - } - if (field.FieldType.GetElementSize().AsInt == 8) - { - floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_SIZE_IS8; - } - - floatFieldFlags2 = floatFieldFlags & ((uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST | (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND); - if (floatFieldFlags2 == 0) - { - floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; - } - else if (floatFieldFlags2 == ((uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST | (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND)) - { - floatFieldFlags ^= ((uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO | (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST | (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND); - } - } - } - break; - - default: - { - if (field.FieldType.GetElementSize().AsInt == 8) - { - if (numIntroducedFields > 1) - { - if (fieldIndex == 0) - { - floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8; - } - else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST) != 0) - { - floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_SIZE_IS8; - } - else - { - floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; - } - } - } - else if (fieldIndex == 1) - { - floatFieldFlags = (floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST) > 0 ? floatFieldFlags : (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; - } - break; - } - } + public static uint GetRISCV64PassStructInRegisterFlags(TypeDesc td) + { + if (td.GetElementSize().AsInt > ENREGISTERED_PARAMTYPE_MAXSIZE) + return (uint)STRUCT_NO_FLOAT_FIELD; - fieldIndex++; - } + Span types = stackalloc StructFloatFieldInfoFlags[] { + STRUCT_NO_FLOAT_FIELD, STRUCT_NO_FLOAT_FIELD + }; + int nFields = 0; + if (!FlattenFieldTypes(td, types, ref nFields) || nFields == 0) + return (uint)STRUCT_NO_FLOAT_FIELD; + + Debug.Assert(nFields == 1 || nFields == 2); + + Debug.Assert((uint)(STRUCT_FLOAT_FIELD_SECOND | STRUCT_SECOND_FIELD_SIZE_IS8) + == (uint)(STRUCT_FLOAT_FIELD_FIRST | STRUCT_FIRST_FIELD_SIZE_IS8) << 1, + "SECOND flags need to be FIRST shifted by 1"); + StructFloatFieldInfoFlags flags = types[0] | (StructFloatFieldInfoFlags)((uint)types[1] << 1); + + const StructFloatFieldInfoFlags bothFloat = STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND; + if ((flags & bothFloat) == 0) + return (uint)STRUCT_NO_FLOAT_FIELD; - return floatFieldFlags; + if ((flags & bothFloat) == bothFloat) + { + Debug.Assert(nFields == 2); + flags ^= (bothFloat | STRUCT_FLOAT_FIELD_ONLY_TWO); // replace bothFloat with ONLY_TWO + } + else if (nFields == 1) + { + Debug.Assert((flags & STRUCT_FLOAT_FIELD_FIRST) != 0); + flags ^= (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_ONE); // replace FIRST with ONLY_ONE + } + return (uint)flags; } } } diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 12b935996b1a41..3e85ecd65947e0 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -1816,17 +1816,7 @@ int ArgIteratorTemplate::GetNextOffset() } else { - MethodTable* pMethodTable = nullptr; - - if (!thValueType.IsTypeDesc()) - pMethodTable = thValueType.AsMethodTable(); - else - { - _ASSERTE(thValueType.IsNativeValueType()); - pMethodTable = thValueType.AsNativeValueType(); - } - _ASSERTE(pMethodTable != nullptr); - flags = MethodTable::GetRiscV64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable); + flags = MethodTable::GetRiscV64PassStructInRegisterFlags(thValueType); if (flags & STRUCT_HAS_FLOAT_FIELDS_MASK) { cFPRegs = (flags & STRUCT_FLOAT_FIELD_ONLY_TWO) ? 2 : 1; @@ -2038,9 +2028,7 @@ void ArgIteratorTemplate::ComputeReturnFlags() if (size <= ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE) { assert(!thValueType.IsTypeDesc()); - - MethodTable *pMethodTable = thValueType.AsMethodTable(); - flags = (MethodTable::GetRiscV64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable) & 0xff) << RETURN_FP_SIZE_SHIFT; + flags = (MethodTable::GetRiscV64PassStructInRegisterFlags(thValueType) & 0xff) << RETURN_FP_SIZE_SHIFT; break; } #else diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 6a02a8c76b9ff6..64447437033199 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9641,7 +9641,7 @@ uint32_t CEEInfo::getRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) uint32_t size = STRUCT_NO_FLOAT_FIELD; #if defined(TARGET_RISCV64) - size = (uint32_t)MethodTable::GetRiscV64PassStructInRegisterFlags(cls); + size = (uint32_t)MethodTable::GetRiscV64PassStructInRegisterFlags(TypeHandle(cls)); #endif // TARGET_RISCV64 EE_TO_JIT_TRANSITION_LEAF(); diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 24f93f4c14899c..c80a4a8afa5a80 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -2074,6 +2074,11 @@ namespace } DWORD numIntroducedFields = pMT->GetNumIntroducedInstanceFields(); + if (numIntroducedFields != 1) + { + return false; + } + FieldDesc *pFieldStart = pMT->GetApproxFieldDescListRaw(); CorElementType firstFieldElementType = pFieldStart->GetFieldType(); @@ -2084,8 +2089,7 @@ namespace // instead of adding additional padding at the end of a one-field structure. // We do this check here to save looking up the FixedBufferAttribute when loading the field // from metadata. - return numIntroducedFields == 1 - && ( CorTypeInfo::IsPrimitiveType_NoThrow(firstFieldElementType) + return (CorTypeInfo::IsPrimitiveType_NoThrow(firstFieldElementType) || firstFieldElementType == ELEMENT_TYPE_VALUETYPE) && (pFieldStart->GetOffset() == 0) && pMT->HasLayout() @@ -2798,50 +2802,50 @@ void MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHe #endif // defined(UNIX_AMD64_ABI_ITF) -#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) +#if defined(TARGET_LOONGARCH64) bool MethodTable::IsOnlyOneField(MethodTable * pMT) { TypeHandle th(pMT); + if (th.GetSize() > ENREGISTERED_PARAMTYPE_MAXSIZE) + return false; + bool ret = false; if (!th.IsTypeDesc()) { MethodTable* pMethodTable = th.AsMethodTable(); - if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) - { - DWORD numIntroducedFields = pMethodTable->GetNumIntroducedInstanceFields(); + DWORD numIntroducedFields = pMethodTable->GetNumIntroducedInstanceFields(); - if (numIntroducedFields == 1) - { - FieldDesc *pFieldStart = pMethodTable->GetApproxFieldDescListRaw(); + if (numIntroducedFields == 1) + { + FieldDesc *pFieldStart = pMethodTable->GetApproxFieldDescListRaw(); - CorElementType fieldType = pFieldStart[0].GetFieldType(); + CorElementType fieldType = pFieldStart[0].GetFieldType(); - // InlineArray types and fixed buffer types have implied repeated fields. - // Checking if a type is an InlineArray type is cheap, so we'll do that first. - bool hasImpliedRepeatedFields = HasImpliedRepeatedFields(pMethodTable); + // InlineArray types and fixed buffer types have implied repeated fields. + // Checking if a type is an InlineArray type is cheap, so we'll do that first. + bool hasImpliedRepeatedFields = HasImpliedRepeatedFields(pMethodTable); - if (hasImpliedRepeatedFields) + if (hasImpliedRepeatedFields) + { + numIntroducedFields = pMethodTable->GetNumInstanceFieldBytes() / pFieldStart->GetSize(); + if (numIntroducedFields != 1) { - numIntroducedFields = pMethodTable->GetNumInstanceFieldBytes() / pFieldStart->GetSize(); - if (numIntroducedFields != 1) - { - goto _End_arg; - } + goto _End_arg; } + } - if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) - { - ret = true; - } - else if (fieldType == ELEMENT_TYPE_VALUETYPE) + if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) + { + ret = true; + } + else if (fieldType == ELEMENT_TYPE_VALUETYPE) + { + pMethodTable = pFieldStart->GetApproxFieldTypeHandleThrowing().GetMethodTable(); + if (pMethodTable->GetNumIntroducedInstanceFields() == 1) { - pMethodTable = pFieldStart->GetApproxFieldTypeHandleThrowing().GetMethodTable(); - if (pMethodTable->GetNumIntroducedInstanceFields() == 1) - { - ret = IsOnlyOneField(pMethodTable); - } + ret = IsOnlyOneField(pMethodTable); } } } @@ -2849,54 +2853,50 @@ bool MethodTable::IsOnlyOneField(MethodTable * pMT) else { MethodTable* pMethodTable = th.AsNativeValueType(); + DWORD numIntroducedFields = pMethodTable->GetNativeLayoutInfo()->GetNumFields(); + FieldDesc *pFieldStart = nullptr; - if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) + if (numIntroducedFields == 1) { - DWORD numIntroducedFields = pMethodTable->GetNativeLayoutInfo()->GetNumFields(); - FieldDesc *pFieldStart = nullptr; + pFieldStart = pMethodTable->GetApproxFieldDescListRaw(); - if (numIntroducedFields == 1) - { - pFieldStart = pMethodTable->GetApproxFieldDescListRaw(); - - CorElementType fieldType = pFieldStart->GetFieldType(); + CorElementType fieldType = pFieldStart->GetFieldType(); - // InlineArray types and fixed buffer types have implied repeated fields. - // Checking if a type is an InlineArray type is cheap, so we'll do that first. - bool hasImpliedRepeatedFields = HasImpliedRepeatedFields(pMethodTable); + // InlineArray types and fixed buffer types have implied repeated fields. + // Checking if a type is an InlineArray type is cheap, so we'll do that first. + bool hasImpliedRepeatedFields = HasImpliedRepeatedFields(pMethodTable); - if (hasImpliedRepeatedFields) + if (hasImpliedRepeatedFields) + { + numIntroducedFields = pMethodTable->GetNumInstanceFieldBytes() / pFieldStart->GetSize(); + if (numIntroducedFields != 1) { - numIntroducedFields = pMethodTable->GetNumInstanceFieldBytes() / pFieldStart->GetSize(); - if (numIntroducedFields != 1) - { - goto _End_arg; - } + goto _End_arg; } + } - if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) + if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) + { + ret = true; + } + else if (fieldType == ELEMENT_TYPE_VALUETYPE) + { + const NativeFieldDescriptor *pNativeFieldDescs = pMethodTable->GetNativeLayoutInfo()->GetNativeFieldDescriptors(); + NativeFieldCategory nfc = pNativeFieldDescs->GetCategory(); + if (nfc == NativeFieldCategory::NESTED) { - ret = true; + pMethodTable = pNativeFieldDescs->GetNestedNativeMethodTable(); + ret = IsOnlyOneField(pMethodTable); } - else if (fieldType == ELEMENT_TYPE_VALUETYPE) + else if (nfc != NativeFieldCategory::ILLEGAL) { - const NativeFieldDescriptor *pNativeFieldDescs = pMethodTable->GetNativeLayoutInfo()->GetNativeFieldDescriptors(); - NativeFieldCategory nfc = pNativeFieldDescs->GetCategory(); - if (nfc == NativeFieldCategory::NESTED) - { - pMethodTable = pNativeFieldDescs->GetNestedNativeMethodTable(); - ret = IsOnlyOneField(pMethodTable); - } - else if (nfc != NativeFieldCategory::ILLEGAL) - { - ret = true; - } + ret = true; } } - else - { - ret = false; - } + } + else + { + ret = false; } } _End_arg: @@ -3442,535 +3442,151 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl #endif #if defined(TARGET_RISCV64) -int MethodTable::GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) +static bool HandleInlineArray(int elementTypeIndex, int nElements, StructFloatFieldInfoFlags types[2], int& typeIndex) { - TypeHandle th(cls); + int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex; + if (nFlattenedFieldsPerElement == 0) + return true; - int size = STRUCT_NO_FLOAT_FIELD; + assert(nFlattenedFieldsPerElement == 1 || nFlattenedFieldsPerElement == 2); - if (!th.IsTypeDesc()) + if (nElements > 2) + return false; + + if (nElements == 2) { - MethodTable* pMethodTable = th.AsMethodTable(); - if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) + if (typeIndex + nFlattenedFieldsPerElement > 2) + return false; + + assert(elementTypeIndex == 0); + assert(typeIndex == 1); + types[typeIndex] = types[elementTypeIndex]; // duplicate the array element type + } + return true; +} + +static bool FlattenFieldTypes(TypeHandle th, StructFloatFieldInfoFlags types[2], int& typeIndex) +{ + bool isManaged = !th.IsTypeDesc(); + MethodTable* pMT = isManaged ? th.AsMethodTable() : th.AsNativeValueType(); + int nFields = isManaged ? pMT->GetNumIntroducedInstanceFields() : pMT->GetNativeLayoutInfo()->GetNumFields(); + + // TODO: templatize isManaged and use if constexpr for differences when we migrate to C++17 + // because the logic for both branches is nearly the same. + if (isManaged) + { + FieldDesc* fields = pMT->GetApproxFieldDescListRaw(); + int elementTypeIndex = typeIndex; + for (int i = 0; i < nFields; ++i) { - DWORD numIntroducedFields = pMethodTable->GetNumIntroducedInstanceFields(); + if (i > 0 && fields[i-1].GetOffset() + fields[i-1].GetSize() > fields[i].GetOffset()) + return false; // overlapping fields - if (numIntroducedFields == 1) + CorElementType type = fields[i].GetFieldType(); + if (type == ELEMENT_TYPE_VALUETYPE) { - FieldDesc *pFieldStart = pMethodTable->GetApproxFieldDescListRaw(); + MethodTable* nested = fields[i].GetApproxFieldTypeHandleThrowing().GetMethodTable(); + if (!FlattenFieldTypes(TypeHandle(nested), types, typeIndex)) + return false; + } + else if (fields[i].GetSize() <= TARGET_POINTER_SIZE) + { + if (typeIndex >= 2) + return false; - CorElementType fieldType = pFieldStart[0].GetFieldType(); + StructFloatFieldInfoFlags retType = StructFloatFieldInfoFlags( + (CorTypeInfo::IsFloat_NoThrow(type) ? STRUCT_FLOAT_FIELD_FIRST : 0) | + (CorTypeInfo::Size_NoThrow(type) == TARGET_POINTER_SIZE ? STRUCT_FIRST_FIELD_SIZE_IS8 : 0)); + types[typeIndex++] = retType; + } + else + { + return false; + } + } - // InlineArray types and fixed buffer types have implied repeated fields. - // Checking if a type is an InlineArray type is cheap, so we'll do that first. - bool hasImpliedRepeatedFields = HasImpliedRepeatedFields(pMethodTable); + if (HasImpliedRepeatedFields(pMT)) // inline array or fixed buffer + { + assert(nFields == 1); + int nElements = pMT->GetNumInstanceFieldBytes() / fields[0].GetSize(); + if (!HandleInlineArray(elementTypeIndex, nElements, types, typeIndex)) + return false; + } + } + else // native layout + { + const NativeFieldDescriptor* fields = pMT->GetNativeLayoutInfo()->GetNativeFieldDescriptors(); + for (int i = 0; i < nFields; ++i) + { + if (i > 0 && fields[i-1].GetExternalOffset() + fields[i-1].NativeSize() > fields[i].GetExternalOffset()) + return false; // overlapping fields - if (hasImpliedRepeatedFields) - { - numIntroducedFields = pMethodTable->GetNumInstanceFieldBytes() / pFieldStart->GetSize(); - if (numIntroducedFields > 2) - { - goto _End_arg; - } + NativeFieldCategory category = fields[i].GetCategory(); + if (category == NativeFieldCategory::NESTED) + { + int elementTypeIndex = typeIndex; - if (fieldType == ELEMENT_TYPE_R4) - { - if (numIntroducedFields == 1) - { - size = STRUCT_FLOAT_FIELD_ONLY_ONE; - } - else if (numIntroducedFields == 2) - { - size = STRUCT_FLOAT_FIELD_ONLY_TWO; - } - goto _End_arg; - } - else if (fieldType == ELEMENT_TYPE_R8) - { - if (numIntroducedFields == 1) - { - size = STRUCT_FLOAT_FIELD_ONLY_ONE | STRUCT_FIRST_FIELD_SIZE_IS8; - } - else if (numIntroducedFields == 2) - { - size = STRUCT_FIELD_TWO_DOUBLES; - } - goto _End_arg; - } - } + MethodTable* nested = fields[i].GetNestedNativeMethodTable(); + if (!FlattenFieldTypes(TypeHandle(nested), types, typeIndex)) + return false; - if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) - { - if (fieldType == ELEMENT_TYPE_R4) - { - size = STRUCT_FLOAT_FIELD_ONLY_ONE; - } - else if (fieldType == ELEMENT_TYPE_R8) - { - size = STRUCT_FLOAT_FIELD_ONLY_ONE | STRUCT_FIRST_FIELD_SIZE_IS8; - } - } - else if (fieldType == ELEMENT_TYPE_VALUETYPE) - { - pMethodTable = pFieldStart->GetApproxFieldTypeHandleThrowing().GetMethodTable(); - size = GetRiscV64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable); - } + // In native layout fixed arrays are marked as NESTED just like structs + int nElements = fields[i].GetNumElements(); + if (!HandleInlineArray(elementTypeIndex, nElements, types, typeIndex)) + return false; } - else if (numIntroducedFields == 2) + else if (fields[i].NativeSize() <= TARGET_POINTER_SIZE) { - FieldDesc *pFieldSecond; - FieldDesc *pFieldFirst = pMethodTable->GetApproxFieldDescListRaw(); - if (pFieldFirst->GetOffset() == 0) - { - pFieldSecond = pFieldFirst + 1; - } - else - { - pFieldSecond = pFieldFirst; - pFieldFirst = pFieldFirst + 1; - } - assert(pFieldFirst->GetOffset() == 0); + if (typeIndex >= 2) + return false; - if (pFieldFirst->GetSize() > 8) - { - goto _End_arg; - } + StructFloatFieldInfoFlags type = StructFloatFieldInfoFlags( + (category == NativeFieldCategory::FLOAT ? STRUCT_FLOAT_FIELD_FIRST : 0) | + (fields[i].NativeSize() == TARGET_POINTER_SIZE ? STRUCT_FIRST_FIELD_SIZE_IS8 : 0)); + types[typeIndex++] = type; + } + else + { + return false; + } + } + } + return true; +} - if (pFieldFirst->GetSize() > pFieldSecond->GetOffset()) - { - goto _End_arg; - } +int MethodTable::GetRiscV64PassStructInRegisterFlags(TypeHandle th) +{ + if (th.GetSize() > ENREGISTERED_PARAMTYPE_MAXSIZE) + return STRUCT_NO_FLOAT_FIELD; - CorElementType fieldType = pFieldFirst[0].GetFieldType(); - if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) - { - if (fieldType == ELEMENT_TYPE_R4) - { - size = STRUCT_FLOAT_FIELD_FIRST; - } - else if (fieldType == ELEMENT_TYPE_R8) - { - size = STRUCT_FIRST_FIELD_DOUBLE; - } - else if (pFieldFirst[0].GetSize() == 8) - { - size = STRUCT_FIRST_FIELD_SIZE_IS8; - } + StructFloatFieldInfoFlags types[2] = {STRUCT_NO_FLOAT_FIELD, STRUCT_NO_FLOAT_FIELD}; + int nFields = 0; + if (!FlattenFieldTypes(th, types, nFields) || nFields == 0) + return STRUCT_NO_FLOAT_FIELD; - } - else if (fieldType == ELEMENT_TYPE_VALUETYPE) - { - pMethodTable = pFieldFirst->GetApproxFieldTypeHandleThrowing().GetMethodTable(); - if (IsOnlyOneField(pMethodTable)) - { - size = GetRiscV64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable); - if ((size & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) - { - size = pFieldFirst[0].GetSize() == 8 ? STRUCT_FIRST_FIELD_DOUBLE : STRUCT_FLOAT_FIELD_FIRST; - } - else if (size == STRUCT_NO_FLOAT_FIELD) - { - size = pFieldFirst[0].GetSize() == 8 ? STRUCT_FIRST_FIELD_SIZE_IS8: 0; - } - else - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } - } - else - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } - } - else if (pFieldFirst[0].GetSize() == 8) - { - size = STRUCT_FIRST_FIELD_SIZE_IS8; - } + assert(nFields == 1 || nFields == 2); - fieldType = pFieldSecond[0].GetFieldType(); - if (pFieldSecond[0].GetSize() > 8) - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } - else if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) - { - if (fieldType == ELEMENT_TYPE_R4) - { - size = size & STRUCT_FLOAT_FIELD_FIRST ? (size ^ STRUCT_MERGE_FIRST_SECOND) : (size | STRUCT_FLOAT_FIELD_SECOND); - } - else if (fieldType == ELEMENT_TYPE_R8) - { - size = size & STRUCT_FLOAT_FIELD_FIRST ? (size ^ STRUCT_MERGE_FIRST_SECOND_8) : (size | STRUCT_SECOND_FIELD_DOUBLE); - } - else if ((size & STRUCT_FLOAT_FIELD_FIRST) == 0) - { - size = STRUCT_NO_FLOAT_FIELD; - } - else if (pFieldSecond[0].GetSize() == 8) - { - size |= STRUCT_SECOND_FIELD_SIZE_IS8; - } - } - else if (fieldType == ELEMENT_TYPE_VALUETYPE) - { - pMethodTable = pFieldSecond[0].GetApproxFieldTypeHandleThrowing().GetMethodTable(); - if (IsOnlyOneField(pMethodTable)) - { - int size2 = GetRiscV64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable); - if ((size2 & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) - { - if (pFieldSecond[0].GetSize() == 8) - { - size = size & STRUCT_FLOAT_FIELD_FIRST ? (size ^ STRUCT_MERGE_FIRST_SECOND_8) : (size | STRUCT_SECOND_FIELD_DOUBLE); - } - else - { - size = size & STRUCT_FLOAT_FIELD_FIRST ? (size ^ STRUCT_MERGE_FIRST_SECOND) : (size | STRUCT_FLOAT_FIELD_SECOND); - } - } - else if ((size & STRUCT_FLOAT_FIELD_FIRST) == 0) - { - size = STRUCT_NO_FLOAT_FIELD; - } - else if (size2 == STRUCT_NO_FLOAT_FIELD) - { - size |= pFieldSecond[0].GetSize() == 8 ? STRUCT_SECOND_FIELD_SIZE_IS8 : 0; - } - else - { - size = STRUCT_NO_FLOAT_FIELD; - } - } - else - { - size = STRUCT_NO_FLOAT_FIELD; - } - } - else if ((size & STRUCT_FLOAT_FIELD_FIRST) == 0) - { - size = STRUCT_NO_FLOAT_FIELD; - } - else if (pFieldSecond[0].GetSize() == 8) - { - size |= STRUCT_SECOND_FIELD_SIZE_IS8; - } - } - } - } - else - { - MethodTable* pMethodTable = th.AsNativeValueType(); - - if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) - { - DWORD numIntroducedFields = pMethodTable->GetNativeLayoutInfo()->GetNumFields(); - FieldDesc *pFieldStart = nullptr; - - if (numIntroducedFields == 1) - { - pFieldStart = pMethodTable->GetApproxFieldDescListRaw(); - - CorElementType fieldType = pFieldStart->GetFieldType(); - - // InlineArray types and fixed buffer types have implied repeated fields. - // Checking if a type is an InlineArray type is cheap, so we'll do that first. - bool hasImpliedRepeatedFields = HasImpliedRepeatedFields(pMethodTable); - - if (hasImpliedRepeatedFields) - { - numIntroducedFields = pMethodTable->GetNumInstanceFieldBytes() / pFieldStart->GetSize(); - if (numIntroducedFields > 2) - { - goto _End_arg; - } - - if (fieldType == ELEMENT_TYPE_R4) - { - if (numIntroducedFields == 1) - { - size = STRUCT_FLOAT_FIELD_ONLY_ONE; - } - else if (numIntroducedFields == 2) - { - size = STRUCT_FLOAT_FIELD_ONLY_TWO; - } - goto _End_arg; - } - else if (fieldType == ELEMENT_TYPE_R8) - { - if (numIntroducedFields == 1) - { - size = STRUCT_FLOAT_FIELD_ONLY_ONE | STRUCT_FIRST_FIELD_SIZE_IS8; - } - else if (numIntroducedFields == 2) - { - size = STRUCT_FIELD_TWO_DOUBLES; - } - goto _End_arg; - } - } + static_assert((STRUCT_FLOAT_FIELD_SECOND | STRUCT_SECOND_FIELD_SIZE_IS8) + == (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FIRST_FIELD_SIZE_IS8) << 1, + "SECOND flags need to be FIRST shifted by 1"); + int flags = types[0] | (types[1] << 1); - if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) - { - if (fieldType == ELEMENT_TYPE_R4) - { - size = STRUCT_FLOAT_FIELD_ONLY_ONE; - } - else if (fieldType == ELEMENT_TYPE_R8) - { - size = STRUCT_FLOAT_FIELD_ONLY_ONE | STRUCT_FIRST_FIELD_SIZE_IS8; - } - } - else if (fieldType == ELEMENT_TYPE_VALUETYPE) - { - const NativeFieldDescriptor *pNativeFieldDescs = pMethodTable->GetNativeLayoutInfo()->GetNativeFieldDescriptors(); - NativeFieldCategory nfc = pNativeFieldDescs->GetCategory(); - if (nfc == NativeFieldCategory::NESTED) - { - pMethodTable = pNativeFieldDescs->GetNestedNativeMethodTable(); - size = GetRiscV64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable); - return size; - } - else if (nfc == NativeFieldCategory::FLOAT) - { - if (pFieldStart->GetSize() == 4) - { - size = STRUCT_FLOAT_FIELD_ONLY_ONE; - } - else if (pFieldStart->GetSize() == 8) - { - size = STRUCT_FLOAT_FIELD_ONLY_ONE | STRUCT_FIRST_FIELD_SIZE_IS8; - } - } - } - } - else if (numIntroducedFields == 2) - { - pFieldStart = pMethodTable->GetApproxFieldDescListRaw(); + static const int bothFloat = STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND; + if ((flags & bothFloat) == 0) + return STRUCT_NO_FLOAT_FIELD; - if (pFieldStart->GetSize() > 8) - { - goto _End_arg; - } - - if (pFieldStart->GetOffset() || !pFieldStart[1].GetOffset() || (pFieldStart[0].GetSize() > pFieldStart[1].GetOffset())) - { - goto _End_arg; - } - - CorElementType fieldType = pFieldStart[0].GetFieldType(); - if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) - { - if (fieldType == ELEMENT_TYPE_R4) - { - size = STRUCT_FLOAT_FIELD_FIRST; - } - else if (fieldType == ELEMENT_TYPE_R8) - { - size = STRUCT_FIRST_FIELD_DOUBLE; - } - else if (pFieldStart[0].GetSize() == 8) - { - size = STRUCT_FIRST_FIELD_SIZE_IS8; - } - - fieldType = pFieldStart[1].GetFieldType(); - if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) - { - if (fieldType == ELEMENT_TYPE_R4) - { - size = size & STRUCT_FLOAT_FIELD_FIRST ? (size ^ STRUCT_MERGE_FIRST_SECOND) : (size | STRUCT_FLOAT_FIELD_SECOND); - } - else if (fieldType == ELEMENT_TYPE_R8) - { - size = size & STRUCT_FLOAT_FIELD_FIRST ? (size ^ STRUCT_MERGE_FIRST_SECOND_8) : (size | STRUCT_SECOND_FIELD_DOUBLE); - } - else if ((size & STRUCT_FLOAT_FIELD_FIRST) == 0) - { - size = STRUCT_NO_FLOAT_FIELD; - } - else if (pFieldStart[1].GetSize() == 8) - { - size |= STRUCT_SECOND_FIELD_SIZE_IS8; - } - goto _End_arg; - } - } - else if (fieldType == ELEMENT_TYPE_VALUETYPE) - { - const NativeFieldDescriptor *pNativeFieldDescs = pMethodTable->GetNativeLayoutInfo()->GetNativeFieldDescriptors(); - - NativeFieldCategory nfc = pNativeFieldDescs->GetCategory(); - - if (nfc == NativeFieldCategory::NESTED) - { - if (pNativeFieldDescs->GetNumElements() != 1) - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } - - MethodTable* pMethodTable2 = pNativeFieldDescs->GetNestedNativeMethodTable(); - - if (!IsOnlyOneField(pMethodTable2)) - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } - - size = GetRiscV64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable2); - if ((size & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) - { - if (pFieldStart->GetSize() == 8) - { - size = STRUCT_FIRST_FIELD_DOUBLE; - } - else - { - size = STRUCT_FLOAT_FIELD_FIRST; - } - } - else if (pFieldStart->GetSize() == 8) - { - size = STRUCT_FIRST_FIELD_SIZE_IS8; - } - else - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } - } - else if (nfc == NativeFieldCategory::FLOAT) - { - if (pFieldStart[0].GetSize() == 4) - { - size = STRUCT_FLOAT_FIELD_FIRST; - } - else if (pFieldStart[0].GetSize() == 8) - { - _ASSERTE((pMethodTable->GetNativeSize() == 8) || (pMethodTable->GetNativeSize() == 16)); - size = STRUCT_FIRST_FIELD_DOUBLE; - } - } - else if (pFieldStart[0].GetSize() == 8) - { - size = STRUCT_FIRST_FIELD_SIZE_IS8; - } - } - else if (pFieldStart[0].GetSize() == 8) - { - size = STRUCT_FIRST_FIELD_SIZE_IS8; - } - - fieldType = pFieldStart[1].GetFieldType(); - if (pFieldStart[1].GetSize() > 8) - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } - else if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) - { - if (fieldType == ELEMENT_TYPE_R4) - { - size = size & STRUCT_FLOAT_FIELD_FIRST ? (size ^ STRUCT_MERGE_FIRST_SECOND) : (size | STRUCT_FLOAT_FIELD_SECOND); - } - else if (fieldType == ELEMENT_TYPE_R8) - { - size = size & STRUCT_FLOAT_FIELD_FIRST ? (size ^ STRUCT_MERGE_FIRST_SECOND_8) : (size | STRUCT_SECOND_FIELD_DOUBLE); - } - else if ((size & STRUCT_FLOAT_FIELD_FIRST) == 0) - { - size = STRUCT_NO_FLOAT_FIELD; - } - else if (pFieldStart[1].GetSize() == 8) - { - size |= STRUCT_SECOND_FIELD_SIZE_IS8; - } - - // Pass with two integer registers in `struct {int a, int b, float/double c}` cases - if ((size | STRUCT_FIRST_FIELD_SIZE_IS8 | STRUCT_FLOAT_FIELD_SECOND) == size) - { - size = STRUCT_NO_FLOAT_FIELD; - } - } - else if (fieldType == ELEMENT_TYPE_VALUETYPE) - { - const NativeFieldDescriptor *pNativeFieldDescs = pMethodTable->GetNativeLayoutInfo()->GetNativeFieldDescriptors(); - NativeFieldCategory nfc = pNativeFieldDescs[1].GetCategory(); - - if (nfc == NativeFieldCategory::NESTED) - { - if (pNativeFieldDescs[1].GetNumElements() != 1) - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } - - MethodTable* pMethodTable2 = pNativeFieldDescs[1].GetNestedNativeMethodTable(); - - if (!IsOnlyOneField(pMethodTable2)) - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } - - if ((GetRiscV64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable2) & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) - { - if (pFieldStart[1].GetSize() == 4) - { - size = size & STRUCT_FLOAT_FIELD_FIRST ? (size ^ STRUCT_MERGE_FIRST_SECOND) : (size | STRUCT_FLOAT_FIELD_SECOND); - } - else if (pFieldStart[1].GetSize() == 8) - { - size = size & STRUCT_FLOAT_FIELD_FIRST ? (size ^ STRUCT_MERGE_FIRST_SECOND_8) : (size | STRUCT_SECOND_FIELD_DOUBLE); - } - } - else if ((size & STRUCT_FLOAT_FIELD_FIRST) == 0) - { - size = STRUCT_NO_FLOAT_FIELD; - } - else if (pFieldStart[1].GetSize() == 8) - { - size |= STRUCT_SECOND_FIELD_SIZE_IS8; - } - } - else if (nfc == NativeFieldCategory::FLOAT) - { - if (pFieldStart[1].GetSize() == 4) - { - size = size & STRUCT_FLOAT_FIELD_FIRST ? (size ^ STRUCT_MERGE_FIRST_SECOND) : (size | STRUCT_FLOAT_FIELD_SECOND); - } - else if (pFieldStart[1].GetSize() == 8) - { - size = size & STRUCT_FLOAT_FIELD_FIRST ? (size ^ STRUCT_MERGE_FIRST_SECOND_8) : (size | STRUCT_SECOND_FIELD_DOUBLE); - } - } - else if ((size & STRUCT_FLOAT_FIELD_FIRST) == 0) - { - size = STRUCT_NO_FLOAT_FIELD; - } - else if (pFieldStart[1].GetSize() == 8) - { - size |= STRUCT_SECOND_FIELD_SIZE_IS8; - } - } - else if ((size & STRUCT_FLOAT_FIELD_FIRST) == 0) - { - size = STRUCT_NO_FLOAT_FIELD; - } - else if (pFieldStart[1].GetSize() == 8) - { - size |= STRUCT_SECOND_FIELD_SIZE_IS8; - } - } - } + if ((flags & bothFloat) == bothFloat) + { + assert(nFields == 2); + flags ^= (bothFloat | STRUCT_FLOAT_FIELD_ONLY_TWO); // replace bothFloat with ONLY_TWO + } + else if (nFields == 1) + { + assert((flags & STRUCT_FLOAT_FIELD_FIRST) != 0); + flags ^= (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_ONE); // replace FIRST with ONLY_ONE } -_End_arg: - return size; + return flags; } #endif diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index e6c3c8c3aa2bec..b933cf6c3cafdc 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -824,13 +824,11 @@ class MethodTable // during object construction. void CheckRunClassInitAsIfConstructingThrowing(); -#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - static bool IsOnlyOneField(MethodTable * pMT); #if defined(TARGET_LOONGARCH64) + static bool IsOnlyOneField(MethodTable * pMT); static int GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE clh); #elif defined(TARGET_RISCV64) - static int GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE clh); -#endif + static int GetRiscV64PassStructInRegisterFlags(TypeHandle th); #endif #if defined(UNIX_AMD64_ABI_ITF)