From a74a3aaddbcc730d9aa0a4787f136c9cc19b82b3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Oct 2014 01:21:22 -0400 Subject: [PATCH] arm: Rewrite vfp_type_p Do not modify the ffi_type. Rearrange the tests so that we quickly eliminate structures that cannot match. Return an encoded value of element count and base type. --- src/arm/ffi.c | 226 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 151 insertions(+), 75 deletions(-) diff --git a/src/arm/ffi.c b/src/arm/ffi.c index 5e5ad0ae..d00ed891 100644 --- a/src/arm/ffi.c +++ b/src/arm/ffi.c @@ -34,7 +34,7 @@ #include /* Forward declares. */ -static int vfp_type_p (ffi_type *); +static int vfp_type_p (const ffi_type *); static void layout_vfp_args (ffi_cif *); int ffi_prep_args_SYSV (char *stack, extended_cif *ecif, float *vfp_space); @@ -141,7 +141,6 @@ ffi_prep_args_VFP (char *stack, extended_cif * ecif, float *vfp_space) register ffi_type **p_arg; char stack_used = 0; char done_with_regs = 0; - char is_vfp_type; /* Make sure we are using FFI_VFP. */ FFI_ASSERT (ecif->cif->abi == FFI_VFP); @@ -164,7 +163,7 @@ ffi_prep_args_VFP (char *stack, extended_cif * ecif, float *vfp_space) 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); + int is_vfp_type = vfp_type_p (*p_arg); /* Allocated in VFP registers. */ if (vi < ecif->cif->vfp_nargs && is_vfp_type) @@ -214,7 +213,6 @@ ffi_prep_args_VFP (char *stack, extended_cif * ecif, float *vfp_space) ffi_status ffi_prep_cif_machdep (ffi_cif * cif) { - int type_code; /* Round the stack up to a multiple of 8 bytes. This isn't needed everywhere, but it is on some platforms, and it doesn't harm anything when it isn't needed. */ @@ -235,13 +233,25 @@ ffi_prep_cif_machdep (ffi_cif * cif) break; case FFI_TYPE_STRUCT: - if (cif->abi == FFI_VFP && (type_code = vfp_type_p (cif->rtype)) != 0) + if (cif->abi == FFI_VFP) { - /* A Composite Type passed in VFP registers, either - FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */ - cif->flags = (unsigned) type_code; + int h = vfp_type_p (cif->rtype); + if (h) + { + int ele_count = h >> 8; + int type_code = h & 0xff; + if (ele_count > 1) + { + if (type_code == FFI_TYPE_FLOAT) + type_code = FFI_TYPE_STRUCT_VFP_FLOAT; + else + type_code = FFI_TYPE_STRUCT_VFP_DOUBLE; + } + cif->flags = type_code; + break; + } } - else if (cif->rtype->size <= 4) + if (cif->rtype->size <= 4) { /* A Composite Type not larger than 4 bytes is returned in r0. */ cif->flags = (unsigned) FFI_TYPE_INT; @@ -446,7 +456,6 @@ ffi_prep_incoming_args_VFP (char *stack, void **rvalue, register ffi_type **p_arg; char done_with_regs = 0; char stack_used = 0; - char is_vfp_type; FFI_ASSERT (cif->abi == FFI_VFP); regp = stack; @@ -462,8 +471,8 @@ ffi_prep_incoming_args_VFP (char *stack, void **rvalue, for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) { + int is_vfp_type = vfp_type_p (*p_arg); size_t z; - is_vfp_type = vfp_type_p (*p_arg); if (vi < cif->vfp_nargs && is_vfp_type) { @@ -820,81 +829,150 @@ ffi_prep_closure_loc (ffi_closure * closure, /* Below are routines for VFP hard-float support. */ +/* A subroutine of vfp_type_p. Given a structure type, return the type code + of the first non-structure element. Recurse for structure elements. + Return -1 if the structure is in fact empty, i.e. no nested elements. */ + static int -rec_vfp_type_p (ffi_type * t, int *elt, int *elnum) +is_hfa0 (const ffi_type *ty) { - switch (t->type) + ffi_type **elements = ty->elements; + int i, ret = -1; + + if (elements != NULL) + for (i = 0; elements[i]; ++i) + { + ret = elements[i]->type; + if (ret == FFI_TYPE_STRUCT) + { + ret = is_hfa0 (elements[i]); + if (ret < 0) + continue; + } + break; + } + + return ret; +} + +/* A subroutine of vfp_type_p. Given a structure type, return true if all + of the non-structure elements are the same as CANDIDATE. */ + +static int +is_hfa1 (const ffi_type *ty, int candidate) +{ + ffi_type **elements = ty->elements; + int i; + + if (elements != NULL) + for (i = 0; elements[i]; ++i) + { + int t = elements[i]->type; + if (t == FFI_TYPE_STRUCT) + { + if (!is_hfa1 (elements[i], candidate)) + return 0; + } + else if (t != candidate) + return 0; + } + + return 1; +} + +/* Determine if TY is an homogenous floating point aggregate (HFA). + That is, a structure consisting of 1 to 4 members of all the same type, + where that type is a floating point scalar. + + Returns non-zero iff TY is an HFA. The result is an encoded value where + bits 0-7 contain the type code, and bits 8-10 contain the element count. */ + +static int +vfp_type_p (const ffi_type *ty) +{ + ffi_type **elements; + int candidate, i; + size_t size, ele_count; + + /* Quickest tests first. */ + switch (ty->type) { + default: + return 0; case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: - *elt = (int) t->type; - *elnum = 1; - return 1; - - case FFI_TYPE_STRUCT_VFP_FLOAT: - *elt = FFI_TYPE_FLOAT; - *elnum = t->size / sizeof (float); - return 1; - - case FFI_TYPE_STRUCT_VFP_DOUBLE: - *elt = FFI_TYPE_DOUBLE; - *elnum = t->size / sizeof (double); - return 1; - - case FFI_TYPE_STRUCT:; - { - int base_elt = 0, total_elnum = 0; - ffi_type **el = t->elements; - while (*el) - { - int el_elt = 0, el_elnum = 0; - if (!rec_vfp_type_p (*el, &el_elt, &el_elnum) - || (base_elt && base_elt != el_elt) - || total_elnum + el_elnum > 4) - return 0; - base_elt = el_elt; - total_elnum += el_elnum; - el++; - } - *elnum = total_elnum; - *elt = base_elt; - return 1; - } - default:; + return 0x100 + ty->type; + case FFI_TYPE_STRUCT: + break; } - return 0; -} -static int -vfp_type_p (ffi_type * t) -{ - int elt, elnum; - if (rec_vfp_type_p (t, &elt, &elnum)) + /* No HFA types are smaller than 4 bytes, or larger than 32 bytes. */ + size = ty->size; + if (size < 4 || size > 32) + return 0; + + /* Find the type of the first non-structure member. */ + elements = ty->elements; + candidate = elements[0]->type; + if (candidate == FFI_TYPE_STRUCT) { - if (t->type == FFI_TYPE_STRUCT) - { - if (elnum == 1) - t->type = elt; - else - t->type = (elt == FFI_TYPE_FLOAT - ? FFI_TYPE_STRUCT_VFP_FLOAT - : FFI_TYPE_STRUCT_VFP_DOUBLE); - } - return (int) t->type; + for (i = 0; ; ++i) + { + candidate = is_hfa0 (elements[i]); + if (candidate >= 0) + break; + } } - return 0; + + /* If the first member is not a floating point type, it's not an HFA. + Also quickly re-check the size of the structure. */ + switch (candidate) + { + case FFI_TYPE_FLOAT: + ele_count = size / sizeof(float); + if (size != ele_count * sizeof(float)) + return 0; + break; + case FFI_TYPE_DOUBLE: + ele_count = size / sizeof(double); + if (size != ele_count * sizeof(double)) + return 0; + break; + default: + return 0; + } + if (ele_count > 4) + return 0; + + /* Finally, make sure that all scalar elements are the same type. */ + for (i = 0; elements[i]; ++i) + { + if (elements[i]->type == FFI_TYPE_STRUCT) + { + if (!is_hfa1 (elements[i], candidate)) + return 0; + } + else if (elements[i]->type != candidate) + return 0; + } + + /* All tests succeeded. Encode the result. */ + return (ele_count << 8) | candidate; } static int -place_vfp_arg (ffi_cif * cif, ffi_type * t) +place_vfp_arg (ffi_cif *cif, int h) { - short reg = cif->vfp_reg_free; - int nregs = t->size / sizeof (float); - int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT - || t->type == FFI_TYPE_FLOAT) ? 1 : 2); + unsigned short reg = cif->vfp_reg_free; + int align = 1, nregs = h >> 8; + + if ((h & 0xff) == FFI_TYPE_DOUBLE) + align = 2, nregs *= 2; + /* Align register number. */ if ((reg & 1) && align == 2) reg++; + while (reg + nregs <= 16) { int s, new_used = 0; @@ -940,10 +1018,8 @@ 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) == 1) - { - break; - } + int h = vfp_type_p (cif->arg_types[i]); + if (h && place_vfp_arg (cif, h) == 1) + break; } }