diff --git a/Makefile.am b/Makefile.am index 95c082aa..7766e900 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,7 +36,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj \ src/sh/ffi.c src/sh/sysv.S src/sh/ffitarget.h src/sh64/ffi.c \ src/sh64/sysv.S src/sh64/ffitarget.h src/sparc/v8.S \ src/sparc/v9.S src/sparc/ffitarget.h src/sparc/ffi.c \ - src/x86/darwin64.S src/x86/ffi.c src/x86/sysv.S \ + src/sparc/ffi64.c src/x86/darwin64.S src/x86/ffi.c src/x86/sysv.S \ src/x86/darwin.S src/x86/ffiw64.c src/x86/win64.S \ src/x86/ffi64.c src/x86/unix64.S \ src/x86/ffitarget.h src/pa/ffitarget.h src/pa/ffi.c \ @@ -141,7 +141,7 @@ if X86_DARWIN nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/darwin.S src/x86/ffi64.c src/x86/darwin64.S endif if SPARC -nodist_libffi_la_SOURCES += src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S +nodist_libffi_la_SOURCES += src/sparc/ffi.c src/sparc/ffi64.c src/sparc/v8.S src/sparc/v9.S endif if ALPHA nodist_libffi_la_SOURCES += src/alpha/ffi.c src/alpha/osf.S diff --git a/src/prep_cif.c b/src/prep_cif.c index be5eae37..5881cebd 100644 --- a/src/prep_cif.c +++ b/src/prep_cif.c @@ -147,9 +147,6 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi, #if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION /* Make space for the return structure pointer */ if (cif->rtype->type == FFI_TYPE_STRUCT -#ifdef SPARC - && (cif->abi != FFI_V9 || cif->rtype->size > 32) -#endif #ifdef TILE && (cif->rtype->size > 10 * FFI_SIZEOF_ARG) #endif @@ -179,14 +176,6 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi, FFI_ASSERT_VALID_TYPE(*ptr); #if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION -#ifdef SPARC - if (((*ptr)->type == FFI_TYPE_STRUCT - && ((*ptr)->size > 16 || cif->abi != FFI_V9)) - || ((*ptr)->type == FFI_TYPE_LONGDOUBLE - && cif->abi != FFI_V9)) - bytes += sizeof(void*); - else -#endif { /* Add any padding if necessary */ if (((*ptr)->alignment - 1) & bytes) diff --git a/src/sparc/ffi.c b/src/sparc/ffi.c index 1f38f543..75428473 100644 --- a/src/sparc/ffi.c +++ b/src/sparc/ffi.c @@ -28,6 +28,9 @@ #include #include #include +#include "internal.h" + +#ifndef SPARC64 /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; all further uses in this file will refer to the 128-bit type. */ @@ -40,632 +43,310 @@ # define FFI_TYPE_LONGDOUBLE 4 #endif - -/* ffi_prep_args is called by the assembly routine once stack space - has been allocated for the function's arguments */ - -void FFI_HIDDEN -ffi_prep_args_v8(char *stack, extended_cif *ecif) -{ - int i; - void **p_argv; - char *argp; - ffi_type **p_arg; - - /* Skip 16 words for the window save area */ - argp = stack + 16*sizeof(int); - - /* This should only really be done when we are returning a structure, - however, it's faster just to do it all the time... - - if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */ - *(int *) argp = (long)ecif->rvalue; - - /* And 1 word for the structure return value. */ - argp += sizeof(int); - -#ifdef USING_PURIFY - /* Purify will probably complain in our assembly routine, unless we - zero out this memory. */ - - ((int*)argp)[0] = 0; - ((int*)argp)[1] = 0; - ((int*)argp)[2] = 0; - ((int*)argp)[3] = 0; - ((int*)argp)[4] = 0; - ((int*)argp)[5] = 0; -#endif - - p_argv = ecif->avalue; - - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++) - { - size_t z; - - if ((*p_arg)->type == FFI_TYPE_STRUCT - || (*p_arg)->type == FFI_TYPE_LONGDOUBLE) - { - *(unsigned int *) argp = (unsigned long)(* p_argv); - z = sizeof(int); - } - else - { - z = (*p_arg)->size; - if (z < sizeof(int)) - { - z = sizeof(int); - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed int *) argp = *(SINT8 *)(* p_argv); - break; - - case FFI_TYPE_UINT8: - *(unsigned int *) argp = *(UINT8 *)(* p_argv); - break; - - case FFI_TYPE_SINT16: - *(signed int *) argp = *(SINT16 *)(* p_argv); - break; - - case FFI_TYPE_UINT16: - *(unsigned int *) argp = *(UINT16 *)(* p_argv); - break; - - default: - FFI_ASSERT(0); - } - } - else - { - memcpy(argp, *p_argv, z); - } - } - p_argv++; - argp += z; - } - - return; -} - -int FFI_HIDDEN -ffi_prep_args_v9(char *stack, extended_cif *ecif) -{ - int i, ret = 0; - int tmp; - void **p_argv; - char *argp; - ffi_type **p_arg; - - tmp = 0; - - /* Skip 16 words for the window save area */ - argp = stack + 16*sizeof(long long); - -#ifdef USING_PURIFY - /* Purify will probably complain in our assembly routine, unless we - zero out this memory. */ - - ((long long*)argp)[0] = 0; - ((long long*)argp)[1] = 0; - ((long long*)argp)[2] = 0; - ((long long*)argp)[3] = 0; - ((long long*)argp)[4] = 0; - ((long long*)argp)[5] = 0; -#endif - - p_argv = ecif->avalue; - - if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && - ecif->cif->rtype->size > 32) - { - *(unsigned long long *) argp = (unsigned long)ecif->rvalue; - argp += sizeof(long long); - tmp = 1; - } - - for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; - i++, p_arg++) - { - size_t z; - - z = (*p_arg)->size; - switch ((*p_arg)->type) - { - case FFI_TYPE_STRUCT: - if (z > 16) - { - /* For structures larger than 16 bytes we pass reference. */ - *(unsigned long long *) argp = (unsigned long)* p_argv; - argp += sizeof(long long); - tmp++; - p_argv++; - continue; - } - /* FALLTHROUGH */ - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - case FFI_TYPE_LONGDOUBLE: - ret = 1; /* We should promote into FP regs as well as integer. */ - break; - } - if (z < sizeof(long long)) - { - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed long long *) argp = *(SINT8 *)(* p_argv); - break; - - case FFI_TYPE_UINT8: - *(unsigned long long *) argp = *(UINT8 *)(* p_argv); - break; - - case FFI_TYPE_SINT16: - *(signed long long *) argp = *(SINT16 *)(* p_argv); - break; - - case FFI_TYPE_UINT16: - *(unsigned long long *) argp = *(UINT16 *)(* p_argv); - break; - - case FFI_TYPE_SINT32: - *(signed long long *) argp = *(SINT32 *)(* p_argv); - break; - - case FFI_TYPE_UINT32: - *(unsigned long long *) argp = *(UINT32 *)(* p_argv); - break; - - case FFI_TYPE_FLOAT: - *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */ - break; - - case FFI_TYPE_STRUCT: - memcpy(argp, *p_argv, z); - break; - - default: - FFI_ASSERT(0); - } - z = sizeof(long long); - tmp++; - } - else if (z == sizeof(long long)) - { - memcpy(argp, *p_argv, z); - z = sizeof(long long); - tmp++; - } - else - { - if ((tmp & 1) && (*p_arg)->alignment > 8) - { - tmp++; - argp += sizeof(long long); - } - memcpy(argp, *p_argv, z); - z = 2 * sizeof(long long); - tmp += 2; - } - p_argv++; - argp += z; - } - - return ret; -} - /* Perform machine dependent cif processing */ ffi_status FFI_HIDDEN ffi_prep_cif_machdep(ffi_cif *cif) { - int wordsize; - - if (cif->abi != FFI_V9) - { - wordsize = 4; - - /* If we are returning a struct, this will already have been added. - Otherwise we need to add it because it's always got to be there! */ - - if (cif->rtype->type != FFI_TYPE_STRUCT) - cif->bytes += wordsize; - - /* sparc call frames require that space is allocated for 6 args, - even if they aren't used. Make that space if necessary. */ - - if (cif->bytes < 4*6+4) - cif->bytes = 4*6+4; - } - else - { - wordsize = 8; - - /* sparc call frames require that space is allocated for 6 args, - even if they aren't used. Make that space if necessary. */ - - if (cif->bytes < 8*6) - cif->bytes = 8*6; - } - - /* Adjust cif->bytes. to include 16 words for the window save area, - and maybe the struct/union return pointer area, */ - - cif->bytes += 16 * wordsize; - - /* The stack must be 2 word aligned, so round bytes up - appropriately. */ - - cif->bytes = ALIGN(cif->bytes, 2 * wordsize); + ffi_type *rtype = cif->rtype; + int rtt = rtype->type; + size_t bytes; + int i, n, flags; /* Set the return type flag */ - switch (cif->rtype->type) + switch (rtt) { case FFI_TYPE_VOID: + flags = SPARC_RET_VOID; + break; case FFI_TYPE_FLOAT: + flags = SPARC_RET_FLOAT; + break; case FFI_TYPE_DOUBLE: + flags = SPARC_RET_DOUBLE; + break; case FFI_TYPE_LONGDOUBLE: - cif->flags = cif->rtype->type; - break; - case FFI_TYPE_STRUCT: - if (cif->abi == FFI_V9 && cif->rtype->size > 32) - cif->flags = FFI_TYPE_VOID; - else - cif->flags = FFI_TYPE_STRUCT; + flags = SPARC_RET_STRUCT; break; - case FFI_TYPE_SINT8: - case FFI_TYPE_UINT8: - case FFI_TYPE_SINT16: - case FFI_TYPE_UINT16: - if (cif->abi == FFI_V9) - cif->flags = FFI_TYPE_INT; - else - cif->flags = cif->rtype->type; + flags = SPARC_RET_SINT8; + break; + case FFI_TYPE_UINT8: + flags = SPARC_RET_UINT8; + break; + case FFI_TYPE_SINT16: + flags = SPARC_RET_SINT16; + break; + case FFI_TYPE_UINT16: + flags = SPARC_RET_UINT16; + break; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + flags = SPARC_RET_UINT32; break; - case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: - if (cif->abi == FFI_V9) - cif->flags = FFI_TYPE_INT; - else - cif->flags = FFI_TYPE_SINT64; + flags = SPARC_RET_INT64; break; - default: - cif->flags = FFI_TYPE_INT; - break; + abort(); } + cif->flags = flags; + + bytes = 0; + for (i = 0, n = cif->nargs; i < n; ++i) + { + ffi_type *ty = cif->arg_types[i]; + size_t z = ty->size; + int tt = ty->type; + + if (tt == FFI_TYPE_STRUCT || tt == FFI_TYPE_LONGDOUBLE) + /* Passed by reference. */ + z = 4; + else + z = ALIGN(z, 4); + bytes += z; + } + + /* Sparc call frames require that space is allocated for 6 args, + even if they aren't used. Make that space if necessary. */ + if (bytes < 6 * 4) + bytes = 6 * 4; + + /* The ABI always requires space for the struct return pointer. */ + bytes += 4; + + /* The stack must be 2 word aligned, so round bytes up appropriately. */ + bytes = ALIGN(bytes, 2 * 4); + + /* Include the call frame to prep_args. */ + bytes += 4*16 + 4*8; + cif->bytes = bytes; + return FFI_OK; } -static int -ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt) +extern void ffi_call_v8(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, size_t bytes) FFI_HIDDEN; + +int FFI_HIDDEN +ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue) { - ffi_type **ptr = &arg->elements[0]; + ffi_type **p_arg; + int flags = cif->flags; + int i, nargs; - while (*ptr != NULL) + if (rvalue == NULL) { - if (off & ((*ptr)->alignment - 1)) - off = ALIGN(off, (*ptr)->alignment); + if (flags == SPARC_RET_STRUCT) + { + /* Since we pass the pointer to the callee, we need a value. + We allowed for this space in ffi_call, before ffi_call_v8 + alloca'd the space. */ + rvalue = (char *)argp + cif->bytes; + } + else + { + /* Otherwise, we can ignore the return value. */ + flags = SPARC_RET_VOID; + } + } - switch ((*ptr)->type) + /* This could only really be done when we are returning a structure. + However, the space is reserved so we can do it unconditionally. */ + *argp++ = (unsigned long)rvalue; + +#ifdef USING_PURIFY + /* Purify will probably complain in our assembly routine, + unless we zero out this memory. */ + memset(argp, 0, 6*4); +#endif + + p_arg = cif->arg_types; + for (i = 0, nargs = cif->nargs; i < nargs; i++) + { + ffi_type *ty = p_arg[i]; + void *a = avalue[i]; + + switch (ty->type) { case FFI_TYPE_STRUCT: - off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt); - off = ALIGN(off, FFI_SIZEOF_ARG); - break; - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: case FFI_TYPE_LONGDOUBLE: - memmove(ret + off, flt + off, (*ptr)->size); - off += (*ptr)->size; + *argp++ = (unsigned long)a; break; + + case FFI_TYPE_DOUBLE: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + memcpy(argp, a, 8); + argp += 2; + break; + + case FFI_TYPE_INT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + *argp++ = *(unsigned *)a; + break; + + case FFI_TYPE_UINT8: + *argp++ = *(UINT8 *)a; + break; + case FFI_TYPE_SINT8: + *argp++ = *(SINT8 *)a; + break; + case FFI_TYPE_UINT16: + *argp++ = *(UINT16 *)a; + break; + case FFI_TYPE_SINT16: + *argp++ = *(SINT16 *)a; + break; + default: - memmove(ret + off, intg + off, (*ptr)->size); - off += (*ptr)->size; - break; + abort(); } - ptr++; } - return off; + + return flags; } - -#ifdef SPARC64 -extern int ffi_call_v9(void *, extended_cif *, unsigned, - unsigned, unsigned *, void (*fn)(void)) FFI_HIDDEN; -#else -extern int ffi_call_v8(void *, extended_cif *, unsigned, - unsigned, unsigned *, void (*fn)(void)) FFI_HIDDEN; -#endif - -#ifndef __GNUC__ -void ffi_flush_icache (void *, size_t) FFI_HIDDEN; -#endif - -void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { - extended_cif ecif; - void *rval = rvalue; + size_t bytes = cif->bytes; - ecif.cif = cif; - ecif.avalue = avalue; + FFI_ASSERT (cif->abi == FFI_V8); - /* If the return value is a struct and we don't have a return */ - /* value address then we need to make one */ + /* If we've not got a return value, we need to create one if we've + got to pass the return value to the callee. Otherwise ignore it. */ + if (rvalue == NULL && cif->flags == SPARC_RET_STRUCT) + bytes += ALIGN (cif->rtype->size, 8); - ecif.rvalue = rvalue; - if (cif->rtype->type == FFI_TYPE_STRUCT) - { - if (cif->rtype->size <= 32) - rval = alloca(64); - else - { - rval = NULL; - if (rvalue == NULL) - ecif.rvalue = alloca(cif->rtype->size); - } - } - - switch (cif->abi) - { - case FFI_V8: -#ifdef SPARC64 - /* We don't yet support calling 32bit code from 64bit */ - FFI_ASSERT(0); -#else - if (rvalue && (cif->rtype->type == FFI_TYPE_STRUCT - || cif->flags == FFI_TYPE_LONGDOUBLE)) - { - /* For v8, we need an "unimp" with size of returning struct */ - /* behind "call", so we alloc some executable space for it. */ - /* l7 is used, we need to make sure v8.S doesn't use %l7. */ - unsigned int *call_struct = NULL; - ffi_closure_alloc(32, (void **)&call_struct); - if (call_struct) - { - unsigned long f = (unsigned long)fn; - call_struct[0] = 0xae10001f; /* mov %i7, %l7 */ - call_struct[1] = 0xbe10000f; /* mov %o7, %i7 */ - call_struct[2] = 0x03000000 | f >> 10; /* sethi %hi(fn), %g1 */ - call_struct[3] = 0x9fc06000 | (f & 0x3ff); /* jmp %g1+%lo(fn), %o7 */ - call_struct[4] = 0x01000000; /* nop */ - if (cif->rtype->size < 0x7f) - call_struct[5] = cif->rtype->size; /* unimp */ - else - call_struct[5] = 0x01000000; /* nop */ - call_struct[6] = 0x81c7e008; /* ret */ - call_struct[7] = 0xbe100017; /* mov %l7, %i7 */ -#ifdef __GNUC__ - asm volatile ("iflush %0; iflush %0+8; iflush %0+16; iflush %0+24" : : - "r" (call_struct) : "memory"); - /* SPARC v8 requires 5 instructions for flush to be visible */ - asm volatile ("nop; nop; nop; nop; nop"); -#else - ffi_flush_icache (call_struct, 32); -#endif - ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, - cif->flags, rvalue, call_struct); - ffi_closure_free(call_struct); - } - else - { - ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, - cif->flags, rvalue, fn); - } - } - else - { - ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, - cif->flags, rvalue, fn); - } -#endif - break; - case FFI_V9: -#ifdef SPARC64 - ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes, - cif->flags, rval, fn); - if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT) - ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32); -#else - /* And vice versa */ - FFI_ASSERT(0); -#endif - break; - default: - FFI_ASSERT(0); - break; - } + ffi_call_v8(cif, fn, rvalue, avalue, -bytes); } - -#ifdef SPARC64 -extern void ffi_closure_v9(void) FFI_HIDDEN; +#ifdef __GNUC__ +static inline void +ffi_flush_icache (void *p) +{ + /* SPARC v8 requires 5 instructions for flush to be visible */ + asm volatile ("iflush %0; iflush %0+8; nop; nop; nop; nop; nop" + : : "r" (p) : "memory"); +} #else -extern void ffi_closure_v8(void) FFI_HIDDEN; +extern void ffi_flush_icache (void *) FFI_HIDDEN; #endif +extern void ffi_closure_v8(void) FFI_HIDDEN; + ffi_status -ffi_prep_closure_loc (ffi_closure* closure, - ffi_cif* cif, +ffi_prep_closure_loc (ffi_closure *closure, + ffi_cif *cif, void (*fun)(ffi_cif*, void*, void**, void*), void *user_data, void *codeloc) { unsigned int *tramp = (unsigned int *) &closure->tramp[0]; - unsigned long fn; -#ifdef SPARC64 - /* Trampoline address is equal to the closure address. We take advantage - of that to reduce the trampoline size by 8 bytes. */ - if (cif->abi != FFI_V9) - return FFI_BAD_ABI; - 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 - unsigned long ctx = (unsigned long) codeloc; + unsigned long ctx = (unsigned long) closure; + unsigned long fn = (unsigned long) ffi_closure_v8; + if (cif->abi != FFI_V8) return FFI_BAD_ABI; - 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. closure is 8 bytes aligned. */ -#ifdef __GNUC__ -#ifdef SPARC64 - asm volatile ("flush %0; flush %0+8" : : "r" (closure) : "memory"); -#else - asm volatile ("iflush %0; iflush %0+8" : : "r" (closure) : "memory"); - /* SPARC v8 requires 5 instructions for flush to be visible */ - asm volatile ("nop; nop; nop; nop; nop"); -#endif -#else - ffi_flush_icache (closure, 16); -#endif + ffi_flush_icache (closure); return FFI_OK; } int FFI_HIDDEN ffi_closure_sparc_inner_v8(ffi_closure *closure, void *rvalue, - unsigned long *gpr, unsigned long *scratch) + unsigned long *argp) { ffi_cif *cif; ffi_type **arg_types; void **avalue; - int i, argn; + int i, nargs, flags; cif = closure->cif; arg_types = cif->arg_types; - avalue = alloca(cif->nargs * sizeof(void *)); + nargs = cif->nargs; + flags = cif->flags; + avalue = alloca(nargs * sizeof(void *)); /* Copy the caller's structure return address so that the closure returns the data directly to the caller. */ - if (cif->flags == FFI_TYPE_STRUCT || cif->flags == FFI_TYPE_LONGDOUBLE) - rvalue = (void *) gpr[0]; + if (flags == SPARC_RET_STRUCT) + rvalue = (void *)*argp; /* Always skip the structure return address. */ - argn = 1; + argp++; /* Grab the addresses of the arguments from the stack frame. */ - for (i = 0; i < cif->nargs; i++) + for (i = 0; i < nargs; i++) { - if (arg_types[i]->type == FFI_TYPE_STRUCT - || arg_types[i]->type == FFI_TYPE_LONGDOUBLE) + ffi_type *ty = arg_types[i]; + int tt = ty->type; + void *a = argp; + + switch (tt) { + case FFI_TYPE_STRUCT: + case FFI_TYPE_LONGDOUBLE: /* Straight copy of invisible reference. */ - avalue[i] = (void *)gpr[argn++]; - } - else if ((arg_types[i]->type == FFI_TYPE_DOUBLE - || arg_types[i]->type == FFI_TYPE_SINT64 - || arg_types[i]->type == FFI_TYPE_UINT64) - /* gpr is 8-byte aligned. */ - && (argn % 2) != 0) - { - /* Align on a 8-byte boundary. */ - scratch[0] = gpr[argn]; - scratch[1] = gpr[argn+1]; - avalue[i] = scratch; - scratch -= 2; - argn += 2; - } - else - { - /* Always right-justify. */ - argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; - avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size; + a = (void *)*argp; + break; + + case FFI_TYPE_DOUBLE: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + if ((unsigned long)a & 7) + { + /* Align on a 8-byte boundary. */ + UINT64 *tmp = alloca(8); + *tmp = ((UINT64)argp[0] << 32) | argp[1]; + a = tmp; + } + argp++; + break; + + case FFI_TYPE_INT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + break; + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + a += 2; + break; + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + a += 3; + break; + + default: + abort(); } + argp++; + avalue[i] = a; } /* 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; -} - -int FFI_HIDDEN -ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue, - unsigned long *gpr, double *fpr) -{ - ffi_cif *cif; - ffi_type **arg_types; - void **avalue; - int i, argn, fp_slot_max; - - cif = closure->cif; - arg_types = cif->arg_types; - avalue = alloca(cif->nargs * sizeof(void *)); - - /* Copy the caller's structure return address so that the closure - returns the data directly to the caller. */ - if (cif->flags == FFI_TYPE_VOID - && cif->rtype->type == FFI_TYPE_STRUCT) - { - rvalue = (void *) gpr[0]; - /* Skip the structure return address. */ - argn = 1; - } - else - argn = 0; - - fp_slot_max = 16 - argn; - - /* Grab the addresses of the arguments from the stack frame. */ - for (i = 0; i < cif->nargs; i++) - { - if (arg_types[i]->type == FFI_TYPE_STRUCT) - { - if (arg_types[i]->size > 16) - { - /* Straight copy of invisible reference. */ - avalue[i] = (void *)gpr[argn++]; - } - else - { - /* Left-justify. */ - ffi_v9_layout_struct(arg_types[i], - 0, - (char *) &gpr[argn], - (char *) &gpr[argn], - (char *) &fpr[argn]); - avalue[i] = &gpr[argn]; - argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; - } - } - else - { - /* Right-justify. */ - argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; - - /* Align on a 16-byte boundary. */ - if (arg_types[i]->type == FFI_TYPE_LONGDOUBLE && (argn % 2) != 0) - argn++; - if (i < fp_slot_max - && (arg_types[i]->type == FFI_TYPE_FLOAT - || arg_types[i]->type == FFI_TYPE_DOUBLE - || arg_types[i]->type == FFI_TYPE_LONGDOUBLE)) - avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size; - else - avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size; - } - } - - /* 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; + return flags; } +#endif /* !SPARC64 */ diff --git a/src/sparc/ffi64.c b/src/sparc/ffi64.c new file mode 100644 index 00000000..7ed928db --- /dev/null +++ b/src/sparc/ffi64.c @@ -0,0 +1,433 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2011, 2013 Anthony Green + Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc. + + SPARC Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include +#include +#include "internal.h" + +/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; + all further uses in this file will refer to the 128-bit type. */ +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +# if FFI_TYPE_LONGDOUBLE != 4 +# error FFI_TYPE_LONGDOUBLE out of date +# endif +#else +# undef FFI_TYPE_LONGDOUBLE +# define FFI_TYPE_LONGDOUBLE 4 +#endif + +#ifdef SPARC64 +/* Perform machine dependent cif processing */ + +int FFI_HIDDEN +ffi_v9_layout_struct (ffi_type *arg, int off, void *d, void *si, void *sf) +{ + ffi_type **elts, *t; + + for (elts = arg->elements; (t = *elts) != NULL; elts++) + { + size_t z = t->size; + void *src = si; + + off = ALIGN(off, t->alignment); + switch (t->type) + { + case FFI_TYPE_STRUCT: + off = ffi_v9_layout_struct(t, off, d, si, sf); + off = ALIGN(off, FFI_SIZEOF_ARG); + continue; + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + /* Note that closures start with the argument offset, + so that we know when to stop looking at fp regs. */ + if (off < 128) + src = sf; + break; + } + memcpy(d + off, src + off, z); + off += z; + } + + return off; +} + +ffi_status FFI_HIDDEN +ffi_prep_cif_machdep(ffi_cif *cif) +{ + ffi_type *rtype = cif->rtype; + int rtt = rtype->type; + size_t bytes = 0; + int i, n, flags; + + /* Set the return type flag */ + switch (rtt) + { + case FFI_TYPE_VOID: + flags = SPARC_RET_VOID; + break; + case FFI_TYPE_FLOAT: + flags = SPARC_RET_FLOAT; + break; + case FFI_TYPE_DOUBLE: + flags = SPARC_RET_DOUBLE; + break; + case FFI_TYPE_LONGDOUBLE: + flags = SPARC_RET_LDOUBLE; + break; + + case FFI_TYPE_STRUCT: + if (rtype->size > 32) + { + flags = SPARC_RET_VOID | SPARC_FLAG_RET_IN_MEM; + bytes = 8; + } + else + flags = SPARC_RET_STRUCT; + break; + + case FFI_TYPE_SINT8: + flags = SPARC_RET_SINT8; + break; + case FFI_TYPE_UINT8: + flags = SPARC_RET_UINT8; + break; + case FFI_TYPE_SINT16: + flags = SPARC_RET_SINT16; + break; + case FFI_TYPE_UINT16: + flags = SPARC_RET_UINT16; + break; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + flags = SPARC_RET_SINT32; + break; + case FFI_TYPE_UINT32: + flags = SPARC_RET_UINT32; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + flags = SPARC_RET_INT64; + break; + + default: + abort(); + } + + bytes = 0; + for (i = 0, n = cif->nargs; i < n; ++i) + { + ffi_type *ty = cif->arg_types[i]; + size_t z = ty->size; + size_t a = ty->alignment; + + switch (ty->type) + { + case FFI_TYPE_STRUCT: + /* Large structs passed by reference. */ + if (z > 16) + { + a = z = 8; + break; + } + /* ??? FALLTHRU -- check for fp members in the struct. */ + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + flags |= SPARC_FLAG_FP_ARGS; + break; + } + bytes = ALIGN(bytes, a); + bytes += ALIGN(z, 8); + } + + /* Sparc call frames require that space is allocated for 6 args, + even if they aren't used. Make that space if necessary. */ + if (bytes < 6 * 8) + bytes = 6 * 8; + + /* The stack must be 2 word aligned, so round bytes up appropriately. */ + bytes = ALIGN(bytes, 16); + + /* Include the call frame to prep_args. */ + bytes += 8*16 + 8*8; + + cif->bytes = bytes; + cif->flags = flags; + return FFI_OK; +} + +extern void ffi_call_v9(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, size_t bytes) FFI_HIDDEN; + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +int FFI_HIDDEN +ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue) +{ + ffi_type **p_arg; + int flags = cif->flags; + int i, nargs; + + if (rvalue == NULL) + { + if (flags & SPARC_FLAG_RET_IN_MEM) + { + /* Since we pass the pointer to the callee, we need a value. + We allowed for this space in ffi_call, before ffi_call_v8 + alloca'd the space. */ + rvalue = (char *)argp + cif->bytes; + } + else + { + /* Otherwise, we can ignore the return value. */ + flags = SPARC_RET_VOID; + } + } + +#ifdef USING_PURIFY + /* Purify will probably complain in our assembly routine, + unless we zero out this memory. */ + memset(argp, 0, 6*8); +#endif + + if (flags & SPARC_FLAG_RET_IN_MEM) + *argp++ = (unsigned long)rvalue; + + p_arg = cif->arg_types; + for (i = 0, nargs = cif->nargs; i < nargs; i++) + { + ffi_type *ty = p_arg[i]; + void *a = avalue[i]; + size_t z; + + switch (ty->type) + { + case FFI_TYPE_SINT8: + *argp++ = *(SINT8 *)a; + break; + case FFI_TYPE_UINT8: + *argp++ = *(UINT8 *)a; + break; + case FFI_TYPE_SINT16: + *argp++ = *(SINT16 *)a; + break; + case FFI_TYPE_UINT16: + *argp++ = *(UINT16 *)a; + break; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + *argp++ = *(SINT32 *)a; + break; + case FFI_TYPE_UINT32: + case FFI_TYPE_FLOAT: + *argp++ = *(UINT32 *)a; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + case FFI_TYPE_DOUBLE: + *argp++ = *(UINT64 *)a; + break; + + case FFI_TYPE_LONGDOUBLE: + case FFI_TYPE_STRUCT: + z = ty->size; + if (z > 16) + { + /* For structures larger than 16 bytes we pass reference. */ + *argp++ = (unsigned long)a; + break; + } + if (((unsigned long)argp & 15) && ty->alignment > 8) + argp++; + memcpy(argp, a, z); + argp += ALIGN(z, 8) / 8; + break; + + default: + abort(); + } + } + + return flags; +} + +void +ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + size_t bytes = cif->bytes; + + FFI_ASSERT (cif->abi == FFI_V9); + + if (rvalue == NULL && (cif->flags & SPARC_FLAG_RET_IN_MEM)) + bytes += ALIGN (cif->rtype->size, 16); + + ffi_call_v9(cif, fn, rvalue, avalue, -bytes); +} + +#ifdef __GNUC__ +static inline void +ffi_flush_icache (void *p) +{ + asm volatile ("flush %0; flush %0+8" : : "r" (p) : "memory"); +} +#else +extern void ffi_flush_icache (void *) FFI_HIDDEN; +#endif + +extern void ffi_closure_v9(void) FFI_HIDDEN; + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + unsigned int *tramp = (unsigned int *) &closure->tramp[0]; + unsigned long fn; + + if (cif->abi != FFI_V9) + return FFI_BAD_ABI; + + /* Trampoline address is equal to the closure address. We take advantage + of that to reduce the trampoline size by 8 bytes. */ + 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; + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + ffi_flush_icache (closure); + + return FFI_OK; +} + +int FFI_HIDDEN +ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue, + unsigned long *gpr, unsigned long *fpr) +{ + ffi_cif *cif; + ffi_type **arg_types; + void **avalue; + int i, argn, nargs, flags; + + cif = closure->cif; + arg_types = cif->arg_types; + nargs = cif->nargs; + flags = cif->flags; + + avalue = alloca(nargs * sizeof(void *)); + + /* Copy the caller's structure return address so that the closure + returns the data directly to the caller. */ + if (flags & SPARC_FLAG_RET_IN_MEM) + { + rvalue = (void *) gpr[0]; + /* Skip the structure return address. */ + argn = 1; + } + else + argn = 0; + + /* Grab the addresses of the arguments from the stack frame. */ + for (i = 0; i < nargs; i++) + { + ffi_type *ty = arg_types[i]; + void *a = &gpr[argn++]; + size_t z; + + switch (ty->type) + { + case FFI_TYPE_STRUCT: + z = ty->size; + if (z > 16) + a = *(void **)a; + else + { + if (--argn < 16) + ffi_v9_layout_struct(arg_types[i], 8*argn, gpr, gpr, fpr); + argn += ALIGN (z, 8) / 8; + } + break; + + case FFI_TYPE_LONGDOUBLE: + if (--argn & 1) + argn++; + a = (argn < 16 ? fpr : gpr) + argn; + argn += 2; + break; + case FFI_TYPE_DOUBLE: + if (argn <= 16) + a = fpr + argn - 1; + break; + case FFI_TYPE_FLOAT: + if (argn <= 16) + a = fpr + argn - 1; + a += 4; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + break; + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + a += 4; + break; + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + a += 6; + break; + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + a += 7; + break; + + default: + abort(); + } + avalue[i] = a; + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_sparc how to perform return type promotions. */ + return flags; +} +#endif /* SPARC64 */ diff --git a/src/sparc/ffitarget.h b/src/sparc/ffitarget.h index d89f7877..ff4dc0b1 100644 --- a/src/sparc/ffitarget.h +++ b/src/sparc/ffitarget.h @@ -46,18 +46,19 @@ typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, - FFI_V8, - FFI_V8PLUS, - FFI_V9, - FFI_LAST_ABI, #ifdef SPARC64 - FFI_DEFAULT_ABI = FFI_V9 + FFI_V9, + FFI_DEFAULT_ABI = FFI_V9, #else - FFI_DEFAULT_ABI = FFI_V8 + FFI_V8, + FFI_DEFAULT_ABI = FFI_V8, #endif + FFI_LAST_ABI } ffi_abi; #endif +#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION + /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 diff --git a/src/sparc/internal.h b/src/sparc/internal.h new file mode 100644 index 00000000..df7c3057 --- /dev/null +++ b/src/sparc/internal.h @@ -0,0 +1,18 @@ +#define SPARC_RET_VOID 0 +#define SPARC_RET_STRUCT 1 +#define SPARC_RET_FLOAT 2 +#define SPARC_RET_DOUBLE 3 +#define SPARC_RET_UINT8 4 +#define SPARC_RET_SINT8 5 +#define SPARC_RET_UINT16 6 +#define SPARC_RET_SINT16 7 +#define SPARC_RET_INT64 8 +#define SPARC_RET_UINT32 9 + +/* These two are only used for V9. */ +#define SPARC_RET_SINT32 10 +#define SPARC_RET_LDOUBLE 11 + +#define SPARC_FLAG_RET_MASK 15 +#define SPARC_FLAG_RET_IN_MEM 32 +#define SPARC_FLAG_FP_ARGS 64 diff --git a/src/sparc/v8.S b/src/sparc/v8.S index 10c66ba3..b0d50a34 100644 --- a/src/sparc/v8.S +++ b/src/sparc/v8.S @@ -29,9 +29,9 @@ #include #include #include +#include "internal.h" -#define STACKFRAME 96 /* Minimum stack framesize for SPARC */ -#define ARGS (64+4) /* Offset of register area in frame */ +#ifndef SPARC64 #define C2(X, Y) X ## Y #define C1(X, Y) C2(X, Y) @@ -53,26 +53,24 @@ C(ffi_flush_icache): cfi_startproc - add %o0, %o1, %o2 -#ifdef SPARC64 -1: flush %o0 -#else 1: iflush %o0 -#endif - add %o0, 8, %o0 - cmp %o0, %o2 - blt 1b + iflush %o+8 nop nop nop nop nop retl - nop + nop cfi_endproc .size C(ffi_flush_icache), . - C(ffi_flush_icache) #endif +.macro E index + .align 16 + .org 2b + \index * 16 +.endm + .align 8 .globl C(ffi_call_v8) .type C(ffi_call_v8),@function @@ -80,104 +78,104 @@ C(ffi_flush_icache): C(ffi_call_v8): cfi_startproc - save %sp, -STACKFRAME, %sp + ! Allocate a stack frame sized by ffi_call. + save %sp, %o4, %sp cfi_def_cfa_register(%fp) cfi_window_save - - sub %sp, %i2, %sp ! alloca() space in stack for frame to set up - add %sp, STACKFRAME, %l0 ! %l0 has start of - ! frame to set up - mov %l0, %o0 ! call routine to set up frame - call %i0 - mov %i1, %o1 ! (delay) + mov %i0, %o0 ! copy cif + add %sp, 64+32, %o1 ! load args area + mov %i2, %o2 ! copy rvalue + call C(ffi_prep_args_v8) + mov %i3, %o3 ! copy avalue - ld [%l0+ARGS], %o0 ! call foreign function - ld [%l0+ARGS+4], %o1 - ld [%l0+ARGS+8], %o2 - ld [%l0+ARGS+12], %o3 - ld [%l0+ARGS+16], %o4 - ld [%l0+ARGS+20], %o5 - call %i5 - mov %l0, %sp ! (delay) switch to frame - nop ! STRUCT returning functions skip 12 instead of 8 bytes + add %sp, 32, %sp ! deallocate prep frame + and %o0, SPARC_FLAG_RET_MASK, %l0 ! save return type + ld [%sp+64+4], %o0 ! load all argument registers + ld [%sp+64+8], %o1 + ld [%sp+64+12], %o2 + ld [%sp+64+16], %o3 + cmp %l0, SPARC_RET_STRUCT ! struct return needs an unimp 4 + ld [%sp+64+20], %o4 + be 8f + ld [%sp+64+24], %o5 - ! If the return value pointer is NULL, assume no return value. - tst %i4 - bz L(done) + ! Call foreign function + call %i1 + nop + +0: call 1f ! load pc in %o7 + sll %l0, 4, %l0 +1: add %o7, %l0, %o7 ! o7 = 0b + ret_type*16 + jmp %o7+(2f-0b) + nop + + ! Note that each entry is 4 insns, enforced by the E macro. + .align 16 +2: +E SPARC_RET_VOID + ret + restore +E SPARC_RET_STRUCT + unimp +E SPARC_RET_FLOAT + st %f0, [%i2] + ret + restore +E SPARC_RET_DOUBLE + std %f0, [%i2] + ret + restore nop - - cmp %i3, FFI_TYPE_INT - be,a L(done) - st %o0, [%i4] ! (delay) - - cmp %i3, FFI_TYPE_FLOAT - be,a L(done) - st %f0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_DOUBLE - be,a L(double) - st %f0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_SINT8 - be,a L(sint8) - sll %o0, 24, %o0 ! (delay) - - cmp %i3, FFI_TYPE_UINT8 - be,a L(uint8) - sll %o0, 24, %o0 ! (delay) - - cmp %i3, FFI_TYPE_SINT16 - be,a L(sint16) - sll %o0, 16, %o0 ! (delay) - - cmp %i3, FFI_TYPE_UINT16 - be,a L(uint16) - sll %o0, 16, %o0 ! (delay) - - cmp %i3, FFI_TYPE_SINT64 - be,a L(longlong) - st %o0, [%i4+0] ! (delay) - -L(done): +E SPARC_RET_UINT8 + and %o0, 0xff, %o0 + st %o0, [%i2] ret - restore - -L(double): - st %f1, [%i4+4] + restore +E SPARC_RET_SINT8 + sll %o0, 24, %o0 + b 7f + sra %o0, 24, %o0 +E SPARC_RET_UINT16 + sll %o0, 16, %o0 + b 7f + srl %o0, 16, %o0 +E SPARC_RET_SINT16 + sll %o0, 16, %o0 + b 7f + sra %o0, 16, %o0 +E SPARC_RET_INT64 + std %o0, [%i2] ret - restore - -L(sint8): - sra %o0, 24, %o0 - st %o0, [%i4+0] + restore +E SPARC_RET_UINT32 +7: st %o0, [%i2] ret - restore + restore -L(uint8): - srl %o0, 24, %o0 - st %o0, [%i4+0] - ret - restore + ! Unused entries. Don't allow bad data to do worse things. +E 10 + unimp +E 11 + unimp +E 12 + unimp +E 13 + unimp +E 14 + unimp +E 15 + unimp -L(sint16): - sra %o0, 16, %o0 - st %o0, [%i4+0] + ! Struct returning functions expect and skip the unimp here. + .align 8 +8: call %i1 + nop + unimp 4 ret - restore + restore -L(uint16): - srl %o0, 16, %o0 - st %o0, [%i4+0] - ret - restore - -L(longlong): - st %o1, [%i4+4] - ret - restore cfi_endproc - .size C(ffi_call_v8),. - C(ffi_call_v8) @@ -185,7 +183,8 @@ L(longlong): #define STACKFRAME 104 /* 16*4 register window + 1*4 struct return + 6*4 args backing store + - 3*4 locals */ + 2*4 return storage + + 1*4 alignment */ /* ffi_closure_v8(...) @@ -201,15 +200,7 @@ C(ffi_closure_v8): .register %g2, #scratch #endif cfi_startproc - ! Reserve frame space for all arguments in case - ! we need to align them on a 8-byte boundary. - ld [%g2+FFI_TRAMPOLINE_SIZE], %g1 - ld [%g1+4], %g1 - sll %g1, 3, %g1 - add %g1, STACKFRAME, %g1 - ! %g1 == STACKFRAME + 8*nargs - neg %g1 - save %sp, %g1, %sp + save %sp, -STACKFRAME, %sp cfi_def_cfa_register(%fp) cfi_window_save @@ -224,55 +215,75 @@ C(ffi_closure_v8): ! Call ffi_closure_sparc_inner to do the bulk of the work. mov %g2, %o0 add %fp, -8, %o1 - add %fp, 64, %o2 call ffi_closure_sparc_inner_v8 - add %fp, -16, %o3 + add %fp, 64, %o2 - ! Load up the return value in the proper type. - ! See ffi_prep_cif_machdep for the list of cases. - cmp %o0, FFI_TYPE_VOID - be L(done1) +0: call 1f + and %o0, SPARC_FLAG_RET_MASK, %o0 +1: sll %o0, 4, %o0 ! o0 = o0 * 16 + add %o7, %o0, %o7 ! o7 = 0b + o0*16 + jmp %o7+(2f-0b) + nop - cmp %o0, FFI_TYPE_INT - be L(done1) - ld [%fp-8], %i0 - - cmp %o0, FFI_TYPE_FLOAT - be,a L(done1) - ld [%fp-8], %f0 - - cmp %o0, FFI_TYPE_DOUBLE - be,a L(done1) - ldd [%fp-8], %f0 - -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - cmp %o0, FFI_TYPE_LONGDOUBLE - be L(done2) -#endif - - cmp %o0, FFI_TYPE_STRUCT - be L(done2) - - cmp %o0, FFI_TYPE_SINT64 - be,a L(done1) - ldd [%fp-8], %i0 - - cmp %o0, FFI_TYPE_UINT64 - be,a L(done1) - ldd [%fp-8], %i0 - - ld [%fp-8], %i0 -L(done1): - jmp %i7+8 + ! Note that each entry is 4 insns, enforced by the E macro. + .align 16 +2: +E SPARC_RET_VOID + ret restore -L(done2): - ! Skip 'unimp'. +E SPARC_RET_STRUCT jmp %i7+12 restore +E SPARC_RET_FLOAT + ld [%fp-8], %f0 + ret + restore +E SPARC_RET_DOUBLE + ldd [%fp-8], %f0 + ret + restore +E SPARC_RET_UINT8 + ldub [%fp-8+3], %i0 + ret + restore +E SPARC_RET_SINT8 + ldsb [%fp-8+3], %i0 + ret + restore +E SPARC_RET_UINT16 + lduh [%fp-8+2], %i0 + ret + restore +E SPARC_RET_SINT16 + ldsh [%fp-8+2], %i0 + ret + restore +E SPARC_RET_INT64 + ldd [%fp-8], %i0 + ret + restore +E SPARC_RET_UINT32 + ld [%fp-8], %i0 + ret + restore + + ! Unused entries. Don't allow bad data to do worse things. +E 10 + unimp +E 11 + unimp +E 12 + unimp +E 13 + unimp +E 14 + unimp +E 15 + unimp cfi_endproc .size C(ffi_closure_v8), . - C(ffi_closure_v8) - +#endif /* !SPARC64 */ #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits #endif diff --git a/src/sparc/v9.S b/src/sparc/v9.S index aba468e0..e2fe0362 100644 --- a/src/sparc/v9.S +++ b/src/sparc/v9.S @@ -28,10 +28,9 @@ #include #include #include +#include "internal.h" #ifdef SPARC64 -/* Only compile this in for 64bit builds, because otherwise the object file - will have inproper architecture due to used instructions. */ #define C2(X, Y) X ## Y #define C1(X, Y) C2(X, Y) @@ -43,12 +42,14 @@ #endif #define L(Y) C1(.L, Y) +.macro E index + .align 16 + .org 2b + \index * 16 +.endm -#define STACKFRAME 176 /* Minimum stack framesize for SPARC 64-bit */ #define STACK_BIAS 2047 -#define ARGS (128) /* Offset of register area in frame */ -.text + .text .align 8 .globl C(ffi_call_v9) .type C(ffi_call_v9),@function @@ -56,86 +57,135 @@ C(ffi_call_v9): cfi_startproc - save %sp, -STACKFRAME, %sp + save %sp, %o4, %sp cfi_def_cfa_register(%fp) cfi_window_save - sub %sp, %i2, %sp ! alloca() space in stack for frame to set up - add %sp, STACKFRAME+STACK_BIAS, %l0 ! %l0 has start of - ! frame to set up + mov %i0, %o0 ! copy cif + add %sp, STACK_BIAS+128+48, %o1 ! load args area + mov %i2, %o2 ! copy rvalue + call C(ffi_prep_args_v9) + mov %i3, %o3 ! copy avalue - mov %l0, %o0 ! call routine to set up frame - call %i0 - mov %i1, %o1 ! (delay) - brz,pt %o0, 1f - ldx [%l0+ARGS], %o0 ! call foreign function + andcc %o0, SPARC_FLAG_FP_ARGS, %g0 ! need fp regs? + add %sp, 48, %sp ! deallocate prep frame + be,pt %xcc, 1f + mov %o0, %l0 ! save flags - ldd [%l0+ARGS], %f0 - ldd [%l0+ARGS+8], %f2 - ldd [%l0+ARGS+16], %f4 - ldd [%l0+ARGS+24], %f6 - ldd [%l0+ARGS+32], %f8 - ldd [%l0+ARGS+40], %f10 - ldd [%l0+ARGS+48], %f12 - ldd [%l0+ARGS+56], %f14 - ldd [%l0+ARGS+64], %f16 - ldd [%l0+ARGS+72], %f18 - ldd [%l0+ARGS+80], %f20 - ldd [%l0+ARGS+88], %f22 - ldd [%l0+ARGS+96], %f24 - ldd [%l0+ARGS+104], %f26 - ldd [%l0+ARGS+112], %f28 - ldd [%l0+ARGS+120], %f30 + ldd [%sp+STACK_BIAS+128], %f0 ! load all fp arg regs + ldd [%sp+STACK_BIAS+128+8], %f2 + ldd [%sp+STACK_BIAS+128+16], %f4 + ldd [%sp+STACK_BIAS+128+24], %f6 + ldd [%sp+STACK_BIAS+128+32], %f8 + ldd [%sp+STACK_BIAS+128+40], %f10 + ldd [%sp+STACK_BIAS+128+48], %f12 + ldd [%sp+STACK_BIAS+128+56], %f14 + ldd [%sp+STACK_BIAS+128+64], %f16 + ldd [%sp+STACK_BIAS+128+72], %f18 + ldd [%sp+STACK_BIAS+128+80], %f20 + ldd [%sp+STACK_BIAS+128+88], %f22 + ldd [%sp+STACK_BIAS+128+96], %f24 + ldd [%sp+STACK_BIAS+128+104], %f26 + ldd [%sp+STACK_BIAS+128+112], %f28 + ldd [%sp+STACK_BIAS+128+120], %f30 -1: ldx [%l0+ARGS+8], %o1 - ldx [%l0+ARGS+16], %o2 - ldx [%l0+ARGS+24], %o3 - ldx [%l0+ARGS+32], %o4 - ldx [%l0+ARGS+40], %o5 - call %i5 - sub %l0, STACK_BIAS, %sp ! (delay) switch to frame +1: ldx [%sp+STACK_BIAS+128], %o0 ! load all int arg regs + ldx [%sp+STACK_BIAS+128+8], %o1 + ldx [%sp+STACK_BIAS+128+16], %o2 + ldx [%sp+STACK_BIAS+128+24], %o3 + ldx [%sp+STACK_BIAS+128+32], %o4 + call %i1 + ldx [%sp+STACK_BIAS+128+40], %o5 - ! If the return value pointer is NULL, assume no return value. - brz,pn %i4, L(done) +0: call 1f ! load pc in %o7 + and %l0, SPARC_FLAG_RET_MASK, %l1 +1: sll %l1, 4, %l1 + add %o7, %l1, %o7 ! o7 = 0b + ret_type*16 + jmp %o7+(2f-0b) nop - cmp %i3, FFI_TYPE_INT - be,a,pt %icc, L(done) - stx %o0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_FLOAT - be,a,pn %icc, L(done) - st %f0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_DOUBLE - be,a,pn %icc, L(done) - std %f0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_STRUCT - be,pn %icc, L(dostruct) - - cmp %i3, FFI_TYPE_LONGDOUBLE - bne,pt %icc, L(done) + .align 16 +2: +E SPARC_RET_VOID + return %i7+8 nop - std %f0, [%i4+0] - std %f2, [%i4+8] +E SPARC_RET_STRUCT + add %sp, STACK_BIAS-64+128+48, %l2 + sub %sp, 64, %sp + b 8f + stx %o0, [%l2] +E SPARC_RET_FLOAT + return %i7+8 + st %f0, [%o2] +E SPARC_RET_DOUBLE + return %i7+8 + std %f0, [%o2] +E SPARC_RET_UINT8 + and %o0, 0xff, %i0 + return %i7+8 + stx %o0, [%o2] +E SPARC_RET_SINT8 + sll %o0, 24, %o0 + sra %o0, 24, %i0 + return %i7+8 + stx %o0, [%o2] +E SPARC_RET_UINT16 + sll %o0, 16, %o0 + srl %o0, 16, %i0 + return %i7+8 + stx %o0, [%o2] +E SPARC_RET_SINT16 + sll %o0, 16, %o0 + sra %o0, 16, %i0 + return %i7+8 + stx %o0, [%o2] +E SPARC_RET_INT64 + stx %o0, [%i2] + return %i7+8 + nop +E SPARC_RET_UINT32 + srl %o0, 0, %i0 + return %i7+8 + stx %o0, [%o2] +E SPARC_RET_SINT32 + sra %o0, 0, %i0 + return %i7+8 + stx %o0, [%o2] +E SPARC_RET_LDOUBLE + std %f0, [%i2] + return %i7+8 + std %f2, [%o2+8] -L(done): - ret - restore + ! Unused entries. Don't allow bad data to do worse things. +E 12 + unimp +E 13 + unimp +E 14 + unimp +E 15 + unimp -L(dostruct): - /* This will not work correctly for unions. */ - stx %o0, [%i4+0] - stx %o1, [%i4+8] - stx %o2, [%i4+16] - stx %o3, [%i4+24] - std %f0, [%i4+32] - std %f2, [%i4+40] - std %f4, [%i4+48] - std %f6, [%i4+56] - ret - restore + ! Finish the SPARC_RET_STRUCT sequence. + .align 8 +8: stx %o1, [%l2+8] + stx %o2, [%l2+16] + stx %o3, [%l2+24] + std %f0, [%l2+32] + std %f2, [%l2+40] + std %f4, [%l2+48] + std %f6, [%l2+56] + + ! Copy the structure into place. + ldx [%i0+16], %o0 ! load rtype from cif + mov 0, %o1 ! load off + mov %i2, %o2 ! load dst + mov %l2, %o3 ! load src_int + call C(ffi_v9_layout_struct) + add %l2, 32, %o4 ! load src_fp + + return %i7+8 + nop cfi_endproc .size C(ffi_call_v9), . - C(ffi_call_v9) @@ -195,54 +245,90 @@ C(ffi_closure_v9): call C(ffi_closure_sparc_inner_v9) add %fp, STACK_BIAS-128, %o3 - ! Load up the return value in the proper type. - ! See ffi_prep_cif_machdep for the list of cases. - cmp %o0, FFI_TYPE_VOID - be,pn %icc, L(done1) +0: call 1f ! load pc in %o7 + and %o0, SPARC_FLAG_RET_MASK, %o0 +1: sll %o0, 4, %o0 ! o2 = i2 * 16 + add %o7, %o0, %o7 ! o7 = 0b + i2*16 + jmp %o7+(2f-0b) + nop - cmp %o0, FFI_TYPE_INT - be,pn %icc, L(integer) - - cmp %o0, FFI_TYPE_FLOAT - be,a,pn %icc, L(done1) - ld [FP-160], %f0 - - cmp %o0, FFI_TYPE_DOUBLE - be,a,pn %icc, L(done1) - ldd [FP-160], %f0 - -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - cmp %o0, FFI_TYPE_LONGDOUBLE - be,a,pn %icc, L(longdouble1) - ldd [FP-160], %f0 -#endif - - ! FFI_TYPE_STRUCT - ldx [FP-152], %i1 - ldx [FP-144], %i2 - ldx [FP-136], %i3 - ldd [FP-160], %f0 - ldd [FP-152], %f2 - ldd [FP-144], %f4 - ldd [FP-136], %f6 - -L(integer): + ! Note that we cannot load the data in the delay slot of + ! the return insn because the data is in the stack frame + ! that is deallocated by the return. + .align 16 +2: +E SPARC_RET_VOID + return %i7+8 + nop +E SPARC_RET_STRUCT ldx [FP-160], %i0 + ldd [FP-160], %f0 + b 8f + ldx [FP-152], %i1 +E SPARC_RET_FLOAT + ld [FP-160], %f0 + return %i7+8 + nop +E SPARC_RET_DOUBLE + ldd [FP-160], %f0 + return %i7+8 + nop +E SPARC_RET_UINT8 + ldub [FP-160+7], %i0 + return %i7+8 + nop +E SPARC_RET_SINT8 + ldsb [FP-160+7], %i0 + return %i7+8 + nop +E SPARC_RET_UINT16 + lduh [FP-160+6], %i0 + return %i7+8 + nop +E SPARC_RET_SINT16 + ldsh [FP-160+6], %i0 + return %i7+8 + nop +E SPARC_RET_INT64 + ldx [FP-160], %i0 + return %i7+8 + nop +E SPARC_RET_UINT32 + lduw [FP-160+4], %i0 + return %i7+8 + nop +E SPARC_RET_SINT32 + ldsw [FP-160+4], %i0 + return %i7+8 + nop +E SPARC_RET_LDOUBLE + ldd [FP-160], %f0 + ldd [FP-160+8], %f2 + return %i7+8 + nop -L(done1): - ret - restore + ! Unused entries. Don't allow bad data to do worse things. +E 12 + unimp +E 13 + unimp +E 14 + unimp +E 15 + unimp -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE -L(longdouble1): - ldd [FP-152], %f2 - ret - restore -#endif + ! Finish the SPARC_RET_STRUCT sequence. + .align 8 +8: ldd [FP-152], %f2 + ldx [FP-144], %i2 + ldd [FP-144], %f4 + ldx [FP-136], %i3 + ldd [FP-136], %f6 + return %i7+8 + nop cfi_endproc .size C(ffi_closure_v9), . - C(ffi_closure_v9) - #endif /* SPARC64 */ #ifdef __linux__ .section .note.GNU-stack,"",@progbits