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 x86-64 patch checked in


I have now checked in the x86-64 support in libffi.

I took the liberty of changing the patch a bit before committing it. The
reason for this is that I was basically doing this in ffi.c:

#ifndef __x86_64__
 /* 386 contents goes here */
#else
 /* x86-64 contents goes here */
#endif

And to make it even more unreadable, this was done with a large number of
ifdefs. So instead I simply took out everything from ffi.c that was in
ifdef x86-64 and put it in ffi64.c instead giving a couple of much nicer
files.

This now means that the x86 dir has ffi.c and sysv.S that handles x86 and
ffi64.c and unix64.S that handles x86-64. The reason the x86-64 files isn't
put in a separate directory is that it needs to handle multilib reasonably
well. The easiest way to do that is to simply compile all four files with
the appropriate -m32 and -m64 compiler options. If someone here is an
automake ubergeek, feel free to make an x86-64 subdirectory and move ffi64.c
and unix64.s to that and make multilib work with this.

Just to make sure that I really didn't make any bad mistakes, I
bootstrapped both x86-64 and i386 with this patch - and even remembered
to tell about it :-) I hope my decision here is acceptable. It should in any
case be more safe than making a lot of changes in the x86 ffi.c.

This is the part of the patch that I changed:

Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libffi/Makefile.am,v
retrieving revision 1.20
diff -u -b -B -r1.20 Makefile.am
--- Makefile.am	18 Jul 2002 17:55:27 -0000	1.20
+++ Makefile.am	18 Jul 2002 21:27:18 -0000
@@ -8,6 +8,7 @@
 		src/mips/n32.s src/mips/o32.S src/mips/o32.s \
 		src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S \
 		src/x86/ffi.c src/x86/sysv.S src/x86/win32.S \
+		src/x86/ffi64.c src/x86/unix64.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 \
@@ -106,6 +107,7 @@
 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
 TARGET_SRC_S390 =  src/s390/sysv.S src/s390/ffi.c
+TARGET_SRC_X86_64 = src/x86/ffi64.c src/x86/unix64.S src/x86/ffi.c src/x86/sysv.S
 
 ##libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c $(TARGET_SRC_@TARGET@)
 ## Work around automake deficiency
@@ -166,6 +168,10 @@
 if S390
 libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_S390)
 libffi_convenience_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_S390)
+endif
+if X86_64
+libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_X86_64)
+libffi_convenience_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_X86_64)
 endif
 
 AM_CFLAGS = -fexceptions
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/libffi/Makefile.in,v
retrieving revision 1.25
diff -u -b -B -r1.25 Makefile.in
--- Makefile.in	18 Jul 2002 17:55:27 -0000	1.25
+++ Makefile.in	18 Jul 2002 21:27:18 -0000
@@ -89,6 +89,7 @@
 		src/mips/n32.s src/mips/o32.S src/mips/o32.s \
 		src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S \
 		src/x86/ffi.c src/x86/sysv.S src/x86/win32.S \
+		src/x86/ffi64.c src/x86/unix64.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 \
@@ -177,6 +178,7 @@
 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
 TARGET_SRC_S390 = src/s390/sysv.S src/s390/ffi.c
+TARGET_SRC_X86_64 = src/x86/ffi64.c src/x86/unix64.S src/x86/ffi.c src/x86/sysv.S
 
 libffi_la_common_SOURCES = src/debug.c src/prep_cif.c src/types.c \
 		src/raw_api.c src/java_raw_api.c
@@ -195,6 +197,7 @@
 @POWERPC_DARWIN_TRUE@libffi_la_SOURCES = @POWERPC_DARWIN_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC_DARWIN)
 @ARM_TRUE@libffi_la_SOURCES = @ARM_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_ARM)
 @S390_TRUE@libffi_la_SOURCES = @S390_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_S390)
