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


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

libffi support for alpha 128-bit long double


The trick here is that the 128-bit long double type can be controlled
by the --with-long-double-128 configure time switch (which sets the
default) and the -mlong-double-{64,128} command-line switches.

I've rearranged things such that long double is always considered to
be the 128-bit type within libffi, and if the user has the 64-bit type
then ffi.h makes sure that ffi_type_longdouble and FFI_TYPE_LONGDOUBLE
point to the plain double items.

Tested on alpha and x86_64 linux.


r~


        * configure.ac: Tidy target case.
        (HAVE_LONG_DOUBLE): Allow the target to override.
        * configure: Regenerate.
        * include/ffi.h.in: Don't define ffi_type_foo if
        LIBFFI_HIDE_BASIC_TYPES is defined.
        (ffi_type_longdouble): If not HAVE_LONG_DOUBLE, define
        to ffi_type_double.
        * types.c (LIBFFI_HIDE_BASIC_TYPES): Define.
        (FFI_TYPEDEF, ffi_type_void): Mark the data const.
        (ffi_type_longdouble): Special case for Alpha.  Don't define
        if long double == double.

        * src/alpha/ffi.c (FFI_TYPE_LONGDOUBLE): Assert unique value.
        (ffi_prep_cif_machdep): Handle it as the 128-bit type.
        (ffi_call, ffi_closure_osf_inner): Likewise.
        (ffi_closure_osf_inner): Likewise.  Mark hidden.
        (ffi_call_osf, ffi_closure_osf): Mark hidden.
        * src/alpha/ffitarget.h (FFI_LAST_ABI): Tidy definition.
        * src/alpha/osf.S (ffi_call_osf, ffi_closure_osf): Mark hidden.
        (load_table): Handle 128-bit long double.

        * testsuite/libffi.call/float4.c: Add -mieee for alpha.

