Skip to content

Commit 95d202b

Browse files
committed
Fix passing float and uint arguments in VM
1 parent b7ef5de commit 95d202b

File tree

3 files changed

+30
-9
lines changed

3 files changed

+30
-9
lines changed

src/coreclr/vm/argdestination.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,26 @@ class ArgDestination
173173
_ASSERTE(!"---------UNReachable-------LoongArch64/RISC-V64!!!");
174174
}
175175
}
176+
177+
#ifdef TARGET_RISCV64
178+
void CopySingleFloatToRegister(void* src)
179+
{
180+
void* dest = GetDestinationAddress();
181+
UINT32 value = *(UINT32*)src;
182+
if (TransitionBlock::IsFloatArgumentRegisterOffset(m_offset))
183+
{
184+
// NaN-box the floating register value or single-float instructions will treat it as NaN
185+
*(UINT64*)dest = 0xffffffff00000000L | value;
186+
}
187+
else
188+
{
189+
// When a single float is passed according to integer calling convention
190+
// (in integer register or on stack), the upper bits are not speciifed.
191+
*(UINT32*)dest = value;
192+
}
193+
}
194+
#endif // TARGET_RISCV64
195+
176196
#endif // !DACCESS_COMPILE
177197

178198
PTR_VOID GetStructGenRegDestinationAddress()
@@ -182,7 +202,6 @@ class ArgDestination
182202
return dac_cast<PTR_VOID>(dac_cast<TADDR>(m_base) + argOfs);
183203
}
184204
#endif // defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
185-
186205
#if defined(UNIX_AMD64_ABI)
187206

188207
// Returns true if the ArgDestination represents a struct passed in registers.

src/coreclr/vm/callhelpers.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,10 +474,15 @@ void MethodDescCallSite::CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT *
474474
*((INT64*)pDest) = (INT16)pArguments[arg];
475475
break;
476476
case 4:
477+
#ifdef TARGET_RISCV64
478+
// RISC-V integer calling convention requires to sign-extend `uint` arguments as well
479+
*((INT64*)pDest) = (INT32)pArguments[arg];
480+
#else // TARGET_LOONGARCH64
477481
if (m_argIt.GetArgType() == ELEMENT_TYPE_U4)
478482
*((INT64*)pDest) = (UINT32)pArguments[arg];
479483
else
480484
*((INT64*)pDest) = (INT32)pArguments[arg];
485+
#endif // TARGET_RISCV64
481486
break;
482487
#else
483488
case 1:

src/coreclr/vm/invokeutil.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,9 @@ void InvokeUtil::CopyArg(TypeHandle th, PVOID argRef, ArgDestination *argDest) {
139139

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

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

171172
case ELEMENT_TYPE_I4:
172-
_ASSERTE(argRef != NULL);
173-
*(INT64 *)pArgDst = *(INT32 *)argRef;
174-
break;
175-
176173
case ELEMENT_TYPE_U4:
177174
_ASSERTE(argRef != NULL);
178-
*(UINT64 *)pArgDst = *(UINT32 *)argRef;
175+
*(INT64 *)pArgDst = *(INT32 *)argRef;
179176
break;
180177

181178
#else // !TARGET_RISCV64

0 commit comments

Comments
 (0)