+@X86_64_TRUE@libffi_la_SOURCES = @X86_64_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_X86_64)
 @MIPS_GCC_TRUE@libffi_convenience_la_SOURCES = @MIPS_GCC_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_GCC)
 @MIPS_LINUX_TRUE@libffi_convenience_la_SOURCES = @MIPS_LINUX_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_LINUX)
 @MIPS_SGI_TRUE@libffi_convenience_la_SOURCES = @MIPS_SGI_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_SGI)
@@ -209,6 +212,7 @@
 @POWERPC_DARWIN_TRUE@libffi_convenience_la_SOURCES = @POWERPC_DARWIN_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC_DARWIN)
 @ARM_TRUE@libffi_convenience_la_SOURCES = @ARM_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_ARM)
 @S390_TRUE@libffi_convenience_la_SOURCES = @S390_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_S390)
+@X86_64_TRUE@libffi_convenience_la_SOURCES = @X86_64_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_X86_64)
 
 AM_CFLAGS = -fexceptions
 
@@ -304,6 +308,9 @@
 @S390_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
 @S390_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
 @S390_TRUE@src/s390/sysv.lo src/s390/ffi.lo
+@X86_64_TRUE@libffi_convenience_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
+@X86_64_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
+@X86_64_TRUE@src/x86/ffi.lo src/x86/sysv.lo src/x86/unix64.lo src/x86/ffi64.lo
 @X86_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo src/types.lo \
 @X86_TRUE@src/raw_api.lo src/java_raw_api.lo src/x86/ffi.lo \
 @X86_TRUE@src/x86/sysv.lo
@@ -323,6 +330,9 @@
 @M68K_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
 @M68K_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
 @M68K_TRUE@src/m68k/ffi.lo src/m68k/sysv.lo
+@X86_64_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo src/types.lo \
+@X86_64_TRUE@src/raw_api.lo src/java_raw_api.lo src/x86/ffi.lo \
+@X86_64_TRUE@src/x86/sysv.lo src/x86/unix64.lo src/x86/ffi64.lo
 noinst_PROGRAMS =  ffitest$(EXEEXT)
 PROGRAMS =  $(noinst_PROGRAMS)
 
Index: src/x86/ffi.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/x86/ffi.c,v
retrieving revision 1.6
diff -u -b -B -r1.6 ffi.c
--- src/x86/ffi.c	28 May 2002 07:11:42 -0000	1.6
+++ src/x86/ffi.c	18 Jul 2002 21:27:18 -0000
@@ -23,6 +23,8 @@
    OTHER DEALINGS IN THE SOFTWARE.
    ----------------------------------------------------------------------- */
 
+#ifndef __x86_64__
+
 #include <ffi.h>
 #include <ffi_common.h>
 
@@ -491,3 +493,5 @@
 }
 
 #endif