--- configure.ac	(revision 123530)
+++ configure.ac	(local)
@@ -41,52 +41,107 @@ AM_CONDITIONAL(TESTSUBDIR, test -d $srcd
 
 TARGETDIR="unknown"
 case "$host" in
-i*86-*-linux*) TARGET=X86; TARGETDIR=x86;;
-i*86-*-gnu*) TARGET=X86; TARGETDIR=x86;;
-i*86-*-solaris2.1[[0-9]]*) TARGET=X86_64; TARGETDIR=x86;;
-i*86-*-solaris*) TARGET=X86; TARGETDIR=x86;;
-i*86-*-beos*) TARGET=X86; TARGETDIR=x86;;
-i*86-*-darwin*) TARGET=X86_DARWIN; TARGETDIR=x86;;
-i*86-*-freebsd* | i*86-*-kfreebsd*-gnu) TARGET=X86; TARGETDIR=x86;;
-i*86-*-netbsdelf* | i*86-*-knetbsd*-gnu) TARGET=X86; TARGETDIR=x86;;
-i*86-*-rtems*) TARGET=X86; TARGETDIR=x86;;
-i*86-*-win32*) TARGET=X86_WIN32; TARGETDIR=x86;;
-i*86-*-cygwin*) TARGET=X86_WIN32; TARGETDIR=x86;;
-i*86-*-mingw*) TARGET=X86_WIN32; TARGETDIR=x86;;
-frv-*-*) TARGET=FRV; TARGETDIR=frv;;
-sparc-sun-4*) TARGET=SPARC; TARGETDIR=sparc;;
-sparc*-sun-*) TARGET=SPARC; TARGETDIR=sparc;;
-sparc-*-linux* | sparc-*-netbsdelf* | sparc-*-knetbsd*-gnu) TARGET=SPARC; TARGETDIR=sparc;;
-sparc*-*-rtems*) TARGET=SPARC; TARGETDIR=sparc;;
-sparc64-*-linux* | sparc64-*-freebsd* | sparc64-*-netbsd* | sparc64-*-knetbsd*-gnu) TARGET=SPARC; TARGETDIR=sparc;;
-alpha*-*-linux* | alpha*-*-osf* | alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu | alpha*-*-netbsd* | alpha*-*-knetbsd*-gnu) TARGET=ALPHA; TARGETDIR=alpha;;
-ia64*-*-*) TARGET=IA64; TARGETDIR=ia64;;
-m32r*-*-linux* ) TARGET=M32R; TARGETDIR=m32r;;
-m68k-*-linux*) TARGET=M68K; TARGETDIR=m68k;;
-mips64*-*);;
-mips-sgi-irix5.* | mips-sgi-irix6.*) TARGET=MIPS_IRIX; TARGETDIR=mips;;
-mips*-*-linux*) TARGET=MIPS_LINUX; TARGETDIR=mips;;
-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;;
-powerpc-*-freebsd*) TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc;;
-powerpc*-*-rtems*) TARGET=POWERPC; TARGETDIR=powerpc;;
-rs6000-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
-arm*-*-linux-*) TARGET=ARM; TARGETDIR=arm;;
-arm*-*-netbsdelf* | arm*-*-knetbsd*-gnu) TARGET=ARM; TARGETDIR=arm;;
-arm*-*-rtems*) TARGET=ARM; TARGETDIR=arm;;
-cris-*-*) TARGET=LIBFFI_CRIS; TARGETDIR=cris;;
-s390-*-linux-*) TARGET=S390; TARGETDIR=s390;;
-s390x-*-linux-*) TARGET=S390; TARGETDIR=s390;;
-x86_64-*-linux* | x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) TARGET=X86_64; TARGETDIR=x86;;
-x86_64-*-darwin*) TARGET=X86_DARWIN; TARGETDIR=x86;;
-sh-*-linux* | sh[[34]]*-*-linux*) TARGET=SH; TARGETDIR=sh;;
-sh-*-rtems*) TARGET=SH; TARGETDIR=sh;;
-sh64-*-linux* | sh5*-*-linux*) TARGET=SH64; TARGETDIR=sh64;;
-hppa*-*-linux* | parisc*-*-linux*) TARGET=PA_LINUX; TARGETDIR=pa;;
-hppa*64-*-hpux*) TARGET=PA64_HPUX; TARGETDIR=pa;;
-hppa*-*-hpux*) TARGET=PA_HPUX; TARGETDIR=pa;;
+  alpha*-*-*)
+	TARGET=ALPHA; TARGETDIR=alpha;
+	# Support 128-bit long double, changable via command-line switch.
+	HAVE_LONG_DOUBLE='defined(__LONG_DOUBLE_128__)'
+	;;
+
+  arm*-*-*)
+	TARGET=ARM; TARGETDIR=arm
+	;;
+
+  cris-*-*)
+	TARGET=LIBFFI_CRIS; TARGETDIR=cris
+	;;
+
+  frv-*-*)
+	TARGET=FRV; TARGETDIR=frv
+	;;
+
+  hppa*-*-linux* | parisc*-*-linux*)
+	TARGET=PA_LINUX; TARGETDIR=pa
+	;;
+  hppa*64-*-hpux*)
+	TARGET=PA64_HPUX; TARGETDIR=pa
+	;;
+  hppa*-*-hpux*)
+	TARGET=PA_HPUX; TARGETDIR=pa
+	;;
+
+  i?86-win32* | i?86-*-cygwin* | i?86-*-mingw*)
+	TARGET=X86_WIN32; TARGETDIR=x86
+	;;
+  i?86-*-darwin*)
+	TARGET=X86_DARWIN; TARGETDIR=x86
+	;;
+  i?86-*-*)
+	TARGET=X86; TARGETDIR=x86
+	;;
+
+  ia64*-*-*)
+	TARGET=IA64; TARGETDIR=ia64
+	;;
+
+  m32r*-*-*)
+	TARGET=M32R; TARGETDIR=m32r
+	;;
+
+  m68k-*-*)
+	TARGET=M68K; TARGETDIR=m68k
+	;;
+
+  mips64*-*)
+	;;
+  mips-sgi-irix5.* | mips-sgi-irix6.*)
+	TARGET=MIPS_IRIX; TARGETDIR=mips
+	;;
+  mips*-*-linux*)
+	TARGET=MIPS_LINUX; TARGETDIR=mips
+	;;
+
+  powerpc*-*-linux* | powerpc-*-sysv*)
+	TARGET=POWERPC; TARGETDIR=powerpc
+	;;
+  powerpc-*-beos*)
+	TARGET=POWERPC; TARGETDIR=powerpc
+	;;
+  powerpc-*-darwin*)
+	TARGET=POWERPC_DARWIN; TARGETDIR=powerpc
+	;;
+  powerpc-*-aix* | rs6000-*-aix*)
+	TARGET=POWERPC_AIX; TARGETDIR=powerpc
+	;;
+  powerpc-*-freebsd*)
+	TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc
+	;;
+  powerpc*-*-rtems*)
+	TARGET=POWERPC; TARGETDIR=powerpc
+	;;
+
+  s390-*-* | s390x-*-*)
+	TARGET=S390; TARGETDIR=s390
+	;;
+
+  sh-*-* | sh[[34]]*-*-*)
+	TARGET=SH; TARGETDIR=sh
+	;;
+  sh64-*-* | sh5*-*-*)
+	TARGET=SH64; TARGETDIR=sh64
+	;;
+
+  sparc*-*-*)
+	TARGET=SPARC; TARGETDIR=sparc
+	;;
+
+  x86_64-*-darwin*)
+	TARGET=X86_DARWIN; TARGETDIR=x86
+	;;
+  x86_64-*-cygwin* | x86_64-*-mingw*)
+	;;
+  x86_64-*-*)
+	TARGET=X86_64; TARGETDIR=x86
+	;;
 esac
 
 AC_SUBST(AM_RUNTESTFLAGS)
