summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>2001-03-24 03:26:28 +0000
committertromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>2001-03-24 03:26:28 +0000
commit384eea1fc8299ebaac0f4986fc31e16a57ece2ad (patch)
treeed1fbe0280cc5d220154b3aa521122d435ce370e
parent46da8d1dc657ba92789bca6785a52fe3d5c80db8 (diff)
downloadgcc-384eea1fc8299ebaac0f4986fc31e16a57ece2ad.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@40807 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--libffi/ChangeLog15
-rw-r--r--libffi/Makefile.am5
-rw-r--r--libffi/Makefile.in7
-rw-r--r--libffi/include/ffi.h.in6
-rw-r--r--libffi/src/powerpc/ffi.c257
-rw-r--r--libffi/src/powerpc/ppc_closure.S148
6 files changed, 433 insertions, 5 deletions
diff --git a/libffi/ChangeLog b/libffi/ChangeLog
index 2110d5b227f..0e92ba64f85 100644
--- a/libffi/ChangeLog
+++ b/libffi/ChangeLog
@@ -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.
diff --git a/libffi/Makefile.am b/libffi/Makefile.am
index 44b169b2a98..8d2eb537486 100644
--- a/libffi/Makefile.am
+++ b/libffi/Makefile.am
@@ -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@)
diff --git a/libffi/Makefile.in b/libffi/Makefile.in
index a9cdfb26fc1..a064a32662e 100644
--- a/libffi/Makefile.in
+++ b/libffi/Makefile.in
@@ -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 \
diff --git a/libffi/include/ffi.h.in b/libffi/include/ffi.h.in
index 17c383d3167..7161e51e92a 100644
--- a/libffi/include/ffi.h.in
+++ b/libffi/include/ffi.h.in
@@ -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
diff --git a/libffi/src/powerpc/ffi.c b/libffi/src/powerpc/ffi.c
index 6d12d653baa..c93aec0ed87 100644
--- a/libffi/src/powerpc/ffi.c
+++ b/libffi/src/powerpc/ffi.c
@@ -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
index 00000000000..311857724cc
--- /dev/null
+++ b/libffi/src/powerpc/ppc_closure.S
@@ -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)
+
+
+
+