This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[m68k 04/13] libffi fixes and closure support
- From: zippel at linux-m68k dot org
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 30 Jan 2007 12:26:19 +0100
- Subject: [m68k 04/13] libffi fixes and closure support
- References: <20070130112615.782382000@linux-m68k.org>
Hi,
The first part of this patch fixes numerous test suite failures,
especially return value handling was broken for various types.
The second part adds closure support.
One question here might be about frame information handling, older
assemblers don't support the cfi instructions, but I'd really like to
avoid having to hardcode this like other ports, as this is impossible to
maintain. Is there maybe a way to make this conditional?
2007-01-30 Roman Zippel <zippel@linux-m68k.org>
* libffi/src/m68k/ffi.c (ffi_prep_args,ffi_prep_cif_machdep),
libffi/src/m68k/sysv.S (ffi_call_SYSV): fix numerous test
suite failures
* libffi/src/m68k/ffi.c (ffi_prep_incoming_args_SYSV,
ffi_closure_SYSV_inner,ffi_prep_closure), libffi/src/m68k/sysv.S
(ffi_closure_SYSV,ffi_closure_struct_SYSV): New, add closure support
---
libffi/src/m68k/ffi.c | 214 ++++++++++++++++++++++++++++++++------------
libffi/src/m68k/ffitarget.h | 3
libffi/src/m68k/sysv.S | 126 +++++++++++++++++++++++--
3 files changed, 273 insertions(+), 70 deletions(-)
Index: egcs/libffi/src/m68k/ffi.c
===================================================================
--- egcs.orig/libffi/src/m68k/ffi.c
+++ egcs/libffi/src/m68k/ffi.c
@@ -8,11 +8,24 @@
#include <ffi_common.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <asm/cachectl.h>
+
+void ffi_call_SYSV (extended_cif *,
+ unsigned, unsigned,
+ void *, void (*fn) ());
+void *ffi_prep_args (void *stack, extended_cif *ecif);
+void ffi_closure_SYSV (ffi_closure *);
+void ffi_closure_struct_SYSV (ffi_closure *);
+unsigned int ffi_closure_SYSV_inner (ffi_closure *closure,
+ void *resp, void *args);
+
/* ffi_prep_args is called by the assembly routine once stack space has
been allocated for the function's arguments. */
-static void *
+void *
ffi_prep_args (void *stack, extended_cif *ecif)
{
unsigned int i;
@@ -24,7 +37,7 @@ ffi_prep_args (void *stack, extended_cif
argp = stack;
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
- && ecif->cif->rtype->size > 8)
+ && !ecif->cif->flags)
struct_value_ptr = ecif->rvalue;
else
struct_value_ptr = NULL;
@@ -37,44 +50,47 @@ ffi_prep_args (void *stack, extended_cif
{
size_t z;
- /* Align if necessary. */
- if (((*p_arg)->alignment - 1) & (unsigned) argp)
- argp = (char *) ALIGN (argp, (*p_arg)->alignment);
-
- z = (*p_arg)->size;
- if (z < sizeof (int))
+ z = (*p_arg)->size;
+ if (z < sizeof (int))
+ {
+ switch ((*p_arg)->type)
{
- switch ((*p_arg)->type)
- {
- case FFI_TYPE_SINT8:
- *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
- break;
-
- case FFI_TYPE_UINT8:
- *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
- break;
-
- case FFI_TYPE_SINT16:
- *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
- break;
-
- case FFI_TYPE_UINT16:
- *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
- break;
-
- case FFI_TYPE_STRUCT:
- memcpy (argp + sizeof (int) - z, *p_argv, z);
- break;
-
- default:
- FFI_ASSERT (0);
- }
- z = sizeof (int);
+ case FFI_TYPE_SINT8:
+ *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ memcpy (argp + sizeof (int) - z, *p_argv, z);
+ break;
+
+ default:
+ FFI_ASSERT (0);
}
- else
- memcpy (argp, *p_argv, z);
- p_argv++;
- argp += z;
+ z = sizeof (int);
+ }
+ else
+ {
+ memcpy (argp, *p_argv, z);
+
+ /* Align if necessary. */
+ if ((sizeof(int) - 1) & z)
+ z = ALIGN(z, sizeof(int));
+ }
+
+ p_argv++;
+ argp += z;
}
return struct_value_ptr;
@@ -86,7 +102,8 @@ ffi_prep_args (void *stack, extended_cif
#define CIF_FLAGS_DOUBLE 8
#define CIF_FLAGS_LDOUBLE 16
#define CIF_FLAGS_POINTER 32
-#define CIF_FLAGS_STRUCT 64
+#define CIF_FLAGS_STRUCT1 64
+#define CIF_FLAGS_STRUCT2 128
/* Perform machine dependent cif processing */
ffi_status
@@ -100,12 +117,24 @@ ffi_prep_cif_machdep (ffi_cif *cif)
break;
case FFI_TYPE_STRUCT:
- if (cif->rtype->size > 4 && cif->rtype->size <= 8)
- cif->flags = CIF_FLAGS_DINT;
- else if (cif->rtype->size <= 4)
- cif->flags = CIF_FLAGS_STRUCT;
- else
- cif->flags = 0;
+ switch (cif->rtype->size)
+ {
+ case 1:
+ cif->flags = CIF_FLAGS_STRUCT1;
+ break;
+ case 2:
+ cif->flags = CIF_FLAGS_STRUCT2;
+ break;
+ case 4:
+ cif->flags = CIF_FLAGS_INT;
+ break;
+ case 8:
+ cif->flags = CIF_FLAGS_DINT;
+ break;
+ default:
+ cif->flags = 0;
+ break;
+ }
break;
case FFI_TYPE_FLOAT:
@@ -137,11 +166,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
return FFI_OK;
}
-extern void ffi_call_SYSV (void *(*) (void *, extended_cif *),
- extended_cif *,
- unsigned, unsigned, unsigned,
- void *, void (*fn) ());
-
void
ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
{
@@ -149,7 +173,7 @@ ffi_call (ffi_cif *cif, void (*fn) (), v
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. */
@@ -159,13 +183,11 @@ ffi_call (ffi_cif *cif, void (*fn) (), v
ecif.rvalue = alloca (cif->rtype->size);
else
ecif.rvalue = rvalue;
-
-
- switch (cif->abi)
+
+ switch (cif->abi)
{
case FFI_SYSV:
- ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes,
- cif->flags, cif->rtype->size * 8,
+ ffi_call_SYSV (&ecif, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
@@ -174,3 +196,83 @@ ffi_call (ffi_cif *cif, void (*fn) (), v
break;
}
}
+
+static void
+ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
+{
+ unsigned int i;
+ void **p_argv;
+ char *argp;
+ ffi_type **p_arg;
+
+ argp = stack;
+ p_argv = avalue;
+
+ for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
+ {
+ size_t z;
+
+ z = (*p_arg)->size;
+ if (z <= 4)
+ {
+ *p_argv = (void *) (argp + 4 - z);
+
+ z = 4;
+ }
+ else
+ {
+ *p_argv = (void *) argp;
+
+ /* Align if necessary */
+ if ((sizeof(int) - 1) & z)
+ z = ALIGN(z, sizeof(int));
+ }
+
+ p_argv++;
+ argp += z;
+ }
+}
+
+unsigned int
+ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args)
+{
+ ffi_cif *cif;
+ void **arg_area;
+
+ cif = closure->cif;
+ arg_area = (void**) alloca (cif->nargs * sizeof (void *));
+
+ ffi_prep_incoming_args_SYSV(args, arg_area, cif);
+
+ (closure->fun) (cif, resp, arg_area, closure->user_data);
+
+ return cif->flags;
+}
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data)
+{
+ FFI_ASSERT (cif->abi == FFI_SYSV);
+
+ *(unsigned short *)closure->tramp = 0x207c;
+ *(void **)(closure->tramp + 2) = closure;
+ *(unsigned short *)(closure->tramp + 6) = 0x4ef9;
+ if (cif->rtype->type == FFI_TYPE_STRUCT
+ && !cif->flags)
+ *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
+ else
+ *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
+
+ syscall(SYS_cacheflush, closure->tramp, FLUSH_SCOPE_LINE,
+ FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE);
+
+ closure->cif = cif;
+ closure->user_data = user_data;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
Index: egcs/libffi/src/m68k/ffitarget.h
===================================================================
--- egcs.orig/libffi/src/m68k/ffitarget.h
+++ egcs/libffi/src/m68k/ffitarget.h
@@ -40,7 +40,8 @@ typedef enum ffi_abi {
/* ---- Definitions for closures ----------------------------------------- */
-#define FFI_CLOSURES 0
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 16
#define FFI_NATIVE_RAW_API 0
#endif
Index: egcs/libffi/src/m68k/sysv.S
===================================================================
--- egcs.orig/libffi/src/m68k/sysv.S
+++ egcs/libffi/src/m68k/sysv.S
@@ -12,36 +12,44 @@
.globl ffi_call_SYSV
.type ffi_call_SYSV,@function
+ .align 4
ffi_call_SYSV:
+ .cfi_startproc
link %fp,#0
+ .cfi_offset 14,-8
+ .cfi_def_cfa 14,8
move.l %d2,-(%sp)
+ .cfi_offset 2,-12
| Make room for all of the new args.
- sub.l 16(%fp),%sp
+ sub.l 12(%fp),%sp
| Call ffi_prep_args
- move.l 12(%fp),-(%sp)
+ move.l 8(%fp),-(%sp)
pea 4(%sp)
- move.l 8(%fp),%a0
- jsr (%a0)
+#if !defined __PIC__
+ jsr ffi_prep_args
+#else
+ bsr.l ffi_prep_args@PLTPC
+#endif
addq.l #8,%sp
| Pass pointer to struct value, if any
move.l %a0,%a1
| Call the function
- move.l 32(%fp),%a0
+ move.l 24(%fp),%a0
jsr (%a0)
| Remove the space we pushed for the args
- add.l 16(%fp),%sp
+ add.l 12(%fp),%sp
| Load the pointer to storage for the return value
- move.l 28(%fp),%a1
+ move.l 20(%fp),%a1
| Load the return type code
- move.l 20(%fp),%d2
+ move.l 16(%fp),%d2
| If the return value pointer is NULL, assume no return value.
tst.l %a1
@@ -79,19 +87,111 @@ retlongdouble:
retpointer:
btst #5,%d2
- jbeq retstruct
+ jbeq retstruct1
move.l %a0,(%a1)
jbra epilogue
-retstruct:
+retstruct1:
btst #6,%d2
+ jbeq retstruct2
+ move.b %d0,(%a1)
+ jbra epilogue
+
+retstruct2:
+ btst #7,%d2
jbeq noretval
- move.l 24(%fp),%d2
- bfins %d0,(%a1){#0,%d2}
+ move.w %d0,(%a1)
noretval:
epilogue:
move.l (%sp)+,%d2
- unlk %a6
+ unlk %fp
rts
+ .cfi_endproc
.size ffi_call_SYSV,.-ffi_call_SYSV
+
+ .globl ffi_closure_SYSV
+ .type ffi_closure_SYSV, @function
+ .align 4
+
+ffi_closure_SYSV:
+ .cfi_startproc
+ link %fp,#-12
+ .cfi_offset 14,-8
+ .cfi_def_cfa 14,8
+ move.l %sp,-12(%fp)
+ pea 8(%fp)
+ pea -12(%fp)
+ move.l %a0,-(%sp)
+#if !defined __PIC__
+ jsr ffi_closure_SYSV_inner
+#else
+ bsr.l ffi_closure_SYSV_inner@PLTPC
+#endif
+
+ lsr.l #1,%d0
+ jne 1f
+ jcc .Lcls_epilogue
+ move.l -12(%fp),%d0
+.Lcls_epilogue:
+ unlk %fp
+ rts
+1:
+ lea -12(%fp),%a0
+ lsr.l #2,%d0
+ jne 1f
+ jcs .Lcls_ret_float
+ move.l (%a0)+,%d0
+ move.l (%a0),%d1
+ jra .Lcls_epilogue
+.Lcls_ret_float:
+ fmove.s (%a0),%fp0
+ jra .Lcls_epilogue
+1:
+ lsr.l #2,%d0
+ jne 1f
+ jcs .Lcls_ret_ldouble
+ fmove.d (%a0),%fp0
+ jra .Lcls_epilogue
+.Lcls_ret_ldouble:
+ fmove.x (%a0),%fp0
+ jra .Lcls_epilogue
+1:
+ lsr.l #2,%d0
+ jne .Lcls_ret_struct2
+ jcs .Lcls_ret_struct1
+ move.l (%a0),%a0
+ move.l %a0,%d0
+ jra .Lcls_epilogue
+.Lcls_ret_struct1:
+ move.b (%a0),%d0
+ jra .Lcls_epilogue
+.Lcls_ret_struct2:
+ move.w (%a0),%d0
+ jra .Lcls_epilogue
+ .cfi_endproc
+
+ .size ffi_closure_SYSV,.-ffi_closure_SYSV
+
+ .globl ffi_closure_struct_SYSV
+ .type ffi_closure_struct_SYSV, @function
+ .align 4
+
+ffi_closure_struct_SYSV:
+ .cfi_startproc
+ link %fp,#0
+ .cfi_offset 14,-8
+ .cfi_def_cfa 14,8
+ move.l %sp,-12(%fp)
+ pea 8(%fp)
+ move.l %a1,-(%sp)
+ move.l %a0,-(%sp)
+#if !defined __PIC__
+ jsr ffi_closure_SYSV_inner
+#else
+ bsr.l ffi_closure_SYSV_inner@PLTPC
+#endif
+ unlk %fp
+ rts
+ .cfi_endproc
+ .size ffi_closure_struct_SYSV,.-ffi_closure_struct_SYSV
--