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


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

[PATCH] libffi powerpc64-*-linux* support


Hi!

Here is libffi port to powerpc64-*-linux*, including closures.
ffitest passes all tests on both powerpc-redhat-linux and
powerpc64-redhat-linux, unless 64-bit ffitest is compiled with
-mstrict-align, in which case struct5 test fails because a structure
containing 2 chars (if it appears among the first 8 argument 64-bit words)
is padded from left without that switch and from right with that switch.
I had to make 3 changes to ffitest too, the first two are I think obvious
(closure_test_fn* were computing the result in *(ffi_arg *)resp but
printing it from *(int *)resp, which doesn't work on 64-bit big endian
(and might not work elsewhere because of aliasing bug) and printing
of unitialized data), the last one is controversial.
int main (void)
{
  static char cl[32];
  ((void (*)(void))cl) ();
}
doesn't link on ppc64 because of undefined symbol .cl.0.
Either ppc64 gcc would need to be taught that if it is trying to call
a data object, it should call cl.0 and not .cl.0, or such calls
can be declared as unsupported (libgcj uses malloced memory for closures
anyway and such closures don't suffer from this).

I wonder if FFI_LINUX64 is the best name for the ABI, maybe FFI_ELF64
or FFI_AIX64 would be better, dunno.

2003-04-10  Jakub Jelinek  <jakub at redhat dot com>

	* configure.in (powerpc64*-*-linux*): Remove.
	* configure: Rebuilt.
libffi/
	* include/ffi.h.in (POWERPC64): Define if 64-bit.
	(enum ffi_abi): Add FFI_LINUX64 on POWERPC.
	Make it the default on POWERPC64.
	(FFI_TRAMPOLINE_SIZE): Define to 24 on POWERPC64.
	* configure.in: Change powerpc-*-linux* into powerpc*-*-linux*.
	* configure: Rebuilt.
	* src/powerpc/ffi.c (hidden): Define.
	(ffi_prep_args_SYSV): Renamed from
	ffi_prep_args.  Cast pointers to unsigned long to shut up warnings.
	(NUM_GPR_ARG_REGISTERS64, NUM_FPR_ARG_REGISTERS64,
	ASM_NEEDS_REGISTERS64): New.
	(ffi_prep_args64): New function.
	(ffi_prep_cif_machdep): Handle FFI_LINUX64 ABI.
	(ffi_call): Likewise.
	(ffi_prep_closure): Likewise.
	(flush_icache): Surround by #ifndef POWERPC64.
	(ffi_dblfl): New union type.
	(ffi_closure_helper_SYSV): Use it to avoid aliasing problems.
	(ffi_closure_helper_LINUX64): New function.
	* src/powerpc/ppc_closure.S: Surround whole file by #ifndef
	__powerpc64__.
	* src/powerpc/sysv.S: Likewise.
	(ffi_call_SYSV): Rename ffi_prep_args to ffi_prep_args_SYSV.
	* src/powerpc/linux64.S: New file.
	* src/powerpc/linux64_closure.S: New file.
	* Makefile.am (EXTRA_DIST): Add src/powerpc/linux64.S and
	src/powerpc/linux64_closure.S.
	(TARGET_SRC_POWERPC): Likewise.

	* src/ffitest.c (closure_test_fn, closure_test_fn1, closure_test_fn2,
	closure_test_fn3): Fix result printing on big-endian 64-bit
	machines.
	(main): Print tst2_arg instead of uninitialized tst2_result.

	* src/ffitest.c (main): Hide what closure pointer really points to
	from the compiler.

--- libffi/include/ffi.h.in.jj	2003-04-07 12:49:53.000000000 -0400
+++ libffi/include/ffi.h.in	2003-04-10 06:22:01.000000000 -0400
@@ -158,6 +158,12 @@ extern "C" {
 #define SIZEOF_ARG SIZEOF_VOID_P
 #endif
 
+#ifdef POWERPC
+#if defined (__powerpc64__)
+#define POWERPC64
+#endif
+#endif
+
 #ifdef SPARC
 #if defined(__arch64__) || defined(__sparcv9)
 #define SPARC64
@@ -250,7 +256,12 @@ typedef enum ffi_abi {
 #ifdef POWERPC
   FFI_SYSV,
   FFI_GCC_SYSV,
+  FFI_LINUX64,
+# ifdef POWERPC64
+  FFI_DEFAULT_ABI = FFI_LINUX64,
+# else
   FFI_DEFAULT_ABI = FFI_GCC_SYSV,
+# endif
 #endif
 
 #ifdef POWERPC_AIX
@@ -435,7 +446,11 @@ struct ffi_ia64_trampoline_struct {
 #elif defined(POWERPC)
 
 #define FFI_CLOSURES 1
+#ifdef POWERPC64
+#define FFI_TRAMPOLINE_SIZE 24
+#else
 #define FFI_TRAMPOLINE_SIZE 40
+#endif
 #define FFI_NATIVE_RAW_API 0
 
 #elif defined(POWERPC_DARWIN)
--- libffi/configure.in.jj	2003-04-07 12:49:53.000000000 -0400
+++ libffi/configure.in	2003-04-09 10:19:34.000000000 -0400
@@ -64,7 +64,7 @@ ia64*-*-*) TARGET=IA64; TARGETDIR=ia64;;
 m68k-*-linux*) TARGET=M68K; TARGETDIR=m68k;;
 mips64*-*);;
 mips*-*-linux*) TARGET=MIPS_LINUX; TARGETDIR=mips;;
-powerpc-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;;
+powerpc*-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;;
 powerpc-*-beos*) TARGET=POWERPC; TARGETDIR=powerpc;;
 powerpc-*-darwin*) TARGET=POWERPC_DARWIN; TARGETDIR=powerpc;;
 powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
--- libffi/src/powerpc/ffi.c.jj	2003-04-07 12:49:53.000000000 -0400
+++ libffi/src/powerpc/ffi.c	2003-04-10 10:29:37.000000000 -0400
@@ -31,7 +31,15 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 1)
+# define hidden __attribute__ ((visibility ("hidden")))
+#else
+# define hidden
+#endif
+
+
 extern void ffi_closure_SYSV(void);
