Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LoongArch64] amend the LoongArch64's ABI for GCstress and NullableObject. #72573

Merged
merged 1 commit into from
Jul 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 42 additions & 10 deletions src/coreclr/vm/argdestination.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>, it is the offset
// of the T value inside of the Nullable<T>
void CopyStructToRegisters(void *src, int fieldBytes, int destOffset)
{
_ASSERTE(IsStructPassedInRegs());
_ASSERTE(fieldBytes <= 16);
Expand All @@ -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<T>, it is the offset of the T value inside of the Nullable<T>.
// 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

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/callhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/gcinfodecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would one store GC pointers in the return address register?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because the ra may be used as a scratch register at some causes.

}

bool GcInfoDecoder::IsScratchStackSlot(INT32 spOffset, GcStackSlotBase spBase, PREGDISPLAY pRD)
Expand Down
Loading