public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PowerPC] libffi fixes and support for PowerPC64 ELFv2
@ 2013-11-16 13:01 Alan Modra
  2013-11-16 13:03 ` Reinstate powerpc bounce buffer copying in ffi.c Alan Modra
                   ` (6 more replies)
  0 siblings, 7 replies; 23+ messages in thread
From: Alan Modra @ 2013-11-16 13:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Edelsohn

The following six patches correspond to patches posted to the libffi
mailing list a few days ago to add support for PowerPC64 ELFv2.  The
patch series has been tested on powerpc-linux, powerpc64-linux,
powerpc64le-linux and powerpc-freebsd by running the libffi testsuite,
and on powerpc64-linux and powerpc64le-linux by gcc bootstrap and
regression testing.  I guess the normal procedure would be to wait for
upstream approval before applying here, but since Uli's gcc support
for ELFv2 is in, it would be nice to have a working libffi along with
that.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Reinstate powerpc bounce buffer copying in ffi.c
  2013-11-16 13:01 [PowerPC] libffi fixes and support for PowerPC64 ELFv2 Alan Modra
@ 2013-11-16 13:03 ` Alan Modra
  2013-11-16 13:05 ` libffi doc fixes Alan Modra
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 23+ messages in thread
From: Alan Modra @ 2013-11-16 13:03 UTC (permalink / raw)
  To: gcc-patches, David Edelsohn

The first patch in the series is a little different to the
corresponding upstream libffi patch, because there I needed to revert
some fixes first.  The second patch in the series is entirely missing
due to the testsuite already being fixed in gcc.

This patch properly copies the bounce buffer to destination, and only
uses the bounce buffer for FFI_SYSV.  I also fix an accounting error
in integer register usage.

	* src/powerpc/ffi.c (ffi_prep_cif_machdep): Do not consume an
	int arg when returning a small struct for FFI_SYSV ABI.
	(ffi_call): Only use bounce buffer when FLAG_RETURNS_SMST.
	Properly copy bounce buffer to destination.

diff -urp gcc-virgin/libffi/src/powerpc/ffi.c gcc1/libffi/src/powerpc/ffi.c
--- gcc-virgin/libffi/src/powerpc/ffi.c	2013-06-25 09:36:39.259402853 +0930
+++ gcc1/libffi/src/powerpc/ffi.c	2013-11-15 23:06:57.313036827 +1030
@@ -691,7 +691,7 @@
     case FFI_TYPE_STRUCT:
       /*
        * 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
+       * are returned in r3/r4.  The FFI_GCC_SYSV ABI instead returns them
        * in memory.
        *
        * NOTE: The assembly code can safely assume that it just needs to
@@ -700,7 +700,10 @@
        *       set.
        */
       if (cif->abi == FFI_SYSV && size <= 8)
-	flags |= FLAG_RETURNS_SMST;
+	{
+	  flags |= FLAG_RETURNS_SMST;
+	  break;
+	}
       intarg_count++;
       flags |= FLAG_RETVAL_REFERENCE;
       /* Fall through.  */
@@ -919,30 +922,25 @@
 {
   /*
    * 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
+   * are returned in r3/r4.  The FFI_GCC_SYSV ABI instead returns them
    * in memory.
    *
-   * Just to keep things simple for the assembly code, we will always
-   * bounce-buffer struct return values less than or equal to 8 bytes.
-   * This allows the ASM to handle SYSV small structures by directly
-   * writing r3 and r4 to memory without worrying about struct size.
+   * We bounce-buffer SYSV small struct return values so that sysv.S
+   * can write r3 and r4 to memory without worrying about struct size.
    */
   unsigned int smst_buffer[2];
   extended_cif ecif;
-  unsigned int rsize = 0;
 
   ecif.cif = cif;
   ecif.avalue = avalue;
 
-  /* Ensure that we have a valid struct return value */
   ecif.rvalue = rvalue;
-  if (cif->rtype->type == FFI_TYPE_STRUCT) {
-    rsize = cif->rtype->size;
-    if (rsize <= 8)
-      ecif.rvalue = smst_buffer;
-    else if (!rvalue)
-      ecif.rvalue = alloca(rsize);
-  }
+  if ((cif->flags & FLAG_RETURNS_SMST) != 0)
+    ecif.rvalue = smst_buffer;
+  /* Ensure that we have a valid struct return value.
+     FIXME: Isn't this just papering over a user problem?  */
+  else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT)
+    ecif.rvalue = alloca (cif->rtype->size);
 
   switch (cif->abi)
     {
@@ -967,7 +965,21 @@
 
   /* Check for a bounce-buffered return value */
   if (rvalue && ecif.rvalue == smst_buffer)
-    memcpy(rvalue, smst_buffer, rsize);
+    {
+      unsigned int rsize = cif->rtype->size;
+#ifndef __LITTLE_ENDIAN__
+      /* The SYSV ABI returns a structure of up to 4 bytes in size
+	 left-padded in r3.  */
+      if (rsize <= 4)
+	memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize);
+      /* The SYSV ABI returns a structure of up to 8 bytes in size
+	 left-padded in r3/r4.  */
+      else if (rsize <= 8)
+	memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize);
+      else
+#endif
+	memcpy (rvalue, smst_buffer, rsize);
+    }
 }
 
 

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* libffi doc fixes
  2013-11-16 13:01 [PowerPC] libffi fixes and support for PowerPC64 ELFv2 Alan Modra
  2013-11-16 13:03 ` Reinstate powerpc bounce buffer copying in ffi.c Alan Modra
@ 2013-11-16 13:05 ` Alan Modra
  2013-11-16 13:06 ` Pass floating point values on powerpc64 as per ABI Alan Modra
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 23+ messages in thread
From: Alan Modra @ 2013-11-16 13:05 UTC (permalink / raw)
  To: gcc-patches, David Edelsohn

This enshrines the current testsuite practice of using ffi_arg for
returned values.  It would be reasonable and logical to use the actual
return argument type as passed to ffi_prep_cif, but this would mean
changing a large number of tests that use ffi_arg and all backends
that write results to an ffi_arg.

	* doc/libffi.texi: Correct example code.

diff -urp gcc1/libffi/doc/libffi.texi gcc3/libffi/doc/libffi.texi
--- gcc1/libffi/doc/libffi.texi	2013-06-13 21:03:53.000000000 +0930
+++ gcc3/libffi/doc/libffi.texi	2013-11-15 23:16:06.811643952 +1030
@@ -214,7 +214,7 @@ int main()
   ffi_type *args[1];
   void *values[1];
   char *s;
-  int rc;
+  ffi_arg rc;
   
   /* Initialize the argument info vectors */    
   args[0] = &ffi_type_pointer;
@@ -222,7 +222,7 @@ int main()
   
   /* Initialize the cif */
   if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
-		       &ffi_type_uint, args) == FFI_OK)
+		       &ffi_type_sint, args) == FFI_OK)
     @{
       s = "Hello World!";
       ffi_call(&cif, puts, &rc, values);
@@ -414,6 +414,7 @@ Here is the corresponding code to descri
       int i;
 
       tm_type.size = tm_type.alignment = 0;
+      tm_type.type = FFI_TYPE_STRUCT;
       tm_type.elements = &tm_type_elements;
     
       for (i = 0; i < 9; i++)
@@ -540,7 +541,7 @@ A trivial example that creates a new @co
 #include <ffi.h>
 
 /* Acts like puts with the file given at time of enclosure. */
-void puts_binding(ffi_cif *cif, unsigned int *ret, void* args[], 
+void puts_binding(ffi_cif *cif, ffi_arg *ret, void* args[], 
                   FILE *stream)
 @{
   *ret = fputs(*(char **)args[0], stream);
@@ -565,7 +566,7 @@ int main()
 
       /* Initialize the cif */
       if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
-                       &ffi_type_uint, args) == FFI_OK)
+                       &ffi_type_sint, args) == FFI_OK)
         @{
           /* Initialize the closure, setting stream to stdout */
           if (ffi_prep_closure_loc(closure, &cif, puts_binding, 

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Pass floating point values on powerpc64 as per ABI
  2013-11-16 13:01 [PowerPC] libffi fixes and support for PowerPC64 ELFv2 Alan Modra
  2013-11-16 13:03 ` Reinstate powerpc bounce buffer copying in ffi.c Alan Modra
  2013-11-16 13:05 ` libffi doc fixes Alan Modra
@ 2013-11-16 13:06 ` Alan Modra
  2013-11-18 10:17   ` Andreas Schwab
  2013-11-16 13:11 ` Support PowerPC64 ELFv2 ABI Alan Modra
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: Alan Modra @ 2013-11-16 13:06 UTC (permalink / raw)
  To: gcc-patches, David Edelsohn

The powerpc64 support opted to pass floating point values both in the
fpr area and the parameter save area, necessary when the backend
doesn't know if a function argument corresponds to the ellipsis
arguments of a variadic function.  This patch adds powerpc support for
variadic functions, and changes the code to only pass fp in the ABI
mandated area.  ELFv2 needs this change since the parameter save area
may not exist there.

This also fixes two faulty tests that used a non-variadic function
cast to call a variadic function, and spuriously reasoned that this is
somehow necessary for static functions..

The whitespace changes, and comment changes in the tests, are to make
the gcc versions of these files mirror upstream libffi.

	* src/powerpc/ffitarget.h (FFI_TARGET_SPECIFIC_VARIADIC): Define.
	(FFI_EXTRA_CIF_FIELDS): Define.
	* src/powerpc/ffi.c (ffi_prep_args64): Save fprs as per the
	ABI, not to both fpr and param save area.
	(ffi_prep_cif_machdep_core): Renamed from ffi_prep_cif_machdep.
	Keep initial flags.  Formatting.  Remove dead FFI_LINUX_SOFT_FLOAT
	code.
	(ffi_prep_cif_machdep, ffi_prep_cif_machdep_var): New functions.
	(ffi_closure_helper_LINUX64): Pass floating point as per ABI,
	not to both fpr and parameter save areas.

	* libffi/testsuite/libffi.call/cls_double_va.c (main): Correct
	function cast and don't call ffi_prep_cif.
	* libffi/testsuite/libffi.call/cls_longdouble_va.c (main): Likewise.

