Merge pull request #406 from trofi/master

ia64: fix variadic function closures with FP arguments
diff --git a/src/ia64/ffi.c b/src/ia64/ffi.c
index b77a836..b1d04c3 100644
--- a/src/ia64/ffi.c
+++ b/src/ia64/ffi.c
@@ -220,8 +220,8 @@
 
 /* Perform machine dependent cif processing. */
 
-ffi_status
-ffi_prep_cif_machdep(ffi_cif *cif)
+static ffi_status
+ffi_prep_cif_machdep_core(ffi_cif *cif)
 {
   int flags;
 
@@ -271,6 +271,22 @@
   return FFI_OK;
 }
 
+ffi_status
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+  cif->nfixedargs = cif->nargs;
+  return ffi_prep_cif_machdep_core(cif);
+}
+
+ffi_status
+ffi_prep_cif_machdep_var(ffi_cif *cif,
+			 unsigned int nfixedargs,
+			 unsigned int ntotalargs MAYBE_UNUSED)
+{
+  cif->nfixedargs = nfixedargs;
+  return ffi_prep_cif_machdep_core(cif);
+}
+
 extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
 
 void
@@ -454,10 +470,11 @@
   ffi_cif *cif;
   void **avalue;
   ffi_type **p_arg;
-  long i, avn, gpcount, fpcount;
+  long i, avn, gpcount, fpcount, nfixedargs;
 
   cif = closure->cif;
   avn = cif->nargs;
+  nfixedargs = cif->nfixedargs;
   avalue = alloca (avn * sizeof (void *));
 
   /* If the structure return value is passed in memory get that location
@@ -468,6 +485,7 @@
   gpcount = fpcount = 0;
   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
     {
+      int named = i < nfixedargs;
       switch ((*p_arg)->type)
 	{
 	case FFI_TYPE_SINT8:
@@ -491,7 +509,7 @@
 	  break;
 
 	case FFI_TYPE_FLOAT:
-	  if (gpcount < 8 && fpcount < 8)
+	  if (named && gpcount < 8 && fpcount < 8)
 	    {
 	      fpreg *addr = &stack->fp_regs[fpcount++];
 	      float result;
@@ -505,7 +523,7 @@
 	  break;
 
 	case FFI_TYPE_DOUBLE:
-	  if (gpcount < 8 && fpcount < 8)
+	  if (named && gpcount < 8 && fpcount < 8)
 	    {
 	      fpreg *addr = &stack->fp_regs[fpcount++];
 	      double result;
@@ -521,7 +539,7 @@
 	case FFI_TYPE_LONGDOUBLE:
 	  if (gpcount & 1)
 	    gpcount++;
-	  if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
+	  if (LDBL_MANT_DIG == 64 && named && gpcount < 8 && fpcount < 8)
 	    {
 	      fpreg *addr = &stack->fp_regs[fpcount++];
 	      __float80 result;
diff --git a/src/ia64/ffitarget.h b/src/ia64/ffitarget.h
index e68cea6..fd5b9a0 100644
--- a/src/ia64/ffitarget.h
+++ b/src/ia64/ffitarget.h
@@ -50,6 +50,7 @@
 #define FFI_TRAMPOLINE_SIZE 24  /* Really the following struct, which 	*/
 				/* can be interpreted as a C function	*/
 				/* descriptor:				*/
+#define FFI_TARGET_SPECIFIC_VARIADIC 1
+#define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs
 
 #endif
-