ffi.c (ffi_pref_cif_machdep): set `cif->flags' to contain `FFI_TYPE_UINT64' as return...
authorCasey Marshall <csm@gnu.org>
Sun, 15 Aug 2004 04:05:18 +0000 (04:05 +0000)
committerDavid Daney <daney@gcc.gnu.org>
Sun, 15 Aug 2004 04:05:18 +0000 (04:05 +0000)
2004-08-14  Casey Marshall <csm@gnu.org>

* src/mips/ffi.c (ffi_pref_cif_machdep): set `cif->flags' to
contain `FFI_TYPE_UINT64' as return type for any 64-bit
integer (O32 ABI only).
(ffi_prep_closure): new function.
(ffi_closure_mips_inner_O32): new function.
* src/mips/ffitarget.h: Define `FFI_CLOSURES' and
`FFI_TRAMPOLINE_SIZE' appropriately if the ABI is o32.
* src/mips/o32.S (ffi_call_O32): add labels for .eh_frame. Return
64 bit integers correctly.
(ffi_closure_O32): new function.
Added DWARF-2 unwind info for both functions.

From-SVN: r86019

libffi/ChangeLog
libffi/src/mips/ffi.c
libffi/src/mips/ffitarget.h
libffi/src/mips/o32.S

index 61b0b4f43f434843baa9fe65c659a05acf042d5c..483e483343c4868cf048f2e712b985fa50570a82 100644 (file)
@@ -1,3 +1,17 @@
+2004-08-14  Casey Marshall <csm@gnu.org>
+
+       * src/mips/ffi.c (ffi_pref_cif_machdep): set `cif->flags' to
+       contain `FFI_TYPE_UINT64' as return type for any 64-bit
+       integer (O32 ABI only).
+       (ffi_prep_closure): new function.
+       (ffi_closure_mips_inner_O32): new function.
+       * src/mips/ffitarget.h: Define `FFI_CLOSURES' and 
+       `FFI_TRAMPOLINE_SIZE' appropriately if the ABI is o32.
+       * src/mips/o32.S (ffi_call_O32): add labels for .eh_frame. Return
+       64 bit integers correctly.
+       (ffi_closure_O32): new function.
+       Added DWARF-2 unwind info for both functions.
+
 2004-08-10  Andrew Haley  <aph@redhat.com>
 
        * src/x86/ffi64.c (ffi_prep_args ): 8-align all stack arguments.
index cc2078bc7e280388f6dcb734a868564c6b936e44..e12922aa0465b6c1a6c99c0abd918f5ed5336b7e 100644 (file)
@@ -27,6 +27,7 @@
 #include <ffi_common.h>
 
 #include <stdlib.h>
+#include <sys/cachectl.h>
 
 #if _MIPS_SIM == _ABIN32
 #define FIX_ARGP \
@@ -314,6 +315,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
     case FFI_TYPE_DOUBLE:
       cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
       break;
+
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_UINT64:
+      cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2);
+      break;
       
     default:
       cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2);
@@ -459,3 +465,117 @@ void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
       break;
     }
 }
