This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[libffi] closures for sparc
- From: Jeff Sturm <jsturm at one-point dot com>
- To: gcc-patches at gcc dot gnu dot org, <java-patches at gcc dot gnu dot org>
- Date: Sat, 28 Dec 2002 12:13:09 -0500 (EST)
- Subject: [libffi] closures for sparc
This is a repost from July, cleaned up and retested on mainline. It
enables closures for sparc and sparc64, to prepare for enabling the
libjava bytecode interpreter.
Special thanks to Ulrich Weigand for sorting through the difficult
size/endianness/alignment issues for s390x:
http://gcc.gnu.org/ml/java-patches/2002-q4/msg00000.html
Tested on sparcv9-sun-solaris2.8 by running ffitest on sparcv7 and sparcv9
multilibs. Bootstrap successful with GNU binutils and Sun as/ld.
OK for mainline?
2002-12-28 Jeff Sturm <jsturm@one-point.com>
* include/ffi.h.in: Add closure defines for SPARC, SPARC64.
* src/ffitest.c (main): Use static storage for closure.
* src/sparc/ffi.c (ffi_prep_closure, ffi_closure_sparc_inner): New.
* src/sparc/v8.S (ffi_closure_v8): New.
* src/sparc/v9.S (ffi_closure_v9): New.
Index: include/ffi.h.in
===================================================================
RCS file: /cvs/gcc/gcc/libffi/include/ffi.h.in,v
retrieving revision 1.21
diff -u -p -r1.21 ffi.h.in
--- include/ffi.h.in 6 Dec 2002 01:16:44 -0000 1.21
+++ include/ffi.h.in 28 Dec 2002 16:44:23 -0000
@@ -443,6 +443,18 @@ struct ffi_ia64_trampoline_struct {
#define FFI_TRAMPOLINE_SIZE 24 /* see struct below */
#define FFI_NATIVE_RAW_API 0
+#elif defined(SPARC64)
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 24
+#define FFI_NATIVE_RAW_API 0
+
+#elif defined(SPARC)
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 16
+#define FFI_NATIVE_RAW_API 0
+
#elif defined(S390)
#define FFI_CLOSURES 1
Index: src/ffitest.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/ffitest.c,v
retrieving revision 1.9
diff -u -p -r1.9 ffitest.c
--- src/ffitest.c 6 Dec 2002 01:16:45 -0000 1.9
+++ src/ffitest.c 28 Dec 2002 16:44:23 -0000
@@ -1044,7 +1044,9 @@ int main(/*@unused@*/ int argc, /*@unuse
# if FFI_CLOSURES
/* A simple closure test */
{
- ffi_closure cl;
+ /* The closure must not be an automatic variable on
+ platforms (Solaris) that forbid stack execution by default. */
+ static ffi_closure cl;
ffi_type * cl_arg_types[3];
cl_arg_types[0] = &ffi_type_sint;
Index: src/sparc/ffi.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/sparc/ffi.c,v
retrieving revision 1.4
diff -u -p -r1.4 ffi.c
--- src/sparc/ffi.c 18 Jul 2002 23:08:31 -0000 1.4
+++ src/sparc/ffi.c 28 Dec 2002 16:44:23 -0000
@@ -28,6 +28,12 @@
#include <stdlib.h>
+#ifdef SPARC64
+extern void ffi_closure_v9(void);
+#else
+extern void ffi_closure_v8(void);
+#endif
+
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
@@ -408,4 +414,102 @@ void ffi_call(ffi_cif *cif, void (*fn)()
break;
}
+}
+
+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 long fn;
+ unsigned long ctx = (unsigned long) closure;
+
+#ifdef SPARC64
+ /* Trampoline address is equal to the closure address. We take advantage
+ of that to reduce the trampoline size by 8 bytes. */
+ FFI_ASSERT (cif->abi == FFI_V9);
+ fn = (unsigned long) ffi_closure_v9;
+ tramp[0] = 0x83414000; /* rd %pc, %g1 */
+ tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */
+ tramp[2] = 0x81c14000; /* jmp %g5 */
+ tramp[3] = 0x01000000; /* nop */
+ *((unsigned long *) &tramp[4]) = fn;
+#else
+ FFI_ASSERT (cif->abi == FFI_V8);
+ fn = (unsigned long) ffi_closure_v8;
+ tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */
+ tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */
+ tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */
+ tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */
+#endif
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ /* Flush the Icache. FIXME: alignment isn't certain, assume 8 bytes */
+#ifdef SPARC64
+ asm volatile ("flush %0" : : "r" (closure) : "memory");
+ asm volatile ("flush %0" : : "r" (((char *) closure) + 8) : "memory");
+#else
+ asm volatile ("iflush %0" : : "r" (closure) : "memory");
+ asm volatile ("iflush %0" : : "r" (((char *) closure) + 8) : "memory");
+#endif
+
+ return FFI_OK;
+}
+
+int
+ffi_closure_sparc_inner(ffi_closure *closure,
+ void *rvalue, unsigned long *gpr, double *fpr)
+{
+ ffi_cif *cif;
+ void **avalue;
+ ffi_type **arg_types;
+ int i, avn, argn;
+
+ 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 *) gpr[0];
+ argn = 1;
+ }
+
+ i = 0;
+ avn = cif->nargs;
+ arg_types = cif->arg_types;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ while (i < avn)
+ {
+ /* Assume big-endian. FIXME */
+ argn += ALIGN(arg_types[i]->size, SIZEOF_ARG) / SIZEOF_ARG;
+
+#ifdef SPARC64
+ if (i < 6 && (arg_types[i]->type == FFI_TYPE_FLOAT
+ || arg_types[i]->type == FFI_TYPE_DOUBLE
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
+#endif
+ ))
+ avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
+ else
+#endif
+ avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
+ i++;
+ }
+
+ /* Invoke the closure. */
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_sparc how to perform return type promotions. */
+ return cif->rtype->type;
}
Index: src/sparc/v8.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/sparc/v8.S,v
retrieving revision 1.6
diff -u -p -r1.6 v8.S
--- src/sparc/v8.S 28 Apr 2002 19:57:42 -0000 1.6
+++ src/sparc/v8.S 28 Dec 2002 16:44:23 -0000
@@ -94,6 +94,72 @@ longlong:
.ffi_call_V8_end:
.size ffi_call_V8,.ffi_call_V8_end-ffi_call_V8
+
+#define STACKFRAME 104 /* 16*4 register window +
+ 1*4 struct return +
+ 6*4 args backing store +
+ 3*4 locals */
+
+/* ffi_closure_v8(...)
+
+ Receives the closure argument in %g2. */
+
+ .text
+ .align 8
+ .globl ffi_closure_v8
+
+ffi_closure_v8:
+ .register %g2, #scratch
+.LLFB2:
+ save %sp, -STACKFRAME, %sp
+.LLCFI1:
+
+ ! Store all of the potential argument registers in va_list format.
+ st %i0, [%fp+68+0]
+ st %i1, [%fp+68+4]
+ st %i2, [%fp+68+8]
+ st %i3, [%fp+68+12]
+ st %i4, [%fp+68+16]
+ st %i5, [%fp+68+20]
+
+ ! Call ffi_closure_sparc_inner to do the bulk of the work.
+ mov %g2, %o0
+ add %fp, -8, %o1
+ add %fp, 68, %o2
+ call ffi_closure_sparc_inner
+ mov 0, %o3
+
+ ! Load up the return value in the proper type.
+ cmp %o0, FFI_TYPE_VOID
+ be done1
+
+ cmp %o0, FFI_TYPE_FLOAT
+ be,a done1
+ ld [%fp-8], %f0
+
+ cmp %o0, FFI_TYPE_DOUBLE
+ be,a done1
+ ldd [%fp-8], %f0
+
+ cmp %o0, FFI_TYPE_SINT64
+ be,a integer
+ ld [%fp-4], %i1
+
+ cmp %o0, FFI_TYPE_UINT64
+ be,a integer
+ ld [%fp-4], %i1
+
+integer:
+ ld [%fp-8], %i0
+
+done1:
+ ret
+ restore
+.LLFE2:
+
+.ffi_closure_v8_end:
+ .size ffi_closure_v8,.ffi_closure_v8_end-ffi_closure_v8
+
#ifdef SPARC64
#define WS 8
#define nword xword
@@ -148,3 +214,26 @@ longlong:
.byte 0x1f ! uleb128 0x1f
.align WS
.LLEFDE1:
+.LLSFDE2:
+ .uaword .LLEFDE2-.LLASFDE2 ! FDE Length
+.LLASFDE2:
+ .uaword .LLASFDE2-.LLframe1 ! FDE CIE offset
+#ifdef HAVE_AS_SPARC_UA_PCREL
+ .uaword %r_disp32(.LLFB2)
+ .uaword .LLFE2-.LLFB2 ! FDE address range
+#else
+ .align WS
+ .nword .LLFB2
+ .uanword .LLFE2-.LLFB2 ! FDE address range
+#endif
+ .byte 0x0 ! uleb128 0x0; Augmentation size
+ .byte 0x4 ! DW_CFA_advance_loc4
+ .uaword .LLCFI1-.LLFB2
+ .byte 0xd ! DW_CFA_def_cfa_register
+ .byte 0x1e ! uleb128 0x1e
+ .byte 0x2d ! DW_CFA_GNU_window_save
+ .byte 0x9 ! DW_CFA_register
+ .byte 0xf ! uleb128 0xf
+ .byte 0x1f ! uleb128 0x1f
+ .align WS
+.LLEFDE2:
Index: src/sparc/v9.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/sparc/v9.S,v
retrieving revision 1.4
diff -u -p -r1.4 v9.S
--- src/sparc/v9.S 28 Apr 2002 19:57:42 -0000 1.4
+++ src/sparc/v9.S 28 Dec 2002 16:44:23 -0000
@@ -99,7 +99,7 @@ _ffi_call_V9:
cmp %i3, FFI_TYPE_STRUCT
be,pn %icc, dostruct
- cmp %i3, FFI_TYPE_LONGDOUBLE
+ cmp %i3, FFI_TYPE_LONGDOUBLE
bne,pt %icc, done
nop
std %f0, [%i4+0]
@@ -125,6 +125,88 @@ dostruct:
.ffi_call_V9_end:
.size ffi_call_V9,.ffi_call_V9_end-ffi_call_V9
+
+#define STACKFRAME 240 /* 16*8 register window +
+ 6*8 args backing store +
+ 8*8 locals */
+#define FP %fp+STACK_BIAS
+
+/* ffi_closure_v9(...)
+
+ Receives the closure argument in %g1. */
+
+ .text
+ .align 8
+ .globl ffi_closure_v9
+
+ffi_closure_v9:
+.LLFB2:
+ save %sp, -STACKFRAME, %sp
+.LLCFI1:
+
+ ! Store all of the potential argument registers in va_list format.
+ stx %i0, [FP+128+0]
+ stx %i1, [FP+128+8]
+ stx %i2, [FP+128+16]
+ stx %i3, [FP+128+24]
+ stx %i4, [FP+128+32]
+ stx %i5, [FP+128+40]
+
+ ! Store possible floating point argument registers too.
+ std %f0, [FP-48]
+ std %f2, [FP-40]
+ std %f4, [FP-32]
+ std %f6, [FP-24]
+ std %f8, [FP-16]
+ std %f10, [FP-8]
+
+ ! Call ffi_closure_sparc_inner to do the bulk of the work.
+ mov %g1, %o0
+ add %fp, STACK_BIAS-64, %o1
+ add %fp, STACK_BIAS+128, %o2
+ call ffi_closure_sparc_inner
+ add %fp, STACK_BIAS-48, %o3
+
+ ! Load up the return value in the proper type.
+ cmp %o0, FFI_TYPE_VOID
+ be,pn %icc, done1
+
+ cmp %o0, FFI_TYPE_FLOAT
+ be,a,pn %icc, done1
+ ld [FP-64], %f0
+
+ cmp %o0, FFI_TYPE_DOUBLE
+ be,a,pn %icc, done1
+ ldd [FP-64], %f0
+
+ cmp %o0, FFI_TYPE_LONGDOUBLE
+ be,a,pn %icc, longdouble1
+ ldd [FP-64], %f0
+
+ cmp %o0, FFI_TYPE_STRUCT
+ be,pn %icc, struct1
+
+ ! FFI_TYPE_UINT64 | FFI_TYPE_SINT64 | FFI_TYPE_POINTER
+ ldx [FP-64], %i0
+
+done1:
+ ret
+ restore
+
+struct1:
+ ldx [FP-56], %i2
+ ret
+ restore
+
+longdouble1:
+ ldd [FP-56], %f2
+ ret
+ restore
+.LLFE2:
+
+.ffi_closure_v9_end:
+ .size ffi_closure_v9,.ffi_closure_v9_end-ffi_closure_v9
+
.section ".eh_frame",#alloc,#write
.LLframe1:
.uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry
@@ -169,5 +251,27 @@ dostruct:
.byte 0x1f ! uleb128 0x1f
.align 8
.LLEFDE1:
-
+.LLSFDE2:
+ .uaword .LLEFDE2-.LLASFDE2 ! FDE Length
+.LLASFDE2:
+ .uaword .LLASFDE2-.LLframe1 ! FDE CIE offset
+#ifdef HAVE_AS_SPARC_UA_PCREL
+ .uaword %r_disp32(.LLFB2)
+ .uaword .LLFE2-.LLFB2 ! FDE address range
+#else
+ .align 8
+ .xword .LLFB2
+ .uaxword .LLFE2-.LLFB2 ! FDE address range
+#endif
+ .byte 0x0 ! uleb128 0x0; Augmentation size
+ .byte 0x4 ! DW_CFA_advance_loc4
+ .uaword .LLCFI1-.LLFB2
+ .byte 0xd ! DW_CFA_def_cfa_register
+ .byte 0x1e ! uleb128 0x1e
+ .byte 0x2d ! DW_CFA_GNU_window_save
+ .byte 0x9 ! DW_CFA_register
+ .byte 0xf ! uleb128 0xf
+ .byte 0x1f ! uleb128 0x1f
+ .align 8
+.LLEFDE2:
#endif