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]

Re: [RFC patch] libffi support for FreeBSD/PowerPC


Andreas Tobler wrote:
Andreas Tobler wrote:

Hi all,

the attached patch brings libffi support for FreeBSD/PowerPC. In the core it is equal to the linux-ppc 32-bit port. But the thing which is different, is the FreeBSD/PowerPC port supports the final SYSV 4 ABI versus the draft one linux-ppc does. This means that small structures (smaller or equal 8 bytes) are passed in r3/r4 instead of memory as linux-ppc does.
I tested the patch on FreeBSD/PowerPC and linux-ppc 32-bit. No regressions. I do not have a 64-bit platform around. I'd appreciate if one could give it a short run. Although I do not expect any fall out.


I'd like to point to test results, but unfortunately the FreeBSD/PowerPC port does not yet support Altivec which prevents me from running a make -k check over the whole build. I need first to clean up/adjust the gcc testsuite to NOT test Altivec tests on FreeBSD/PowerPC. (Which is not that easy since we have tests which check Altivec directly.) GDB does it better ....

A suitable CL will follow. I smoked my fbsd machine just before writing the CL, with Altivec tests .....


Third try, more tunings. Ok for main?

Andreas

2005-07-11 Andreas Tobler <a.tobler@schweiz.ch>

    * Makefile.am (nodist_libffi_la_SOURCES): Add POWERPC_FREEBSD.
    * Makefile.in: Regenerate.
    * configure.ac: Add POWERPC_FREEBSD rules.
    * configure: Regenerate.
    * src/powerpc/ffitarget.h: Add POWERPC_FREEBSD rules.
    (FFI_SYSV_TYPE_SMALL_STRUCT): Define.
    * src/powerpc/ffi.c: Add flags to handle small structure returns
    in ffi_call_SYSV.
    (ffi_prep_cif_machdep): Handle small structures for SYSV 4 ABI.
    Aka FFI_SYSV.
    (ffi_closure_helper_SYSV): Likewise.
    * src/powerpc/ppc_closure.S: Add return types for small structures.
    * src/powerpc/sysv.S: Add bits to handle small structures for
    final SYSV 4 ABI.
Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libffi/Makefile.am,v
retrieving revision 1.40
diff -u -r1.40 Makefile.am
--- Makefile.am	18 May 2005 01:49:29 -0000	1.40
+++ Makefile.am	16 Jul 2005 12:30:07 -0000
@@ -117,6 +117,9 @@
 if POWERPC_DARWIN
 nodist_libffi_la_SOURCES += src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S
 endif
+if POWERPC_FREEBSD
+nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S
+endif
 if ARM
 nodist_libffi_la_SOURCES += src/arm/sysv.S src/arm/ffi.c
 endif
Index: configure.ac
===================================================================
RCS file: /cvs/gcc/gcc/libffi/configure.ac,v
retrieving revision 1.15
diff -u -r1.15 configure.ac
--- configure.ac	14 Jun 2005 23:37:05 -0000	1.15
+++ configure.ac	16 Jul 2005 12:30:07 -0000
@@ -68,6 +68,7 @@
 powerpc-*-beos*) TARGET=POWERPC; TARGETDIR=powerpc;;
 powerpc-*-darwin*) TARGET=POWERPC_DARWIN; TARGETDIR=powerpc;;
 powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
+powerpc-*-freebsd*) TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc;;
 powerpc*-*-rtems*) TARGET=POWERPC; TARGETDIR=powerpc;;
 rs6000-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
 arm*-*-linux-*) TARGET=ARM; TARGETDIR=arm;;
@@ -101,6 +102,7 @@
 AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC)
 AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
 AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET = xPOWERPC_DARWIN)
+AM_CONDITIONAL(POWERPC_FREEBSD, test x$TARGET = xPOWERPC_FREEBSD)
 AM_CONDITIONAL(ARM, test x$TARGET = xARM)
 AM_CONDITIONAL(LIBFFI_CRIS, test x$TARGET = xLIBFFI_CRIS)
 AM_CONDITIONAL(FRV, test x$TARGET = xFRV)
