public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Fix PR libffi/60073
@ 2014-02-13 16:19 Eric Botcazou
  2014-02-14  9:55 ` Alan Modra
  2014-02-17 12:00 ` Eric Botcazou
  0 siblings, 2 replies; 5+ messages in thread
From: Eric Botcazou @ 2014-02-13 16:19 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 785 bytes --]

This adds proper variadic support to the SPARC port of libffi, thus fixing a 
regression in the testsuite in 64-bit mode, and fixes a small inaccuracy in 
the documentation.

Tested on SPARC/Solaris and SPARC64/Solaris, applied on the mainline.


2014-02-13  Eric Botcazou  <ebotcazou@adacore.com>

	PR libffi/60073
	* src/sparc/ffitarget.h (FFI_TARGET_SPECIFIC_VARIADIC): Define.
	(FFI_EXTRA_CIF_FIELDS): Likewise.
	(FFI_NATIVE_RAW_API): Move around.
	* src/sparc/ffi.c (ffi_prep_cif_machdep_core): New function from...
	(ffi_prep_cif_machdep): ...here.  Call ffi_prep_cif_machdep_core.
	(ffi_prep_cif_machdep_var): New function.
	(ffi_closure_sparc_inner_v9): Do not pass anonymous FP arguments in
	FP registers.
	* doc/libffi.texi (Introduction): Fix inaccuracy.


-- 
Eric Botcazou