+
+#endif /* __x86_64__  */
Index: src/x86/ffi64.c
===================================================================
RCS file: src/x86/ffi64.c
diff -N src/x86/ffi64.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/x86/ffi64.c	18 Jul 2002 21:27:18 -0000
@@ -0,0 +1,572 @@
+/* -----------------------------------------------------------------------
+   ffi.c - Copyright (c) 2002  Bo Thorsen <bo@suse.de>
+   
+   x86-64 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 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.
+   ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+
+/* ffi_prep_args is called by the assembly routine once stack space
+   has been allocated for the function's arguments */
+
+#ifdef __x86_64__
+
+#define MAX_GPR_REGS 6
+#define MAX_SSE_REGS 8
+typedef struct
+{
+  /* Registers for argument passing.  */
+  long gpr[MAX_GPR_REGS];
+  __int128_t sse[MAX_SSE_REGS];
+
+  /* Stack space for arguments.  */
+  char argspace[0];
+} stackLayout;
+
+/* All reference to register classes here is identical to the code in
+   gcc/config/i386/i386.c. Do *not* change one without the other.  */
+
+/* Register class used for passing given 64bit part of the argument.
+   These represent classes as documented by the PS ABI, with the exception
+   of SSESF, SSEDF classes, that are basically SSE class, just gcc will
+   use SF or DFmode move instead of DImode to avoid reformating penalties.
+
+   Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
+   whenever possible (upper half does contain padding).
+ */
+enum x86_64_reg_class
+  {
+    X86_64_NO_CLASS,
+    X86_64_INTEGER_CLASS,
+    X86_64_INTEGERSI_CLASS,
+    X86_64_SSE_CLASS,
+    X86_64_SSESF_CLASS,
+    X86_64_SSEDF_CLASS,
+    X86_64_SSEUP_CLASS,
+    X86_64_X87_CLASS,
+    X86_64_X87UP_CLASS,
+    X86_64_MEMORY_CLASS
+  };
+
+#define MAX_CLASSES 4
+
+/* x86-64 register passing implementation.  See x86-64 ABI for details.  Goal
+   of this code is to classify each 8bytes of incoming argument by the register
+   class and assign registers accordingly.  */
+
+/* Return the union class of CLASS1 and CLASS2.
+   See the x86-64 PS ABI for details.  */
+
+static enum x86_64_reg_class
+merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
+{
+  /* Rule #1: If both classes are equal, this is the resulting class.  */
+  if (class1 == class2)
+    return class1;
+
+  /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
+     the other class.  */
+  if (class1 == X86_64_NO_CLASS)
+    return class2;
+  if (class2 == X86_64_NO_CLASS)
+    return class1;
+
+  /* Rule #3: If one of the classes is MEMORY, the result is MEMORY.  */
+  if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
+    return X86_64_MEMORY_CLASS;
+
+  /* Rule #4: If one of the classes is INTEGER, the result is INTEGER.  */
+  if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
+      || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
+    return X86_64_INTEGERSI_CLASS;
+  if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
+      || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
+    return X86_64_INTEGER_CLASS;
+
+  /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used.  */
+  if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS
+      || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS)
+    return X86_64_MEMORY_CLASS;
+
+  /* Rule #6: Otherwise class SSE is used.  */
+  return X86_64_SSE_CLASS;
+}
+
+/* Classify the argument of type TYPE and mode MODE.
+   CLASSES will be filled by the register class used to pass each word
+   of the operand.  The number of words is returned.  In case the parameter
+   should be passed in memory, 0 is returned. As a special case for zero
+   sized containers, classes[0] will be NO_CLASS and 1 is returned.
+
+   See the x86-64 PS ABI for details.
+*/
+static int
+classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
+		   int *byte_offset)
+{
+  /* First, align to the right place.  */
+  *byte_offset = ALIGN(*byte_offset, type->alignment);
+
+  switch (type->type)
+    {
+    case FFI_TYPE_UINT8:
+    case FFI_TYPE_SINT8:
+    case FFI_TYPE_UINT16:
+    case FFI_TYPE_SINT16:
+    case FFI_TYPE_UINT32:
+    case FFI_TYPE_SINT32:
+    case FFI_TYPE_UINT64:
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_POINTER:
+      if (((*byte_offset) % 8 + type->size) <= 4)
+	classes[0] = X86_64_INTEGERSI_CLASS;
+      else
+	classes[0] = X86_64_INTEGER_CLASS;
+      return 1;
+    case FFI_TYPE_FLOAT:
+      if (((*byte_offset) % 8) == 0)
+	classes[0] = X86_64_SSESF_CLASS;
+      else
+	classes[0] = X86_64_SSE_CLASS;
+      return 1;
+    case FFI_TYPE_DOUBLE:
+      classes[0] = X86_64_SSEDF_CLASS;
+      return 1;
+    case FFI_TYPE_LONGDOUBLE:
+      classes[0] = X86_64_X87_CLASS;
+      classes[1] = X86_64_X87UP_CLASS;
+      return 2;
+    case FFI_TYPE_STRUCT:
+      {
+	const int UNITS_PER_WORD = 8;
+	int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+	ffi_type **ptr; 
+	int i;
+	enum x86_64_reg_class subclasses[MAX_CLASSES];
+
+	/* If the struct is larger than 16 bytes, pass it on the stack.  */
+	if (type->size > 16)
+	  return 0;
+
+	for (i = 0; i < words; i++)
+	  classes[i] = X86_64_NO_CLASS;
+
+	/* Merge the fields of structure.  */
+	for (ptr=type->elements; (*ptr)!=NULL; ptr++)
+	  {
+	    int num;
+
+	    num = classify_argument (*ptr, subclasses, byte_offset);
+	    if (num == 0)
+	      return 0;
+	    for (i = 0; i < num; i++)
+	      {
+		int pos = *byte_offset / 8;
+		classes[i + pos] =
+		  merge_classes (subclasses[i], classes[i + pos]);
+	      }
+
+	    if ((*ptr)->type != FFI_TYPE_STRUCT)
+	      *byte_offset += (*ptr)->size;
+	  }
+
+	/* Final merger cleanup.  */
+	for (i = 0; i < words; i++)
+	  {
+	    /* If one class is MEMORY, everything should be passed in
+	       memory.  */
+	    if (classes[i] == X86_64_MEMORY_CLASS)
+	      return 0;
+
+	    /* The X86_64_SSEUP_CLASS should be always preceded by
+	       X86_64_SSE_CLASS.  */
+	    if (classes[i] == X86_64_SSEUP_CLASS
+		&& (i == 0 || classes[i - 1] != X86_64_SSE_CLASS))
+	      classes[i] = X86_64_SSE_CLASS;
+
+	    /*  X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS.  */
+	    if (classes[i] == X86_64_X87UP_CLASS
+		&& (i == 0 || classes[i - 1] != X86_64_X87_CLASS))
+	      classes[i] = X86_64_SSE_CLASS;
+	  }
+	return words;
+      }
+
+    default:
+      FFI_ASSERT(0);
+    }
+  return 0; /* Never reached.  */
+}
+
+/* Examine the argument and return set number of register required in each
+   class.  Return 0 iff parameter should be passed in memory.  */
+static int
+examine_argument (ffi_type *type, int in_return, int *int_nregs,int *sse_nregs)
+{
+  enum x86_64_reg_class class[MAX_CLASSES];
+  int offset = 0;
+  int n;
+
+  n = classify_argument (type, class, &offset);
+
+  if (n == 0)
+    return 0;
+
+  *int_nregs = 0;
+  *sse_nregs = 0;
+  for (n--; n>=0; n--)
+    switch (class[n])
+      {
+      case X86_64_INTEGER_CLASS:
+      case X86_64_INTEGERSI_CLASS:
+	(*int_nregs)++;
+	break;
+      case X86_64_SSE_CLASS:
+      case X86_64_SSESF_CLASS:
+      case X86_64_SSEDF_CLASS:
+	(*sse_nregs)++;
+	break;
+      case X86_64_NO_CLASS:
+      case X86_64_SSEUP_CLASS:
+	break;
+      case X86_64_X87_CLASS:
+      case X86_64_X87UP_CLASS:
+	if (!in_return)
+	  return 0;
+	break;
+      default:
+	abort ();
+      }
+  return 1;
+}
+
+/* Functions to load floats and double to an SSE register placeholder.  */
+extern void float2sse (float, __int128_t *);
+extern void double2sse (double, __int128_t *);
+extern void floatfloat2sse (void *, __int128_t *);
+
+/* Functions to put the floats and doubles back.  */
+extern float sse2float (__int128_t *);
+extern double sse2double (__int128_t *);
+extern void sse2floatfloat(__int128_t *, void *);
+
+/*@-exportheader@*/
+void
+ffi_prep_args (stackLayout *stack, extended_cif *ecif)
+/*@=exportheader@*/
+{
+  int gprcount, ssecount, i, g, s;
+  void **p_argv;
+  void *argp = &stack->argspace;
+  ffi_type **p_arg;
+
+  /* First check if the return value should be passed in memory. If so,
+     pass the pointer as the first argument.  */
+  gprcount = ssecount = 0;
+  if (examine_argument (ecif->cif->rtype, 1, &g, &s) == 0)
+    (void *)stack->gpr[gprcount++] = ecif->rvalue;
+
+  for (i=ecif->cif->nargs, p_arg=ecif->cif->arg_types, p_argv = ecif->avalue;
+       i!=0; i--, p_arg++, p_argv++)
+    {
+      int in_register = 0;
+
+      switch ((*p_arg)->type)
+	{
+	case FFI_TYPE_SINT8:
+	case FFI_TYPE_SINT16:
+	case FFI_TYPE_SINT32:
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_UINT8:
+	case FFI_TYPE_UINT16:
+	case FFI_TYPE_UINT32:
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_POINTER:
+	  if (gprcount < MAX_GPR_REGS)
+	    {
+	      stack->gpr[gprcount] = 0;
+	      stack->gpr[gprcount++] = *(long long *)(*p_argv);
+	      in_register = 1;
+	    }
+	  break;
+
+	case FFI_TYPE_FLOAT:
+	  if (ssecount < MAX_SSE_REGS)
+	    {
+	      float2sse (*(float *)(*p_argv), &stack->sse[ssecount++]);
+	      in_register = 1;
+	    }
+	  break;
+
+	case FFI_TYPE_DOUBLE:
+	  if (ssecount < MAX_SSE_REGS)
+	    {
+	      double2sse (*(double *)(*p_argv), &stack->sse[ssecount++]);
+	      in_register = 1;
+	    }
+	  break;
+	}
+
+      if (in_register)
+	continue;
+
+      /* Either all places in registers where filled, or this is a
+	 type that potentially goes into a memory slot.  */
+      if (examine_argument (*p_arg, 0, &g, &s) == 0
+	  || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
+	{
+	  /* Pass this argument in memory.  */
+	  argp = (void *)ALIGN(argp, (*p_arg)->alignment);
+	  memcpy (argp, *p_argv, (*p_arg)->size);
+	  argp += (*p_arg)->size;
+	}
+      else
+	{
+	  /* All easy cases are eliminated. Now fire the big guns.  */
+
+	  enum x86_64_reg_class classes[MAX_CLASSES];
+	  int offset = 0, j, num;
+	  void *a;
+
+	  num = classify_argument (*p_arg, classes, &offset);
+	  for (j=0, a=*p_argv; j<num; j++, a+=8)
+	    {
+	      switch (classes[j])
+		{
+		case X86_64_INTEGER_CLASS:
+		case X86_64_INTEGERSI_CLASS:
+		  stack->gpr[gprcount++] = *(long long *)a;
+		  break;
+		case X86_64_SSE_CLASS:
+		  floatfloat2sse (a, &stack->sse[ssecount++]);
+		  break;
+		case X86_64_SSESF_CLASS:
+		  float2sse (*(float *)a, &stack->sse[ssecount++]);
+		  break;
+		case X86_64_SSEDF_CLASS:
+		  double2sse (*(double *)a, &stack->sse[ssecount++]);
+		  break;
+		default:
+		  abort();
+		}
+	    }
+	}
+    }
+}
+
+/* Perform machine dependent cif processing.  */
+ffi_status
+ffi_prep_cif_machdep (ffi_cif *cif)
+{
+  int gprcount, ssecount, i, g, s;
+
+  gprcount = ssecount = 0;
+
+  /* Reset the byte count. We handle this size estimation here.  */
+  cif->bytes = 0;
+
+  /* If the return value should be passed in memory, pass the pointer
+     as the first argument. The actual memory isn't allocated here.  */
+  if (examine_argument (cif->rtype, 1, &g, &s) == 0)
+    gprcount = 1;
+
+  /* Go over all arguments and determine the way they should be passed.
+     If it's in a register and there is space for it, let that be so. If
+     not, add it's size to the stack byte count.  */
+  for (i=0; i<cif->nargs; i++)
+    {
+      if (examine_argument (cif->arg_types[i], 0, &g, &s) == 0
+	  || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
+	{
+	  /* This is passed in memory. First align to the basic type.  */
+	  cif->bytes = ALIGN(cif->bytes, cif->arg_types[i]->alignment);
+
+	  /* Stack arguments are *always* at least 8 byte aligned.  */
+	  cif->bytes = ALIGN(cif->bytes, 8);
+
+	  /* Now add the size of this argument.  */
+	  cif->bytes += cif->arg_types[i]->size;
+	}
+      else
+	{
+	  gprcount += g;
+	  ssecount += s;
+	}
+    }
+
+  /* Set the flag for the closures return.  */
+    switch (cif->rtype->type)
+    {
+    case FFI_TYPE_VOID:
+    case FFI_TYPE_STRUCT:
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_FLOAT:
+    case FFI_TYPE_DOUBLE:
+    case FFI_TYPE_LONGDOUBLE:
+      cif->flags = (unsigned) cif->rtype->type;
+      break;
+
+    case FFI_TYPE_UINT64:
+      cif->flags = FFI_TYPE_SINT64;
+      break;
+
+    default:
+      cif->flags = FFI_TYPE_INT;
+      break;
+    }
+
+  return FFI_OK;
+}
+
+typedef struct
+{
+  long gpr[2];
+  __int128_t sse[2];
+  long double st0;
+} return_value;
+
+void
+ffi_fill_return_value (return_value *rv, extended_cif *ecif)
+{
+  enum x86_64_reg_class classes[MAX_CLASSES];
+  int i = 0, num;
+  long *gpr = rv->gpr;
+  __int128_t *sse = rv->sse;
+  signed char sc;
+  signed short ss;
+
+  /* This is needed because of the way x86-64 handles signed short
+     integers.  */
+  switch (ecif->cif->rtype->type)
+    {
+    case FFI_TYPE_SINT8:
+      sc = *(signed char *)gpr;
+      *(long long *)ecif->rvalue = (long long)sc;
+      return;
+    case FFI_TYPE_SINT16:
+      ss = *(signed short *)gpr;
+      *(long long *)ecif->rvalue = (long long)ss;
+      return;
+    default:
+      /* Just continue.  */
+      ;
+    }
+
+  num = classify_argument (ecif->cif->rtype, classes, &i);
+
+  if (num == 0)
+    /* Return in memory.  */
+    ecif->rvalue = (void *) rv->gpr[0];
+  else if (num == 2 && classes[0] == X86_64_X87_CLASS &&
+	classes[1] == X86_64_X87UP_CLASS)
+    /* This is a long double (this is easiest to handle this way instead
+       of an eightbyte at a time as in the loop below.  */
+    *((long double *)ecif->rvalue) = rv->st0;
+  else
+    {
+      void *a;
+
+      for (i=0, a=ecif->rvalue; i<num; i++, a+=8)
+	{
+	  switch (classes[i])
+	    {
+	    case X86_64_INTEGER_CLASS:
+	    case X86_64_INTEGERSI_CLASS:
+	      *(long long *)a = *gpr;
+	      gpr++;
+	      break;
+	    case X86_64_SSE_CLASS:
+	      sse2floatfloat (sse++, a);
+	      break;
+	    case X86_64_SSESF_CLASS:
+	      *(float *)a = sse2float (sse++);
+	      break;
+	    case X86_64_SSEDF_CLASS:
+	      *(double *)a = sse2double (sse++);
+	      break;
+	    default:
+	      abort();
+	    }
+	}
+    }
+}
+
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_UNIX64(void (*)(stackLayout *, extended_cif *),
+			    void (*) (return_value *, extended_cif *),
+			    /*@out@*/ extended_cif *, 
+			    unsigned, /*@out@*/ unsigned *, void (*fn)());
+/*@=declundef@*/
+/*@=exportheader@*/
+
+void ffi_call(/*@dependent@*/ ffi_cif *cif, 
+	      void (*fn)(), 
+	      /*@out@*/ void *rvalue, 
+	      /*@dependent@*/ void **avalue)
+{
+  extended_cif ecif;
+  int dummy;
+
+  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) && 
+      (examine_argument (cif->rtype, 1, &dummy, &dummy) == 0))
+    {
+      /*@-sysunrecog@*/
+      ecif.rvalue = alloca(cif->rtype->size);
+      /*@=sysunrecog@*/
+    }
+  else
+    ecif.rvalue = rvalue;
+    
+  /* Stack must always be 16byte aligned. Make it so.  */
+  cif->bytes = ALIGN(cif->bytes, 16);
+  
+  switch (cif->abi) 
+    {
+    case FFI_SYSV:
+      /* Calling 32bit code from 64bit is not possible  */
+      FFI_ASSERT(0);
+      break;
+
+    case FFI_UNIX64:
+      /*@-usedef@*/
+      ffi_call_UNIX64 (ffi_prep_args, ffi_fill_return_value, &ecif,
+		       cif->bytes, ecif.rvalue, fn);
+      /*@=usedef@*/
+      break;
+
+    default:
+      FFI_ASSERT(0);
+      break;
+    }
+}
+
+#endif /* ifndef __x86_64__ */
Index: src/x86/sysv.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/x86/sysv.S,v
retrieving revision 1.4
diff -u -b -B -r1.4 sysv.S
--- src/x86/sysv.S	16 Jul 2001 17:10:53 -0000	1.4
+++ src/x86/sysv.S	18 Jul 2002 21:27:18 -0000
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   sysv.S - Copyright (c) 1996, 1998, 2001  Cygnus Solutions
+   sysv.S - Copyright (c) 1996, 1998, 2001, 2002  Cygnus Solutions
    
    X86 Foreign Function Interface 
 
