This is the mail archive of the
libffi-discuss@sourceware.org
mailing list for the libffi project.
[PATCH 2/4] alpha: Clean up conversion of float values
- From: Richard Henderson <rth at twiddle dot net>
- To: libffi-discuss at sourceware dot org
- Date: Wed, 29 Oct 2014 20:54:39 -0700
- Subject: [PATCH 2/4] alpha: Clean up conversion of float values
- Authentication-results: sourceware.org; auth=none
- References: <1414641281-15172-1-git-send-email-rth at twiddle dot net>
Don't use "real" conversion to double, lest we raise
exceptions when passing signalling nans.
---
src/alpha/ffi.c | 95 +++++++++++++++++++++++++++++++--------------------------
1 file changed, 51 insertions(+), 44 deletions(-)
diff --git a/src/alpha/ffi.c b/src/alpha/ffi.c
index 519bd2c..2f9e7e5 100644
--- a/src/alpha/ffi.c
+++ b/src/alpha/ffi.c
@@ -45,6 +45,20 @@ extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)(void)
FFI_HIDDEN;
extern void ffi_closure_osf(void) FFI_HIDDEN;
+/* Promote a float value to its in-register double representation.
+ Unlike actually casting to double, this does not trap on NaN. */
+static inline UINT64 lds(void *ptr)
+{
+ UINT64 ret;
+ asm("lds %0,%1" : "=f"(ret) : "m"(*(UINT32 *)ptr));
+ return ret;
+}
+
+/* And the reverse. */
+static inline void sts(void *ptr, UINT64 val)
+{
+ asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val));
+}
ffi_status
ffi_prep_cif_machdep(ffi_cif *cif)
@@ -127,71 +141,67 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
avn = cif->nargs;
arg_types = cif->arg_types;
- while (i < avn)
+ for (i = 0, avn = cif->nargs; i < avn; i++)
{
- size_t size = (*arg_types)->size;
+ ffi_type *ty = arg_types[i];
+ void *valp = avalue[i];
+ unsigned long val;
+ size_t size;
- switch ((*arg_types)->type)
+ switch (ty->type)
{
case FFI_TYPE_SINT8:
- *(SINT64 *) argp = *(SINT8 *)(* avalue);
+ val = *(SINT8 *)valp;
break;
case FFI_TYPE_UINT8:
- *(SINT64 *) argp = *(UINT8 *)(* avalue);
+ val = *(UINT8 *)valp;
break;
case FFI_TYPE_SINT16:
- *(SINT64 *) argp = *(SINT16 *)(* avalue);
+ val = *(SINT16 *)valp;
break;
case FFI_TYPE_UINT16:
- *(SINT64 *) argp = *(UINT16 *)(* avalue);
+ val = *(UINT16 *)valp;
break;
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
/* Note that unsigned 32-bit quantities are sign extended. */
- *(SINT64 *) argp = *(SINT32 *)(* avalue);
+ val = *(SINT32 *)valp;
break;
-
+
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
- *(UINT64 *) argp = *(UINT64 *)(* avalue);
+ case FFI_TYPE_DOUBLE:
+ val = *(UINT64 *)valp;
+ break;
+
+ case FFI_TYPE_LONGDOUBLE:
+ /* Note that 128-bit long double is passed by reference. */
+ val = (unsigned long)valp;
break;
case FFI_TYPE_FLOAT:
if (argp - stack < 6)
- {
- /* Note the conversion -- all the fp regs are loaded as
- doubles. The in-register format is the same. */
- *(double *) argp = *(float *)(* avalue);
- }
+ val = lds(valp);
else
- *(float *) argp = *(float *)(* avalue);
- break;
-
- case FFI_TYPE_DOUBLE:
- *(double *) argp = *(double *)(* avalue);
- break;
-
- case FFI_TYPE_LONGDOUBLE:
- /* 128-bit long double is passed by reference. */
- *(long double **) argp = (long double *)(* avalue);
- size = sizeof (long double *);
+ val = *(UINT32 *)valp;
break;
case FFI_TYPE_STRUCT:
- memcpy(argp, *avalue, (*arg_types)->size);
- break;
+ size = ty->size;
+ memcpy(argp, valp, size);
+ argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ continue;
default:
- FFI_ASSERT(0);
+ abort();
}
- argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
- i++, arg_types++, avalue++;
+ *argp++ = val;
}
flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
@@ -255,14 +265,13 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
argn = 1;
}
- i = 0;
- avn = cif->nargs;
arg_types = cif->arg_types;
/* Grab the addresses of the arguments from the stack frame. */
- while (i < avn)
+ for (i = 0, avn = cif->nargs; i < avn; i++)
{
size_t size = arg_types[i]->size;
+ void *valp = &argp[argn];
switch (arg_types[i]->type)
{
@@ -276,28 +285,26 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
case FFI_TYPE_STRUCT:
- avalue[i] = &argp[argn];
break;
case FFI_TYPE_FLOAT:
+ /* Floats coming from registers need conversion from double
+ back to float format. */
if (argn < 6)
{
- /* Floats coming from registers need conversion from double
- back to float format. */
- *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6];
- avalue[i] = &argp[argn - 6];
+ valp = &argp[argn - 6];
+ sts(valp, argp[argn - 6]);
}
- else
- avalue[i] = &argp[argn];
break;
case FFI_TYPE_DOUBLE:
- avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
+ if (argn < 6)
+ valp = &argp[argn - 6];
break;
case FFI_TYPE_LONGDOUBLE:
/* 128-bit long double is passed by reference. */
- avalue[i] = (long double *) argp[argn];
+ valp = (long double *) argp[argn];
size = sizeof (long double *);
break;
@@ -305,8 +312,8 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
abort ();
}
+ avalue[i] = valp;
argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
- i++;
}
/* Invoke the closure. */
--
1.9.3