diff -urp gcc3/libffi/src/powerpc/ffitarget.h gcc4/libffi/src/powerpc/ffitarget.h
--- gcc3/libffi/src/powerpc/ffitarget.h	2013-11-15 23:03:07.313959745 +1030
+++ gcc4/libffi/src/powerpc/ffitarget.h	2013-11-15 23:19:21.692053339 +1030
@@ -106,6 +106,10 @@ typedef enum ffi_abi {
 
 #define FFI_CLOSURES 1
 #define FFI_NATIVE_RAW_API 0
+#if defined (POWERPC) || defined (POWERPC_FREEBSD)
+# define FFI_TARGET_SPECIFIC_VARIADIC 1
+# define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs
+#endif
 
 /* For additional types like the below, take care about the order in
    ppc_closures.S. They must follow after the FFI_TYPE_LAST.  */
diff -urp gcc3/libffi/src/powerpc/ffi.c gcc4/libffi/src/powerpc/ffi.c
--- gcc3/libffi/src/powerpc/ffi.c	2013-11-15 23:06:57.313036827 +1030
+++ gcc4/libffi/src/powerpc/ffi.c	2013-11-15 23:47:24.402296569 +1030
@@ -443,9 +443,9 @@ ffi_prep_args64 (extended_cif *ecif, uns
   /* 'fpr_base' points at the space for fpr3, and grows upwards as
      we use FPR registers.  */
   valp fpr_base;
-  int fparg_count;
+  unsigned int fparg_count;
 
-  int i, words;
+  unsigned int i, words, nargs, nfixedargs;
   ffi_type **ptr;
   double double_tmp;
   union {
@@ -482,30 +482,34 @@ ffi_prep_args64 (extended_cif *ecif, uns
 
   /* Now for the arguments.  */
   p_argv.v = ecif->avalue;
-  for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
-       i > 0;
-       i--, ptr++, p_argv.v++)
+  nargs = ecif->cif->nargs;
+  nfixedargs = ecif->cif->nfixedargs;
+  for (ptr = ecif->cif->arg_types, i = 0;
+       i < nargs;
+       i++, ptr++, p_argv.v++)
     {
       switch ((*ptr)->type)
 	{
 	case FFI_TYPE_FLOAT:
 	  double_tmp = **p_argv.f;
-	  *next_arg.f = (float) double_tmp;
+	  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
+	    *fpr_base.d++ = double_tmp;
+	  else
+	    *next_arg.f = (float) double_tmp;
 	  if (++next_arg.ul == gpr_end.ul)
 	    next_arg.ul = rest.ul;
-	  if (fparg_count < NUM_FPR_ARG_REGISTERS64)
-	    *fpr_base.d++ = double_tmp;
 	  fparg_count++;
 	  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
 	  break;
 
 	case FFI_TYPE_DOUBLE:
 	  double_tmp = **p_argv.d;
-	  *next_arg.d = double_tmp;
+	  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
+	    *fpr_base.d++ = double_tmp;
+	  else
+	    *next_arg.d = double_tmp;
 	  if (++next_arg.ul == gpr_end.ul)
 	    next_arg.ul = rest.ul;
-	  if (fparg_count < NUM_FPR_ARG_REGISTERS64)
-	    *fpr_base.d++ = double_tmp;
 	  fparg_count++;
 	  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
 	  break;
@@ -513,18 +517,20 @@ ffi_prep_args64 (extended_cif *ecif, uns
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
 	case FFI_TYPE_LONGDOUBLE:
 	  double_tmp = (*p_argv.d)[0];
-	  *next_arg.d = double_tmp;
+	  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
+	    *fpr_base.d++ = double_tmp;
+	  else
+	    *next_arg.d = double_tmp;
 	  if (++next_arg.ul == gpr_end.ul)
 	    next_arg.ul = rest.ul;
-	  if (fparg_count < NUM_FPR_ARG_REGISTERS64)
-	    *fpr_base.d++ = double_tmp;
 	  fparg_count++;
 	  double_tmp = (*p_argv.d)[1];
-	  *next_arg.d = double_tmp;
+	  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
+	    *fpr_base.d++ = double_tmp;
+	  else
+	    *next_arg.d = double_tmp;
 	  if (++next_arg.ul == gpr_end.ul)
 	    next_arg.ul = rest.ul;
-	  if (fparg_count < NUM_FPR_ARG_REGISTERS64)
-	    *fpr_base.d++ = double_tmp;
 	  fparg_count++;
 	  FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
 	  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
@@ -597,15 +603,14 @@ ffi_prep_args64 (extended_cif *ecif, uns
 
 
 /* Perform machine dependent cif processing */
-ffi_status
-ffi_prep_cif_machdep (ffi_cif *cif)
+static ffi_status
+ffi_prep_cif_machdep_core (ffi_cif *cif)
 {
   /* All this is for the SYSV and LINUX64 ABI.  */
-  int i;
   ffi_type **ptr;
   unsigned bytes;
-  int fparg_count = 0, intarg_count = 0;
-  unsigned flags = 0;
+  unsigned i, fparg_count = 0, intarg_count = 0;
+  unsigned flags = cif->flags;
   unsigned struct_copy_size = 0;
   unsigned type = cif->rtype->type;
   unsigned size = cif->rtype->size;
@@ -650,19 +655,23 @@ ffi_prep_cif_machdep (ffi_cif *cif)
      - soft-float float/doubles are treated as UINT32/UINT64 respectivley.
      - soft-float long doubles are returned in gpr3-gpr6.  */
   /* First translate for softfloat/nonlinux */
-  if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
-	if (type == FFI_TYPE_FLOAT)
-		type = FFI_TYPE_UINT32;
-	if (type == FFI_TYPE_DOUBLE)
-		type = FFI_TYPE_UINT64;
-	if (type == FFI_TYPE_LONGDOUBLE)
-		type = FFI_TYPE_UINT128;
-  } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
+  if (cif->abi == FFI_LINUX_SOFT_FLOAT)
+    {
+      if (type == FFI_TYPE_FLOAT)
+	type = FFI_TYPE_UINT32;
+      if (type == FFI_TYPE_DOUBLE)
+	type = FFI_TYPE_UINT64;
+      if (type == FFI_TYPE_LONGDOUBLE)
+	type = FFI_TYPE_UINT128;
+    }
+  else if (cif->abi != FFI_LINUX
+	   && cif->abi != FFI_LINUX64)
+    {
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-	if (type == FFI_TYPE_LONGDOUBLE)
-		type = FFI_TYPE_STRUCT;
+      if (type == FFI_TYPE_LONGDOUBLE)
+	type = FFI_TYPE_STRUCT;
 #endif
-  }
+    }
 
   switch (type)
     {
@@ -823,13 +832,8 @@ ffi_prep_cif_machdep (ffi_cif *cif)
 	  {
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
 	  case FFI_TYPE_LONGDOUBLE:
-	    if (cif->abi == FFI_LINUX_SOFT_FLOAT)
-	      intarg_count += 4;
-	    else
-	      {
-		fparg_count += 2;
-		intarg_count += 2;
-	      }
+	    fparg_count += 2;
+	    intarg_count += 2;
 	    break;
 #endif
 	  case FFI_TYPE_FLOAT:
@@ -911,6 +915,22 @@ ffi_prep_cif_machdep (ffi_cif *cif)
   return FFI_OK;
 }
 
+ffi_status
+ffi_prep_cif_machdep (ffi_cif *cif)
+{
+  cif->nfixedargs = cif->nargs;
+  return ffi_prep_cif_machdep_core (cif);
+}
+
+ffi_status
+ffi_prep_cif_machdep_var (ffi_cif *cif,
+			  unsigned int nfixedargs,
+			  unsigned int ntotalargs MAYBE_UNUSED)
+{
+  cif->nfixedargs = nfixedargs;
+  return ffi_prep_cif_machdep_core (cif);
+}
+
 extern void ffi_call_SYSV(extended_cif *, unsigned, unsigned, unsigned *,
 			  void (*fn)(void));
 extern void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, unsigned long,
@@ -1238,6 +1258,7 @@ ffi_closure_helper_SYSV (ffi_closure *cl
 	    }
 	  break;
 #endif
+
 	case FFI_TYPE_SINT16:
 	case FFI_TYPE_UINT16:
 #ifndef __LITTLE_ENDIAN__
@@ -1255,6 +1276,7 @@ ffi_closure_helper_SYSV (ffi_closure *cl
 	    }
 	  break;
 #endif
+
 	case FFI_TYPE_SINT32:
 	case FFI_TYPE_UINT32:
 	case FFI_TYPE_POINTER:
@@ -1358,7 +1380,7 @@ ffi_closure_helper_LINUX64 (ffi_closure
 
   void **avalue;
   ffi_type **arg_types;
-  long i, avn;
+  unsigned long i, avn, nfixedargs;
   ffi_cif *cif;
   ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
 
@@ -1375,6 +1397,7 @@ ffi_closure_helper_LINUX64 (ffi_closure
 
   i = 0;
   avn = cif->nargs;
+  nfixedargs = cif->nfixedargs;
   arg_types = cif->arg_types;
 
   /* Grab the addresses of the arguments from the stack frame.  */
@@ -1389,6 +1412,7 @@ ffi_closure_helper_LINUX64 (ffi_closure
 	  pst++;
 	  break;
 #endif
+
 	case FFI_TYPE_SINT16:
 	case FFI_TYPE_UINT16:
 #ifndef __LITTLE_ENDIAN__
@@ -1396,6 +1420,7 @@ ffi_closure_helper_LINUX64 (ffi_closure
 	  pst++;
 	  break;
 #endif
+
 	case FFI_TYPE_SINT32:
 	case FFI_TYPE_UINT32:
 #ifndef __LITTLE_ENDIAN__
@@ -1403,6 +1428,7 @@ ffi_closure_helper_LINUX64 (ffi_closure
 	  pst++;
 	  break;
 #endif
+
 	case FFI_TYPE_SINT64:
 	case FFI_TYPE_UINT64:
 	case FFI_TYPE_POINTER:
@@ -1430,7 +1456,7 @@ ffi_closure_helper_LINUX64 (ffi_closure
 
 	  /* there are 13 64bit floating point registers */
 
-	  if (pfr < end_pfr)
+	  if (pfr < end_pfr && i < nfixedargs)
 	    {
 	      double temp = pfr->d;
 	      pfr->f = (float) temp;
@@ -1446,7 +1472,7 @@ ffi_closure_helper_LINUX64 (ffi_closure
 	  /* On the outgoing stack all values are aligned to 8 */
 	  /* there are 13 64bit floating point registers */
 
-	  if (pfr < end_pfr)
+	  if (pfr < end_pfr && i < nfixedargs)
 	    {
 	      avalue[i] = pfr;
 	      pfr++;
@@ -1458,14 +1484,14 @@ ffi_closure_helper_LINUX64 (ffi_closure
 
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
 	case FFI_TYPE_LONGDOUBLE:
-	  if (pfr + 1 < end_pfr)
+	  if (pfr + 1 < end_pfr && i + 1 < nfixedargs)
 	    {
 	      avalue[i] = pfr;
 	      pfr += 2;
 	    }
 	  else
 	    {
-	      if (pfr < end_pfr)
+	      if (pfr < end_pfr && i < nfixedargs)
 		{
 		  /* Passed partly in f13 and partly on the stack.
 		     Move it all to the stack.  */
diff -urp gcc3/libffi/testsuite/libffi.call/cls_double_va.c gcc4/libffi/testsuite/libffi.call/cls_double_va.c
--- gcc3/libffi/testsuite/libffi.call/cls_double_va.c	2013-11-15 23:03:07.193964372 +1030
+++ gcc4/libffi/testsuite/libffi.call/cls_double_va.c	2013-11-15 23:22:51.383884118 +1030
@@ -38,26 +38,24 @@ int main (void)
 
 	/* This printf call is variadic */
 	CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
-		arg_types) == FFI_OK);
+			       arg_types) == FFI_OK);
 
 	args[0] = &format;
 	args[1] = &doubleArg;
 	args[2] = NULL;
 
 	ffi_call(&cif, FFI_FN(printf), &res, args);
-	// { dg-output "7.0" }
+	/* { dg-output "7.0" } */
 	printf("res: %d\n", (int) res);
-	// { dg-output "\nres: 4" }
+	/* { dg-output "\nres: 4" } */
 
-	/* The call to cls_double_va_fn is static, so have to use a normal prep_cif */
-	CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, arg_types) == FFI_OK);
+	CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL,
+				   code) == FFI_OK);
 
-	CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL, code) == FFI_OK);
-
-	res	= ((int(*)(char*, double))(code))(format, doubleArg);
-	// { dg-output "\n7.0" }
+	res = ((int(*)(char*, ...))(code))(format, doubleArg);
+	/* { dg-output "\n7.0" } */
 	printf("res: %d\n", (int) res);
-	// { dg-output "\nres: 4" }
+	/* { dg-output "\nres: 4" } */
 
 	exit(0);
 }
diff -urp gcc3/libffi/testsuite/libffi.call/cls_longdouble_va.c gcc4/libffi/testsuite/libffi.call/cls_longdouble_va.c
--- gcc3/libffi/testsuite/libffi.call/cls_longdouble_va.c	2013-11-15 23:03:07.205963908 +1030
+++ gcc4/libffi/testsuite/libffi.call/cls_longdouble_va.c	2013-11-15 23:24:19.372455652 +1030
@@ -38,27 +38,24 @@ int main (void)
 
 	/* This printf call is variadic */
 	CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
-		arg_types) == FFI_OK);
+			       arg_types) == FFI_OK);
 
 	args[0] = &format;
 	args[1] = &ldArg;
 	args[2] = NULL;
 
 	ffi_call(&cif, FFI_FN(printf), &res, args);
-	// { dg-output "7.0" }
+	/* { dg-output "7.0" } */
 	printf("res: %d\n", (int) res);
-	// { dg-output "\nres: 4" }
+	/* { dg-output "\nres: 4" } */
 
-	/* The call to cls_longdouble_va_fn is static, so have to use a normal prep_cif */
-	CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
-		arg_types) == FFI_OK);
+	CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL,
+				   code) == FFI_OK);
 
-	CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL, code) == FFI_OK);
-
-	res	= ((int(*)(char*, long double))(code))(format, ldArg);
-	// { dg-output "\n7.0" }
+	res = ((int(*)(char*, ...))(code))(format, ldArg);
+	/* { dg-output "\n7.0" } */
 	printf("res: %d\n", (int) res);
-	// { dg-output "\nres: 4" }
+	/* { dg-output "\nres: 4" } */
 
 	exit(0);
 }

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Support PowerPC64 ELFv2 ABI
  2013-11-16 13:01 [PowerPC] libffi fixes and support for PowerPC64 ELFv2 Alan Modra
                   ` (2 preceding siblings ...)
  2013-11-16 13:06 ` Pass floating point values on powerpc64 as per ABI Alan Modra
@ 2013-11-16 13:11 ` Alan Modra
  2013-11-16 13:12 ` Tidy powerpc linux64_closure.S with defines for stack offsets Alan Modra
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 23+ messages in thread
From: Alan Modra @ 2013-11-16 13:11 UTC (permalink / raw)
  To: gcc-patches, David Edelsohn

Finally, this adds _CALL_ELF == 2 support.  ELFv1 objects can't be
linked with ELFv2 objects, so this is one case where preprocessor
tests in ffi.c are fine.  Also, there is no need to define a new
FFI_ELFv2 or somesuch value in enum ffi_abi.  FFI_LINUX64 will happily
serve both ABIs.

	* src/powerpc/ffitarget.h (FFI_V2_TYPE_FLOAT_HOMOG,
	FFI_V2_TYPE_DOUBLE_HOMOG, FFI_V2_TYPE_SMALL_STRUCT): Define.
	(FFI_TRAMPOLINE_SIZE): Define variant for ELFv2.
	* src/powerpc/ffi.c (FLAG_ARG_NEEDS_PSAVE): Define.
	(discover_homogeneous_aggregate): New function.
	(ffi_prep_args64): Adjust start of param save area for ELFv2.
	Handle homogenous floating point struct parms.
	(ffi_prep_cif_machdep_core): Adjust space calculation for ELFv2.
	Handle ELFv2 return values.  Set FLAG_ARG_NEEDS_PSAVE.  Handle
	homogenous floating point structs.
	(ffi_call): Increase size of smst_buffer for ELFv2.  Handle ELFv2.
	(flush_icache): Compile for ELFv2.
	(ffi_prep_closure_loc): Set up ELFv2 trampoline.
	(ffi_closure_helper_LINUX64): Don't return all structs directly
	to caller.  Handle homogenous floating point structs.  Handle
	ELFv2 struct return values.
	* src/powerpc/linux64.S (ffi_call_LINUX64): Set up r2 for
	ELFv2.  Adjust toc save location.  Call function pointer using
	r12.  Handle FLAG_RETURNS_SMST.  Don't predict branches.
	* src/powerpc/linux64_closure.S (ffi_closure_LINUX64): Set up r2
	for ELFv2.  Define ELFv2 versions of STACKFRAME, PARMSAVE, and
	RETVAL.  Handle possibly missing parameter save area.  Handle
	ELFv2 return values.
	(.note.GNU-stack): Move inside outer #ifdef.

