OSDN Git Service

* configure.in (powerpc64*-*-linux*): Remove.
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 18 Apr 2003 12:32:36 +0000 (12:32 +0000)
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 18 Apr 2003 12:32:36 +0000 (12:32 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@65781 138bc75d-0d04-0410-961f-82ee72b054a4

15 files changed:
ChangeLog
configure
configure.in
libffi/ChangeLog
libffi/Makefile.am
libffi/Makefile.in
libffi/configure
libffi/configure.in
libffi/include/ffi.h.in
libffi/src/ffitest.c
libffi/src/powerpc/ffi.c
libffi/src/powerpc/linux64.S [new file with mode: 0644]
libffi/src/powerpc/linux64_closure.S [new file with mode: 0644]
libffi/src/powerpc/ppc_closure.S
libffi/src/powerpc/sysv.S

index 4b26025..94dc631 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2003-04-18  Jakub Jelinek  <jakub@redhat.com>
+
+       * configure.in (powerpc64*-*-linux*): Remove.
+       * configure: Rebuilt.
+
 2003-04-17  Phil Edwards  <pme@gcc.gnu.org>
 
        * Makefile.tpl (GCC_STRAP_TARGETS):  New variable containing all the
index 8b10e66..045ad14 100755 (executable)
--- a/configure
+++ b/configure
@@ -1267,11 +1267,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}"
     ;;
index b4e8099..f695982 100644 (file)
@@ -607,11 +607,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}"
     ;;
index 93b171a..e07b07f 100644 (file)
@@ -1,3 +1,42 @@
+2003-04-18  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2003-04-16  Richard Earnshaw  <rearnsha@arm.com>
 
        * configure.in (arm-*-netbsdelf*): Add configuration.
index 33c365c..82381b8 100644 (file)
@@ -12,6 +12,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \
                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/sparc/v8.S src/sparc/v9.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
index 6f89e0a..08d8c73 100644 (file)
@@ -95,6 +95,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \
                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/sparc/v8.S src/sparc/v9.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@libffi_convenience_la_OBJECTS =  src/debug.lo \
 @POWERPC_TRUE@src/prep_cif.lo src/types.lo src/raw_api.lo \
 @POWERPC_TRUE@src/java_raw_api.lo src/powerpc/ffi.lo \
-@POWERPC_TRUE@src/powerpc/sysv.lo src/powerpc/ppc_closure.lo
+@POWERPC_TRUE@src/powerpc/sysv.lo src/powerpc/ppc_closure.lo \
+@POWERPC_TRUE@src/powerpc/linux64.lo src/powerpc/linux64_closure.lo
 @MIPS_LINUX_TRUE@libffi_convenience_la_OBJECTS =  src/debug.lo \
 @MIPS_LINUX_TRUE@src/prep_cif.lo src/types.lo src/raw_api.lo \
 @MIPS_LINUX_TRUE@src/java_raw_api.lo src/mips/ffi.lo src/mips/o32.lo
@@ -301,7 +303,8 @@ libffi_la_LIBADD =
 @POWERPC_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
 @POWERPC_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
 @POWERPC_TRUE@src/powerpc/ffi.lo src/powerpc/sysv.lo \
-@POWERPC_TRUE@src/powerpc/ppc_closure.lo
+@POWERPC_TRUE@src/powerpc/ppc_closure.lo src/powerpc/linux64.lo \
+@POWERPC_TRUE@src/powerpc/linux64_closure.lo
 @MIPS_LINUX_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
 @MIPS_LINUX_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
 @MIPS_LINUX_TRUE@src/mips/ffi.lo src/mips/o32.lo
index 42ff71c..6197a44 100755 (executable)
@@ -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;;
index e6606f9..7bb01d6 100644 (file)
@@ -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;;
index fe91ecd..c51a809 100644 (file)
@@ -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)
index a05b746..223b49c 100644 (file)
@@ -309,7 +309,7 @@ closure_test_fn(ffi_cif* cif,void* resp,void** args, void* userdata)
               (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* cif,void* resp,void** args,
           (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* cif,void* resp,void** args,
           (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* cif,void* resp,void** args,
           (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(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
   /* 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(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
     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(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
 #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 ("" : "=g" (pcl) : "0" (pcl));
+#  endif
+
   /* A simple closure test */
     {
       (void) puts("\nEnter FFI_CLOSURES\n");
@@ -1187,10 +1195,10 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
       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(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
       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(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
       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(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
       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);
     }
index ea1a14e..6f0e2a5 100644 (file)
 #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 };
    */
 
 /*@-exportheader@*/
-void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
+void ffi_prep_args_SYSV(extended_cif *ecif, unsigned *const stack)
 /*@=exportheader@*/
 {
   const unsigned bytes = ecif->cif->bytes;
@@ -124,7 +132,7 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
   /* 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, unsigned *const stack)
          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, unsigned *const stack)
   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
+
+   */
+
+/*@-exportheader@*/
+void hidden ffi_prep_args64(extended_cif *ecif, unsigned long *const stack)
+/*@=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 *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 *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 *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(/*@out@*/ extended_cif *,
                          unsigned, unsigned, 
                          /*@out@*/ unsigned *, 
                          void (*fn)());
+extern void hidden ffi_call_LINUX64(/*@out@*/ extended_cif *, 
+                                   unsigned long, unsigned long,
+                                   /*@out@*/ unsigned long *, 
+                                   void (*fn)());
 /*@=declundef@*/
 /*@=exportheader@*/
 
@@ -437,6 +684,7 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
   
   switch (cif->abi) 
     {
+#ifndef POWERPC64
     case FFI_SYSV:
     case FFI_GCC_SYSV:
       /*@-usedef@*/
@@ -444,6 +692,14 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
                    cif->flags, ecif.rvalue, fn);
       /*@=usedef@*/
       break;
+#else
+    case FFI_LINUX64:
+      /*@-usedef@*/
+      ffi_call_LINUX64(&ecif, -(long) cif->bytes,
+                      cif->flags, ecif.rvalue, fn);
+      /*@=usedef@*/
+      break;
+#endif
     default:
       FFI_ASSERT(0);
       break;
@@ -451,14 +707,38 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
 }
 
 
+#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*, void*, unsigned long*,
 
 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* closure, void * rvalue,
      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* closure, void * rvalue,
           /* 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* closure, void * rvalue,
           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* closure, void * rvalue,
 
   (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;
+
+}
diff --git a/libffi/src/powerpc/linux64.S b/libffi/src/powerpc/linux64.S
new file mode 100644 (file)
index 0000000..9619c53
--- /dev/null
@@ -0,0 +1,185 @@
+/* -----------------------------------------------------------------------
+   sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.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,.TOC.@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
diff --git a/libffi/src/powerpc/linux64_closure.S b/libffi/src/powerpc/linux64_closure.S
new file mode 100644 (file)
index 0000000..d435e58
--- /dev/null
@@ -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,.TOC.@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
index e402fb5..4cfc8fd 100644 (file)
@@ -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
index 538ffa8..c1e0d18 100644 (file)
@@ -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