+extern void hidden ffi_closure_LINUX64(void);
 
 enum {
   /* The assembly depends on these exact flags.  */
@@ -52,7 +60,7 @@ enum {
 };
 enum { ASM_NEEDS_REGISTERS = 4 };
 
-/* ffi_prep_args is called by the assembly routine once stack space
+/* ffi_prep_args_SYSV is called by the assembly routine once stack space
    has been allocated for the function's arguments.
 
    The stack layout we want looks like this:
@@ -79,7 +87,7 @@ enum { ASM_NEEDS_REGISTERS = 4 };
    */
 
 /* at -exportheader@*/
-void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
+void ffi_prep_args_SYSV(extended_cif *ecif, unsigned *const stack)
 /* at =exportheader@*/
 {
   const unsigned bytes = ecif->cif->bytes;
@@ -124,7 +132,7 @@ void ffi_prep_args(extended_cif *ecif, u
   /* Deal with return values that are actually pass-by-reference.  */
   if (flags & FLAG_RETVAL_REFERENCE)
   {
-    *gpr_base++ = (unsigned)(char *)ecif->rvalue;
+    *gpr_base++ = (unsigned long)(char *)ecif->rvalue;
     intarg_count++;
   }
 
@@ -210,7 +218,7 @@ void ffi_prep_args(extended_cif *ecif, u
 	  copy_space -= struct_copy_size;
 	  memcpy(copy_space, (char *)*p_argv, (*ptr)->size);
 	  
-	  gprvalue = (unsigned)copy_space;
+	  gprvalue = (unsigned long)copy_space;
 
 	  FFI_ASSERT(copy_space > (char *)next_arg);
 	  FFI_ASSERT(flags & FLAG_ARG_NEEDS_COPY);
@@ -252,34 +260,229 @@ void ffi_prep_args(extended_cif *ecif, u
   FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
 }
 
+/* About the LINUX64 ABI.  */
+enum {
+  NUM_GPR_ARG_REGISTERS64 = 8,
+  NUM_FPR_ARG_REGISTERS64 = 13
+};
+enum { ASM_NEEDS_REGISTERS64 = 4 };
+
+/* ffi_prep_args64 is called by the assembly routine once stack space
+   has been allocated for the function's arguments.
+
+   The stack layout we want looks like this:
+
+   |   Ret addr from ffi_call_LINUX64	8bytes	|	higher addresses
+   |--------------------------------------------|
+   |   CR save area			8bytes	|
+   |--------------------------------------------|
+   |   Previous backchain pointer	8	| 	stack pointer here
+   |--------------------------------------------|<+ <<<	on entry to
+   |   Saved r28-r31			4*8	| |	ffi_call_LINUX64
+   |--------------------------------------------| |
+   |   GPR registers r3-r10		8*8	| |
+   |--------------------------------------------| |
+   |   FPR registers f1-f13 (optional)	13*8	| |
+   |--------------------------------------------| |
+   |   Parameter save area		        | |
+   |--------------------------------------------| |
+   |   TOC save area			8	| |
+   |--------------------------------------------| |	stack	|
+   |   Linker doubleword		8	| |	gorws	|
+   |--------------------------------------------| |	down	V
+   |   Compiler doubleword		8	| |
+   |--------------------------------------------| |	lower addresses
+   |   Space for callee's LR		8	| |
+   |--------------------------------------------| |
+   |   CR save area			8	| |
+   |--------------------------------------------| |	stack pointer here
+   |   Current backchain pointer	8	|-/	during
+   |--------------------------------------------|   <<<	ffi_call_LINUX64
+
+   */
+
+/* at -exportheader@*/
+void hidden ffi_prep_args64(extended_cif *ecif, unsigned long *const stack)
+/* at =exportheader@*/
+{
+  const unsigned long bytes = ecif->cif->bytes;
+  const unsigned long flags = ecif->cif->flags;
+
+  /* 'stacktop' points at the previous backchain pointer.  */
+  unsigned long *const stacktop = stack + (bytes / sizeof(unsigned long));
+
+  /* 'next_arg' points at the space for gpr3, and grows upwards as
+     we use GPR registers, then continues at rest.  */
+  unsigned long *const gpr_base = stacktop - ASM_NEEDS_REGISTERS64
+				  - NUM_GPR_ARG_REGISTERS64;
+  unsigned long *const gpr_end = gpr_base + NUM_GPR_ARG_REGISTERS64;
+  unsigned long *const rest = stack + 6 + NUM_GPR_ARG_REGISTERS64;
+  unsigned long *next_arg = gpr_base;
+
+  /* 'fpr_base' points at the space for fpr3, and grows upwards as
+     we use FPR registers.  */
+  double *fpr_base = (double *)gpr_base - NUM_FPR_ARG_REGISTERS64;
+  int fparg_count = 0;
+
+  int i, words;
+  ffi_type **ptr;
+  double double_tmp;
+  void **p_argv;
+  unsigned long gprvalue;
+
+  /* Check that everything starts aligned properly.  */
+  FFI_ASSERT(((unsigned long)(char *)stack & 0xF) == 0);
+  FFI_ASSERT(((unsigned long)(char *)stacktop & 0xF) == 0);
+  FFI_ASSERT((bytes & 0xF) == 0);
+
+  /* Deal with return values that are actually pass-by-reference.  */
+  if (flags & FLAG_RETVAL_REFERENCE)
+    *next_arg++ = (unsigned long)(char *)ecif->rvalue;
+
+  /* Now for the arguments.  */
+  p_argv = ecif->avalue;
+  for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
+       i > 0;
+       i--, ptr++, p_argv++)
+    {
+      switch ((*ptr)->type)
+	{
+	case FFI_TYPE_FLOAT:
+	  double_tmp = *(float *)*p_argv;
+	  *(float *)next_arg = (float)double_tmp;
+	  if (++next_arg == gpr_end)
+	    next_arg = rest;
+	  if (fparg_count < NUM_FPR_ARG_REGISTERS64)
+	    *fpr_base++ = double_tmp;
+	  fparg_count++;
+	  FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+	  break;
+
+	case FFI_TYPE_DOUBLE:
+	  double_tmp = *(double *)*p_argv;
+	  *(double *)next_arg = double_tmp;
+	  if (++next_arg == gpr_end)
+	    next_arg = rest;
+	  if (fparg_count < NUM_FPR_ARG_REGISTERS64)
+	    *fpr_base++ = double_tmp;
+	  fparg_count++;
+	  FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+	  break;
+
+	case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+	case FFI_TYPE_LONGDOUBLE:
+#endif
+	  words = ((*ptr)->size + 7) / 8;
+	  if (next_arg >= gpr_base && next_arg + words > gpr_end)
+	    {
+	      unsigned int first = (char *) gpr_end - (char *) next_arg;
+	      memcpy((char *) next_arg, (char *) *p_argv, first);
+	      memcpy((char *) rest, (char *) *p_argv + first,
+		     (*ptr)->size - first);
+	      next_arg = rest + words * 8 - first;
+	    }
+	  else
+	    {
+	      /* Structures with 1, 2 and 4 byte sizes are passed left-padded
+		 if they are in the first 8 arguments.  */
+	      if (next_arg >= gpr_base
+		  && (*ptr)->size < 8
+		  && ((*ptr)->size & ~((*ptr)->size - 1)) == (*ptr)->size)
+		memcpy((char *) next_arg + 8 - (*ptr)->size,
+		       (char *) *p_argv, (*ptr)->size);
+	      else
+		memcpy((char *) next_arg, (char *) *p_argv, (*ptr)->size);
+	      next_arg += words;
+	      if (next_arg == gpr_end)
+		next_arg = rest;
+	    }
+	  break;
+
+	case FFI_TYPE_UINT8:
+	  gprvalue = *(unsigned char *)*p_argv;
+	  goto putgpr;
+	case FFI_TYPE_SINT8:
+	  gprvalue = *(signed char *)*p_argv;
+	  goto putgpr;
+	case FFI_TYPE_UINT16:
+	  gprvalue = *(unsigned short *)*p_argv;
+	  goto putgpr;
+	case FFI_TYPE_SINT16:
+	  gprvalue = *(signed short *)*p_argv;
+	  goto putgpr;
+	case FFI_TYPE_UINT32:
+	  gprvalue = *(unsigned int *)*p_argv;
+	  goto putgpr;
+	case FFI_TYPE_INT:
+	case FFI_TYPE_SINT32:
+	  gprvalue = *(signed int *)*p_argv;
+	  goto putgpr;
+	
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_POINTER:
+	  gprvalue = *(unsigned long *)*p_argv;
+	putgpr:
+	  *next_arg++ = gprvalue;
+	  if (next_arg == gpr_end)
+	    next_arg = rest;
+	  break;
+	}
+    }
+
+  FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS
+	     || (next_arg >= gpr_base && next_arg <= gpr_base + 4));
+}
+
+
+
 /* Perform machine dependent cif processing */
 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
 {
-  /* All this is for the SYSV ABI.  */
+  /* 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 struct_copy_size = 0;
-  
-  /* 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);
+  if (cif->abi != FFI_LINUX64)
+    {    
+      /* All the machine-independent calculation of cif->bytes will be wrong.
+	 Redo the calculation for SYSV.  */
 
-  /* Space for the GPR registers.  */
-  bytes += NUM_GPR_ARG_REGISTERS * sizeof(int);
+      /* Space for the frame pointer, callee's LR, and the asm's temp regs.  */
+      bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof(int);
 
-  /* Return value handling.  The rules are as follows:
+      /* Space for the GPR registers.  */
+      bytes += NUM_GPR_ARG_REGISTERS * sizeof(int);
+    }
+  else
+    {
+      /* 64-bit ABI.  */
+
+      /* 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);
+    }
+
+  /* Return value handling.  The rules for SYSV are as follows:
      - 32-bit (or less) integer values are returned in gpr3;
      - Structures of size <= 4 bytes also returned in gpr3;
      - 64-bit integer values and structures between 5 and 8 bytes are returned
        in gpr3 and gpr4;
      - Single/double FP values are returned in fpr1;
      - Larger structures and long double (if not equivalent to double) values
-       are allocated space and a pointer is passed as the first argument.  */
+       are allocated space and a pointer is passed as the first argument.
+     For LINUX64:
+     - integer values in gpr3;
+     - Structures/Unions and long double by reference;
+     - Single/double FP values in fpr1.  */
   switch (cif->rtype->type)
     {
     case FFI_TYPE_DOUBLE:
@@ -295,7 +498,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif 
       break;
 
     case FFI_TYPE_STRUCT:
-      if (cif->abi != FFI_GCC_SYSV)
+      if (cif->abi != FFI_GCC_SYSV && cif->abi != FFI_LINUX64)
 	if (cif->rtype->size <= 4)
 	  break;
 	else if (cif->rtype->size <= 8)
@@ -319,59 +522,86 @@ ffi_status ffi_prep_cif_machdep(ffi_cif 
       break;
     }
 
-  /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the
-     first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest
-     goes on the stack.  Structures and long doubles (if not equivalent
-     to double) are passed as a pointer to a copy of the structure.
-     Stuff on the stack needs to keep proper alignment.  */
-  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
-    {
-      switch ((*ptr)->type)
-	{
-	case FFI_TYPE_FLOAT:
-	  fparg_count++;
-	  /* floating singles are not 8-aligned on stack */
-	  break;
+  if (cif->abi != FFI_LINUX64)
+    /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the
+       first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest
+       goes on the stack.  Structures and long doubles (if not equivalent
+       to double) are passed as a pointer to a copy of the structure.
+       Stuff on the stack needs to keep proper alignment.  */
+    for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+      {
+	switch ((*ptr)->type)
+	  {
+	  case FFI_TYPE_FLOAT:
+	    fparg_count++;
+	    /* floating singles are not 8-aligned on stack */
+	    break;
 
-	case FFI_TYPE_DOUBLE:
-	  fparg_count++;
-	  /* If this FP arg is going on the stack, it must be
-	     8-byte-aligned.  */
-	  if (fparg_count > NUM_FPR_ARG_REGISTERS
-	      && intarg_count%2 != 0)
-	    intarg_count++;
-	  break;
+	  case FFI_TYPE_DOUBLE:
+	    fparg_count++;
+	    /* If this FP arg is going on the stack, it must be
+	       8-byte-aligned.  */
+	    if (fparg_count > NUM_FPR_ARG_REGISTERS
+		&& intarg_count%2 != 0)
+	      intarg_count++;
+	    break;
 
-	case FFI_TYPE_UINT64:
-	case FFI_TYPE_SINT64:
-	  /* 'long long' arguments are passed as two words, but
-	     either both words must fit in registers or both go
-	     on the stack.  If they go on the stack, they must
-	     be 8-byte-aligned.  */
-	  if (intarg_count == NUM_GPR_ARG_REGISTERS-1
-	      || intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0)
+	  case FFI_TYPE_UINT64:
+	  case FFI_TYPE_SINT64:
+	    /* 'long long' arguments are passed as two words, but
+	       either both words must fit in registers or both go
+	       on the stack.  If they go on the stack, they must
+	       be 8-byte-aligned.  */
+	    if (intarg_count == NUM_GPR_ARG_REGISTERS-1
+		|| (intarg_count >= NUM_GPR_ARG_REGISTERS
+		    && intarg_count%2 != 0))
+	      intarg_count++;
+	    intarg_count += 2;
+	    break;
+
+	  case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+	  case FFI_TYPE_LONGDOUBLE:
+#endif
+	    /* We must allocate space for a copy of these to enforce
+	       pass-by-value.  Pad the space up to a multiple of 16
+	       bytes (the maximum alignment required for anything under
+	       the SYSV ABI).  */
+	    struct_copy_size += ((*ptr)->size + 15) & ~0xF;
+	    /* Fall through (allocate space for the pointer).  */
+
+	  default:
+	    /* Everything else is passed as a 4-byte word in a GPR, either
+	       the object itself or a pointer to it.  */
 	    intarg_count++;
-	  intarg_count += 2;
-	  break;
+	    break;
+	  }
+      }
+  else
+    for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+      {
+	switch ((*ptr)->type)
+	  {
+	  case FFI_TYPE_FLOAT:
+	  case FFI_TYPE_DOUBLE:
+	    fparg_count++;
+	    intarg_count++;
+	    break;
 
-	case FFI_TYPE_STRUCT:
+	  case FFI_TYPE_STRUCT:
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-	case FFI_TYPE_LONGDOUBLE:
+	  case FFI_TYPE_LONGDOUBLE:
 #endif
-	  /* We must allocate space for a copy of these to enforce
-	     pass-by-value.  Pad the space up to a multiple of 16
-	     bytes (the maximum alignment required for anything under
-	     the SYSV ABI).  */
-	  struct_copy_size += ((*ptr)->size + 15) & ~0xF;
-	  /* Fall through (allocate space for the pointer).  */
+	    intarg_count += ((*ptr)->size + 7) & ~7;
+	    break;
 
-	default:
-	  /* Everything else is passed as a 4-byte word in a GPR, either
-	     the object itself or a pointer to it.  */
-	  intarg_count++;
-	  break;
-	}
-    }
+	  default:
+	    /* Everything else is passed as a 8-byte word in a GPR, either
+	       the object itself or a pointer to it.  */
+	    intarg_count++;
+	    break;
+	  }
+      }
 
   if (fparg_count != 0)
     flags |= FLAG_FP_ARGUMENTS;
@@ -379,16 +609,29 @@ ffi_status ffi_prep_cif_machdep(ffi_cif 
     flags |= FLAG_4_GPR_ARGUMENTS;
   if (struct_copy_size != 0)
     flags |= FLAG_ARG_NEEDS_COPY;
-  
-  /* Space for the FPR registers, if needed.  */
-  if (fparg_count != 0)
-    bytes += NUM_FPR_ARG_REGISTERS * sizeof(double);
 
-  /* Stack space.  */
-  if (intarg_count > NUM_GPR_ARG_REGISTERS)
-    bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof(int);
-  if (fparg_count > NUM_FPR_ARG_REGISTERS)
-    bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof(double);
+  if (cif->abi != FFI_LINUX64)
+    {
+      /* Space for the FPR registers, if needed.  */
+      if (fparg_count != 0)
+	bytes += NUM_FPR_ARG_REGISTERS * sizeof(double);
+
+      /* Stack space.  */
+      if (intarg_count > NUM_GPR_ARG_REGISTERS)
+	bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof(int);
+      if (fparg_count > NUM_FPR_ARG_REGISTERS)
+	bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof(double);
+    }
+  else
+    {
+      /* Space for the FPR registers, if needed.  */
+      if (fparg_count != 0)
+	bytes += NUM_FPR_ARG_REGISTERS64 * sizeof(double);
+
+      /* Stack space.  */
+      if (intarg_count > NUM_GPR_ARG_REGISTERS64)
+	bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof(long);
+    }
 
   /* The stack space allocated needs to be a multiple of 16 bytes.  */
   bytes = (bytes + 15) & ~0xF;
@@ -408,6 +651,10 @@ extern void ffi_call_SYSV(/* at out@*/ exte
 			  unsigned, unsigned, 
 			  /* at out@*/ unsigned *, 
 			  void (*fn)());
+extern void hidden ffi_call_LINUX64(/* at out@*/ extended_cif *, 
+				    unsigned long, unsigned long,
+				    /* at out@*/ unsigned long *, 
+				    void (*fn)());
 /* at =declundef@*/
 /* at =exportheader@*/
 
@@ -437,6 +684,7 @@ void ffi_call(/* at dependent@*/ ffi_cif *c
   
   switch (cif->abi) 
     {
+#ifndef POWERPC64
     case FFI_SYSV:
     case FFI_GCC_SYSV:
       /* at -usedef@*/
@@ -444,6 +692,14 @@ void ffi_call(/* at dependent@*/ ffi_cif *c
 		    cif->flags, ecif.rvalue, fn);
       /* at =usedef@*/
       break;
+#else
+    case FFI_LINUX64:
+      /* at -usedef@*/
+      ffi_call_LINUX64(&ecif, -(long) cif->bytes,
+		       cif->flags, ecif.rvalue, fn);
+      /* at =usedef@*/
+      break;
+#endif
     default:
       FFI_ASSERT(0);
       break;
@@ -451,14 +707,38 @@ void ffi_call(/* at dependent@*/ ffi_cif *c
 }
 
 
+#ifndef POWERPC64
 static void flush_icache(char *, int);
 
+#define MIN_CACHE_LINE_SIZE 8
+
+static void flush_icache(char * addr1, int size)
+{
+  int i;
+  char * addr;
+  for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) {
+     addr = addr1 + i;
+     __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" : : "r"(addr) : "memory");
+  }
+  addr = addr1 + size - 1;
+  __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" "sync;" "isync;" : : "r"(addr) : "memory");
+}
+#endif
+
 ffi_status
 ffi_prep_closure (ffi_closure* closure,
 		  ffi_cif* cif,
 		  void (*fun)(ffi_cif*, void*, void**, void*),
 		  void *user_data)
 {
+#ifdef POWERPC64
+  void **tramp = (void **) &closure->tramp[0];
+
+  FFI_ASSERT (cif->abi == FFI_LINUX64);
+  /* Copy function address and TOC from ffi_closure_LINUX64.  */
+  memcpy (tramp, (char *) ffi_closure_LINUX64, 16);
+  tramp[2] = (void *) closure;
+#else
   unsigned int *tramp;
 
   FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
@@ -475,34 +755,25 @@ ffi_prep_closure (ffi_closure* closure,
   *(void **) &tramp[2] = (void *)ffi_closure_SYSV; /* function */
   *(void **) &tramp[3] = (void *)closure;          /* context */
 
+  /* Flush the icache.  */
+  flush_icache(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
+#endif
+
   closure->cif = cif;
   closure->fun = fun;
   closure->user_data = user_data;
 
-  /* Flush the icache.  */
-  flush_icache(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
-
   return FFI_OK;
 }
 
-
-#define MIN_CACHE_LINE_SIZE 8
-
-static void flush_icache(char * addr1, int size)
+typedef union
 {
-  int i;
-  char * addr;
-  for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) {
-     addr = addr1 + i;
-     __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" : : "r"(addr) : "memory");
-  }
-  addr = addr1 + size - 1;
-  __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" "sync;" "isync;" : : "r"(addr) : "memory");
-}
-
+  float f;
+  double d;
+} ffi_dblfl;
 
 int ffi_closure_helper_SYSV (ffi_closure*, void*, unsigned long*, 
-                                     unsigned long*, unsigned long*);
+			     ffi_dblfl*, unsigned long*);
 
 /* Basically the trampoline invokes ffi_closure_SYSV, and on 
  * entry, r11 holds the address of the closure.
@@ -514,7 +785,7 @@ int ffi_closure_helper_SYSV (ffi_closure
 
 int
 ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue, 
-            unsigned long * pgr, unsigned long * pfr, 
+            unsigned long * pgr, ffi_dblfl * pfr, 
             unsigned long * pst)
 {
   /* rvalue is the pointer to space for return value in closure assembly */
@@ -540,7 +811,7 @@ ffi_closure_helper_SYSV (ffi_closure* cl
      returns the data directly to the caller.  */
   if (cif->rtype->type == FFI_TYPE_STRUCT)
     {
-      rvalue = *pgr;
+      rvalue = (void *) *pgr;
       ng++;
       pgr++;
     }
@@ -631,11 +902,11 @@ ffi_closure_helper_SYSV (ffi_closure* cl
           /* there are 8 64bit floating point registers */
 
           if (nf < 8) {
-             temp = *(double*)pfr;
-             *(float*)pfr = (float)temp;
+             temp = pfr->d;
+             pfr->f = (float)temp;
              avalue[i] = pfr;
              nf++;
-             pfr+=2;
+             pfr++;
           } else {
 	    /* FIXME? here we are really changing the values
              * stored in the original calling routines outgoing
@@ -655,7 +926,7 @@ ffi_closure_helper_SYSV (ffi_closure* cl
           if (nf < 8) {
 	     avalue[i] = pfr;
              nf++;
-             pfr+=2;
+             pfr++;
           } else {
 	     if (((long)pst) & 4) pst++;
 	     avalue[i] = pst;
@@ -674,12 +945,148 @@ ffi_closure_helper_SYSV (ffi_closure* cl
 
   (closure->fun) (cif, rvalue, avalue, closure->user_data);
 
-  /* Tell ffi_closure_osf how to perform return type promotions.  */
+  /* Tell ffi_closure_SYSV how to perform return type promotions.  */
   return cif->rtype->type;
 
 }
 
+int hidden ffi_closure_helper_LINUX64 (ffi_closure*, void*, unsigned long*,
+				       ffi_dblfl*);
 
+int hidden
+ffi_closure_helper_LINUX64 (ffi_closure* closure, void * rvalue, 
+            unsigned long * pst, ffi_dblfl * pfr)
+{
+  /* rvalue is the pointer to space for return value in closure assembly */
+  /* pst is the pointer to parameter save area
+     (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
+  /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
+
+  void **          avalue;
+  ffi_type **      arg_types;
+  long             i, avn;
+  long             nf;   /* number of floating registers already used */
+  long             ng;   /* number of general registers already used */
+  ffi_cif *        cif; 
+  double           temp; 
 
+  cif = closure->cif;
+  avalue = alloca(cif->nargs * sizeof(void *));
 
+  nf = 0;
+  ng = 0;
 
+  /* 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)
+    {
+      rvalue = (void *) *pst;
+      ng++;
+      pst++;
+    }
+
+  i = 0;
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+  
+  /* Grab the addresses of the arguments from the stack frame.  */
+  while (i < avn)
+    {
+      switch (arg_types[i]->type)
+	{
+	case FFI_TYPE_SINT8:
+	case FFI_TYPE_UINT8:
+	  avalue[i] = (char *) pst + 7;
+	  ng++;
+	  pst++;
+	  break;
+           
+	case FFI_TYPE_SINT16:
+	case FFI_TYPE_UINT16:
+	  avalue[i] = (char *) pst + 6;
+	  ng++;
+	  pst++;
+	  break;
+
+	case FFI_TYPE_SINT32:
+	case FFI_TYPE_UINT32:
+	  avalue[i] = (char *) pst + 4;
+	  ng++;
+	  pst++;
+	  break;
+
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_POINTER:
+	  avalue[i] = pst;
+	  ng++;
+	  pst++;
+	  break;
+
+	case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+	case FFI_TYPE_LONGDOUBLE:
+#endif
+	  /* Structures with 1, 2 and 4 byte sizes are passed left-padded
+	     if they are in the first 8 arguments.  */
+	  if (ng < NUM_GPR_ARG_REGISTERS64
+	      && arg_types[i]->size < 8
+	      && ((arg_types[i]->size & ~(arg_types[i]->size - 1))
+		  == arg_types[i]->size))
+	    avalue[i] = (char *) pst + 8 - arg_types[i]->size;
+	  else
+	    avalue[i] = pst;
+	  ng += (arg_types[i]->size + 7) / 8;
+	  pst += (arg_types[i]->size + 7) / 8;
+	  break;
+
+	case FFI_TYPE_FLOAT:
+	  /* unfortunately float values are stored as doubles
+           * in the ffi_closure_LINUX64 code (since we don't check
+           * the type in that routine).
+           */
+
+          /* there are 13 64bit floating point registers */
+
+          if (nf < NUM_FPR_ARG_REGISTERS64) {
+             temp = pfr->d;
+             pfr->f = (float)temp;
+             avalue[i] = pfr;
+             pfr++;
+          } else {
+	     avalue[i] = pst;
+          }
+          nf++;
+	  ng++;
+	  pst++;
+	  break;
+
+	case FFI_TYPE_DOUBLE:
+	  /* On the outgoing stack all values are aligned to 8 */
+          /* there are 13 64bit floating point registers */
+
+          if (nf < NUM_FPR_ARG_REGISTERS64) {
+	     avalue[i] = pfr;
+             pfr++;
+          } else {
+	     avalue[i] = pst;
+          }
+          nf++;
+	  ng++;
+	  pst++;
+	  break;
+
+	default:
+	  FFI_ASSERT(0);
+	}
+
+      i++;
+    }
+
+
+  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+  /* Tell ffi_closure_LINUX64 how to perform return type promotions.  */
+  return cif->rtype->type;
+
+}
--- libffi/src/powerpc/ppc_closure.S.jj	2003-04-07 12:49:53.000000000 -0400
+++ libffi/src/powerpc/ppc_closure.S	2003-04-04 14:59:12.000000000 -0500
@@ -3,6 +3,8 @@
 
         .file   "ppc_closure.S"
 
+#ifndef __powerpc64__
+
 ENTRY(ffi_closure_SYSV)
 .LFB1:
 	stwu %r1,-144(%r1)
@@ -227,3 +229,5 @@ __FRAME_BEGIN__:
 	.byte	0x1	 # uleb128 0x1
 	.align 2
 .LEFDE1:
+
+#endif
--- libffi/src/powerpc/sysv.S.jj	2003-04-07 12:49:53.000000000 -0400
+++ libffi/src/powerpc/sysv.S	2003-04-09 10:09:17.000000000 -0400
@@ -29,7 +29,8 @@
 #include <ffi.h>
 #include <powerpc/asm.h>
 
-	.globl ffi_prep_args
+#ifndef __powerpc64__
+	.globl ffi_prep_args_SYSV
 ENTRY(ffi_call_SYSV)
 .LFB1:
 	/* Save the old stack pointer as AP.  */
@@ -58,9 +59,9 @@ ENTRY(ffi_call_SYSV)
 	mr	%r28,%r8	/* our AP. */
 .LCFI6:
 
-	/* Call ffi_prep_args.  */
+	/* Call ffi_prep_args_SYSV.  */
 	mr	%r4,%r1
-	bl	JUMPTARGET(ffi_prep_args)
+	bl	JUMPTARGET(ffi_prep_args_SYSV)
 
 	/* Now do the call.  */
 	/* Set up cr1 with bits 4-7 of the flags.  */
@@ -171,3 +172,4 @@ __FRAME_BEGIN__:
       .byte     0x1c     /*  uleb128 0x1c */
       .align 2
 .LEFDE1:
+#endif
--- libffi/src/powerpc/linux64.S.jj	2003-04-09 10:21:02.000000000 -0400
+++ libffi/src/powerpc/linux64.S	2003-04-09 18:22:34.000000000 -0400
@@ -0,0 +1,185 @@
+/* -----------------------------------------------------------------------
+   sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub at redhat dot com>
+   
+   PowerPC64 Assembly glue.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM	
+#include <ffi.h>
+
+#ifdef __powerpc64__
+	.hidden	ffi_call_LINUX64, .ffi_call_LINUX64
+	.globl	ffi_call_LINUX64, .ffi_call_LINUX64
+	.section	".opd","aw"
+	.align	3
+ffi_call_LINUX64:
+	.quad	.ffi_call_LINUX64, dot TOC dot  at tocbase,0
+	.size	ffi_call_LINUX64,24
+	.type	.ffi_call_LINUX64,@function
+	.text
+.ffi_call_LINUX64:
+.LFB1:
+	mflr	%r0
+	std	%r28, -32(%r1)
+	std	%r29, -24(%r1)
+	std	%r30, -16(%r1)
+	std	%r31, -8(%r1)
+	std	%r0, 16(%r1)
+
+	mr	%r28, %r1	/* our AP.  */
+	stdux	%r1, %r1, %r4
+.LCFI0:
+	mr	%r31, %r5	/* flags, */
+	mr	%r30, %r6	/* rvalue, */
+	mr	%r29, %r7	/* function address.  */
+	std	%r2, 40(%r1)
+
+	/* Call ffi_prep_args64.  */
+	mr	%r4, %r1
+	bl	.ffi_prep_args64
+
+	ld	%r0, 0(%r29)
+	ld	%r2, 8(%r29)
+	ld	%r11, 16(%r29)
+
+	/* 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
+	/* Load all those argument registers.  */
+	ld	%r3, -32-(8*8)(%r28)
+	ld	%r4, -32-(7*8)(%r28)
+	ld	%r5, -32-(6*8)(%r28)
+	ld	%r6, -32-(5*8)(%r28)
+	bf-	5, 1f
+	ld	%r7, -32-(4*4)(%r28)
+	ld	%r8, -32-(3*4)(%r28)
+	ld	%r9, -32-(2*4)(%r28)
+	ld	%r10, -32-(1*4)(%r28)
+1:
+
+	/* Load all the FP registers.  */
+	bf-	6, 2f
+	lfd	%f1, -32-(21*8)(%r28)
+	lfd	%f2, -32-(20*8)(%r28)
+	lfd	%f3, -32-(19*8)(%r28)
+	lfd	%f4, -32-(18*8)(%r28)
+	lfd	%f5, -32-(17*8)(%r28)
+	lfd	%f6, -32-(16*8)(%r28)
+	lfd	%f7, -32-(15*8)(%r28)
+	lfd	%f8, -32-(14*8)(%r28)
+	lfd	%f9, -32-(13*8)(%r28)
+	lfd	%f10, -32-(12*8)(%r28)
+	lfd	%f11, -32-(11*8)(%r28)
+	lfd	%f12, -32-(10*8)(%r28)
+	lfd	%f13, -32-(9*8)(%r28)
+2:
+	/* FIXME: Shouldn't gcc use %r3-%r10 in this case
+	   and not the parm save area?  */
+	std	%r3, 48+(0*8)(%r1)
+	std	%r4, 48+(1*8)(%r1)
+	std	%r5, 48+(2*8)(%r1)
+	std	%r6, 48+(3*8)(%r1)
+	std	%r7, 48+(4*8)(%r1)
+	std	%r8, 48+(5*8)(%r1)
+	std	%r9, 48+(6*8)(%r1)
+	std	%r10, 48+(7*8)(%r1)
+	/* end of FIXME.  */
+
+	/* Make the call.  */
+	bctrl
+
+	/* Now, deal with the return value.  */
+	mtcrf	0x01, %r31
+	bt-	30, .Ldone_return_value
+	bt-	29, .Lfp_return_value
+	std	%r3, 0(%r30)
+	/* Fall through...  */
+
+.Ldone_return_value:
+	/* Restore the registers we used and return.  */
+	ld	%r2, 40(%r1)
+	mr	%r1, %r28
+	ld	%r0, 16(%r28)
+	ld	%r28, -32(%r1)
+	mtlr	%r0
+	ld	%r29, -24(%r1)
+	ld	%r30, -16(%r1)
+	ld	%r31, -8(%r1)
+	blr
+
+.Lfp_return_value:
+	bf	28, .Lfloat_return_value
+	stfd	%f1, 0(%r30)
+	b	.Ldone_return_value
+.Lfloat_return_value:
+	stfs	%f1, 0(%r30)
+	b	.Ldone_return_value
+.LFE1:
+	.long	0
+	.byte	0,12,0,1,128,4,0,0
+	.size	.ffi_call_LINUX64,.-.ffi_call_LINUX64
+
+	.section	.eh_frame,"aw",@progbits
+.Lframe1:
+	.4byte	.LECIE1-.LSCIE1	 # Length of Common Information Entry
+.LSCIE1:
+	.4byte	0x0	 # CIE Identifier Tag
+	.byte	0x1	 # CIE Version
+	.ascii "zR\0"	 # CIE Augmentation
+	.uleb128 0x1	 # CIE Code Alignment Factor
+	.sleb128 -8	 # CIE Data Alignment Factor
+	.byte	0x41	 # CIE RA Column
+	.uleb128 0x1	 # Augmentation size
+	.byte	0x14	 # FDE Encoding (pcrel udata8)
+	.byte	0xc	 # DW_CFA_def_cfa
+	.uleb128 0x1
+	.uleb128 0x0
+	.align 3
+.LECIE1:
+.LSFDE1:
+	.4byte	.LEFDE1-.LASFDE1	 # FDE Length
+.LASFDE1:
+	.4byte	.LASFDE1-.Lframe1	 # FDE CIE offset
+	.8byte	.LFB1-.	 # FDE initial location
+	.8byte	.LFE1-.LFB1	 # FDE address range
+	.uleb128 0x0	 # Augmentation size
+	.byte	0x2	 # DW_CFA_advance_loc1
+	.byte	.LCFI0-.LFB1
+	.byte	0xd	 # DW_CFA_def_cfa_register
+	.uleb128 0x1c
+	.byte	0x11	 # DW_CFA_offset_extended_sf
+	.uleb128 0x41
+	.sleb128 -2
+	.byte	0x9f	 # DW_CFA_offset, column 0x1f
+	.uleb128 0x1
+	.byte	0x9e	 # DW_CFA_offset, column 0x1e
+	.uleb128 0x2
+	.byte	0x9d	 # DW_CFA_offset, column 0x1d
+	.uleb128 0x3
+	.byte	0x9c	 # DW_CFA_offset, column 0x1c
+	.uleb128 0x4
+	.align 3
+.LEFDE1:
+#endif
--- libffi/src/powerpc/linux64_closure.S.jj	2003-04-09 15:35:03.000000000 -0400
+++ libffi/src/powerpc/linux64_closure.S	2003-04-10 07:34:14.000000000 -0400
@@ -0,0 +1,210 @@
+	.file	"linux64_closure.S"
+
+#ifdef __powerpc64__
+        .hidden ffi_closure_LINUX64, .ffi_closure_LINUX64
+        .globl  ffi_closure_LINUX64, .ffi_closure_LINUX64
+        .section        ".opd","aw"
+        .align  3
+ffi_closure_LINUX64:
+        .quad   .ffi_closure_LINUX64, dot TOC dot  at tocbase,0
+        .size   ffi_closure_LINUX64,24
+        .type   .ffi_closure_LINUX64,@function
+        .text
+.ffi_closure_LINUX64:
+.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
+
+	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
+	# + 8 bytes retval area + 13*8 bytes fpr save area
+	stdu	%r1, -224(%r1)
+.LCFI0:
+
+	# next save fpr 1 to fpr 13
+	stfd  %f1, 120+(0*8)(%r1)
+	stfd  %f2, 120+(1*8)(%r1)
+	stfd  %f3, 120+(2*8)(%r1)
+	stfd  %f4, 120+(3*8)(%r1)
+	stfd  %f5, 120+(4*8)(%r1)
+	stfd  %f6, 120+(5*8)(%r1)
+	stfd  %f7, 120+(6*8)(%r1)
+	stfd  %f8, 120+(7*8)(%r1)
+	stfd  %f9, 120+(8*8)(%r1)
+	stfd  %f10, 120+(9*8)(%r1)
+	stfd  %f11, 120+(10*8)(%r1)
+	stfd  %f12, 120+(11*8)(%r1)
+	stfd  %f13, 120+(12*8)(%r1)
+
+	# set up registers for the routine that actually does the work
+	# get the context pointer from the trampoline
+	mr %r3, %r11
+
+	# now load up the pointer to the result storage
+	addi %r4, %r1, 112
+
+	# now load up the pointer to the parameter save area
+	# in the previous frame
+	addi %r5, %r1, 224 + 48
+
+	# now load up the pointer to the saved fpr registers */
+	addi %r6, %r1, 120
+
+	# make the call
+	bl .ffi_closure_helper_LINUX64
+
+	# now r3 contains the return type
+	# so use it to look up in a table
+	# so we know how to deal with each type
+
+	# look up the proper starting point in table 
+	# by using return type as offset
+	addi %r5, %r1, 112	# get pointer to results area
+	bl .Lget_ret_type0_addr # get pointer to .Lret_type0 into LR
+	mflr %r4		# move to r4
+	sldi %r3, %r3, 4	# now multiply return type by 16
+	add %r3, %r3, %r4	# add contents of table to table address
+	mtctr %r3
+	bctr			# jump to it
+
+# Each of the ret_typeX code fragments has to be exactly 16 bytes long
+# (4 instructions). For cache effectiveness we align to a 16 byte boundary
+# first.
+	.align 4
+
+	nop
+	nop
+	nop
+.Lget_ret_type0_addr:
+	blrl
+
+.Lret_type0:
+# case FFI_TYPE_VOID
+	b .Lfinish
+	nop
+	nop
+	nop
+# case FFI_TYPE_INT
+	lwa %r3, 4(%r5)
+	b .Lfinish
+	nop
+	nop
+# case FFI_TYPE_FLOAT
+	lfs %f1, 4(%r5)
+	b .Lfinish
+	nop
+	nop
+# case FFI_TYPE_DOUBLE
+	lfd %f1, 0(%r5)
+	b .Lfinish
+	nop
+	nop
+# case FFI_TYPE_LONGDOUBLE
+	lfd %f1, 0(%r5)
+	b .Lfinish
+	nop
+	nop
+# case FFI_TYPE_UINT8
+	lbz %r3, 7(%r5)
+	b .Lfinish
+	nop
+	nop
+# case FFI_TYPE_SINT8
+	lbz %r3, 7(%r5)
+	extsb %r3,%r3
+	b .Lfinish
+	nop
+# case FFI_TYPE_UINT16
+	lhz %r3, 6(%r5)
+	b .Lfinish
+	nop
+	nop
+# case FFI_TYPE_SINT16
+	lha %r3, 6(%r5)
+	b .Lfinish
+	nop
+	nop
+# case FFI_TYPE_UINT32
+	lwz %r3, 4(%r5)
+	b .Lfinish
+	nop
+	nop
+# case FFI_TYPE_SINT32
+	lwa %r3, 4(%r5)
+	b .Lfinish
+	nop
+	nop
+# case FFI_TYPE_UINT64
+	ld %r3, 0(%r5)
+	b .Lfinish
+	nop
+	nop
+# case FFI_TYPE_SINT64
+	ld %r3, 0(%r5)
+	b .Lfinish
+	nop
+	nop
+# case FFI_TYPE_STRUCT
+	b .Lfinish
+	nop
+	nop
+	nop
+# case FFI_TYPE_POINTER
+	ld %r3, 0(%r5)
+	b .Lfinish
+	nop
+	nop
+# esac
+.Lfinish:
+	ld %r0, 224+16(%r1)
+	mtlr %r0
+	addi %r1, %r1, 224
+	blr
+.LFE1:
+	.long	0
+	.byte	0,12,0,1,128,0,0,0
+	.size	.ffi_closure_LINUX64,.-.ffi_closure_LINUX64
+
+	.section	.eh_frame,"aw",@progbits
+.Lframe1:
+	.4byte	.LECIE1-.LSCIE1	 # Length of Common Information Entry
+.LSCIE1:
+	.4byte	0x0	 # CIE Identifier Tag
+	.byte	0x1	 # CIE Version
+	.ascii "zR\0"	 # CIE Augmentation
+	.uleb128 0x1	 # CIE Code Alignment Factor
+	.sleb128 -8	 # CIE Data Alignment Factor
+	.byte	0x41	 # CIE RA Column
+	.uleb128 0x1	 # Augmentation size
+	.byte	0x14	 # FDE Encoding (pcrel udata8)
+	.byte	0xc	 # DW_CFA_def_cfa
+	.uleb128 0x1
+	.uleb128 0x0
+	.align 3
+.LECIE1:
+.LSFDE1:
+	.4byte	.LEFDE1-.LASFDE1	 # FDE Length
+.LASFDE1:
+	.4byte	.LASFDE1-.Lframe1	 # FDE CIE offset
+	.8byte	.LFB1-.	 # FDE initial location
+	.8byte	.LFE1-.LFB1	 # FDE address range
+	.uleb128 0x0	 # Augmentation size
+	.byte	0x2	 # DW_CFA_advance_loc1
+	.byte	.LCFI0-.LFB1
+	.byte	0xe	 # DW_CFA_def_cfa_offset
+	.uleb128 224
+	.byte	0x11	 # DW_CFA_offset_extended_sf
+	.uleb128 0x41
+	.sleb128 -2
+	.align 3
+.LEFDE1:
+#endif
--- libffi/src/ffitest.c.jj	2003-01-14 04:50:48.000000000 -0500
+++ libffi/src/ffitest.c	2003-04-10 10:20:16.000000000 -0400
@@ -309,7 +309,7 @@ closure_test_fn(ffi_cif* cif,void* resp,
 	       (int)(*(int *)args[10]), (int)(*(float *)args[11]),
 	       (int)*(int *)args[12], (int)(*(int *)args[13]), 
 	       (int)(*(int *)args[14]),*(int *)args[15],
-	       (int)(long)userdata, *(int*)resp);
+	       (int)(long)userdata, (int)*(ffi_arg *)resp);
 }
 
 typedef int (*closure_test_type)(unsigned long long, int, unsigned long long, 
@@ -339,7 +339,7 @@ static void closure_test_fn1(ffi_cif* ci
 	   (int)(*(int *)args[10]), (int)(*(float *)args[11]),
 	   (int)*(int *)args[12], (int)(*(int *)args[13]),
 	   (int)(*(int *)args[14]), *(int *)args[15],
-	   (int)(long)userdata, *(int*)resp);
+	   (int)(long)userdata, (int)*(ffi_arg *)resp);
 }
 
 typedef int (*closure_test_type1)(float, float, float, float, signed short, 
@@ -368,7 +368,7 @@ static void closure_test_fn2(ffi_cif* ci
 	   (int)(*(int *)args[10]), (int)(*(float *)args[11]),
 	   (int)*(int *)args[12], (int)(*(float *)args[13]), 
 	   (int)(*(int *)args[14]), *(int *)args[15], (int)(long)userdata, 
-	   *(int*)resp);
+	   (int)*(ffi_arg *)resp);
  }
 
 typedef int (*closure_test_type2)(double, double, double, double, signed short,
@@ -397,7 +397,7 @@ static void closure_test_fn3(ffi_cif* ci
 	   (int)(*(float *)args[10]), (int)(*(float *)args[11]),
 	   (int)*(int *)args[12], (int)(*(float *)args[13]), 
 	   (int)(*(float *)args[14]), *(int *)args[15], (int)(long)userdata,
-	   *(int*)resp);
+	   (int)*(ffi_arg *)resp);
  }
 
 typedef int (*closure_test_type3)(float, float, float, float, float, float,
@@ -430,6 +430,7 @@ int main(/* at unused@*/ int argc, /* at unuse
   /* The closure must not be an automatic variable on
      platforms (Solaris) that forbid stack execution by default. */
   static ffi_closure cl;
+  ffi_closure *pcl = &cl;
 #endif
 
   ffi_type * cl_arg_types[17];
@@ -841,8 +842,8 @@ int main(/* at unused@*/ int argc, /* at unuse
     ts2_arg.d1 = 5.55;
     ts2_arg.d2 = 6.66;
 
-    printf ("%g\n", ts2_result->d1);
-    printf ("%g\n", ts2_result->d2);
+    printf ("%g\n", ts2_arg.d1);
+    printf ("%g\n", ts2_arg.d2);
 
     ffi_call(&cif, FFI_FN(struct2), ts2_result, values);
 
@@ -1161,6 +1162,13 @@ int main(/* at unused@*/ int argc, /* at unuse
 #endif /* X86_WIN32 */
 
 # if FFI_CLOSURES
+#  if __GNUC__ >= 2
+   /* Hide before the compiler that pcl is &cl, since on
+      some architectures it is not possible to call a data
+      object using direct function call.  */
+   asm ("" : "=X" (pcl) : "0" (pcl));
+#  endif
+
   /* A simple closure test */
     {
       (void) puts("\nEnter FFI_CLOSURES\n");
@@ -1187,10 +1195,10 @@ int main(/* at unused@*/ int argc, /* at unuse
       CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
 			 &ffi_type_sint, cl_arg_types) == FFI_OK);
 
-      CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn,
+      CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn,
 			     (void *) 3 /* userdata */) == FFI_OK);
       
-      CHECK((*((closure_test_type)(&cl)))
+      CHECK((*((closure_test_type)pcl))
 	    (1LL, 2, 3LL, 4, 127, 429LL, 7, 8, 9.5, 10, 11, 12, 13, 
 	     19, 21, 1) == 680);
     }
@@ -1219,10 +1227,10 @@ int main(/* at unused@*/ int argc, /* at unuse
       CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
 			 &ffi_type_sint, cl_arg_types) == FFI_OK);
 
-      CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn1,
+      CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn1,
 			     (void *) 3 /* userdata */)  == FFI_OK);
       
-      CHECK((*((closure_test_type1)(&cl)))
+      CHECK((*((closure_test_type1)pcl))
 	    (1.1, 2.2, 3.3, 4.4, 127, 5.5, 6.6, 8, 9, 10, 11, 12.0, 13,
 	     19, 21, 1) == 255);
     }
@@ -1251,10 +1259,10 @@ int main(/* at unused@*/ int argc, /* at unuse
       CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
 			 &ffi_type_sint, cl_arg_types) == FFI_OK);
 
-      CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn2,
+      CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn2,
 			     (void *) 3 /* userdata */) == FFI_OK);
 
-      CHECK((*((closure_test_type2)(&cl)))
+      CHECK((*((closure_test_type2)pcl))
 	    (1, 2, 3, 4, 127, 5, 6, 8, 9, 10, 11, 12.0, 13,
 	     19.0, 21, 1) == 255);
 
@@ -1284,10 +1292,10 @@ int main(/* at unused@*/ int argc, /* at unuse
       CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
 			 &ffi_type_sint, cl_arg_types) == FFI_OK);
 
-      CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn3,
+      CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn3,
 			     (void *) 3 /* userdata */)  == FFI_OK);
       
-      CHECK((*((closure_test_type3)(&cl)))
+      CHECK((*((closure_test_type3)pcl))
 	    (1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9, 10, 11.11, 12.0, 13,
 	     19.19, 21.21, 1) == 135);
     }
--- libffi/Makefile.am.jj	2003-01-27 20:48:33.000000000 -0500
+++ libffi/Makefile.am	2003-04-10 08:25:02.000000000 -0400
@@ -12,6 +12,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mi
 		src/alpha/ffi.c src/alpha/osf.S \
 		src/m68k/ffi.c src/m68k/sysv.S \
 		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/ffi_darwin.c \
 		src/powerpc/darwin.S src/powerpc/aix.S \
@@ -94,7 +95,7 @@ TARGET_SRC_SPARC = src/sparc/ffi.c src/s
 TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S
 TARGET_SRC_IA64 = src/ia64/ffi.c src/ia64/unix.S
 TARGET_SRC_M68K = src/m68k/ffi.c src/m68k/sysv.S
-TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S
+TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S
 TARGET_SRC_POWERPC_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S
 TARGET_SRC_POWERPC_DARWIN = src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S
 TARGET_SRC_ARM =  src/arm/sysv.S src/arm/ffi.c
--- libffi/configure.jj	2003-04-07 12:49:53.000000000 -0400
+++ libffi/configure	2003-04-09 10:19:56.000000000 -0400
@@ -2469,7 +2469,7 @@ ia64*-*-*) TARGET=IA64; TARGETDIR=ia64;;
 m68k-*-linux*) TARGET=M68K; TARGETDIR=m68k;;
 mips64*-*);;
 mips*-*-linux*) TARGET=MIPS_LINUX; TARGETDIR=mips;;
