Skip to content

Commit 5c9c976

Browse files
committed
ffi: fix float passing in libffi for riscv64
libffi was incorrectly passing floats as doubles on RISC-V. This PR applies the merged upstream fix (libffi/libffi#972) for the vendored copy of libffi since libffi appears to have a very long release cycle (last release was at 2025-08-02). This fixes the following three new test failures: test/ffi/test-ffi-dynamic-library.js test/ffi/test-ffi-shared-buffer.js test/ffi/test-ffi-calls.js Signed-off-by: Levi Zim <rsworktech@outlook.com>
1 parent 4e7c07d commit 5c9c976

1 file changed

Lines changed: 46 additions & 12 deletions

File tree

  • deps/libffi/src/riscv

deps/libffi/src/riscv/ffi.c

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,15 @@
3535

3636
#if __riscv_float_abi_double
3737
#define ABI_FLEN 64
38-
#define ABI_FLOAT double
38+
typedef union {
39+
uint64_t i;
40+
double d;
41+
} float_reg;
3942
#elif __riscv_float_abi_single
4043
#define ABI_FLEN 32
41-
#define ABI_FLOAT float
44+
typedef union {
45+
float f;
46+
} float_reg;
4247
#endif
4348

4449
#define NARGREG 8
@@ -48,7 +53,7 @@
4853
typedef struct call_context
4954
{
5055
#if ABI_FLEN
51-
ABI_FLOAT fa[8];
56+
float_reg fa[8];
5257
#endif
5358
size_t a[8];
5459
/* used by the assembly code to in-place construct its own stack frame */
@@ -127,6 +132,30 @@ static float_struct_info struct_passed_as_elements(call_builder *cb, ffi_type *t
127132

128133
return ret;
129134
}
135+
136+
#if ABI_FLEN >= 64
137+
/* Float values in wider RISC-V FP registers are NaN-boxed */
138+
static void marshal_float(call_builder *cb, void *data) {
139+
union {
140+
uint32_t i;
141+
float f;
142+
} value;
143+
144+
value.f = *(float *)data;
145+
cb->aregs->fa[cb->used_float++].i =
146+
UINT64_C(0xffffffff00000000) | value.i;
147+
}
148+
149+
static void unmarshal_float(call_builder *cb, void *data) {
150+
union {
151+
uint32_t i;
152+
float f;
153+
} value;
154+
155+
value.i = (uint32_t)cb->aregs->fa[cb->used_float++].i;
156+
*(float *)data = value.f;
157+
}
158+
#endif
130159
#endif
131160

132161
/* allocates a single register, float register, or XLEN-sized stack slot to a datum */
@@ -146,17 +175,18 @@ static void marshal_atom(call_builder *cb, int type, void *data) {
146175
#endif
147176
case FFI_TYPE_POINTER: value = *(size_t *)data; break;
148177

149-
/* float values may be recoded in an implementation-defined way
150-
by hardware conforming to 2.1 or earlier, so use asm to
151-
reinterpret floats as doubles */
152-
#if ABI_FLEN >= 32
178+
#if ABI_FLEN >= 64
179+
case FFI_TYPE_FLOAT:
180+
marshal_float(cb, data);
181+
return;
182+
#elif ABI_FLEN >= 32
153183
case FFI_TYPE_FLOAT:
154-
asm("" : "=f"(cb->aregs->fa[cb->used_float++]) : "0"(*(float *)data));
184+
asm("" : "=f"(cb->aregs->fa[cb->used_float++].f) : "0"(*(float *)data));
155185
return;
156186
#endif
157187
#if ABI_FLEN >= 64
158188
case FFI_TYPE_DOUBLE:
159-
asm("" : "=f"(cb->aregs->fa[cb->used_float++]) : "0"(*(double *)data));
189+
asm("" : "=f"(cb->aregs->fa[cb->used_float++].d) : "0"(*(double *)data));
160190
return;
161191
#endif
162192
default: FFI_ASSERT(0); break;
@@ -172,14 +202,18 @@ static void marshal_atom(call_builder *cb, int type, void *data) {
172202
static void unmarshal_atom(call_builder *cb, int type, void *data) {
173203
size_t value;
174204
switch (type) {
175-
#if ABI_FLEN >= 32
205+
#if ABI_FLEN >= 64
206+
case FFI_TYPE_FLOAT:
207+
unmarshal_float(cb, data);
208+
return;
209+
#elif ABI_FLEN >= 32
176210
case FFI_TYPE_FLOAT:
177-
asm("" : "=f"(*(float *)data) : "0"(cb->aregs->fa[cb->used_float++]));
211+
asm("" : "=f"(*(float *)data) : "0"(cb->aregs->fa[cb->used_float++].f));
178212
return;
179213
#endif
180214
#if ABI_FLEN >= 64
181215
case FFI_TYPE_DOUBLE:
182-
asm("" : "=f"(*(double *)data) : "0"(cb->aregs->fa[cb->used_float++]));
216+
asm("" : "=f"(*(double *)data) : "0"(cb->aregs->fa[cb->used_float++].d));
183217
return;
184218
#endif
185219
}

0 commit comments

Comments
 (0)