@@ -133,11 +188,13 @@ AC_CHECK_SIZEOF(double)
 AC_CHECK_SIZEOF(long double)
 
 # Also AC_SUBST this variable for ffi.h.
-HAVE_LONG_DOUBLE=0
-if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then
-  if test $ac_cv_sizeof_long_double != 0; then
-    HAVE_LONG_DOUBLE=1
-    AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the long double type and it is bigger than a double])
+if test -z "$HAVE_LONG_DOUBLE"; then
+  HAVE_LONG_DOUBLE=0
+  if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then
+    if test $ac_cv_sizeof_long_double != 0; then
+      HAVE_LONG_DOUBLE=1
+      AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the long double type and it is bigger than a double])
+    fi
   fi
 fi
 AC_SUBST(HAVE_LONG_DOUBLE)
--- include/ffi.h.in	(revision 123530)
+++ include/ffi.h.in	(local)
@@ -82,6 +82,18 @@ extern "C" {
 # endif
 #endif
 
+/* The closure code assumes that this works on pointers, i.e. a size_t	*/
+/* can hold a pointer.							*/
+
+typedef struct _ffi_type
+{
+  size_t size;
+  unsigned short alignment;
+  unsigned short type;
+  struct _ffi_type **elements;
+} ffi_type;
+
+#ifndef LIBFFI_HIDE_BASIC_TYPES
 #if SCHAR_MAX == 127
 # define ffi_type_uchar                ffi_type_uint8
 # define ffi_type_schar                ffi_type_sint8
@@ -130,17 +142,6 @@ extern "C" {
  #error "long size not supported"
 #endif
 
-/* The closure code assumes that this works on pointers, i.e. a size_t	*/
-/* can hold a pointer.							*/
-
-typedef struct _ffi_type
-{
-  size_t size;
-  unsigned short alignment;
-  unsigned short type;
-  struct _ffi_type **elements;
-} ffi_type;
-
 /* These are defined in types.c */
 extern ffi_type ffi_type_void;
 extern ffi_type ffi_type_uint8;
@@ -153,9 +154,14 @@ extern ffi_type ffi_type_uint64;
 extern ffi_type ffi_type_sint64;
 extern ffi_type ffi_type_float;
 extern ffi_type ffi_type_double;
-extern ffi_type ffi_type_longdouble;
 extern ffi_type ffi_type_pointer;
 
+#if @HAVE_LONG_DOUBLE@
+extern ffi_type ffi_type_longdouble;
+#else
+#define ffi_type_longdouble ffi_type_double
+#endif
+#endif /* LIBFFI_HIDE_BASIC_TYPES */
 
 typedef enum {
   FFI_OK = 0,
@@ -342,4 +348,3 @@ void ffi_call(ffi_cif *cif,
 #endif
 
 #endif
-
--- src/alpha/ffi.c	(revision 123530)
+++ src/alpha/ffi.c	(local)
@@ -25,11 +25,22 @@
 
 #include <ffi.h>
 #include <ffi_common.h>
-
 #include <stdlib.h>
 
-extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)());
-extern void ffi_closure_osf(void);
+/* 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 *, unsigned long, unsigned, void *, void (*)())
+  FFI_HIDDEN;
+extern void ffi_closure_osf(void) FFI_HIDDEN;
 
 
 ffi_status
@@ -49,6 +60,11 @@ ffi_prep_cif_machdep(ffi_cif *cif)
       cif->flags = cif->rtype->type;
       break;
 
+    case FFI_TYPE_LONGDOUBLE:
+      /* 128-bit long double is returned in memory, like a struct.  */
+      cif->flags = FFI_TYPE_STRUCT;
+      break;
+
     default:
       cif->flags = FFI_TYPE_INT;
       break;
@@ -57,6 +73,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
   return FFI_OK;
 }
 
+
 void
 ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
 {
@@ -64,8 +81,6 @@ ffi_call(ffi_cif *cif, void (*fn)(), voi
   long i, avn;
   ffi_type **arg_types;
   
-  FFI_ASSERT (cif->abi == FFI_OSF);
-
   /* 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->flags == FFI_TYPE_STRUCT)
@@ -84,6 +99,8 @@ ffi_call(ffi_cif *cif, void (*fn)(), voi
 
   while (i < avn)
     {
+      size_t size = (*arg_types)->size;
+
       switch ((*arg_types)->type)
 	{
 	case FFI_TYPE_SINT8:
@@ -129,6 +146,12 @@ ffi_call(ffi_cif *cif, void (*fn)(), voi
 	  *(double *) argp = *(double *)(* avalue);
 	  break;
 
+	case FFI_TYPE_LONGDOUBLE:
+	  /* 128-bit long double is passed by reference.  */
+	  *(long double **) argp = (long double *)(* avalue);
+	  size = sizeof (long double *);
+	  break;
+
 	case FFI_TYPE_STRUCT:
 	  memcpy(argp, *avalue, (*arg_types)->size);
 	  break;
@@ -137,7 +160,7 @@ ffi_call(ffi_cif *cif, void (*fn)(), voi
 	  FFI_ASSERT(0);
 	}
 
-      argp += ALIGN((*arg_types)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+      argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
       i++, arg_types++, avalue++;
     }
 
@@ -154,8 +177,6 @@ ffi_prep_closure_loc (ffi_closure* closu
 {
   unsigned int *tramp;
 
-  FFI_ASSERT (cif->abi == FFI_OSF);
-
   tramp = (unsigned int *) &closure->tramp[0];
   tramp[0] = 0x47fb0401;	/* mov $27,$1		*/
   tramp[1] = 0xa77b0010;	/* ldq $27,16($27)	*/
@@ -178,7 +199,8 @@ ffi_prep_closure_loc (ffi_closure* closu
   return FFI_OK;
 }
 
-int
+
+long FFI_HIDDEN
 ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
 {
   ffi_cif *cif;
@@ -206,6 +228,8 @@ ffi_closure_osf_inner(ffi_closure *closu
   /* Grab the addresses of the arguments from the stack frame.  */
   while (i < avn)
     {
+      size_t size = arg_types[i]->size;
+
       switch (arg_types[i]->type)
 	{
 	case FFI_TYPE_SINT8:
@@ -237,16 +261,22 @@ ffi_closure_osf_inner(ffi_closure *closu
 	  avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
 	  break;
 
+	case FFI_TYPE_LONGDOUBLE:
+	  /* 128-bit long double is passed by reference.  */
+	  avalue[i] = (long double *) argp[argn];
+	  size = sizeof (long double *);
+	  break;
+
 	default:
-	  FFI_ASSERT(0);
+	  abort ();
 	}
 
-      argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+      argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
       i++;
     }
 
   /* Invoke the closure.  */
-  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+  closure->fun (cif, rvalue, avalue, closure->user_data);
 
   /* Tell ffi_closure_osf how to perform return type promotions.  */
   return cif->rtype->type;
--- src/alpha/ffitarget.h	(revision 123530)
+++ src/alpha/ffitarget.h	(local)
@@ -33,8 +33,8 @@ typedef signed long            ffi_sarg;
 typedef enum ffi_abi {
   FFI_FIRST_ABI = 0,
   FFI_OSF,
-  FFI_DEFAULT_ABI = FFI_OSF,
-  FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+  FFI_LAST_ABI,
+  FFI_DEFAULT_ABI = FFI_OSF
 } ffi_abi;
 #endif
 
@@ -45,4 +45,3 @@ typedef enum ffi_abi {
 #define FFI_NATIVE_RAW_API 0
 
 #endif
-
--- src/alpha/osf.S	(revision 123530)
+++ src/alpha/osf.S	(local)
@@ -1,10 +1,8 @@
 /* -----------------------------------------------------------------------
-   osf.S - Copyright (c) 1998, 2001 Red Hat
+   osf.S - Copyright (c) 1998, 2001, 2007 Red Hat
    
    Alpha/OSF Foreign Function Interface 
 
-   $Id: osf.S,v 1.1.1.1 1998/11/29 16:48:16 green Exp $
-
    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
@@ -42,6 +40,8 @@
 	.align	3
 	.globl	ffi_call_osf
 	.ent	ffi_call_osf
+	FFI_HIDDEN(ffi_call_osf)
+
 ffi_call_osf:
 	.frame	$15, 32, $26, 0
 	.mask   0x4008000, -32
@@ -129,6 +129,8 @@ $LFE1:
 	.align	3
 	.globl	ffi_closure_osf
 	.ent	ffi_closure_osf
+	FFI_HIDDEN(ffi_closure_osf)
+
 ffi_closure_osf:
 	.frame	$30, 16*8, $26, 0
 	.mask	0x4000000, -16*8
@@ -265,7 +267,7 @@ $load_table:
 	.gprel32 $load_32	# FFI_TYPE_INT
 	.gprel32 $load_float	# FFI_TYPE_FLOAT
 	.gprel32 $load_double	# FFI_TYPE_DOUBLE
-	.gprel32 $load_double	# FFI_TYPE_LONGDOUBLE
+	.gprel32 $load_none	# FFI_TYPE_LONGDOUBLE
 	.gprel32 $load_u8	# FFI_TYPE_UINT8
 	.gprel32 $load_s8	# FFI_TYPE_SINT8
 	.gprel32 $load_u16	# FFI_TYPE_UINT16
--- src/types.c	(revision 123530)
+++ src/types.c	(local)
@@ -23,6 +23,10 @@
    OTHER DEALINGS IN THE SOFTWARE.
    ----------------------------------------------------------------------- */
 
+/* Hide the basic type definitions from the header file, so that we
+   can redefine them here as "const".  */
+#define LIBFFI_HIDE_BASIC_TYPES
+
 #include <ffi.h>
 #include <ffi_common.h>
 
@@ -33,14 +37,14 @@ struct struct_align_##name {			\
   char c;					\
   type x;					\
 };						\
-ffi_type ffi_type_##name = {			\
+const ffi_type ffi_type_##name = {		\
   sizeof(type),					\
   offsetof(struct struct_align_##name, x),	\
   id, NULL					\
 }
 
 /* Size and alignment are fake here. They must not be 0. */
-ffi_type ffi_type_void = {
+const ffi_type ffi_type_void = {
   1, 1, FFI_TYPE_VOID, NULL
 };
 
@@ -57,4 +61,16 @@ FFI_TYPEDEF(pointer, void*, FFI_TYPE_POI
 
 FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT);
 FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE);
+
+#ifdef __alpha__
+/* 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.  */
+/* Validate the hard-coded number below.  */
+# if defined(__LONG_DOUBLE_128__) && FFI_TYPE_LONGDOUBLE != 4
+#  error FFI_TYPE_LONGDOUBLE out of date
+# endif
+const ffi_type ffi_type_longdouble = { 16, 16, 4, NULL };
+#elif FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
 FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE);
+#endif
--- testsuite/libffi.call/float4.c	(revision 123530)
+++ testsuite/libffi.call/float4.c	(local)
@@ -5,6 +5,8 @@
    Originator:	From the original ffitest.c  */
 
 /* { dg-do run } */
+/* { dg-options "-mieee" { target alpha*-*-* } } */
+
 #include "ffitest.h"
 #include "float.h"
 


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