From 399558e5a99db58839e2a9a8802f743d9631466a Mon Sep 17 00:00:00 2001
From: wuzx <wuzx1226@qq.com>
Date: Fri, 18 Nov 2022 12:04:50 +0800
Subject: [PATCH] Add sw64 architecture

Add sw64 architecture in file Makefile.am Makefile.in config.guess config.sub configure configure.host m4/ax_gcc_archflag.m4 src/sw_64/ffi.c src/sw_64/ffitarget.h src/sw_64/internal.h src/sw_64/osf.S src/types.c and testsuite/libffi.go/static-chain.h to support sw64 architecture.

Signed-off-by: wuzx <wuzx1226@qq.com>
---
 Makefile.am                        |   2 +
 Makefile.in                        |  24 ++
 config.guess                       |   9 +
 config.sub                         |   1 +
 configure                          |   2 +-
 configure.host                     |   6 +
 m4/ax_gcc_archflag.m4              |   2 +-
 src/sw_64/ffi.c                    | 521 +++++++++++++++++++++++++++++
 src/sw_64/ffitarget.h              |  57 ++++
 src/sw_64/internal.h               |  23 ++
 src/sw_64/osf.S                    | 282 ++++++++++++++++
 src/types.c                        |   4 +-
 testsuite/libffi.go/static-chain.h |   2 +
 13 files changed, 931 insertions(+), 4 deletions(-)
 create mode 100644 src/sw_64/ffi.c
 create mode 100644 src/sw_64/ffitarget.h
 create mode 100644 src/sw_64/internal.h
 create mode 100644 src/sw_64/osf.S

diff --git a/Makefile.am b/Makefile.am
index 1b18198..e29722f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -47,6 +47,7 @@ endif
 
 noinst_HEADERS = src/aarch64/ffitarget.h src/aarch64/internal.h		\
 	src/alpha/ffitarget.h src/alpha/internal.h			\
+	src/sw_64/ffitarget.h src/sw_64/internal.h			\
 	src/arc/ffitarget.h src/arm/ffitarget.h src/arm/internal.h	\
 	src/avr32/ffitarget.h src/bfin/ffitarget.h			\
 	src/cris/ffitarget.h src/csky/ffitarget.h src/frv/ffitarget.h	\
@@ -67,6 +68,7 @@ noinst_HEADERS = src/aarch64/ffitarget.h src/aarch64/internal.h		\
 
 EXTRA_libffi_la_SOURCES = src/aarch64/ffi.c src/aarch64/sysv.S		\
 	src/aarch64/win64_armasm.S src/alpha/ffi.c src/alpha/osf.S	\
+	src/sw_64/ffi.c src/sw_64/osf.S
 	src/arc/ffi.c src/arc/arcompact.S src/arm/ffi.c			\
 	src/arm/sysv.S src/arm/ffi.c src/arm/sysv_msvc_arm32.S		\
 	src/avr32/ffi.c src/avr32/sysv.S src/bfin/ffi.c			\
diff --git a/Makefile.in b/Makefile.in
index a4b67a7..b4eddc2 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -202,6 +202,7 @@ am__depfiles_remade = src/$(DEPDIR)/closures.Plo \
 	src/aarch64/$(DEPDIR)/ffi.Plo src/aarch64/$(DEPDIR)/sysv.Plo \
 	src/aarch64/$(DEPDIR)/win64_armasm.Plo \
 	src/alpha/$(DEPDIR)/ffi.Plo src/alpha/$(DEPDIR)/osf.Plo \
+	src/sw_64/$(DEPDIR)/ffi.Plo src/sw_64/$(DEPDIR)/osf.Plo \
 	src/arc/$(DEPDIR)/arcompact.Plo src/arc/$(DEPDIR)/ffi.Plo \
 	src/arm/$(DEPDIR)/ffi.Plo src/arm/$(DEPDIR)/sysv.Plo \
 	src/arm/$(DEPDIR)/sysv_msvc_arm32.Plo \
@@ -548,6 +549,7 @@ libffi_la_SOURCES = src/prep_cif.c src/types.c src/raw_api.c \
 	src/java_raw_api.c src/closures.c src/tramp.c $(am__append_2)
 noinst_HEADERS = src/aarch64/ffitarget.h src/aarch64/internal.h		\
 	src/alpha/ffitarget.h src/alpha/internal.h			\
+	src/sw_64/ffitarget.h src/sw_64/internal.h			\
 	src/arc/ffitarget.h src/arm/ffitarget.h src/arm/internal.h	\
 	src/avr32/ffitarget.h src/bfin/ffitarget.h			\
 	src/cris/ffitarget.h src/csky/ffitarget.h src/frv/ffitarget.h	\
@@ -568,6 +570,7 @@ noinst_HEADERS = src/aarch64/ffitarget.h src/aarch64/internal.h		\
 
 EXTRA_libffi_la_SOURCES = src/aarch64/ffi.c src/aarch64/sysv.S		\
 	src/aarch64/win64_armasm.S src/alpha/ffi.c src/alpha/osf.S	\
+	src/sw_64/ffi.c src/sw_64/osf.S	\
 	src/arc/ffi.c src/arc/arcompact.S src/arm/ffi.c			\
 	src/arm/sysv.S src/arm/ffi.c src/arm/sysv_msvc_arm32.S		\
 	src/avr32/ffi.c src/avr32/sysv.S src/bfin/ffi.c			\