Index: src/powerpc/ffi.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/powerpc/ffi.c,v
retrieving revision 1.12
diff -u -r1.12 ffi.c
--- src/powerpc/ffi.c	23 Feb 2005 14:05:12 -0000	1.12
+++ src/powerpc/ffi.c	16 Jul 2005 12:30:08 -0000
@@ -41,6 +41,7 @@
 
 enum {
   /* The assembly depends on these exact flags.  */
+  FLAG_RETURNS_SMST	= 1 << (31-31), /* Used for FFI_SYSV small structs.  */
   FLAG_RETURNS_NOTHING  = 1 << (31-30), /* These go in cr7 */
   FLAG_RETURNS_FP       = 1 << (31-29),
   FLAG_RETURNS_64BITS   = 1 << (31-28),
@@ -462,6 +463,7 @@
   unsigned flags = 0;
   unsigned struct_copy_size = 0;
   unsigned type = cif->rtype->type;
+  unsigned size = cif->rtype->size;
 
   if (cif->abi != FFI_LINUX64)
     {
@@ -518,15 +520,30 @@
       break;
 
     case FFI_TYPE_STRUCT:
-      if (cif->abi != FFI_GCC_SYSV && cif->abi != FFI_LINUX64)
+      if (cif->abi == FFI_SYSV)
 	{
-	  if (cif->rtype->size <= 4)
-	    break;
-	  else if (cif->rtype->size <= 8)
-	    {
-	      flags |= FLAG_RETURNS_64BITS;
+	  /* The final SYSV ABI says that structures smaller or equal 8 bytes
+	     are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them
+	     in memory.  */
+
+	  /* Treat structs with size <= 8 bytes.  */
+	  if (size <= 8) {
+	    flags |= FLAG_RETURNS_SMST;
+	    /* These structs are returned in r3. We pack the type and the
+	       precalculated shift value (needed in the sysv.S) into flags.
+	       The same applies for the structs returned in r3/r4.  */
+	    if (size <= 4) {
+	      flags |= 1 << (31 - FFI_SYSV_TYPE_SMALL_STRUCT - 1 )
+		| (8 * (4 - size) << 4);
 	      break;
 	    }
+	    /* These structs are returned in r3 and r4. See above.   */
+	    if  (size <= 8) {
+	      flags |= 1 << (31 - FFI_SYSV_TYPE_SMALL_STRUCT - 2 )
+		| (8 * (8 - size) << 4);
+	    break;
+	    }
+	  }
 	}
       /* else fall through.  */
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
@@ -573,7 +590,7 @@
 	    /* 'long long' arguments are passed as two words, but
 	       either both words must fit in registers or both go
 	       on the stack.  If they go on the stack, they must
-	       be 8-byte-aligned.  
+	       be 8-byte-aligned.
 
 	       Also, only certain register pairs can be used for
 	       passing long long int -- specifically (r3,r4), (r5,r6),
@@ -770,7 +787,7 @@
 #else
   unsigned int *tramp;
 
-  FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
+  FFI_ASSERT (cif->abi == FFI_GCC_SYSV || cif->abi == FFI_SYSV);
 
   tramp = (unsigned int *) &closure->tramp[0];
   tramp[0] = 0x7c0802a6;  /*   mflr    r0 */
@@ -829,20 +846,27 @@
   long             ng;   /* number of general registers already used */
   ffi_cif *        cif;
   double           temp;
+  unsigned         size;
 
   cif = closure->cif;
   avalue = alloca(cif->nargs * sizeof(void *));
+  size = cif->rtype->size;
 
   nf = 0;
   ng = 0;
 
   /* Copy the caller's structure return value address so that the closure
-     returns the data directly to the caller.  */
+     returns the data directly to the caller.
+     For FFI_SYSV the result is passed in r3/r4 if the struct size is less
+     or equal 8 bytes.  */
+
   if (cif->rtype->type == FFI_TYPE_STRUCT)
     {
-      rvalue = (void *) *pgr;
-      ng++;
-      pgr++;
+      if (!((cif->abi == FFI_SYSV) && (size <= 8))) {
+	rvalue = (void *) *pgr;
+	ng++;
+	pgr++;
+      }
     }
 
   i = 0;
@@ -986,7 +1010,12 @@
 
   (closure->fun) (cif, rvalue, avalue, closure->user_data);
 
-  /* Tell ffi_closure_SYSV how to perform return type promotions.  */
+  /* Tell ffi_closure_SYSV how to perform return type promotions.
+     Since the FFI_SYSV ABI returns the structures <= 8 bytes in r3/r4
+     we have to tell ffi_closure_SYSV how to treat them.  */
+  if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT
+      && size <= 8)
+    return FFI_SYSV_TYPE_SMALL_STRUCT + size;
   return cif->rtype->type;
 
 }
Index: src/powerpc/ffitarget.h
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/powerpc/ffitarget.h,v
retrieving revision 1.2
diff -u -r1.2 ffitarget.h
--- src/powerpc/ffitarget.h	2 Sep 2004 21:07:21 -0000	1.2
+++ src/powerpc/ffitarget.h	16 Jul 2005 12:30:09 -0000
@@ -62,6 +62,13 @@
   FFI_DEFAULT_ABI = FFI_DARWIN,
 #endif
 
+#ifdef POWERPC_FREEBSD
+  FFI_SYSV,
+  FFI_GCC_SYSV,
+  FFI_LINUX64,
+  FFI_DEFAULT_ABI = FFI_SYSV,
+#endif
+
   FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
 } ffi_abi;
 #endif
