From d7a35c6c8ed56febd7ecab5f2248fe633ccb5b48 Mon Sep 17 00:00:00 2001
From: green <green@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Mon, 17 Apr 2000 02:15:32 +0000
Subject: [PATCH] Port to sparc 32 and 64 Linux.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@33196 138bc75d-0d04-0410-961f-82ee72b054a4
---
 libffi/ChangeLog        |  35 +++++
 libffi/Makefile.am      |   4 +-
 libffi/Makefile.in      |   9 +-
 libffi/configure        |   2 +
 libffi/configure.in     |   2 +
 libffi/include/ffi.h.in |  14 +-
 libffi/src/ffitest.c    |   4 +-
 libffi/src/prep_cif.c   |  13 +-
 libffi/src/sparc/ffi.c  | 296 ++++++++++++++++++++++++++++++++++------
 libffi/src/sparc/v8.S   |  10 ++
 libffi/src/sparc/v9.S   | 127 +++++++++++++++++
 libffi/src/types.c      |  19 ++-
 12 files changed, 476 insertions(+), 59 deletions(-)
 create mode 100644 libffi/src/sparc/v9.S

diff --git a/libffi/ChangeLog b/libffi/ChangeLog
index 6376b75f163c..037726e11449 100644
--- a/libffi/ChangeLog
+++ b/libffi/ChangeLog
@@ -1,3 +1,38 @@
+2000-04-14  Jakub Jelinek  <jakub@redhat.com>
+
+        * include/ffi.h.in (SPARC64): Define for 64bit SPARC builds.
+	Set SPARC FFI_DEFAULT_ABI based on SPARC64 define.
+	* src/sparc/ffi.c (ffi_prep_args_v8): Renamed from ffi_prep_args.
+	Replace all void * sizeofs with sizeof(int).
+	Only compare type with FFI_TYPE_LONGDOUBLE if LONGDOUBLE is
+	different than DOUBLE.
+	Remove FFI_TYPE_SINT32 and FFI_TYPE_UINT32 cases (handled elsewhere).
+	(ffi_prep_args_v9): New function.
+	(ffi_prep_cif_machdep): Handle V9 ABI and long long on V8.
+	(ffi_V9_return_struct): New function.
+	(ffi_call): Handle FFI_V9 ABI from 64bit code and FFI_V8 ABI from
+	32bit code (not yet cross-arch calls).
+	* src/sparc/v8.S: Add struct return delay nop.
+	Handle long long.
+	* src/sparc/v9.S: New file.
+	* src/prep_cif.c (ffi_prep_cif): Return structure pointer
+	is used on sparc64 only for structures larger than 32 bytes.
+	Pass by reference for structures is done for structure arguments
+	larger than 16 bytes.
+	* src/ffitest.c (main): Use 64bit rint on sparc64.
+	Run long long tests on sparc.
+	* src/types.c (FFI_TYPE_POINTER): Pointer is 64bit on alpha and
+	sparc64.
+	(FFI_TYPE_LONGDOUBLE): long double is 128 bit aligned to 128 bits
+	on sparc64.
+	* configure.in (sparc-*-linux*): New supported target.
+	(sparc64-*-linux*): Likewise.
+	* configure: Rebuilt.
+	* Makefile.am: Add v9.S to SPARC files.
+	* Makefile.in: Likewise.
+	(LINK): Surround $(CCLD) into double quotes, so that multilib
+	compiles work correctly.
+
 2000-04-04  Alexandre Petit-Bianco  <apbianco@cygnus.com>
 
 	* configure: Rebuilt.
diff --git a/libffi/Makefile.am b/libffi/Makefile.am
index cbb05616b337..8f51eb34d898 100644
--- a/libffi/Makefile.am
+++ b/libffi/Makefile.am
@@ -4,7 +4,7 @@ AUTOMAKE_OPTIONS = cygnus
 
 EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \
 		src/mips/n32.s src/mips/o32.S src/mips/o32.s \
