From 02e348b505ec5d95621a662835abd6d915962801 Mon Sep 17 00:00:00 2001 From: Xu Liangyu Date: Thu, 9 May 2024 21:47:45 +0800 Subject: [PATCH] [LoongArch64] Simplify flags for passing struct in registers. (#102041) Change-Id: Idbe644c0bc5baeb53a53e16731824e28aacf67a0 --- .../LoongArch64PassStructInRegister.cs | 255 +++---- src/coreclr/vm/callingconvention.h | 16 +- src/coreclr/vm/jitinterface.cpp | 2 +- src/coreclr/vm/methodtable.cpp | 680 ++---------------- src/coreclr/vm/methodtable.h | 3 +- 5 files changed, 139 insertions(+), 817 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs b/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs index 856b9905a1fb4..250ea428c44d9 100644 --- a/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs +++ b/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs @@ -1,192 +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 LoongArch64PassStructInRegister { - public static uint GetLoongArch64PassStructInRegisterFlags(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; + prevField = field; - bool hasImpliedRepeatedFields = mdType.HasImpliedRepeatedFields(); + TypeFlags category = field.FieldType.Category; + if (category == TypeFlags.ValueType) + { + TypeDesc nested = field.FieldType; + if (!FlattenFieldTypes(nested, types, ref typeIndex)) + return false; + } + else if (field.FieldType.GetElementSize().AsInt <= TARGET_POINTER_SIZE) + { + if (typeIndex >= 2) + return false; - if (hasImpliedRepeatedFields) - { - numIntroducedFields = typeDesc.GetElementSize().AsInt / firstFieldSize; - if (numIntroducedFields > 2) + 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 { - return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; + return false; } } - int fieldIndex = 0; - foreach (FieldDesc field in typeDesc.GetFields()) + if ((td as MetadataType).HasImpliedRepeatedFields()) { - if (field.IsStatic) - { - continue; - } + Debug.Assert(nFields == 1); + int nElements = td.GetElementSize().AsInt / prevField.FieldType.GetElementSize().AsInt; + if (!HandleInlineArray(elementTypeIndex, nElements, types, ref typeIndex)) + return false; + } + return true; + } - Debug.Assert(fieldIndex < numIntroducedFields); + public static uint GetLoongArch64PassStructInRegisterFlags(TypeDesc td) + { + if (td.GetElementSize().AsInt > ENREGISTERED_PARAMTYPE_MAXSIZE) + return (uint)STRUCT_NO_FLOAT_FIELD; - 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; - } - } - 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; - } - } - break; - - case TypeFlags.ValueType: - //case TypeFlags.Class: - //case TypeFlags.Array: - //case TypeFlags.SzArray: - { - uint floatFieldFlags2 = GetLoongArch64PassStructInRegisterFlags(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 ((numIntroducedFields == 2) && (field.FieldType.Category == TypeFlags.Class)) - { - return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; - } - - 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; - } - } + 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; - fieldIndex++; - } + 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 3e85ecd65947e..7ec2525d48ef2 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -1692,17 +1692,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::GetLoongArch64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable); + flags = MethodTable::GetLoongArch64PassStructInRegisterFlags(thValueType); if (flags & STRUCT_HAS_FLOAT_FIELDS_MASK) { cFPRegs = (flags & STRUCT_FLOAT_FIELD_ONLY_TWO) ? 2 : 1; @@ -2019,9 +2009,7 @@ void ArgIteratorTemplate::ComputeReturnFlags() if (size <= ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE) { assert(!thValueType.IsTypeDesc()); - - MethodTable *pMethodTable = thValueType.AsMethodTable(); - flags = (MethodTable::GetLoongArch64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable) & 0xff) << RETURN_FP_SIZE_SHIFT; + flags = (MethodTable::GetLoongArch64PassStructInRegisterFlags(thValueType) & 0xff) << RETURN_FP_SIZE_SHIFT; break; } #elif defined(TARGET_RISCV64) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 394b87a187396..0324a02c2c750 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9632,7 +9632,7 @@ uint32_t CEEInfo::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE c uint32_t size = STRUCT_NO_FLOAT_FIELD; #if defined(TARGET_LOONGARCH64) - size = (uint32_t)MethodTable::GetLoongArch64PassStructInRegisterFlags(cls); + size = (uint32_t)MethodTable::GetLoongArch64PassStructInRegisterFlags(TypeHandle(cls)); #endif EE_TO_JIT_TRANSITION_LEAF(); diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index aa836100071b5..51b7d3b1d381d 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -2813,646 +2813,7 @@ void MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHe #endif // defined(UNIX_AMD64_ABI_ITF) -#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(); - DWORD numIntroducedFields = pMethodTable->GetNumIntroducedInstanceFields(); - - if (numIntroducedFields == 1) - { - FieldDesc *pFieldStart = pMethodTable->GetApproxFieldDescListRaw(); - - 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); - - if (hasImpliedRepeatedFields) - { - numIntroducedFields = pMethodTable->GetNumInstanceFieldBytes() / pFieldStart->GetSize(); - if (numIntroducedFields != 1) - { - goto _End_arg; - } - } - - if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) - { - ret = true; - } - else if (fieldType == ELEMENT_TYPE_VALUETYPE) - { - pMethodTable = pFieldStart->GetApproxFieldTypeHandleThrowing().GetMethodTable(); - if (pMethodTable->GetNumIntroducedInstanceFields() == 1) - { - ret = IsOnlyOneField(pMethodTable); - } - } - } - } - else - { - MethodTable* pMethodTable = th.AsNativeValueType(); - 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 != 1) - { - goto _End_arg; - } - } - - 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) - { - pMethodTable = pNativeFieldDescs->GetNestedNativeMethodTable(); - ret = IsOnlyOneField(pMethodTable); - } - else if (nfc != NativeFieldCategory::ILLEGAL) - { - ret = true; - } - } - } - else - { - ret = false; - } - } -_End_arg: - - return ret; -} -#endif - -#if defined(TARGET_LOONGARCH64) -int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) -{ - TypeHandle th(cls); - - int size = STRUCT_NO_FLOAT_FIELD; - - if (!th.IsTypeDesc()) - { - MethodTable* pMethodTable = th.AsMethodTable(); - if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) - { - DWORD numIntroducedFields = pMethodTable->GetNumIntroducedInstanceFields(); - - if (numIntroducedFields == 1) - { - FieldDesc *pFieldStart = pMethodTable->GetApproxFieldDescListRaw(); - - 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); - - 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; - } - } - - 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 = GetLoongArch64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable); - } - } - else if (numIntroducedFields == 2) - { - FieldDesc *pFieldSecond; - FieldDesc *pFieldFirst = pMethodTable->GetApproxFieldDescListRaw(); - if (pFieldFirst->GetOffset() == 0) - { - pFieldSecond = pFieldFirst + 1; - } - else - { - pFieldSecond = pFieldFirst; - pFieldFirst = pFieldFirst + 1; - } - assert(pFieldFirst->GetOffset() == 0); - - if (pFieldFirst->GetSize() > 8) - { - goto _End_arg; - } - - if (pFieldFirst->GetSize() > pFieldSecond->GetOffset()) - { - goto _End_arg; - } - - 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; - } - - } - else if (fieldType == ELEMENT_TYPE_VALUETYPE) - { - pMethodTable = pFieldFirst->GetApproxFieldTypeHandleThrowing().GetMethodTable(); - if (IsOnlyOneField(pMethodTable)) - { - size = GetLoongArch64PassStructInRegisterFlags((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; - } - - 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 = GetLoongArch64PassStructInRegisterFlags((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; - } - } - - 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 = GetLoongArch64PassStructInRegisterFlags((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(); - - 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 = GetLoongArch64PassStructInRegisterFlags((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 (fieldType == ELEMENT_TYPE_CLASS) - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } - 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; - } - } - 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 ((GetLoongArch64PassStructInRegisterFlags((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 (fieldType == ELEMENT_TYPE_CLASS) - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } - 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; - } - } - } - } -_End_arg: - - return size; -} -#endif - -#if defined(TARGET_RISCV64) +#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) static bool HandleInlineArray(int elementTypeIndex, int nElements, StructFloatFieldInfoFlags types[2], int& typeIndex) { int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex; @@ -3564,7 +2925,46 @@ static bool FlattenFieldTypes(TypeHandle th, StructFloatFieldInfoFlags types[2], } return true; } +#endif + +#if defined(TARGET_LOONGARCH64) +int MethodTable::GetLoongArch64PassStructInRegisterFlags(TypeHandle th) +{ + if (th.GetSize() > ENREGISTERED_PARAMTYPE_MAXSIZE) + return STRUCT_NO_FLOAT_FIELD; + + 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; + + assert(nFields == 1 || nFields == 2); + 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); + + static const int bothFloat = STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND; + if ((flags & bothFloat) == 0) + return STRUCT_NO_FLOAT_FIELD; + + 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 + } + + return flags; +} +#endif + +#if defined(TARGET_RISCV64) int MethodTable::GetRiscV64PassStructInRegisterFlags(TypeHandle th) { if (th.GetSize() > ENREGISTERED_PARAMTYPE_MAXSIZE) diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 3b498200cecb4..cb8a7ce9f9c24 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -825,8 +825,7 @@ class MethodTable void CheckRunClassInitAsIfConstructingThrowing(); #if defined(TARGET_LOONGARCH64) - static bool IsOnlyOneField(MethodTable * pMT); - static int GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE clh); + static int GetLoongArch64PassStructInRegisterFlags(TypeHandle th); #elif defined(TARGET_RISCV64) static int GetRiscV64PassStructInRegisterFlags(TypeHandle th); #endif