Skip to content

Commit

Permalink
Fix passing float and uint arguments in VM
Browse files Browse the repository at this point in the history
  • Loading branch information
tomeksowi committed Jul 17, 2024
1 parent b7ef5de commit 95d202b
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 9 deletions.
21 changes: 20 additions & 1 deletion src/coreclr/vm/argdestination.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,26 @@ class ArgDestination
_ASSERTE(!"---------UNReachable-------LoongArch64/RISC-V64!!!");
}
}

#ifdef TARGET_RISCV64
void CopySingleFloatToRegister(void* src)
{
void* dest = GetDestinationAddress();
UINT32 value = *(UINT32*)src;
if (TransitionBlock::IsFloatArgumentRegisterOffset(m_offset))
{
// NaN-box the floating register value or single-float instructions will treat it as NaN
*(UINT64*)dest = 0xffffffff00000000L | value;
}
else
{
// When a single float is passed according to integer calling convention
// (in integer register or on stack), the upper bits are not speciifed.
*(UINT32*)dest = value;
}
}
#endif // TARGET_RISCV64

#endif // !DACCESS_COMPILE

PTR_VOID GetStructGenRegDestinationAddress()
Expand All @@ -182,7 +202,6 @@ class ArgDestination
return dac_cast<PTR_VOID>(dac_cast<TADDR>(m_base) + argOfs);
}
#endif // defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)

#if defined(UNIX_AMD64_ABI)

// Returns true if the ArgDestination represents a struct passed in registers.
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/vm/callhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,10 +474,15 @@ void MethodDescCallSite::CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT *
*((INT64*)pDest) = (INT16)pArguments[arg];
break;
case 4:
#ifdef TARGET_RISCV64
// RISC-V integer calling convention requires to sign-extend `uint` arguments as well
*((INT64*)pDest) = (INT32)pArguments[arg];
#else // TARGET_LOONGARCH64
if (m_argIt.GetArgType() == ELEMENT_TYPE_U4)
*((INT64*)pDest) = (UINT32)pArguments[arg];
else
*((INT64*)pDest) = (INT32)pArguments[arg];
#endif // TARGET_RISCV64
break;
#else
case 1:
Expand Down
13 changes: 5 additions & 8 deletions src/coreclr/vm/invokeutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ void InvokeUtil::CopyArg(TypeHandle th, PVOID argRef, ArgDestination *argDest) {

switch (type) {
#ifdef TARGET_RISCV64
// RISC-V call convention requires signed ints sign-extended (unsigned -- zero-extended) to register width
// RISC-V call convention requires integer scalars narrower than XLEN bits to be widened according to the sign
// of their type up to 32 bits, then sign-extended to XLEN bits. In practice it means type-extending all ints
// except `uint` which is sign-extended regardless.
case ELEMENT_TYPE_BOOLEAN:
case ELEMENT_TYPE_U1:
_ASSERTE(argRef != NULL);
Expand All @@ -164,18 +166,13 @@ void InvokeUtil::CopyArg(TypeHandle th, PVOID argRef, ArgDestination *argDest) {

case ELEMENT_TYPE_R4:
_ASSERTE(argRef != NULL);
// NaN-box the register value or single-float instructions will treat it as NaN
*(UINT64 *)pArgDst = 0xffffffff00000000L | *(UINT32 *)argRef;
argDest->CopySingleFloatToRegister(argRef);
break;

case ELEMENT_TYPE_I4:
_ASSERTE(argRef != NULL);
*(INT64 *)pArgDst = *(INT32 *)argRef;
break;

case ELEMENT_TYPE_U4:
_ASSERTE(argRef != NULL);
*(UINT64 *)pArgDst = *(UINT32 *)argRef;
*(INT64 *)pArgDst = *(INT32 *)argRef;
break;

#else // !TARGET_RISCV64
Expand Down

0 comments on commit 95d202b

Please sign in to comment.