-		src/sparc/ffi.c src/sparc/v8.S \
+		src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S \
 		src/x86/ffi.c src/x86/sysv.S \
 		src/alpha/ffi.c src/alpha/osf.S \
 		src/m68k/ffi.c src/m68k/sysv.S \
@@ -40,7 +40,7 @@ ffitest_LDADD = libffi.la
 TARGET_SRC_MIPS_GCC = src/mips/ffi.c src/mips/o32.S src/mips/n32.S
 TARGET_SRC_MIPS_SGI = src/mips/ffi.c src/mips/o32.s src/mips/n32.s
 TARGET_SRC_X86 = src/x86/ffi.c src/x86/sysv.S
-TARGET_SRC_SPARC = src/sparc/ffi.c src/sparc/v8.S
+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
diff --git a/libffi/Makefile.in b/libffi/Makefile.in
index 2bf459c09829..078daf4d058a 100644
--- a/libffi/Makefile.in
+++ b/libffi/Makefile.in
@@ -84,7 +84,7 @@ AUTOMAKE_OPTIONS = cygnus
 
 EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \
 		src/mips/n32.s src/mips/o32.S src/mips/o32.s \
-		src/sparc/ffi.c src/sparc/v8.S \
+		src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S \
 		src/x86/ffi.c src/x86/sysv.S \
 		src/alpha/ffi.c src/alpha/osf.S \
 		src/m68k/ffi.c src/m68k/sysv.S \
@@ -115,7 +115,7 @@ ffitest_LDADD = libffi.la
 TARGET_SRC_MIPS_GCC = src/mips/ffi.c src/mips/o32.S src/mips/n32.S
 TARGET_SRC_MIPS_SGI = src/mips/ffi.c src/mips/o32.s src/mips/n32.s
 TARGET_SRC_X86 = src/x86/ffi.c src/x86/sysv.S
-TARGET_SRC_SPARC = src/sparc/ffi.c src/sparc/v8.S
+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
@@ -164,7 +164,7 @@ libffi_la_LIBADD =
 @POWERPC_TRUE@am_libffi_la_OBJECTS =  debug.lo prep_cif.lo types.lo \
 @POWERPC_TRUE@raw_api.lo java_raw_api.lo ffi.lo sysv.lo
 @SPARC_TRUE@am_libffi_la_OBJECTS =  debug.lo prep_cif.lo types.lo \
-@SPARC_TRUE@raw_api.lo java_raw_api.lo ffi.lo v8.lo
+@SPARC_TRUE@raw_api.lo java_raw_api.lo ffi.lo v8.lo v9.lo
 @X86_TRUE@am_libffi_la_OBJECTS =  debug.lo prep_cif.lo types.lo \
 @X86_TRUE@raw_api.lo java_raw_api.lo ffi.lo sysv.lo
 libffi_la_OBJECTS =  $(am_libffi_la_OBJECTS)
@@ -179,7 +179,7 @@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CF
 LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
 CFLAGS = @CFLAGS@
 CCLD = $(CC)
-LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+LINK = $(LIBTOOL) --mode=link "$(CCLD)" $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
 DIST_SOURCES =  $(libffi_la_SOURCES) $(ffitest_SOURCES)
 DIST_COMMON =  README ./stamp-h.in ChangeLog Makefile.am Makefile.in \
 acconfig.h aclocal.m4 config.guess config.sub configure configure.in \
@@ -299,6 +299,7 @@ sysv.lo: src/arm/sysv.S
 o32.lo: src/mips/o32.S
 n32.lo: src/mips/n32.S
 v8.lo: src/sparc/v8.S
+v9.lo: src/sparc/v9.S
 
 libffi.la: $(libffi_la_OBJECTS) $(libffi_la_DEPENDENCIES)
 	$(LINK) -rpath $(toolexeclibdir) $(libffi_la_LDFLAGS) $(libffi_la_OBJECTS) $(libffi_la_LIBADD) $(LIBS)
