OSDN Git Service

libffi closures for Alpha
authorgreen <green@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 8 Dec 2000 19:41:15 +0000 (19:41 +0000)
committergreen <green@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 8 Dec 2000 19:41:15 +0000 (19:41 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@38136 138bc75d-0d04-0410-961f-82ee72b054a4

libffi/ChangeLog
libffi/include/ffi.h.in
libffi/src/alpha/ffi.c
libffi/src/alpha/osf.S

index c409192..71dad41 100644 (file)
@@ -1,3 +1,19 @@
+2000-12-07 Dec  8 11:23:29 2000  Richard Henderson  <rth@redhat.com>
+
+       * src/raw_api.c (ffi_translate_args): Fix typo.
+       (ffi_prep_closure): Likewise.
+
+       * include/ffi.h.in [ALPHA]: Define FFI_CLOSURES and
+       FFI_TRAMPOLINE_SIZE.
+       * src/alpha/ffi.c (ffi_prep_cif_machdep): Adjust minimal
+       cif->bytes for new ffi_call_osf implementation.
+       (ffi_prep_args): Absorb into ...
+       (ffi_call): ... here.  Do all stack allocation here and
+       avoid a callback function.
+       (ffi_prep_closure, ffi_closure_osf_inner): New.
+       * src/alpha/osf.S (ffi_call_osf): Reimplement with no callback.
+       (ffi_closure_osf): New.
+
 2000-09-10  Alexandre Oliva  <aoliva@redhat.com>
 
        * config.guess, config.sub, install-sh: Removed.
index 6be7e23..0d8e707 100644 (file)
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------*-C-*-
    libffi @VERSION@ - Copyright (c) 1996-1999  Cygnus Solutions
 
-   $Id: ffi.h.in,v 1.4 2000/02/25 19:13:44 tromey Exp $
+   $Id: ffi.h.in,v 1.5 2000/04/17 02:15:31 green Exp $
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
@@ -368,6 +368,12 @@ struct ffi_ia64_trampoline_struct {
 };
 #define FFI_NATIVE_RAW_API 0
 
+#elif defined(ALPHA)
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 24
+#define FFI_NATIVE_RAW_API 0
+
 #else 
 
 #define FFI_CLOSURES 0
index e3d807a..84ee849 100644 (file)
 
 #include <stdlib.h>
 
-/* ffi_prep_args is called by the assembly routine once stack space
-   has been allocated for the function's arguments */
+extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)());
+extern void ffi_closure_osf(void);
 