@@ -23,6 +23,8 @@
    OTHER DEALINGS IN THE SOFTWARE.
    ----------------------------------------------------------------------- */
 
+#ifndef __x86_64__
+
 #define LIBFFI_ASM	
 #include <ffi.h>
 
@@ -163,3 +165,5 @@
 	.align 4
 .LEFDE1:
 	.set	.LLFDE1,.LEFDE1-.LSFDE1
+
+#endif /* ifndef __x86_64__ */
Index: src/x86/unix64.S
===================================================================
RCS file: src/x86/unix64.S
diff -N src/x86/unix64.S
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/x86/unix64.S	18 Jul 2002 21:27:18 -0000
@@ -0,0 +1,166 @@
+/* -----------------------------------------------------------------------
+   unix64.S - Copyright (c) 2002  Bo Thorsen <bo@suse.de>
+
+   x86-64 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 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.
+   ----------------------------------------------------------------------- */
+
+#ifdef __x86_64__
+#define LIBFFI_ASM	
+#include <ffi.h>
+
+	.section	.rodata
+.LC0:
+	.string	"asm in progress %lld\n"
+.LC1:
+	.string	"asm in progress\n"
+.text
+	.align	2
+.globl ffi_call_UNIX64
+        .type	ffi_call_UNIX64,@function
+
+ffi_call_UNIX64:
+.LFB1:
+        pushq	%rbp
+.LCFI0:
+        movq	%rsp, %rbp
+.LCFI1:
+	/* Save all arguments */
+	subq	$48, %rsp
+.LCFI2:
+	movq	%rdi, -8(%rbp)		/* ffi_prep_args	 */
+	movq	%rsi, -16(%rbp)		/* ffi_fill_return_value */
+	movq	%rdx, -24(%rbp)		/* ecif			 */
+	movq	%rcx, -32(%rbp)		/* cif->bytes		 */
+	movq	%r8, -40(%rbp)		/* ecif.rvalue		 */
+	movq	%r9, -48(%rbp)		/* fn			 */
+
+	/* Make room for all of the new args and the register args */
+	addl	$176, %ecx
+.LCFI3:
+	subq	%rcx, %rsp
+.LCFI4:
+	/* Setup the call to ffi_prep_args.  */
+	movq	%rdi, %rax		/* &ffi_prep_args	*/
+	movq	%rsp, %rdi		/* stackLayout		*/
+	movq	%rdx, %rsi		/* ecif			*/
+	call	*%rax			/* ffi_prep_args(stackLayout, ecif);*/ 
+
+	/* ffi_prep_args have put all the register contents into the  */
+	/* stackLayout struct. Now put the register values in place.  */
+	movq	(%rsp), %rdi
+	movq	8(%rsp), %rsi
+	movq	16(%rsp), %rdx
+	movq	24(%rsp), %rcx
+	movq	32(%rsp), %r8
+	movq	40(%rsp), %r9
+	movaps	48(%rsp), %xmm0
+	movaps	64(%rsp), %xmm1
+	movaps	80(%rsp), %xmm2
+	movaps	96(%rsp), %xmm3
+	movaps	112(%rsp), %xmm4
+	movaps	128(%rsp), %xmm5
+	movaps	144(%rsp), %xmm6
+	movaps	160(%rsp), %xmm7
+
+	/* Remove space for stackLayout so stack arguments are placed
+	   correctly for the call.  */
+.LCFI5:
+	addq	$176, %rsp
+.LCFI6:
+	/* Call the user function.  */
+	call	*-48(%rbp)
+
+	/* Make stack space for the return_value struct.  */
+	subq	$64, %rsp
+
+	/* Fill in all potential return values to this struct.  */
+	movq	%rax, (%rsp)
+	movq	%rdx, 8(%rsp)
+	movaps	%xmm0, 16(%rsp)
+	movaps	%xmm1, 32(%rsp)
+	fstpt	48(%rsp)
+
+	/* Now call ffi_fill_return_value.  */
+	movq	%rsp, %rdi		/* struct return_value	  */
+	movq	-24(%rbp), %rsi		/* ecif			  */
+	movq	-16(%rbp), %rax		/* &ffi_fill_return_value */
+	call	*%rax			/* call it		  */
+
+	/* And the work is done.  */
+        leave
+        ret
+.LFE1:
+.ffi_call_UNIX64_end:
+        .size    ffi_call_UNIX64,.ffi_call_UNIX64_end-ffi_call_UNIX64
+
+.text
+	.align	2
+.globl float2sse
+        .type	float2sse,@function
+float2sse:
+	/* Save the contents of this sse-float in a pointer.  */
+	movaps	%xmm0, (%rdi)
+	ret
+
+	.align	2
+.globl floatfloat2sse
+        .type	floatfloat2sse,@function
+floatfloat2sse:
+	/* Save the contents of these two sse-floats in a pointer.  */
+	movq	(%rdi), %xmm0
+	movaps	%xmm0, (%rsi)
+	ret
+
+	.align	2
+.globl double2sse
+        .type	double2sse,@function
+double2sse:
+	/* Save the contents of this sse-double in a pointer.  */
+	movaps	%xmm0, (%rdi)
+	ret
+
+	.align	2
+.globl sse2float
+        .type	sse2float,@function
+sse2float:
+	/* Save the contents of this sse-float in a pointer.  */
+	movaps	(%rdi), %xmm0
+	ret
+
+	.align	2
+.globl sse2double
+        .type	sse2double,@function
+sse2double:
+	/* Save the contents of this pointer in a sse-double.  */
+	movaps	(%rdi), %xmm0
+	ret
+
+	.align	2
+.globl sse2floatfloat
+        .type	sse2floatfloat,@function
+sse2floatfloat:
+	/* Save the contents of this pointer in two sse-floats.  */
+	movaps	(%rdi), %xmm0
+	movq	%xmm0, (%rsi)
+	ret
+	
+#endif /* __x86_64__  */


-- 

     Bo Thorsen                 |   Praestevejen 4
     Free software developer    |   5290 Marslev
     SuSE Labs                  |   Denmark


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