+
+#if FFI_CLOSURES  /* N32 not implemented yet, FFI_CLOSURES not defined */
+#if defined(FFI_MIPS_O32)
+extern void ffi_closure_O32(void);
+#endif /* FFI_MIPS_O32 */
+
+ffi_status
+ffi_prep_closure (ffi_closure *closure,
+                 ffi_cif *cif,
+                 void (*fun)(ffi_cif*,void*,void**,void*),
+                 void *user_data)
+{
+  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
+  unsigned int fn;
+  unsigned int ctx = (unsigned int) closure;
+
+#if defined(FFI_MIPS_O32)
+  FFI_ASSERT(cif->abi == FFI_O32);
+  fn = (unsigned int) ffi_closure_O32;
+#else /* FFI_MIPS_N32 */
+  FFI_ASSERT(cif->abi == FFI_N32);
+  FFI_ASSERT(!"not implemented");
+#endif /* FFI_MIPS_O32 */
+
+  tramp[0] = 0x3c190000 | (fn >> 16);     /* lui  $25,high(fn) */
+  tramp[1] = 0x3c080000 | (ctx >> 16);    /* lui  $8,high(ctx) */
+  tramp[2] = 0x37390000 | (fn & 0xffff);  /* ori  $25,low(fn)  */
+  tramp[3] = 0x03200008;                  /* jr   $25          */
+  tramp[4] = 0x35080000 | (ctx & 0xffff); /* ori  $8,low(ctx)  */
+
+  closure->cif = cif;
+  closure->fun = fun;
+  closure->user_data = user_data;
+
+  /* XXX this is available on Linux, but anything else? */
+  cacheflush (tramp, FFI_TRAMPOLINE_SIZE, ICACHE);
+
+  return FFI_OK;
+}
+
+/*
+ * Decodes the arguments to a function, which will be stored on the
+ * stack. AR is the pointer to the beginning of the integer arguments
+ * (and, depending upon the arguments, some floating-point arguments
+ * as well). FPR is a pointer to the area where floating point
+ * registers have been saved, if any.
+ *
+ * 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 type.
+ *
+ * Based on the similar routine for sparc.
+ */
+int
+ffi_closure_mips_inner_O32 (ffi_closure *closure,
+                           void *rvalue, unsigned long *ar,
+                           double *fpr)
+{
+  ffi_cif *cif;
+  void **avalue;
+  ffi_type **arg_types;
+  int i, avn, argn, seen_int;
+
+  cif = closure->cif;
+  avalue = alloca (cif->nargs * sizeof (void *));
+
+  seen_int = 0;
+  argn = 0;
+
+  if (cif->flags == FFI_TYPE_STRUCT)
+    {
+      rvalue = (void *) ar[0];
+      argn = 1;
+    }
+
+  i = 0;
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+
+  while (i < avn)
+    {
+      if (i < 2 && !seen_int &&
+         (arg_types[i]->type == FFI_TYPE_FLOAT ||
+          arg_types[i]->type == FFI_TYPE_DOUBLE))
+       {
+         avalue[i] = ((char *) &fpr[i]);
+       }
+      else
+       {
+         /* 8-byte arguments are always 8-byte aligned. */
+         if (arg_types[i]->size == 8 && (argn & 0x1))
+           argn++;
+         /* Float arguments take up two register slots. The float word
+            is the upper one. */
+         if (argn == 2 && arg_types[i]->type == FFI_TYPE_FLOAT)
+           argn++;
+         avalue[i] = ((char *) &ar[argn]);
+         seen_int = 1;
+       }
+      argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+      i++;
+    }
+
+  /* Invoke the closure. */
+  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+  return cif->rtype->type;
+}
+
+#endif /* FFI_CLOSURES */
index 9378ed0da483ac2cbd518100b281c16715bcb7f1..2e6fbaeec0ad4d308798ec57c8e8a601b0394738 100644 (file)
@@ -153,7 +153,13 @@ typedef enum ffi_abi {
 
 /* ---- Definitions for closures ----------------------------------------- */
 
+#if defined(FFI_MIPS_O32)
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 20
+#else
+/* N32/N64 not implemented yet. */
 #define FFI_CLOSURES 0
+#endif /* FFI_MIPS_O32 */
 #define FFI_NATIVE_RAW_API 0
 
 #endif
index 295095f1ed87d246b5bee04301b666eb2de287fe..e2dfa8debdb14647b4cd921a8d37164e18353e12 100644 (file)
 #define flags   a3
                
 #define SIZEOF_FRAME   ( 4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG )
+#define SIZEOF_FRAME2  ( 8 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG )
 
        .text
        .align  2
        .globl  ffi_call_O32
        .ent    ffi_call_O32
 ffi_call_O32:  
-
+$LFB0:
        # Prologue
        SUBU    $sp, SIZEOF_FRAME                       # Frame size
+$LCFI0:
        REG_S   $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp)       # Save frame pointer