-static void
-ffi_prep_args(char *stack, extended_cif *ecif, int bytes, int flags)
+
+ffi_status
+ffi_prep_cif_machdep(ffi_cif *cif)
 {
-  register long i, avn;
-  register void **p_argv;
-  register char *argp;
-  register ffi_type **p_arg;
-
-  /* To streamline things in the assembly code, we always allocate 12
-     words for loading up the int and fp argument registers.  The layout
-     is as when processing varargs: the 6 fp args, the 6 int args, then
-     the incoming stack.  ARGP points to the first int slot.  */
-  argp = stack + 6 * SIZEOF_ARG;
-  memset (stack, 0, 12 * SIZEOF_ARG);
-
-  if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
+  /* Adjust cif->bytes to represent a minimum 6 words for the temporary
+     register argument loading area.  */
+  if (cif->bytes < 6*SIZEOF_ARG)
+    cif->bytes = 6*SIZEOF_ARG;
+
+  /* Set the return type flag */
+  switch (cif->rtype->type)
     {
-      *(void **) argp = ecif->rvalue;
-      argp += sizeof(void *);
+    case FFI_TYPE_STRUCT:
+    case FFI_TYPE_FLOAT:
+    case FFI_TYPE_DOUBLE:
+      cif->flags = cif->rtype->type;
+      break;
+
+    default:
+      cif->flags = FFI_TYPE_INT;
+      break;
     }
+  
+  return FFI_OK;
+}
+
+void
+ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
+{
+  unsigned long *stack, *argp;
+  long i, avn;
+  ffi_type **arg_types;
+  
+  FFI_ASSERT (cif->abi == FFI_OSF);
+
+  /* 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)
+    rvalue = alloca(cif->rtype->size);
+
+  /* Allocate the space for the arguments, plus 4 words of temp
+     space for ffi_call_osf.  */
+  argp = stack = alloca(cif->bytes + 4*SIZEOF_ARG);
+
+  if (cif->flags == FFI_TYPE_STRUCT)
+    *(void **) argp++ = rvalue;
 
   i = 0;
-  avn = ecif->cif->nargs;
-  p_arg = ecif->cif->arg_types;
-  p_argv = ecif->avalue;
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+
   while (i < avn)
     {
-      size_t z = ALIGN((*p_arg)->size, SIZEOF_ARG);
-
-      switch ((*p_arg)->type)
+      switch ((*arg_types)->type)
        {
        case FFI_TYPE_SINT8:
-         *(SINT64 *) argp = *(SINT8 *)(* p_argv);
+         *(SINT64 *) argp = *(SINT8 *)(* avalue);
          break;
                  
        case FFI_TYPE_UINT8:
-         *(UINT64 *) argp = *(UINT8 *)(* p_argv);
+         *(SINT64 *) argp = *(UINT8 *)(* avalue);
          break;
                  
        case FFI_TYPE_SINT16:
-         *(SINT64 *) argp = *(SINT16 *)(* p_argv);
+         *(SINT64 *) argp = *(SINT16 *)(* avalue);
          break;
                  
        case FFI_TYPE_UINT16:
-         *(UINT64 *) argp = *(UINT16 *)(* p_argv);
+         *(SINT64 *) argp = *(UINT16 *)(* avalue);
          break;
                  
        case FFI_TYPE_SINT32:
-         *(SINT64 *) argp = *(SINT32 *)(* p_argv);
-         break;
-                 
        case FFI_TYPE_UINT32:
-         *(UINT64 *) argp = *(UINT32 *)(* p_argv);
+         /* Note that unsigned 32-bit quantities are sign extended.  */
+         *(SINT64 *) argp = *(SINT32 *)(* avalue);
          break;
-
+                 
        case FFI_TYPE_SINT64:
        case FFI_TYPE_UINT64:
        case FFI_TYPE_POINTER:
-         *(UINT64 *) argp = *(UINT64 *)(* p_argv);
+         *(UINT64 *) argp = *(UINT64 *)(* avalue);
          break;
 
        case FFI_TYPE_FLOAT:
-         if (argp - stack < 12 * SIZEOF_ARG)
+         if (argp - stack < 6)
            {
              /* Note the conversion -- all the fp regs are loaded as
                 doubles.  The in-register format is the same.  */
-             *(double *) (argp - 6 * SIZEOF_ARG) = *(float *)(* p_argv);
+             *(double *) argp = *(float *)(* avalue);
            }
          else
-           *(float *) argp = *(float *)(* p_argv);
+           *(float *) argp = *(float *)(* avalue);
          break;
 
        case FFI_TYPE_DOUBLE:
-         if (argp - stack < 12 * SIZEOF_ARG)
-           *(double *) (argp - 6 * SIZEOF_ARG) = *(double *)(* p_argv);
-         else
-           *(double *) argp = *(double *)(* p_argv);
+         *(double *) argp = *(double *)(* avalue);
          break;
 
        case FFI_TYPE_STRUCT:
-         memcpy(argp, *p_argv, (*p_arg)->size);
+         memcpy(argp, *avalue, (*arg_types)->size);
          break;
 
        default:
          FFI_ASSERT(0);
        }
 
-      argp += z;
-      i++, p_arg++, p_argv++;
+      argp += ALIGN((*arg_types)->size, SIZEOF_ARG) / SIZEOF_ARG;
+      i++, arg_types++, avalue++;
     }
+
+  ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn);
 }
 