diff -urp gcc6/libffi/src/powerpc/ffitarget.h gcc7/libffi/src/powerpc/ffitarget.h
--- gcc6/libffi/src/powerpc/ffitarget.h	2013-11-15 23:19:21.692053339 +1030
+++ gcc7/libffi/src/powerpc/ffitarget.h	2013-11-15 23:48:02.452807673 +1030
@@ -122,14 +122,23 @@ typedef enum ffi_abi {
    defined in ffi.c, to determine the exact return type and its size.  */
 #define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 2)
 
-#if defined(POWERPC64) || defined(POWERPC_AIX)
+/* Used by ELFv2 for homogenous structure returns.  */
+#define FFI_V2_TYPE_FLOAT_HOMOG		(FFI_TYPE_LAST + 1)
+#define FFI_V2_TYPE_DOUBLE_HOMOG	(FFI_TYPE_LAST + 2)
+#define FFI_V2_TYPE_SMALL_STRUCT	(FFI_TYPE_LAST + 3)
+
+#if _CALL_ELF == 2
+# define FFI_TRAMPOLINE_SIZE 32
+#else
+# if defined(POWERPC64) || defined(POWERPC_AIX)
 #  if defined(POWERPC_DARWIN64)
 #    define FFI_TRAMPOLINE_SIZE 48
 #  else
 #    define FFI_TRAMPOLINE_SIZE 24
 #  endif
-#else /* POWERPC || POWERPC_AIX */
+# else /* POWERPC || POWERPC_AIX */
 #  define FFI_TRAMPOLINE_SIZE 40
+# endif
 #endif
 
 #ifndef LIBFFI_ASM
diff -urp gcc6/libffi/src/powerpc/ffi.c gcc7/libffi/src/powerpc/ffi.c
--- gcc6/libffi/src/powerpc/ffi.c	2013-11-15 23:47:40.153680507 +1030
+++ gcc7/libffi/src/powerpc/ffi.c	2013-11-15 23:51:02.333766929 +1030
@@ -49,6 +49,7 @@ enum {
   FLAG_RETURNS_128BITS  = 1 << (31-27), /* cr6  */
 
   FLAG_ARG_NEEDS_COPY   = 1 << (31- 7),
+  FLAG_ARG_NEEDS_PSAVE  = FLAG_ARG_NEEDS_COPY, /* Used by ELFv2 */
 #ifndef __NO_FPRS__
   FLAG_FP_ARGUMENTS     = 1 << (31- 6), /* cr1.eq; specified by ABI */
 #endif
@@ -383,6 +384,45 @@ enum {
 };
 enum { ASM_NEEDS_REGISTERS64 = 4 };
 
+#if _CALL_ELF == 2
+static unsigned int
+discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
+{
+  switch (t->type)
+    {
+    case FFI_TYPE_FLOAT:
+    case FFI_TYPE_DOUBLE:
+      *elnum = 1;
+      return (int) t->type;
+
+    case FFI_TYPE_STRUCT:;
+      {
+	unsigned int base_elt = 0, total_elnum = 0;
+	ffi_type **el = t->elements;
+	while (*el)
+	  {
+	    unsigned int el_elt, el_elnum = 0;
+	    el_elt = discover_homogeneous_aggregate (*el, &el_elnum);
+	    if (el_elt == 0
+		|| (base_elt && base_elt != el_elt))
+	      return 0;
+	    base_elt = el_elt;
+	    total_elnum += el_elnum;
+	    if (total_elnum > 8)
+	      return 0;
+	    el++;
+	  }
+	*elnum = total_elnum;
+	return base_elt;
+      }
+
+    default:
+      return 0;
+    }
+}
+#endif
+
+
 /* ffi_prep_args64 is called by the assembly routine once stack space
    has been allocated for the function's arguments.
 
@@ -470,7 +510,11 @@ ffi_prep_args64 (extended_cif *ecif, uns
   stacktop.c = (char *) stack + bytes;
   gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64;
   gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64;
+#if _CALL_ELF == 2
+  rest.ul = stack + 4 + NUM_GPR_ARG_REGISTERS64;
+#else
   rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64;
+#endif
   fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
   fparg_count = 0;
   next_arg.ul = gpr_base.ul;
@@ -492,6 +536,8 @@ ffi_prep_args64 (extended_cif *ecif, uns
        i < nargs;
        i++, ptr++, p_argv.v++)
     {
+      unsigned int elt, elnum;
+
       switch ((*ptr)->type)
 	{
 	case FFI_TYPE_FLOAT:
@@ -549,28 +595,79 @@ ffi_prep_args64 (extended_cif *ecif, uns
 	  if (align > 1)
 	    next_arg.p = ALIGN (next_arg.p, align);
 #endif
-	  words = ((*ptr)->size + 7) / 8;
-	  if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
-	    {
-	      size_t first = gpr_end.c - next_arg.c;
-	      memcpy (next_arg.c, *p_argv.c, first);
-	      memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first);
-	      next_arg.c = rest.c + words * 8 - first;
+	  elt = 0;
+#if _CALL_ELF == 2
+	  elt = discover_homogeneous_aggregate (*ptr, &elnum);
+#endif
+	  if (elt)
+	    {
+	      union {
+		void *v;
+		float *f;
+		double *d;
+	      } arg;
+
+	      arg.v = *p_argv.v;
+	      if (elt == FFI_TYPE_FLOAT)
+		{
+		  do
+		    {
+		      double_tmp = *arg.f++;
+		      if (fparg_count < NUM_FPR_ARG_REGISTERS64
+			  && i < nfixedargs)
+			*fpr_base.d++ = double_tmp;
+		      else
+			*next_arg.f = (float) double_tmp;
+		      if (++next_arg.f == gpr_end.f)
+			next_arg.f = rest.f;
+		      fparg_count++;
+		    }
+		  while (--elnum != 0);
+		  if ((next_arg.p & 3) != 0)
+		    {
+		      if (++next_arg.f == gpr_end.f)
+			next_arg.f = rest.f;
+		    }
+		}
+	      else
+		do
+		  {
+		    double_tmp = *arg.d++;
+		    if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
+		      *fpr_base.d++ = double_tmp;
+		    else
+		      *next_arg.d = double_tmp;
+		    if (++next_arg.d == gpr_end.d)
+		      next_arg.d = rest.d;
+		    fparg_count++;
+		  }
+		while (--elnum != 0);
 	    }
 	  else
 	    {
-	      char *where = next_arg.c;
+	      words = ((*ptr)->size + 7) / 8;
+	      if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
+		{
+		  size_t first = gpr_end.c - next_arg.c;
+		  memcpy (next_arg.c, *p_argv.c, first);
+		  memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first);
+		  next_arg.c = rest.c + words * 8 - first;
+		}
+	      else
+		{
+		  char *where = next_arg.c;
 
 #ifndef __LITTLE_ENDIAN__
-	      /* Structures with size less than eight bytes are passed
-		 left-padded.  */
-	      if ((*ptr)->size < 8)
-		where += 8 - (*ptr)->size;
-#endif
-	      memcpy (where, *p_argv.c, (*ptr)->size);
-	      next_arg.ul += words;
-	      if (next_arg.ul == gpr_end.ul)
-		next_arg.ul = rest.ul;
+		  /* Structures with size less than eight bytes are passed
+		     left-padded.  */
+		  if ((*ptr)->size < 8)
+		    where += 8 - (*ptr)->size;
+#endif
+		  memcpy (where, *p_argv.c, (*ptr)->size);
+		  next_arg.ul += words;
+		  if (next_arg.ul == gpr_end.ul)
+		    next_arg.ul = rest.ul;
+		}
 	    }
 	  break;
 
@@ -626,11 +723,10 @@ ffi_prep_cif_machdep_core (ffi_cif *cif)
   unsigned type = cif->rtype->type;
   unsigned size = cif->rtype->size;
 
+  /* The machine-independent calculation of cif->bytes doesn't work
+     for us.  Redo the calculation.  */
   if (cif->abi != FFI_LINUX64)
     {
-      /* All the machine-independent calculation of cif->bytes will be wrong.
-	 Redo the calculation for SYSV.  */
-
       /* Space for the frame pointer, callee's LR, and the asm's temp regs.  */
       bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof (int);
 
@@ -640,13 +736,20 @@ ffi_prep_cif_machdep_core (ffi_cif *cif)
   else
     {
       /* 64-bit ABI.  */
+#if _CALL_ELF == 2
+      /* Space for backchain, CR, LR, TOC and the asm's temp regs.  */
+      bytes = (4 + ASM_NEEDS_REGISTERS64) * sizeof (long);
 
+      /* Space for the general registers.  */
+      bytes += NUM_GPR_ARG_REGISTERS64 * sizeof (long);
+#else
       /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp
 	 regs.  */
       bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long);
 
       /* Space for the mandatory parm save area and general registers.  */
       bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long);
+#endif
     }
 
   /* Return value handling.  The rules for SYSV are as follows:
@@ -724,6 +827,25 @@ ffi_prep_cif_machdep_core (ffi_cif *cif)
 	  flags |= FLAG_RETURNS_SMST;
 	  break;
 	}
+#if _CALL_ELF == 2
+      if (cif->abi == FFI_LINUX64)
+	{
+	  unsigned int elt, elnum;
+	  elt = discover_homogeneous_aggregate (cif->rtype, &elnum);
+	  if (elt)
+	    {
+	      if (elt == FFI_TYPE_DOUBLE)
+		flags |= FLAG_RETURNS_64BITS;
+	      flags |= FLAG_RETURNS_FP | FLAG_RETURNS_SMST;
+	      break;
+	    }
+	  if (size <= 16)
+	    {
+	      flags |= FLAG_RETURNS_SMST;
+	      break;
+	    }
+	}
+#endif
       intarg_count++;
       flags |= FLAG_RETVAL_REFERENCE;
       /* Fall through.  */
@@ -839,6 +961,7 @@ ffi_prep_cif_machdep_core (ffi_cif *cif)
   else
     for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
       {
+	unsigned int elt, elnum;
 #ifdef __STRUCT_PARM_ALIGN__
 	unsigned int align;
 #endif
@@ -849,12 +972,16 @@ ffi_prep_cif_machdep_core (ffi_cif *cif)
 	  case FFI_TYPE_LONGDOUBLE:
 	    fparg_count += 2;
 	    intarg_count += 2;
+	    if (fparg_count > NUM_FPR_ARG_REGISTERS)
+	      flags |= FLAG_ARG_NEEDS_PSAVE;
 	    break;
 #endif
 	  case FFI_TYPE_FLOAT:
 	  case FFI_TYPE_DOUBLE:
 	    fparg_count++;
 	    intarg_count++;
+	    if (fparg_count > NUM_FPR_ARG_REGISTERS)
+	      flags |= FLAG_ARG_NEEDS_PSAVE;
 	    break;
 
 	  case FFI_TYPE_STRUCT:
@@ -867,6 +994,21 @@ ffi_prep_cif_machdep_core (ffi_cif *cif)
 	      intarg_count = ALIGN (intarg_count, align);
 #endif
 	    intarg_count += ((*ptr)->size + 7) / 8;
+	    elt = 0;
+#if _CALL_ELF == 2
+	    elt = discover_homogeneous_aggregate (*ptr, &elnum);
+#endif
+	    if (elt)
+	      {
+		fparg_count += elnum;
+		if (fparg_count > NUM_FPR_ARG_REGISTERS)
+		  flags |= FLAG_ARG_NEEDS_PSAVE;
+	      }
+	    else
+	      {
+		if (intarg_count > NUM_GPR_ARG_REGISTERS)
+		  flags |= FLAG_ARG_NEEDS_PSAVE;
+	      }
 	    break;
 
 	  case FFI_TYPE_POINTER:
@@ -882,9 +1024,11 @@ ffi_prep_cif_machdep_core (ffi_cif *cif)
 	    /* Everything else is passed as a 8-byte word in a GPR, either
 	       the object itself or a pointer to it.  */
 	    intarg_count++;
+	    if (intarg_count > NUM_GPR_ARG_REGISTERS)
+	      flags |= FLAG_ARG_NEEDS_PSAVE;
 	    break;
 	  default:
-		FFI_ASSERT (0);
+	    FFI_ASSERT (0);
 	  }
       }
 
@@ -922,8 +1066,13 @@ ffi_prep_cif_machdep_core (ffi_cif *cif)
 #endif
 
       /* Stack space.  */
+#if _CALL_ELF == 2
+      if ((flags & FLAG_ARG_NEEDS_PSAVE) != 0)
+	bytes += intarg_count * sizeof (long);
+#else
       if (intarg_count > NUM_GPR_ARG_REGISTERS64)
 	bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long);
+#endif
     }
 
   /* The stack space allocated needs to be a multiple of 16 bytes.  */
@@ -951,6 +1100,10 @@ ffi_prep_cif_machdep_var (ffi_cif *cif,
 			  unsigned int ntotalargs MAYBE_UNUSED)
 {
   cif->nfixedargs = nfixedargs;
+#if _CALL_ELF == 2
+  if (cif->abi == FFI_LINUX64)
+    cif->flags |= FLAG_ARG_NEEDS_PSAVE;
+#endif
   return ffi_prep_cif_machdep_core (cif);
 }
 
@@ -970,8 +1123,11 @@ ffi_call(ffi_cif *cif, void (*fn)(void),
    *
    * We bounce-buffer SYSV small struct return values so that sysv.S
    * can write r3 and r4 to memory without worrying about struct size.
+   *
+   * For ELFv2 ABI, use a bounce buffer for homogeneous structs too,
+   * for similar reasons.
    */
-  unsigned int smst_buffer[2];
+  unsigned long smst_buffer[8];
   extended_cif ecif;
 
   ecif.cif = cif;
@@ -1013,10 +1169,11 @@ ffi_call(ffi_cif *cif, void (*fn)(void),
 #ifndef __LITTLE_ENDIAN__
       /* The SYSV ABI returns a structure of up to 4 bytes in size
 	 left-padded in r3.  */
-      if (rsize <= 4)
+      if (cif->abi == FFI_SYSV && rsize <= 4)
 	memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize);
       /* The SYSV ABI returns a structure of up to 8 bytes in size
-	 left-padded in r3/r4.  */
+	 left-padded in r3/r4, and the ELFv2 ABI similarly returns a
+	 structure of up to 8 bytes in size left-padded in r3.  */
       else if (rsize <= 8)
 	memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize);
       else
