This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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;
                 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]