@@ -71,6 +78,9 @@
 #define FFI_CLOSURES 1
 #define FFI_NATIVE_RAW_API 0
 
+/* Needed for FFI_SYSV small structure returns.  */
+#define FFI_SYSV_TYPE_SMALL_STRUCT  (FFI_TYPE_LAST)
+
 #if defined(POWERPC64) || defined(POWERPC_AIX)
 #define FFI_TRAMPOLINE_SIZE 24
 #else /* POWERPC || POWERPC_AIX */
Index: src/powerpc/ppc_closure.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/powerpc/ppc_closure.S,v
retrieving revision 1.10
diff -u -r1.10 ppc_closure.S
--- src/powerpc/ppc_closure.S	1 Jun 2005 00:33:09 -0000	1.10
+++ src/powerpc/ppc_closure.S	16 Jul 2005 12:30:09 -0000
@@ -63,9 +63,22 @@
 	# so use it to look up in a table
 	# so we know how to deal with each type
 
+	# Extract the size of the return type for small structures.
+	# Then calculate (4 - size) and multiply the result by 8.
+	# This gives the value needed for the shift operation below.
+	# This part is only needed for FFI_SYSV and small structures.
+	addic	%r5,%r3,-(FFI_SYSV_TYPE_SMALL_STRUCT)
+	cmpwi	cr0,%r5,4
+	ble	cr0,.Lnext
+	addic	%r5,%r5,-4
+.Lnext:
+	addic	%r5,%r5,-4
+	neg	%r5,%r5
+	slwi	%r5,%r5,3
+
 	# look up the proper starting point in table
 	# by using return type as offset
-	addi %r5,%r1,112   # get pointer to results area
+	addi %r6,%r1,112   # get pointer to results area
 	bl .Lget_ret_type0_addr # get pointer to .Lret_type0 into LR
 	mflr %r4           # move to r4
 	slwi %r3,%r3,4     # now multiply return type by 16
@@ -94,85 +107,85 @@
 
 # case FFI_TYPE_INT
 .Lret_type1:
-	lwz %r3,0(%r5)
+	lwz %r3,0(%r6)
 	b .Lfinish
 	nop
 	nop
 
 # case FFI_TYPE_FLOAT
 .Lret_type2:
-	lfs %f1,0(%r5)
+	lfs %f1,0(%r6)
 	b .Lfinish
 	nop
 	nop
 
 # case FFI_TYPE_DOUBLE
 .Lret_type3:
-	lfd %f1,0(%r5)
+	lfd %f1,0(%r6)
 	b .Lfinish
 	nop
 	nop
 
 # case FFI_TYPE_LONGDOUBLE
 .Lret_type4:
-	lfd %f1,0(%r5)
+	lfd %f1,0(%r6)
 	b .Lfinish
 	nop
 	nop
 
 # case FFI_TYPE_UINT8
 .Lret_type5:
-	lbz %r3,3(%r5)
+	lbz %r3,3(%r6)
 	b .Lfinish
 	nop
 	nop
 
 # case FFI_TYPE_SINT8
 .Lret_type6:
-	lbz %r3,3(%r5)
+	lbz %r3,3(%r6)
 	extsb %r3,%r3
 	b .Lfinish
 	nop
 
 # case FFI_TYPE_UINT16
 .Lret_type7:
-	lhz %r3,2(%r5)
+	lhz %r3,2(%r6)
 	b .Lfinish
 	nop
 	nop
 
 # case FFI_TYPE_SINT16
 .Lret_type8:
-	lha %r3,2(%r5)
+	lha %r3,2(%r6)
 	b .Lfinish
 	nop
 	nop
 
 # case FFI_TYPE_UINT32
 .Lret_type9:
-	lwz %r3,0(%r5)
+	lwz %r3,0(%r6)
 	b .Lfinish
 	nop
 	nop
 
 # case FFI_TYPE_SINT32
 .Lret_type10:
-	lwz %r3,0(%r5)
+	lwz %r3,0(%r6)
 	b .Lfinish
 	nop
 	nop
 
 # case FFI_TYPE_UINT64
 .Lret_type11:
-	lwz %r3,0(%r5)
-	lwz %r4,4(%r5)
+	lwz %r3,0(%r6)
+	lwz %r4,4(%r6)
 	b .Lfinish
 	nop
 
 # case FFI_TYPE_SINT64
 .Lret_type12:
-	lwz %r3,0(%r5)
-	lwz %r4,4(%r5)
+	lwz %r3,0(%r6)
+	lwz %r4,4(%r6)
 	b .Lfinish
 	nop
 
@@ -185,11 +198,76 @@
 
 # case FFI_TYPE_POINTER
 .Lret_type14:
-	lwz %r3,0(%r5)
+	lwz %r3,0(%r6)
+	b .Lfinish
+	nop
+	nop
+
+# The return types below are only used when the ABI type is FFI_SYSV.
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.
+.Lret_type15:
+# fall through.
+	nop
+	nop
+	nop
+	nop
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct.
+.Lret_type16:
+# fall through.
+	nop
+	nop
+	nop
+	nop
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct.
+.Lret_type17:
+# fall through.
+	nop
+	nop
+	nop
+	nop
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct.
+.Lret_type18:
+# this one handles the structs from above too.
+	lwz %r3,0(%r6)
+	srw %r3,%r3,%r5
 	b .Lfinish
 	nop
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct.
+.Lret_type19:
+# fall through.
+	nop
+	nop
+	nop
 	nop
 
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct.
+.Lret_type20:
+# fall through.
+	nop
+	nop
+	nop
+	nop
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct.
+.Lret_type21:
+# fall through.
+        nop
+        nop
+        nop
+        nop
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct.
+.Lret_type22:
+# this one handles the above unhandled structs.
+	lwz %r3,0(%r6)
+	lwz %r4,4(%r6)
+	bl __lshrdi3	# libgcc function to shift r3/r4, shift value in r5.
+	b .Lfinish
+
 # case done
 .Lfinish:
 
Index: src/powerpc/sysv.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/powerpc/sysv.S,v
retrieving revision 1.7
diff -u -r1.7 sysv.S
--- src/powerpc/sysv.S	1 Jun 2005 00:33:09 -0000	1.7
+++ src/powerpc/sysv.S	16 Jul 2005 12:30:09 -0000
@@ -99,6 +99,7 @@
 
 	/* Now, deal with the return value.  */
 	mtcrf	0x01,%r31
+	bt-	31,L(small_struct_return_value)
 	bt-	30,L(done_return_value)
 	bt-	29,L(fp_return_value)
 	stw	%r3,0(%r30)
@@ -124,6 +125,27 @@
 L(float_return_value):
 	stfs	%f1,0(%r30)
 	b	L(done_return_value)
+
+L(small_struct_return_value):
+	mtcrf	0x10,%r31	/* cr3  */
+	bt-	15,L(smst_one_register)
+	mtcrf	0x08,%r31	/* cr4  */
+	bt-	16,L(smst_two_register)
+	b       L(done_return_value)
+
+L(smst_one_register):
+	rlwinm  %r5,%r31,5+23,32-5,31 /* Extract the value to shift.  */
+	slw	%r3,%r3,%r5
+	stw	%r3,0(%r30)
+	b	L(done_return_value)
+L(smst_two_register):
+	rlwinm  %r5,%r31,5+23,32-5,31 /* Extract the value to shift.  */
+	bl	__ashldi3  /* libgcc function to shift r3/r4,
+			      shift value in r5.  */
+	stw	%r3,0(%r30)
+	stw	%r4,4(%r30)
+	b	L(done_return_value)
+
 .LFE1:
 END(ffi_call_SYSV)
 

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