@@ -1026,7 +1183,7 @@ ffi_call(ffi_cif *cif, void (*fn)(void),
 }
 
 
-#ifndef POWERPC64
+#if !defined POWERPC64 || _CALL_ELF == 2
 #define MIN_CACHE_LINE_SIZE 8
 
 static void
@@ -1050,6 +1207,22 @@ ffi_prep_closure_loc (ffi_closure *closu
 		      void *codeloc)
 {
 #ifdef POWERPC64
+# if _CALL_ELF == 2
+  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
+
+  if (cif->abi != FFI_LINUX64)
+    return FFI_BAD_ABI;
+
+  tramp[0] = 0xe96c0018;	/* 0:	ld	11,2f-0b(12)	*/
+  tramp[1] = 0xe98c0010;	/*	ld	12,1f-0b(12)	*/
+  tramp[2] = 0x7d8903a6;	/*	mtctr	12		*/
+  tramp[3] = 0x4e800420;	/*	bctr			*/
+				/* 1:	.quad	function_addr	*/
+				/* 2:	.quad	context		*/
+  *(void **) &tramp[4] = (void *) ffi_closure_LINUX64;
+  *(void **) &tramp[6] = codeloc;
+  flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE);
+# else
   void **tramp = (void **) &closure->tramp[0];
 
   if (cif->abi != FFI_LINUX64)
