OSDN Git Service

PR libffi/28313
authordaney <daney@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 10 Aug 2007 15:35:55 +0000 (15:35 +0000)
committerdaney <daney@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 10 Aug 2007 15:35:55 +0000 (15:35 +0000)
* configure.ac: Don't treat mips64 as a special case.
* Makefile.am (nodist_libffi_la_SOURCES): Add n32.S.
* configure: Regenerate
* Makefile.in: Ditto.
* fficonfig.h.in: Ditto.
* src/mips/ffitarget.h (REG_L, REG_S, SUBU, ADDU, SRL, LI): Indent.
(LA, EH_FRAME_ALIGN, FDE_ADDR_BYTES): New preprocessor macros.
(FFI_DEFAULT_ABI): Set for n64 case.
(FFI_CLOSURES, FFI_TRAMPOLINE_SIZE): Define for n32 and n64 cases.
* src/mips/n32.S (ffi_call_N32): Add debug macros and labels for FDE.
(ffi_closure_N32): New function.
(.eh_frame): New section
* src/mips/o32.S: Clean up comments.
(ffi_closure_O32): Pass ffi_closure parameter in $12.
* src/mips/ffi.c: Use FFI_MIPS_N32 instead of
_MIPS_SIM == _ABIN32 throughout.
(FFI_MIPS_STOP_HERE): New, use in place of
ffi_stop_here.
(ffi_prep_args): Use unsigned long to hold pointer values.  Rewrite
to support n32/n64 ABIs.
(calc_n32_struct_flags): Rewrite.
(calc_n32_return_struct_flags): Remove unused variable.  Reverse
position of flag bits.
(ffi_prep_cif_machdep): Rewrite n32 portion.
(ffi_call): Enable for n64.  Add special handling for small structure
return values.
(ffi_prep_closure_loc): Add n32 and n64 support.
(ffi_closure_mips_inner_O32): Add cast to silence warning.
(copy_struct_N32, ffi_closure_mips_inner_N32): New functions.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@127336 138bc75d-0d04-0410-961f-82ee72b054a4

libffi/ChangeLog
libffi/Makefile.am
libffi/Makefile.in
libffi/configure
libffi/configure.ac
libffi/fficonfig.h.in
libffi/src/mips/ffi.c
libffi/src/mips/ffitarget.h
libffi/src/mips/n32.S
libffi/src/mips/o32.S

index 947621f..8a3ddc9 100644 (file)
@@ -1,3 +1,36 @@
+2007-08-10  David Daney  <ddaney@avtrex.com>
+
+       PR libffi/28313
+       * configure.ac: Don't treat mips64 as a special case.
+       * Makefile.am (nodist_libffi_la_SOURCES): Add n32.S.
+       * configure: Regenerate
+       * Makefile.in: Ditto.
+       * fficonfig.h.in: Ditto.
+       * src/mips/ffitarget.h (REG_L, REG_S, SUBU, ADDU, SRL, LI): Indent.
+       (LA, EH_FRAME_ALIGN, FDE_ADDR_BYTES): New preprocessor macros.
+       (FFI_DEFAULT_ABI): Set for n64 case.
+       (FFI_CLOSURES, FFI_TRAMPOLINE_SIZE): Define for n32 and n64 cases.
+       * src/mips/n32.S (ffi_call_N32): Add debug macros and labels for FDE.
+       (ffi_closure_N32): New function.
+       (.eh_frame): New section
+       * src/mips/o32.S: Clean up comments.
+       (ffi_closure_O32): Pass ffi_closure parameter in $12.
+       * src/mips/ffi.c: Use FFI_MIPS_N32 instead of
+       _MIPS_SIM == _ABIN32 throughout.
+       (FFI_MIPS_STOP_HERE): New, use in place of
+       ffi_stop_here.
+       (ffi_prep_args): Use unsigned long to hold pointer values.  Rewrite
+       to support n32/n64 ABIs.
+       (calc_n32_struct_flags): Rewrite.
+       (calc_n32_return_struct_flags): Remove unused variable.  Reverse
+       position of flag bits.
+       (ffi_prep_cif_machdep): Rewrite n32 portion.
+       (ffi_call): Enable for n64.  Add special handling for small structure
+       return values.
+       (ffi_prep_closure_loc): Add n32 and n64 support.
+       (ffi_closure_mips_inner_O32): Add cast to silence warning.
+       (copy_struct_N32, ffi_closure_mips_inner_N32): New functions.
+
 2007-08-08  David Daney  <ddaney@avtrex.com>
 
        * testsuite/libffi.call/ffitest.h (ffi_type_mylong): Remove definition.
index 3000c9c..2a2d174 100644 (file)
@@ -88,7 +88,7 @@ if MIPS_IRIX
 nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S
 endif
 if MIPS_LINUX
-nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S
+nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S
 endif
 if X86
 nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S
index fc5539e..42a444d 100644 (file)
@@ -38,7 +38,7 @@ build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
 @MIPS_IRIX_TRUE@am__append_1 = src/mips/ffi.c src/mips/o32.S src/mips/n32.S
-@MIPS_LINUX_TRUE@am__append_2 = src/mips/ffi.c src/mips/o32.S
+@MIPS_LINUX_TRUE@am__append_2 = src/mips/ffi.c src/mips/o32.S src/mips/n32.S
 @X86_TRUE@am__append_3 = src/x86/ffi.c src/x86/sysv.S
 @X86_WIN32_TRUE@am__append_4 = src/x86/ffi.c src/x86/win32.S
 @X86_DARWIN_TRUE@am__append_5 = src/x86/ffi.c src/x86/darwin.S src/x86/ffi64.c src/x86/darwin64.S