-/* Perform machine dependent cif processing */
+
 ffi_status
-ffi_prep_cif_machdep(ffi_cif *cif)
+ffi_prep_closure (ffi_closure* closure,
+                 ffi_cif* cif,
+                 void (*fun)(ffi_cif*, void*, void**, void*),
+                 void *user_data)
 {
-  /* Adjust cif->bytes. to include 12 words for the temporary register
-     argument loading area.  This will be removed before the call.  */
-
-  cif->bytes += 6*SIZEOF_ARG;
-  if (cif->bytes < 12*SIZEOF_ARG)
-    cif->bytes = 12*SIZEOF_ARG;
-
-  /* The stack must be double word aligned, so round bytes up
-     appropriately. */
+  unsigned int *tramp;
 
-  cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
+  FFI_ASSERT (cif->abi == FFI_OSF);
 
-  /* Set the return type flag */
-  switch (cif->rtype->type)
-    {
-    case FFI_TYPE_VOID:
-    case FFI_TYPE_STRUCT:
-      cif->flags = cif->rtype->type;
-      break;
+  tramp = (unsigned int *) &closure->tramp[0];
+  tramp[0] = 0x47fb0401;       /* mov $27,$1           */
+  tramp[1] = 0xa77b0010;       /* ldq $27,16($27)      */
+  tramp[2] = 0x6bfb0000;       /* jmp $31,($27),0      */
+  tramp[3] = 0x47ff041f;       /* nop                  */
+  *(void **) &tramp[4] = ffi_closure_osf;
 
-    case FFI_TYPE_FLOAT:
-      cif->flags = FFI_TYPE_FLOAT;
-      break;
+  closure->cif = cif;
+  closure->fun = fun;
+  closure->user_data = user_data;
 
-    case FFI_TYPE_DOUBLE:
-      cif->flags = FFI_TYPE_DOUBLE;
-      break;
+  /* Flush the Icache.  */
+  asm volatile ("imb" : : : "memory");
 
-    default:
-      cif->flags = FFI_TYPE_INT;
-      break;
-    }
-  
   return FFI_OK;
 }
 
-extern int ffi_call_osf(void (*)(char *, extended_cif *, int, int), 
-                       extended_cif *, unsigned, 
-                       unsigned, unsigned *, void (*)());
-
-void
-ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
+int
+ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
 {
-  extended_cif ecif;
+  ffi_cif *cif;
+  void **avalue;
+  ffi_type **arg_types;
+  long i, avn, argn;
 
-  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.  */
+  cif = closure->cif;
+  avalue = alloca(cif->nargs * sizeof(void *));
+
+  argn = 0;
+
+  /* Copy the caller's structure return address to that the closure
+     returns the data directly to the caller.  */
+  if (cif->flags == FFI_TYPE_STRUCT)
+    {
+      rvalue = (void *) argp[0];
+      argn = 1;
+    }
+
+  i = 0;
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
   
-  if (rvalue == NULL && cif->rtype->type == FFI_TYPE_STRUCT)
-    ecif.rvalue = alloca(cif->rtype->size);
-  else
-    ecif.rvalue = rvalue;
-    
-  switch (cif->abi) 
+  /* Grab the addresses of the arguments from the stack frame.  */
+  while (i < avn)
     {
-    case FFI_OSF:
-      ffi_call_osf(ffi_prep_args, &ecif, cif->bytes, 
-                  cif->flags, rvalue, fn);
-      break;
+      switch ((*arg_types)->type)
+       {
+       case FFI_TYPE_SINT8:
+       case FFI_TYPE_UINT8:
+       case FFI_TYPE_SINT16:
+       case FFI_TYPE_UINT16:
+       case FFI_TYPE_SINT32:
+       case FFI_TYPE_UINT32:
+       case FFI_TYPE_SINT64:
+       case FFI_TYPE_UINT64:
+       case FFI_TYPE_POINTER:
+       case FFI_TYPE_STRUCT:
+         *avalue = &argp[argn];
+         break;
 
-    default:
-      FFI_ASSERT(0);
-      break;
+       case FFI_TYPE_FLOAT:
+         if (argn < 6)
+           {
+             /* Floats coming from registers need conversion from double
+                back to float format.  */
+             *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6];
+             *avalue = &argp[argn - 6];
+           }
+         else
+           *avalue = &argp[argn];
+         break;
+
+       case FFI_TYPE_DOUBLE:
+         *avalue = &argp[argn - (argn < 6 ? 6 : 0)];
+         break;
+
+       default:
+         FFI_ASSERT(0);
+       }
+
+      argn += ALIGN((*arg_types)->size, SIZEOF_ARG) / SIZEOF_ARG;
+      i++, arg_types++, avalue++;
     }