@@ -1057,6 +1230,7 @@ ffi_prep_closure_loc (ffi_closure *closu
   /* Copy function address and TOC from ffi_closure_LINUX64.  */
   memcpy (tramp, (char *) ffi_closure_LINUX64, 16);
   tramp[2] = codeloc;
+# endif
 #else
   unsigned int *tramp;
 
@@ -1413,9 +1587,10 @@ ffi_closure_helper_LINUX64 (ffi_closure
   cif = closure->cif;
   avalue = alloca (cif->nargs * sizeof (void *));
 
-  /* Copy the caller's structure return value address so that the closure
-     returns the data directly to the caller.  */
-  if (cif->rtype->type == FFI_TYPE_STRUCT)
+  /* Copy the caller's structure return value address so that the
+     closure returns the data directly to the caller.  */
+  if (cif->rtype->type == FFI_TYPE_STRUCT
+      && (cif->flags & FLAG_RETURNS_SMST) == 0)
     {
       rvalue = (void *) *pst;
       pst++;
@@ -1429,6 +1604,8 @@ ffi_closure_helper_LINUX64 (ffi_closure
   /* Grab the addresses of the arguments from the stack frame.  */
   while (i < avn)
     {
+      unsigned int elt, elnum;
+
       switch (arg_types[i]->type)
 	{
 	case FFI_TYPE_SINT8:
@@ -1470,14 +1647,75 @@ ffi_closure_helper_LINUX64 (ffi_closure
 	  if (align > 1)
 	    pst = (unsigned long *) ALIGN ((size_t) pst, align);
 #endif
-#ifndef __LITTLE_ENDIAN__
-	  /* Structures with size less than eight bytes are passed
-	     left-padded.  */
-	  if (arg_types[i]->size < 8)
-	    avalue[i] = (char *) pst + 8 - arg_types[i]->size;
+	  elt = 0;
+#if _CALL_ELF == 2
+	  elt = discover_homogeneous_aggregate (arg_types[i], &elnum);
+#endif
+	  if (elt)
+	    {
+	      union {
+		void *v;
+		unsigned long *ul;
+		float *f;
+		double *d;
+		size_t p;
+	      } to, from;
+
+	      /* Repackage the aggregate from its parts.  The
+		 aggregate size is not greater than the space taken by
+		 the registers so store back to the register/parameter
+		 save arrays.  */
+	      if (pfr + elnum <= end_pfr)
+		to.v = pfr;
+	      else
+		to.v = pst;
+
+	      avalue[i] = to.v;
+	      from.ul = pst;
+	      if (elt == FFI_TYPE_FLOAT)
+		{
+		  do
+		    {
+		      if (pfr < end_pfr && i < nfixedargs)
+			{
+			  *to.f = (float) pfr->d;
+			  pfr++;
+			}
+		      else
+			*to.f = *from.f;
+		      to.f++;
+		      from.f++;
+		    }
+		  while (--elnum != 0);
+		}
+	      else
+		{
+		  do
+		    {
+		      if (pfr < end_pfr && i < nfixedargs)
+			{
+			  *to.d = pfr->d;
+			  pfr++;
+			}
+		      else
+			*to.d = *from.d;
+		      to.d++;
+		      from.d++;
+		    }
+		  while (--elnum != 0);
+		}
+	    }
 	  else
+	    {
+#ifndef __LITTLE_ENDIAN__
+	      /* Structures with size less than eight bytes are passed
+		 left-padded.  */
+	      if (arg_types[i]->size < 8)
+		avalue[i] = (char *) pst + 8 - arg_types[i]->size;
+	      else
 #endif
-	    avalue[i] = pst;
+		avalue[i] = pst;
+	    }
 	  pst += (arg_types[i]->size + 7) / 8;
 	  break;
 
@@ -1548,5 +1786,14 @@ ffi_closure_helper_LINUX64 (ffi_closure
   (closure->fun) (cif, rvalue, avalue, closure->user_data);
 
   /* Tell ffi_closure_LINUX64 how to perform return type promotions.  */
+  if ((cif->flags & FLAG_RETURNS_SMST) != 0)
+    {
+      if ((cif->flags & FLAG_RETURNS_FP) == 0)
+	return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1;
+      else if ((cif->flags & FLAG_RETURNS_64BITS) != 0)
+	return FFI_V2_TYPE_DOUBLE_HOMOG;
+      else
+	return FFI_V2_TYPE_FLOAT_HOMOG;
+    }
   return cif->rtype->type;
 }
diff -urp gcc6/libffi/src/powerpc/linux64.S gcc7/libffi/src/powerpc/linux64.S
--- gcc6/libffi/src/powerpc/linux64.S	2013-11-15 23:37:49.672792802 +1030
+++ gcc7/libffi/src/powerpc/linux64.S	2013-11-15 23:48:02.452807673 +1030
@@ -32,15 +32,22 @@
 #ifdef __powerpc64__
 	.hidden	ffi_call_LINUX64
 	.globl	ffi_call_LINUX64
+# if _CALL_ELF == 2
+	.text
+ffi_call_LINUX64:
+	addis	%r2, %r12, .TOC.-ffi_call_LINUX64@ha
+	addi	%r2, %r2, .TOC.-ffi_call_LINUX64@l
+	.localentry ffi_call_LINUX64, . - ffi_call_LINUX64
+# else
 	.section	".opd","aw"
 	.align	3
 ffi_call_LINUX64:
-#ifdef _CALL_LINUX
+#  ifdef _CALL_LINUX
 	.quad	.L.ffi_call_LINUX64,.TOC.@tocbase,0
 	.type	ffi_call_LINUX64,@function
 	.text
 .L.ffi_call_LINUX64:
-#else
+#  else
 	.hidden	.ffi_call_LINUX64
 	.globl	.ffi_call_LINUX64
 	.quad	.ffi_call_LINUX64,.TOC.@tocbase,0
@@ -48,7 +55,8 @@ ffi_call_LINUX64:
 	.type	.ffi_call_LINUX64,@function
 	.text
 .ffi_call_LINUX64:
-#endif
+#  endif
+# endif
 .LFB1:
 	mflr	%r0
 	std	%r28, -32(%r1)
@@ -63,26 +71,35 @@ ffi_call_LINUX64:
 	mr	%r31, %r5	/* flags, */
 	mr	%r30, %r6	/* rvalue, */
 	mr	%r29, %r7	/* function address.  */
+/* Save toc pointer, not for the ffi_prep_args64 call, but for the later
+   bctrl function call.  */
+# if _CALL_ELF == 2
+	std	%r2, 24(%r1)
+# else
 	std	%r2, 40(%r1)
+# endif
 
 	/* Call ffi_prep_args64.  */
 	mr	%r4, %r1
-#ifdef _CALL_LINUX
+# if defined _CALL_LINUX || _CALL_ELF == 2
 	bl	ffi_prep_args64
-#else
+# else
 	bl	.ffi_prep_args64
-#endif
+# endif
 
-	ld	%r0, 0(%r29)
+# if _CALL_ELF == 2
+	mr	%r12, %r29
+# else
+	ld	%r12, 0(%r29)
 	ld	%r2, 8(%r29)
 	ld	%r11, 16(%r29)
-
+# endif
 	/* Now do the call.  */
 	/* Set up cr1 with bits 4-7 of the flags.  */
 	mtcrf	0x40, %r31
 
 	/* Get the address to call into CTR.  */
-	mtctr	%r0
+	mtctr	%r12
 	/* Load all those argument registers.  */
 	ld	%r3, -32-(8*8)(%r28)
 	ld	%r4, -32-(7*8)(%r28)
@@ -117,12 +134,17 @@ ffi_call_LINUX64:
 
 	/* This must follow the call immediately, the unwinder
 	   uses this to find out if r2 has been saved or not.  */
+# if _CALL_ELF == 2
+	ld	%r2, 24(%r1)
+# else
 	ld	%r2, 40(%r1)
+# endif
 
 	/* Now, deal with the return value.  */
 	mtcrf	0x01, %r31
-	bt-	30, .Ldone_return_value
-	bt-	29, .Lfp_return_value
+	bt	31, .Lstruct_return_value
+	bt	30, .Ldone_return_value
+	bt	29, .Lfp_return_value
 	std	%r3, 0(%r30)
 	/* Fall through...  */
 
@@ -147,14 +169,48 @@ ffi_call_LINUX64:
 .Lfloat_return_value:
 	stfs	%f1, 0(%r30)
 	b	.Ldone_return_value
+
+.Lstruct_return_value:
+	bf	29, .Lsmall_struct
+	bf	28, .Lfloat_homog_return_value
+	stfd	%f1, 0(%r30)
+	stfd	%f2, 8(%r30)
+	stfd	%f3, 16(%r30)
+	stfd	%f4, 24(%r30)
+	stfd	%f5, 32(%r30)
+	stfd	%f6, 40(%r30)
+	stfd	%f7, 48(%r30)
+	stfd	%f8, 56(%r30)
+	b	.Ldone_return_value
+
+.Lfloat_homog_return_value:
+	stfs	%f1, 0(%r30)
+	stfs	%f2, 4(%r30)
+	stfs	%f3, 8(%r30)
+	stfs	%f4, 12(%r30)
+	stfs	%f5, 16(%r30)
+	stfs	%f6, 20(%r30)
+	stfs	%f7, 24(%r30)
+	stfs	%f8, 28(%r30)
+	b	.Ldone_return_value
+
+.Lsmall_struct:
+	std	%r3, 0(%r30)
+	std	%r4, 8(%r30)
+	b	.Ldone_return_value
+
 .LFE1:
 	.long	0
 	.byte	0,12,0,1,128,4,0,0
-#ifdef _CALL_LINUX
+# if _CALL_ELF == 2
+	.size	ffi_call_LINUX64,.-ffi_call_LINUX64
+# else
+#  ifdef _CALL_LINUX
 	.size	ffi_call_LINUX64,.-.L.ffi_call_LINUX64
-#else
+#  else
 	.size	.ffi_call_LINUX64,.-.ffi_call_LINUX64
-#endif
+#  endif
+# endif
 
 	.section	.eh_frame,EH_FRAME_FLAGS,@progbits
 .Lframe1:
diff -urp gcc6/libffi/src/powerpc/linux64_closure.S gcc7/libffi/src/powerpc/linux64_closure.S
--- gcc6/libffi/src/powerpc/linux64_closure.S	2013-11-15 23:37:49.672792802 +1030
+++ gcc7/libffi/src/powerpc/linux64_closure.S	2013-11-15 23:48:02.452807673 +1030
@@ -33,15 +33,22 @@
 #ifdef __powerpc64__
 	FFI_HIDDEN (ffi_closure_LINUX64)
 	.globl  ffi_closure_LINUX64
+# if _CALL_ELF == 2
+	.text
+ffi_closure_LINUX64:
+	addis	%r2, %r12, .TOC.-ffi_closure_LINUX64@ha
+	addi	%r2, %r2, .TOC.-ffi_closure_LINUX64@l
+	.localentry ffi_closure_LINUX64, . - ffi_closure_LINUX64
+# else
 	.section        ".opd","aw"
 	.align  3
 ffi_closure_LINUX64:
-#ifdef _CALL_LINUX
+#  ifdef _CALL_LINUX
 	.quad   .L.ffi_closure_LINUX64,.TOC.@tocbase,0
 	.type   ffi_closure_LINUX64,@function
 	.text
 .L.ffi_closure_LINUX64:
-#else
+#  else
 	FFI_HIDDEN (.ffi_closure_LINUX64)
 	.globl  .ffi_closure_LINUX64
 	.quad   .ffi_closure_LINUX64,.TOC.@tocbase,0
@@ -49,15 +56,52 @@ ffi_closure_LINUX64:
 	.type   .ffi_closure_LINUX64,@function
 	.text
 .ffi_closure_LINUX64:
-#endif
+#  endif
+# endif
 
+# if _CALL_ELF == 2
+#  32 byte special reg save area + 64 byte parm save area and retval
+#  + 13*8 fpr save area + round to 16
+#  define STACKFRAME 208
+#  define PARMSAVE 32
+#  No parameter save area is needed for the call to ffi_closure_helper_LINUX64,
+#  so return value can start there.
+#  define RETVAL PARMSAVE
+# else
 #  48 bytes special reg save area + 64 bytes parm save area
 #  + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
 #  define STACKFRAME 240
 #  define PARMSAVE 48
 #  define RETVAL PARMSAVE+64
+# endif
 
 .LFB1:
+# if _CALL_ELF == 2
+	ld	%r12, FFI_TRAMPOLINE_SIZE(%r11)		# closure->cif
+	mflr	%r0
+	lwz	%r12, 28(%r12)				# cif->flags
+	mtcrf	0x40, %r12
+	addi	%r12, %r1, PARMSAVE
+	bt	7, .Lparmsave
+	# Our caller has not allocated a parameter save area.
+	# We need to allocate one here and use it to pass gprs to
+	# ffi_closure_helper_LINUX64.  The return value area will do.
+	addi	%r12, %r1, -STACKFRAME+RETVAL
+.Lparmsave:
+	std	%r0, 16(%r1)
+	# Save general regs into parm save area
+	std	%r3, 0(%r12)
+	std	%r4, 8(%r12)
+	std	%r5, 16(%r12)
+	std	%r6, 24(%r12)
+	std	%r7, 32(%r12)
+	std	%r8, 40(%r12)
+	std	%r9, 48(%r12)
+	std	%r10, 56(%r12)
+
+	# load up the pointer to the parm save area
+	mr	%r5, %r12
+# else
 	mflr	%r0
 	# Save general regs into parm save area
 	# This is the parameter save area set up by our caller.
@@ -74,6 +118,7 @@ ffi_closure_LINUX64:
 
 	# load up the pointer to the parm save area
 	addi	%r5, %r1, PARMSAVE
+# endif
 
 	# next save fpr 1 to fpr 13
 	stfd	%f1, -104+(0*8)(%r1)
@@ -103,11 +148,11 @@ ffi_closure_LINUX64:
 	mr	%r3, %r11
 
 	# make the call
-#ifdef _CALL_LINUX
+# if defined _CALL_LINUX || _CALL_ELF == 2
 	bl ffi_closure_helper_LINUX64
-#else
+# else
 	bl .ffi_closure_helper_LINUX64
-#endif
+# endif
 .Lret:
 
 	# now r3 contains the return type
@@ -116,10 +161,12 @@ ffi_closure_LINUX64:
 
 	# look up the proper starting point in table
 	# by using return type as offset
+	ld %r0, STACKFRAME+16(%r1)
+	cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT
+	bge .Lsmall
 	mflr %r4		# move address of .Lret to r4
 	sldi %r3, %r3, 4	# now multiply return type by 16
 	addi %r4, %r4, .Lret_type0 - .Lret
-	ld %r0, STACKFRAME+16(%r1)
 	add %r3, %r3, %r4	# add contents of table to table address
 	mtctr %r3
 	bctr			# jump to it
@@ -234,15 +281,73 @@ ffi_closure_LINUX64:
 	mtlr %r0
 	addi %r1, %r1, STACKFRAME
 	blr
-# esac
+# case FFI_V2_TYPE_FLOAT_HOMOG
+	lfs %f1, RETVAL+0(%r1)
+	lfs %f2, RETVAL+4(%r1)
+	lfs %f3, RETVAL+8(%r1)
+	b .Lmorefloat
+# case FFI_V2_TYPE_DOUBLE_HOMOG
+	lfd %f1, RETVAL+0(%r1)
+	lfd %f2, RETVAL+8(%r1)
+	lfd %f3, RETVAL+16(%r1)
+	lfd %f4, RETVAL+24(%r1)
+	mtlr %r0
+	lfd %f5, RETVAL+32(%r1)
+	lfd %f6, RETVAL+40(%r1)
+	lfd %f7, RETVAL+48(%r1)
+	lfd %f8, RETVAL+56(%r1)
+	addi %r1, %r1, STACKFRAME
+	blr
+.Lmorefloat:
+	lfs %f4, RETVAL+12(%r1)
+	mtlr %r0
+	lfs %f5, RETVAL+16(%r1)
+	lfs %f6, RETVAL+20(%r1)
+	lfs %f7, RETVAL+24(%r1)
+	lfs %f8, RETVAL+28(%r1)
+	addi %r1, %r1, STACKFRAME
+	blr
+.Lsmall:
+# ifdef __LITTLE_ENDIAN__
+	ld %r3,RETVAL+0(%r1)
+	mtlr %r0
+	ld %r4,RETVAL+8(%r1)
+	addi %r1, %r1, STACKFRAME
+	blr
+# else
+	# A struct smaller than a dword is returned in the low bits of r3
+	# ie. right justified.  Larger structs are passed left justified
+	# in r3 and r4.  The return value area on the stack will have
+	# the structs as they are usually stored in memory.
+	cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes?
+	neg %r5, %r3
+	ld %r3,RETVAL+0(%r1)
+	blt .Lsmalldown
+	mtlr %r0
+	ld %r4,RETVAL+8(%r1)
+	addi %r1, %r1, STACKFRAME
+	blr
+.Lsmalldown:
+	addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7
+	mtlr %r0
+	sldi %r5, %r5, 3
+	addi %r1, %r1, STACKFRAME
+	srd %r3, %r3, %r5
+	blr
+# endif
+
 .LFE1:
 	.long	0
 	.byte	0,12,0,1,128,0,0,0
-#ifdef _CALL_LINUX
+# if _CALL_ELF == 2
+	.size	ffi_closure_LINUX64,.-ffi_closure_LINUX64
+# else
+#  ifdef _CALL_LINUX
 	.size	ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64
-#else
+#  else
 	.size	.ffi_closure_LINUX64,.-.ffi_closure_LINUX64
-#endif
+#  endif
+# endif
 
 	.section	.eh_frame,EH_FRAME_FLAGS,@progbits
 .Lframe1:

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Tidy powerpc linux64_closure.S with defines for stack offsets
  2013-11-16 13:01 [PowerPC] libffi fixes and support for PowerPC64 ELFv2 Alan Modra
                   ` (3 preceding siblings ...)
  2013-11-16 13:11 ` Support PowerPC64 ELFv2 ABI Alan Modra
@ 2013-11-16 13:12 ` Alan Modra
  2013-11-16 13:25 ` Align powerpc64 structs passed by value as per ABI Alan Modra
  2013-11-17 18:27 ` [PowerPC] libffi fixes and support for PowerPC64 ELFv2 Alan Modra
  6 siblings, 0 replies; 23+ messages in thread
From: Alan Modra @ 2013-11-16 13:12 UTC (permalink / raw)
  To: gcc-patches, David Edelsohn

This patch prepares for ELFv2, where sizes of these areas change.  It
also makes some minor changes to improve code efficiency.

	* src/powerpc/linux64.S (ffi_call_LINUX64): Tweak restore of r28.
	(.note.GNU-stack): Move inside outer #ifdef.
	* src/powerpc/linux64_closure.S (STACKFRAME, PARMSAVE,
	RETVAL): Define and use throughout.
	(ffi_closure_LINUX64): Save fprs before buying stack.
	(.note.GNU-stack): Move inside outer #ifdef.

diff -urp gcc4/libffi/src/powerpc/linux64.S gcc5/libffi/src/powerpc/linux64.S
--- gcc4/libffi/src/powerpc/linux64.S	2013-11-15 23:03:07.337958821 +1030
+++ gcc5/libffi/src/powerpc/linux64.S	2013-11-15 23:37:49.672792802 +1030
@@ -130,7 +130,7 @@ ffi_call_LINUX64:
 	/* Restore the registers we used and return.  */
 	mr	%r1, %r28
 	ld	%r0, 16(%r28)
-	ld	%r28, -32(%r1)
+	ld	%r28, -32(%r28)
 	mtlr	%r0
 	ld	%r29, -24(%r1)
 	ld	%r30, -16(%r1)
@@ -197,8 +197,8 @@ ffi_call_LINUX64:
 	.uleb128 0x4
 	.align 3
 .LEFDE1:
-#endif
 
-#if defined __ELF__ && defined __linux__
+# if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2
 	.section	.note.GNU-stack,"",@progbits
+# endif
 #endif
diff -urp gcc4/libffi/src/powerpc/linux64_closure.S gcc5/libffi/src/powerpc/linux64_closure.S
--- gcc4/libffi/src/powerpc/linux64_closure.S	2013-11-15 23:03:07.333958973 +1030
+++ gcc5/libffi/src/powerpc/linux64_closure.S	2013-11-15 23:37:49.672792802 +1030
@@ -50,53 +50,57 @@ ffi_closure_LINUX64:
 	.text
 .ffi_closure_LINUX64:
 #endif
+
+#  48 bytes special reg save area + 64 bytes parm save area
+#  + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
+#  define STACKFRAME 240
+#  define PARMSAVE 48
+#  define RETVAL PARMSAVE+64
+
 .LFB1:
-	# save general regs into parm save area
-	std	%r3, 48(%r1)
-	std	%r4, 56(%r1)
-	std	%r5, 64(%r1)
-	std	%r6, 72(%r1)
 	mflr	%r0
+	# Save general regs into parm save area
+	# This is the parameter save area set up by our caller.
+	std	%r3, PARMSAVE+0(%r1)
+	std	%r4, PARMSAVE+8(%r1)
+	std	%r5, PARMSAVE+16(%r1)
+	std	%r6, PARMSAVE+24(%r1)
+	std	%r7, PARMSAVE+32(%r1)
+	std	%r8, PARMSAVE+40(%r1)
+	std	%r9, PARMSAVE+48(%r1)
+	std	%r10, PARMSAVE+56(%r1)
 
-	std	%r7, 80(%r1)
-	std	%r8, 88(%r1)
-	std	%r9, 96(%r1)
-	std	%r10, 104(%r1)
 	std	%r0, 16(%r1)
 
-	# mandatory 48 bytes special reg save area + 64 bytes parm save area
-	# + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
-	stdu	%r1, -240(%r1)
-.LCFI0:
+	# load up the pointer to the parm save area
+	addi	%r5, %r1, PARMSAVE
 
 	# next save fpr 1 to fpr 13
-	stfd  %f1, 128+(0*8)(%r1)
-	stfd  %f2, 128+(1*8)(%r1)
-	stfd  %f3, 128+(2*8)(%r1)
-	stfd  %f4, 128+(3*8)(%r1)
-	stfd  %f5, 128+(4*8)(%r1)
-	stfd  %f6, 128+(5*8)(%r1)
-	stfd  %f7, 128+(6*8)(%r1)
-	stfd  %f8, 128+(7*8)(%r1)
-	stfd  %f9, 128+(8*8)(%r1)
-	stfd  %f10, 128+(9*8)(%r1)
-	stfd  %f11, 128+(10*8)(%r1)
-	stfd  %f12, 128+(11*8)(%r1)
-	stfd  %f13, 128+(12*8)(%r1)
+	stfd	%f1, -104+(0*8)(%r1)
+	stfd	%f2, -104+(1*8)(%r1)
+	stfd	%f3, -104+(2*8)(%r1)
+	stfd	%f4, -104+(3*8)(%r1)
+	stfd	%f5, -104+(4*8)(%r1)
+	stfd	%f6, -104+(5*8)(%r1)
+	stfd	%f7, -104+(6*8)(%r1)
+	stfd	%f8, -104+(7*8)(%r1)
+	stfd	%f9, -104+(8*8)(%r1)
+	stfd	%f10, -104+(9*8)(%r1)
+	stfd	%f11, -104+(10*8)(%r1)
+	stfd	%f12, -104+(11*8)(%r1)
+	stfd	%f13, -104+(12*8)(%r1)
 
-	# set up registers for the routine that actually does the work
-	# get the context pointer from the trampoline
-	mr %r3, %r11
+	# load up the pointer to the saved fpr registers */
+	addi	%r6, %r1, -104
 
-	# now load up the pointer to the result storage
-	addi %r4, %r1, 112
+	# load up the pointer to the result storage
+	addi	%r4, %r1, -STACKFRAME+RETVAL
 
-	# now load up the pointer to the parameter save area
-	# in the previous frame
-	addi %r5, %r1, 240 + 48
+	stdu	%r1, -STACKFRAME(%r1)
+.LCFI0:
 
-	# now load up the pointer to the saved fpr registers */
-	addi %r6, %r1, 128
+	# get the context pointer from the trampoline
+	mr	%r3, %r11
 
 	# make the call
 #ifdef _CALL_LINUX
@@ -115,7 +119,7 @@ ffi_closure_LINUX64:
 	mflr %r4		# move address of .Lret to r4
 	sldi %r3, %r3, 4	# now multiply return type by 16
 	addi %r4, %r4, .Lret_type0 - .Lret
-	ld %r0, 240+16(%r1)
+	ld %r0, STACKFRAME+16(%r1)
 	add %r3, %r3, %r4	# add contents of table to table address
 	mtctr %r3
 	bctr			# jump to it
@@ -128,107 +132,107 @@ ffi_closure_LINUX64:
 .Lret_type0:
 # case FFI_TYPE_VOID
 	mtlr %r0
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 	nop
 # case FFI_TYPE_INT
-#ifdef __LITTLE_ENDIAN__
-	lwa %r3, 112+0(%r1)
-#else
-	lwa %r3, 112+4(%r1)
-#endif
+# ifdef __LITTLE_ENDIAN__
+	lwa %r3, RETVAL+0(%r1)
+# else
+	lwa %r3, RETVAL+4(%r1)
+# endif
 	mtlr %r0
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 # case FFI_TYPE_FLOAT
-	lfs %f1, 112+0(%r1)
+	lfs %f1, RETVAL+0(%r1)
 	mtlr %r0
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 # case FFI_TYPE_DOUBLE
-	lfd %f1, 112+0(%r1)
+	lfd %f1, RETVAL+0(%r1)
 	mtlr %r0
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 # case FFI_TYPE_LONGDOUBLE
-	lfd %f1, 112+0(%r1)
+	lfd %f1, RETVAL+0(%r1)
 	mtlr %r0
-	lfd %f2, 112+8(%r1)
+	lfd %f2, RETVAL+8(%r1)
 	b .Lfinish
 # case FFI_TYPE_UINT8
-#ifdef __LITTLE_ENDIAN__
-	lbz %r3, 112+0(%r1)
-#else
-	lbz %r3, 112+7(%r1)
-#endif
+# ifdef __LITTLE_ENDIAN__
+	lbz %r3, RETVAL+0(%r1)
+# else
+	lbz %r3, RETVAL+7(%r1)
+# endif
 	mtlr %r0
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 # case FFI_TYPE_SINT8
-#ifdef __LITTLE_ENDIAN__
-	lbz %r3, 112+0(%r1)
-#else
-	lbz %r3, 112+7(%r1)
-#endif
+# ifdef __LITTLE_ENDIAN__
+	lbz %r3, RETVAL+0(%r1)
+# else
+	lbz %r3, RETVAL+7(%r1)
+# endif
 	extsb %r3,%r3
 	mtlr %r0
 	b .Lfinish
 # case FFI_TYPE_UINT16
-#ifdef __LITTLE_ENDIAN__
-	lhz %r3, 112+0(%r1)
-#else
-	lhz %r3, 112+6(%r1)
-#endif
+# ifdef __LITTLE_ENDIAN__
+	lhz %r3, RETVAL+0(%r1)
+# else
+	lhz %r3, RETVAL+6(%r1)
+# endif
 	mtlr %r0
 .Lfinish:
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 # case FFI_TYPE_SINT16
-#ifdef __LITTLE_ENDIAN__
-	lha %r3, 112+0(%r1)
-#else
-	lha %r3, 112+6(%r1)
-#endif
+# ifdef __LITTLE_ENDIAN__
+	lha %r3, RETVAL+0(%r1)
+# else
+	lha %r3, RETVAL+6(%r1)
+# endif
 	mtlr %r0
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 # case FFI_TYPE_UINT32
-#ifdef __LITTLE_ENDIAN__
-	lwz %r3, 112+0(%r1)
-#else
-	lwz %r3, 112+4(%r1)
-#endif
+# ifdef __LITTLE_ENDIAN__
+	lwz %r3, RETVAL+0(%r1)
+# else
+	lwz %r3, RETVAL+4(%r1)
+# endif
 	mtlr %r0
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 # case FFI_TYPE_SINT32
-#ifdef __LITTLE_ENDIAN__
-	lwa %r3, 112+0(%r1)
-#else
-	lwa %r3, 112+4(%r1)
-#endif
+# ifdef __LITTLE_ENDIAN__
+	lwa %r3, RETVAL+0(%r1)
+# else
+	lwa %r3, RETVAL+4(%r1)
+# endif
 	mtlr %r0
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 # case FFI_TYPE_UINT64
-	ld %r3, 112+0(%r1)
+	ld %r3, RETVAL+0(%r1)
 	mtlr %r0
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 # case FFI_TYPE_SINT64
-	ld %r3, 112+0(%r1)
+	ld %r3, RETVAL+0(%r1)
 	mtlr %r0
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 # case FFI_TYPE_STRUCT
 	mtlr %r0
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 	nop
 # case FFI_TYPE_POINTER
-	ld %r3, 112+0(%r1)
+	ld %r3, RETVAL+0(%r1)
 	mtlr %r0
-	addi %r1, %r1, 240
+	addi %r1, %r1, STACKFRAME
 	blr
 # esac
 .LFE1:
@@ -267,14 +271,14 @@ ffi_closure_LINUX64:
 	.byte	0x2	 # DW_CFA_advance_loc1
 	.byte	.LCFI0-.LFB1
 	.byte	0xe	 # DW_CFA_def_cfa_offset
-	.uleb128 240
+	.uleb128 STACKFRAME
 	.byte	0x11	 # DW_CFA_offset_extended_sf
 	.uleb128 0x41
 	.sleb128 -2
 	.align 3
 .LEFDE1:
-#endif
 
-#if defined __ELF__ && defined __linux__
+# if defined __ELF__ && defined __linux__
 	.section	.note.GNU-stack,"",@progbits
+# endif
 #endif

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Align powerpc64 structs passed by value as per ABI
  2013-11-16 13:01 [PowerPC] libffi fixes and support for PowerPC64 ELFv2 Alan Modra
                   ` (4 preceding siblings ...)
  2013-11-16 13:12 ` Tidy powerpc linux64_closure.S with defines for stack offsets Alan Modra
@ 2013-11-16 13:25 ` Alan Modra
  2013-11-17 18:27 ` [PowerPC] libffi fixes and support for PowerPC64 ELFv2 Alan Modra
  6 siblings, 0 replies; 23+ messages in thread
From: Alan Modra @ 2013-11-16 13:25 UTC (permalink / raw)
  To: gcc-patches, David Edelsohn

The powerpc64 ABIs align structs passed by value, a fact ignored by
gcc for quite some time.  Since gcc now does the correct alignment,
libffi needs to follow suit.  This ought to be made selectable via
a new abi value, and the #ifdefs removed from ffi.c along with almost
all the other #ifdefs present there and in assembly.

	* src/powerpc/ffi.c (ffi_prep_args64): Align struct parameters
	according to __STRUCT_PARM_ALIGN__.
	(ffi_prep_cif_machdep_core): Likewise.
	(ffi_closure_helper_LINUX64): Likewise.

diff -urp gcc5/libffi/src/powerpc/ffi.c gcc6/libffi/src/powerpc/ffi.c
--- gcc5/libffi/src/powerpc/ffi.c	2013-11-15 23:47:31.890003986 +1030
+++ gcc6/libffi/src/powerpc/ffi.c	2013-11-15 23:47:40.153680507 +1030
@@ -428,6 +428,7 @@ ffi_prep_args64 (extended_cif *ecif, uns
     unsigned long *ul;
     float *f;
     double *d;
+    size_t p;
   } valp;
 
   /* 'stacktop' points at the previous backchain pointer.  */
@@ -462,6 +463,9 @@ ffi_prep_args64 (extended_cif *ecif, uns
     double **d;
   } p_argv;
   unsigned long gprvalue;
+#ifdef __STRUCT_PARM_ALIGN__
+  unsigned long align;
+#endif
 
   stacktop.c = (char *) stack + bytes;
   gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64;
@@ -538,6 +542,13 @@ ffi_prep_args64 (extended_cif *ecif, uns
 #endif
 
 	case FFI_TYPE_STRUCT:
+#ifdef __STRUCT_PARM_ALIGN__
+	  align = (*ptr)->alignment;
+	  if (align > __STRUCT_PARM_ALIGN__)
+	    align = __STRUCT_PARM_ALIGN__;
+	  if (align > 1)
+	    next_arg.p = ALIGN (next_arg.p, align);
+#endif
 	  words = ((*ptr)->size + 7) / 8;
 	  if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
 	    {
@@ -828,6 +839,10 @@ ffi_prep_cif_machdep_core (ffi_cif *cif)
   else
     for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
       {
+#ifdef __STRUCT_PARM_ALIGN__
+	unsigned int align;
+#endif
+
 	switch ((*ptr)->type)
 	  {
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
@@ -843,6 +858,14 @@ ffi_prep_cif_machdep_core (ffi_cif *cif)
 	    break;
 
 	  case FFI_TYPE_STRUCT:
+#ifdef __STRUCT_PARM_ALIGN__
+	    align = (*ptr)->alignment;
+	    if (align > __STRUCT_PARM_ALIGN__)
+	      align = __STRUCT_PARM_ALIGN__;
+	    align = align / 8;
+	    if (align > 1)
+	      intarg_count = ALIGN (intarg_count, align);
+#endif
 	    intarg_count += ((*ptr)->size + 7) / 8;
 	    break;
 
@@ -1383,6 +1406,9 @@ ffi_closure_helper_LINUX64 (ffi_closure
   unsigned long i, avn, nfixedargs;
   ffi_cif *cif;
   ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
+#ifdef __STRUCT_PARM_ALIGN__
+  unsigned long align;
+#endif
 
   cif = closure->cif;
   avalue = alloca (cif->nargs * sizeof (void *));
@@ -1437,6 +1463,13 @@ ffi_closure_helper_LINUX64 (ffi_closure
 	  break;
 
 	case FFI_TYPE_STRUCT:
+#ifdef __STRUCT_PARM_ALIGN__
+	  align = arg_types[i]->alignment;
+	  if (align > __STRUCT_PARM_ALIGN__)
+	    align = __STRUCT_PARM_ALIGN__;
+	  if (align > 1)
+	    pst = (unsigned long *) ALIGN ((size_t) pst, align);
+#endif
 #ifndef __LITTLE_ENDIAN__
 	  /* Structures with size less than eight bytes are passed
 	     left-padded.  */

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PowerPC] libffi fixes and support for PowerPC64 ELFv2
  2013-11-16 13:01 [PowerPC] libffi fixes and support for PowerPC64 ELFv2 Alan Modra
                   ` (5 preceding siblings ...)
  2013-11-16 13:25 ` Align powerpc64 structs passed by value as per ABI Alan Modra
@ 2013-11-17 18:27 ` Alan Modra
  2013-11-18  0:22   ` David Edelsohn
  6 siblings, 1 reply; 23+ messages in thread
From: Alan Modra @ 2013-11-17 18:27 UTC (permalink / raw)
  To: gcc-patches, David Edelsohn

On Sat, Nov 16, 2013 at 10:18:05PM +1030, Alan Modra wrote:
> The following six patches correspond to patches posted to the libffi
> mailing list a few days ago to add support for PowerPC64 ELFv2.  The

The ChangeLog just became easier to write.  :)

	* src/powerpc/ffitarget.h: Import from upstream.
	* src/powerpc/ffi.c: Likewise.
	* src/powerpc/linux64.S: Likewise.
	* src/powerpc/linux64_closure.S: Likewise.
	* doc/libffi.texi: Likewise.
	* testsuite/libffi.call/cls_double_va.c: Likewise.
	* testsuite/libffi.call/cls_longdouble_va.c: Likewise.

OK to apply?

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PowerPC] libffi fixes and support for PowerPC64 ELFv2
  2013-11-17 18:27 ` [PowerPC] libffi fixes and support for PowerPC64 ELFv2 Alan Modra
@ 2013-11-18  0:22   ` David Edelsohn
  2013-11-18  2:09     ` Alan Modra
  0 siblings, 1 reply; 23+ messages in thread
From: David Edelsohn @ 2013-11-18  0:22 UTC (permalink / raw)
  To: GCC Patches, Alan Modra

On Sun, Nov 17, 2013 at 1:25 AM, Alan Modra <amodra@gmail.com> wrote:
> On Sat, Nov 16, 2013 at 10:18:05PM +1030, Alan Modra wrote:
>> The following six patches correspond to patches posted to the libffi
>> mailing list a few days ago to add support for PowerPC64 ELFv2.  The
>
> The ChangeLog just became easier to write.  :)
>
>         * src/powerpc/ffitarget.h: Import from upstream.
>         * src/powerpc/ffi.c: Likewise.
>         * src/powerpc/linux64.S: Likewise.
>         * src/powerpc/linux64_closure.S: Likewise.
>         * doc/libffi.texi: Likewise.
>         * testsuite/libffi.call/cls_double_va.c: Likewise.
>         * testsuite/libffi.call/cls_longdouble_va.c: Likewise.
>
> OK to apply?

Okay.

Thanks, David

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PowerPC] libffi fixes and support for PowerPC64 ELFv2
  2013-11-18  0:22   ` David Edelsohn
@ 2013-11-18  2:09     ` Alan Modra
  2013-11-22  7:48       ` Alan Modra
  0 siblings, 1 reply; 23+ messages in thread
From: Alan Modra @ 2013-11-18  2:09 UTC (permalink / raw)
  To: David Edelsohn; +Cc: GCC Patches

On Sun, Nov 17, 2013 at 07:53:59AM -0500, David Edelsohn wrote:
> On Sun, Nov 17, 2013 at 1:25 AM, Alan Modra <amodra@gmail.com> wrote:
> > On Sat, Nov 16, 2013 at 10:18:05PM +1030, Alan Modra wrote:
> >> The following six patches correspond to patches posted to the libffi
> >> mailing list a few days ago to add support for PowerPC64 ELFv2.  The
> >
> > The ChangeLog just became easier to write.  :)
> >
> >         * src/powerpc/ffitarget.h: Import from upstream.
> >         * src/powerpc/ffi.c: Likewise.
> >         * src/powerpc/linux64.S: Likewise.
> >         * src/powerpc/linux64_closure.S: Likewise.
> >         * doc/libffi.texi: Likewise.
> >         * testsuite/libffi.call/cls_double_va.c: Likewise.
> >         * testsuite/libffi.call/cls_longdouble_va.c: Likewise.
> >
> > OK to apply?
> 
> Okay.
> 
> Thanks, David

Committed revision 204917.  I'm also going to apply the following as
obvious.  The error I'm fixing here doesn't cause a runtime failure,
but does mess with the processor return branch prediction.

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 204917)
+++ ChangeLog	(working copy)
@@ -1,5 +1,7 @@
 2013-11-18  Alan Modra  <amodra@gmail.com>
 
+	* src/powerpc/ppc_closure.S: Don't bl .Luint128.
+
 	* src/powerpc/ffitarget.h: Import from upstream.
 	* src/powerpc/ffi.c: Likewise.
 	* src/powerpc/linux64.S: Likewise.
Index: src/powerpc/ppc_closure.S
===================================================================
--- src/powerpc/ppc_closure.S	(revision 204916)
+++ src/powerpc/ppc_closure.S	(working copy)
@@ -238,7 +238,7 @@
 	lwz %r3,112+0(%r1)
 	lwz %r4,112+4(%r1)
 	lwz %r5,112+8(%r1)
-	bl .Luint128
+	b .Luint128
 
 # The return types below are only used when the ABI type is FFI_SYSV.
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Pass floating point values on powerpc64 as per ABI
  2013-11-16 13:06 ` Pass floating point values on powerpc64 as per ABI Alan Modra
@ 2013-11-18 10:17   ` Andreas Schwab
  2013-11-19  2:30     ` Alan Modra
  0 siblings, 1 reply; 23+ messages in thread
From: Andreas Schwab @ 2013-11-18 10:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Edelsohn

Alan Modra <amodra@gmail.com> writes:

> diff -urp gcc3/libffi/testsuite/libffi.call/cls_double_va.c gcc4/libffi/testsuite/libffi.call/cls_double_va.c
> --- gcc3/libffi/testsuite/libffi.call/cls_double_va.c	2013-11-15 23:03:07.193964372 +1030
> +++ gcc4/libffi/testsuite/libffi.call/cls_double_va.c	2013-11-15 23:22:51.383884118 +1030
> @@ -38,26 +38,24 @@ int main (void)
>  
>  	/* This printf call is variadic */
>  	CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
> -		arg_types) == FFI_OK);
> +			       arg_types) == FFI_OK);
>  
>  	args[0] = &format;
>  	args[1] = &doubleArg;
>  	args[2] = NULL;
>  
>  	ffi_call(&cif, FFI_FN(printf), &res, args);
> -	// { dg-output "7.0" }
> +	/* { dg-output "7.0" } */
>  	printf("res: %d\n", (int) res);
> -	// { dg-output "\nres: 4" }
> +	/* { dg-output "\nres: 4" } */
>  
> -	/* The call to cls_double_va_fn is static, so have to use a normal prep_cif */
> -	CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, arg_types) == FFI_OK);