@@ -97,7 +97,8 @@ am_libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo src/types.lo \
        src/raw_api.lo src/java_raw_api.lo src/closures.lo
 @MIPS_IRIX_TRUE@am__objects_1 = src/mips/ffi.lo src/mips/o32.lo \
 @MIPS_IRIX_TRUE@       src/mips/n32.lo
-@MIPS_LINUX_TRUE@am__objects_2 = src/mips/ffi.lo src/mips/o32.lo
+@MIPS_LINUX_TRUE@am__objects_2 = src/mips/ffi.lo src/mips/o32.lo \
+@MIPS_LINUX_TRUE@      src/mips/n32.lo
 @X86_TRUE@am__objects_3 = src/x86/ffi.lo src/x86/sysv.lo
 @X86_WIN32_TRUE@am__objects_4 = src/x86/ffi.lo src/x86/win32.lo
 @X86_DARWIN_TRUE@am__objects_5 = src/x86/ffi.lo src/x86/darwin.lo \
index 404475f..6816520 100755 (executable)
@@ -10324,8 +10324,6 @@ case "$host" in
        TARGET=M68K; TARGETDIR=m68k
        ;;
 
-  mips64*-*)
-       ;;
   mips-sgi-irix5.* | mips-sgi-irix6.*)
        TARGET=MIPS_IRIX; TARGETDIR=mips
        ;;
index 6c7a9d2..e47013f 100644 (file)
@@ -94,8 +94,6 @@ case "$host" in
        TARGET=M68K; TARGETDIR=m68k
        ;;
 
-  mips64*-*)
-       ;;
   mips-sgi-irix5.* | mips-sgi-irix6.*)
        TARGET=MIPS_IRIX; TARGETDIR=mips
        ;;
index d32d488..e93cf8a 100644 (file)
@@ -37,6 +37,9 @@
    */
 #undef HAVE_AS_SPARC_UA_PCREL
 
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
 /* Define if __attribute__((visibility("hidden"))) is supported. */
 #undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
 
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
 /* Define to 1 if your C compiler doesn't accept -c and -o together. */
 #undef NO_MINUS_C_MINUS_O
 
index 12b8b62..cc2a42e 100644 (file)
 
 #include <stdlib.h>
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_DEBUG
+# define FFI_MIPS_STOP_HERE() ffi_stop_here()
+#else
+# define FFI_MIPS_STOP_HERE() do {} while(0)
+#endif
+
+#ifdef FFI_MIPS_N32
 #define FIX_ARGP \
 FFI_ASSERT(argp <= &stack[bytes]); \
 if (argp == &stack[bytes]) \
 { \
   argp = stack; \
-  ffi_stop_here(); \
+  FFI_MIPS_STOP_HERE(); \
 }
 #else
 #define FIX_ARGP 