diff --git a/libffi/configure b/libffi/configure
index dbd1f2e36d63..d876117f90f2 100755
--- a/libffi/configure
+++ b/libffi/configure
@@ -1630,6 +1630,8 @@ i*86-*-solaris*) TARGET=X86; TARGETDIR=x86;;
 i*86-*-beos*) TARGET=X86; TARGETDIR=x86;;
 sparc-sun-4*) TARGET=SPARC; TARGETDIR=sparc;;
 sparc-sun-*) TARGET=SPARC; TARGETDIR=sparc;;
+sparc-*-linux*) TARGET=SPARC; TARGETDIR=sparc;;
+sparc64-*-linux*) TARGET=SPARC; TARGETDIR=sparc;;
 alpha*-*-linux* | alpha*-*-osf*) TARGET=ALPHA; TARGETDIR=alpha;;
 ia64*-*-*) TARGET=IA64; TARGETDIR=ia64;;
 m68k-*-linux*) TARGET=M68K; TARGETDIR=m68k;;
diff --git a/libffi/configure.in b/libffi/configure.in
index db643ecf01f1..38d8473852ce 100644
--- a/libffi/configure.in
+++ b/libffi/configure.in
@@ -50,6 +50,8 @@ i*86-*-solaris*) TARGET=X86; TARGETDIR=x86;;
 i*86-*-beos*) TARGET=X86; TARGETDIR=x86;;
 sparc-sun-4*) TARGET=SPARC; TARGETDIR=sparc;;
 sparc-sun-*) TARGET=SPARC; TARGETDIR=sparc;;
+sparc-*-linux*) TARGET=SPARC; TARGETDIR=sparc;;
+sparc64-*-linux*) TARGET=SPARC; TARGETDIR=sparc;;
 alpha*-*-linux* | alpha*-*-osf*) TARGET=ALPHA; TARGETDIR=alpha;;
 ia64*-*-*) TARGET=IA64; TARGETDIR=ia64;;
 m68k-*-linux*) TARGET=M68K; TARGETDIR=m68k;;
diff --git a/libffi/include/ffi.h.in b/libffi/include/ffi.h.in
index 655cc1c6cbf8..6be7e23c727e 100644
--- a/libffi/include/ffi.h.in
+++ b/libffi/include/ffi.h.in
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------*-C-*-
    libffi @VERSION@ - Copyright (c) 1996-1999  Cygnus Solutions
 
