diff --git a/src/coreclr/vm/argdestination.h b/src/coreclr/vm/argdestination.h index 57df0326648167..ec5c692672cf3b 100644 --- a/src/coreclr/vm/argdestination.h +++ b/src/coreclr/vm/argdestination.h @@ -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() @@ -182,7 +202,6 @@ class ArgDestination return dac_cast(dac_cast(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. diff --git a/src/coreclr/vm/callhelpers.cpp b/src/coreclr/vm/callhelpers.cpp index 3125c21ea3d13d..25388ed1640465 100644 --- a/src/coreclr/vm/callhelpers.cpp +++ b/src/coreclr/vm/callhelpers.cpp @@ -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: diff --git a/src/coreclr/vm/invokeutil.cpp b/src/coreclr/vm/invokeutil.cpp index cfec2c5259a5f1..44f51dae7c7cf3 100644 --- a/src/coreclr/vm/invokeutil.cpp +++ b/src/coreclr/vm/invokeutil.cpp @@ -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); @@ -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