]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ppc_closure.S: New file.
authorKevin B Hendricks <khendricks@ivey.uwo.ca>
Sat, 24 Mar 2001 03:26:28 +0000 (03:26 +0000)
committerTom Tromey <tromey@gcc.gnu.org>
Sat, 24 Mar 2001 03:26:28 +0000 (03:26 +0000)
* src/powerpc/ppc_closure.S: New file.
* src/powerpc/ffi.c (ffi_prep_args): Fixed ABI compatibility bug
involving long long and register pairs.
(ffi_prep_closure): New function.
(flush_icache): Likewise.
(ffi_closure_helper_SYSV): Likewise.
* include/ffi.h.in (FFI_CLOSURES): Define on PPC.
(FFI_TRAMPOLINE_SIZE): Likewise.
(FFI_NATIVE_RAW_API): Likewise.
* Makefile.in: Rebuilt.
* Makefile.am (EXTRA_DIST): Added src/powerpc/ppc_closure.S.
(TARGET_SRC_POWERPC): Likewise.

From-SVN: r40807

libffi/ChangeLog
libffi/Makefile.am
libffi/Makefile.in
libffi/include/ffi.h.in
libffi/src/powerpc/ffi.c
libffi/src/powerpc/ppc_closure.S [new file with mode: 0644]

index 2110d5b227feb3dc269447a199fa2c5be589c064..0e92ba64f85506be8c16d90ebf0b6874bc19230c 100644 (file)
@@ -1,3 +1,18 @@
+2001-03-23  Tom Tromey  <tromey@redhat.com>
+
+       * src/powerpc/ppc_closure.S: New file.
+       * src/powerpc/ffi.c (ffi_prep_args): Fixed ABI compatibility bug
+       involving long long and register pairs.
+       (ffi_prep_closure): New function.
+       (flush_icache): Likewise.
+       (ffi_closure_helper_SYSV): Likewise.
+       * include/ffi.h.in (FFI_CLOSURES): Define on PPC.
+       (FFI_TRAMPOLINE_SIZE): Likewise.
+       (FFI_NATIVE_RAW_API): Likewise.
+       * Makefile.in: Rebuilt.
+       * Makefile.am (EXTRA_DIST): Added src/powerpc/ppc_closure.S.
+       (TARGET_SRC_POWERPC): Likewise.
+
 2001-03-19  Tom Tromey  <tromey@redhat.com>
 
        * Makefile.in: Rebuilt.
index 44b169b2a98519483ec161712f2aa149254bfda0..8d2eb53748689934cea11ad7a27a498678546f7b 100644 (file)
@@ -10,7 +10,8 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \
                src/x86/ffi.c src/x86/sysv.S \
                src/alpha/ffi.c src/alpha/osf.S \
                src/m68k/ffi.c src/m68k/sysv.S \
-               src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/asm.h \
+               src/powerpc/ffi.c src/powerpc/sysv.S \
+                src/powerpc/ppc_closure.S src/powerpc/asm.h \
                src/arm/ffi.c src/arm/sysv.S
 
 VPATH = @srcdir@:@srcdir@/src:@srcdir@/src/@TARGETDIR@
@@ -93,7 +94,7 @@ TARGET_SRC_SPARC = src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S
 TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S
 TARGET_SRC_IA64 = src/ia64/ffi.c src/ia64/unix.S
 TARGET_SRC_M68K = src/m68k/ffi.c src/m68k/sysv.S
-TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S
+TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S
 TARGET_SRC_ARM =  src/arm/sysv.S src/arm/ffi.c
 
 ##libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c $(TARGET_SRC_@TARGET@)
index a9cdfb26fc10cbb2fedccb712c3394ee58e2d6e9..a064a32662e5863cd6b14bf00ee4f3d3ad0a2369 100644 (file)
@@ -86,7 +86,8 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \
                src/x86/ffi.c src/x86/sysv.S \
                src/alpha/ffi.c src/alpha/osf.S \
                src/m68k/ffi.c src/m68k/sysv.S \