This breaks ia64:

FAIL: libffi.call/cls_double_va.c -O0 -W -Wall output pattern test, is 7.0
res: 4
0.0
res: 4
, should match 7.0?
res: 4?
7.0?
res: 4

FAIL: libffi.call/cls_longdouble_va.c -O0 -W -Wall output pattern test, is 7.0
res: 4
0.0
res: 4
, should match 7.0?
res: 4?
7.0?
res: 4

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Pass floating point values on powerpc64 as per ABI
  2013-11-18 10:17   ` Andreas Schwab
@ 2013-11-19  2:30     ` Alan Modra
  2013-11-19  3:30       ` Andreas Schwab
  0 siblings, 1 reply; 23+ messages in thread
From: Alan Modra @ 2013-11-19  2:30 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: gcc-patches, David Edelsohn

On Mon, Nov 18, 2013 at 10:10:39AM +0100, Andreas Schwab wrote:
> Alan Modra <amodra@gmail.com> writes:
> 
> > -	/* The call to cls_double_va_fn is static, so have to use a normal prep_cif */
> > -	CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, arg_types) == FFI_OK);
> 
> This breaks ia64:
> 
> FAIL: libffi.call/cls_double_va.c -O0 -W -Wall output pattern test, is 7.0
> res: 4
> 0.0
> res: 4
> , should match 7.0?
> res: 4?
> 7.0?
> res: 4

This indicates a real error in the ia64 libffi support.  The test was
bogus before, in exactly the same way as if you defined a function as
int f(char *, ...)
but declared it and called it in another file as
int f(char *, double)
To add to the confusion, someone wrote a comment that it had to be
that way because "cls_double_va_fn is static"..

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Pass floating point values on powerpc64 as per ABI
  2013-11-19  2:30     ` Alan Modra