@@ -751,6 +754,16 @@ src/alpha/ffi.lo: src/alpha/$(am__dirstamp) \
 	src/alpha/$(DEPDIR)/$(am__dirstamp)
 src/alpha/osf.lo: src/alpha/$(am__dirstamp) \
 	src/alpha/$(DEPDIR)/$(am__dirstamp)
+src/sw_64/$(am__dirstamp):
+	@$(MKDIR_P) src/sw_64
+	@: > src/sw_64/$(am__dirstamp)
+src/sw_64/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) src/sw_64/$(DEPDIR)
+	@: > src/sw_64/$(DEPDIR)/$(am__dirstamp)
+src/sw_64/ffi.lo: src/sw_64/$(am__dirstamp) \
+	src/sw_64/$(DEPDIR)/$(am__dirstamp)
+src/sw_64/osf.lo: src/sw_64/$(am__dirstamp) \
+	src/sw_64/$(DEPDIR)/$(am__dirstamp)
 src/arc/$(am__dirstamp):
 	@$(MKDIR_P) src/arc
 	@: > src/arc/$(am__dirstamp)
@@ -1096,6 +1109,8 @@ mostlyclean-compile:
 	-rm -f src/aarch64/*.lo
 	-rm -f src/alpha/*.$(OBJEXT)
 	-rm -f src/alpha/*.lo
+	-rm -f src/sw_64/*.$(OBJEXT)
+	-rm -f src/sw_64/*.lo
 	-rm -f src/arc/*.$(OBJEXT)
 	-rm -f src/arc/*.lo
 	-rm -f src/arm/*.$(OBJEXT)
@@ -1168,6 +1183,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@src/aarch64/$(DEPDIR)/ffi.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@src/aarch64/$(DEPDIR)/sysv.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@src/aarch64/$(DEPDIR)/win64_armasm.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@src/sw_64/$(DEPDIR)/ffi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@src/sw_64/$(DEPDIR)/osf.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@src/alpha/$(DEPDIR)/ffi.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@src/alpha/$(DEPDIR)/osf.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@src/arc/$(DEPDIR)/arcompact.Plo@am__quote@ # am--include-marker
@@ -1311,6 +1328,7 @@ clean-libtool:
 	-rm -rf .libs _libs
 	-rm -rf src/.libs src/_libs
 	-rm -rf src/aarch64/.libs src/aarch64/_libs
+	-rm -rf src/sw_64/.libs src/sw_64/_libs
 	-rm -rf src/alpha/.libs src/alpha/_libs
 	-rm -rf src/arc/.libs src/arc/_libs
 	-rm -rf src/arm/.libs src/arm/_libs
@@ -1710,6 +1728,8 @@ distclean-generic:
 	-rm -f src/$(am__dirstamp)
 	-rm -f src/aarch64/$(DEPDIR)/$(am__dirstamp)
 	-rm -f src/aarch64/$(am__dirstamp)
+	-rm -f src/sw_64/$(DEPDIR)/$(am__dirstamp)
+	-rm -f src/sw_64/$(am__dirstamp)
 	-rm -f src/alpha/$(DEPDIR)/$(am__dirstamp)
 	-rm -f src/alpha/$(am__dirstamp)
 	-rm -f src/arc/$(DEPDIR)/$(am__dirstamp)
@@ -1792,6 +1812,8 @@ distclean: distclean-recursive
 	-rm -f src/aarch64/$(DEPDIR)/ffi.Plo
 	-rm -f src/aarch64/$(DEPDIR)/sysv.Plo
 	-rm -f src/aarch64/$(DEPDIR)/win64_armasm.Plo
+	-rm -f src/sw_64/$(DEPDIR)/ffi.Plo
+	-rm -f src/sw_64/$(DEPDIR)/osf.Plo
 	-rm -f src/alpha/$(DEPDIR)/ffi.Plo
 	-rm -f src/alpha/$(DEPDIR)/osf.Plo
 	-rm -f src/arc/$(DEPDIR)/arcompact.Plo
@@ -1930,6 +1952,8 @@ maintainer-clean: maintainer-clean-recursive
 	-rm -f src/aarch64/$(DEPDIR)/ffi.Plo
 	-rm -f src/aarch64/$(DEPDIR)/sysv.Plo
 	-rm -f src/aarch64/$(DEPDIR)/win64_armasm.Plo
+	-rm -f src/sw_64/$(DEPDIR)/ffi.Plo
+	-rm -f src/sw_64/$(DEPDIR)/osf.Plo
 	-rm -f src/alpha/$(DEPDIR)/ffi.Plo
 	-rm -f src/alpha/$(DEPDIR)/osf.Plo
 	-rm -f src/arc/$(DEPDIR)/arcompact.Plo
diff --git a/config.guess b/config.guess
index e94095c..01a1ef3 100644
--- a/config.guess
+++ b/config.guess
@@ -925,6 +925,15 @@ EOF
 	UNAME_MACHINE=aarch64_be
 	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
+    sw_64:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+          sw)   UNAME_MACHINE=sw_64 ;;
+	esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+	echo ${UNAME_MACHINE}-sunway-linux-${LIBC}
+	exit ;;
+
     alpha:Linux:*:*)
 	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in
 	  EV5)   UNAME_MACHINE=alphaev5 ;;
diff --git a/config.sub b/config.sub
index 14b5150..bbb4efe 100644
--- a/config.sub
+++ b/config.sub
@@ -1158,6 +1158,7 @@ case $cpu-$vendor in
 		case $cpu in
 			1750a | 580 \
 			| a29k \
+			| sw_64 \
 			| aarch64 | aarch64_be \
 			| abacus \
 			| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
diff --git a/configure b/configure
index 94e149c..f911a05 100755
--- a/configure
+++ b/configure
@@ -17216,7 +17216,7 @@ fi
          *hypersparc*|*rt62[056]*) ax_gcc_arch="hypersparc v8" ;;
          *cypress*) ax_gcc_arch=cypress ;;
      esac ;;
-
+  sw_64*) ax_gcc_arch=sw6b ;;
   alphaev5) ax_gcc_arch=ev5 ;;
   alphaev56) ax_gcc_arch=ev56 ;;
   alphapca56) ax_gcc_arch="pca56 ev56" ;;
diff --git a/configure.host b/configure.host
index 2682671..372e20b 100644
--- a/configure.host
+++ b/configure.host
@@ -24,6 +24,12 @@ case "${host}" in
 	HAVE_LONG_DOUBLE='defined(__LONG_DOUBLE_128__)'
 	SOURCES="ffi.c osf.S"
 	;;
+  sw_64*-*-*)
+	TARGET=SW_64; TARGETDIR=sw_64;
+	# Support 128-bit long double, changeable via command-line switch.
+	HAVE_LONG_DOUBLE='defined(__LONG_DOUBLE_128__)'
+	SOURCES="ffi.c osf.S"
+	;;
 
   arc*-*-*)
 	TARGET=ARC; TARGETDIR=arc
diff --git a/m4/ax_gcc_archflag.m4 b/m4/ax_gcc_archflag.m4
index c52b9b2..de17232 100644
--- a/m4/ax_gcc_archflag.m4
+++ b/m4/ax_gcc_archflag.m4
@@ -174,7 +174,7 @@ case $host_cpu in
          *hypersparc*|*rt62[[056]]*) ax_gcc_arch="hypersparc v8" ;;
          *cypress*) ax_gcc_arch=cypress ;;
      esac ;;
-
+  sw_64*) ax_gcc_arch=sw6b ;;
   alphaev5) ax_gcc_arch=ev5 ;;
   alphaev56) ax_gcc_arch=ev56 ;;
   alphapca56) ax_gcc_arch="pca56 ev56" ;;
diff --git a/src/sw_64/ffi.c b/src/sw_64/ffi.c
new file mode 100644
index 0000000..d99668f
--- /dev/null
+++ b/src/sw_64/ffi.c
@@ -0,0 +1,521 @@
+/* -----------------------------------------------------------------------
+   ffi.c - Copyright (c) 2012  Anthony Green
+	   Copyright (c) 1998, 2001, 2007, 2008  Red Hat, Inc.
+
+   Alpha Foreign Function Interface
+
+   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 AUTHORS OR COPYRIGHT
+   HOLDERS 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.
+   ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+#include <stdlib.h>
+#include "internal.h"
+
+/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
+   all further uses in this file will refer to the 128-bit type.  */
+#if defined(__LONG_DOUBLE_128__)
+# if FFI_TYPE_LONGDOUBLE != 4
+#  error FFI_TYPE_LONGDOUBLE out of date
+# endif
+#else
+# undef FFI_TYPE_LONGDOUBLE
+# define FFI_TYPE_LONGDOUBLE 4
+#endif
+
+extern void ffi_call_osf(void *stack, void *frame, unsigned flags,
+			 void *raddr, void (*fn)(void), void *closure)
+	FFI_HIDDEN;
+extern void ffi_closure_osf(void) FFI_HIDDEN;
+extern void ffi_go_closure_osf(void) FFI_HIDDEN;
+
+/* Promote a float value to its in-register double representation.
+   Unlike actually casting to double, this does not trap on NaN.  */
+static inline UINT64 lds(void *ptr)
+{
+  UINT64 ret;
+  asm("flds %0,%1" : "=f"(ret) : "m"(*(UINT32 *)ptr));
+  return ret;
+}
+
+/* And the reverse.  */
+static inline void sts(void *ptr, UINT64 val)
+{
+  asm("fsts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val));
+}
+
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+  size_t bytes = 0;
+  int flags, i, avn;
+  ffi_type *rtype, *itype;
+
+  if (cif->abi != FFI_OSF)
+    return FFI_BAD_ABI;
+
+  /* Compute the size of the argument area.  */
+  for (i = 0, avn = cif->nargs; i < avn; i++)
+    {
+      itype = cif->arg_types[i];
+      switch (itype->type)
+	{
+	case FFI_TYPE_INT:
+	case FFI_TYPE_SINT8:
+	case FFI_TYPE_UINT8:
+	case FFI_TYPE_SINT16:
+	case FFI_TYPE_UINT16:
+	case FFI_TYPE_SINT32:
+	case FFI_TYPE_UINT32:
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_POINTER:
+	case FFI_TYPE_FLOAT:
+	case FFI_TYPE_DOUBLE:
+	case FFI_TYPE_LONGDOUBLE:
+	  /* All take one 8 byte slot.  */
+	  bytes += 8;
+	  break;
+
+	case FFI_TYPE_VOID:
+	case FFI_TYPE_STRUCT:
+	  /* Passed by value in N slots.  */
+	  bytes += FFI_ALIGN(itype->size, FFI_SIZEOF_ARG);
+	  break;
+
+	case FFI_TYPE_COMPLEX:
+	  /* _Complex long double passed by reference; others in 2 slots.  */
+	  if (itype->elements[0]->type == FFI_TYPE_LONGDOUBLE)
+	    bytes += 8;
+	  else
+	    bytes += 16;
+	  break;
+
+	default:
+	  abort();
+	}
+    }
+
+  /* Set the return type flag */
+  rtype = cif->rtype;
+  switch (rtype->type)
+    {
+    case FFI_TYPE_VOID:
+      flags = SW_64_FLAGS(SW_64_ST_VOID, SW_64_LD_VOID);
+      break;
+    case FFI_TYPE_INT:
+    case FFI_TYPE_UINT32:
+    case FFI_TYPE_SINT32:
+      flags = SW_64_FLAGS(SW_64_ST_INT, SW_64_LD_INT32);
+      break;
+    case FFI_TYPE_FLOAT:
+      flags = SW_64_FLAGS(SW_64_ST_FLOAT, SW_64_LD_FLOAT);
+      break;
+    case FFI_TYPE_DOUBLE:
+      flags = SW_64_FLAGS(SW_64_ST_DOUBLE, SW_64_LD_DOUBLE);
+      break;
+    case FFI_TYPE_UINT8:
+      flags = SW_64_FLAGS(SW_64_ST_INT, SW_64_LD_UINT8);
+      break;
+    case FFI_TYPE_SINT8:
+      flags = SW_64_FLAGS(SW_64_ST_INT, SW_64_LD_SINT8);
+      break;
+    case FFI_TYPE_UINT16:
+      flags = SW_64_FLAGS(SW_64_ST_INT, SW_64_LD_UINT16);
+      break;
+    case FFI_TYPE_SINT16:
+      flags = SW_64_FLAGS(SW_64_ST_INT, SW_64_LD_SINT16);
+      break;
+    case FFI_TYPE_UINT64:
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_POINTER:
+      flags = SW_64_FLAGS(SW_64_ST_INT, SW_64_LD_INT64);
+      break;
+    case FFI_TYPE_LONGDOUBLE:
+    case FFI_TYPE_STRUCT:
+      /* Passed in memory, with a hidden pointer.  */
+      flags = SW_64_RET_IN_MEM;
+      break;
+    case FFI_TYPE_COMPLEX:
+      itype = rtype->elements[0];
+      switch (itype->type)
+	{
+	case FFI_TYPE_FLOAT:
+	  flags = SW_64_FLAGS(SW_64_ST_CPLXF, SW_64_LD_CPLXF);
+	  break;
+	case FFI_TYPE_DOUBLE:
+	  flags = SW_64_FLAGS(SW_64_ST_CPLXD, SW_64_LD_CPLXD);
+	  break;
+	default:
+	  if (rtype->size <= 8)
+	    flags = SW_64_FLAGS(SW_64_ST_INT, SW_64_LD_INT64);
+	  else
+	    flags = SW_64_RET_IN_MEM;
+	  break;
+	}
+      break;
+    default:
+      abort();
+    }
+  cif->flags = flags;
+
+  /* Include the hidden structure pointer in args requirement.  */
+  if (flags == SW_64_RET_IN_MEM)
+    bytes += 8;
+  /* Minimum size is 6 slots, so that ffi_call_osf can pop them.  */
+  if (bytes < 6*8)
+    bytes = 6*8;
+  cif->bytes = bytes;
+
+  return FFI_OK;
+}
+
+static unsigned long
+extend_basic_type(void *valp, int type, int argn)
+{
+  switch (type)
+    {
+    case FFI_TYPE_SINT8:
+      return *(SINT8 *)valp;
+    case FFI_TYPE_UINT8:
+      return *(UINT8 *)valp;
+    case FFI_TYPE_SINT16:
+      return *(SINT16 *)valp;
+    case FFI_TYPE_UINT16:
+      return *(UINT16 *)valp;
+
+    case FFI_TYPE_FLOAT:
+      if (argn < 6)
+	return lds(valp);
+      /* FALLTHRU */
+
+    case FFI_TYPE_INT:
+    case FFI_TYPE_SINT32:
+    case FFI_TYPE_UINT32:
+      /* Note that unsigned 32-bit quantities are sign extended.  */
+      return *(SINT32 *)valp;
+
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_UINT64:
+    case FFI_TYPE_POINTER:
+    case FFI_TYPE_DOUBLE:
+      return *(UINT64 *)valp;
+
+    default:
+      abort();
+    }
+}
+
+static void
+ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
+	      void **avalue, void *closure)
+{
+  unsigned long *argp;
+  long i, avn, argn, flags = cif->flags;
+  ffi_type **arg_types;
+  void *frame;
+
+  /* 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 && flags == SW_64_RET_IN_MEM)
+    rvalue = alloca(cif->rtype->size);
+
+  /* Allocate the space for the arguments, plus 4 words of temp
+     space for ffi_call_osf.  */
+  argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
+  frame += cif->bytes;
+
+  argn = 0;
+  if (flags == SW_64_RET_IN_MEM)
+    argp[argn++] = (unsigned long)rvalue;
+
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+
+  for (i = 0, avn = cif->nargs; i < avn; i++)
+    {
+      ffi_type *ty = arg_types[i];
+      void *valp = avalue[i];
+      int type = ty->type;
+      size_t size;
+
+      switch (type)
+	{
+	case FFI_TYPE_INT:
+	case FFI_TYPE_SINT8:
+	case FFI_TYPE_UINT8:
+	case FFI_TYPE_SINT16:
+	case FFI_TYPE_UINT16:
+	case FFI_TYPE_SINT32:
+	case FFI_TYPE_UINT32:
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_POINTER:
+	case FFI_TYPE_FLOAT:
+	case FFI_TYPE_DOUBLE:
+	  argp[argn] = extend_basic_type(valp, type, argn);
+	  argn++;
+	  break;
+
+	case FFI_TYPE_LONGDOUBLE:
+	by_reference:
+	  /* Note that 128-bit long double is passed by reference.  */
+	  argp[argn++] = (unsigned long)valp;
+	  break;
+
+	case FFI_TYPE_VOID:
+	case FFI_TYPE_STRUCT:
+	  size = ty->size;
+	  memcpy(argp + argn, valp, size);
+	  argn += FFI_ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+	  break;
+
+	case FFI_TYPE_COMPLEX:
+	  type = ty->elements[0]->type;
+	  if (type == FFI_TYPE_LONGDOUBLE)
+	    goto by_reference;
+
+	  /* Most complex types passed as two separate arguments.  */
+	  size = ty->elements[0]->size;
+	  argp[argn] = extend_basic_type(valp, type, argn);
+	  argp[argn + 1] = extend_basic_type(valp + size, type, argn + 1);
+	  argn += 2;
+	  break;
+
+	default:
+	  abort();
+	}
+    }
+
+  flags = (flags >> SW_64_ST_SHIFT) & 0xff;
+  ffi_call_osf(argp, frame, flags, rvalue, fn, closure);
+}
+
+void
+ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+  ffi_call_int(cif, fn, rvalue, avalue, NULL);
+}
+
+void
+ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+	     void **avalue, void *closure)
+{
+  ffi_call_int(cif, fn, rvalue, avalue, closure);
+}
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure* closure,
+		      ffi_cif* cif,
+		      void (*fun)(ffi_cif*, void*, void**, void*),
+		      void *user_data,
+		      void *codeloc)
+{
+  unsigned int *tramp;
+
+  if (cif->abi != FFI_OSF)
+    return FFI_BAD_ABI;
+
+  tramp = (unsigned int *) &closure->tramp[0];
+  tramp[0] = 0x43fb0741;	/* mov $27,$1		*/
+  tramp[1] = 0x8f7b0010;	/* ldq $27,16($27)	*/
+  tramp[2] = 0x0ffb0000;	/* jmp $31,($27),0	*/
+  tramp[3] = 0x43ff075f;	/* nop			*/
+  *(void **) &tramp[4] = ffi_closure_osf;
+
+  closure->cif = cif;
+  closure->fun = fun;
+  closure->user_data = user_data;
+
+  /* Flush the Icache.
+
+     Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal
+     instead, since both Compaq as and gas can handle it.
+
+     0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>.  */
+  asm volatile ("sys_call 0x86" : : : "memory");
+
+  return FFI_OK;
+}
+
+ffi_status
+ffi_prep_go_closure (ffi_go_closure* closure,
+		     ffi_cif* cif,
+		     void (*fun)(ffi_cif*, void*, void**, void*))
+{
+  if (cif->abi != FFI_OSF)
+    return FFI_BAD_ABI;
+
+  closure->tramp = (void *)ffi_go_closure_osf;
+  closure->cif = cif;
+  closure->fun = fun;
+
+  return FFI_OK;
+}
+
+long FFI_HIDDEN
+ffi_closure_osf_inner (ffi_cif *cif,
+		       void (*fun)(ffi_cif*, void*, void**, void*),
+		       void *user_data,
+		       void *rvalue, unsigned long *argp)
+{
+  void **avalue;
+  ffi_type **arg_types;
+  long i, avn, argn, flags;
+
+  avalue = alloca(cif->nargs * sizeof(void *));
+  flags = cif->flags;
+  argn = 0;
+
+  /* Copy the caller's structure return address to that the closure
+     returns the data directly to the caller.  */
+  if (flags == SW_64_RET_IN_MEM)
+    {
+      rvalue = (void *) argp[0];
+      argn = 1;
+    }
+
+  arg_types = cif->arg_types;
+
+  /* Grab the addresses of the arguments from the stack frame.  */
+  for (i = 0, avn = cif->nargs; i < avn; i++)
+    {
+      ffi_type *ty = arg_types[i];
+      int type = ty->type;
+      void *valp = &argp[argn];
+      size_t size;
+
+      switch (type)
+	{
+	case FFI_TYPE_INT:
+	case FFI_TYPE_SINT8:
+	case FFI_TYPE_UINT8:
+	case FFI_TYPE_SINT16:
+	case FFI_TYPE_UINT16:
+	case FFI_TYPE_SINT32:
+	case FFI_TYPE_UINT32:
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_POINTER:
+	  argn += 1;
+	  break;
+
+	case FFI_TYPE_VOID:
+	case FFI_TYPE_STRUCT:
+	  size = ty->size;
+	  argn += FFI_ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+	  break;
+
+	case FFI_TYPE_FLOAT:
+	  /* Floats coming from registers need conversion from double
+	     back to float format.  */
+	  if (argn < 6)
+	    {
+	      valp = &argp[argn - 6];
+	      sts(valp, argp[argn - 6]);
+	    }
+	  argn += 1;
+	  break;
+
+	case FFI_TYPE_DOUBLE:
+	  if (argn < 6)
+	    valp = &argp[argn - 6];
+	  argn += 1;
+	  break;
+
+	case FFI_TYPE_LONGDOUBLE:
+	by_reference:
+	  /* 128-bit long double is passed by reference.  */
+	  valp = (void *)argp[argn];
+	  argn += 1;
+	  break;
+
+	case FFI_TYPE_COMPLEX:
+	  type = ty->elements[0]->type;
+	  switch (type)
+	    {
+	    case FFI_TYPE_SINT64:
+	    case FFI_TYPE_UINT64:
+	      /* Passed as separate arguments, but they wind up sequential.  */
+	      break;
+
+	    case FFI_TYPE_INT:
+	    case FFI_TYPE_SINT8:
+	    case FFI_TYPE_UINT8:
+	    case FFI_TYPE_SINT16:
+	    case FFI_TYPE_UINT16:
+	    case FFI_TYPE_SINT32:
+	    case FFI_TYPE_UINT32:
+	      /* Passed as separate arguments.  Disjoint, but there's room
+		 enough in one slot to hold the pair.  */
+	      size = ty->elements[0]->size;
+	      memcpy(valp + size, valp + 8, size);
+	      break;
+
+	    case FFI_TYPE_FLOAT:
+	      /* Passed as separate arguments.  Disjoint, and each piece
+		 may need conversion back to float.  */
+	      if (argn < 6)
+		{
+		  valp = &argp[argn - 6];
+		  sts(valp, argp[argn - 6]);
+		}
+	      if (argn + 1 < 6)
+		sts(valp + 4, argp[argn + 1 - 6]);
+	      else
+		*(UINT32 *)(valp + 4) = argp[argn + 1];
+	      break;
+
+	    case FFI_TYPE_DOUBLE:
+	      /* Passed as separate arguments.  Only disjoint if one part
+		 is in fp regs and the other is on the stack.  */
+	      if (argn < 5)
+		valp = &argp[argn - 6];
+	      else if (argn == 5)
+		{
+		  valp = alloca(16);
+		  ((UINT64 *)valp)[0] = argp[5 - 6];
+		  ((UINT64 *)valp)[1] = argp[6];
+		}
+	      break;
+
+	    case FFI_TYPE_LONGDOUBLE:
+	      goto by_reference;
+
+	    default:
+	      abort();
+	    }
+	  argn += 2;
+	  break;
+
+	default:
+	  abort ();
+	}
+
+      avalue[i] = valp;
+    }
+
+  /* Invoke the closure.  */
+  fun (cif, rvalue, avalue, user_data);
+
+  /* Tell ffi_closure_osf how to perform return type promotions.  */
+  return (flags >> SW_64_LD_SHIFT) & 0xff;
+}
diff --git a/src/sw_64/ffitarget.h b/src/sw_64/ffitarget.h
new file mode 100644
index 0000000..a02dbd0
--- /dev/null
+++ b/src/sw_64/ffitarget.h
@@ -0,0 +1,57 @@
+/* -----------------------------------------------------------------*-C-*-
+   ffitarget.h - Copyright (c) 2012  Anthony Green
+                 Copyright (c) 1996-2003  Red Hat, Inc.
+   Target configuration macros for Alpha.
+
+   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 AUTHORS OR COPYRIGHT
+   HOLDERS 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.
+
+   ----------------------------------------------------------------------- */
+
+#ifndef LIBFFI_TARGET_H
+#define LIBFFI_TARGET_H
+
+#ifndef LIBFFI_H
+#error "Please do not include ffitarget.h directly into your source.  Use ffi.h instead."
+#endif
+
+#ifndef LIBFFI_ASM
+typedef unsigned long          ffi_arg;
+typedef signed long            ffi_sarg;
+
+typedef enum ffi_abi {
+  FFI_FIRST_ABI = 0,
+  FFI_OSF,
+  FFI_LAST_ABI,
+  FFI_DEFAULT_ABI = FFI_OSF
+} ffi_abi;
+#endif
+
+#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
+#define FFI_TARGET_HAS_COMPLEX_TYPE
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_GO_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 24
+#define FFI_NATIVE_RAW_API 0
+
+#endif
diff --git a/src/sw_64/internal.h b/src/sw_64/internal.h
new file mode 100644
index 0000000..1866a8c
--- /dev/null
+++ b/src/sw_64/internal.h
@@ -0,0 +1,23 @@
+#define SW_64_ST_VOID	0
+#define SW_64_ST_INT	1
+#define SW_64_ST_FLOAT	2
+#define SW_64_ST_DOUBLE	3
+#define SW_64_ST_CPLXF	4
+#define SW_64_ST_CPLXD	5
+
+#define SW_64_LD_VOID	0
+#define SW_64_LD_INT64	1
+#define SW_64_LD_INT32	2
+#define SW_64_LD_UINT16	3
+#define SW_64_LD_SINT16	4
+#define SW_64_LD_UINT8	5
+#define SW_64_LD_SINT8	6
+#define SW_64_LD_FLOAT	7
+#define SW_64_LD_DOUBLE	8
+#define SW_64_LD_CPLXF	9
+#define SW_64_LD_CPLXD	10
+
+#define SW_64_ST_SHIFT		0
+#define SW_64_LD_SHIFT		8
+#define SW_64_RET_IN_MEM	0x10000
+#define SW_64_FLAGS(S, L)	(((L) << SW_64_LD_SHIFT) | (S))
diff --git a/src/sw_64/osf.S b/src/sw_64/osf.S
new file mode 100644
index 0000000..b4b58e5
--- /dev/null
+++ b/src/sw_64/osf.S
@@ -0,0 +1,282 @@
+/* -----------------------------------------------------------------------
+   osf.S - Copyright (c) 1998, 2001, 2007, 2008, 2011, 2014 Red Hat
+
+   SW_64/OSF Foreign Function Interface
+
+   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 AUTHORS OR COPYRIGHT
+   HOLDERS 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 <fficonfig.h>
+#include <ffi.h>
+#include <ffi_cfi.h>
+#include "internal.h"
+
+	.arch sw6b
+	.text
+
+/* Aid in building a direct addressed jump table, 4 insns per entry.  */
+.macro E index
+	.align	4
+	.org	99b + \index * 16
+.endm
+
+/* ffi_call_osf (void *stack, void *frame, unsigned flags,
+		 void *raddr, void (*fnaddr)(void), void *closure)
+
+   Bit o trickiness here -- FRAME is the base of the stack frame
+   for this function.  This has been allocated by ffi_call.  We also
+   deallocate some of the stack that has been alloca'd.  */
+
+	.align	4
+	.globl	ffi_call_osf
+	.ent	ffi_call_osf
+	FFI_HIDDEN(ffi_call_osf)
+
+ffi_call_osf:
+	cfi_startproc
+	cfi_def_cfa($17, 32)
+	mov	$16, $30
+	stl	$26, 0($17)
+	stl	$15, 8($17)
+	mov	$17, $15
+	.prologue 0
+	cfi_def_cfa_register($15)
+	cfi_rel_offset($26, 0)
+	cfi_rel_offset($15, 8)
+
+	stl	$18, 16($17)		# save flags into frame
+	stl	$19, 24($17)		# save rvalue into frame
+	mov	$20, $27		# fn into place for call
+	mov	$21, $1			# closure into static chain
+
+	# Load up all of the (potential) argument registers.
+	ldl	$16, 0($30)
+	fldd	$f16, 0($30)
+	fldd	$f17, 8($30)
+	ldl	$17, 8($30)
+	fldd	$f18, 16($30)
+	ldl	$18, 16($30)
+	fldd	$f19, 24($30)
+	ldl	$19, 24($30)
+	fldd	$f20, 32($30)
+	ldl	$20, 32($30)
+	fldd	$f21, 40($30)
+	ldl	$21, 40($30)
+
+	# Deallocate the register argument area.
+	ldi	$30, 48($30)
+
+	call	$26, ($27), 0
+0:
+	ldih	$29, 0($26)		!gpdisp!1
+	ldl	$2, 24($15)		# reload rvalue
+	ldi	$29, 0($29)		!gpdisp!1
+	ldl	$3, 16($15)		# reload flags
+	ldi	$1, 99f-0b($26)
+	ldl	$26, 0($15)
+	ldl	$15, 8($15)
+	cfi_restore($26)
+	cfi_restore($15)
+	cfi_def_cfa($sp, 0)
+	seleq	$2, SW_64_ST_VOID, $3	# mash null rvalue to void
+	addl	$3, $3, $3
+	s8addl	$3, $1, $1		# 99f + stcode * 16
+	jmp	$31, ($1), $st_int
+
+	.align	4
+99:
+E SW_64_ST_VOID
+	ret
+E SW_64_ST_INT
+$st_int:
+	stl	$0, 0($2)
+	ret
+E SW_64_ST_FLOAT
+	fsts	$f0, 0($2)
+	ret
+E SW_64_ST_DOUBLE
+	fstd	$f0, 0($2)
+	ret
+E SW_64_ST_CPLXF
+	fsts	$f0, 0($2)
+	fsts	$f1, 4($2)
+	ret
+E SW_64_ST_CPLXD
+	fstd	$f0, 0($2)
+	fstd	$f1, 8($2)
+	ret
+
+	cfi_endproc
+	.end	ffi_call_osf
+
+/* ffi_closure_osf(...)
+
+   Receives the closure argument in $1.   */
+
+#define CLOSURE_FS	(16*8)
+
+	.align	4
+	.globl	ffi_go_closure_osf
+	.ent	ffi_go_closure_osf
+	FFI_HIDDEN(ffi_go_closure_osf)
+
+ffi_go_closure_osf:
+	cfi_startproc
+	ldgp	$29, 0($27)
+	subl	$30, CLOSURE_FS, $30
+	cfi_adjust_cfa_offset(CLOSURE_FS)
+	stl	$26, 0($30)
+	.prologue 1
+	cfi_rel_offset($26, 0)
+
+	stl	$16, 10*8($30)
+	stl	$17, 11*8($30)
+	stl	$18, 12*8($30)
+
+	ldl	$16, 8($1)			# load cif
+	ldl	$17, 16($1)			# load fun
+	mov	$1, $18				# closure is user_data
+	br	$do_closure
+
+	cfi_endproc
+	.end	ffi_go_closure_osf
+
+	.align	4
+	.globl	ffi_closure_osf
+	.ent	ffi_closure_osf
+	FFI_HIDDEN(ffi_closure_osf)
+
+ffi_closure_osf:
+	cfi_startproc
+	ldgp	$29, 0($27)
+	subl	$30, CLOSURE_FS, $30
+	cfi_adjust_cfa_offset(CLOSURE_FS)
+	stl	$26, 0($30)
+	.prologue 1
+	cfi_rel_offset($26, 0)
+
+	# Store all of the potential argument registers in va_list format.
+	stl	$16, 10*8($30)
+	stl	$17, 11*8($30)
+	stl	$18, 12*8($30)
+
+	ldl	$16, 24($1)			# load cif
+	ldl	$17, 32($1)			# load fun
+	ldl	$18, 40($1)			# load user_data
+
+$do_closure:
+	stl	$19, 13*8($30)
+	stl	$20, 14*8($30)
+	stl	$21, 15*8($30)
+	fstd	$f16, 4*8($30)
+	fstd	$f17, 5*8($30)
+	fstd	$f18, 6*8($30)
+	fstd	$f19, 7*8($30)
+	fstd	$f20, 8*8($30)
+        fstd	$f21, 9*8($30)
+
+	# Call ffi_closure_osf_inner to do the bulk of the work.
+	ldi	$19, 2*8($30)
+	ldi	$20, 10*8($30)
+	call	$26, ffi_closure_osf_inner
+0:
+	ldih	$29, 0($26)			!gpdisp!2
+	ldi	$2, 99f-0b($26)
+	s4addl	$0, 0, $1			# ldcode * 4
+	ldl	$0, 16($30)			# preload return value
+	s4addl	$1, $2, $1			# 99f + ldcode * 16
+	ldi	$29, 0($29)			!gpdisp!2
+	ldl	$26, 0($30)
+	cfi_restore($26)
+	jmp	$31, ($1), $load_32
+
+.macro epilogue
+	addl	$30, CLOSURE_FS, $30
+	cfi_adjust_cfa_offset(-CLOSURE_FS)
+	ret
+	.align	4
+	cfi_adjust_cfa_offset(CLOSURE_FS)
+.endm
+
+	.align 4
+99:
+E SW_64_LD_VOID
+	epilogue
+
+E SW_64_LD_INT64
+	epilogue
+
+E SW_64_LD_INT32
+$load_32:
+	sextl	$0, $0
+	epilogue
+
+E SW_64_LD_UINT16
+	zapnot	$0, 3, $0
+	epilogue
+
+E SW_64_LD_SINT16
+#ifdef __sw_64_bwx__
+	sexth	$0, $0
+#else
+	sll	$0, 48, $0
+	sra	$0, 48, $0
+#endif
+	epilogue
+
+E SW_64_LD_UINT8
+	and	$0, 0xff, $0
+	epilogue
+
+E SW_64_LD_SINT8
+#ifdef __sw_64_bwx__
+	sextb	$0, $0
+#else
+	sll	$0, 56, $0
+	sra	$0, 56, $0
+#endif
+	epilogue
+
+E SW_64_LD_FLOAT
+	flds	$f0, 16($sp)
+	epilogue
+
+E SW_64_LD_DOUBLE
+	fldd	$f0, 16($sp)
+	epilogue
+
+E SW_64_LD_CPLXF
+	flds	$f0, 16($sp)
+	flds	$f1, 20($sp)
+	epilogue
+
+E SW_64_LD_CPLXD
+        fldd	$f0, 16($sp)
+	fldd	$f1, 24($sp)
+	epilogue
+
+	cfi_endproc
+	.end	ffi_closure_osf
+
+#if defined __ELF__ && defined __linux__
+	.section	.note.GNU-stack,"",@progbits
+#endif
diff --git a/src/types.c b/src/types.c
index 9ec27f6..e5f666b 100644
--- a/src/types.c
+++ b/src/types.c
@@ -80,13 +80,13 @@ FFI_TYPEDEF(pointer, void*, FFI_TYPE_POINTER, const);
 FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT, const);
 FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE, const);
 
-#if !defined HAVE_LONG_DOUBLE_VARIANT || defined __alpha__
+#if !defined HAVE_LONG_DOUBLE_VARIANT || defined __alpha__ || defined __sw_64__
 #define FFI_LDBL_CONST const
 #else
 #define FFI_LDBL_CONST
 #endif
 
-#ifdef __alpha__
+#if defined __alpha__ || defined __sw_64__
 /* Even if we're not configured to default to 128-bit long double, 
    maintain binary compatibility, as -mlong-double-128 can be used
    at any time.  */
diff --git a/testsuite/libffi.go/static-chain.h b/testsuite/libffi.go/static-chain.h
index 3675b40..25ef76e 100644
--- a/testsuite/libffi.go/static-chain.h
+++ b/testsuite/libffi.go/static-chain.h
@@ -2,6 +2,8 @@
 # define STATIC_CHAIN_REG  "x18"
 #elif defined(__alpha__)
 # define STATIC_CHAIN_REG  "$1"
+#elif defined(__sw_64__)
+# define STATIC_CHAIN_REG  "$1"
 #elif defined(__arm__)
 # define STATIC_CHAIN_REG  "ip"
 #elif defined(__sparc__)
-- 
2.33.0

