diff options
author | Richard Henderson <rth@redhat.com> | 2015-01-12 08:19:59 -0800 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2015-01-12 08:19:59 -0800 |
commit | b1760f7f915a36ee9b4636fb54719c9b3ae59356 (patch) | |
tree | 1a64d747b069bdebf651d856989dd40a54daf0cc /libffi/src/sparc | |
parent | 62e22fcb7985349b93646b86351033e1fb09c46c (diff) | |
download | gcc-b1760f7f915a36ee9b4636fb54719c9b3ae59356.zip gcc-b1760f7f915a36ee9b4636fb54719c9b3ae59356.tar.gz gcc-b1760f7f915a36ee9b4636fb54719c9b3ae59356.tar.bz2 |
Merge libffi to upstream commit c82cc159426d8d4402375fa1ae3f045b9cf82e16
From-SVN: r219477
Diffstat (limited to 'libffi/src/sparc')
-rw-r--r-- | libffi/src/sparc/ffi.c | 913 | ||||
-rw-r--r-- | libffi/src/sparc/ffi64.c | 608 | ||||
-rw-r--r-- | libffi/src/sparc/ffitarget.h | 32 | ||||
-rw-r--r-- | libffi/src/sparc/internal.h | 26 | ||||
-rw-r--r-- | libffi/src/sparc/v8.S | 535 | ||||
-rw-r--r-- | libffi/src/sparc/v9.S | 504 |
6 files changed, 1554 insertions, 1064 deletions
diff --git a/libffi/src/sparc/ffi.c b/libffi/src/sparc/ffi.c index 77e3822..d5212d8 100644 --- a/libffi/src/sparc/ffi.c +++ b/libffi/src/sparc/ffi.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- - ffi.c - Copyright (c) 2011 Anthony Green + 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 @@ -27,697 +27,442 @@ #include <ffi.h> #include <ffi_common.h> - #include <stdlib.h> +#include "internal.h" +#ifndef SPARC64 -/* ffi_prep_args is called by the assembly routine once stack space - has been allocated for the function's arguments */ - -#ifdef SPARC64 - -int -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; +/* 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 - p_argv = ecif->avalue; +/* Perform machine dependent cif processing */ +ffi_status FFI_HIDDEN +ffi_prep_cif_machdep(ffi_cif *cif) +{ + ffi_type *rtype = cif->rtype; + int rtt = rtype->type; + size_t bytes; + int i, n, flags; - if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && - ecif->cif->rtype->size > 32) + /* Set the return type flag */ + switch (rtt) { - *(unsigned long long *) argp = (unsigned long)ecif->rvalue; - argp += sizeof(long long); - tmp = 1; + case FFI_TYPE_VOID: + flags = SPARC_RET_VOID; + break; + case FFI_TYPE_FLOAT: + flags = SPARC_RET_F_1; + break; + case FFI_TYPE_DOUBLE: + flags = SPARC_RET_F_2; + break; + case FFI_TYPE_LONGDOUBLE: + case FFI_TYPE_STRUCT: + flags = (rtype->size & 0xfff) << SPARC_SIZEMASK_SHIFT; + 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: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + flags = SPARC_RET_UINT32; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + flags = SPARC_RET_INT64; + break; + case FFI_TYPE_COMPLEX: + rtt = rtype->elements[0]->type; + switch (rtt) + { + case FFI_TYPE_FLOAT: + flags = SPARC_RET_F_2; + break; + case FFI_TYPE_DOUBLE: + flags = SPARC_RET_F_4; + break; + case FFI_TYPE_LONGDOUBLE: + flags = SPARC_RET_F_8; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + flags = SPARC_RET_INT128; + break; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + flags = SPARC_RET_INT64; + break; + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + flags = SP_V8_RET_CPLX16; + break; + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + flags = SP_V8_RET_CPLX8; + break; + default: + abort(); + } + break; + default: + abort(); } + cif->flags = flags; - for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; - i++, p_arg++) + bytes = 0; + for (i = 0, n = cif->nargs; i < n; ++i) { - size_t z; + ffi_type *ty = cif->arg_types[i]; + size_t z = ty->size; + int tt = ty->type; - z = (*p_arg)->size; - switch ((*p_arg)->type) + switch (tt) { 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: -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: -#endif - ret = 1; /* We should promote into FP regs as well as integer. */ + by_reference: + /* Passed by reference. */ + z = 4; break; + + case FFI_TYPE_COMPLEX: + tt = ty->elements[0]->type; + if (tt == FFI_TYPE_FLOAT || z > 8) + goto by_reference; + /* FALLTHRU */ + + default: + z = ALIGN(z, 4); } - if (z < sizeof(long long)) - { - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed long long *) argp = *(SINT8 *)(* p_argv); - break; + bytes += z; + } - case FFI_TYPE_UINT8: - *(unsigned long long *) argp = *(UINT8 *)(* p_argv); - break; + /* 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; - case FFI_TYPE_SINT16: - *(signed long long *) argp = *(SINT16 *)(* p_argv); - break; + /* The ABI always requires space for the struct return pointer. */ + bytes += 4; - case FFI_TYPE_UINT16: - *(unsigned long long *) argp = *(UINT16 *)(* p_argv); - break; + /* The stack must be 2 word aligned, so round bytes up appropriately. */ + bytes = ALIGN(bytes, 2 * 4); - case FFI_TYPE_SINT32: - *(signed long long *) argp = *(SINT32 *)(* p_argv); - break; + /* Include the call frame to prep_args. */ + bytes += 4*16 + 4*8; + cif->bytes = bytes; - case FFI_TYPE_UINT32: - *(unsigned long long *) argp = *(UINT32 *)(* p_argv); - break; + return FFI_OK; +} - case FFI_TYPE_FLOAT: - *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */ - break; +extern void ffi_call_v8(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, size_t bytes, void *closure) FFI_HIDDEN; - case FFI_TYPE_STRUCT: - memcpy(argp, *p_argv, z); - break; +int FFI_HIDDEN +ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue) +{ + ffi_type **p_arg; + int flags = cif->flags; + int i, nargs; - default: - FFI_ASSERT(0); - } - z = sizeof(long long); - tmp++; - } - else if (z == sizeof(long long)) + if (rvalue == NULL) + { + if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT) { - memcpy(argp, *p_argv, z); - z = sizeof(long long); - tmp++; + /* 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 { - if ((tmp & 1) && (*p_arg)->alignment > 8) - { - tmp++; - argp += sizeof(long long); - } - memcpy(argp, *p_argv, z); - z = 2 * sizeof(long long); - tmp += 2; + /* Otherwise, we can ignore the return value. */ + flags = SPARC_RET_VOID; } - p_argv++; - argp += z; } - return ret; -} - -#else - -void -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); + /* 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. */ - - ((int*)argp)[0] = 0; - ((int*)argp)[1] = 0; - ((int*)argp)[2] = 0; - ((int*)argp)[3] = 0; - ((int*)argp)[4] = 0; - ((int*)argp)[5] = 0; + /* Purify will probably complain in our assembly routine, + unless we zero out this memory. */ + memset(argp, 0, 6*4); #endif - p_argv = ecif->avalue; - - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++) + p_arg = cif->arg_types; + for (i = 0, nargs = cif->nargs; i < nargs; i++) { + ffi_type *ty = p_arg[i]; + void *a = avalue[i]; + int tt = ty->type; size_t z; - if ((*p_arg)->type == FFI_TYPE_STRUCT -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - || (*p_arg)->type == FFI_TYPE_LONGDOUBLE -#endif - ) + switch (tt) + { + case FFI_TYPE_STRUCT: + case FFI_TYPE_LONGDOUBLE: + by_reference: + *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; + + case FFI_TYPE_COMPLEX: + tt = ty->elements[0]->type; + z = ty->size; + if (tt == FFI_TYPE_FLOAT || z > 8) + goto by_reference; + if (z < 4) { - *(unsigned int *) argp = (unsigned long)(* p_argv); - z = sizeof(int); + memcpy((char *)argp + 4 - z, a, z); + argp++; } 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); - } + memcpy(argp, a, z); + argp += z / 4; } - p_argv++; - argp += z; - } - - return; -} - -#endif - -/* Perform machine dependent cif processing */ - -static -ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif) -{ - int wordsize; - - if (!V9_ABI_P (cif->abi)) - { - 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; + break; - /* 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; + default: + abort(); + } } - /* 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); + return flags; +} - /* Set the return type flag */ - switch (cif->rtype->type) - { - case FFI_TYPE_VOID: - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: -#endif - cif->flags = cif->rtype->type; - break; +static void +ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + size_t bytes = cif->bytes; - case FFI_TYPE_STRUCT: - if (V9_ABI_P (cif->abi) && cif->rtype->size > 32) - cif->flags = FFI_TYPE_VOID; - else - cif->flags = FFI_TYPE_STRUCT; - break; + FFI_ASSERT (cif->abi == FFI_V8); - case FFI_TYPE_SINT8: - case FFI_TYPE_UINT8: - case FFI_TYPE_SINT16: - case FFI_TYPE_UINT16: - if (V9_ABI_P (cif->abi)) - cif->flags = FFI_TYPE_INT; - else - cif->flags = cif->rtype->type; - break; + /* 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_FLAG_RET_MASK) == SPARC_RET_STRUCT) + bytes += ALIGN (cif->rtype->size, 8); - case FFI_TYPE_SINT64: - case FFI_TYPE_UINT64: - if (V9_ABI_P (cif->abi)) - cif->flags = FFI_TYPE_INT; - else - cif->flags = FFI_TYPE_SINT64; - break; - - default: - cif->flags = FFI_TYPE_INT; - break; - } - return FFI_OK; + ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure); } -ffi_status -ffi_prep_cif_machdep(ffi_cif *cif) +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { -#ifdef SPARC64 - if (cif->abi != FFI_COMPAT_V9) - cif->nfixedargs = cif->nargs; -#endif - return ffi_prep_cif_machdep_core (cif); + ffi_call_int (cif, fn, rvalue, avalue, NULL); } -ffi_status -ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, - unsigned int ntotalargs) +void +ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) { -#ifdef SPARC64 - if (cif->abi != FFI_COMPAT_V9) - cif->nfixedargs = nfixedargs; -#endif - return ffi_prep_cif_machdep_core (cif); + ffi_call_int (cif, fn, rvalue, avalue, closure); } -#ifdef SPARC64 - -int -ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt) +#ifdef __GNUC__ +static inline void +ffi_flush_icache (void *p) { - ffi_type **ptr = &arg->elements[0]; - - while (*ptr != NULL) - { - if (off & ((*ptr)->alignment - 1)) - off = ALIGN(off, (*ptr)->alignment); - - switch ((*ptr)->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: -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: -#endif - memmove(ret + off, flt + off, (*ptr)->size); - off += (*ptr)->size; - break; - default: - memmove(ret + off, intg + off, (*ptr)->size); - off += (*ptr)->size; - break; - } - ptr++; - } - return off; + /* 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"); } - -#endif - -#ifdef SPARC64 -extern int ffi_call_v9(void *, extended_cif *, unsigned, - unsigned, unsigned *, void (*fn)(void)); -#else -extern int ffi_call_v8(void *, extended_cif *, unsigned, - unsigned, unsigned *, void (*fn)(void)); -#endif - -void -ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) -{ - extended_cif ecif; -#ifdef SPARC64 - void *rval = rvalue; -#endif - - ecif.cif = cif; - ecif.avalue = avalue; - ecif.rvalue = rvalue; - - /* If the return value is a struct and we don't have a return value address, - then we need to make one. */ - if (cif->rtype->type == FFI_TYPE_STRUCT) - { - if (ecif.rvalue == NULL) - ecif.rvalue = alloca(cif->rtype->size); - -#ifdef SPARC64 - if (cif->rtype->size <= 32) - rval = alloca(64); - else - rval = NULL; -#endif - } - - switch (cif->abi) - { - case FFI_V8: - case FFI_V8PLUS: -#ifdef SPARC64 - /* We don't yet support calling 32bit code from 64bit */ - FFI_ASSERT(0); #else - if (rvalue && (cif->rtype->type == FFI_TYPE_STRUCT -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - || cif->flags == FFI_TYPE_LONGDOUBLE +extern void ffi_flush_icache (void *) FFI_HIDDEN; #endif - )) - { - /* 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 */ - 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"); - ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, - cif->flags, rvalue, (void (*)(void)) 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_COMPAT_V9: - 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; - } -} - -#ifdef SPARC64 -extern void ffi_closure_v9(void); -#else -extern void ffi_closure_v8(void); -#endif +extern void ffi_closure_v8(void) FFI_HIDDEN; +extern void ffi_go_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 (!V9_ABI_P (cif->abi)) - 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; - if (!V8_ABI_P (cif->abi)) + 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 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 + ffi_flush_icache (closure); return FFI_OK; } -#ifdef SPARC64 +ffi_status +ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*)) +{ + if (cif->abi != FFI_V8) + return FFI_BAD_ABI; -int -ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue, - unsigned long *gpr, double *fpr) + closure->tramp = ffi_go_closure_v8; + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; +} + +int FFI_HIDDEN +ffi_closure_sparc_inner_v8(ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, void *rvalue, + unsigned long *argp) { - ffi_cif *cif; ffi_type **arg_types; void **avalue; - int i, argn, fp_slot_max; + 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_VOID && cif->rtype->type == FFI_TYPE_STRUCT) + returns the data directly to the caller. Also install it so we + can return the address in %o0. */ + if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT) { - rvalue = (void *) gpr[0]; - /* Skip the structure return address. */ - argn = 1; + void *new_rvalue = (void *)*argp; + *(void **)rvalue = new_rvalue; + rvalue = new_rvalue; } - else - argn = 0; - fp_slot_max = 16 - argn; + /* Always skip the structure return address. */ + 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 the function is variadic, FP arguments are passed in FP - registers only if the corresponding parameter is named. */ - const int named - = (cif->abi == FFI_COMPAT_V9 ? 1 : i < cif->nfixedargs); + ffi_type *ty = arg_types[i]; + int tt = ty->type; + void *a = argp; + size_t z; - if (arg_types[i]->type == FFI_TYPE_STRUCT) + switch (tt) { - if (arg_types[i]->size > 16) - { - /* Straight copy of invisible reference. */ - avalue[i] = (void *)gpr[argn++]; - } - else + case FFI_TYPE_STRUCT: + case FFI_TYPE_LONGDOUBLE: + by_reference: + /* Straight copy of invisible reference. */ + a = (void *)*argp; + break; + + case FFI_TYPE_DOUBLE: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + if ((unsigned long)a & 7) { - /* Left-justify. */ - ffi_v9_layout_struct(arg_types[i], - 0, - (char *) &gpr[argn], - (char *) &gpr[argn], - named - ? (char *) &fpr[argn] - : (char *) &gpr[argn]); - avalue[i] = &gpr[argn]; - argn - += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + /* Align on a 8-byte boundary. */ + UINT64 *tmp = alloca(8); + *tmp = ((UINT64)argp[0] << 32) | argp[1]; + a = tmp; } - } - else - { - /* Right-justify. */ - argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; - - /* Align on a 16-byte boundary. */ -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - if (arg_types[i]->type == FFI_TYPE_LONGDOUBLE && (argn % 2) != 0) - argn++; -#endif - if (i < fp_slot_max - && named - && (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 - 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; -} - -#else - -int -ffi_closure_sparc_inner_v8(ffi_closure *closure, void *rvalue, - unsigned long *gpr, unsigned long *scratch) -{ - ffi_cif *cif; - ffi_type **arg_types; - void **avalue; - int i, argn; - - cif = closure->cif; - arg_types = cif->arg_types; - avalue = alloca(cif->nargs * sizeof(void *)); + argp++; + break; - /* Copy the caller's structure return address so that the closure - returns the data directly to the caller. */ - if (cif->flags == FFI_TYPE_STRUCT -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - || cif->flags == FFI_TYPE_LONGDOUBLE -#endif - ) - rvalue = (void *) gpr[0]; + 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; - /* Always skip the structure return address. */ - argn = 1; + case FFI_TYPE_COMPLEX: + tt = ty->elements[0]->type; + z = ty->size; + if (tt == FFI_TYPE_FLOAT || z > 8) + goto by_reference; + if (z < 4) + a += 4 - z; + else if (z > 4) + argp++; + break; - /* 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 FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - || arg_types[i]->type == FFI_TYPE_LONGDOUBLE -#endif - ) - { - /* 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; + default: + abort(); } + argp++; + avalue[i] = a; } /* Invoke the closure. */ - closure->fun (cif, rvalue, avalue, closure->user_data); + fun (cif, rvalue, avalue, user_data); /* Tell ffi_closure_sparc how to perform return type promotions. */ - return cif->rtype->type; + return flags; } - -#endif +#endif /* !SPARC64 */ diff --git a/libffi/src/sparc/ffi64.c b/libffi/src/sparc/ffi64.c new file mode 100644 index 0000000..340b198 --- /dev/null +++ b/libffi/src/sparc/ffi64.c @@ -0,0 +1,608 @@ +/* ----------------------------------------------------------------------- + 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 <ffi.h> +#include <ffi_common.h> +#include <stdlib.h> +#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 + +/* Flatten the contents of a structure to the parts that are passed in + floating point registers. The return is a bit mask wherein bit N + set means bytes [4*n, 4*n+3] are passed in %fN. + + We encode both the (running) size (maximum 32) and mask (maxumum 255) + into one integer. The size is placed in the low byte, so that align + and addition work correctly. The mask is placed in the second byte. */ + +static int +ffi_struct_float_mask (ffi_type *outer_type, int size_mask) +{ + ffi_type **elts; + ffi_type *t; + + if (outer_type->type == FFI_TYPE_COMPLEX) + { + int m = 0, tt = outer_type->elements[0]->type; + size_t z = outer_type->size; + + if (tt == FFI_TYPE_FLOAT + || tt == FFI_TYPE_DOUBLE + || tt == FFI_TYPE_LONGDOUBLE) + m = (1 << (z / 4)) - 1; + return (m << 8) | z; + } + FFI_ASSERT (outer_type->type == FFI_TYPE_STRUCT); + + for (elts = outer_type->elements; (t = *elts) != NULL; elts++) + { + size_t z = t->size; + int o, m, tt; + + size_mask = ALIGN(size_mask, t->alignment); + switch (t->type) + { + case FFI_TYPE_STRUCT: + size_mask = ffi_struct_float_mask (t, size_mask); + continue; + case FFI_TYPE_COMPLEX: + tt = t->elements[0]->type; + if (tt != FFI_TYPE_FLOAT + && tt != FFI_TYPE_DOUBLE + && tt != FFI_TYPE_LONGDOUBLE) + break; + /* FALLTHRU */ + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + m = (1 << (z / 4)) - 1; /* compute mask for type */ + o = (size_mask >> 2) & 0x3f; /* extract word offset */ + size_mask |= m << (o + 8); /* insert mask into place */ + break; + } + size_mask += z; + } + + size_mask = ALIGN(size_mask, outer_type->alignment); + FFI_ASSERT ((size_mask & 0xff) == outer_type->size); + + return size_mask; +} + +/* Merge floating point data into integer data. If the structure is + entirely floating point, simply return a pointer to the fp data. */ + +static void * +ffi_struct_float_merge (int size_mask, void *vi, void *vf) +{ + int size = size_mask & 0xff; + int mask = size_mask >> 8; + int n = size >> 2; + + if (mask == 0) + return vi; + else if (mask == (1 << n) - 1) + return vf; + else + { + unsigned int *wi = vi, *wf = vf; + int i; + + for (i = 0; i < n; ++i) + if ((mask >> i) & 1) + wi[i] = wf[i]; + + return vi; + } +} + +/* Similar, but place the data into VD in the end. */ + +void FFI_HIDDEN +ffi_struct_float_copy (int size_mask, void *vd, void *vi, void *vf) +{ + int size = size_mask & 0xff; + int mask = size_mask >> 8; + int n = size >> 2; + + if (mask == 0) + ; + else if (mask == (1 << n) - 1) + vi = vf; + else + { + unsigned int *wd = vd, *wi = vi, *wf = vf; + int i; + + for (i = 0; i < n; ++i) + wd[i] = ((mask >> i) & 1 ? wf : wi)[i]; + return; + } + memcpy (vd, vi, size); +} + +/* Perform machine dependent cif processing */ + +static ffi_status +ffi_prep_cif_machdep_core(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_F_1; + break; + case FFI_TYPE_DOUBLE: + flags = SPARC_RET_F_2; + break; + case FFI_TYPE_LONGDOUBLE: + flags = SPARC_RET_F_4; + break; + + case FFI_TYPE_COMPLEX: + case FFI_TYPE_STRUCT: + if (rtype->size > 32) + { + flags = SPARC_RET_VOID | SPARC_FLAG_RET_IN_MEM; + bytes = 8; + } + else + { + int size_mask = ffi_struct_float_mask (rtype, 0); + int word_size = (size_mask >> 2) & 0x3f; + int all_mask = (1 << word_size) - 1; + int fp_mask = size_mask >> 8; + + flags = (size_mask << SPARC_SIZEMASK_SHIFT) | SPARC_RET_STRUCT; + + /* For special cases of all-int or all-fp, we can return + the value directly without popping through a struct copy. */ + if (fp_mask == 0) + { + if (rtype->alignment >= 8) + { + if (rtype->size == 8) + flags = SPARC_RET_INT64; + else if (rtype->size == 16) + flags = SPARC_RET_INT128; + } + } + else if (fp_mask == all_mask) + switch (word_size) + { + case 1: flags = SPARC_RET_F_1; break; + case 2: flags = SPARC_RET_F_2; break; + case 3: flags = SP_V9_RET_F_3; break; + case 4: flags = SPARC_RET_F_4; break; + /* 5 word structures skipped; handled via RET_STRUCT. */ + case 6: flags = SPARC_RET_F_6; break; + /* 7 word structures skipped; handled via RET_STRUCT. */ + case 8: flags = SPARC_RET_F_8; break; + } + } + 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 = SP_V9_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_COMPLEX: + case FFI_TYPE_STRUCT: + /* Large structs passed by reference. */ + if (z > 16) + { + a = z = 8; + break; + } + /* Small structs may be passed in integer or fp regs or both. */ + if (bytes >= 16*8) + break; + if ((ffi_struct_float_mask (ty, 0) & 0xff00) == 0) + break; + /* FALLTHRU */ + 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; +} + +ffi_status FFI_HIDDEN +ffi_prep_cif_machdep(ffi_cif *cif) +{ + cif->nfixedargs = cif->nargs; + return ffi_prep_cif_machdep_core(cif); +} + +ffi_status FFI_HIDDEN +ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned nfixedargs, unsigned ntotalargs) +{ + cif->nfixedargs = nfixedargs; + return ffi_prep_cif_machdep_core(cif); +} + +extern void ffi_call_v9(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, size_t bytes, void *closure) 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_COMPLEX: + 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; +} + +static void +ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + 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, closure); +} + +void +ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + ffi_call_int(cif, fn, rvalue, avalue, NULL); +} + +void +ffi_call_go(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + ffi_call_int(cif, fn, rvalue, avalue, closure); +} + +#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; +extern void ffi_go_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; +} + +ffi_status +ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*)) +{ + if (cif->abi != FFI_V9) + return FFI_BAD_ABI; + + closure->tramp = ffi_go_closure_v9; + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; +} + +int FFI_HIDDEN +ffi_closure_sparc_inner_v9(ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, void *rvalue, + unsigned long *gpr, unsigned long *fpr) +{ + ffi_type **arg_types; + void **avalue; + int i, argn, argx, nargs, flags, nfixedargs; + + arg_types = cif->arg_types; + nargs = cif->nargs; + flags = cif->flags; + nfixedargs = cif->nfixedargs; + + 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++, argn = argx) + { + int named = i < nfixedargs; + ffi_type *ty = arg_types[i]; + void *a = &gpr[argn]; + size_t z; + + argx = argn + 1; + switch (ty->type) + { + case FFI_TYPE_COMPLEX: + case FFI_TYPE_STRUCT: + z = ty->size; + if (z > 16) + a = *(void **)a; + else + { + argx = argn + ALIGN (z, 8) / 8; + if (named && argn < 16) + { + int size_mask = ffi_struct_float_mask (ty, 0); + int argn_mask = (0xffff00 >> argn) & 0xff00; + + /* Eliminate fp registers off the end. */ + size_mask = (size_mask & 0xff) | (size_mask & argn_mask); + a = ffi_struct_float_merge (size_mask, gpr+argn, fpr+argn); + } + } + break; + + case FFI_TYPE_LONGDOUBLE: + argn = ALIGN (argn, 2); + a = (named && argn < 16 ? fpr : gpr) + argn; + argx = argn + 2; + break; + case FFI_TYPE_DOUBLE: + if (named && argn < 16) + a = fpr + argn; + break; + case FFI_TYPE_FLOAT: + if (named && argn < 16) + a = fpr + argn; + 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. */ + fun (cif, rvalue, avalue, user_data); + + /* Tell ffi_closure_sparc how to perform return type promotions. */ + return flags; +} +#endif /* SPARC64 */ diff --git a/libffi/src/sparc/ffitarget.h b/libffi/src/sparc/ffitarget.h index 6489ac0..2f4cd9a 100644 --- a/libffi/src/sparc/ffitarget.h +++ b/libffi/src/sparc/ffitarget.h @@ -46,42 +46,36 @@ typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, - FFI_V8, - FFI_V8PLUS, - /* See below for the COMPAT_V9 rationale. */ - FFI_COMPAT_V9, - 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 V8_ABI_P(abi) ((abi) == FFI_V8 || (abi) == FFI_V8PLUS) -#define V9_ABI_P(abi) ((abi) == FFI_COMPAT_V9 || (abi) == FFI_V9) - -#define FFI_TARGET_SPECIFIC_VARIADIC 1 +#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION 1 +#define FFI_TARGET_HAS_COMPLEX_TYPE 1 -/* The support of variadic functions was broken in the original implementation - of the FFI_V9 ABI. This has been fixed by adding one extra field to the - CIF structure (nfixedargs field), which means that the ABI of libffi itself - has changed. In order to support applications using the original ABI, we - have renamed FFI_V9 into FFI_COMPAT_V9 and defined a new FFI_V9 value. */ #ifdef SPARC64 -#define FFI_EXTRA_CIF_FIELDS unsigned int nfixedargs +# define FFI_TARGET_SPECIFIC_VARIADIC 1 +# define FFI_EXTRA_CIF_FIELDS unsigned int nfixedargs #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 +#define FFI_GO_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + #ifdef SPARC64 #define FFI_TRAMPOLINE_SIZE 24 #else #define FFI_TRAMPOLINE_SIZE 16 #endif -#define FFI_NATIVE_RAW_API 0 #endif + diff --git a/libffi/src/sparc/internal.h b/libffi/src/sparc/internal.h new file mode 100644 index 0000000..0a66472 --- /dev/null +++ b/libffi/src/sparc/internal.h @@ -0,0 +1,26 @@ +#define SPARC_RET_VOID 0 +#define SPARC_RET_STRUCT 1 +#define SPARC_RET_UINT8 2 +#define SPARC_RET_SINT8 3 +#define SPARC_RET_UINT16 4 +#define SPARC_RET_SINT16 5 +#define SPARC_RET_UINT32 6 +#define SP_V9_RET_SINT32 7 /* v9 only */ +#define SP_V8_RET_CPLX16 7 /* v8 only */ +#define SPARC_RET_INT64 8 +#define SPARC_RET_INT128 9 + +/* Note that F_7 is missing, and is handled by SPARC_RET_STRUCT. */ +#define SPARC_RET_F_8 10 +#define SPARC_RET_F_6 11 +#define SPARC_RET_F_4 12 +#define SPARC_RET_F_2 13 +#define SP_V9_RET_F_3 14 /* v9 only */ +#define SP_V8_RET_CPLX8 14 /* v8 only */ +#define SPARC_RET_F_1 15 + +#define SPARC_FLAG_RET_MASK 15 +#define SPARC_FLAG_RET_IN_MEM 32 +#define SPARC_FLAG_FP_ARGS 64 + +#define SPARC_SIZEMASK_SHIFT 8 diff --git a/libffi/src/sparc/v8.S b/libffi/src/sparc/v8.S index 7ec6e1c..3a811ef 100644 --- a/libffi/src/sparc/v8.S +++ b/libffi/src/sparc/v8.S @@ -1,7 +1,8 @@ /* ----------------------------------------------------------------------- - v8.S - Copyright (c) 1996, 1997, 2003, 2004, 2008 Red Hat, Inc. + v8.S - Copyright (c) 2013 The Written Word, Inc. + Copyright (c) 1996, 1997, 2003, 2004, 2008 Red Hat, Inc. - SPARC Foreign Function Interface + 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 @@ -24,153 +25,243 @@ DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ -#define LIBFFI_ASM +#define LIBFFI_ASM #include <fficonfig.h> #include <ffi.h> +#include <ffi_cfi.h> +#include "internal.h" #ifndef SPARC64 -#define STACKFRAME 96 /* Minimum stack framesize for SPARC */ -#define ARGS (64+4) /* Offset of register area in frame */ +#define C2(X, Y) X ## Y +#define C1(X, Y) C2(X, Y) -.text - .align 8 -.globl ffi_call_v8 -.globl _ffi_call_v8 - -ffi_call_v8: -_ffi_call_v8: -.LLFB1: - save %sp, -STACKFRAME, %sp -.LLCFI0: - - 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) - - 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 - - ! If the return value pointer is NULL, assume no return value. - tst %i4 - bz done - nop - - cmp %i3, FFI_TYPE_INT - be,a done - st %o0, [%i4] ! (delay) - - cmp %i3, FFI_TYPE_FLOAT - be,a done - st %f0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_DOUBLE - be,a double - st %f0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_SINT8 - be,a sint8 - sll %o0, 24, %o0 ! (delay) +#ifdef __USER_LABEL_PREFIX__ +# define C(Y) C1(__USER_LABEL_PREFIX__, Y) +#else +# define C(Y) Y +#endif +#define L(Y) C1(.L, Y) - cmp %i3, FFI_TYPE_UINT8 - be,a uint8 - sll %o0, 24, %o0 ! (delay) + .text - cmp %i3, FFI_TYPE_SINT16 - be,a sint16 - sll %o0, 16, %o0 ! (delay) +#ifndef __GNUC__ + .align 8 + .globl C(ffi_flush_icache) + .type C(ffi_flush_icache),@function + FFI_HIDDEN(C(ffi_flush_icache)) + +C(ffi_flush_icache): + cfi_startproc +1: iflush %o0 + iflush %o+8 + nop + nop + nop + nop + nop + retl + nop + cfi_endproc + .size C(ffi_flush_icache), . - C(ffi_flush_icache) +#endif - cmp %i3, FFI_TYPE_UINT16 - be,a uint16 - sll %o0, 16, %o0 ! (delay) +.macro E index + .align 16 + .org 2b + \index * 16 +.endm - cmp %i3, FFI_TYPE_SINT64 - be,a longlong - st %o0, [%i4+0] ! (delay) -done: + .align 8 + .globl C(ffi_call_v8) + .type C(ffi_call_v8),@function + FFI_HIDDEN(C(ffi_call_v8)) + +C(ffi_call_v8): + cfi_startproc + ! Allocate a stack frame sized by ffi_call. + save %sp, %o4, %sp + cfi_def_cfa_register(%fp) + cfi_window_save + + 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 + + add %sp, 32, %sp ! deallocate prep frame + and %o0, SPARC_FLAG_RET_MASK, %l0 ! save return type + srl %o0, SPARC_SIZEMASK_SHIFT, %l1 ! save return size + 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 + + ! Call foreign function + call %i1 + mov %i5, %g2 ! load static chain + +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 - -double: - st %f1, [%i4+4] + restore +E SPARC_RET_STRUCT + unimp +E SPARC_RET_UINT8 + and %o0, 0xff, %o0 + st %o0, [%i2] ret - restore - -sint8: - sra %o0, 24, %o0 - st %o0, [%i4+0] + 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_UINT32 +7: st %o0, [%i2] ret - restore - -uint8: - srl %o0, 24, %o0 - st %o0, [%i4+0] + restore +E SP_V8_RET_CPLX16 + sth %o0, [%i2+2] + b 9f + srl %o0, 16, %o0 +E SPARC_RET_INT64 + st %o0, [%i2] + st %o1, [%i2+4] ret - restore - -sint16: - sra %o0, 16, %o0 - st %o0, [%i4+0] + restore +E SPARC_RET_INT128 + std %o0, [%i2] + std %o2, [%i2+8] ret - restore + restore +E SPARC_RET_F_8 + st %f7, [%i2+7*4] + nop + st %f6, [%i2+6*4] + nop +E SPARC_RET_F_6 + st %f5, [%i2+5*4] + nop + st %f4, [%i2+4*4] + nop +E SPARC_RET_F_4 + st %f3, [%i2+3*4] + nop + st %f2, [%i2+2*4] + nop +E SPARC_RET_F_2 + st %f1, [%i2+4] + st %f0, [%i2] + ret + restore +E SP_V8_RET_CPLX8 + stb %o0, [%i2+1] + b 10f + srl %o0, 8, %o0 +E SPARC_RET_F_1 + st %f0, [%i2] + ret + restore -uint16: - srl %o0, 16, %o0 - st %o0, [%i4+0] + .align 8 +9: sth %o0, [%i2] + ret + restore + .align 8 +10: stb %o0, [%i2] ret - restore + restore -longlong: - st %o1, [%i4+4] + ! Struct returning functions expect and skip the unimp here. + ! To make it worse, conforming callees examine the unimp and + ! make sure the low 12 bits of the unimp match the size of + ! the struct being returned. + .align 8 +8: call 1f ! load pc in %o7 + sll %l1, 2, %l0 ! size * 4 +1: sll %l1, 4, %l1 ! size * 16 + add %l0, %l1, %l0 ! size * 20 + add %o7, %l0, %o7 ! o7 = 0b + size*20 + jmp %o7+(2f-8b) + mov %i5, %g2 ! load static chain +2: +.rept 0x1000 + call %i1 + nop + unimp (. - 2b) / 20 ret - restore -.LLFE1: + restore +.endr -.ffi_call_v8_end: - .size ffi_call_v8,.ffi_call_v8_end-ffi_call_v8 + cfi_endproc + .size C(ffi_call_v8),. - C(ffi_call_v8) -#undef STACKFRAME -#define STACKFRAME 104 /* 16*4 register window + - 1*4 struct return + - 6*4 args backing store + - 3*4 locals */ +/* 16*4 register window + 1*4 struct return + 6*4 args backing store + + 8*4 return storage + 1*4 alignment. */ +#define STACKFRAME (16*4 + 4 + 6*4 + 8*4 + 4) /* ffi_closure_v8(...) Receives the closure argument in %g2. */ - .text - .align 8 - .globl ffi_closure_v8 - -ffi_closure_v8: #ifdef HAVE_AS_REGISTER_PSEUDO_OP - .register %g2, #scratch + .register %g2, #scratch #endif -.LLFB2: - ! 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 -.LLCFI1: + .align 8 + .globl C(ffi_go_closure_v8) + .type C(ffi_go_closure_v8),@function + FFI_HIDDEN(C(ffi_go_closure_v8)) + +C(ffi_go_closure_v8): + cfi_startproc + save %sp, -STACKFRAME, %sp + cfi_def_cfa_register(%fp) + cfi_window_save + + ld [%g2+4], %o0 ! load cif + ld [%g2+8], %o1 ! load fun + b 0f + mov %g2, %o2 ! load user_data + cfi_endproc + .size C(ffi_go_closure_v8), . - C(ffi_go_closure_v8) + + .align 8 + .globl C(ffi_closure_v8) + .type C(ffi_closure_v8),@function + FFI_HIDDEN(C(ffi_closure_v8)) + +C(ffi_closure_v8): + cfi_startproc + save %sp, -STACKFRAME, %sp + cfi_def_cfa_register(%fp) + cfi_window_save + + ld [%g2+FFI_TRAMPOLINE_SIZE], %o0 ! load cif + ld [%g2+FFI_TRAMPOLINE_SIZE+4], %o1 ! load fun + ld [%g2+FFI_TRAMPOLINE_SIZE+8], %o2 ! load user_data +0: ! Store all of the potential argument registers in va_list format. st %i0, [%fp+68+0] st %i1, [%fp+68+4] @@ -180,137 +271,91 @@ ffi_closure_v8: 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, 64, %o2 + add %fp, -8*4, %o3 call ffi_closure_sparc_inner_v8 - add %fp, -16, %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 done1 - - cmp %o0, FFI_TYPE_INT - be done1 - ld [%fp-8], %i0 - - cmp %o0, FFI_TYPE_FLOAT - be,a done1 - ld [%fp-8], %f0 - - cmp %o0, FFI_TYPE_DOUBLE - be,a done1 - ldd [%fp-8], %f0 - -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - cmp %o0, FFI_TYPE_LONGDOUBLE - be done2 -#endif - - cmp %o0, FFI_TYPE_STRUCT - be done2 - - cmp %o0, FFI_TYPE_SINT64 - be,a done1 - ldd [%fp-8], %i0 - - ld [%fp-8], %i0 -done1: - jmp %i7+8 + add %fp, 64, %o4 + +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) + add %fp, -8*4, %i2 + + ! Note that each entry is 4 insns, enforced by the E macro. + .align 16 +2: +E SPARC_RET_VOID + ret restore -done2: - ! Skip 'unimp'. +E SPARC_RET_STRUCT + ld [%i2], %i0 jmp %i7+12 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 -#define uanword uaxword -#else -#define WS 4 -#define nword long -#define uanword uaword -#endif - -#ifdef HAVE_RO_EH_FRAME - .section ".eh_frame",#alloc -#else - .section ".eh_frame",#alloc,#write -#endif -.LLframe1: - .uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry -.LLSCIE1: - .uaword 0x0 ! CIE Identifier Tag - .byte 0x1 ! CIE Version - .ascii "zR\0" ! CIE Augmentation - .byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor - .byte 0x80-WS ! sleb128 -WS; CIE Data Alignment Factor - .byte 0xf ! CIE RA Column - .byte 0x1 ! uleb128 0x1; Augmentation size -#ifdef HAVE_AS_SPARC_UA_PCREL - .byte 0x1b ! FDE Encoding (pcrel sdata4) -#else - .byte 0x50 ! FDE Encoding (aligned absolute) -#endif - .byte 0xc ! DW_CFA_def_cfa - .byte 0xe ! uleb128 0xe - .byte 0x0 ! uleb128 0x0 - .align WS -.LLECIE1: -.LLSFDE1: - .uaword .LLEFDE1-.LLASFDE1 ! FDE Length -.LLASFDE1: - .uaword .LLASFDE1-.LLframe1 ! FDE CIE offset -#ifdef HAVE_AS_SPARC_UA_PCREL - .uaword %r_disp32(.LLFB1) - .uaword .LLFE1-.LLFB1 ! FDE address range -#else - .align WS - .nword .LLFB1 - .uanword .LLFE1-.LLFB1 ! FDE address range -#endif - .byte 0x0 ! uleb128 0x0; Augmentation size - .byte 0x4 ! DW_CFA_advance_loc4 - .uaword .LLCFI0-.LLFB1 - .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 -.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: -#endif +E SPARC_RET_UINT8 + ldub [%i2+3], %i0 + ret + restore +E SPARC_RET_SINT8 + ldsb [%i2+3], %i0 + ret + restore +E SPARC_RET_UINT16 + lduh [%i2+2], %i0 + ret + restore +E SPARC_RET_SINT16 + ldsh [%i2+2], %i0 + ret + restore +E SPARC_RET_UINT32 + ld [%i2], %i0 + ret + restore +E SP_V8_RET_CPLX16 + ld [%i2], %i0 + ret + restore +E SPARC_RET_INT64 + ldd [%i2], %i0 + ret + restore +E SPARC_RET_INT128 + ldd [%i2], %i0 + ldd [%i2+8], %i2 + ret + restore +E SPARC_RET_F_8 + ld [%i2+7*4], %f7 + nop + ld [%i2+6*4], %f6 + nop +E SPARC_RET_F_6 + ld [%i2+5*4], %f5 + nop + ld [%i2+4*4], %f4 + nop +E SPARC_RET_F_4 + ld [%i2+3*4], %f3 + nop + ld [%i2+2*4], %f2 + nop +E SPARC_RET_F_2 + ldd [%i2], %f0 + ret + restore +E SP_V8_RET_CPLX8 + lduh [%i2], %i0 + ret + restore +E SPARC_RET_F_1 + ld [%i2], %f0 + ret + restore + 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/libffi/src/sparc/v9.S b/libffi/src/sparc/v9.S index 2c97673..52732d3 100644 --- a/libffi/src/sparc/v9.S +++ b/libffi/src/sparc/v9.S @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- v9.S - Copyright (c) 2000, 2003, 2004, 2008 Red Hat, Inc. - + SPARC 64-bit Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining @@ -27,103 +27,178 @@ #define LIBFFI_ASM #include <fficonfig.h> #include <ffi.h> +#include <ffi_cfi.h> +#include "internal.h" #ifdef SPARC64 -#define STACKFRAME 176 /* Minimum stack framesize for SPARC 64-bit */ +#define C2(X, Y) X ## Y +#define C1(X, Y) C2(X, Y) + +#ifdef __USER_LABEL_PREFIX__ +# define C(Y) C1(__USER_LABEL_PREFIX__, Y) +#else +# define C(Y) Y +#endif +#define L(Y) C1(.L, Y) + +.macro E index + .align 16 + .org 2b + \index * 16 +.endm + #define STACK_BIAS 2047 -#define ARGS (128) /* Offset of register area in frame */ -.text + .text .align 8 -.globl ffi_call_v9 -.globl _ffi_call_v9 - -ffi_call_v9: -_ffi_call_v9: -.LLFB1: - save %sp, -STACKFRAME, %sp -.LLCFI0: + .globl C(ffi_call_v9) + .type C(ffi_call_v9),@function + FFI_HIDDEN(C(ffi_call_v9)) + +C(ffi_call_v9): + cfi_startproc + 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 %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 - - 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 - -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 - - ! If the return value pointer is NULL, assume no return value. - brz,pn %i4, done + 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 + + 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 [%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 [%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 + ldx [%sp+STACK_BIAS+128+40], %o5 + call %i1 + mov %i5, %g5 ! load static chain + +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, done - stx %o0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_FLOAT - be,a,pn %icc, done - st %f0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_DOUBLE - be,a,pn %icc, done - std %f0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_STRUCT - be,pn %icc, dostruct - - cmp %i3, FFI_TYPE_LONGDOUBLE - bne,pt %icc, done + .align 16 +2: +E SPARC_RET_VOID + return %i7+8 + nop +E SPARC_RET_STRUCT + add %sp, STACK_BIAS-64+128+48, %l2 + sub %sp, 64, %sp + b 8f + stx %o0, [%l2] +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_UINT32 + srl %o0, 0, %i0 + return %i7+8 + stx %o0, [%o2] +E SP_V9_RET_SINT32 + sra %o0, 0, %i0 + return %i7+8 + stx %o0, [%o2] +E SPARC_RET_INT64 + stx %o0, [%i2] + return %i7+8 + nop +E SPARC_RET_INT128 + stx %o0, [%i2] + stx %o1, [%i2+8] + return %i7+8 + nop +E SPARC_RET_F_8 + st %f7, [%i2+7*4] + nop + st %f6, [%i2+6*4] + nop +E SPARC_RET_F_6 + st %f5, [%i2+5*4] + nop + st %f4, [%i2+4*4] + nop +E SPARC_RET_F_4 + std %f2, [%i2+2*4] + return %i7+8 + std %f0, [%o2] +E SPARC_RET_F_2 + return %i7+8 + std %f0, [%o2] +E SP_V9_RET_F_3 + st %f2, [%i2+2*4] + nop + st %f1, [%i2+1*4] + nop +E SPARC_RET_F_1 + return %i7+8 + st %f0, [%o2] + + ! 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. + srl %l0, SPARC_SIZEMASK_SHIFT, %o0 ! load size_mask + mov %i2, %o1 ! load dst + mov %l2, %o2 ! load src_gp + call C(ffi_struct_float_copy) + add %l2, 32, %o3 ! load src_fp + + return %i7+8 nop - std %f0, [%i4+0] - std %f2, [%i4+8] - -done: ret - restore - -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 -.LLFE1: - -.ffi_call_v9_end: - .size ffi_call_v9,.ffi_call_v9_end-ffi_call_v9 + + cfi_endproc + .size C(ffi_call_v9), . - C(ffi_call_v9) #undef STACKFRAME @@ -136,15 +211,40 @@ dostruct: Receives the closure argument in %g1. */ - .text .align 8 - .globl ffi_closure_v9 + .globl C(ffi_go_closure_v9) + .type C(ffi_go_closure_v9),@function + FFI_HIDDEN(C(ffi_go_closure_v9)) -ffi_closure_v9: -.LLFB2: +C(ffi_go_closure_v9): + cfi_startproc save %sp, -STACKFRAME, %sp -.LLCFI1: + cfi_def_cfa_register(%fp) + cfi_window_save + ldx [%g5+8], %o0 + ldx [%g5+16], %o1 + b 0f + mov %g5, %o2 + + cfi_endproc + .size C(ffi_go_closure_v9), . - C(ffi_go_closure_v9) + + .align 8 + .globl C(ffi_closure_v9) + .type C(ffi_closure_v9),@function + FFI_HIDDEN(C(ffi_closure_v9)) + +C(ffi_closure_v9): + cfi_startproc + save %sp, -STACKFRAME, %sp + cfi_def_cfa_register(%fp) + cfi_window_save + + ldx [%g1+FFI_TRAMPOLINE_SIZE], %o0 + ldx [%g1+FFI_TRAMPOLINE_SIZE+8], %o1 + ldx [%g1+FFI_TRAMPOLINE_SIZE+16], %o2 +0: ! Store all of the potential argument registers in va_list format. stx %i0, [FP+128+0] stx %i1, [FP+128+8] @@ -172,134 +272,106 @@ ffi_closure_v9: std %f30, [FP-8] ! Call ffi_closure_sparc_inner to do the bulk of the work. - mov %g1, %o0 - add %fp, STACK_BIAS-160, %o1 - add %fp, STACK_BIAS+128, %o2 - call 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, done1 - - cmp %o0, FFI_TYPE_INT - be,pn %icc, integer - - cmp %o0, FFI_TYPE_FLOAT - be,a,pn %icc, done1 - ld [FP-160], %f0 - - cmp %o0, FFI_TYPE_DOUBLE - be,a,pn %icc, done1 - ldd [FP-160], %f0 - -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - cmp %o0, FFI_TYPE_LONGDOUBLE - be,a,pn %icc, longdouble1 - ldd [FP-160], %f0 -#endif + add %fp, STACK_BIAS-160, %o3 + add %fp, STACK_BIAS+128, %o4 + call C(ffi_closure_sparc_inner_v9) + add %fp, STACK_BIAS-128, %o5 + +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 - ! FFI_TYPE_STRUCT - ldx [FP-152], %i1 - ldx [FP-144], %i2 - ldx [FP-136], %i3 + ! 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 - ldd [FP-152], %f2 - ldd [FP-144], %f4 - ldd [FP-136], %f6 - -integer: + b 8f + ldx [FP-152], %i1 +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_UINT32 + lduw [FP-160+4], %i0 + return %i7+8 + nop +E SP_V9_RET_SINT32 + ldsw [FP-160+4], %i0 + return %i7+8 + nop +E SPARC_RET_INT64 ldx [FP-160], %i0 + return %i7+8 + nop +E SPARC_RET_INT128 + ldx [FP-160], %i0 + ldx [FP-160+8], %i1 + return %i7+8 + nop +E SPARC_RET_F_8 + ld [FP-160+7*4], %f7 + nop + ld [FP-160+6*4], %f6 + nop +E SPARC_RET_F_6 + ld [FP-160+5*4], %f5 + nop + ld [FP-160+4*4], %f4 + nop +E SPARC_RET_F_4 + ldd [FP-160], %f0 + ldd [FP-160+8], %f2 + return %i7+8 + nop +E SPARC_RET_F_2 + ldd [FP-160], %f0 + return %i7+8 + nop +E SP_V9_RET_F_3 + ld [FP-160+2*4], %f2 + nop + ld [FP-160+1*4], %f1 + nop +E SPARC_RET_F_1 + ld [FP-160], %f0 + return %i7+8 + nop -done1: - ret - restore - -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE -longdouble1: - ldd [FP-152], %f2 - ret - restore -#endif -.LLFE2: - -.ffi_closure_v9_end: - .size ffi_closure_v9,.ffi_closure_v9_end-ffi_closure_v9 - -#ifdef HAVE_RO_EH_FRAME - .section ".eh_frame",#alloc -#else - .section ".eh_frame",#alloc,#write -#endif -.LLframe1: - .uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry -.LLSCIE1: - .uaword 0x0 ! CIE Identifier Tag - .byte 0x1 ! CIE Version - .ascii "zR\0" ! CIE Augmentation - .byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor - .byte 0x78 ! sleb128 -8; CIE Data Alignment Factor - .byte 0xf ! CIE RA Column - .byte 0x1 ! uleb128 0x1; Augmentation size -#ifdef HAVE_AS_SPARC_UA_PCREL - .byte 0x1b ! FDE Encoding (pcrel sdata4) -#else - .byte 0x50 ! FDE Encoding (aligned absolute) -#endif - .byte 0xc ! DW_CFA_def_cfa - .byte 0xe ! uleb128 0xe - .byte 0xff,0xf ! uleb128 0x7ff - .align 8 -.LLECIE1: -.LLSFDE1: - .uaword .LLEFDE1-.LLASFDE1 ! FDE Length -.LLASFDE1: - .uaword .LLASFDE1-.LLframe1 ! FDE CIE offset -#ifdef HAVE_AS_SPARC_UA_PCREL - .uaword %r_disp32(.LLFB1) - .uaword .LLFE1-.LLFB1 ! FDE address range -#else - .align 8 - .xword .LLFB1 - .uaxword .LLFE1-.LLFB1 ! FDE address range -#endif - .byte 0x0 ! uleb128 0x0; Augmentation size - .byte 0x4 ! DW_CFA_advance_loc4 - .uaword .LLCFI0-.LLFB1 - .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 -.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 + ! 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 #endif |