@ 2013-11-19  3:30       ` Andreas Schwab
  2013-11-19  3:49         ` Alan Modra
  0 siblings, 1 reply; 23+ messages in thread
From: Andreas Schwab @ 2013-11-19  3:30 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Edelsohn

Alan Modra <amodra@gmail.com> writes:

> On Mon, Nov 18, 2013 at 10:10:39AM +0100, Andreas Schwab wrote:
>> Alan Modra <amodra@gmail.com> writes:
>> 
>> > -	/* The call to cls_double_va_fn is static, so have to use a normal prep_cif */
>> > -	CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, arg_types) == FFI_OK);
>> 
>> This breaks ia64:
>> 
>> FAIL: libffi.call/cls_double_va.c -O0 -W -Wall output pattern test, is 7.0
>> res: 4
>> 0.0
>> res: 4
>> , should match 7.0?
>> res: 4?
>> 7.0?
>> res: 4
>
> This indicates a real error in the ia64 libffi support.  The test was
> bogus before, in exactly the same way as if you defined a function as
> int f(char *, ...)
> but declared it and called it in another file as
> int f(char *, double)

Where does it call a varargs function?

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Pass floating point values on powerpc64 as per ABI
  2013-11-19  3:30       ` Andreas Schwab
@ 2013-11-19  3:49         ` Alan Modra
  2013-11-19  5:17           ` Alan Modra
  0 siblings, 1 reply; 23+ messages in thread
From: Alan Modra @ 2013-11-19  3:49 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: gcc-patches, David Edelsohn

On Tue, Nov 19, 2013 at 01:27:39AM +0100, Andreas Schwab wrote:
> Alan Modra <amodra@gmail.com> writes:
> 
> > On Mon, Nov 18, 2013 at 10:10:39AM +0100, Andreas Schwab wrote:
> >> Alan Modra <amodra@gmail.com> writes:
> >> 
> >> > -	/* The call to cls_double_va_fn is static, so have to use a normal prep_cif */
> >> > -	CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, arg_types) == FFI_OK);
> >> 
> >> This breaks ia64:
> >> 
> >> FAIL: libffi.call/cls_double_va.c -O0 -W -Wall output pattern test, is 7.0
> >> res: 4
> >> 0.0
> >> res: 4
> >> , should match 7.0?
> >> res: 4?
> >> 7.0?
> >> res: 4
> >
> > This indicates a real error in the ia64 libffi support.  The test was
> > bogus before, in exactly the same way as if you defined a function as
> > int f(char *, ...)
> > but declared it and called it in another file as
> > int f(char *, double)
> 
> Where does it call a varargs function?

printf

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Pass floating point values on powerpc64 as per ABI
  2013-11-19  3:49         ` Alan Modra
@ 2013-11-19  5:17           ` Alan Modra
  2013-11-19 10:22             ` Andreas Schwab
  0 siblings, 1 reply; 23+ messages in thread
From: Alan Modra @ 2013-11-19  5:17 UTC (permalink / raw)
  To: Andreas Schwab, gcc-patches, David Edelsohn

On Tue, Nov 19, 2013 at 11:16:26AM +1030, Alan Modra wrote:
> On Tue, Nov 19, 2013 at 01:27:39AM +0100, Andreas Schwab wrote:
> > Where does it call a varargs function?
> 
> printf

Sorry that wasn't such a helpful response.

Here, really:
	res = ((int(*)(char*, ...))(code))(format, doubleArg);

Prior to that point ffi_prep_cif_var and ffi_prep_closure_loc have set
things up to expect a varargs function.  The old test didn't test a
closure call with variable arguments.  Actually that makes my claims
about calling functions differently to the way they were defined
wrong.  The old test didn't actually do that, since there was another
ffi_prep_cif call that said the closure was not varargs, and the call
matched that.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Pass floating point values on powerpc64 as per ABI
  2013-11-19  5:17           ` Alan Modra
@ 2013-11-19 10:22             ` Andreas Schwab
  2013-11-25 11:02               ` Alan Modra
  0 siblings, 1 reply; 23+ messages in thread
From: Andreas Schwab @ 2013-11-19 10:22 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Edelsohn

Alan Modra <amodra@gmail.com> writes:

> On Tue, Nov 19, 2013 at 11:16:26AM +1030, Alan Modra wrote:
>> On Tue, Nov 19, 2013 at 01:27:39AM +0100, Andreas Schwab wrote:
>> > Where does it call a varargs function?
>> 
>> printf
>
> Sorry that wasn't such a helpful response.
>
> Here, really:
> 	res = ((int(*)(char*, ...))(code))(format, doubleArg);

But cls_double_va_fn doesn't expect a varargs call.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PowerPC] libffi fixes and support for PowerPC64 ELFv2
  2013-11-18  2:09     ` Alan Modra
@ 2013-11-22  7:48       ` Alan Modra
  2013-12-02  6:29         ` Alan Modra
                           ` (2 more replies)
  0 siblings, 3 replies; 23+ messages in thread
From: Alan Modra @ 2013-11-22  7:48 UTC (permalink / raw)
  To: David Edelsohn; +Cc: gcc-patches

David,
Here comes the inevitable followup..  I broke backwards compatibility
when adding an extra field to ffi_cif.  I'd like to import again from
upstream, where I've already fixed the problem.

https://sourceware.org/ml/libffi-discuss/2013/msg00220.html

Actually, it's not a straight import because many files outside of
libffi/src/powerpc/ have diverged, but fortunately for me, not
significantly.  For the record, I've shown the files that need
patching below.  Identical patches went in upstream (except for
formatting differences in Makefile.am).  Bootstrapped etc.
powerpc64-linux and powerpc64le-linux.  OK to apply?

libffi/
	* src/powerpc/ffitarget.h: Import from upstream.
	* src/powerpc/ffi_powerpc.h: Likewise.
	* src/powerpc/ffi.c: Likewise.
	* src/powerpc/ffi_sysv.c: Likewise.
	* src/powerpc/ffi_linux64.c: Likewise.
	* src/powerpc/sysv.S: Likewise.
	* src/powerpc/ppc_closure.S: Likewise.
	* src/powerpc/linux64.S: Likewise.
	* src/powerpc/linux64_closure.S: Likewise.
	* src/types.c: Likewise.
	* Makefile.am (EXTRA_DIST): Add new src/powerpc files.
	(nodist_libffi_la_SOURCES <POWERPC, POWERPC_FREEBSD>): Likewise.
	* configure.ac (HAVE_LONG_DOUBLE_VARIANT): Define for powerpc.
	* include/ffi.h.in (ffi_prep_types): Declare.
	* src/prep_cif.c (ffi_prep_cif_core): Call ffi_prep_types.
	* configure: Regenerate.
	* fficonfig.h.in: Regenerate.
	* Makefile.in: Regenerate.
	* man/Makefile.in: Regenerate.
	* include/Makefile.in: Regenerate.
	* testsuite/Makefile.in: Regenerate.

Index: libffi/include/ffi.h.in
===================================================================
--- libffi/include/ffi.h.in	(revision 205058)
+++ libffi/include/ffi.h.in	(working copy)
@@ -207,6 +207,11 @@
 #endif
 } ffi_cif;
 
+#if HAVE_LONG_DOUBLE_VARIANT
+/* Used to adjust size/alignment of ffi types.  */
+void ffi_prep_types (ffi_abi abi);
+# endif
+
 /* Used internally, but overridden by some architectures */
 ffi_status ffi_prep_cif_core(ffi_cif *cif,
 			     ffi_abi abi,
Index: libffi/src/prep_cif.c
===================================================================
--- libffi/src/prep_cif.c	(revision 205058)
+++ libffi/src/prep_cif.c	(working copy)
@@ -126,6 +126,10 @@
 
   cif->flags = 0;
 
+#if HAVE_LONG_DOUBLE_VARIANT
+  ffi_prep_types (abi);
+#endif
+
   /* Initialize the return type if necessary */
   if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
     return FFI_BAD_TYPEDEF;
Index: libffi/configure.ac
===================================================================
--- libffi/configure.ac	(revision 205058)
+++ libffi/configure.ac	(working copy)
@@ -65,6 +65,7 @@
 AM_CONDITIONAL(TESTSUBDIR, test -d $srcdir/testsuite)
 
 TARGETDIR="unknown"
+HAVE_LONG_DOUBLE_VARIANT=0
 case "$host" in
   aarch64*-*-*)
 	TARGET=AARCH64; TARGETDIR=aarch64
@@ -162,6 +163,7 @@
 
   powerpc*-*-linux* | powerpc-*-sysv*)
 	TARGET=POWERPC; TARGETDIR=powerpc
+	HAVE_LONG_DOUBLE_VARIANT=1
 	;;
   powerpc-*-amigaos*)
 	TARGET=POWERPC; TARGETDIR=powerpc
@@ -177,6 +179,7 @@
 	;;
   powerpc-*-freebsd* | powerpc-*-openbsd*)
 	TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc
+	HAVE_LONG_DOUBLE_VARIANT=1
 	;;
   powerpc64-*-freebsd*)
 	TARGET=POWERPC; TARGETDIR=powerpc
@@ -273,14 +276,20 @@
 # Also AC_SUBST this variable for ffi.h.
 if test -z "$HAVE_LONG_DOUBLE"; then
   HAVE_LONG_DOUBLE=0
-  if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then
-    if test $ac_cv_sizeof_long_double != 0; then
+  if test $ac_cv_sizeof_long_double != 0; then
+    if test $HAVE_LONG_DOUBLE_VARIANT != 0; then
+      AC_DEFINE(HAVE_LONG_DOUBLE_VARIANT, 1, [Define if you support more than one size of the long double type])
       HAVE_LONG_DOUBLE=1
-      AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the long double type and it is bigger than a double])
+    else
+      if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then
+        HAVE_LONG_DOUBLE=1
+        AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the long double type and it is bigger than a double])
+      fi
     fi
   fi
 fi
 AC_SUBST(HAVE_LONG_DOUBLE)
+AC_SUBST(HAVE_LONG_DOUBLE_VARIANT)
 
 AC_C_BIGENDIAN
 
Index: libffi/Makefile.am
===================================================================
--- libffi/Makefile.am	(revision 205058)
+++ libffi/Makefile.am	(working copy)
@@ -15,10 +15,12 @@
 	 src/ia64/unix.S src/mips/ffi.c src/mips/n32.S src/mips/o32.S	\
 	 src/mips/ffitarget.h src/m32r/ffi.c src/m32r/sysv.S		\
 	 src/m32r/ffitarget.h src/m68k/ffi.c src/m68k/sysv.S		\
-	 src/m68k/ffitarget.h src/powerpc/ffi.c src/powerpc/sysv.S	\
-	 src/powerpc/linux64.S src/powerpc/linux64_closure.S		\
-	 src/powerpc/ppc_closure.S src/powerpc/asm.h			\
-	src/powerpc/aix.S src/powerpc/darwin.S				\
+	 src/m68k/ffitarget.h						\
+	src/powerpc/ffi.c src/powerpc/ffi_powerpc.h			\
+	src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c		\
+	src/powerpc/sysv.S src/powerpc/linux64.S			\
+	src/powerpc/linux64_closure.S src/powerpc/ppc_closure.S		\
+	src/powerpc/asm.h src/powerpc/aix.S src/powerpc/darwin.S	\
 	src/powerpc/aix_closure.S src/powerpc/darwin_closure.S		\
 	src/powerpc/ffi_darwin.c src/powerpc/ffitarget.h		\
 	src/s390/ffi.c src/s390/sysv.S src/s390/ffitarget.h		\
@@ -179,7 +181,7 @@
 nodist_libffi_la_SOURCES += src/m68k/ffi.c src/m68k/sysv.S
 endif
 if POWERPC
-nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S
+nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S
 endif
 if POWERPC_AIX
 nodist_libffi_la_SOURCES += src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S
@@ -188,7 +190,7 @@
 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
+nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/sysv.S src/powerpc/ppc_closure.S
 endif
 if AARCH64
 nodist_libffi_la_SOURCES += src/aarch64/sysv.S src/aarch64/ffi.c

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Pass floating point values on powerpc64 as per ABI
  2013-11-19 10:22             ` Andreas Schwab