@@ -54,7 +60,7 @@ static void ffi_prep_args(char *stack,
   char *argp;
   ffi_type **p_arg;
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
   /* If more than 8 double words are used, the remainder go
      on the stack. We reorder stuff on the stack here to 
      support this easily. */
@@ -68,7 +74,7 @@ static void ffi_prep_args(char *stack,
 
   memset(stack, 0, bytes);
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
   if ( ecif->cif->rstruct_flag != 0 )
 #else
   if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
@@ -91,7 +97,7 @@ static void ffi_prep_args(char *stack,
       if (a < sizeof(ffi_arg))
         a = sizeof(ffi_arg);
       
-      if ((a - 1) & (unsigned int) argp)
+      if ((a - 1) & (unsigned long) argp)
        {
          argp = (char *) ALIGN(argp, a);
          FIX_ARGP;
@@ -100,9 +106,15 @@ static void ffi_prep_args(char *stack,
       z = (*p_arg)->size;
       if (z <= sizeof(ffi_arg))
        {
+          int type = (*p_arg)->type;
          z = sizeof(ffi_arg);
 
-         switch ((*p_arg)->type)
+          /* The size of a pointer depends on the ABI */
+          if (type == FFI_TYPE_POINTER)
+            type =
+              (ecif->cif->abi == FFI_N64) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+
+         switch (type)
            {
              case FFI_TYPE_SINT8:
                *(ffi_arg *)argp = *(SINT8 *)(* p_argv);
@@ -125,7 +137,6 @@ static void ffi_prep_args(char *stack,
                break;
                  
              case FFI_TYPE_UINT32:
-             case FFI_TYPE_POINTER:
                *(ffi_arg *)argp = *(UINT32 *)(* p_argv);
                break;
 
@@ -134,8 +145,7 @@ static void ffi_prep_args(char *stack,
                *(float *) argp = *(float *)(* p_argv);
                break;
 
-             /* Handle small structures.  */
-             case FFI_TYPE_STRUCT:
+             /* Handle structures.  */
              default:
                memcpy(argp, *p_argv, (*p_arg)->size);
                break;
@@ -143,12 +153,12 @@ static void ffi_prep_args(char *stack,
        }
       else
        {
-#if _MIPS_SIM == _ABIO32
+#ifdef FFI_MIPS_O32
          memcpy(argp, *p_argv, z);
 #else
          {
-           unsigned end = (unsigned) argp+z;
-           unsigned cap = (unsigned) stack+bytes;
+           unsigned long end = (unsigned long) argp + z;
+           unsigned long cap = (unsigned long) stack + bytes;
 
            /* Check if the data will fit within the register space.
               Handle it if it doesn't.  */
@@ -157,12 +167,13 @@ static void ffi_prep_args(char *stack,
              memcpy(argp, *p_argv, z);
            else
              {
-               unsigned portion = end - cap;
+               unsigned long portion = cap - (unsigned long)argp;
 
                memcpy(argp, *p_argv, portion);
                argp = stack;
-               memcpy(argp,
-                      (void*)((unsigned)(*p_argv)+portion), z - portion);
+                z -= portion;
+               memcpy(argp, (void*)((unsigned long)(*p_argv) + portion),
+                       z);
              }
          }
 #endif
@@ -173,7 +184,7 @@ static void ffi_prep_args(char *stack,
     }
 }
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
 
 /* The n32 spec says that if "a chunk consists solely of a double 
    float field (but not a double, which is part of a union), it
@@ -181,35 +192,41 @@ static void ffi_prep_args(char *stack,
    passed in an integer register". This code traverses structure
    definitions and generates the appropriate flags. */
 
-unsigned calc_n32_struct_flags(ffi_type *arg, unsigned *shift)
+static unsigned
+calc_n32_struct_flags(ffi_type *arg, unsigned *loc, unsigned *arg_reg)
 {
   unsigned flags = 0;
   unsigned index = 0;
 
   ffi_type *e;
 
-  while (e = arg->elements[index])
+  while ((e = arg->elements[index]))
     {
+      /* Align this object.  */
+      *loc = ALIGN(*loc, e->alignment);
       if (e->type == FFI_TYPE_DOUBLE)
        {
-         flags += (FFI_TYPE_DOUBLE << *shift);
-         *shift += FFI_FLAG_BITS;
+          /* Already aligned to FFI_SIZEOF_ARG.  */
+          *arg_reg = *loc / FFI_SIZEOF_ARG;
+          if (*arg_reg > 7)
+            break;
+         flags += (FFI_TYPE_DOUBLE << (*arg_reg * FFI_FLAG_BITS));
+          *loc += e->size;
        }
-      else if (e->type == FFI_TYPE_STRUCT)
-         flags += calc_n32_struct_flags(e, shift);
       else
-       *shift += FFI_FLAG_BITS;
-
+        *loc += e->size;
       index++;
     }
+  /* Next Argument register at alignment of FFI_SIZEOF_ARG.  */
+  *arg_reg = ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
 
   return flags;
 }
 
-unsigned calc_n32_return_struct_flags(ffi_type *arg)
+static unsigned
+calc_n32_return_struct_flags(ffi_type *arg)
 {
   unsigned flags = 0;
-  unsigned index = 0;
   unsigned small = FFI_TYPE_SMALLSTRUCT;
   ffi_type *e;
 
@@ -228,16 +245,16 @@ unsigned calc_n32_return_struct_flags(ffi_type *arg)
 
   e = arg->elements[0];
   if (e->type == FFI_TYPE_DOUBLE)
-    flags = FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
+    flags = FFI_TYPE_DOUBLE;
   else if (e->type == FFI_TYPE_FLOAT)
-    flags = FFI_TYPE_FLOAT << FFI_FLAG_BITS;
+    flags = FFI_TYPE_FLOAT;
 
   if (flags && (e = arg->elements[1]))
     {
       if (e->type == FFI_TYPE_DOUBLE)
-       flags += FFI_TYPE_DOUBLE;
+       flags += FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
       else if (e->type == FFI_TYPE_FLOAT)
-       flags += FFI_TYPE_FLOAT;
+       flags += FFI_TYPE_FLOAT << FFI_FLAG_BITS;
       else 
        return small;
 
@@ -262,7 +279,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
 {
   cif->flags = 0;
 
-#if _MIPS_SIM == _ABIO32
+#ifdef FFI_MIPS_O32
   /* Set the flags necessary for O32 processing.  FFI_O32_SOFT_FLOAT
    * does not have special handling for floating point args.
    */
@@ -350,10 +367,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
     }
 #endif
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
   /* Set the flags necessary for N32 processing */
   {
-    unsigned shift = 0;
+    unsigned arg_reg = 0;
+    unsigned loc = 0;
     unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
     unsigned index = 0;
 
@@ -368,7 +386,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
            /* This means that the structure is being passed as
               a hidden argument */
 
-           shift = FFI_FLAG_BITS;
+           arg_reg = 1;
            count = (cif->nargs < 7) ? cif->nargs : 7;
 
            cif->rstruct_flag = !0;
@@ -379,23 +397,37 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
     else
       cif->rstruct_flag = 0;
 
-    while (count-- > 0)
+    while (count-- > 0 && arg_reg < 8)
       {
        switch ((cif->arg_types)[index]->type)
          {
          case FFI_TYPE_FLOAT:
          case FFI_TYPE_DOUBLE:
-           cif->flags += ((cif->arg_types)[index]->type << shift);
-           shift += FFI_FLAG_BITS;
+           cif->flags +=
+              ((cif->arg_types)[index]->type << (arg_reg * FFI_FLAG_BITS));
+           arg_reg++;
            break;
+          case FFI_TYPE_LONGDOUBLE:
+            /* Align it.  */
+            arg_reg = ALIGN(arg_reg, 2);
+            /* Treat it as two adjacent doubles.  */
+           cif->flags +=
+              (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
+            arg_reg++;
+           cif->flags +=
+              (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
+            arg_reg++;
+            break;
 
          case FFI_TYPE_STRUCT:
+            loc = arg_reg * FFI_SIZEOF_ARG;
            cif->flags += calc_n32_struct_flags((cif->arg_types)[index],
-                                               &shift);
+                                               &loc, &arg_reg);
            break;
 
          default:
-           shift += FFI_FLAG_BITS;
+           arg_reg++;
+            break;
          }
 
        index++;
@@ -430,7 +462,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
       case FFI_TYPE_DOUBLE:
        cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
        break;
-       
+
       default:
        cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
        break;
@@ -469,7 +501,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
     
   switch (cif->abi) 
     {
-#if _MIPS_SIM == _ABIO32
+#ifdef FFI_MIPS_O32
     case FFI_O32:
     case FFI_O32_SOFT_FLOAT:
       ffi_call_O32(ffi_prep_args, &ecif, cif->bytes, 
@@ -477,10 +509,25 @@ void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
       break;
 #endif
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
     case FFI_N32:
-      ffi_call_N32(ffi_prep_args, &ecif, cif->bytes, 
-                  cif->flags, ecif.rvalue, fn);
+    case FFI_N64:
+      {
+        int copy_rvalue = 0;
+        void *rvalue_copy = ecif.rvalue;
+        if (cif->rtype->type == FFI_TYPE_STRUCT && cif->rtype->size < 16)
+          {
+            /* For structures smaller than 16 bytes we clobber memory
+               in 8 byte increments.  Make a copy so we don't clobber
+               the callers memory outside of the struct bounds.  */
+            rvalue_copy = alloca(16);
+            copy_rvalue = 1;
+          }
+        ffi_call_N32(ffi_prep_args, &ecif, cif->bytes,
+                     cif->flags, rvalue_copy, fn);
+        if (copy_rvalue)
+          memcpy(ecif.rvalue, rvalue_copy, cif->rtype->size);
+      }
       break;
 #endif
 
@@ -490,9 +537,11 @@ void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
     }
 }
 
-#if FFI_CLOSURES  /* N32 not implemented yet, FFI_CLOSURES not defined */
+#if FFI_CLOSURES
 #if defined(FFI_MIPS_O32)
 extern void ffi_closure_O32(void);
+#else
+extern void ffi_closure_N32(void);
 #endif /* FFI_MIPS_O32 */
 
 ffi_status
@@ -503,23 +552,58 @@ ffi_prep_closure_loc (ffi_closure *closure,
                      void *codeloc)
 {
   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
-  unsigned int fn;
-  unsigned int ctx = (unsigned int) codeloc;
+  void * fn;
   char *clear_location = (char *) codeloc;
 
 #if defined(FFI_MIPS_O32)
   FFI_ASSERT(cif->abi == FFI_O32 || cif->abi == FFI_O32_SOFT_FLOAT);
-  fn = (unsigned int) ffi_closure_O32;
+  fn = ffi_closure_O32;
 #else /* FFI_MIPS_N32 */
-  FFI_ASSERT(cif->abi == FFI_N32);
-  FFI_ASSERT(!"not implemented");
+  FFI_ASSERT(cif->abi == FFI_N32 || cif->abi == FFI_N64);
+  fn = ffi_closure_N32;
 #endif /* FFI_MIPS_O32 */
 
-  tramp[0] = 0x3c190000 | (fn >> 16);     /* lui  $25,high(fn) */
-  tramp[1] = 0x37390000 | (fn & 0xffff);  /* ori  $25,low(fn)  */
-  tramp[2] = 0x3c080000 | (ctx >> 16);    /* lui  $8,high(ctx) */
-  tramp[3] = 0x03200008;                  /* jr   $25          */
-  tramp[4] = 0x35080000 | (ctx & 0xffff); /* ori  $8,low(ctx)  */
+#if defined(FFI_MIPS_O32) || (_MIPS_SIM ==_ABIN32)
+  /* lui  $25,high(fn) */
+  tramp[0] = 0x3c190000 | ((unsigned)fn >> 16);
+  /* ori  $25,low(fn)  */
+  tramp[1] = 0x37390000 | ((unsigned)fn & 0xffff);
+  /* lui  $12,high(codeloc) */
+  tramp[2] = 0x3c0c0000 | ((unsigned)codeloc >> 16);
+  /* jr   $25          */
+  tramp[3] = 0x03200008;
+  /* ori  $12,low(codeloc)  */
+  tramp[4] = 0x358c0000 | ((unsigned)codeloc & 0xffff);
+#else
+  /* N64 has a somewhat larger trampoline.  */
+  /* lui  $25,high(fn) */
+  tramp[0] = 0x3c190000 | ((unsigned long)fn >> 48);
+  /* lui  $12,high(codeloc) */
+  tramp[1] = 0x3c0c0000 | ((unsigned long)codeloc >> 48);
+  /* ori  $25,mid-high(fn)  */
+  tramp[2] = 0x37390000 | (((unsigned long)fn >> 32 ) & 0xffff);
+  /* ori  $12,mid-high(codeloc)  */
+  tramp[3] = 0x358c0000 | (((unsigned long)codeloc >> 32) & 0xffff);
+  /* dsll $25,$25,16 */
+  tramp[4] = 0x0019cc38;
+  /* dsll $12,$12,16 */
+  tramp[5] = 0x000c6438;
+  /* ori  $25,mid-low(fn)  */
+  tramp[6] = 0x37390000 | (((unsigned long)fn >> 16 ) & 0xffff);
+  /* ori  $12,mid-low(codeloc)  */
+  tramp[7] = 0x358c0000 | (((unsigned long)codeloc >> 16) & 0xffff);
+  /* dsll $25,$25,16 */
+  tramp[8] = 0x0019cc38;
+  /* dsll $12,$12,16 */
+  tramp[9] = 0x000c6438;
+  /* ori  $25,low(fn)  */
+  tramp[10] = 0x37390000 | ((unsigned long)fn  & 0xffff);
+  /* jr   $25          */
+  tramp[11] = 0x03200008;
+  /* ori  $12,low(codeloc)  */
+  tramp[12] = 0x358c0000 | ((unsigned long)codeloc & 0xffff);
+
+#endif
 
   closure->cif = cif;
   closure->fun = fun;
@@ -567,7 +651,7 @@ ffi_closure_mips_inner_O32 (ffi_closure *closure,
 
   if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT)
     {
-      rvalue = (void *) ar[0];
+      rvalue = (void *)(UINT32)ar[0];
       argn = 1;
     }
 
@@ -645,4 +729,177 @@ ffi_closure_mips_inner_O32 (ffi_closure *closure,
     }
 }
 
+#if defined(FFI_MIPS_N32)
+
+static void
+copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type,
+                int argn, unsigned arg_offset, ffi_arg *ar,
+                ffi_arg *fpr)
+{
+  ffi_type **elt_typep = type->elements;
+  while(*elt_typep)
+    {
+      ffi_type *elt_type = *elt_typep;
+      unsigned o;
+      char *tp;
+      char *argp;
+      char *fpp;
+
+      o = ALIGN(offset, elt_type->alignment);
+      arg_offset += o - offset;
+      offset = o;
+      argn += arg_offset / sizeof(ffi_arg);
+      arg_offset = arg_offset % sizeof(ffi_arg);
+
+      argp = (char *)(ar + argn);
+      fpp = (char *)(argn >= 8 ? ar + argn : fpr + argn);
+
+      tp = target + offset;
+
+      if (elt_type->type == FFI_TYPE_DOUBLE)
+        *(double *)tp = *(double *)fpp;
+      else
+        memcpy(tp, argp + arg_offset, elt_type->size);
+
+      offset += elt_type->size;
+      arg_offset += elt_type->size;
+      elt_typep++;
+      argn += arg_offset / sizeof(ffi_arg);
+      arg_offset = arg_offset % sizeof(ffi_arg);
+    }
+}
+
+/*
+ * Decodes the arguments to a function, which will be stored on the
+ * stack. AR is the pointer to the beginning of the integer
+ * arguments. FPR is a pointer to the area where floating point
+ * registers have been saved.
+ *
+ * RVALUE is the location where the function return value will be
+ * stored. CLOSURE is the prepared closure to invoke.
+ *
+ * This function should only be called from assembly, which is in
+ * turn called from a trampoline.
+ *
+ * Returns the function return flags.
+ *
+ */
+int
+ffi_closure_mips_inner_N32 (ffi_closure *closure,
+                           void *rvalue, ffi_arg *ar,
+                           ffi_arg *fpr)
+{
+  ffi_cif *cif;
+  void **avaluep;
+  ffi_arg *avalue;
+  ffi_type **arg_types;
+  int i, avn, argn;
+
+  cif = closure->cif;
+  avalue = alloca (cif->nargs * sizeof (ffi_arg));
+  avaluep = alloca (cif->nargs * sizeof (ffi_arg));
+
+  argn = 0;
+
+  if (cif->rstruct_flag)
+    {
+#if _MIPS_SIM==_ABIN32
+      rvalue = (void *)(UINT32)ar[0];
+#else /* N64 */
+      rvalue = (void *)ar[0];
+#endif
+      argn = 1;
+    }
+
+  i = 0;
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+
+  while (i < avn)
+    {
+      if (arg_types[i]->type == FFI_TYPE_FLOAT
+          || arg_types[i]->type == FFI_TYPE_DOUBLE)
+        {
+          ffi_arg *argp = argn >= 8 ? ar + argn : fpr + argn;
+#ifdef __MIPSEB__
+          if (arg_types[i]->type == FFI_TYPE_FLOAT && argn < 8)
+            avaluep[i] = ((char *) argp) + sizeof (float);
+          else
+#endif
+            avaluep[i] = (char *) argp;
+        }
+      else
+        {
+          unsigned type = arg_types[i]->type;
+
+          if (arg_types[i]->alignment > sizeof(ffi_arg))
+            argn = ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg));
+
+          ffi_arg *argp = ar + argn;
+
+          /* The size of a pointer depends on the ABI */
+          if (type == FFI_TYPE_POINTER)
+            type = (cif->abi == FFI_N64) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+
+          switch (type)
+            {
+            case FFI_TYPE_SINT8:
+              avaluep[i] = &avalue[i];
+              *(SINT8 *) &avalue[i] = (SINT8) *argp;
+              break;
+
+            case FFI_TYPE_UINT8:
+              avaluep[i] = &avalue[i];
+              *(UINT8 *) &avalue[i] = (UINT8) *argp;
+              break;
+
+            case FFI_TYPE_SINT16:
+              avaluep[i] = &avalue[i];
+              *(SINT16 *) &avalue[i] = (SINT16) *argp;
+              break;
+
+            case FFI_TYPE_UINT16:
+              avaluep[i] = &avalue[i];
+              *(UINT16 *) &avalue[i] = (UINT16) *argp;
+              break;
+
+            case FFI_TYPE_SINT32:
+              avaluep[i] = &avalue[i];
+              *(SINT32 *) &avalue[i] = (SINT32) *argp;
+              break;
+
+            case FFI_TYPE_UINT32:
+              avaluep[i] = &avalue[i];
+              *(UINT32 *) &avalue[i] = (UINT32) *argp;
+              break;
+
+            case FFI_TYPE_STRUCT:
+              if (argn < 8)
+                {
+                  /* Allocate space for the struct as at least part of
+                     it was passed in registers.  */
+                  avaluep[i] = alloca(arg_types[i]->size);
+                  copy_struct_N32(avaluep[i], 0, cif->abi, arg_types[i],
+                                  argn, 0, ar, fpr);
+
+                  break;
+                }
+              /* Else fall through.  */
+            default:
+              avaluep[i] = (char *) argp;
+              break;
+            }
+        }
+      argn += ALIGN(arg_types[i]->size, sizeof(ffi_arg)) / sizeof(ffi_arg);
+      i++;
+    }
+
+  /* Invoke the closure. */
+  (closure->fun) (cif, rvalue, avaluep, closure->user_data);
+
+  return cif->flags >> (FFI_FLAG_BITS * 8);
+}
+
+#endif /* FFI_MIPS_N32 */
+
 #endif /* FFI_CLOSURES */
index e610745..08f03c3 100644 (file)
 #define ra $31         
 
 #ifdef FFI_MIPS_O32
-#define REG_L  lw
-#define REG_S  sw
-#define SUBU   subu
-#define ADDU   addu
-#define SRL    srl
-#define LI     li
+# define REG_L lw
+# define REG_S sw
+# define SUBU  subu
+# define ADDU  addu
+# define SRL   srl
+# define LI    li
 #else /* !FFI_MIPS_O32 */
-#define REG_L  ld
-#define REG_S  sd
-#define SUBU   dsubu
-#define ADDU   daddu
-#define SRL    dsrl
-#define LI     dli
+# define REG_L ld
+# define REG_S sd
+# define SUBU  dsubu
+# define ADDU  daddu
+# define SRL   dsrl
+# define LI    dli
+# if (_MIPS_SIM==_ABI64)
+#  define LA dla
+#  define EH_FRAME_ALIGN 3
+#  define FDE_ADDR_BYTES .8byte
+# else
+#  define LA la
+#  define EH_FRAME_ALIGN 2
+#  define FDE_ADDR_BYTES .4byte
+# endif /* _MIPS_SIM==_ABI64 */
 #endif /* !FFI_MIPS_O32 */
 #else /* !LIBFFI_ASM */
 #ifdef FFI_MIPS_O32
@@ -143,7 +152,11 @@ typedef enum ffi_abi {
   FFI_DEFAULT_ABI = FFI_O32,
 #endif
 #else
+# if _MIPS_SIM==_ABI64
+  FFI_DEFAULT_ABI = FFI_N64,
+# else
   FFI_DEFAULT_ABI = FFI_N32,
+# endif
 #endif
 
   FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
@@ -158,8 +171,13 @@ typedef enum ffi_abi {
 #define FFI_CLOSURES 1
 #define FFI_TRAMPOLINE_SIZE 20
 #else
-/* N32/N64 not implemented yet. */
-#define FFI_CLOSURES 0
+/* N32/N64. */
+# define FFI_CLOSURES 1
+#if _MIPS_SIM==_ABI64
+#define FFI_TRAMPOLINE_SIZE 52
+#else
+#define FFI_TRAMPOLINE_SIZE 20
+#endif
 #endif /* FFI_MIPS_O32 */
 #define FFI_NATIVE_RAW_API 0
 
index 358cfd7..ff268c6 100644 (file)
        .globl  ffi_call_N32
        .ent    ffi_call_N32
 ffi_call_N32:  
+.LFB3:
+       .frame  $fp, SIZEOF_FRAME, ra
+       .mask   0xc0000000,-FFI_SIZEOF_ARG
+       .fmask  0x00000000,0
 
        # Prologue
        SUBU    $sp, SIZEOF_FRAME                       # Frame size
+.LCFI0:
        REG_S   $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp)       # Save frame pointer
        REG_S   ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)        # Save return address
+.LCFI1:
        move    $fp, $sp
-
+.LCFI3:
        move    t9, callback    # callback function pointer
        REG_S   bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
        REG_S   flags, 3*FFI_SIZEOF_ARG($fp) # flags
@@ -315,6 +321,224 @@ epilogue:
        ADDU    $sp, SIZEOF_FRAME                     # Fix stack pointer
        j       ra
 
+.LFE3:
        .end    ffi_call_N32
+
+/* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0
+   ($12). Stores any arguments passed in registers onto the stack,
+   then calls ffi_closure_mips_inner_N32, which then decodes
+   them.
+       
+       Stack layout:
+
+       20 - Start of parameters, original sp
+       19 - Called function a7 save
+       18 - Called function a6 save
+       17 - Called function a5 save
+       16 - Called function a4 save
+       15 - Called function a3 save
+       14 - Called function a2 save
+       13 - Called function a1 save
+       12 - Called function a0 save
+       11 - Called function f19
+       10 - Called function f18
+        9 - Called function f17
+        8 - Called function f16
+        7 - Called function f15
+         6 - Called function f14
+         5 - Called function f13
+         4 - Called function f12
+        3 - return value high (v1 or $f2)
+        2 - return value low (v0 or $f0)
+        1 - ra save
+        0 - gp save our sp  points here
+        */
+
+#define SIZEOF_FRAME2  (20 * FFI_SIZEOF_ARG)
+       
+#define A7_OFF2                (19 * FFI_SIZEOF_ARG)
+#define A6_OFF2                (18 * FFI_SIZEOF_ARG)
+#define A5_OFF2                (17 * FFI_SIZEOF_ARG)
+#define A4_OFF2                (16 * FFI_SIZEOF_ARG)
+#define A3_OFF2                (15 * FFI_SIZEOF_ARG)
+#define A2_OFF2                (14 * FFI_SIZEOF_ARG)
+#define A1_OFF2                (13 * FFI_SIZEOF_ARG)
+#define A0_OFF2                (12 * FFI_SIZEOF_ARG)   
+
+#define F19_OFF2       (11 * FFI_SIZEOF_ARG)
+#define F18_OFF2       (10 * FFI_SIZEOF_ARG)
+#define F17_OFF2       (9  * FFI_SIZEOF_ARG)
+#define F16_OFF2       (8  * FFI_SIZEOF_ARG)
+#define F15_OFF2       (7  * FFI_SIZEOF_ARG)
+#define F14_OFF2       (6  * FFI_SIZEOF_ARG)
+#define F13_OFF2       (5  * FFI_SIZEOF_ARG)
+#define F12_OFF2       (4  * FFI_SIZEOF_ARG)
+
+#define V1_OFF2                (3  * FFI_SIZEOF_ARG)
+#define V0_OFF2                (2  * FFI_SIZEOF_ARG)
+
+#define RA_OFF2                (1  * FFI_SIZEOF_ARG)
+#define GP_OFF2                (0  * FFI_SIZEOF_ARG)
+
+       .align  2
+       .globl  ffi_closure_N32
+       .ent    ffi_closure_N32
+ffi_closure_N32:
+.LFB2:
+       .frame  $sp, SIZEOF_FRAME2, ra
+       .mask   0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
+       .fmask  0x00000000,0
+       SUBU    $sp, SIZEOF_FRAME2
+.LCFI5:
+       .cpsetup t9, GP_OFF2, ffi_closure_N32
+       REG_S   ra, RA_OFF2($sp)        # Save return address
+.LCFI6:
+       # Store all possible argument registers. If there are more than
+       # fit in registers, then they were stored on the stack.
+       REG_S   a0, A0_OFF2($sp)
+       REG_S   a1, A1_OFF2($sp)
+       REG_S   a2, A2_OFF2($sp)
+       REG_S   a3, A3_OFF2($sp)
+       REG_S   a4, A4_OFF2($sp)
+       REG_S   a5, A5_OFF2($sp)
+       REG_S   a6, A6_OFF2($sp)
+       REG_S   a7, A7_OFF2($sp)
+
+       # Store all possible float/double registers.
+       s.d     $f12, F12_OFF2($sp)
+       s.d     $f13, F13_OFF2($sp)
+       s.d     $f14, F14_OFF2($sp)
+       s.d     $f15, F15_OFF2($sp)
+       s.d     $f16, F16_OFF2($sp)
+       s.d     $f17, F17_OFF2($sp)
+       s.d     $f18, F18_OFF2($sp)
+       s.d     $f19, F19_OFF2($sp)
+
+       # Call ffi_closure_mips_inner_N32 to do the real work.
+       LA      t9, ffi_closure_mips_inner_N32
+       move    a0, $12  # Pointer to the ffi_closure
+       addu    a1, $sp, V0_OFF2
+       addu    a2, $sp, A0_OFF2
+       addu    a3, $sp, F12_OFF2
+       jalr    t9
+
+       # Return flags are in v0
+       bne     v0, FFI_TYPE_INT, cls_retfloat
+       REG_L   v0, V0_OFF2($sp)
+       b       cls_epilogue
+
+cls_retfloat:
+       bne     v0, FFI_TYPE_FLOAT, cls_retdouble
+       l.s     $f0, V0_OFF2($sp)
+       b       cls_epilogue
+
+cls_retdouble: 
+       bne     v0, FFI_TYPE_DOUBLE, cls_retstruct_d
+       l.d     $f0, V0_OFF2($sp)
+       b       cls_epilogue
+
+cls_retstruct_d:       
+       bne     v0, FFI_TYPE_STRUCT_D, cls_retstruct_f
+       l.d     $f0, V0_OFF2($sp)
+       b       cls_epilogue
+       
+cls_retstruct_f:       
+       bne     v0, FFI_TYPE_STRUCT_F, cls_retstruct_d_d
+       l.s     $f0, V0_OFF2($sp)
+       b       cls_epilogue
+       
+cls_retstruct_d_d:     
+       bne     v0, FFI_TYPE_STRUCT_DD, cls_retstruct_f_f
+       l.d     $f0, V0_OFF2($sp)
+       l.d     $f2, V1_OFF2($sp)
+       b       cls_epilogue
+       
+cls_retstruct_f_f:     
+       bne     v0, FFI_TYPE_STRUCT_FF, cls_retstruct_d_f
+       l.s     $f0, V0_OFF2($sp)
+       l.s     $f2, V1_OFF2($sp)
+       b       cls_epilogue
+       
+cls_retstruct_d_f:     
+       bne     v0, FFI_TYPE_STRUCT_DF, cls_retstruct_f_d
+       l.d     $f0, V0_OFF2($sp)
+       l.s     $f2, V1_OFF2($sp)
+       b       cls_epilogue
+       
+cls_retstruct_f_d:     
+       bne     v0, FFI_TYPE_STRUCT_FD, cls_retstruct_small2
+       l.s     $f0, V0_OFF2($sp)
+       l.d     $f2, V1_OFF2($sp)
+       b       cls_epilogue
+       
+cls_retstruct_small2:  
+       REG_L   v0, V0_OFF2($sp)
+       REG_L   v1, V1_OFF2($sp)
+       
+       # Epilogue
+cls_epilogue:  
+       REG_L   ra,  RA_OFF2($sp)        # Restore return address
+       .cpreturn
+       ADDU    $sp, SIZEOF_FRAME2
+       j       ra
+.LFE2: 
+       .end    ffi_closure_N32
+
+        .section        .eh_frame,"aw",@progbits
+.Lframe1:
+        .4byte  .LECIE1-.LSCIE1                # length
+.LSCIE1:
+        .4byte  0x0                    # CIE
+        .byte   0x1                    # Version 1
+        .ascii  "\000"                 # Augmentation
+        .uleb128 0x1                   # Code alignment 1
+        .sleb128 -4                    # Data alignment -4
+        .byte   0x1f                   # Return Address $31
+        .byte   0xc                    # DW_CFA_def_cfa
+        .uleb128 0x1d                  # in $sp
+        .uleb128 0x0                   # offset 0
+        .align  EH_FRAME_ALIGN
+.LECIE1:
+
+.LSFDE1:
+        .4byte  .LEFDE1-.LASFDE1       # length.
+.LASFDE1:
+        .4byte  .LASFDE1-.Lframe1      # CIE_pointer.
+        FDE_ADDR_BYTES  .LFB3          # initial_location.
+        FDE_ADDR_BYTES  .LFE3-.LFB3    # address_range.
+        .byte   0x4                    # DW_CFA_advance_loc4
+        .4byte  .LCFI0-.LFB3           # to .LCFI0
+        .byte   0xe                    # DW_CFA_def_cfa_offset
+        .uleb128 SIZEOF_FRAME          # adjust stack.by SIZEOF_FRAME
+        .byte   0x4                    # DW_CFA_advance_loc4
+        .4byte  .LCFI1-.LCFI0          # to .LCFI1
+        .byte   0x9e                   # DW_CFA_offset of $fp
+        .uleb128 2*FFI_SIZEOF_ARG/4    # 
+        .byte   0x9f                   # DW_CFA_offset of ra
+        .uleb128 1*FFI_SIZEOF_ARG/4    # 
+        .byte   0x4                    # DW_CFA_advance_loc4
+        .4byte  .LCFI3-.LCFI1          # to .LCFI3
+        .byte   0xd                    # DW_CFA_def_cfa_register
+        .uleb128 0x1e                  # in $fp
+        .align  EH_FRAME_ALIGN
+.LEFDE1:
+.LSFDE3:
+       .4byte  .LEFDE3-.LASFDE3        # length
+.LASFDE3:
+       .4byte  .LASFDE3-.Lframe1       # CIE_pointer.
+       FDE_ADDR_BYTES  .LFB2           # initial_location.
+       FDE_ADDR_BYTES  .LFE2-.LFB2     # address_range.
+       .byte   0x4                     # DW_CFA_advance_loc4
+       .4byte  .LCFI5-.LFB2            # to .LCFI5
+       .byte   0xe                     # DW_CFA_def_cfa_offset
+       .uleb128 SIZEOF_FRAME2          # adjust stack.by SIZEOF_FRAME
+       .byte   0x4                     # DW_CFA_advance_loc4
+       .4byte  .LCFI6-.LCFI5           # to .LCFI6
+       .byte   0x9c                    # DW_CFA_offset of $gp ($28)
+       .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
+       .byte   0x9f                    # DW_CFA_offset of ra ($31)
+       .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
+       .align  EH_FRAME_ALIGN
+.LEFDE3:
        
 #endif
index 63f3d14..f6363cb 100644 (file)
@@ -183,27 +183,30 @@ $LFE0:
 
 
 /* ffi_closure_O32. Expects address of the passed-in ffi_closure
-       in t0. Stores any arguments passed in registers onto the
+       in t4 ($12). Stores any arguments passed in registers onto the
        stack, then calls ffi_closure_mips_inner_O32, which
        then decodes them.
        
        Stack layout:
 
-       14 - Start of parameters, original sp
-       13 - ra save
-       12 - fp save
-       11 - $16 (s0) save
-       10 - cprestore
-        9 - return value high (v1)
-        8 - return value low (v0)
-        7 - f14 (le high, be low)
-        6 - f14 (le low, be high)
-        5 - f12 (le high, be low)
-        4 - f12 (le low, be high)
-        3 - Called function a3 save
-        2 - Called function a2 save
-        1 - Called function a1 save
-        0 - Called function a0 save our sp, fp point here
+        3 - a3 save
+        2 - a2 save
+        1 - a1 save
+        0 - a0 save, original sp
+       -1 - ra save
+       -2 - fp save
+       -3 - $16 (s0) save
+       -4 - cprestore
+       -5 - return value high (v1)
+       -6 - return value low (v0)
+       -7 - f14 (le high, be low)
+       -8 - f14 (le low, be high)
+       -9 - f12 (le high, be low)
+       -10 - f12 (le low, be high)
+       -11 - Called function a3 save
+       -12 - Called function a2 save
+       -13 - Called function a1 save
+       -14 - Called function a0 save, our sp and fp point here
         */
        
 #define SIZEOF_FRAME2  (14 * FFI_SIZEOF_ARG)
@@ -251,7 +254,7 @@ $LCFI7:
        REG_S   a3, A3_OFF2($fp)
 
        # Load ABI enum to s0
-       REG_L   $16, 20($8)     # cif pointer follows tramp.
+       REG_L   $16, 20($12)    # cif pointer follows tramp.
        REG_L   $16, 0($16)     # abi is first member.
 
        li      $13, 1          # FFI_O32
@@ -263,7 +266,7 @@ $LCFI7:
 1:     
        # Call ffi_closure_mips_inner_O32 to do the work.
        la      t9, ffi_closure_mips_inner_O32
-       move    a0, $  # Pointer to the ffi_closure
+       move    a0, $12  # Pointer to the ffi_closure
        addu    a1, $fp, V0_OFF2
        addu    a2, $fp, A0_OFF2
        addu    a3, $fp, FA_0_0_OFF2