-   $Id: ffi.h.in,v 1.3 1999/09/01 23:16:34 tromey Exp $
+   $Id: ffi.h.in,v 1.4 2000/02/25 19:13:44 tromey Exp $
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
@@ -160,6 +160,12 @@ extern "C" {
 #define SIZEOF_ARG SIZEOF_VOID_P
 #endif
 
+#ifdef SPARC
+#if defined(__arch64__) || defined(__sparcv9)
+#define SPARC64
+#endif
+#endif
+
 #ifndef LIBFFI_ASM
 
 /* ---- Generic type definitions ----------------------------------------- */
@@ -176,9 +182,13 @@ typedef enum ffi_abi {
   /* ---- Sparc -------------------- */
 #ifdef SPARC
   FFI_V8,
-  FFI_DEFAULT_ABI = FFI_V8,
   FFI_V8PLUS,
   FFI_V9,
+#ifdef SPARC64
+  FFI_DEFAULT_ABI = FFI_V9,
+#else
+  FFI_DEFAULT_ABI = FFI_V8,
+#endif
 #endif
 
   /* ---- Intel x86 ---------------- */
diff --git a/libffi/src/ffitest.c b/libffi/src/ffitest.c
index 3dd0989783c3..d4a687c6d53c 100644
--- a/libffi/src/ffitest.c
+++ b/libffi/src/ffitest.c
@@ -224,7 +224,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
   signed int si1;
   signed int si2;
 
-#if defined(ALPHA) || defined(IA64) || (defined(MIPS) && (_MIPS_SIM == _ABIN32))
+#if defined(ALPHA) || defined(IA64) || defined(SPARC64) || (defined(MIPS) && (_MIPS_SIM == _ABIN32))
   long long rint;
 #else
   int rint;
@@ -295,7 +295,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
 
   /* return value tests */
   {
-#if defined(MIPS) || defined(SPARC) /* || defined(ARM) */
+#if defined(MIPS) /* || defined(ARM) */
     puts ("long long tests not run. This is a known bug on this architecture.");
 #else
     args[0] = &ffi_type_sint64;
diff --git a/libffi/src/prep_cif.c b/libffi/src/prep_cif.c
index 4c731b994555..3f21411a6cb2 100644
--- a/libffi/src/prep_cif.c
+++ b/libffi/src/prep_cif.c
@@ -107,7 +107,11 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
 
 #ifndef M68K
   /* Make space for the return structure pointer */
-  if (cif->rtype->type == FFI_TYPE_STRUCT)
+  if (cif->rtype->type == FFI_TYPE_STRUCT
+#ifdef SPARC
+      && (cif->abi != FFI_V9 || cif->rtype->size > 32)
+#endif
+      )
     bytes = STACK_ARG_SIZE(sizeof(void*));
 #endif
 
@@ -121,8 +125,10 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
 	return FFI_BAD_TYPEDEF;
 
 #ifdef SPARC
-      if ((*ptr)->type == FFI_TYPE_STRUCT
-	  || (*ptr)->type == FFI_TYPE_LONGDOUBLE)
+      if (((*ptr)->type == FFI_TYPE_STRUCT
+	   && ((*ptr)->size > 16 || cif->abi != FFI_V9))
+	  || ((*ptr)->type == FFI_TYPE_LONGDOUBLE
+	      && cif->abi != FFI_V9))
 	bytes += sizeof(void*);
       else
 #endif
@@ -140,4 +146,3 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
   /* Perform machine dependent cif processing */
   return ffi_prep_cif_machdep(cif);
 }
-
diff --git a/libffi/src/sparc/ffi.c b/libffi/src/sparc/ffi.c
index 8ca6710c94a4..647063686b9e 100644
--- a/libffi/src/sparc/ffi.c
+++ b/libffi/src/sparc/ffi.c
@@ -33,7 +33,7 @@
 /* ffi_prep_args is called by the assembly routine once stack space
    has been allocated for the function's arguments */
 
-void ffi_prep_args(char *stack, extended_cif *ecif)
+void ffi_prep_args_v8(char *stack, extended_cif *ecif)
 {
   int i;
   int tmp;
@@ -45,16 +45,16 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
   tmp = 0;
 
   /* Skip 16 words for the window save area */
-  argp = stack + 16*sizeof(void*);
+  argp = stack + 16*sizeof(int);
 
   /* This should only really be done when we are returning a structure,
      however, it's faster just to do it all the time...
 
   if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
-  *(void **) argp = ecif->rvalue;
+  *(int *) argp = (long)ecif->rvalue;
 
   /* And 1 word for the  structure return value. */
-  argp += sizeof(void*);
+  argp += sizeof(int);
 
 #ifdef USING_PURIFY
   /* Purify will probably complain in our assembly routine, unless we
@@ -81,10 +81,13 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
 	{
 	  avn--;
 	  if ((*p_arg)->type == FFI_TYPE_STRUCT
-	      || (*p_arg)->type == FFI_TYPE_LONGDOUBLE)
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+	      || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
+#endif
+	      )
 	    {
-	      *(unsigned int *) argp = (unsigned int)(* p_argv);
-	      z = sizeof(void*);
+	      *(unsigned int *) argp = (unsigned long)(* p_argv);
+	      z = sizeof(int);
 	    }
 	  else
 	    {
@@ -109,15 +112,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
 		    case FFI_TYPE_UINT16:
 		      *(unsigned int *) argp = *(UINT16 *)(* p_argv);
 		      break;
-		      
-		    case FFI_TYPE_SINT32:
-		      *(signed int *) argp = *(SINT32 *)(* p_argv);
-		      break;
-		      
-		    case FFI_TYPE_UINT32:
-		      *(unsigned int *) argp = *(UINT32 *)(* p_argv);
-		      break;
-		      
+
 		    default:
 		      FFI_ASSERT(0);
 		    }
@@ -135,82 +130,295 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
   return;
 }
 
+int ffi_prep_args_v9(char *stack, extended_cif *ecif)
+{
+  int i, ret = 0;
+  int tmp;
+  void **p_argv;
+  char *argp;
+  ffi_type **p_arg;
+
+  tmp = 0;
+
+  /* Skip 16 words for the window save area */
+  argp = stack + 16*sizeof(long long);
+
+#ifdef USING_PURIFY
+  /* Purify will probably complain in our assembly routine, unless we
+     zero out this memory. */
+
+  ((long long*)argp)[0] = 0;
+  ((long long*)argp)[1] = 0;
+  ((long long*)argp)[2] = 0;
+  ((long long*)argp)[3] = 0;
+  ((long long*)argp)[4] = 0;
+  ((long long*)argp)[5] = 0;
+#endif
+
+  p_argv = ecif->avalue;
+
+  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT &&
+      ecif->cif->rtype->size > 32)
+    {
+      *(unsigned long long *) argp = (unsigned long)ecif->rvalue;
+      tmp = 1;
+    }
+
+  for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
+       i++, p_arg++)
+    {
+      size_t z;
+
+      z = (*p_arg)->size;
+      switch ((*p_arg)->type)
+	{
+	case FFI_TYPE_STRUCT:
+	  if (z > 16)
+	    {
+	      /* For structures larger than 16 bytes we pass reference.  */
+	      *(unsigned long long *) argp = (unsigned long)* p_argv;
+	      argp += sizeof(long long);
+	      tmp++;
+	      p_argv++;
+	      continue;
+	    }
+	  /* FALLTHROUGH */
+	case FFI_TYPE_FLOAT:
+	case FFI_TYPE_DOUBLE:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+	case FFI_TYPE_LONGDOUBLE:
+#endif
+	  ret = 1; /* We should promote into FP regs as well as integer.  */
+	  break;
+	}
+      if (z < sizeof(long long))
+	{
+	  switch ((*p_arg)->type)
+	    {
+	    case FFI_TYPE_SINT8:
+	      *(signed long long *) argp = *(SINT8 *)(* p_argv);
+	      break;
+
+	    case FFI_TYPE_UINT8:
+	      *(unsigned long long *) argp = *(UINT8 *)(* p_argv);
+	      break;
+
+	    case FFI_TYPE_SINT16:
+	      *(signed long long *) argp = *(SINT16 *)(* p_argv);
+	      break;
+
+	    case FFI_TYPE_UINT16:
+	      *(unsigned long long *) argp = *(UINT16 *)(* p_argv);
+	      break;
+
+	    case FFI_TYPE_SINT32:
+	      *(signed long long *) argp = *(SINT32 *)(* p_argv);
+	      break;
+
+	    case FFI_TYPE_UINT32:
+	      *(unsigned long long *) argp = *(UINT32 *)(* p_argv);
+	      break;
+
+	    case FFI_TYPE_FLOAT:
+	      *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */
+	      break;
+
+	    case FFI_TYPE_STRUCT:
+	      memcpy(argp, *p_argv, z);
+	      break;
+
+	    default:
+	      FFI_ASSERT(0);
+	    }
+	  z = sizeof(long long);
+	  tmp++;
+	}
+      else if (z == sizeof(long long))
+	{
+	  memcpy(argp, *p_argv, z);
+	  z = sizeof(long long);
+	  tmp++;
+	}
+      else
+	{
+	  if ((tmp & 1) && (*p_arg)->alignment > 8)
+	    {
+	      tmp++;
+	      argp += sizeof(long long);
+	    }
+	  memcpy(argp, *p_argv, z);
+	  z = 2 * sizeof(long long);
+	  tmp += 2;
+	}
+      p_argv++;
+      argp += z;
+    }
+
+  return ret;
+}
+
 /* Perform machine dependent cif processing */
 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
 {
-  /* If we are returning a struct, this will already have been added.
-     Otherwise we need to add it because it's always got to be there! */
+  int wordsize;
+
+  if (cif->abi != FFI_V9)
+    {
+      wordsize = 4;
 
-  if (cif->rtype->type != FFI_TYPE_STRUCT)
-    cif->bytes += sizeof(void*);
+      /* If we are returning a struct, this will already have been added.
+	 Otherwise we need to add it because it's always got to be there! */
 
-  /* sparc call frames require that space is allocated for 6 args,
-     even if they aren't used. Make that space if necessary. */
+      if (cif->rtype->type != FFI_TYPE_STRUCT)
+	cif->bytes += wordsize;
+
+      /* sparc call frames require that space is allocated for 6 args,
+	 even if they aren't used. Make that space if necessary. */
   
-  if (cif->bytes < 4*6+4)
-    cif->bytes = 4*6+4;
+      if (cif->bytes < 4*6+4)
+	cif->bytes = 4*6+4;
+    }
+  else
+    {
+      wordsize = 8;
+
+      /* sparc call frames require that space is allocated for 6 args,
+	 even if they aren't used. Make that space if necessary. */
+  
+      if (cif->bytes < 8*6)
+	cif->bytes = 8*6;
+    }
 
   /* Adjust cif->bytes. to include 16 words for the window save area,
      and maybe the struct/union return pointer area, */
 
-  cif->bytes += 64;
+  cif->bytes += 16 * wordsize;
 
-  /* The stack must be double word aligned, so round bytes up
+  /* The stack must be 2 word aligned, so round bytes up
      appropriately. */
 
-  cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
+  cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
 
   /* Set the return type flag */
   switch (cif->rtype->type)
     {
     case FFI_TYPE_VOID:
-    case FFI_TYPE_STRUCT:
-      cif->flags = cif->rtype->type;
-      break;
-
     case FFI_TYPE_FLOAT:
-      cif->flags = FFI_TYPE_FLOAT;
+    case FFI_TYPE_DOUBLE:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+    case FFI_TYPE_LONGDOUBLE:
+#endif
+      cif->flags = cif->rtype->type;
       break;
 
-    case FFI_TYPE_DOUBLE:
-      cif->flags = FFI_TYPE_DOUBLE;
+    case FFI_TYPE_STRUCT:
+      if (cif->abi == FFI_V9 && cif->rtype->size > 32)
+	cif->flags = FFI_TYPE_VOID;
+      else
+	cif->flags = FFI_TYPE_STRUCT;
       break;
 
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_UINT64:
+      if (cif->abi != FFI_V9)
+	{
+	  cif->flags = FFI_TYPE_SINT64;
+	  break;
+	}
+      /* FALLTHROUGH */
     default:
       cif->flags = FFI_TYPE_INT;
       break;
     }
-
   return FFI_OK;
 }
 