+
+  /* Invoke the closure.  */
+  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+  /* Tell ffi_closure_osf what register to put the return value in.  */
+  return cif->flags;
 }
index 2078683..9ed37cb 100644 (file)
 #define LIBFFI_ASM     
 #include <ffi.h>
 
-#define callback $16
-#define ecifp   $17
-#define bytes   $18
-#define flags   $19
-#define raddr    $20
-#define fn       $21
+       .text
 
-#define flags_ofs      16
-#define raddr_ofs      24
-#define fn_ofs         32
+/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags,
+                void *raddr, void (*fnaddr)());
 
-#define SIZEOF_FRAME   (6*8)
+   Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
+   for this function.  This has been allocated by ffi_call.  We also
+   deallocate some of the stack that has been alloca'd.  */
 
-       .text
-       .align  4
+       .align  3
        .globl  ffi_call_osf
        .ent    ffi_call_osf
-       
 ffi_call_osf:
-       lda     $30, -SIZEOF_FRAME($30)
-       stq     $26, 0($30)
-       stq     $15, 8($30)
-       stq     flags, flags_ofs($30)
-       stq     raddr, raddr_ofs($30)
-       stq     fn, fn_ofs($30)
-       mov     $30, $15
-       .frame  $15, SIZEOF_FRAME, $26, 0
-        .mask   0x4008000, -SIZEOF_FRAME
+       .frame  $15, 32, $26, 0
+       .mask   0x4008000, -32
+       addq    $16,$17,$1
+       mov     $16, $30
+       stq     $26, 0($1)
+       stq     $15, 8($1)
+       stq     $18, 16($1)
+       mov     $1, $15
        .prologue 0
 
-       mov     callback, $27           # mov callback into place
-       subq    $30, bytes, $30         # allocate stack space
-       
-       # Call ffi_prep_args; ecif, bytes and flags are already in place.
-       mov     $30, $16                # push stack arg
-       jsr     $26, ($27), 0
+       stq     $19, 24($1)
+       mov     $20, $27
 
        # Load up all of the (potential) argument registers.
+       ldq     $16, 0($30)
        ldt     $f16, 0($30)
        ldt     $f17, 8($30)
+       ldq     $17, 8($30)
        ldt     $f18, 16($30)
+       ldq     $18, 16($30)
        ldt     $f19, 24($30)
+       ldq     $19, 24($30)
        ldt     $f20, 32($30)
+       ldq     $20, 32($30)
        ldt     $f21, 40($30)
-       ldq     $16, 48($30)
-       ldq     $17, 56($30)
-       ldq     $18, 64($30)
-       ldq     $19, 72($30)
-       ldq     $20, 80($30)
-       ldq     $21, 88($30)
-
-       # Get rid of the arg reg temp space and call the function.
-       ldq     $27, fn_ofs($15)
-       lda     $30, 12*8($30)
+       ldq     $21, 40($30)
+
+       # Deallocate the register argument area.
+       lda     $30, 48($30)
+
        jsr     $26, ($27), 0
+       ldgp    $29, 0($26)
 
        # If the return value pointer is NULL, assume no return value.
