Merge branch 'master' of https://github.com/bivab/libffi Conflicts: ChangeLog
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
diff --git a/ChangeLog b/ChangeLog
index 806af18..a789f85 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2013-11-14 David Schneider <david.schneider@bivab.de>
+
+ * src/arm/ffi.c: Fix register allocation for mixed float and
+ doubles.
+ * testsuite/libffi.call/cls_many_mixed_float_double.c: Testcase
+ for many mixed float and double arguments.
+
2013-11-13 Alan Modra <amodra@gmail.com>
* doc/libffi.texi (Simple Example): Correct example code.
diff --git a/src/arm/ffi.c b/src/arm/ffi.c
index d52ad02..09883b1 100644
--- a/src/arm/ffi.c
+++ b/src/arm/ffi.c
@@ -861,7 +861,7 @@ static int vfp_type_p (ffi_type *t)
return 0;
}
-static void place_vfp_arg (ffi_cif *cif, ffi_type *t)
+static int place_vfp_arg (ffi_cif *cif, ffi_type *t)
{
int reg = cif->vfp_reg_free;
int nregs = t->size / sizeof (float);
@@ -894,9 +894,13 @@ static void place_vfp_arg (ffi_cif *cif, ffi_type *t)
reg += 1;
cif->vfp_reg_free = reg;
}
- return;
+ return 0;
next_reg: ;
}
+ // done, mark all regs as used
+ cif->vfp_reg_free = 16;
+ cif->vfp_used = 0xFFFF;
+ return 1;
}
static void layout_vfp_args (ffi_cif *cif)
@@ -911,7 +915,9 @@ static void layout_vfp_args (ffi_cif *cif)
for (i = 0; i < cif->nargs; i++)
{
ffi_type *t = cif->arg_types[i];
- if (vfp_type_p (t))
- place_vfp_arg (cif, t);
+ if (vfp_type_p (t) && place_vfp_arg (cif, t) == 1)
+ {
+ break;
+ }
}
}
diff --git a/testsuite/libffi.call/cls_many_mixed_float_double.c b/testsuite/libffi.call/cls_many_mixed_float_double.c
new file mode 100644
index 0000000..62b0697
--- /dev/null
+++ b/testsuite/libffi.call/cls_many_mixed_float_double.c
@@ -0,0 +1,55 @@
+/* Area: closure_call
+ Purpose: Check register allocation for closure calls with many float and double arguments
+ Limitations: none.
+ PR: none.
+ Originator: <david.schneider@picle.org> */
+
+/* { dg-do run } */
+#include "ffitest.h"
+#include <float.h>
+#include <math.h>
+
+#define NARGS 16
+
+static void cls_mixed_float_double_fn(ffi_cif* cif , void* ret, void** args,
+ void* userdata __UNUSED__)
+{
+ double r = 0;
+ unsigned int i;
+ double t;
+ for(i=0; i < cif->nargs; i++)
+ {
+ if(cif->arg_types[i] == &ffi_type_double) {
+ t = *(((double**)(args))[i]);
+ } else {
+ t = *(((float**)(args))[i]);
+ }
+ r += t;
+ }
+ *((double*)ret) = r;
+}
+typedef double (*cls_mixed)(double, float, double, double, double, double, double, float, float, double, float, float);
+
+int main (void)
+{
+ ffi_cif cif;
+ ffi_closure *closure;
+ void* code;
+ ffi_type *argtypes[12] = {&ffi_type_double, &ffi_type_float, &ffi_type_double,
+ &ffi_type_double, &ffi_type_double, &ffi_type_double,
+ &ffi_type_double, &ffi_type_float, &ffi_type_float,
+ &ffi_type_double, &ffi_type_float, &ffi_type_float};
+
+
+ closure = ffi_closure_alloc(sizeof(ffi_closure), (void**)&code);
+ if(closure ==NULL)
+ abort();
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 12, &ffi_type_double, argtypes) == FFI_OK);
+ CHECK(ffi_prep_closure_loc(closure, &cif, cls_mixed_float_double_fn, NULL, code) == FFI_OK);
+ double ret = ((cls_mixed)code)(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2);
+ ffi_closure_free(closure);
+ if(fabs(ret - 7.8) < FLT_EPSILON)
+ exit(0);
+ else
+ abort();
+}