-powerpc-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;;
+powerpc*-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;;
 powerpc-*-beos*) TARGET=POWERPC; TARGETDIR=powerpc;;
 powerpc-*-darwin*) TARGET=POWERPC_DARWIN; TARGETDIR=powerpc;;
 powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
--- libffi/Makefile.in.jj	2003-01-28 17:58:58.000000000 -0500
+++ libffi/Makefile.in	2003-04-10 08:27:33.000000000 -0400
@@ -95,6 +95,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mi
 		src/alpha/ffi.c src/alpha/osf.S \
 		src/m68k/ffi.c src/m68k/sysv.S \
 		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/ffi_darwin.c \
 		src/powerpc/darwin.S src/powerpc/aix.S \
@@ -173,7 +174,7 @@ TARGET_SRC_SPARC = src/sparc/ffi.c src/s
 TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S
 TARGET_SRC_IA64 = src/ia64/ffi.c src/ia64/unix.S
 TARGET_SRC_M68K = src/m68k/ffi.c src/m68k/sysv.S
-TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S
+TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S
 TARGET_SRC_POWERPC_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S
 TARGET_SRC_POWERPC_DARWIN = src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S
 TARGET_SRC_ARM = src/arm/sysv.S src/arm/ffi.c
@@ -257,7 +258,8 @@ libffi_convenience_la_LIBADD = 
 @POWERPC_TRUE at libffi_convenience_la_OBJECTS =  src/debug.lo \
 @POWERPC_TRUE at src/prep_cif.lo src/types.lo src/raw_api.lo \
 @POWERPC_TRUE at src/java_raw_api.lo src/powerpc/ffi.lo \