-               src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/asm.h \
+               src/powerpc/ffi.c src/powerpc/sysv.S \
+                src/powerpc/asm.h src/powerpc/ppc_closure.S \
                src/arm/ffi.c src/arm/sysv.S
 
 
@@ -159,7 +160,7 @@ TARGET_SRC_SPARC = src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S
 TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S
 TARGET_SRC_IA64 = src/ia64/ffi.c src/ia64/unix.S
 TARGET_SRC_M68K = src/m68k/ffi.c src/m68k/sysv.S
-TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S
+TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S
 TARGET_SRC_ARM = src/arm/sysv.S src/arm/ffi.c
 
 libffi_la_common_SOURCES = src/debug.c src/prep_cif.c src/types.c \
@@ -206,7 +207,7 @@ libffi_la_LIBADD =
 @MIPS_SGI_TRUE@am_libffi_la_OBJECTS =  debug.lo prep_cif.lo types.lo \
 @MIPS_SGI_TRUE@raw_api.lo java_raw_api.lo ffi.lo o32.lo n32.lo
 @POWERPC_TRUE@am_libffi_la_OBJECTS =  debug.lo prep_cif.lo types.lo \
-@POWERPC_TRUE@raw_api.lo java_raw_api.lo ffi.lo sysv.lo
+@POWERPC_TRUE@raw_api.lo java_raw_api.lo ffi.lo sysv.lo ppc_closure.lo
 @SPARC_TRUE@am_libffi_la_OBJECTS =  debug.lo prep_cif.lo types.lo \
 @SPARC_TRUE@raw_api.lo java_raw_api.lo ffi.lo v8.lo v9.lo
 @X86_TRUE@am_libffi_la_OBJECTS =  debug.lo prep_cif.lo types.lo \
index 17c383d3167d22aaafea8bbf15ec092b3527c797..7161e51e92a3ebf4e0a5140fe37969c423727587 100644 (file)
@@ -372,6 +372,12 @@ struct ffi_ia64_trampoline_struct {
 #define FFI_TRAMPOLINE_SIZE 24
 #define FFI_NATIVE_RAW_API 0
 
+#elif defined(POWERPC)
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 40
+#define FFI_NATIVE_RAW_API 0
+
 #else 
 
 #define FFI_CLOSURES 0
index 6d12d653baa4e05cab730ff240f05e821519f6f8..c93aec0ed874b9b31c6d6c0c5419fa4d606bb666 100644 (file)
@@ -29,6 +29,9 @@
 #include <ffi_common.h>
 
 #include <stdlib.h>
+#include <stdio.h>
+
+extern void ffi_closure_SYSV(void);
 
 enum {
   /* The assembly depends on these exact flags.  */
@@ -172,6 +175,18 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
            }
          else
            {
+              /* whoops: abi states only certain register pairs
+               * can be used for passing long long int
+               * specifically (r3,r4), (r5,r6), (r7,r8), 
+               * (r9,r10) and if next arg is long long but
+               * not correct starting register of pair then skip
+               * until the proper starting register
+              */
+              if (intarg_count%2 != 0)
+                {
+                  intarg_count ++;
+                  gpr_base++;
+                }
              *(long long *)gpr_base = *(long long *)*p_argv;
              gpr_base += 2;
            }
@@ -421,3 +436,245 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
       break;
     }
 }
