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
4853typedef 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) {
172202static 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