From 2fbdb0f231cafdb77b025d3cd8afe90cda99b3ba Mon Sep 17 00:00:00 2001 From: David Schneider Date: Mon, 25 Mar 2013 13:26:02 +0100 Subject: [PATCH 01/11] use the absolute value to check the test result against an epsilon --- testsuite/libffi.call/many.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/testsuite/libffi.call/many.c b/testsuite/libffi.call/many.c index 4869ba9dd..67a367fd5 100644 --- a/testsuite/libffi.call/many.c +++ b/testsuite/libffi.call/many.c @@ -7,7 +7,9 @@ /* { dg-do run } */ #include "ffitest.h" +#include #include +#include static float many(float f1, float f2, @@ -62,7 +64,7 @@ int main (void) fa[8], fa[9], fa[10],fa[11],fa[12]); - if (f - ff < FLT_EPSILON) + if (fabs(f - ff) < FLT_EPSILON) exit(0); else abort(); From b9f013788f0f384c423ad963475aaacb55598135 Mon Sep 17 00:00:00 2001 From: David Schneider Date: Mon, 25 Mar 2013 13:27:36 +0100 Subject: [PATCH 02/11] add a testcase, that on ARM hardfloat needs more than the 8 VFP argument registers to pass arguments to a call --- testsuite/libffi.call/many_double.c | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 testsuite/libffi.call/many_double.c diff --git a/testsuite/libffi.call/many_double.c b/testsuite/libffi.call/many_double.c new file mode 100644 index 000000000..4ef8c8ab2 --- /dev/null +++ b/testsuite/libffi.call/many_double.c @@ -0,0 +1,70 @@ +/* Area: ffi_call + Purpose: Check return value double, with many arguments + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" + +#include +#include +#include + +static double many(double f1, + double f2, + double f3, + double f4, + double f5, + double f6, + double f7, + double f8, + double f9, + double f10, + double f11, + double f12, + double f13) +{ +#if 0 + printf("%f %f %f %f %f %f %f %f %f %f %f %f %f\n", + (double) f1, (double) f2, (double) f3, (double) f4, (double) f5, + (double) f6, (double) f7, (double) f8, (double) f9, (double) f10, + (double) f11, (double) f12, (double) f13); +#endif + + return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13); +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[13]; + void *values[13]; + double fa[13]; + double f, ff; + int i; + + for (i = 0; i < 13; i++) + { + args[i] = &ffi_type_double; + values[i] = &fa[i]; + fa[i] = (double) i; + } + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13, + &ffi_type_double, args) == FFI_OK); + + ffi_call(&cif, FFI_FN(many), &f, values); + + ff = many(fa[0], fa[1], + fa[2], fa[3], + fa[4], fa[5], + fa[6], fa[7], + fa[8], fa[9], + fa[10],fa[11],fa[12]); + if (fabs(f - ff) < FLT_EPSILON) + exit(0); + else + abort(); +} From 7d1048c471bb4b1f9d67a9e9f8e95f9a1d2e6d45 Mon Sep 17 00:00:00 2001 From: David Schneider Date: Tue, 26 Mar 2013 11:33:33 +0100 Subject: [PATCH 03/11] extract code to align the argument storage pointer to a helper function --- src/arm/ffi.c | 55 +++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/arm/ffi.c b/src/arm/ffi.c index 3ccceb9a5..4b5fb3dcb 100644 --- a/src/arm/ffi.c +++ b/src/arm/ffi.c @@ -37,6 +37,31 @@ static int vfp_type_p (ffi_type *); static void layout_vfp_args (ffi_cif *); +static char* ffi_align(ffi_type **p_arg, char *argp) +{ + /* Align if necessary */ + register size_t alignment = (*p_arg)->alignment; + if (alignment < 4) + { + alignment = 4; + } +#ifdef _WIN32_WCE + if (alignment > 4) + { + alignment = 4; + } +#endif + if ((alignment - 1) & (unsigned) argp) + { + argp = (char *) ALIGN(argp, alignment); + } + + if ((*p_arg)->type == FFI_TYPE_STRUCT) + { + argp = (char *) ALIGN(argp, 4); + } + return argp; +} /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments @@ -65,7 +90,6 @@ int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space) i--, p_arg++) { size_t z; - size_t alignment; /* Allocated in VFP registers. */ if (ecif->cif->abi == FFI_VFP @@ -81,19 +105,7 @@ int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space) p_argv++; continue; } - - /* Align if necessary */ - alignment = (*p_arg)->alignment; -#ifdef _WIN32_WCE - if (alignment > 4) - alignment = 4; -#endif - if ((alignment - 1) & (unsigned) argp) { - argp = (char *) ALIGN(argp, alignment); - } - - if ((*p_arg)->type == FFI_TYPE_STRUCT) - argp = (char *) ALIGN(argp, 4); + argp = ffi_align(p_arg, argp); z = (*p_arg)->size; if (z < sizeof(int)) @@ -329,7 +341,6 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) { size_t z; - size_t alignment; if (cif->abi == FFI_VFP && vi < cif->vfp_nargs && vfp_type_p (*p_arg)) @@ -337,19 +348,7 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]); continue; } - - alignment = (*p_arg)->alignment; - if (alignment < 4) - alignment = 4; -#ifdef _WIN32_WCE - else - if (alignment > 4) - alignment = 4; -#endif - /* Align if necessary */ - if ((alignment - 1) & (unsigned) argp) { - argp = (char *) ALIGN(argp, alignment); - } + argp = ffi_align(p_arg, argp); z = (*p_arg)->size; From 5df6b7944a4225b6eb329f3886be64e04e966f29 Mon Sep 17 00:00:00 2001 From: David Schneider Date: Tue, 26 Mar 2013 14:02:21 +0100 Subject: [PATCH 04/11] extract setting of arguments to be passed to a helper function --- src/arm/ffi.c | 90 ++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/src/arm/ffi.c b/src/arm/ffi.c index 4b5fb3dcb..c670465cd 100644 --- a/src/arm/ffi.c +++ b/src/arm/ffi.c @@ -62,6 +62,53 @@ static char* ffi_align(ffi_type **p_arg, char *argp) } return argp; } + +static size_t ffi_put_arg(ffi_type **arg_type, void **arg, char *stack) +{ + register char* argp = stack; + register ffi_type **p_arg = arg_type; + register void **p_argv = arg; + register size_t z = (*p_arg)->size; + if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + memcpy(argp, *p_argv, (*p_arg)->size); + break; + + default: + FFI_ASSERT(0); + } + } + else if (z == sizeof(int)) + { + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + } + else + { + memcpy(argp, *p_argv, z); + } + return z; + +} /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments @@ -105,48 +152,9 @@ int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space) p_argv++; continue; } - argp = ffi_align(p_arg, argp); - - z = (*p_arg)->size; - if (z < sizeof(int)) - { - z = sizeof(int); - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); - break; - - case FFI_TYPE_UINT8: - *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); - break; - - case FFI_TYPE_SINT16: - *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); - break; - - case FFI_TYPE_UINT16: - *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); - break; - - case FFI_TYPE_STRUCT: - memcpy(argp, *p_argv, (*p_arg)->size); - break; - - default: - FFI_ASSERT(0); - } - } - else if (z == sizeof(int)) - { - *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); - } - else - { - memcpy(argp, *p_argv, z); - } + argp = ffi_align(p_arg, argp); + argp += ffi_put_arg(p_arg, p_argv, argp); p_argv++; - argp += z; } /* Indicate the VFP registers used. */ From 3a352b8a8252400a83de22c7c424bf1887b4a2ef Mon Sep 17 00:00:00 2001 From: David Schneider Date: Tue, 26 Mar 2013 14:24:04 +0100 Subject: [PATCH 05/11] move the hardfloat specific argument copying code to the helper function --- src/arm/ffi.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/arm/ffi.c b/src/arm/ffi.c index c670465cd..1fb71999f 100644 --- a/src/arm/ffi.c +++ b/src/arm/ffi.c @@ -71,8 +71,8 @@ static size_t ffi_put_arg(ffi_type **arg_type, void **arg, char *stack) register size_t z = (*p_arg)->size; if (z < sizeof(int)) { - z = sizeof(int); - switch ((*p_arg)->type) + z = sizeof(int); + switch ((*p_arg)->type) { case FFI_TYPE_SINT8: *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); @@ -100,14 +100,20 @@ static size_t ffi_put_arg(ffi_type **arg_type, void **arg, char *stack) } else if (z == sizeof(int)) { - *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + if ((*p_arg)->type == FFI_TYPE_FLOAT) + *(float *) argp = *(float *)(* p_argv); + else + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); } + else if (z == sizeof(double) && (*p_arg)->type == FFI_TYPE_DOUBLE) + { + *(double *) argp = *(double *)(* p_argv); + } else { memcpy(argp, *p_argv, z); } return z; - } /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments @@ -136,19 +142,13 @@ int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space) (i != 0); i--, p_arg++) { - size_t z; /* Allocated in VFP registers. */ if (ecif->cif->abi == FFI_VFP && vi < ecif->cif->vfp_nargs && vfp_type_p (*p_arg)) { - float* vfp_slot = vfp_space + ecif->cif->vfp_args[vi++]; - if ((*p_arg)->type == FFI_TYPE_FLOAT) - *((float*)vfp_slot) = *((float*)*p_argv); - else if ((*p_arg)->type == FFI_TYPE_DOUBLE) - *((double*)vfp_slot) = *((double*)*p_argv); - else - memcpy(vfp_slot, *p_argv, (*p_arg)->size); + char *vfp_slot = (char *)(vfp_space + ecif->cif->vfp_args[vi++]); + ffi_put_arg(p_arg, p_argv, vfp_slot); p_argv++; continue; } From 0f2ff2d4c92719be8936179f9ab674f4d1a3fd14 Mon Sep 17 00:00:00 2001 From: David Schneider Date: Tue, 26 Mar 2013 19:22:02 +0100 Subject: [PATCH 06/11] separate ARM ffi_prepare_args in a version implementing the simple SYSV calling convention and one for the hard-float calling convention --- src/arm/ffi.c | 26 +++++++++++--------------- src/arm/sysv.S | 4 ++-- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/arm/ffi.c b/src/arm/ffi.c index 1fb71999f..d3dba9ca6 100644 --- a/src/arm/ffi.c +++ b/src/arm/ffi.c @@ -122,14 +122,14 @@ static size_t ffi_put_arg(ffi_type **arg_type, void **arg, char *stack) value is cif->vfp_used (word bitset of VFP regs used for passing arguments). These are only used for the VFP hard-float ABI. */ -int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space) +int ffi_prep_args_SYSV(char *stack, extended_cif *ecif, float *vfp_space) { - register unsigned int i, vi = 0; + register unsigned int i; register void **p_argv; register char *argp; register ffi_type **p_arg; - argp = stack; + if ( ecif->cif->flags == FFI_TYPE_STRUCT ) { *(void **) argp = ecif->rvalue; @@ -140,23 +140,19 @@ int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space) for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); - i--, p_arg++) + i--, p_arg++, p_argv++) { - - /* Allocated in VFP registers. */ - if (ecif->cif->abi == FFI_VFP - && vi < ecif->cif->vfp_nargs && vfp_type_p (*p_arg)) - { - char *vfp_slot = (char *)(vfp_space + ecif->cif->vfp_args[vi++]); - ffi_put_arg(p_arg, p_argv, vfp_slot); - p_argv++; - continue; - } argp = ffi_align(p_arg, argp); argp += ffi_put_arg(p_arg, p_argv, argp); - p_argv++; } + return 0; +} + +int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space) +{ + // make sure we are using FFI_VFP + FFI_ASSERT(ecif->cif->abi == FFI_VFP); /* Indicate the VFP registers used. */ return ecif->cif->vfp_used; } diff --git a/src/arm/sysv.S b/src/arm/sysv.S index fb38cd640..de1809b5e 100644 --- a/src/arm/sysv.S +++ b/src/arm/sysv.S @@ -187,7 +187,7 @@ ARM_FUNC_START ffi_call_SYSV @ r1 already set @ Call ffi_prep_args(stack, &ecif) - bl CNAME(ffi_prep_args) + bl CNAME(ffi_prep_args_SYSV) @ move first 4 parameters in registers ldmia sp, {r0-r3} @@ -364,7 +364,7 @@ ARM_FUNC_START ffi_call_VFP sub r2, fp, #64 @ VFP scratch space @ Call ffi_prep_args(stack, &ecif, vfp_space) - bl CNAME(ffi_prep_args) + bl CNAME(ffi_prep_args_VFP) @ Load VFP register args if needed cmp r0, #0 From 3c1608613ab3c2184222b98c5482cddedd6b559b Mon Sep 17 00:00:00 2001 From: David Schneider Date: Tue, 26 Mar 2013 19:24:47 +0100 Subject: [PATCH 07/11] extend ffi_prepare_args for FFI_VFP (hard-float ABI), fixing an issue with passing VFP arguments in VFP registers and the stack, while at the same time not using all core registers. --- src/arm/ffi.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/arm/ffi.c b/src/arm/ffi.c index d3dba9ca6..cce24d814 100644 --- a/src/arm/ffi.c +++ b/src/arm/ffi.c @@ -153,6 +153,76 @@ int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space) { // make sure we are using FFI_VFP FFI_ASSERT(ecif->cif->abi == FFI_VFP); + + register unsigned int i, vi = 0; + register void **p_argv; + register char *argp, *regp, *eo_regp; + register ffi_type **p_arg; + char stack_used = 0; + char done_with_regs = 0; + char is_vfp_type; + + /* the first 4 words on the stack are used for values passed in core + * registers. */ + regp = stack; + eo_regp = argp = regp + 16; + + + /* if the function returns an FFI_TYPE_STRUCT in memory, that address is + * passed in r0 to the function */ + if ( ecif->cif->flags == FFI_TYPE_STRUCT ) { + *(void **) regp = ecif->rvalue; + regp += 4; + } + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0); + i--, p_arg++, p_argv++) + { + is_vfp_type = vfp_type_p (*p_arg); + + /* Allocated in VFP registers. */ + if(vi < ecif->cif->vfp_nargs && is_vfp_type) + { + char *vfp_slot = (char *)(vfp_space + ecif->cif->vfp_args[vi++]); + ffi_put_arg(p_arg, p_argv, vfp_slot); + continue; + } + /* Try allocating in core registers. */ + else if (!done_with_regs && !is_vfp_type) + { + char *tregp = ffi_align(p_arg, regp); + size_t size = (*p_arg)->size; + size = (size < 4)? 4 : size; // pad + /* Check if there is space left in the aligned register area to place + * the argument */ + if(tregp + size <= eo_regp) + { + regp = tregp + ffi_put_arg(p_arg, p_argv, tregp); + done_with_regs = (regp == argp); + // ensure we did not write into the stack area + FFI_ASSERT(regp <= argp); + continue; + } + /* In case there are no arguments in the stack area yet, + the argument is passed in the remaining core registers and on the + stack. */ + else if (!stack_used) + { + stack_used = 1; + done_with_regs = 1; + argp = tregp + ffi_put_arg(p_arg, p_argv, tregp); + FFI_ASSERT(eo_regp < argp); + continue; + } + } + /* Base case, arguments are passed on the stack */ + stack_used = 1; + argp = ffi_align(p_arg, argp); + argp += ffi_put_arg(p_arg, p_argv, argp); + } /* Indicate the VFP registers used. */ return ecif->cif->vfp_used; } From dd26f1f39c54861c5b91931f0f37a72942c2a072 Mon Sep 17 00:00:00 2001 From: David Schneider Date: Thu, 28 Mar 2013 15:39:01 +0100 Subject: [PATCH 08/11] add a failing test for closures on ARM hardfloat --- testsuite/libffi.call/cls_many_mixed_args.c | 68 +++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 testsuite/libffi.call/cls_many_mixed_args.c diff --git a/testsuite/libffi.call/cls_many_mixed_args.c b/testsuite/libffi.call/cls_many_mixed_args.c new file mode 100644 index 000000000..fc75b1d1a --- /dev/null +++ b/testsuite/libffi.call/cls_many_mixed_args.c @@ -0,0 +1,68 @@ +/* Area: closure_call + Purpose: Check closures called with many args of mixed types + Limitations: none. + PR: none. + Originator: */ + +/* { dg-do run } */ +#include "ffitest.h" +#include +#include + +#define NARGS 12 + +static void cls_ret_double_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + int i; + double r; + double t; + for(i = 0; i < NARGS; i++) + { + if(i == 8) + { + t = *(long int *)args[i]; + CHECK(t == i+1); + } + else + { + t = *(double *)args[i]; + CHECK(fabs(t - ((i+1) * 0.1)) < FLT_EPSILON); + } + r += t; + } + *(double *)resp = r; +} +typedef double (*cls_ret_double)(double, double, double, double, double, double, double, double, long int, double, double, double); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[NARGS]; + double res; + int i; + double expected = 15.9; + + for(i = 0; i < NARGS; i++) + { + if(i == 8) + cl_arg_types[i] = &ffi_type_slong; + else + cl_arg_types[i] = &ffi_type_double; + } + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, NARGS, + &ffi_type_double, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_double_fn, NULL, code) == FFI_OK); + + res = (((cls_ret_double)code))(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 9, + 1.0, 1.1, 1.2); + if (abs(res - expected) < FLT_EPSILON) + exit(0); + else + abort(); +} From b41120981e5e49ca2da10b94b154775f50da5f36 Mon Sep 17 00:00:00 2001 From: David Schneider Date: Wed, 27 Mar 2013 16:38:35 +0100 Subject: [PATCH 09/11] create separated versions of ffi_prep_incoming_args_* for SYSV and VFP ABIs. The different versions will be called depending on the value of cif->abi --- src/arm/ffi.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++--- src/arm/sysv.S | 6 +++--- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/arm/ffi.c b/src/arm/ffi.c index cce24d814..0165d6454 100644 --- a/src/arm/ffi.c +++ b/src/arm/ffi.c @@ -357,6 +357,9 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, void** args, ffi_cif* cif, float *vfp_stack); +static void ffi_prep_incoming_args_VFP (char *stack, void **ret, + void** args, ffi_cif* cif, float *vfp_stack); + void ffi_closure_SYSV (ffi_closure *); void ffi_closure_VFP (ffi_closure *); @@ -364,7 +367,7 @@ void ffi_closure_VFP (ffi_closure *); /* This function is jumped to by the trampoline */ unsigned int -ffi_closure_SYSV_inner (closure, respp, args, vfp_args) +ffi_closure_inner (closure, respp, args, vfp_args) ffi_closure *closure; void **respp; void *args; @@ -382,8 +385,10 @@ ffi_closure_SYSV_inner (closure, respp, args, vfp_args) * value on the stack; and if the function returns * a structure, it will re-set RESP to point to the * structure return address. */ - - ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args); + if (cif->abi == FFI_VFP) + ffi_prep_incoming_args_VFP(args, respp, arg_area, cif, vfp_args); + else + ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args); (closure->fun) (cif, *respp, arg_area, closure->user_data); @@ -397,6 +402,47 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, /* Used only under VFP hard-float ABI. */ float *vfp_stack) /*@=exportheader@*/ +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if ( cif->flags == FFI_TYPE_STRUCT ) { + *rvalue = *(void **) argp; + argp += 4; + } + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + { + size_t z; + + argp = ffi_align(p_arg, argp); + + z = (*p_arg)->size; + + /* because we're little endian, this is what it turns into. */ + + *p_argv = (void*) argp; + + p_argv++; + argp += z; + } + + return; +} + +/*@-exportheader@*/ +static void +ffi_prep_incoming_args_VFP(char *stack, void **rvalue, + void **avalue, ffi_cif *cif, + /* Used only under VFP hard-float ABI. */ + float *vfp_stack) +/*@=exportheader@*/ { register unsigned int i, vi = 0; register void **p_argv; diff --git a/src/arm/sysv.S b/src/arm/sysv.S index de1809b5e..454dfc942 100644 --- a/src/arm/sysv.S +++ b/src/arm/sysv.S @@ -260,7 +260,7 @@ LSYM(Lepilogue): /* unsigned int FFI_HIDDEN - ffi_closure_SYSV_inner (closure, respp, args) + ffi_closure_inner (closure, respp, args) ffi_closure *closure; void **respp; void *args; @@ -276,7 +276,7 @@ ARM_FUNC_START ffi_closure_SYSV sub sp, sp, #16 str sp, [sp, #8] add r1, sp, #8 - bl CNAME(ffi_closure_SYSV_inner) + bl CNAME(ffi_closure_inner) cmp r0, #FFI_TYPE_INT beq .Lretint @@ -446,7 +446,7 @@ ARM_FUNC_START ffi_closure_VFP sub sp, sp, #72 str sp, [sp, #64] add r1, sp, #64 - bl CNAME(ffi_closure_SYSV_inner) + bl CNAME(ffi_closure_inner) cmp r0, #FFI_TYPE_INT beq .Lretint_vfp From 9708e7cf09f1bf815f4d6485eb1f180fabb35804 Mon Sep 17 00:00:00 2001 From: David Schneider Date: Wed, 27 Mar 2013 19:31:04 +0100 Subject: [PATCH 10/11] folow the ARM hard-float ABI in ffi_prep_incoming_args_VFP --- src/arm/ffi.c | 73 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/src/arm/ffi.c b/src/arm/ffi.c index 0165d6454..4c3b146c4 100644 --- a/src/arm/ffi.c +++ b/src/arm/ffi.c @@ -446,38 +446,75 @@ ffi_prep_incoming_args_VFP(char *stack, void **rvalue, { register unsigned int i, vi = 0; register void **p_argv; - register char *argp; + register char *argp, *regp, *eo_regp; register ffi_type **p_arg; + char done_with_regs = 0; + char stack_used = 0; + char is_vfp_type; - argp = stack; + FFI_ASSERT(cif->abi == FFI_VFP); + regp = stack; + eo_regp = argp = regp + 16; if ( cif->flags == FFI_TYPE_STRUCT ) { - *rvalue = *(void **) argp; - argp += 4; + *rvalue = *(void **) regp; + regp += 4; } p_argv = avalue; for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) { - size_t z; - - if (cif->abi == FFI_VFP - && vi < cif->vfp_nargs && vfp_type_p (*p_arg)) - { - *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]); - continue; - } - argp = ffi_align(p_arg, argp); + size_t z; + is_vfp_type = vfp_type_p (*p_arg); - z = (*p_arg)->size; + if(vi < cif->vfp_nargs && is_vfp_type) + { + *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]); + continue; + } + else if (!done_with_regs && !is_vfp_type) + { + char* tregp = ffi_align(p_arg, regp); - /* because we're little endian, this is what it turns into. */ + z = (*p_arg)->size; + z = (z < 4)? 4 : z; // pad + + /* if the arguments either fits into the registers or uses registers + * and stack, while we haven't read other things from the stack */ + if(tregp + z <= eo_regp || !stack_used) + { + /* because we're little endian, this is what it turns into. */ + *p_argv = (void*) tregp; + + p_argv++; + regp = tregp + z; + /* if regp points above the end of the register area */ + if(regp >= eo_regp) + { + /* sanity check that we haven't read from the stack area before + * reaching this point */ + FFI_ASSERT(argp <= regp); + FFI_ASSERT(argp == stack + 16); + argp = regp; + done_with_regs = 1; + stack_used = 1; + } + continue; + } + } + stack_used = 1; - *p_argv = (void*) argp; + argp = ffi_align(p_arg, argp); - p_argv++; - argp += z; + z = (*p_arg)->size; + + /* because we're little endian, this is what it turns into. */ + + *p_argv = (void*) argp; + + p_argv++; + argp += z; } return; From 4750e3c662fd9569cb3e2d28f539685fd1ca8caf Mon Sep 17 00:00:00 2001 From: David Schneider Date: Thu, 28 Mar 2013 16:56:36 +0100 Subject: [PATCH 11/11] update changelog --- ChangeLog | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ChangeLog b/ChangeLog index e0b057c79..4603e6818 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2013-03-28 David Schneider + + * src/arm/ffi.c: Fix support for ARM hard-float calling convention. + * src/arm/sysv.S: call different methods for SYSV and VFP ABIs. + * testsuite/libffi.call/cls_many_mixed_args.c: testcase for a closure with + mixed arguments, many doubles. + * testsuite/libffi.call/many_double.c: testcase for calling a function using + more than 8 doubles. + * testcase/libffi.call/many.c: use absolute value to check result against an + epsilon + 2013-03-17 Anthony Green * README: Update for 3.0.13.