+
+
+static void flush_icache(char *, int);
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+                 ffi_cif* cif,
+                 void (*fun)(ffi_cif*, void*, void**, void*),
+                 void *user_data)
+{
+  unsigned int *tramp;
+
+  FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
+
+  tramp = (unsigned int *) &closure->tramp[0];
+  tramp[0] = 0x7c0802a6;  /*   mflr    r0 */
+  tramp[1] = 0x4800000d;  /*   bl      10 <trampoline_initial+0x10> */
+  tramp[4] = 0x7d6802a6;  /*   mflr    r11 */
+  tramp[5] = 0x7c0803a6;  /*   mtlr    r0 */
+  tramp[6] = 0x800b0000;  /*   lwz     r0,0(r11) */
+  tramp[7] = 0x816b0004;  /*   lwz     r11,4(r11) */
+  tramp[8] = 0x7c0903a6;  /*   mtctr   r0 */
+  tramp[9] = 0x4e800420;  /*   bctr */
+  *(void **) &tramp[2] = (void *)ffi_closure_SYSV; /* function */
+  *(void **) &tramp[3] = (void *)closure;          /* context */
+
+  closure->cif = cif;
+  closure->fun = fun;
+  closure->user_data = user_data;
+
+  /* Flush the icache.  */
+  flush_icache(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
+
+  return FFI_OK;
+}
+
+
+#define MIN_CACHE_LINE_SIZE 8
+
+static void flush_icache(char * addr1, int size)
+{
+  int i;
+  char * addr;
+  for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) {
+     addr = addr1 + i;
+     __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" : : "r"(addr) : "memory");
+  }
+  addr = addr1 + size - 1;
+  __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" "sync;" "isync;" : : "r"(addr) : "memory");
+}
+
+
+int ffi_closure_helper_SYSV (ffi_closure*, void*, unsigned long*, 
+                                     unsigned long*, unsigned long*);
+
+/* Basically the trampoline invokes ffi_closure_SYSV, and on 
+ * entry, r11 holds the address of the closure.
+ * After storing the registers that could possibly contain
+ * parameters to be passed into the stack frame and setting
+ * up space for a return value, ffi_closure_SYSV invokes the 
+ * following helper function to do most of the work
+ */
+
+int
+ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue, 
+            unsigned long * pgr, unsigned long * pfr, 
+            unsigned long * pst)
+{
+  /* rvalue is the pointer to space for return value in closure assembly */
+  /* pgr is the pointer to where r3-r10 are stored in ffi_closure_SYSV */
+  /* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV  */
+  /* pst is the pointer to outgoing parameter stack in original caller */
+
+  void **          avalue;
+  ffi_type **      arg_types;
+  long             i, avn;
+  long             nf;   /* number of floating registers already used */
+  long             ng;   /* number of general registers already used */
+  ffi_cif *        cif; 
+  double           temp; 
+
+  cif = closure->cif;
+  avalue = alloca(cif->nargs * sizeof(void *));
+
+  nf = 0;
+  ng = 0;
+
+  /* Copy the caller's structure return value address so that the closure
+     returns the data directly to the caller.  */
+  if (cif->rtype->type == FFI_TYPE_STRUCT)
+    {
+      rvalue = *pgr;
+      ng++;
+      pgr++;
+    }
+
+  i = 0;
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+  
+  /* Grab the addresses of the arguments from the stack frame.  */
+  while (i < avn)
+    {
+      switch (arg_types[i]->type)
+       {
+       case FFI_TYPE_SINT8:
+       case FFI_TYPE_UINT8:
+       /* there are 8 gpr registers used to pass values */
+          if (ng < 8) {
+            avalue[i] = (((char *)pgr)+3);
+             ng++;
+             pgr++;
+          } else {
+             avalue[i] = (((char *)pst)+3);
+             pst++;
+          }
+         break;
+           
+       case FFI_TYPE_SINT16:
+       case FFI_TYPE_UINT16:
+       /* there are 8 gpr registers used to pass values */
+          if (ng < 8) {
+            avalue[i] = (((char *)pgr)+2);
+             ng++;
+             pgr++;
+          } else {
+             avalue[i] = (((char *)pst)+2);
+             pst++;
+          }
+         break;
+
+       case FFI_TYPE_SINT32:
+       case FFI_TYPE_UINT32:
+       case FFI_TYPE_POINTER:
+       case FFI_TYPE_STRUCT:
+       /* there are 8 gpr registers used to pass values */
+          if (ng < 8) {
+            avalue[i] = pgr;
+             ng++;
+             pgr++;
+          } else {
+             avalue[i] = pst;
+             pst++;
+          }
+         break;
+
+       case FFI_TYPE_SINT64:
+       case FFI_TYPE_UINT64:
+         /* passing long long ints are complex, they must
+           * be passed in suitable register pairs such as
+           * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10)
+           * and if the entire pair aren't available then the outgoing
+           * parameter stack is used for both but an alignment of 8
+           * must will be kept.  So we must either look in pgr
+           * or pst to find the correct address for this type
+           * of parameter.
+           */
+           if (ng < 7) {
+              if (ng & 0x01) {
+               /* skip r4, r6, r8 as starting points */
+                  ng++;
+                  pgr++;
+              }
+              avalue[i] = pgr;
+              ng+=2;
+              pgr+=2;
+           } else {
+              if (((long)pst) & 4) pst++;
+              avalue[i] = pst;
+              pst+=2;
+           }
+           break;
+
+       case FFI_TYPE_FLOAT:
+           /* unfortunately float values are stored as doubles
+             * in the ffi_closure_SYSV code (since we don't check
+             * the type in that routine).  This is also true
+             * of floats passed on the outgoing parameter stack.
+             * Also, on the outgoing stack all values are aligned
+             * to 8
+             *
+             * Don't you just love the simplicity of this ABI!
+             */
+
+          /* there are 8 64bit floating point registers */
+
+          if (nf < 8) {
+            temp = *(double*)pfr;
+             *(float*)pfr = (float)temp;
+            avalue[i] = pfr;
+             nf++;
+             pfr+=2;
+          } else {
+           /* FIXME? here we are really changing the values
+             * stored in the original calling routines outgoing
+             * parameter stack.  This is probably a really
+             * naughty thing to do but...
+             */
+            if (((long)pst) & 4) pst++;
+            temp = *(double*)pst;
+             *(float*)pst = (float)temp;
+            avalue[i] = pst;
+             nf++;
+             pst+=2;
+          }
+         break;
+
+       case FFI_TYPE_DOUBLE:
+         /* On the outgoing stack all values are aligned to 8 */
+          /* there are 8 64bit floating point registers */
+
+          if (nf < 8) {
+            avalue[i] = pfr;
+             nf++;
+             pfr+=2;
+          } else {
+            if (((long)pst) & 4) pst++;
+            avalue[i] = pst;
+             nf++;
+             pst+=2;
+          }
+         break;
+
+       default:
+         FFI_ASSERT(0);
+       }
+
+      i++;
+    }
+
+
+  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+  /* Tell ffi_closure_osf how to perform return type promotions.  */
+  return cif->rtype->type;
+
+}
+
+
+
+
+
diff --git a/libffi/src/powerpc/ppc_closure.S b/libffi/src/powerpc/ppc_closure.S
new file mode 100644 (file)
index 0000000..3118577
--- /dev/null
@@ -0,0 +1,148 @@
+#define LIBFFI_ASM
+#include <powerpc/asm.h>
+
+.globl ffi_closure_helper_SYSV
+
+ENTRY(ffi_closure_SYSV)
+       stwu %r1,-144(%r1)
+       mflr %r0
+       stw %r31,140(%r1)
+       stw %r0,148(%r1)
+
+# we want to build up an areas for the parameters passed
+# in registers (both floating point and integer)
+       
+       # so first save gpr 3 to gpr 10 (aligned to 4)
+       stw   %r3, 16(%r1)
+       stw   %r4, 20(%r1)
+       stw   %r5, 24(%r1) 
+       stw   %r6, 28(%r1)
+       stw   %r7, 32(%r1)
+       stw   %r8, 36(%r1) 
+       stw   %r9, 40(%r1)
+       stw   %r10,44(%r1)
+
+       # next save fpr 1 to fpr 8 (aligned to 8)
+       stfd  %f1, 48(%r1)
+       stfd  %f2, 56(%r1)
+       stfd  %f3, 64(%r1)
+       stfd  %f4, 72(%r1)
+       stfd  %f5, 80(%r1)
+       stfd  %f6, 88(%r1)
+       stfd  %f7, 96(%r1)
+       stfd  %f8, 104(%r1)
+
+       # set up registers for the routine that actually does the work
+       # get the context pointer from the trampoline
+       mr %r3,%r11
+       
+        # now load up the pointer to the result storage
+       addi %r4,%r1,112
+       
+       # now load up the pointer to the saved gpr registers
+        addi %r5,%r1,16
+
+        # now load up the pointer to the saved fpr registers */
+        addi %r6,%r1,48
+
+       # now load up the pointer to the outgoing parameter 
+       # stack in the previous frame
+       # i.e. the previous frame pointer + 8
+       addi %r7,%r1,152
+       
+        # make the call
+       bl JUMPTARGET(ffi_closure_helper_SYSV)
+
+       # now r3 contains the return type
+       # so use it to look up in a table
+       # so we know how to deal with each type
+
+        # look up the proper starting point in table 
+       # by using return type as offset
+       addi %r5,%r1,112   # get pointer to results area
+       addis %r4,0,.L60@ha  # get address of jump table
+       addi %r4,%r4,.L60@l
+       slwi %r3,%r3,2         # now multiply return type by 4
+       lwzx %r3,%r4,%r3         # get the contents of that table value
+       add %r3,%r3,%r4          # add contents of table to table address
+       mtctr %r3
+       bctr               # jump to it
+       .align 2
+.L60:
+       .long .L44-.L60    # FFI_TYPE_VOID
+       .long .L50-.L60    # FFI_TYPE_INT
+       .long .L47-.L60    # FFI_TYPE_FLOAT
+       .long .L46-.L60    # FFI_TYPE_DOUBLE
+       .long .L46-.L60    # FFI_TYPE_LONGDOUBLE
+       .long .L56-.L60    # FFI_TYPE_UINT8
+       .long .L55-.L60    # FFI_TYPE_SINT8
+       .long .L58-.L60    # FFI_TYPE_UINT16
+       .long .L57-.L60    # FFI_TYPE_SINT16
+       .long .L50-.L60    # FFI_TYPE_UINT32
+       .long .L50-.L60    # FFI_TYPE_SINT32
+       .long .L48-.L60    # FFI_TYPE_UINT64
+       .long .L48-.L60    # FFI_TYPE_SINT64
+       .long .L44-.L60    # FFI_TYPE_STRUCT
+       .long .L50-.L60    # FFI_TYPE_POINTER
+
+
+# case double
+.L46:   
+        lfd %f1,0(%r5)
+       b .L44
+
+# case float
+.L47:
+       lfs %f1,0(%r5)
+       b .L44
+       
+# case long long
+.L48:
+       lwz %r3,0(%r5)
+       lwz %r4,4(%r5)
+       b .L44
+       
+# case default / int32 / pointer
+.L50:
+       lwz %r3,0(%r5)
+       b .L44
+       
+# case signed int8     
+.L55:
+       addi %r5,%r5,3
+       lbz %r3,0(%r5)
+       extsb %r3,%r3
+       b .L44
+
+# case unsigned int8   
+.L56:
+       addi %r5,%r5,3
+        lbz %r3,0(%r5)
+       b .L44
+
+# case signed int16
+.L57:
+       addi %r5,%r5,2
+       lhz %r3,0(%r5)
+       extsh %r3,%r3
+       b .L44
+
+#case unsigned int16
+.L58:  
+       addi %r5,%r5,2
+       lhz %r3,0(%r5)
+
+# case void / done     
+.L44:
+       
+       lwz %r11,0(%r1)
+       lwz %r0,4(%r11)
+       mtlr %r0
+       lwz %r31,-4(%r11)
+       mr %r1,%r11
+       blr
+END(ffi_closure_SYSV)
+
+
+
+