diff libffi/src/arc/ffi.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libffi/src/arc/ffi.c	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,268 @@
+/* -----------------------------------------------------------------------
+   ffi.c - Copyright (c) 2013  Synopsys, Inc. (www.synopsys.com)
+   
+   ARC Foreign Function Interface 
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <sys/cachectl.h>
+
+/* for little endian ARC, the code is in fact stored as mixed endian for
+   performance reasons */
+#if __BIG_ENDIAN__
+#define CODE_ENDIAN(x) (x)
+#else
+#define CODE_ENDIAN(x) ( (((uint32_t) (x)) << 16) | (((uint32_t) (x)) >> 16))
+#endif
+
+/* ffi_prep_args is called by the assembly routine once stack
+   space has been allocated for the function's arguments.  */
+
+void
+ffi_prep_args (char *stack, extended_cif * ecif)
+{
+  unsigned int i;
+  int tmp;
+  void **p_argv;
+  char *argp;
+  ffi_type **p_arg;
+
+  tmp = 0;
+  argp = stack;
+
+  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
+    {
+      *(void **) argp = ecif->rvalue;
+      argp += 4;
+    }
+
+  p_argv = ecif->avalue;
+
+  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
+       (i != 0); i--, p_arg++)
+    {
+      size_t z;
+      int alignment;
+
+      /* align alignment to 4 */
+      alignment = (((*p_arg)->alignment - 1) | 3) + 1;
+
+      /* Align if necessary.  */
+      if ((alignment - 1) & (unsigned) argp)
+	argp = (char *) ALIGN (argp, alignment);
+
+      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
+	{
+	  if ((*p_arg)->type == FFI_TYPE_STRUCT)
+	    {
+	      memcpy (argp, *p_argv, z);
+	    }
+	  else
+	    {
+	      /* Double or long long 64bit.  */
+	      memcpy (argp, *p_argv, z);
+	    }
+	}
+      p_argv++;
+      argp += z;
+    }
+
+  return;
+}
+
+/* Perform machine dependent cif processing.  */
+ffi_status
+ffi_prep_cif_machdep (ffi_cif * cif)
+{
+  /* Set the return type flag.  */
+  switch (cif->rtype->type)
+    {
+    case FFI_TYPE_VOID:
+      cif->flags = (unsigned) cif->rtype->type;
+      break;
+
+    case FFI_TYPE_STRUCT:
+      cif->flags = (unsigned) cif->rtype->type;
+      break;
+
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_UINT64:
+    case FFI_TYPE_DOUBLE:
+      cif->flags = FFI_TYPE_DOUBLE;
+      break;
+
+    case FFI_TYPE_FLOAT:
+    default:
+      cif->flags = FFI_TYPE_INT;
+      break;
+    }
+
+  return FFI_OK;
+}
+
+extern void ffi_call_ARCompact (void (*)(char *, extended_cif *),
+				extended_cif *, unsigned, unsigned,
+				unsigned *, void (*fn) (void));
+
+void
+ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue)
+{
+  extended_cif ecif;
+
+  ecif.cif = cif;
+  ecif.avalue = avalue;
+
+  /* If the return value is a struct and we don't have
+     a return value address then we need to make one.  */
+  if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
+    {
+      ecif.rvalue = alloca (cif->rtype->size);
+    }
+  else
+    ecif.rvalue = rvalue;
+
+  switch (cif->abi)
+    {
+    case FFI_ARCOMPACT:
+      ffi_call_ARCompact (ffi_prep_args, &ecif, cif->bytes,
+			  cif->flags, ecif.rvalue, fn);
+      break;
+
+    default:
+      FFI_ASSERT (0);
+      break;
+    }
+}
+
+int
+ffi_closure_inner_ARCompact (ffi_closure * closure, void *rvalue,
+			     ffi_arg * args)
+{
+  void **arg_area, **p_argv;
+  ffi_cif *cif = closure->cif;
+  char *argp = (char *) args;
+  ffi_type **p_argt;
+  int i;
+
+  arg_area = (void **) alloca (cif->nargs * sizeof (void *));
+
+  /* handle hidden argument */
+  if (cif->flags == FFI_TYPE_STRUCT)
+    {
+      rvalue = *(void **) argp;
+      argp += 4;
+    }
+
+  p_argv = arg_area;
+
+  for (i = 0, p_argt = cif->arg_types; i < cif->nargs;
+       i++, p_argt++, p_argv++)
+    {
+      size_t z;
+      int alignment;
+
+      /* align alignment to 4 */
+      alignment = (((*p_argt)->alignment - 1) | 3) + 1;
+
+      /* Align if necessary.  */
+      if ((alignment - 1) & (unsigned) argp)
+	argp = (char *) ALIGN (argp, alignment);
+
+      z = (*p_argt)->size;
+      *p_argv = (void *) argp;
+      argp += z;
+    }
+
+  (closure->fun) (cif, rvalue, arg_area, closure->user_data);
+
+  return cif->flags;
+}
+
+extern void ffi_closure_ARCompact (void);
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif,
+		      void (*fun) (ffi_cif *, void *, void **, void *),
+		      void *user_data, void *codeloc)
+{
+  uint32_t *tramp = (uint32_t *) & (closure->tramp[0]);
+
+  switch (cif->abi)
+    {
+    case FFI_ARCOMPACT:
+      FFI_ASSERT (tramp == codeloc);
+      tramp[0] = CODE_ENDIAN (0x200a1fc0);	/* mov r8, pcl  */
+      tramp[1] = CODE_ENDIAN (0x20200f80);	/* j [long imm] */
+      tramp[2] = CODE_ENDIAN (ffi_closure_ARCompact);
+      break;
+
+    default:
+      return FFI_BAD_ABI;
+    }
+
+  closure->cif = cif;
+  closure->fun = fun;
+  closure->user_data = user_data;
+  cacheflush (codeloc, FFI_TRAMPOLINE_SIZE, BCACHE);
+
+  return FFI_OK;
+}