From af2f32a24f38fd33aa1b54c130ce331ba96e3d99 Mon Sep 17 00:00:00 2001 From: qiaopengcheng Date: Tue, 19 Jul 2022 17:22:08 +0800 Subject: [PATCH] amend the LoongArch64-ABI for GCstress and NullableObject. --- src/coreclr/vm/argdestination.h | 52 ++++-- src/coreclr/vm/callhelpers.cpp | 2 +- src/coreclr/vm/gcinfodecoder.cpp | 2 +- src/coreclr/vm/methodtable.cpp | 276 +++++++++++++++++++++++++------ src/coreclr/vm/methodtable.h | 1 + src/coreclr/vm/object.cpp | 2 +- 6 files changed, 273 insertions(+), 62 deletions(-) diff --git a/src/coreclr/vm/argdestination.h b/src/coreclr/vm/argdestination.h index dcf86a87bb62d..3890a0f5098de 100644 --- a/src/coreclr/vm/argdestination.h +++ b/src/coreclr/vm/argdestination.h @@ -90,7 +90,13 @@ class ArgDestination } #ifndef DACCESS_COMPILE - void CopyStructToRegisters(void *src, int fieldBytes) + // Copy struct argument into registers described by the current ArgDestination. + // Arguments: + // src = source data of the structure + // fieldBytes - size of the structure + // destOffset - nonzero when copying values into Nullable, it is the offset + // of the T value inside of the Nullable + void CopyStructToRegisters(void *src, int fieldBytes, int destOffset) { _ASSERTE(IsStructPassedInRegs()); _ASSERTE(fieldBytes <= 16); @@ -106,33 +112,59 @@ class ArgDestination } else if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_FIRST) != 0) { // the first field is float or double. + _ASSERTE(m_argLocDescForStructInRegs->m_cFloatReg == 1); + _ASSERTE(m_argLocDescForStructInRegs->m_cGenReg == 1); + _ASSERTE((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_SECOND) == 0);//the second field is integer. + if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_FIRST_FIELD_SIZE_IS8) == 0) + { *(INT64*)((char*)m_base + argOfs) = *(INT32*)src; // the first field is float + } else + { *(UINT64*)((char*)m_base + argOfs) = *(UINT64*)src; // the first field is double. - _ASSERTE(m_argLocDescForStructInRegs->m_cFloatReg == 1); - _ASSERTE(m_argLocDescForStructInRegs->m_cGenReg == 1); - _ASSERTE((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_SECOND) == 0);//the second field is integer. + } + argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_argLocDescForStructInRegs->m_idxGenReg * 8; if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_HAS_8BYTES_FIELDS_MASK) != 0) + { *(UINT64*)((char*)m_base + argOfs) = *((UINT64*)src + 1); + } else + { *(INT64*)((char*)m_base + argOfs) = *((INT32*)src + 1); // the second field is int32. + } } else if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_SECOND) != 0) { // the second field is float or double. - *(UINT64*)((char*)m_base + argOfs) = *(UINT64*)src; // NOTE: here ignoring the first size. - if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_HAS_8BYTES_FIELDS_MASK) == 0) - *(UINT64*)((char*)m_base + argOfs) = *((INT32*)src + 1); // the second field is int32. - else - *(UINT64*)((char*)m_base + argOfs) = *((UINT64*)src + 1); _ASSERTE(m_argLocDescForStructInRegs->m_cFloatReg == 1); _ASSERTE(m_argLocDescForStructInRegs->m_cGenReg == 1); _ASSERTE((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_FIRST) == 0);//the first field is integer. - argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_argLocDescForStructInRegs->m_idxGenReg * 8; + + // destOffset - nonzero when copying values into Nullable, it is the offset of the T value inside of the Nullable. + // here the first field maybe Nullable. + if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_HAS_8BYTES_FIELDS_MASK) == 0) + { + // the second field is float. + *(INT64*)((char*)m_base + argOfs) = destOffset == 0 ? *((INT32*)src + 1) : *(INT32*)src; + } + else + { + // the second field is double. + *(UINT64*)((char*)m_base + argOfs) = destOffset == 0 ? *((UINT64*)src + 1) : *(UINT64*)src; + } + + if (0 == destOffset) + { + // NOTE: here ignoring the first size. + argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_argLocDescForStructInRegs->m_idxGenReg * 8; + *(UINT64*)((char*)m_base + argOfs) = *(UINT64*)src; + } } else + { _ASSERTE(!"---------UNReachable-------LoongArch64!!!"); + } } #endif // !DACCESS_COMPILE diff --git a/src/coreclr/vm/callhelpers.cpp b/src/coreclr/vm/callhelpers.cpp index a439136cd704c..b525f3378ddae 100644 --- a/src/coreclr/vm/callhelpers.cpp +++ b/src/coreclr/vm/callhelpers.cpp @@ -462,7 +462,7 @@ void MethodDescCallSite::CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT * #elif defined(TARGET_LOONGARCH64) if (argDest.IsStructPassedInRegs()) { - argDest.CopyStructToRegisters(pSrc, stackSize); + argDest.CopyStructToRegisters(pSrc, stackSize, 0); } else #endif // TARGET_LOONGARCH64 diff --git a/src/coreclr/vm/gcinfodecoder.cpp b/src/coreclr/vm/gcinfodecoder.cpp index 64853c8d3848e..ab87649a1ebc7 100644 --- a/src/coreclr/vm/gcinfodecoder.cpp +++ b/src/coreclr/vm/gcinfodecoder.cpp @@ -1810,7 +1810,7 @@ bool GcInfoDecoder::IsScratchRegister(int regNum, PREGDISPLAY pRD) { _ASSERTE(regNum >= 0 && regNum <= 31); - return (regNum <= 21 && regNum >= 4); + return (regNum <= 21 && ((regNum >= 4) || (regNum == 1))); } bool GcInfoDecoder::IsScratchStackSlot(INT32 spOffset, GcStackSlotBase spBase, PREGDISPLAY pRD) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 444dd1ef4c503..b2276017f417c 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -2853,6 +2853,115 @@ void MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHe #endif // defined(UNIX_AMD64_ABI_ITF) #if defined(TARGET_LOONGARCH64) + +bool MethodTable::IsLoongArch64OnlyOneField(MethodTable * pMT) +{ + TypeHandle th(pMT); + + bool useNativeLayout = false; + bool ret = false; + MethodTable* pMethodTable = nullptr; + + if (!th.IsTypeDesc()) + { + pMethodTable = th.AsMethodTable(); + if (pMethodTable->HasLayout()) + { + useNativeLayout = true; + } + else if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) + { + DWORD numIntroducedFields = pMethodTable->GetNumIntroducedInstanceFields(); + + if (numIntroducedFields == 1) + { + FieldDesc *pFieldStart = pMethodTable->GetApproxFieldDescListRaw(); + + CorElementType fieldType = pFieldStart[0].GetFieldType(); + + if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) + { + ret = true; + } + else if (fieldType == ELEMENT_TYPE_VALUETYPE) + { + pMethodTable = pFieldStart->GetFieldTypeHandleThrowing(CLASS_LOAD_APPROXPARENTS, TRUE).GetMethodTable(); + if (pMethodTable->GetNumIntroducedInstanceFields() == 1) + { + ret = IsLoongArch64OnlyOneField(pMethodTable); + } + } + } + goto _End_arg; + } + } + else + { + _ASSERTE(th.IsNativeValueType()); + + useNativeLayout = true; + pMethodTable = th.AsNativeValueType(); + } + _ASSERTE(pMethodTable != nullptr); + + if (useNativeLayout) + { + 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(); + + bool isFixedBuffer = (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType) + || fieldType == ELEMENT_TYPE_VALUETYPE) + && (pFieldStart->GetOffset() == 0) + && pMethodTable->HasLayout() + && (pMethodTable->GetNumInstanceFieldBytes() % pFieldStart->GetSize() == 0); + + if (isFixedBuffer) + { + 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 = IsLoongArch64OnlyOneField(pMethodTable); + } + else if (nfc != NativeFieldCategory::ILLEGAL) + { + ret = true; + } + } + } + else + { + ret = false; + } + } + } +_End_arg: + + return ret; +} + int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) { TypeHandle th(cls); @@ -2865,7 +2974,9 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl { pMethodTable = th.AsMethodTable(); if (pMethodTable->HasLayout()) + { useNativeLayout = true; + } else if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) { DWORD numIntroducedFields = pMethodTable->GetNumIntroducedInstanceFields(); @@ -2879,9 +2990,13 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl 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) { @@ -2900,17 +3015,25 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl { FieldDesc *pFieldStart = pMethodTable->GetApproxFieldDescListRaw(); if (pFieldStart->GetSize() > 8) + { 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; + } } else if (fieldType == ELEMENT_TYPE_VALUETYPE) @@ -2951,13 +3074,21 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl 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) { @@ -2968,9 +3099,13 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl if ((size2 & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) { if (pFieldStart[1].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) { @@ -2991,9 +3126,13 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl } } 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; } @@ -3034,17 +3173,25 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl 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; } } @@ -3052,9 +3199,13 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl 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) { @@ -3084,7 +3235,9 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl pFieldStart = pMethodTable->GetApproxFieldDescListRaw(); if (pFieldStart->GetSize() > 8) + { goto _End_arg; + } if (pFieldStart->GetOffset() || !pFieldStart[1].GetOffset() || (pFieldStart[0].GetSize() > pFieldStart[1].GetOffset())) { @@ -3095,23 +3248,37 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl 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; } } @@ -3131,13 +3298,23 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl MethodTable* pMethodTable2 = pNativeFieldDescs->GetNestedNativeMethodTable(); + if (!IsLoongArch64OnlyOneField(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) { @@ -3176,10 +3353,14 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl goto _End_arg; } 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) @@ -3190,52 +3371,44 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl 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) { - MethodTable* pMethodTable2 = pFieldStart[1].GetFieldTypeHandleThrowing().AsMethodTable(); - - if (pMethodTable2->GetNumIntroducedInstanceFields() > 1) - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } + const NativeFieldDescriptor *pNativeFieldDescs = pMethodTable->GetNativeLayoutInfo()->GetNativeFieldDescriptors(); + NativeFieldCategory nfc = pNativeFieldDescs[1].GetCategory(); - if (pMethodTable2->HasLayout()) + if (nfc == NativeFieldCategory::NESTED) { - const NativeFieldDescriptor *pNativeFieldDescs = pMethodTable2->GetNativeLayoutInfo()->GetNativeFieldDescriptors(); - - NativeFieldCategory nfc = pNativeFieldDescs->GetCategory(); - if (nfc == NativeFieldCategory::NESTED) + if (pNativeFieldDescs[1].GetNumElements() != 1) { - pMethodTable = pNativeFieldDescs->GetNestedNativeMethodTable(); + size = STRUCT_NO_FLOAT_FIELD; + goto _End_arg; + } - if (pMethodTable->GetNumIntroducedInstanceFields() > 1) - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } + MethodTable* pMethodTable2 = pNativeFieldDescs[1].GetNestedNativeMethodTable(); - if ((GetLoongArch64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable) & 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; + if (!IsLoongArch64OnlyOneField(pMethodTable2)) + { + size = STRUCT_NO_FLOAT_FIELD; + goto _End_arg; } - else if (nfc == NativeFieldCategory::FLOAT) + + if ((GetLoongArch64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable2) & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) { if (pFieldStart[1].GetSize() == 4) { @@ -3245,33 +3418,34 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl { 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 + else if ((size & STRUCT_FLOAT_FIELD_FIRST) == 0) { - if ((size & STRUCT_FLOAT_FIELD_FIRST) == 0) - { - size = STRUCT_NO_FLOAT_FIELD; - goto _End_arg; - } - else if (pFieldStart[1].GetSize() == 8) - size |= STRUCT_SECOND_FIELD_SIZE_IS8; + size = STRUCT_NO_FLOAT_FIELD; + } + else if (pFieldStart[1].GetSize() == 8) + { + size |= STRUCT_SECOND_FIELD_SIZE_IS8; } } - else + else if (nfc == NativeFieldCategory::FLOAT) { - if ((GetLoongArch64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable2) & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) + if (pFieldStart[1].GetSize() == 4) { - 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); + 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 (pFieldStart[1].GetSize() == 8) - size |= STRUCT_SECOND_FIELD_SIZE_IS8; + { + 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) @@ -3292,14 +3466,18 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cl 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; + } } } } diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 55366191f28d8..4acb1ad6c5229 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -750,6 +750,7 @@ class MethodTable void CheckRunClassInitAsIfConstructingThrowing(); #if defined(TARGET_LOONGARCH64) + static bool IsLoongArch64OnlyOneField(MethodTable * pMT); static int GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE clh); #endif diff --git a/src/coreclr/vm/object.cpp b/src/coreclr/vm/object.cpp index 0e1bf133986c4..a36b4fe9c86cf 100644 --- a/src/coreclr/vm/object.cpp +++ b/src/coreclr/vm/object.cpp @@ -396,7 +396,7 @@ void STDCALL CopyValueClassArgUnchecked(ArgDestination *argDest, void* src, Meth if (argDest->IsStructPassedInRegs()) { - argDest->CopyStructToRegisters(src, pMT->GetNumInstanceFieldBytes()); + argDest->CopyStructToRegisters(src, pMT->GetNumInstanceFieldBytes(), destOffset); return; }