+$LCFI1:
        REG_S   ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)        # Save return address
+$LCFI2:
        move    $fp, $sp
 
+$LCFI3:
        move    t9, callback    # callback function pointer
        REG_S   flags, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # flags
 
@@ -136,9 +141,18 @@ call_it:
        REG_L   t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
        beqz    t1, noretval
 
-       bne     t2, FFI_TYPE_INT, retfloat
+       bne     t2, FFI_TYPE_INT, retlonglong
+       jal     t9
+       REG_L   t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+       REG_S   v0, 0(t0)
+       b       epilogue
+
+retlonglong:
+       # Really any 64-bit int, signed or not.
+       bne     t2, FFI_TYPE_UINT64, retfloat
        jal     t9
        REG_L   t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+       REG_S   v1, 4(t0)
        REG_S   v0, 0(t0)
        b       epilogue
 
@@ -167,6 +181,159 @@ epilogue:
        ADDU    $sp, SIZEOF_FRAME                     # Fix stack pointer
        j       ra
 
+$LFE0:
        .end    ffi_call_O32
-       
+
+
+/* ffi_closure_O32. Expects address of the passed-in ffi_closure
+       in t0. Stores any arguments passed in registers onto the
+       stack, then calls ffi_closure_mips_inner_O32, which
+       then decodes them. */
+
+       .text
+       .align  2
+       .globl  ffi_closure_O32
+       .ent    ffi_closure_O32
+ffi_closure_O32:
+$LFB1:
+       # Prologue
+       .frame  $fp, SIZEOF_FRAME2, $31
+       .set    noreorder
+       .cpload $25
+       .set    reorder
+       SUBU    $sp, SIZEOF_FRAME2
+       .cprestore SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG
+$LCFI4:
+       REG_S   $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)       # Save frame pointer
+$LCFI5:
+       REG_S   ra, SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)        # Save return address
+$LCFI6:
+       move    $fp, $sp
+
+$LCFI7:
+       # Store all possible argument registers. If there are more than
+       # four arguments, then they should be stored above where we put $7.
+       REG_S   $4, SIZEOF_FRAME2 + 0*FFI_SIZEOF_ARG($fp)
+       REG_S   $5, SIZEOF_FRAME2 + 1*FFI_SIZEOF_ARG($fp)
+       REG_S   $6, SIZEOF_FRAME2 + 2*FFI_SIZEOF_ARG($fp)
+       REG_S   $7, SIZEOF_FRAME2 + 3*FFI_SIZEOF_ARG($fp)
+
+       # Store all possible float/double registers.
+       s.d     $f12, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG($fp)
+       s.d     $f14, SIZEOF_FRAME2 -  8*FFI_SIZEOF_ARG($fp)
+
+       # Call ffi_closure_mips_inner_O32 to do the work.
+       la      $25, ffi_closure_mips_inner_O32
+       move    $4, $8   # Pointer to the ffi_closure
+       addu    $5, $fp, SIZEOF_FRAME2 -  4*FFI_SIZEOF_ARG
+       addu    $6, $fp, SIZEOF_FRAME2 +  0*FFI_SIZEOF_ARG
+       addu    $7, $fp, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG
+       jal     $31, $25
+
+       # Load the return value into the appropriate register.
+       move    $8, $2
+       li      $9, FFI_TYPE_VOID
+       beq     $8, $9, closure_done
+
+       li      $9, FFI_TYPE_FLOAT
+       l.s     $f0, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
+       beq     $8, $9, closure_done
+
+       li      $9, FFI_TYPE_DOUBLE
+       l.d     $f0, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
+       beq     $8, $9, closure_done
+
+       li      $9, FFI_TYPE_SINT64
+       REG_L   $3, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($fp)
+       beq     $8, $9, integer
+
+       li      $9, FFI_TYPE_UINT64
+       REG_L   $3, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($fp)
+       beq     $8, $9, integer
+
+integer:
+       REG_L   $2, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
+
+closure_done:
+       # Epilogue
+       move    $sp, $fp
+       REG_L   $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)       # Restore frame pointer
+       REG_L   ra,  SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)       # Restore return address
+       ADDU    $sp, SIZEOF_FRAME2
+       j       ra
+$LFE1:
+       .end    ffi_closure_O32
+
+/* DWARF-2 unwind info. */
+
+       .section        .eh_frame,"a",@progbits
+$Lframe0:
+       .4byte  $LECIE0-$LSCIE0  # Length of Common Information Entry
+$LSCIE0:
+       .4byte  0x0      # CIE Identifier Tag
+       .byte   0x1      # CIE Version
+       .ascii "zR\0"    # CIE Augmentation
+       .uleb128 0x1     # CIE Code Alignment Factor
+       .sleb128 4       # CIE Data Alignment Factor
+       .byte   0x1f     # CIE RA Column
+       .uleb128 0x1     # Augmentation size
+       .byte   0x1b     # FDE Encoding (pcrel sdata4)
+       .byte   0xc      # DW_CFA_def_cfa
+       .uleb128 0x1d
+       .uleb128 0x0
+       .align  2
+$LECIE0:
+$LSFDE0:
+       .4byte  $LEFDE0-$LASFDE0         # FDE Length
+$LASFDE0:
+       .4byte  $LASFDE0-$Lframe0        # FDE CIE offset
+       .4byte  $LFB0-.  # FDE initial location
+       .4byte  $LFE0-$LFB0      # FDE address range
+       .uleb128 0x0     # Augmentation size
+       .byte   0x4      # DW_CFA_advance_loc4
+       .4byte  $LCFI0-$LFB0
+       .byte   0xe      # DW_CFA_def_cfa_offset
+       .uleb128 0x18
+       .byte   0x4      # DW_CFA_advance_loc4
+       .4byte  $LCFI2-$LCFI0
+       .byte   0x11     # DW_CFA_offset_extended_sf
+       .uleb128 0x1e    # $fp
+       .sleb128 -2      # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
+       .byte   0x11     # DW_CFA_offset_extended_sf
+       .uleb128 0x1f    # $ra
+       .sleb128 -1      # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
+       .byte   0x4      # DW_CFA_advance_loc4
+       .4byte  $LCFI3-$LCFI2
+       .byte   0xc      # DW_CFA_def_cfa
+       .uleb128 0x1e
+       .uleb128 0x18
+       .align  2
+$LEFDE0:
+$LSFDE1:
+       .4byte  $LEFDE1-$LASFDE1         # FDE Length
+$LASFDE1:
+       .4byte  $LASFDE1-$Lframe0        # FDE CIE offset
+       .4byte  $LFB1-.  # FDE initial location
+       .4byte  $LFE1-$LFB1      # FDE address range
+       .uleb128 0x0     # Augmentation size
+       .byte   0x4      # DW_CFA_advance_loc4
+       .4byte  $LCFI4-$LFB1
+       .byte   0xe      # DW_CFA_def_cfa_offset
+       .uleb128 0x28
+       .byte   0x4      # DW_CFA_advance_loc4
+       .4byte  $LCFI6-$LCFI4
+       .byte   0x11     # DW_CFA_offset_extended_sf
+       .uleb128 0x1e    # $fp
+       .sleb128 -2      # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
+       .byte   0x11     # DW_CFA_offset_extended_sf
+       .uleb128 0x1f    # $ra
+       .sleb128 -1      # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
+       .byte   0x4      # DW_CFA_advance_loc4
+       .4byte  $LCFI7-$LCFI6
+       .byte   0xc      # DW_CFA_def_cfa
+       .uleb128 0x1e
+       .uleb128 0x28
+       .align  2
+$LEFDE1:
+
 #endif