- at POWERPC_TRUE@src/powerpc/sysv.lo src/powerpc/ppc_closure.lo
+ at POWERPC_TRUE@src/powerpc/sysv.lo src/powerpc/ppc_closure.lo \
+ at POWERPC_TRUE@src/powerpc/linux64.lo src/powerpc/linux64_closure.lo
 @MIPS_LINUX_TRUE at libffi_convenience_la_OBJECTS =  src/debug.lo \
 @MIPS_LINUX_TRUE at src/prep_cif.lo src/types.lo src/raw_api.lo \
 @MIPS_LINUX_TRUE at src/java_raw_api.lo src/mips/ffi.lo src/mips/o32.lo
@@ -301,7 +303,8 @@ libffi_la_LIBADD = 
 @POWERPC_TRUE at libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
 @POWERPC_TRUE at src/types.lo src/raw_api.lo src/java_raw_api.lo \
 @POWERPC_TRUE at src/powerpc/ffi.lo src/powerpc/sysv.lo \
- at POWERPC_TRUE@src/powerpc/ppc_closure.lo
+ at POWERPC_TRUE@src/powerpc/ppc_closure.lo src/powerpc/linux64.lo \
+ at POWERPC_TRUE@src/powerpc/linux64_closure.lo
 @MIPS_LINUX_TRUE at libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
 @MIPS_LINUX_TRUE at src/types.lo src/raw_api.lo src/java_raw_api.lo \
 @MIPS_LINUX_TRUE at src/mips/ffi.lo src/mips/o32.lo
