public inbox for libffi-discuss@sourceware.org
 help / color / mirror / Atom feed
From: Richard Henderson <rth@twiddle.net>
To: libffi-discuss@sourceware.org
Subject: [PATCH 04/10] arm: Rewrite vfp_type_p
Date: Wed, 29 Oct 2014 20:06:00 -0000	[thread overview]
Message-ID: <1414613147-10917-5-git-send-email-rth@twiddle.net> (raw)
In-Reply-To: <1414613147-10917-1-git-send-email-rth@twiddle.net>

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 | 218 +++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 147 insertions(+), 71 deletions(-)

diff --git a/src/arm/ffi.c b/src/arm/ffi.c
index 5e5ad0a..d00ed89 100644
--- a/src/arm/ffi.c
+++ b/src/arm/ffi.c
@@ -34,7 +34,7 @@
 #include <stdlib.h>
 
 /* 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)
-    {
-    case FFI_TYPE_FLOAT:
-    case FFI_TYPE_DOUBLE:
-      *elt = (int) t->type;
-      *elnum = 1;
-      return 1;
+  ffi_type **elements = ty->elements;
+  int i, ret = -1;
 
-    case FFI_TYPE_STRUCT_VFP_FLOAT:
-      *elt = FFI_TYPE_FLOAT;
-      *elnum = t->size / sizeof (float);
-      return 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;
+      }
 
-    case FFI_TYPE_STRUCT_VFP_DOUBLE:
-      *elt = FFI_TYPE_DOUBLE;
-      *elnum = t->size / sizeof (double);
-      return 1;
+  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;
 
-    case FFI_TYPE_STRUCT:;
+  if (elements != NULL)
+    for (i = 0; elements[i]; ++i)
       {
-	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;
+        int t = elements[i]->type;
+        if (t == FFI_TYPE_STRUCT)
+          {
+            if (!is_hfa1 (elements[i], candidate))
+              return 0;
+          }
+        else if (t != candidate)
+          return 0;
       }
-    default:;
-    }
-  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 (ffi_type * t)
+vfp_type_p (const ffi_type *ty)
 {
-  int elt, elnum;
-  if (rec_vfp_type_p (t, &elt, &elnum))
+  ffi_type **elements;
+  int candidate, i;
+  size_t size, ele_count;
+
+  /* Quickest tests first.  */
+  switch (ty->type)
     {
-      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;
+    default:
+      return 0;
+    case FFI_TYPE_FLOAT:
+    case FFI_TYPE_DOUBLE:
+      return 0x100 + ty->type;
+    case FFI_TYPE_STRUCT:
+      break;
     }
-  return 0;
+
+  /* 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)
+    {
+      for (i = 0; ; ++i)
+        {
+          candidate = is_hfa0 (elements[i]);
+          if (candidate >= 0)
+            break;
+        }
+    }
+
+  /* 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;
     }
 }
-- 
1.9.3

  parent reply	other threads:[~2014-10-29 20:06 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-29 20:05 [PATCH 00/10] Go closures for arm Richard Henderson
2014-10-29 20:06 ` [PATCH 01/10] arm: Reindent arm/ffi.c Richard Henderson
2014-10-29 20:06 ` [PATCH 09/10] arm: Add argument space for the hidden struct return pointer Richard Henderson
2014-10-29 20:06 ` [PATCH 06/10] arm: Rewrite ffi_closure Richard Henderson
2014-10-29 20:06 ` [PATCH 07/10] arm: Remove internal FFI_TYPE constants Richard Henderson
2014-10-29 20:06 ` [PATCH 03/10] arm: Deref ffi_put_arg arguments Richard Henderson
2014-10-29 20:06 ` Richard Henderson [this message]
2014-10-29 20:06 ` [PATCH 05/10] arm: Rewrite ffi_call Richard Henderson
2014-10-29 20:06 ` [PATCH 10/10] arm: Add support for Go closures Richard Henderson
2014-10-29 20:06 ` [PATCH 08/10] arm: Add support for complex types Richard Henderson
2014-10-29 20:06 ` [PATCH 02/10] arm: Deref ffi_align argument Richard Henderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1414613147-10917-5-git-send-email-rth@twiddle.net \
    --to=rth@twiddle.net \
    --cc=libffi-discuss@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).