[-- Attachment #2: pr60073.diff --]
[-- Type: text/x-patch, Size: 4469 bytes --]

Index: src/sparc/ffitarget.h
===================================================================
--- src/sparc/ffitarget.h	(revision 207685)
+++ src/sparc/ffitarget.h	(working copy)
@@ -58,16 +58,17 @@ typedef enum ffi_abi {
 } ffi_abi;
 #endif
 
+#define FFI_TARGET_SPECIFIC_VARIADIC 1
+#define FFI_EXTRA_CIF_FIELDS unsigned int nfixedargs
+
 /* ---- Definitions for closures ----------------------------------------- */
 
 #define FFI_CLOSURES 1
-#define FFI_NATIVE_RAW_API 0
-
 #ifdef SPARC64
 #define FFI_TRAMPOLINE_SIZE 24
 #else
 #define FFI_TRAMPOLINE_SIZE 16
 #endif
+#define FFI_NATIVE_RAW_API 0
 
 #endif
-
Index: src/sparc/ffi.c
===================================================================
--- src/sparc/ffi.c	(revision 207685)
+++ src/sparc/ffi.c	(working copy)
@@ -249,7 +249,7 @@ int ffi_prep_args_v9(char *stack, extend
 }
 
 /* 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)
 {
   int wordsize;
 
@@ -334,6 +334,19 @@ ffi_status ffi_prep_cif_machdep(ffi_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)
+{
+  cif->nfixedargs = nfixedargs;
+  return ffi_prep_cif_machdep_core (cif);
+}
+
 int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
 {
   ffi_type **ptr = &arg->elements[0];
@@ -604,8 +617,7 @@ ffi_closure_sparc_inner_v9(ffi_closure *
 
   /* Copy the caller's structure return address so that the closure
      returns the data directly to the caller.  */
-  if (cif->flags == FFI_TYPE_VOID
-      && cif->rtype->type == FFI_TYPE_STRUCT)
+  if (cif->flags == FFI_TYPE_VOID && cif->rtype->type == FFI_TYPE_STRUCT)
     {
       rvalue = (void *) gpr[0];
       /* Skip the structure return address.  */
@@ -619,6 +631,10 @@ ffi_closure_sparc_inner_v9(ffi_closure *
   /* Grab the addresses of the arguments from the stack frame.  */
   for (i = 0; i < cif->nargs; i++)
     {
+      /* If the function is variadic, FP arguments are passed in FP
+	 registers only if the corresponding parameter is named.  */
+      const int named = (i < cif->nfixedargs);
+
       if (arg_types[i]->type == FFI_TYPE_STRUCT)
 	{
 	  if (arg_types[i]->size > 16)
@@ -633,7 +649,9 @@ ffi_closure_sparc_inner_v9(ffi_closure *
 				   0,
 				   (char *) &gpr[argn],
 				   (char *) &gpr[argn],
-				   (char *) &fpr[argn]);
+				   named
+				   ? (char *) &fpr[argn]
+				   : (char *) &gpr[argn]);
 	      avalue[i] = &gpr[argn];
 	      argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
 	    }
@@ -649,6 +667,7 @@ ffi_closure_sparc_inner_v9(ffi_closure *
 	    argn++;
 #endif
 	  if (i < fp_slot_max
+	      && named
 	      && (arg_types[i]->type == FFI_TYPE_FLOAT
 		  || arg_types[i]->type == FFI_TYPE_DOUBLE
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
@@ -662,7 +681,7 @@ ffi_closure_sparc_inner_v9(ffi_closure *
     }
 
   /* Invoke the closure.  */
-  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+  closure->fun (cif, rvalue, avalue, closure->user_data);
 
   /* Tell ffi_closure_sparc how to perform return type promotions.  */
   return cif->rtype->type;
Index: doc/libffi.texi
===================================================================
--- doc/libffi.texi	(revision 207685)
+++ doc/libffi.texi	(working copy)
@@ -63,14 +63,14 @@ section entitled ``GNU General Public Li
 @node Introduction
 @chapter What is libffi?
 
-Compilers for high level languages generate code that follow certain
+Compilers for high-level languages generate code that follow certain
 conventions.  These conventions are necessary, in part, for separate
 compilation to work.  One such convention is the @dfn{calling
 convention}.  The calling convention is a set of assumptions made by
 the compiler about where function arguments will be found on entry to
 a function.  A calling convention also specifies where the return
-value for a function is found.  The calling convention is also
-sometimes called the @dfn{ABI} or @dfn{Application Binary Interface}.
+value for a function is found.  The calling convention is part of
+what is called the @dfn{ABI} or @dfn{Application Binary Interface}.
 @cindex calling convention
 @cindex ABI
 @cindex Application Binary Interface

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

* Re: Fix PR libffi/60073
  2014-02-13 16:19 Fix PR libffi/60073 Eric Botcazou
@ 2014-02-14  9:55 ` Alan Modra
  2014-02-14 10:33   ` Eric Botcazou
  2014-02-17 12:00 ` Eric Botcazou
  1 sibling, 1 reply; 5+ messages in thread
From: Alan Modra @ 2014-02-14  9:55 UTC (permalink / raw)
  To: Eric Botcazou; +Cc: gcc-patches

On Thu, Feb 13, 2014 at 05:18:10PM +0100, Eric Botcazou wrote:
> This adds proper variadic support to the SPARC port of libffi, thus fixing a 
> regression in the testsuite in 64-bit mode, and fixes a small inaccuracy in 
> the documentation.
> 
> Tested on SPARC/Solaris and SPARC64/Solaris, applied on the mainline.

> +ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
> +{
> +  cif->nfixedargs = cif->nargs;
> +  return ffi_prep_cif_machdep_core (cif);
> +}

Eric, sorry to rain on your parade, but you're making the same mistake
I did at first when adding powerpc64le support to libffi.  libffi is
built as a shared library.  You can't add a field to ffi_cif like this
and uncondionally write to it:  An application linked against an older
version of libffi will only allocate the old size ffi_cif.  Your new
shared library will trash some random location in the old user app..
I worked around this problem on powerpc by defining new enum ffi_abi
values so that you can recognize an old app.

-- 
Alan Modra
Australia Development Lab, IBM

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

* Re: Fix PR libffi/60073
  2014-02-14  9:55 ` Alan Modra
@ 2014-02-14 10:33   ` Eric Botcazou
  0 siblings, 0 replies; 5+ messages in thread
From: Eric Botcazou @ 2014-02-14 10:33 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

> Eric, sorry to rain on your parade, but you're making the same mistake
> I did at first when adding powerpc64le support to libffi.  libffi is
> built as a shared library.  You can't add a field to ffi_cif like this
> and uncondionally write to it:  An application linked against an older
> version of libffi will only allocate the old size ffi_cif.  Your new
> shared library will trash some random location in the old user app..

OK, I didn't realize that libffi was built as a shared library.  That seems a 
little strange and inconvenient for a glue library.

> I worked around this problem on powerpc by defining new enum ffi_abi
> values so that you can recognize an old app.

I see, thanks for the heads up and the hint!

-- 
Eric Botcazou

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

* Re: Fix PR libffi/60073
  2014-02-13 16:19 Fix PR libffi/60073 Eric Botcazou
  2014-02-14  9:55 ` Alan Modra
@ 2014-02-17 12:00 ` Eric Botcazou
  1 sibling, 0 replies; 5+ messages in thread
From: Eric Botcazou @ 2014-02-17 12:00 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1527 bytes --]

> This adds proper variadic support to the SPARC port of libffi, thus fixing a
> regression in the testsuite in 64-bit mode, and fixes a small inaccuracy in
> the documentation.

Follow-up patch attached.  It renames the existing FFI_V9 into FFI_COMPAT_V9 
and defines a new FFI_V9 value.  In order to avoid disturbing the V8 part, the 
new field is only added for V9, which means that more code is compiled only 
for SPARC64, hence some internal re-shuffling.

Tested on SPARC/Solaris and SPARC64/Solaris, both in a regular setup and in a 
mixed GCC 4.8/mainline setup, applied on the mainline.


2014-02-17  Eric Botcazou  <ebotcazou@adacore.com>

	PR libffi/60073
	* src/sparc/v8.S: Assemble only if !SPARC64.
	* src/sparc/v9.S: Remove obsolete comment.
	* src/sparc/ffitarget.h (enum ffi_abi): Add FFI_COMPAT_V9.
	(V8_ABI_P): New macro.
	(V9_ABI_P): Likewise.
	(FFI_EXTRA_CIF_FIELDS): Define only if SPARC64.
	* src/sparc/ffi.c (ffi_prep_args_v8): Compile only if !SPARC64.
	(ffi_prep_args_v9): Compile only if SPARC64.
	(ffi_prep_cif_machdep_core): Use V9_ABI_P predicate.
	(ffi_prep_cif_machdep): Guard access to nfixedargs field.
	(ffi_prep_cif_machdep_var): Likewise.
	(ffi_v9_layout_struct): Compile only if SPARC64.
	(ffi_call): Deal with FFI_V8PLUS and FFI_COMPAT_V9 and fix warnings.
	(ffi_prep_closure_loc): Use V9_ABI_P and V8_ABI_P predicates.
	(ffi_closure_sparc_inner_v8): Compile only if !SPARC64.
	(ffi_closure_sparc_inner_v9): Compile only if SPARC64.  Guard access
	to nfixedargs field.


-- 
Eric Botcazou

[-- Attachment #2: pr60073-2.diff --]
[-- Type: text/x-patch, Size: 17921 bytes --]

Index: src/sparc/v9.S
===================================================================
--- src/sparc/v9.S	(revision 207796)
+++ src/sparc/v9.S	(working copy)
@@ -1,6 +1,6 @@
 /* -----------------------------------------------------------------------
    v9.S - Copyright (c) 2000, 2003, 2004, 2008 Red Hat, Inc.
-   
+
    SPARC 64-bit Foreign Function Interface 
 
    Permission is hereby granted, free of charge, to any person obtaining
@@ -29,8 +29,6 @@
 #include <ffi.h>
 
 #ifdef SPARC64
-/* Only compile this in for 64bit builds, because otherwise the object file
-   will have inproper architecture due to used instructions.  */
 
 #define STACKFRAME 176		/* Minimum stack framesize for SPARC 64-bit */
 #define STACK_BIAS 2047
Index: src/sparc/ffitarget.h
===================================================================
--- src/sparc/ffitarget.h	(revision 207796)
+++ src/sparc/ffitarget.h	(working copy)
@@ -48,6 +48,8 @@ typedef enum ffi_abi {
   FFI_FIRST_ABI = 0,
   FFI_V8,
   FFI_V8PLUS,
+  /* See below for the COMPAT_V9 rationale.  */
+  FFI_COMPAT_V9,
   FFI_V9,
   FFI_LAST_ABI,
 #ifdef SPARC64
@@ -58,8 +60,19 @@ typedef enum ffi_abi {
 } ffi_abi;
 #endif
 
+#define V8_ABI_P(abi) ((abi) == FFI_V8 || (abi) == FFI_V8PLUS)
+#define V9_ABI_P(abi) ((abi) == FFI_COMPAT_V9 || (abi) == FFI_V9)
+
 #define FFI_TARGET_SPECIFIC_VARIADIC 1
+
+/* The support of variadic functions was broken in the original implementation
+   of the FFI_V9 ABI.  This has been fixed by adding one extra field to the
+   CIF structure (nfixedargs field), which means that the ABI of libffi itself
+   has changed.  In order to support applications using the original ABI, we
+   have renamed FFI_V9 into FFI_COMPAT_V9 and defined a new FFI_V9 value.  */
+#ifdef SPARC64
 #define FFI_EXTRA_CIF_FIELDS unsigned int nfixedargs
+#endif
 
 /* ---- Definitions for closures ----------------------------------------- */
 
Index: src/sparc/ffi.c
===================================================================
--- src/sparc/ffi.c	(revision 207796)
+++ src/sparc/ffi.c	(working copy)
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------
    ffi.c - Copyright (c) 2011 Anthony Green
            Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc.
-   
+
    SPARC Foreign Function Interface 
 
    Permission is hereby granted, free of charge, to any person obtaining
@@ -34,93 +34,10 @@
 /* ffi_prep_args is called by the assembly routine once stack space
    has been allocated for the function's arguments */
 
-void ffi_prep_args_v8(char *stack, extended_cif *ecif)
-{
-  int i;
-  void **p_argv;
-  char *argp;
-  ffi_type **p_arg;
-
-  /* Skip 16 words for the window save area */
-  argp = stack + 16*sizeof(int);
-
-  /* This should only really be done when we are returning a structure,
-     however, it's faster just to do it all the time...
-
-  if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
-  *(int *) argp = (long)ecif->rvalue;
-
-  /* And 1 word for the  structure return value. */
-  argp += sizeof(int);
-
-#ifdef USING_PURIFY
-  /* Purify will probably complain in our assembly routine, unless we
-     zero out this memory. */
-
-  ((int*)argp)[0] = 0;
-  ((int*)argp)[1] = 0;
-  ((int*)argp)[2] = 0;
-  ((int*)argp)[3] = 0;
-  ((int*)argp)[4] = 0;
-  ((int*)argp)[5] = 0;
-#endif
-
-  p_argv = ecif->avalue;
-
-  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
-    {
-      size_t z;
-
-	  if ((*p_arg)->type == FFI_TYPE_STRUCT
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-	      || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
-#endif
-	      )
-	    {
-	      *(unsigned int *) argp = (unsigned long)(* p_argv);
-	      z = sizeof(int);
-	    }
-	  else
-	    {
-	      z = (*p_arg)->size;
-	      if (z < sizeof(int))
-		{
-		  z = sizeof(int);
-		  switch ((*p_arg)->type)
-		    {
-		    case FFI_TYPE_SINT8:
-		      *(signed int *) argp = *(SINT8 *)(* p_argv);
-		      break;
-		      
-		    case FFI_TYPE_UINT8:
-		      *(unsigned int *) argp = *(UINT8 *)(* p_argv);
-		      break;
-		      
-		    case FFI_TYPE_SINT16:
-		      *(signed int *) argp = *(SINT16 *)(* p_argv);
-		      break;
-		      
-		    case FFI_TYPE_UINT16:
-		      *(unsigned int *) argp = *(UINT16 *)(* p_argv);
-		      break;
-
-		    default:
-		      FFI_ASSERT(0);
-		    }
-		}
-	      else
-		{
-		  memcpy(argp, *p_argv, z);
-		}
-	    }
-	  p_argv++;
-	  argp += z;
-    }
-  
-  return;
-}
+#ifdef SPARC64
 
-int ffi_prep_args_v9(char *stack, extended_cif *ecif)
+int
+ffi_prep_args_v9(char *stack, extended_cif *ecif)
 {
   int i, ret = 0;
   int tmp;
@@ -248,12 +165,105 @@ int ffi_prep_args_v9(char *stack, extend
   return ret;
 }
 
+#else
+
+void
+ffi_prep_args_v8(char *stack, extended_cif *ecif)
+{
+  int i;
+  void **p_argv;
+  char *argp;
+  ffi_type **p_arg;
+
+  /* Skip 16 words for the window save area */
+  argp = stack + 16*sizeof(int);
+
+  /* This should only really be done when we are returning a structure,
+     however, it's faster just to do it all the time...
+
+  if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
+  *(int *) argp = (long)ecif->rvalue;
+
+  /* And 1 word for the  structure return value. */
+  argp += sizeof(int);
+
+#ifdef USING_PURIFY
+  /* Purify will probably complain in our assembly routine, unless we
+     zero out this memory. */
+
+  ((int*)argp)[0] = 0;
+  ((int*)argp)[1] = 0;
+  ((int*)argp)[2] = 0;
+  ((int*)argp)[3] = 0;
+  ((int*)argp)[4] = 0;
+  ((int*)argp)[5] = 0;
+#endif
+
+  p_argv = ecif->avalue;
+
+  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
+    {
+      size_t z;
+
+	  if ((*p_arg)->type == FFI_TYPE_STRUCT
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+	      || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
+#endif
+	      )
+	    {
+	      *(unsigned int *) argp = (unsigned long)(* p_argv);
+	      z = sizeof(int);
+	    }
+	  else
+	    {
+	      z = (*p_arg)->size;
+	      if (z < sizeof(int))
+		{
+		  z = sizeof(int);
+		  switch ((*p_arg)->type)
+		    {
+		    case FFI_TYPE_SINT8:
+		      *(signed int *) argp = *(SINT8 *)(* p_argv);
+		      break;
+		      
+		    case FFI_TYPE_UINT8:
+		      *(unsigned int *) argp = *(UINT8 *)(* p_argv);
+		      break;
+		      
+		    case FFI_TYPE_SINT16:
+		      *(signed int *) argp = *(SINT16 *)(* p_argv);
+		      break;
+		      
+		    case FFI_TYPE_UINT16:
+		      *(unsigned int *) argp = *(UINT16 *)(* p_argv);
+		      break;
+
+		    default:
+		      FFI_ASSERT(0);
+		    }
+		}
+	      else
+		{
+		  memcpy(argp, *p_argv, z);
+		}
+	    }
+	  p_argv++;
+	  argp += z;
+    }
+  
+  return;
+}
+
+#endif
+
 /* Perform machine dependent cif processing */
-static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
+
+static
+ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
 {
   int wordsize;
 
-  if (cif->abi != FFI_V9)
+  if (!V9_ABI_P (cif->abi))
     {
       wordsize = 4;
 
@@ -303,7 +313,7 @@ static ffi_status ffi_prep_cif_machdep_c
       break;
 
     case FFI_TYPE_STRUCT:
-      if (cif->abi == FFI_V9 && cif->rtype->size > 32)
+      if (V9_ABI_P (cif->abi) && cif->rtype->size > 32)
 	cif->flags = FFI_TYPE_VOID;
       else
 	cif->flags = FFI_TYPE_STRUCT;
@@ -313,7 +323,7 @@ static ffi_status ffi_prep_cif_machdep_c
     case FFI_TYPE_UINT8:
     case FFI_TYPE_SINT16:
     case FFI_TYPE_UINT16:
-      if (cif->abi == FFI_V9)
+      if (V9_ABI_P (cif->abi))
 	cif->flags = FFI_TYPE_INT;
       else
 	cif->flags = cif->rtype->type;
@@ -321,7 +331,7 @@ static ffi_status ffi_prep_cif_machdep_c
 
     case FFI_TYPE_SINT64:
     case FFI_TYPE_UINT64:
-      if (cif->abi == FFI_V9)
+      if (V9_ABI_P (cif->abi))
 	cif->flags = FFI_TYPE_INT;
       else
 	cif->flags = FFI_TYPE_SINT64;
@@ -334,20 +344,31 @@ static ffi_status ffi_prep_cif_machdep_c
   return FFI_OK;
 }
 
-ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+ffi_status
+ffi_prep_cif_machdep(ffi_cif *cif)
 {
-  cif->nfixedargs = cif->nargs;
+#ifdef SPARC64
+  if (cif->abi != FFI_COMPAT_V9)
+    cif->nfixedargs = cif->nargs;
+#endif
   return ffi_prep_cif_machdep_core (cif);
 }
 
-ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs,
-				    unsigned int ntotalargs)
+ffi_status
+ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs,
+			 unsigned int ntotalargs)
 {
-  cif->nfixedargs = nfixedargs;
+#ifdef SPARC64
+  if (cif->abi != FFI_COMPAT_V9)
+    cif->nfixedargs = nfixedargs;
+#endif
   return ffi_prep_cif_machdep_core (cif);
 }
 
-int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
+#ifdef SPARC64
+
+int
+ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
 {
   ffi_type **ptr = &arg->elements[0];
 
@@ -380,6 +401,7 @@ int ffi_v9_layout_struct(ffi_type *arg,
   return off;
 }
 
+#endif
 
 #ifdef SPARC64
 extern int ffi_call_v9(void *, extended_cif *, unsigned, 
@@ -389,33 +411,37 @@ extern int ffi_call_v8(void *, extended_
 		       unsigned, unsigned *, void (*fn)(void));
 #endif
 
-void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+void
+ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
 {
   extended_cif ecif;
+#ifdef SPARC64
   void *rval = rvalue;
+#endif
 
   ecif.cif = cif;
   ecif.avalue = avalue;
-
-  /* If the return value is a struct and we don't have a return	*/
-  /* value address then we need to make one		        */
-
   ecif.rvalue = rvalue;
+
+  /* If the return value is a struct and we don't have a return value address,
+     then we need to make one.  */
   if (cif->rtype->type == FFI_TYPE_STRUCT)
     {
+      if (ecif.rvalue == NULL)
+	ecif.rvalue = alloca(cif->rtype->size);
+
+#ifdef SPARC64
       if (cif->rtype->size <= 32)
 	rval = alloca(64);
       else
-	{
-	  rval = NULL;
-	  if (rvalue == NULL)
-	    ecif.rvalue = alloca(cif->rtype->size);
-	}
+	rval = NULL;
+#endif
     }
 
   switch (cif->abi) 
     {
     case FFI_V8:
+    case FFI_V8PLUS:
 #ifdef SPARC64
       /* We don't yet support calling 32bit code from 64bit */
       FFI_ASSERT(0);
@@ -430,7 +456,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(v
 	  /* behind "call", so we alloc some executable space for it. */
 	  /* l7 is used, we need to make sure v8.S doesn't use %l7.   */
 	  unsigned int *call_struct = NULL;
-	  ffi_closure_alloc(32, &call_struct);
+	  ffi_closure_alloc(32, (void **)&call_struct);
 	  if (call_struct)
 	    {
 	      unsigned long f = (unsigned long)fn;
@@ -450,7 +476,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(v
 	      /* SPARC v8 requires 5 instructions for flush to be visible */
 	      asm volatile ("nop; nop; nop; nop; nop");
 	      ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
-			  cif->flags, rvalue, call_struct);
+			  cif->flags, rvalue, (void (*)(void)) call_struct);
 	      ffi_closure_free(call_struct);
 	    }
 	  else
@@ -466,12 +492,13 @@ void ffi_call(ffi_cif *cif, void (*fn)(v
 	}
 #endif
       break;
+    case FFI_COMPAT_V9:
     case FFI_V9:
 #ifdef SPARC64
-      ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes,
-		  cif->flags, rval, fn);
+      ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes, cif->flags, rval, fn);
       if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
-	ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
+	ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval,
+			     ((char *)rval)+32);
 #else
       /* And vice versa */
       FFI_ASSERT(0);
@@ -502,7 +529,7 @@ ffi_prep_closure_loc (ffi_closure* closu
 #ifdef SPARC64
   /* Trampoline address is equal to the closure address.  We take advantage
      of that to reduce the trampoline size by 8 bytes. */
-  if (cif->abi != FFI_V9)
+  if (!V9_ABI_P (cif->abi))
     return FFI_BAD_ABI;
   fn = (unsigned long) ffi_closure_v9;
   tramp[0] = 0x83414000;	/* rd	%pc, %g1	*/
@@ -512,7 +539,7 @@ ffi_prep_closure_loc (ffi_closure* closu
   *((unsigned long *) &tramp[4]) = fn;
 #else
   unsigned long ctx = (unsigned long) codeloc;
-  if (cif->abi != FFI_V8)
+  if (!V8_ABI_P (cif->abi))
     return FFI_BAD_ABI;
   fn = (unsigned long) ffi_closure_v8;
   tramp[0] = 0x03000000 | fn >> 10;	/* sethi %hi(fn), %g1	*/
@@ -537,74 +564,11 @@ ffi_prep_closure_loc (ffi_closure* closu
   return FFI_OK;
 }
 
-int
-ffi_closure_sparc_inner_v8(ffi_closure *closure,
-  void *rvalue, unsigned long *gpr, unsigned long *scratch)
-{
-  ffi_cif *cif;
-  ffi_type **arg_types;
-  void **avalue;
-  int i, argn;
-
-  cif = closure->cif;
-  arg_types = cif->arg_types;
-  avalue = alloca(cif->nargs * sizeof(void *));
-
-  /* Copy the caller's structure return address so that the closure
-     returns the data directly to the caller.  */
-  if (cif->flags == FFI_TYPE_STRUCT
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE  
-      || cif->flags == FFI_TYPE_LONGDOUBLE
-#endif
-     )
-    rvalue = (void *) gpr[0];
-
-  /* Always skip the structure return address.  */
-  argn = 1;
-
-  /* Grab the addresses of the arguments from the stack frame.  */
-  for (i = 0; i < cif->nargs; i++)
-    {
-      if (arg_types[i]->type == FFI_TYPE_STRUCT
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-	  || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
-#endif
-         )
-	{
-	  /* Straight copy of invisible reference.  */
-	  avalue[i] = (void *)gpr[argn++];
-	}
-      else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
-	       || arg_types[i]->type == FFI_TYPE_SINT64
-	       || arg_types[i]->type == FFI_TYPE_UINT64)
-	       /* gpr is 8-byte aligned.  */
-	       && (argn % 2) != 0)
-	{
-	  /* Align on a 8-byte boundary.  */
-	  scratch[0] = gpr[argn];
-	  scratch[1] = gpr[argn+1];
-	  avalue[i] = scratch;
-	  scratch -= 2;
-	  argn += 2;
-	}
-      else
-	{
-	  /* Always right-justify.  */
-	  argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
-	  avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
-	}
-    }
-
-  /* Invoke the closure.  */
-  (closure->fun) (cif, rvalue, avalue, closure->user_data);
-
-  /* Tell ffi_closure_sparc how to perform return type promotions.  */
-  return cif->rtype->type;
-}
+#ifdef SPARC64
 
 int
-ffi_closure_sparc_inner_v9(ffi_closure *closure,
-  void *rvalue, unsigned long *gpr, double *fpr)
+ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue,
+			   unsigned long *gpr, double *fpr)
 {
   ffi_cif *cif;
   ffi_type **arg_types;
@@ -633,7 +597,8 @@ ffi_closure_sparc_inner_v9(ffi_closure *
     {
       /* If the function is variadic, FP arguments are passed in FP
 	 registers only if the corresponding parameter is named.  */
-      const int named = (i < cif->nfixedargs);
+      const int named
+	= (cif->abi == FFI_COMPAT_V9 ? 1 : i < cif->nfixedargs);
 
       if (arg_types[i]->type == FFI_TYPE_STRUCT)
 	{
@@ -653,7 +618,8 @@ ffi_closure_sparc_inner_v9(ffi_closure *
 				   ? (char *) &fpr[argn]
 				   : (char *) &gpr[argn]);
 	      avalue[i] = &gpr[argn];
-	      argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+	      argn
+	        += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
 	    }
 	}
       else
@@ -686,3 +652,72 @@ ffi_closure_sparc_inner_v9(ffi_closure *
   /* Tell ffi_closure_sparc how to perform return type promotions.  */
   return cif->rtype->type;
 }
+
+#else
+
+int
+ffi_closure_sparc_inner_v8(ffi_closure *closure, void *rvalue,
+			   unsigned long *gpr, unsigned long *scratch)
+{
+  ffi_cif *cif;
+  ffi_type **arg_types;
+  void **avalue;
+  int i, argn;
+
+  cif = closure->cif;
+  arg_types = cif->arg_types;
+  avalue = alloca(cif->nargs * sizeof(void *));
+
+  /* Copy the caller's structure return address so that the closure
+     returns the data directly to the caller.  */
+  if (cif->flags == FFI_TYPE_STRUCT
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE  
+      || cif->flags == FFI_TYPE_LONGDOUBLE
+#endif
+     )
+    rvalue = (void *) gpr[0];
+
+  /* Always skip the structure return address.  */
+  argn = 1;
+
+  /* Grab the addresses of the arguments from the stack frame.  */
+  for (i = 0; i < cif->nargs; i++)
+    {
+      if (arg_types[i]->type == FFI_TYPE_STRUCT
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+	  || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
+#endif
+         )
+	{
+	  /* Straight copy of invisible reference.  */
+	  avalue[i] = (void *)gpr[argn++];
+	}
+      else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
+	       || arg_types[i]->type == FFI_TYPE_SINT64
+	       || arg_types[i]->type == FFI_TYPE_UINT64)
+	       /* gpr is 8-byte aligned.  */
+	       && (argn % 2) != 0)
+	{
+	  /* Align on a 8-byte boundary.  */
+	  scratch[0] = gpr[argn];
+	  scratch[1] = gpr[argn+1];
+	  avalue[i] = scratch;
+	  scratch -= 2;
+	  argn += 2;
+	}
+      else
+	{
+	  /* Always right-justify.  */
+	  argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+	  avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
+	}
+    }
+
+  /* Invoke the closure.  */
+  closure->fun (cif, rvalue, avalue, closure->user_data);
+
+  /* Tell ffi_closure_sparc how to perform return type promotions.  */
+  return cif->rtype->type;
+}
+
+#endif
Index: src/sparc/v8.S
===================================================================
--- src/sparc/v8.S	(revision 207796)
+++ src/sparc/v8.S	(working copy)
@@ -1,6 +1,6 @@
 /* -----------------------------------------------------------------------
    v8.S - Copyright (c) 1996, 1997, 2003, 2004, 2008 Red Hat, Inc.
-   
+
    SPARC Foreign Function Interface 
 
    Permission is hereby granted, free of charge, to any person obtaining
@@ -28,6 +28,8 @@
 #include <fficonfig.h>
 #include <ffi.h>
 
+#ifndef SPARC64
+
 #define STACKFRAME 96		/* Minimum stack framesize for SPARC */
 #define ARGS (64+4)		/* Offset of register area in frame */
 
@@ -307,6 +309,7 @@ done2:
 	.byte	0x1f	! uleb128 0x1f
 	.align	WS
 .LLEFDE2:
+#endif
 
 #if defined __ELF__ && defined __linux__
 	.section	.note.GNU-stack,"",@progbits

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

* Fix PR libffi/60073
@ 2014-02-13 16:19 Eric Botcazou
  0 siblings, 0 replies; 5+ messages in thread
From: Eric Botcazou @ 2014-02-13 16:19 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 785 bytes --]

This adds proper variadic support to the SPARC port of libffi, thus fixing a 
regression in the testsuite in 64-bit mode, and fixes a small inaccuracy in 
the documentation.

Tested on SPARC/Solaris and SPARC64/Solaris, applied on the mainline.


2014-02-13  Eric Botcazou  <ebotcazou@adacore.com>

	PR libffi/60073
	* src/sparc/ffitarget.h (FFI_TARGET_SPECIFIC_VARIADIC): Define.
	(FFI_EXTRA_CIF_FIELDS): Likewise.
	(FFI_NATIVE_RAW_API): Move around.
	* src/sparc/ffi.c (ffi_prep_cif_machdep_core): New function from...
	(ffi_prep_cif_machdep): ...here.  Call ffi_prep_cif_machdep_core.
	(ffi_prep_cif_machdep_var): New function.
	(ffi_closure_sparc_inner_v9): Do not pass anonymous FP arguments in
	FP registers.
	* doc/libffi.texi (Introduction): Fix inaccuracy.


-- 
Eric Botcazou

[-- Attachment #2: pr60073.diff --]
[-- Type: text/x-patch, Size: 4469 bytes --]

Index: src/sparc/ffitarget.h
===================================================================
--- src/sparc/ffitarget.h	(revision 207685)
+++ src/sparc/ffitarget.h	(working copy)
@@ -58,16 +58,17 @@ typedef enum ffi_abi {
 } ffi_abi;
 #endif
 
+#define FFI_TARGET_SPECIFIC_VARIADIC 1
+#define FFI_EXTRA_CIF_FIELDS unsigned int nfixedargs
+
 /* ---- Definitions for closures ----------------------------------------- */
 
 #define FFI_CLOSURES 1
-#define FFI_NATIVE_RAW_API 0
-
 #ifdef SPARC64
 #define FFI_TRAMPOLINE_SIZE 24
 #else
 #define FFI_TRAMPOLINE_SIZE 16
 #endif
+#define FFI_NATIVE_RAW_API 0
 
 #endif
-
Index: src/sparc/ffi.c
===================================================================
--- src/sparc/ffi.c	(revision 207685)
+++ src/sparc/ffi.c	(working copy)
@@ -249,7 +249,7 @@ int ffi_prep_args_v9(char *stack, extend
 }
 
 /* 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)
 {
   int wordsize;
 
@@ -334,6 +334,19 @@ ffi_status ffi_prep_cif_machdep(ffi_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)
+{
+  cif->nfixedargs = nfixedargs;
+  return ffi_prep_cif_machdep_core (cif);
+}
+
 int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
 {
   ffi_type **ptr = &arg->elements[0];
@@ -604,8 +617,7 @@ ffi_closure_sparc_inner_v9(ffi_closure *
 
   /* Copy the caller's structure return address so that the closure
      returns the data directly to the caller.  */
-  if (cif->flags == FFI_TYPE_VOID
-      && cif->rtype->type == FFI_TYPE_STRUCT)
+  if (cif->flags == FFI_TYPE_VOID && cif->rtype->type == FFI_TYPE_STRUCT)
     {
       rvalue = (void *) gpr[0];
       /* Skip the structure return address.  */
@@ -619,6 +631,10 @@ ffi_closure_sparc_inner_v9(ffi_closure *
   /* Grab the addresses of the arguments from the stack frame.  */
   for (i = 0; i < cif->nargs; i++)
     {
+      /* If the function is variadic, FP arguments are passed in FP
+	 registers only if the corresponding parameter is named.  */
+      const int named = (i < cif->nfixedargs);
+
       if (arg_types[i]->type == FFI_TYPE_STRUCT)
 	{
 	  if (arg_types[i]->size > 16)
@@ -633,7 +649,9 @@ ffi_closure_sparc_inner_v9(ffi_closure *
 				   0,
 				   (char *) &gpr[argn],
 				   (char *) &gpr[argn],
-				   (char *) &fpr[argn]);
+				   named
+				   ? (char *) &fpr[argn]
+				   : (char *) &gpr[argn]);
 	      avalue[i] = &gpr[argn];
 	      argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
 	    }
@@ -649,6 +667,7 @@ ffi_closure_sparc_inner_v9(ffi_closure *
 	    argn++;
 #endif
 	  if (i < fp_slot_max
+	      && named
 	      && (arg_types[i]->type == FFI_TYPE_FLOAT
 		  || arg_types[i]->type == FFI_TYPE_DOUBLE
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
@@ -662,7 +681,7 @@ ffi_closure_sparc_inner_v9(ffi_closure *
     }
 
   /* Invoke the closure.  */
-  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+  closure->fun (cif, rvalue, avalue, closure->user_data);
 
   /* Tell ffi_closure_sparc how to perform return type promotions.  */
   return cif->rtype->type;
Index: doc/libffi.texi
===================================================================
--- doc/libffi.texi	(revision 207685)
+++ doc/libffi.texi	(working copy)
@@ -63,14 +63,14 @@ section entitled ``GNU General Public Li
 @node Introduction
 @chapter What is libffi?
 
-Compilers for high level languages generate code that follow certain
+Compilers for high-level languages generate code that follow certain
 conventions.  These conventions are necessary, in part, for separate
 compilation to work.  One such convention is the @dfn{calling
 convention}.  The calling convention is a set of assumptions made by
 the compiler about where function arguments will be found on entry to
 a function.  A calling convention also specifies where the return
-value for a function is found.  The calling convention is also
-sometimes called the @dfn{ABI} or @dfn{Application Binary Interface}.
+value for a function is found.  The calling convention is part of
+what is called the @dfn{ABI} or @dfn{Application Binary Interface}.
 @cindex calling convention
 @cindex ABI
 @cindex Application Binary Interface

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

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

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-13 16:19 Fix PR libffi/60073 Eric Botcazou
2014-02-14  9:55 ` Alan Modra
2014-02-14 10:33   ` Eric Botcazou
2014-02-17 12:00 ` Eric Botcazou
2014-02-13 16:19 Eric Botcazou

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).