--- configure.in.jj	2003-03-13 19:22:52.000000000 -0500
+++ configure.in	2003-04-09 10:27:16.000000000 -0400
@@ -606,11 +606,6 @@ case "${target}" in
   powerpc-*-eabi)
     noconfigdirs="$noconfigdirs ${libgcj}"
     ;;
-  powerpc64*-*-linux*)
-    noconfigdirs="$noconfigdirs target-newlib target-libgloss"
-    # not yet ported.
-    noconfigdirs="$noconfigdirs target-libffi"
-    ;;
   rs6000-*-lynxos*)
     noconfigdirs="$noconfigdirs target-newlib gprof ${libgcj}"
     ;;
--- configure.jj	2003-03-13 19:22:52.000000000 -0500
+++ configure	2003-04-09 10:27:29.000000000 -0400
@@ -1266,11 +1266,6 @@ case "${target}" in
   powerpc-*-eabi)
     noconfigdirs="$noconfigdirs ${libgcj}"
     ;;
-  powerpc64*-*-linux*)
-    noconfigdirs="$noconfigdirs target-newlib target-libgloss"
-    # not yet ported.
-    noconfigdirs="$noconfigdirs target-libffi"
-    ;;
   rs6000-*-lynxos*)
     noconfigdirs="$noconfigdirs target-newlib gprof ${libgcj}"
     ;;

	Jakub


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