+int ffi_V9_return_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
+{
+  ffi_type **ptr = &arg->elements[0];
+
+  while (*ptr != NULL)
+    {
+      if (off & ((*ptr)->alignment - 1))
+	off = ALIGN(off, (*ptr)->alignment);
+
+      switch ((*ptr)->type)
+	{
+	case FFI_TYPE_STRUCT:
+	  off = ffi_V9_return_struct(*ptr, off, ret, intg, flt);
+	  break;
+	case FFI_TYPE_FLOAT:
+	case FFI_TYPE_DOUBLE:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+	case FFI_TYPE_LONGDOUBLE:
+#endif
+	  memcpy(ret + off, flt + off, (*ptr)->size);
+	  off += (*ptr)->size;
+	  break;
+	default:
+	  memcpy(ret + off, intg + off, (*ptr)->size);
+	  off += (*ptr)->size;
+	  break;
+	}
+      ptr++;
+    }
+  return off;
+}
+
 extern int ffi_call_V8(void *, extended_cif *, unsigned, 
 		       unsigned, unsigned *, void (*fn)());
+extern int ffi_call_V9(void *, extended_cif *, unsigned, 
+		       unsigned, unsigned *, void (*fn)());
 
 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
 {
   extended_cif ecif;
+  void *rval = rvalue;
 
   ecif.cif = cif;
   ecif.avalue = avalue;
-  
+
   /* If the return value is a struct and we don't have a return	*/
   /* value address then we need to make one		        */
-  
-  if ((rvalue == NULL) && 
-      (cif->rtype->type == FFI_TYPE_STRUCT))
-    ecif.rvalue = alloca(cif->rtype->size);
-  else
-    ecif.rvalue = rvalue;
-    
+
+  ecif.rvalue = rvalue;
+  if (cif->rtype->type == FFI_TYPE_STRUCT)
+    {
+      if (cif->rtype->size <= 32)
+	rval = alloca(64);
+      else
+	{
+	  rval = NULL;
+	  if (rvalue == NULL)
+	    ecif.rvalue = alloca(cif->rtype->size);
+	}
+    }
+
   switch (cif->abi) 
     {
     case FFI_V8:
-      ffi_call_V8(ffi_prep_args, &ecif, cif->bytes, 
+#ifdef SPARC64
+      /* We don't yet support calling 32bit code from 64bit */
+      FFI_ASSERT(0);
+#else
+      ffi_call_V8(ffi_prep_args_v8, &ecif, cif->bytes, 
 		  cif->flags, rvalue, fn);
+#endif
+      break;
+    case FFI_V9:
+#ifdef SPARC64
+      ffi_call_V9(ffi_prep_args_v9, &ecif, cif->bytes,
+		  cif->flags, rval, fn);
+      if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
+	ffi_V9_return_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
+#else
+      /* And vice versa */
+      FFI_ASSERT(0);
+#endif
       break;
     default:
       FFI_ASSERT(0);
       break;
     }
+
 }
diff --git a/libffi/src/sparc/v8.S b/libffi/src/sparc/v8.S
index da0dbe694b4c..e4b2ba96a6cc 100644
--- a/libffi/src/sparc/v8.S
+++ b/libffi/src/sparc/v8.S
@@ -56,6 +56,7 @@ _ffi_call_V8:
 	ld	[%l0+ARGS+20], %o5
 	call	%i5
 	mov	%l0, %sp	! (delay) switch to frame
+	nop			! STRUCT returning functions skip 12 instead of 8 bytes
 
 	! If the return value pointer is NULL, assume no return value.
 	tst	%i4
@@ -70,6 +71,9 @@ _ffi_call_V8:
 	be,a	done
 	st	%f0, [%i4+0]	! (delay)
 
+	cmp	%i3, FFI_TYPE_SINT64
+	be	longlong
+
 	cmp	%i3, FFI_TYPE_DOUBLE
 	bne	done
 	nop
@@ -80,6 +84,12 @@ done:
 	ret
 	restore
 
+longlong:
+	st	%o0, [%i4+0]
+	st	%o1, [%i4+4]
+	ret
+	restore
+
 .ffi_call_V8_end:
         .size    ffi_call_V8,.ffi_call_V8_end-ffi_call_V8
 
diff --git a/libffi/src/sparc/v9.S b/libffi/src/sparc/v9.S
new file mode 100644
index 000000000000..38494344dbb1
--- /dev/null
+++ b/libffi/src/sparc/v9.S
@@ -0,0 +1,127 @@
+/* -----------------------------------------------------------------------
+   v9.S - Copyright (c) 2000 Cygnus Solutions
+   
+   Sparc 64bit Foreign Function Interface 
+
+   $Id:$
+
+   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 CYGNUS SOLUTIONS 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 SPARC64
+/* Only compile this in for 64bit builds, because otherwise the object file
+   will have inproper architecture due to used instructions.  */
+
+#define STACKFRAME 128		/* Minimum stack framesize for SPARC */
+#define STACK_BIAS 2047
+#define ARGS (128)		/* Offset of register area in frame */
+
+.text
+        .align 8
+.globl ffi_call_V9
+.globl _ffi_call_V9
+
+ffi_call_V9:
+_ffi_call_V9:
+	save	%sp, -STACKFRAME, %sp
+	
+	sub	%sp, %i2, %sp	! alloca() space in stack for frame to set up
+	add	%sp, STACKFRAME+STACK_BIAS, %l0	! %l0 has start of 
+						! frame to set up
+
+	mov	%l0, %o0	! call routine to set up frame
+	call	%i0
+	 mov	%i1, %o1	! (delay)
+	brz,pt	%o0, 1f
+	 ldx	[%l0+ARGS], %o0	! call foreign function
+
+	ldd	[%l0+ARGS], %f0
+	ldd	[%l0+ARGS+8], %f2
+	ldd	[%l0+ARGS+16], %f4
+	ldd	[%l0+ARGS+24], %f6
+	ldd	[%l0+ARGS+32], %f8
+	ldd	[%l0+ARGS+40], %f10
+	ldd	[%l0+ARGS+48], %f12
+	ldd	[%l0+ARGS+56], %f14
+	ldd	[%l0+ARGS+64], %f16
+	ldd	[%l0+ARGS+72], %f18
+	ldd	[%l0+ARGS+80], %f20
+	ldd	[%l0+ARGS+88], %f22
+	ldd	[%l0+ARGS+96], %f24
+	ldd	[%l0+ARGS+104], %f26
+	ldd	[%l0+ARGS+112], %f28
+	ldd	[%l0+ARGS+120], %f30
+
+1:	ldx	[%l0+ARGS+8], %o1
+	ldx	[%l0+ARGS+16], %o2
+	ldx	[%l0+ARGS+24], %o3
+	ldx	[%l0+ARGS+32], %o4
+	ldx	[%l0+ARGS+40], %o5
+	call	%i5
+	 sub	%l0, STACK_BIAS, %sp	! (delay) switch to frame
+
+	! If the return value pointer is NULL, assume no return value.
+	brz,pn	%i4, done
+	 nop
+
+	cmp	%i3, FFI_TYPE_INT
+	be,a,pt	%icc, done
+	 stx	%o0, [%i4]	! (delay)
+
+	cmp	%i3, FFI_TYPE_FLOAT
+	be,a,pn	%icc, done
+	 st	%f0, [%i4+0]	! (delay)
+
+	cmp	%i3, FFI_TYPE_DOUBLE
+	be,a,pn	%icc, done
+	 std	%f0, [%i4+0]	! (delay)
+
+	cmp	%i3, FFI_TYPE_STRUCT
+	be,pn	%icc, dostruct
+
+	 cmp	%i3, FFI_TYPE_LONGDOUBLE
+	bne,pt	%icc, done
+	 nop
+	std	%f0, [%i4+0]
+	std	%f2, [%i4+8]
+
+done:	ret
+	 restore
+
+dostruct:
+	/* This will not work correctly for unions. */
+	stx	%o0, [%i4+0]
+	stx	%o1, [%i4+8]
+	stx	%o2, [%i4+16]
+	stx	%o3, [%i4+24]
+	std	%f0, [%i4+32]
+	std	%f2, [%i4+40]
+	std	%f4, [%i4+48]
+	std	%f6, [%i4+56]
+	ret
+	 restore
+
+.ffi_call_V9_end:
+        .size    ffi_call_V9,.ffi_call_V9_end-ffi_call_V9
+
+#endif
diff --git a/libffi/src/types.c b/libffi/src/types.c
index abf276d5cdde..43aab913130b 100644
--- a/libffi/src/types.c
+++ b/libffi/src/types.c
@@ -42,9 +42,17 @@ FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16);
 FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16);
 FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32);
 FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32);
-FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER);
 FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT);
 
+#if defined ALPHA || defined SPARC64
+
+FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER);
+
+#else
+
+FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER);
+
+#endif
 
 #ifdef X86
 
@@ -87,8 +95,17 @@ FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE);
 #elif defined SPARC
 
 FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
+
+#ifdef SPARC64
+
+FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
+
+#else
+
 FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE);
 
+#endif
+
 #else
 
 FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
-- 
GitLab