This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java 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: improvements for MIPS o32.


Hi.

The attached patch expands on my previous patches to libffi for the
MIPS o32 ABI. It adds closure and exception unwinding support for this
architecture.

I have some questions about this, however:

  * It's been indicated that the ABI is different for software-only
    floating point architectures. I don't know how to handle this,
    though. Is this something an #ifdef can handle?

  * I'm using the `cacheflush' system call to flush the I-cache, but
    have been warned by the man page that that function is only
    available for MIPS. I don't know if this means "MIPS Linux", or if
    this system call is available on other OSes.

    I also see that on Linux this system call is totally inefficient
    (it flushes the entire cache, not just the region specified).

  * The libffi testsuite in mainline seems broken for my cross-compile
    setup. I have run the old `ffitest.c' test file (with the long
    long test enabled) and all tests pass.

  * gij isn't created when I make my cross gcc. I built and installed
    it on the target by hand, but don't know if tests that use it get
    missed.

Should I post my test results to gcc-testresults? Even though it is a
patched version? At any rate, I get the following results for libjava:

# of expected passes            2711
# of unexpected failures        24
# of expected failures          14
# of untested testcases         34

Comments greatly appreciated.


2004-06-30  Casey Marshall <csm@gnu.org>

	* src/mips/ffi.c (ffi_pref_cif_machdep): set `cif->flags' to
	contain `FFI_TYPE_UINT64' as return type for any 64-bit
	integer (O32 ABI only).
	(ffi_prep_closure): new function. 
	(ffi_closure_mips_inner_O32): new function.
	* src/mips/ffitarget.h: Define `FFI_CLOSURES' and
	`FFI_TRAMPOLINE_SIZE' appropriately if the ABI is o32.
	* src/mips/o32.S (ffi_call_O32): add labels for .eh_frame. Return
	64 bit integers correctly.
	(ffi_closure_O32): new function.
	Added DWARF-2 unwind info for both functions.

-- 
Casey Marshall || csm@gnu.org
? ffi-o32.patch
? o32-dw2.patch
Index: src/mips/ffi.c
===================================================================
RCS file: /cvsroot/gcc/gcc/libffi/src/mips/ffi.c,v
retrieving revision 1.6
diff -u -r1.6 ffi.c
--- src/mips/ffi.c	21 Oct 2003 19:01:56 -0000	1.6
+++ src/mips/ffi.c	29 Jun 2004 17:54:03 -0000
@@ -27,6 +27,7 @@
 #include <ffi_common.h>
 
 #include <stdlib.h>
+#include <sys/cachectl.h>
 
 #if _MIPS_SIM == _ABIN32
 #define FIX_ARGP \
@@ -314,6 +315,11 @@
     case FFI_TYPE_DOUBLE:
       cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
       break;
+
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_UINT64:
+      cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2);
+      break;
       
     default:
       cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2);
@@ -459,3 +465,117 @@
       break;
     }
 }
+
+#if FFI_CLOSURES  /* N32 not implemented yet, FFI_CLOSURES not defined */
+#if defined(FFI_MIPS_O32)
+extern void ffi_closure_O32(void);
+#endif /* FFI_MIPS_O32 */
+
+ffi_status
+ffi_prep_closure (ffi_closure *closure,
+		  ffi_cif *cif,
+		  void (*fun)(ffi_cif*,void*,void**,void*),
+		  void *user_data)
+{
+  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
+  unsigned int fn;
+  unsigned int ctx = (unsigned int) closure;
+
+#if defined(FFI_MIPS_O32)
+  FFI_ASSERT(cif->abi == FFI_O32);
+  fn = (unsigned int) ffi_closure_O32;
+#else /* FFI_MIPS_N32 */
+  FFI_ASSERT(cif->abi == FFI_N32);
+  FFI_ASSERT(!"not implemented");
+#endif /* FFI_MIPS_O32 */
+
+  tramp[0] = 0x3c190000 | (fn >> 16);     /* lui  $25,high(fn) */
+  tramp[1] = 0x3c080000 | (ctx >> 16);    /* lui  $8,high(ctx) */
+  tramp[2] = 0x37390000 | (fn & 0xffff);  /* ori  $25,low(fn)  */
+  tramp[3] = 0x03200008;                  /* jr   $25          */
+  tramp[4] = 0x35080000 | (ctx & 0xffff); /* ori  $8,low(ctx)  */
+
+  closure->cif = cif;
+  closure->fun = fun;
+  closure->user_data = user_data;
+
+  /* XXX this is available on Linux, but anything else? */
+  cacheflush (tramp, FFI_TRAMPOLINE_SIZE, ICACHE);
+
+  return FFI_OK;
+}
+
+/*
+ * Decodes the arguments to a function, which will be stored on the
+ * stack. AR is the pointer to the beginning of the integer arguments
+ * (and, depending upon the arguments, some floating-point arguments
+ * as well). FPR is a pointer to the area where floating point
+ * registers have been saved, if any.
+ *
+ * RVALUE is the location where the function return value will be
+ * stored. CLOSURE is the prepared closure to invoke.
+ *
+ * This function should only be called from assembly, which is in
+ * turn called from a trampoline.
+ *
+ * Returns the function return type.
+ *
+ * Based on the similar routine for sparc.
+ */
+int
+ffi_closure_mips_inner_O32 (ffi_closure *closure,
+			    void *rvalue, unsigned long *ar,
+			    double *fpr)
+{
+  ffi_cif *cif;
+  void **avalue;
+  ffi_type **arg_types;
+  int i, avn, argn, seen_int;
+
+  cif = closure->cif;
+  avalue = alloca (cif->nargs * sizeof (void *));
+
+  seen_int = 0;
+  argn = 0;
+
+  if (cif->flags == FFI_TYPE_STRUCT)
+    {
+      rvalue = (void *) ar[0];
+      argn = 1;
+    }
+
+  i = 0;
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+
+  while (i < avn)
+    {
+      if (i < 2 && !seen_int &&
+	  (arg_types[i]->type == FFI_TYPE_FLOAT ||
+	   arg_types[i]->type == FFI_TYPE_DOUBLE))
+	{
+	  avalue[i] = ((char *) &fpr[i]);
+	}
+      else
+	{
+	  /* 8-byte arguments are always 8-byte aligned. */
+	  if (arg_types[i]->size == 8 && (argn & 0x1))
+	    argn++;
+	  /* Float arguments take up two register slots. The float word
+	     is the upper one. */
+	  if (argn == 2 && arg_types[i]->type == FFI_TYPE_FLOAT)
+	    argn++;
+	  avalue[i] = ((char *) &ar[argn]);
+	  seen_int = 1;
+	}
+      argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+      i++;
+    }
+
+  /* Invoke the closure. */
+  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+  return cif->rtype->type;
+}
+
+#endif /* FFI_CLOSURES */
Index: src/mips/ffitarget.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libffi/src/mips/ffitarget.h,v
retrieving revision 1.2
diff -u -r1.2 ffitarget.h
--- src/mips/ffitarget.h	22 Oct 2003 15:32:13 -0000	1.2
+++ src/mips/ffitarget.h	29 Jun 2004 17:54:03 -0000
@@ -153,7 +153,13 @@
 
 /* ---- Definitions for closures ----------------------------------------- */
 
+#if defined(FFI_MIPS_O32)
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 20
+#else
+/* N32/N64 not implemented yet. */
 #define FFI_CLOSURES 0
+#endif /* FFI_MIPS_O32 */
 #define FFI_NATIVE_RAW_API 0
 
 #endif
Index: src/mips/o32.S
===================================================================
RCS file: /cvsroot/gcc/gcc/libffi/src/mips/o32.S,v
retrieving revision 1.3
diff -u -r1.3 o32.S
--- src/mips/o32.S	21 Oct 2003 19:01:56 -0000	1.3
+++ src/mips/o32.S	29 Jun 2004 17:54:03 -0000
@@ -36,19 +36,24 @@
 #define flags	 a3
 		
 #define SIZEOF_FRAME	( 4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG )
+#define SIZEOF_FRAME2	( 8 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG )
 
 	.text
 	.align	2
 	.globl	ffi_call_O32
 	.ent	ffi_call_O32
 ffi_call_O32:	
-
+$LFB0:
 	# Prologue
 	SUBU	$sp, SIZEOF_FRAME			# Frame size
+$LCFI0:
 	REG_S	$fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp)	# Save frame pointer
+$LCFI1:
 	REG_S	ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)	# Save return address
+$LCFI2:
 	move	$fp, $sp
 
+$LCFI3:
 	move	t9, callback	# callback function pointer
 	REG_S	flags, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # flags
 
@@ -136,12 +141,21 @@
 	REG_L	t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
 	beqz	t1, noretval
 
-	bne     t2, FFI_TYPE_INT, retfloat
+	bne     t2, FFI_TYPE_INT, retlonglong
 	jal	t9
 	REG_L	t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
 	REG_S	v0, 0(t0)
 	b	epilogue
 
+retlonglong:
+	# Really any 64-bit int, signed or not.
+	bne	t2, FFI_TYPE_UINT64, retfloat
+	jal	t9
+	REG_L	t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+	REG_S	v1, 4(t0)
+	REG_S	v0, 0(t0)
+	b	epilogue
+
 retfloat:
 	bne     t2, FFI_TYPE_FLOAT, retdouble
 	jal	t9
@@ -167,6 +181,159 @@
 	ADDU	$sp, SIZEOF_FRAME		      # Fix stack pointer
 	j	ra
 
+$LFE0:
 	.end	ffi_call_O32
-	
+
+
+/* ffi_closure_O32. Expects address of the passed-in ffi_closure
+	in t0. Stores any arguments passed in registers onto the
+	stack, then calls ffi_closure_mips_inner_O32, which
+	then decodes them. */
+
+	.text
+	.align	2
+	.globl	ffi_closure_O32
+	.ent	ffi_closure_O32
+ffi_closure_O32:
+$LFB1:
+	# Prologue
+	.frame	$fp, SIZEOF_FRAME2, $31
+	.set	noreorder
+	.cpload	$25
+	.set	reorder
+	SUBU	$sp, SIZEOF_FRAME2
+	.cprestore SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG
+$LCFI4:
+	REG_S	$fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)	 # Save frame pointer
+$LCFI5:
+	REG_S	ra, SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)	 # Save return address
+$LCFI6:
+	move	$fp, $sp
+
+$LCFI7:
+	# Store all possible argument registers. If there are more than
+	# four arguments, then they should be stored above where we put $7.
+	REG_S	$4, SIZEOF_FRAME2 + 0*FFI_SIZEOF_ARG($fp)
+	REG_S	$5, SIZEOF_FRAME2 + 1*FFI_SIZEOF_ARG($fp)
+	REG_S	$6, SIZEOF_FRAME2 + 2*FFI_SIZEOF_ARG($fp)
+	REG_S	$7, SIZEOF_FRAME2 + 3*FFI_SIZEOF_ARG($fp)
+
+	# Store all possible float/double registers.
+	s.d	$f12, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG($fp)
+	s.d	$f14, SIZEOF_FRAME2 -  8*FFI_SIZEOF_ARG($fp)
+
+	# Call ffi_closure_mips_inner_O32 to do the work.
+	la	$25, ffi_closure_mips_inner_O32
+	move	$4, $8	 # Pointer to the ffi_closure
+	addu	$5, $fp, SIZEOF_FRAME2 -  4*FFI_SIZEOF_ARG
+	addu	$6, $fp, SIZEOF_FRAME2 +  0*FFI_SIZEOF_ARG
+	addu	$7, $fp, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG
+	jal	$31, $25
+
+	# Load the return value into the appropriate register.
+	move	$8, $2
+	li	$9, FFI_TYPE_VOID
+	beq	$8, $9, closure_done
+
+	li	$9, FFI_TYPE_FLOAT
+	l.s	$f0, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
+	beq	$8, $9, closure_done
+
+	li	$9, FFI_TYPE_DOUBLE
+	l.d	$f0, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
+	beq	$8, $9, closure_done
+
+	li	$9, FFI_TYPE_SINT64
+	REG_L	$3, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($fp)
+	beq	$8, $9, integer
+
+	li	$9, FFI_TYPE_UINT64
+	REG_L	$3, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($fp)
+	beq	$8, $9, integer
+
+integer:
+	REG_L	$2, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
+
+closure_done:
+	# Epilogue
+	move	$sp, $fp
+	REG_L	$fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)	 # Restore frame pointer
+	REG_L	ra,  SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)	 # Restore return address
+	ADDU	$sp, SIZEOF_FRAME2
+	j	ra
+$LFE1:
+	.end	ffi_closure_O32
+
+/* DWARF-2 unwind info. */
+
+	.section	.eh_frame,"a",@progbits
+$Lframe0:
+	.4byte	$LECIE0-$LSCIE0	 # Length of Common Information Entry
+$LSCIE0:
+	.4byte	0x0	 # CIE Identifier Tag
+	.byte	0x1	 # CIE Version
+	.ascii "zR\0"	 # CIE Augmentation
+	.uleb128 0x1	 # CIE Code Alignment Factor
+	.sleb128 4	 # CIE Data Alignment Factor
+	.byte	0x1f	 # CIE RA Column
+	.uleb128 0x1	 # Augmentation size
+	.byte	0x1b	 # FDE Encoding (pcrel sdata4)
+	.byte	0xc	 # DW_CFA_def_cfa
+	.uleb128 0x1d
+	.uleb128 0x0
+	.align	2
+$LECIE0:
+$LSFDE0:
+	.4byte	$LEFDE0-$LASFDE0	 # FDE Length
+$LASFDE0:
+	.4byte	$LASFDE0-$Lframe0	 # FDE CIE offset
+	.4byte	$LFB0-.	 # FDE initial location
+	.4byte	$LFE0-$LFB0	 # FDE address range
+	.uleb128 0x0	 # Augmentation size
+	.byte	0x4	 # DW_CFA_advance_loc4
+	.4byte	$LCFI0-$LFB0
+	.byte	0xe	 # DW_CFA_def_cfa_offset
+	.uleb128 0x18
+	.byte	0x4	 # DW_CFA_advance_loc4
+	.4byte	$LCFI2-$LCFI0
+	.byte	0x11	 # DW_CFA_offset_extended_sf
+	.uleb128 0x1e	 # $fp
+	.sleb128 -2	 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
+	.byte	0x11	 # DW_CFA_offset_extended_sf
+	.uleb128 0x1f	 # $ra
+	.sleb128 -1	 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
+	.byte	0x4	 # DW_CFA_advance_loc4
+	.4byte	$LCFI3-$LCFI2
+	.byte	0xc	 # DW_CFA_def_cfa
+	.uleb128 0x1e
+	.uleb128 0x18
+	.align	2
+$LEFDE0:
+$LSFDE1:
+	.4byte	$LEFDE1-$LASFDE1	 # FDE Length
+$LASFDE1:
+	.4byte	$LASFDE1-$Lframe0	 # FDE CIE offset
+	.4byte	$LFB1-.	 # FDE initial location
+	.4byte	$LFE1-$LFB1	 # FDE address range
+	.uleb128 0x0	 # Augmentation size
+	.byte	0x4	 # DW_CFA_advance_loc4
+	.4byte	$LCFI4-$LFB1
+	.byte	0xe	 # DW_CFA_def_cfa_offset
+	.uleb128 0x28
+	.byte	0x4	 # DW_CFA_advance_loc4
+	.4byte	$LCFI6-$LCFI4
+	.byte	0x11	 # DW_CFA_offset_extended_sf
+	.uleb128 0x1e	 # $fp
+	.sleb128 -2	 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
+	.byte	0x11	 # DW_CFA_offset_extended_sf
+	.uleb128 0x1f	 # $ra
+	.sleb128 -1	 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
+	.byte	0x4	 # DW_CFA_advance_loc4
+	.4byte	$LCFI7-$LCFI6
+	.byte	0xc	 # DW_CFA_def_cfa
+	.uleb128 0x1e
+	.uleb128 0x28
+	.align	2
+$LEFDE1:
+
 #endif

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