@ 2013-11-25 11:02               ` Alan Modra
  0 siblings, 0 replies; 23+ messages in thread
From: Alan Modra @ 2013-11-25 11:02 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: gcc-patches, David Edelsohn

On Tue, Nov 19, 2013 at 10:16:31AM +0100, Andreas Schwab wrote:
> Alan Modra <amodra@gmail.com> writes:
> 
> > On Tue, Nov 19, 2013 at 11:16:26AM +1030, Alan Modra wrote:
> >> On Tue, Nov 19, 2013 at 01:27:39AM +0100, Andreas Schwab wrote:
> >> > Where does it call a varargs function?
> >> 
> >> printf
> >
> > Sorry that wasn't such a helpful response.
> >
> > Here, really:
> > 	res = ((int(*)(char*, ...))(code))(format, doubleArg);
> 
> But cls_double_va_fn doesn't expect a varargs call.

It works this way:  The call shown above sets up arguments as for a
call to printf, and transfers control to a trampoline.  On powerpc64
the trampoline bounces to ffi_closure_LINUX64.  This assembly function
saves parameter passing registers to memory and calls some C code,
ffi_closure_helper_LINUX64, that uses information set up by
ffi_prep_cif_var to extract the arguments and package them up for
cls_double_va_fn.  So it is ffi_closure_helper_LINUX64 that expects a
varargs call, under control of ffi_prep_cif_var.

It looks to me like the new libffi test failures on ia64 are due to
libffi on ia64 not differentiating between varargs and normal calls,
yet ia64 passes passes fp differently for varargs if I'm reading
gcc/config/ia64.c function_arg correctly.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PowerPC] libffi fixes and support for PowerPC64 ELFv2
  2013-11-22  7:48       ` Alan Modra
@ 2013-12-02  6:29         ` Alan Modra
  2013-12-03 14:06         ` David Edelsohn
  2013-12-09 17:02         ` David Edelsohn
  2 siblings, 0 replies; 23+ messages in thread
From: Alan Modra @ 2013-12-02  6:29 UTC (permalink / raw)
  To: David Edelsohn, gcc-patches

Ping http://gcc.gnu.org/ml/gcc-patches/2013-11/msg02793.html

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PowerPC] libffi fixes and support for PowerPC64 ELFv2
  2013-11-22  7:48       ` Alan Modra
  2013-12-02  6:29         ` Alan Modra
@ 2013-12-03 14:06         ` David Edelsohn
  2013-12-04  0:45           ` Alan Modra
  2013-12-09 17:02         ` David Edelsohn
  2 siblings, 1 reply; 23+ messages in thread
From: David Edelsohn @ 2013-12-03 14:06 UTC (permalink / raw)
  To: David Edelsohn, GCC Patches

On Thu, Nov 21, 2013 at 9:57 PM, Alan Modra <amodra@gmail.com> wrote:
> David,
> Here comes the inevitable followup..  I broke backwards compatibility
> when adding an extra field to ffi_cif.  I'd like to import again from
> upstream, where I've already fixed the problem.
>
> https://sourceware.org/ml/libffi-discuss/2013/msg00220.html
>
> Actually, it's not a straight import because many files outside of
> libffi/src/powerpc/ have diverged, but fortunately for me, not
> significantly.  For the record, I've shown the files that need
> patching below.  Identical patches went in upstream (except for
> formatting differences in Makefile.am).  Bootstrapped etc.
> powerpc64-linux and powerpc64le-linux.  OK to apply?
>
> libffi/
>         * src/powerpc/ffitarget.h: Import from upstream.
>         * src/powerpc/ffi_powerpc.h: Likewise.
>         * src/powerpc/ffi.c: Likewise.
>         * src/powerpc/ffi_sysv.c: Likewise.
>         * src/powerpc/ffi_linux64.c: Likewise.
>         * src/powerpc/sysv.S: Likewise.
>         * src/powerpc/ppc_closure.S: Likewise.
>         * src/powerpc/linux64.S: Likewise.
>         * src/powerpc/linux64_closure.S: Likewise.
>         * src/types.c: Likewise.
>         * Makefile.am (EXTRA_DIST): Add new src/powerpc files.
>         (nodist_libffi_la_SOURCES <POWERPC, POWERPC_FREEBSD>): Likewise.
>         * configure.ac (HAVE_LONG_DOUBLE_VARIANT): Define for powerpc.
>         * include/ffi.h.in (ffi_prep_types): Declare.
>         * src/prep_cif.c (ffi_prep_cif_core): Call ffi_prep_types.
>         * configure: Regenerate.
>         * fficonfig.h.in: Regenerate.
>         * Makefile.in: Regenerate.
>         * man/Makefile.in: Regenerate.
>         * include/Makefile.in: Regenerate.
>         * testsuite/Makefile.in: Regenerate.

Have you tested this patch on targets other than powerpc-linux? Have
you tested this patch on AIX?

- David

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PowerPC] libffi fixes and support for PowerPC64 ELFv2
  2013-12-03 14:06         ` David Edelsohn
@ 2013-12-04  0:45           ` Alan Modra
  2013-12-04  3:41             ` David Edelsohn
  0 siblings, 1 reply; 23+ messages in thread
From: Alan Modra @ 2013-12-04  0:45 UTC (permalink / raw)
  To: David Edelsohn; +Cc: GCC Patches

On Tue, Dec 03, 2013 at 09:05:53AM -0500, David Edelsohn wrote:
> On Thu, Nov 21, 2013 at 9:57 PM, Alan Modra <amodra@gmail.com> wrote:
> > David,
> > Here comes the inevitable followup..  I broke backwards compatibility
> > when adding an extra field to ffi_cif.  I'd like to import again from
> > upstream, where I've already fixed the problem.
> >
> > https://sourceware.org/ml/libffi-discuss/2013/msg00220.html
> >
> > Actually, it's not a straight import because many files outside of
> > libffi/src/powerpc/ have diverged, but fortunately for me, not
> > significantly.  For the record, I've shown the files that need
> > patching below.  Identical patches went in upstream (except for
> > formatting differences in Makefile.am).  Bootstrapped etc.
> > powerpc64-linux and powerpc64le-linux.  OK to apply?
> >
> > libffi/
> >         * src/powerpc/ffitarget.h: Import from upstream.
> >         * src/powerpc/ffi_powerpc.h: Likewise.
> >         * src/powerpc/ffi.c: Likewise.
> >         * src/powerpc/ffi_sysv.c: Likewise.
> >         * src/powerpc/ffi_linux64.c: Likewise.
> >         * src/powerpc/sysv.S: Likewise.
> >         * src/powerpc/ppc_closure.S: Likewise.
> >         * src/powerpc/linux64.S: Likewise.
> >         * src/powerpc/linux64_closure.S: Likewise.
> >         * src/types.c: Likewise.
> >         * Makefile.am (EXTRA_DIST): Add new src/powerpc files.
> >         (nodist_libffi_la_SOURCES <POWERPC, POWERPC_FREEBSD>): Likewise.
> >         * configure.ac (HAVE_LONG_DOUBLE_VARIANT): Define for powerpc.
> >         * include/ffi.h.in (ffi_prep_types): Declare.
> >         * src/prep_cif.c (ffi_prep_cif_core): Call ffi_prep_types.
> >         * configure: Regenerate.
> >         * fficonfig.h.in: Regenerate.
> >         * Makefile.in: Regenerate.
> >         * man/Makefile.in: Regenerate.
> >         * include/Makefile.in: Regenerate.
> >         * testsuite/Makefile.in: Regenerate.
> 
> Have you tested this patch on targets other than powerpc-linux? Have
> you tested this patch on AIX?

I haven't tested on AIX or Darwin, sorry  If you find any problems on
AIX, please let me know and I'll fix them.  I have tested on
powerpc-linux, powerpc64-linux, powerpc64le-linux and powerpc-freebsd,
which are the targets most affected by this change.  I have also
bootstrapped and regression tested x86_64-linux gcc with this patch
applied.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PowerPC] libffi fixes and support for PowerPC64 ELFv2
  2013-12-04  0:45           ` Alan Modra
@ 2013-12-04  3:41             ` David Edelsohn
  0 siblings, 0 replies; 23+ messages in thread
From: David Edelsohn @ 2013-12-04  3:41 UTC (permalink / raw)
  To: GCC Patches, Alan Modra

> I haven't tested on AIX or Darwin, sorry  If you find any problems on
> AIX, please let me know and I'll fix them.  I have tested on
> powerpc-linux, powerpc64-linux, powerpc64le-linux and powerpc-freebsd,
> which are the targets most affected by this change.  I have also
> bootstrapped and regression tested x86_64-linux gcc with this patch
> applied.

I will try to test it soon on AIX and let you know.

- David

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PowerPC] libffi fixes and support for PowerPC64 ELFv2
  2013-11-22  7:48       ` Alan Modra
  2013-12-02  6:29         ` Alan Modra
  2013-12-03 14:06         ` David Edelsohn
@ 2013-12-09 17:02         ` David Edelsohn
  2 siblings, 0 replies; 23+ messages in thread
From: David Edelsohn @ 2013-12-09 17:02 UTC (permalink / raw)
  To: GCC Patches, Alan Modra

On Thu, Nov 21, 2013 at 9:57 PM, Alan Modra <amodra@gmail.com> wrote:
> David,
> Here comes the inevitable followup..  I broke backwards compatibility
> when adding an extra field to ffi_cif.  I'd like to import again from
> upstream, where I've already fixed the problem.
>
> https://sourceware.org/ml/libffi-discuss/2013/msg00220.html
>
> Actually, it's not a straight import because many files outside of
> libffi/src/powerpc/ have diverged, but fortunately for me, not
> significantly.  For the record, I've shown the files that need
> patching below.  Identical patches went in upstream (except for
> formatting differences in Makefile.am).  Bootstrapped etc.
> powerpc64-linux and powerpc64le-linux.  OK to apply?
>
> libffi/
>         * src/powerpc/ffitarget.h: Import from upstream.
>         * src/powerpc/ffi_powerpc.h: Likewise.
>         * src/powerpc/ffi.c: Likewise.
>         * src/powerpc/ffi_sysv.c: Likewise.
>         * src/powerpc/ffi_linux64.c: Likewise.
>         * src/powerpc/sysv.S: Likewise.
>         * src/powerpc/ppc_closure.S: Likewise.
>         * src/powerpc/linux64.S: Likewise.
>         * src/powerpc/linux64_closure.S: Likewise.
>         * src/types.c: Likewise.
>         * Makefile.am (EXTRA_DIST): Add new src/powerpc files.
>         (nodist_libffi_la_SOURCES <POWERPC, POWERPC_FREEBSD>): Likewise.
>         * configure.ac (HAVE_LONG_DOUBLE_VARIANT): Define for powerpc.
>         * include/ffi.h.in (ffi_prep_types): Declare.
>         * src/prep_cif.c (ffi_prep_cif_core): Call ffi_prep_types.
>         * configure: Regenerate.
>         * fficonfig.h.in: Regenerate.
>         * Makefile.in: Regenerate.
>         * man/Makefile.in: Regenerate.
>         * include/Makefile.in: Regenerate.
>         * testsuite/Makefile.in: Regenerate.

Okay.

- David

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2013-12-09 17:02 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-16 13:01 [PowerPC] libffi fixes and support for PowerPC64 ELFv2 Alan Modra
2013-11-16 13:03 ` Reinstate powerpc bounce buffer copying in ffi.c Alan Modra
2013-11-16 13:05 ` libffi doc fixes Alan Modra
2013-11-16 13:06 ` Pass floating point values on powerpc64 as per ABI Alan Modra
2013-11-18 10:17   ` Andreas Schwab
2013-11-19  2:30     ` Alan Modra
2013-11-19  3:30       ` Andreas Schwab
2013-11-19  3:49         ` Alan Modra
2013-11-19  5:17           ` Alan Modra
2013-11-19 10:22             ` Andreas Schwab
2013-11-25 11:02               ` Alan Modra
2013-11-16 13:11 ` Support PowerPC64 ELFv2 ABI Alan Modra
2013-11-16 13:12 ` Tidy powerpc linux64_closure.S with defines for stack offsets Alan Modra
2013-11-16 13:25 ` Align powerpc64 structs passed by value as per ABI Alan Modra
2013-11-17 18:27 ` [PowerPC] libffi fixes and support for PowerPC64 ELFv2 Alan Modra
2013-11-18  0:22   ` David Edelsohn
2013-11-18  2:09     ` Alan Modra
2013-11-22  7:48       ` Alan Modra
2013-12-02  6:29         ` Alan Modra
2013-12-03 14:06         ` David Edelsohn
2013-12-04  0:45           ` Alan Modra
2013-12-04  3:41             ` David Edelsohn
2013-12-09 17:02         ` David Edelsohn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).