-       ldq     raddr, raddr_ofs($15)
-       beq     raddr, $noretval
+       ldq     $19, 24($15)
+       ldq     $18, 16($15)
+       ldq     $26, 0($15)
+       beq     $19, $noretval
 
-       ldq     flags, flags_ofs($15)
-       cmpeq   flags, FFI_TYPE_INT, $1
+       # Store the return value out in the proper type.
+       cmpeq   $18, FFI_TYPE_INT, $1
        bne     $1, $retint
-       cmpeq   flags, FFI_TYPE_FLOAT, $2
+       cmpeq   $18, FFI_TYPE_FLOAT, $2
        bne     $2, $retfloat
-       cmpeq   flags, FFI_TYPE_DOUBLE, $3
+       cmpeq   $18, FFI_TYPE_DOUBLE, $3
        bne     $3, $retdouble
-       br      $retstruct
-       
-       .align 3
+
+$noretval:
+       ldq     $15, 8($15)
+       ret
+
 $retint:
-       stq     $0, 0(raddr)
-       br      $noretval
+       stq     $0, 0($19)
+       nop
+       ldq     $15, 8($15)
+       ret
+
 $retfloat:
-       sts     $f0, 0(raddr)
-       br      $noretval
-$retdouble:
-       stt     $f0, 0(raddr)
+       sts     $f0, 0($19)
+       nop
+       ldq     $15, 8($15)
+       ret
 
-$retstruct:
-$noretval:
-       mov     $15, $30
-       ldq     $26, 0($15)
+$retdouble:
+       stt     $f0, 0($19)
+       nop
        ldq     $15, 8($15)
-       lda     $30, SIZEOF_FRAME($30)
        ret
 
        .end    ffi_call_osf
+
+/* ffi_closure_osf(...)
+
+   Receives the closure argument in $1.   */
+
+       .align  3
+       .globl  ffi_closure_osf
+       .ent    ffi_closure_osf
+ffi_closure_osf:
+       .frame  $30, 16*8, $26, 0
+       .mask   0x4000000, -14*8
+       ldgp    $29, 0($27)
+       subq    $30, 14*8, $30
+       stq     $26, 0($30)
+       .prologue 1
+
+       # Store all of the potential argument registers in va_list format.
+       stt     $f16, 4*8($30)
+       stt     $f17, 5*8($30)
+       stt     $f18, 6*8($30)
+       stt     $f19, 7*8($30)
+       stt     $f20, 8*8($30)
+       stt     $f21, 9*8($30)
+       stq     $16, 10*8($30)
+       stq     $17, 11*8($30)
+       stq     $18, 12*8($30)
+       stq     $19, 13*8($30)
+       stq     $20, 14*8($30)
+       stq     $21, 15*8($30)
+
+       # Call ffi_closure_osf_inner to do the bulk of the work.
+       mov     $1, $16
+       lda     $17, 2*8($30)
+       lda     $18, 10*8($30)
+       jsr     $26, ffi_closure_osf_inner
+       ldgp    $29, 0($26)
+       ldq     $26, 0($30)
+
+       # Load up the return value in the proper type.
+       cmpeq   $0, FFI_TYPE_INT, $1
+       bne     $1, $loadint
+       cmpeq   $0, FFI_TYPE_FLOAT, $2
+       bne     $2, $loadfloat
+       cmpeq   $18, FFI_TYPE_DOUBLE, $3
+       bne     $3, $loaddouble
+
+       addq    $30, 16*8, $30
+       ret
+
+       .align 3
+$loadint:
+       ldq     $0, 16($30)
+       nop
+       addq    $30, 16*8, $30
+       ret
+
+$loadfloat:
+       lds     $f0, 16($30)
+       nop
+       addq    $30, 16*8, $30
+       ret
+
+$loaddouble:
+       ldt     $f0, 16($30)
+       nop
+       addq    $30, 16*8, $30
+       ret
+
+       .end    ffi_closure_osf