This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[Patch,libffi] Add MIPS64 soft-float support to libffi.
- From: David Daney <ddaney at caviumnetworks dot com>
- To: GCJ-patches <java-patches at gcc dot gnu dot org>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 28 Aug 2009 10:50:32 -0700
- Subject: [Patch,libffi] Add MIPS64 soft-float support to libffi.
libffi is lacking support for the mips64 soft-float ABIs. In addition
be being annoying in and of itself, it also causes libjava failures.
The patch adds soft-float support for both n32 and n64 ABIs. Quite a
bit of code had to be touched as the rules for passing structures
containing floating point elements are a slightly complex.
While working on the patch I noticed that we were failing a bunch if
pointer passing test cases that where recently added. It turns out that
the original closure support for returning pointers was incorrect and
this was unmasked by the new test cases. I wrapped fixes for this into
the patch as well (Yes, I know it is technically a no-no). The change
to ffi_java_raw_to_rvalue() is needed with with the fixed closure
pointer return.
I would like to add that I think there is still incorrect handling for
values of most types on big-endian systems in java_raw_api.c, but since
the java interpreter only uses a couple of types, the problematical
cases are never used.
The end result is that all libffi tests except for some long double
things now pass at -O0. There are a couple of floating point failures
with optimization turned on, but they look like they may be issues with
libgcc's soft-float support. The long double FAILures seem to be due
to lack of support in my glibc's printf.
Tested on mips64-unknown-linux-gnu soft-float with both n32 and n64 ABIs
with no regressions. Currently testing mips64-unknown-linux-gnu
hard-float n32 and n64.
OK to commit given the hard-float testing is good?
2009-08-28 David Daney <ddaney@caviumnetworks.com>
* src/java_raw_api.c (ffi_java_raw_to_rvalue): Remove special
handling for FFI_TYPE_POINTER.
* src/mips/ffitarget.h (FFI_TYPE_STRUCT_D_SOFT,
FFI_TYPE_STRUCT_F_SOFT, FFI_TYPE_STRUCT_DD_SOFT,
FFI_TYPE_STRUCT_FF_SOFT, FFI_TYPE_STRUCT_FD_SOFT,
FFI_TYPE_STRUCT_DF_SOFT, FFI_TYPE_STRUCT_SOFT): New defines.
(FFI_N32_SOFT_FLOAT, FFI_N64_SOFT_FLOAT): New ffi_abi enumerations.
(enum ffi_abi): Set FFI_DEFAULT_ABI for soft-float.
* src/mips/n32.S (ffi_call_N32): Add handling for soft-float
structure and pointer returns.
(ffi_closure_N32): Add handling for pointer returns.
* src/mips/ffi.c (ffi_prep_args, calc_n32_struct_flags,
calc_n32_return_struct_flags): Handle soft-float.
(ffi_prep_cif_machdep): Handle soft-float, fix pointer handling.
(ffi_call_N32): Declare proper argument types.
(ffi_call, copy_struct_N32, ffi_closure_mips_inner_N32): Handle
soft-float.
Index: src/java_raw_api.c
===================================================================
--- src/java_raw_api.c (revision 151156)
+++ src/java_raw_api.c (working copy)
@@ -276,9 +276,6 @@ ffi_java_raw_to_rvalue (ffi_cif *cif, vo
case FFI_TYPE_SINT16:
case FFI_TYPE_SINT32:
case FFI_TYPE_INT:
-#if FFI_SIZEOF_JAVA_RAW == 4
- case FFI_TYPE_POINTER:
-#endif
*(SINT64 *)rvalue >>= 32;
break;
Index: src/mips/ffitarget.h
===================================================================
--- src/mips/ffitarget.h (revision 151156)
+++ src/mips/ffitarget.h (working copy)
@@ -95,6 +95,15 @@
#define FFI_TYPE_STRUCT_DF 189
#define FFI_TYPE_STRUCT_SMALL 93
#define FFI_TYPE_STRUCT_SMALL2 109
+
+/* and for n32 soft float, add 16 * 2^4 */
+#define FFI_TYPE_STRUCT_D_SOFT 317
+#define FFI_TYPE_STRUCT_F_SOFT 301
+#define FFI_TYPE_STRUCT_DD_SOFT 509
+#define FFI_TYPE_STRUCT_FF_SOFT 429
+#define FFI_TYPE_STRUCT_FD_SOFT 493
+#define FFI_TYPE_STRUCT_DF_SOFT 445
+#define FFI_TYPE_STRUCT_SOFT 16
#endif
#ifdef LIBFFI_ASM
@@ -161,6 +170,8 @@ typedef enum ffi_abi {
FFI_N32,
FFI_N64,
FFI_O32_SOFT_FLOAT,
+ FFI_N32_SOFT_FLOAT,
+ FFI_N64_SOFT_FLOAT,
#ifdef FFI_MIPS_O32
#ifdef __mips_soft_float
@@ -170,9 +181,17 @@ typedef enum ffi_abi {
#endif
#else
# if _MIPS_SIM==_ABI64
+# ifdef __mips_soft_float
+ FFI_DEFAULT_ABI = FFI_N64_SOFT_FLOAT,
+# else
FFI_DEFAULT_ABI = FFI_N64,
+# endif
# else
+# ifdef __mips_soft_float
+ FFI_DEFAULT_ABI = FFI_N32_SOFT_FLOAT,
+# else
FFI_DEFAULT_ABI = FFI_N32,
+# endif
# endif
#endif
Index: src/mips/n32.S
===================================================================
--- src/mips/n32.S (revision 151156)
+++ src/mips/n32.S (working copy)
@@ -217,8 +217,10 @@ callit:
# Shift the return type flag over
SRL t6, 8*FFI_FLAG_BITS
-
+
+ beq t6, FFI_TYPE_SINT32, retint
bne t6, FFI_TYPE_INT, retfloat
+retint:
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
REG_S v0, 0(t4)
@@ -277,12 +279,58 @@ retstruct_d_f:
b epilogue
retstruct_f_d:
- bne t6, FFI_TYPE_STRUCT_FD, retstruct_small
+ bne t6, FFI_TYPE_STRUCT_FD, retstruct_d_soft
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
s.s $f0, 0(t4)
s.d $f2, 8(t4)
b epilogue
+
+retstruct_d_soft:
+ bne t6, FFI_TYPE_STRUCT_D_SOFT, retstruct_f_soft
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ sd v0, 0(t4)
+ b epilogue
+
+retstruct_f_soft:
+ bne t6, FFI_TYPE_STRUCT_F_SOFT, retstruct_d_d_soft
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ sw v0, 0(t4)
+ b epilogue
+
+retstruct_d_d_soft:
+ bne t6, FFI_TYPE_STRUCT_DD_SOFT, retstruct_f_f_soft
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ sd v0, 0(t4)
+ sd v1, 8(t4)
+ b epilogue
+
+retstruct_f_f_soft:
+ bne t6, FFI_TYPE_STRUCT_FF_SOFT, retstruct_d_f_soft
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ sw v0, 0(t4)
+ sw v1, 4(t4)
+ b epilogue
+
+retstruct_d_f_soft:
+ bne t6, FFI_TYPE_STRUCT_DF_SOFT, retstruct_f_d_soft
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ sd v0, 0(t4)
+ sw v1, 8(t4)
+ b epilogue
+
+retstruct_f_d_soft:
+ bne t6, FFI_TYPE_STRUCT_FD_SOFT, retstruct_small
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ sw v0, 0(t4)
+ sd v1, 8(t4)
+ b epilogue
retstruct_small:
bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2
@@ -413,6 +461,11 @@ ffi_closure_N32:
jalr t9
# Return flags are in v0
+ bne v0, FFI_TYPE_SINT32, cls_retint
+ lw v0, V0_OFF2($sp)
+ b cls_epilogue
+
+cls_retint:
bne v0, FFI_TYPE_INT, cls_retfloat
REG_L v0, V0_OFF2($sp)
b cls_epilogue
Index: src/mips/ffi.c
===================================================================
--- src/mips/ffi.c (revision 151156)
+++ src/mips/ffi.c (working copy)
@@ -99,7 +99,7 @@ static void ffi_prep_args(char *stack,
p_argv = ecif->avalue;
- for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
+ for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; i++, p_arg++)
{
size_t z;
unsigned int a;
@@ -123,9 +123,25 @@ static void ffi_prep_args(char *stack,
/* The size of a pointer depends on the ABI */
if (type == FFI_TYPE_POINTER)
- type =
- (ecif->cif->abi == FFI_N64) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+ type = (ecif->cif->abi == FFI_N64
+ || ecif->cif->abi == FFI_N64_SOFT_FLOAT)
+ ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+ if (i < 8 && (ecif->cif->abi == FFI_N32_SOFT_FLOAT
+ || ecif->cif->abi == FFI_N64_SOFT_FLOAT))
+ {
+ switch (type)
+ {
+ case FFI_TYPE_FLOAT:
+ type = FFI_TYPE_UINT32;
+ break;
+ case FFI_TYPE_DOUBLE:
+ type = FFI_TYPE_UINT64;
+ break;
+ default:
+ break;
+ }
+ }
switch (type)
{
case FFI_TYPE_SINT8:
@@ -205,13 +221,17 @@ static void ffi_prep_args(char *stack,
definitions and generates the appropriate flags. */
static unsigned
-calc_n32_struct_flags(ffi_type *arg, unsigned *loc, unsigned *arg_reg)
+calc_n32_struct_flags(int soft_float, ffi_type *arg,
+ unsigned *loc, unsigned *arg_reg)
{
unsigned flags = 0;
unsigned index = 0;
ffi_type *e;
+ if (soft_float)
+ return 0;
+
while ((e = arg->elements[index]))
{
/* Align this object. */
@@ -236,7 +256,7 @@ calc_n32_struct_flags(ffi_type *arg, uns
}
static unsigned
-calc_n32_return_struct_flags(ffi_type *arg)
+calc_n32_return_struct_flags(int soft_float, ffi_type *arg)
{
unsigned flags = 0;
unsigned small = FFI_TYPE_SMALLSTRUCT;
@@ -256,6 +276,7 @@ calc_n32_return_struct_flags(ffi_type *a
small = FFI_TYPE_SMALLSTRUCT2;
e = arg->elements[0];
+
if (e->type == FFI_TYPE_DOUBLE)
flags = FFI_TYPE_DOUBLE;
else if (e->type == FFI_TYPE_FLOAT)
@@ -276,6 +297,8 @@ calc_n32_return_struct_flags(ffi_type *a
floats! This must be passed the old way. */
return small;
}
+ if (soft_float)
+ flags += FFI_TYPE_STRUCT_SOFT;
}
else
if (!flags)
@@ -382,16 +405,19 @@ ffi_status ffi_prep_cif_machdep(ffi_cif
#ifdef FFI_MIPS_N32
/* Set the flags necessary for N32 processing */
{
+ int type;
unsigned arg_reg = 0;
unsigned loc = 0;
unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
unsigned index = 0;
unsigned struct_flags = 0;
+ int soft_float = (cif->abi == FFI_N32_SOFT_FLOAT
+ || cif->abi == FFI_N64_SOFT_FLOAT);
if (cif->rtype->type == FFI_TYPE_STRUCT)
{
- struct_flags = calc_n32_return_struct_flags(cif->rtype);
+ struct_flags = calc_n32_return_struct_flags(soft_float, cif->rtype);
if (struct_flags == 0)
{
@@ -411,7 +437,22 @@ ffi_status ffi_prep_cif_machdep(ffi_cif
while (count-- > 0 && arg_reg < 8)
{
- switch ((cif->arg_types)[index]->type)
+ type = (cif->arg_types)[index]->type;
+ if (soft_float)
+ {
+ switch (type)
+ {
+ case FFI_TYPE_FLOAT:
+ type = FFI_TYPE_UINT32;
+ break;
+ case FFI_TYPE_DOUBLE:
+ type = FFI_TYPE_UINT64;
+ break;
+ default:
+ break;
+ }
+ }
+ switch (type)
{
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
@@ -423,17 +464,25 @@ ffi_status ffi_prep_cif_machdep(ffi_cif
/* Align it. */
arg_reg = ALIGN(arg_reg, 2);
/* Treat it as two adjacent doubles. */
- cif->flags +=
- (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
- arg_reg++;
- cif->flags +=
- (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
- arg_reg++;
+ if (soft_float)
+ {
+ arg_reg += 2;
+ }
+ else
+ {
+ cif->flags +=
+ (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
+ arg_reg++;
+ cif->flags +=
+ (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
+ arg_reg++;
+ }
break;
case FFI_TYPE_STRUCT:
loc = arg_reg * FFI_SIZEOF_ARG;
- cif->flags += calc_n32_struct_flags((cif->arg_types)[index],
+ cif->flags += calc_n32_struct_flags(soft_float,
+ (cif->arg_types)[index],
&loc, &arg_reg);
break;
@@ -469,17 +518,43 @@ ffi_status ffi_prep_cif_machdep(ffi_cif
case FFI_TYPE_VOID:
/* Do nothing, 'cause FFI_TYPE_VOID is 0 */
break;
-
+
+ case FFI_TYPE_POINTER:
+ if (cif->abi == FFI_N32_SOFT_FLOAT || cif->abi == FFI_N32)
+ cif->flags += FFI_TYPE_SINT32 << (FFI_FLAG_BITS * 8);
+ else
+ cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
+ break;
+
case FFI_TYPE_FLOAT:
+ if (soft_float)
+ {
+ cif->flags += FFI_TYPE_SINT32 << (FFI_FLAG_BITS * 8);
+ break;
+ }
+ /* else fall through */
case FFI_TYPE_DOUBLE:
- cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
+ if (soft_float)
+ cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
+ else
+ cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
break;
+
case FFI_TYPE_LONGDOUBLE:
/* Long double is returned as if it were a struct containing
two doubles. */
- cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
- cif->flags += (FFI_TYPE_DOUBLE + (FFI_TYPE_DOUBLE << FFI_FLAG_BITS))
- << (4 + (FFI_FLAG_BITS * 8));
+ if (soft_float)
+ {
+ cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
+ cif->flags += FFI_TYPE_SMALLSTRUCT2 << (4 + (FFI_FLAG_BITS * 8));
+ }
+ else
+ {
+ cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
+ cif->flags += (FFI_TYPE_DOUBLE
+ + (FFI_TYPE_DOUBLE << FFI_FLAG_BITS))
+ << (4 + (FFI_FLAG_BITS * 8));
+ }
break;
default:
cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
@@ -499,7 +574,7 @@ extern int ffi_call_O32(void (*)(char *,
/* Low level routine for calling N32 functions */
extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int),
extended_cif *, unsigned,
- unsigned, unsigned *, void (*)(void));
+ unsigned, void *, void (*)(void));
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
@@ -529,10 +604,13 @@ void ffi_call(ffi_cif *cif, void (*fn)(v
#ifdef FFI_MIPS_N32
case FFI_N32:
+ case FFI_N32_SOFT_FLOAT:
case FFI_N64:
+ case FFI_N64_SOFT_FLOAT:
{
int copy_rvalue = 0;
- void *rvalue_copy = ecif.rvalue;
+ int copy_offset = 0;
+ char *rvalue_copy = ecif.rvalue;
if (cif->rtype->type == FFI_TYPE_STRUCT && cif->rtype->size < 16)
{
/* For structures smaller than 16 bytes we clobber memory
@@ -541,10 +619,20 @@ void ffi_call(ffi_cif *cif, void (*fn)(v
rvalue_copy = alloca(16);
copy_rvalue = 1;
}
+ else if (cif->rtype->type == FFI_TYPE_FLOAT
+ && (cif->abi == FFI_N64_SOFT_FLOAT
+ || cif->abi == FFI_N32_SOFT_FLOAT))
+ {
+ rvalue_copy = alloca (8);
+ copy_rvalue = 1;
+#ifdef __MIPSEB__
+ copy_offset = 4;
+#endif
+ }
ffi_call_N32(ffi_prep_args, &ecif, cif->bytes,
cif->flags, rvalue_copy, fn);
if (copy_rvalue)
- memcpy(ecif.rvalue, rvalue_copy, cif->rtype->size);
+ memcpy(ecif.rvalue, rvalue_copy + copy_offset, cif->rtype->size);
}
break;
#endif
@@ -755,7 +843,7 @@ ffi_closure_mips_inner_O32 (ffi_closure
static void
copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type,
int argn, unsigned arg_offset, ffi_arg *ar,
- ffi_arg *fpr)
+ ffi_arg *fpr, int soft_float)
{
ffi_type **elt_typep = type->elements;
while(*elt_typep)
@@ -777,7 +865,7 @@ copy_struct_N32(char *target, unsigned o
tp = target + offset;
- if (elt_type->type == FFI_TYPE_DOUBLE)
+ if (elt_type->type == FFI_TYPE_DOUBLE && !soft_float)
*(double *)tp = *(double *)fpp;
else
memcpy(tp, argp + arg_offset, elt_type->size);
@@ -815,8 +903,12 @@ ffi_closure_mips_inner_N32 (ffi_closure
ffi_arg *avalue;
ffi_type **arg_types;
int i, avn, argn;
+ int soft_float;
+ ffi_arg *argp;
cif = closure->cif;
+ soft_float = cif->abi == FFI_N64_SOFT_FLOAT
+ || cif->abi == FFI_N32_SOFT_FLOAT;
avalue = alloca (cif->nargs * sizeof (ffi_arg));
avaluep = alloca (cif->nargs * sizeof (ffi_arg));
@@ -839,9 +931,9 @@ ffi_closure_mips_inner_N32 (ffi_closure
while (i < avn)
{
if (arg_types[i]->type == FFI_TYPE_FLOAT
- || arg_types[i]->type == FFI_TYPE_DOUBLE)
+ || arg_types[i]->type == FFI_TYPE_DOUBLE)
{
- ffi_arg *argp = argn >= 8 ? ar + argn : fpr + argn;
+ argp = (argn >= 8 || soft_float) ? ar + argn : fpr + argn;
#ifdef __MIPSEB__
if (arg_types[i]->type == FFI_TYPE_FLOAT && argn < 8)
avaluep[i] = ((char *) argp) + sizeof (float);
@@ -856,11 +948,15 @@ ffi_closure_mips_inner_N32 (ffi_closure
if (arg_types[i]->alignment > sizeof(ffi_arg))
argn = ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg));
- ffi_arg *argp = ar + argn;
+ argp = ar + argn;
/* The size of a pointer depends on the ABI */
if (type == FFI_TYPE_POINTER)
- type = (cif->abi == FFI_N64) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+ type = (cif->abi == FFI_N64 || cif->abi == FFI_N64_SOFT_FLOAT)
+ ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+
+ if (soft_float && type == FFI_TYPE_FLOAT)
+ type = FFI_TYPE_UINT32;
switch (type)
{
@@ -901,7 +997,7 @@ ffi_closure_mips_inner_N32 (ffi_closure
it was passed in registers. */
avaluep[i] = alloca(arg_types[i]->size);
copy_struct_N32(avaluep[i], 0, cif->abi, arg_types[i],
- argn, 0, ar, fpr);
+ argn, 0, ar, fpr, soft_float);
break;
}