alpha: Clean up conversion of float values Don't use "real" conversion to double, lest we raise exceptions when passing signalling nans.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
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. */