diff options
Diffstat (limited to 'libffi/src/sparc/ffi.c')
-rw-r--r-- | libffi/src/sparc/ffi.c | 401 |
1 files changed, 218 insertions, 183 deletions
diff --git a/libffi/src/sparc/ffi.c b/libffi/src/sparc/ffi.c index a4ee84ec514..77e38220657 100644 --- a/libffi/src/sparc/ffi.c +++ b/libffi/src/sparc/ffi.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 2011 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 @@ -34,93 +34,10 @@ /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments */ -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); - -#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 -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - || (*p_arg)->type == FFI_TYPE_LONGDOUBLE -#endif - ) - { - *(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; -} +#ifdef SPARC64 -int ffi_prep_args_v9(char *stack, extended_cif *ecif) +int +ffi_prep_args_v9(char *stack, extended_cif *ecif) { int i, ret = 0; int tmp; @@ -248,12 +165,105 @@ int ffi_prep_args_v9(char *stack, extended_cif *ecif) 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); + +#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 +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || (*p_arg)->type == FFI_TYPE_LONGDOUBLE +#endif + ) + { + *(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; +} + +#endif + /* Perform machine dependent cif processing */ -static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif) + +static +ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif) { int wordsize; - if (cif->abi != FFI_V9) + if (!V9_ABI_P (cif->abi)) { wordsize = 4; @@ -303,7 +313,7 @@ static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif) break; case FFI_TYPE_STRUCT: - if (cif->abi == FFI_V9 && cif->rtype->size > 32) + if (V9_ABI_P (cif->abi) && cif->rtype->size > 32) cif->flags = FFI_TYPE_VOID; else cif->flags = FFI_TYPE_STRUCT; @@ -313,7 +323,7 @@ static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif) case FFI_TYPE_UINT8: case FFI_TYPE_SINT16: case FFI_TYPE_UINT16: - if (cif->abi == FFI_V9) + if (V9_ABI_P (cif->abi)) cif->flags = FFI_TYPE_INT; else cif->flags = cif->rtype->type; @@ -321,7 +331,7 @@ static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif) case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: - if (cif->abi == FFI_V9) + if (V9_ABI_P (cif->abi)) cif->flags = FFI_TYPE_INT; else cif->flags = FFI_TYPE_SINT64; @@ -334,20 +344,31 @@ static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif) return FFI_OK; } -ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +ffi_status +ffi_prep_cif_machdep(ffi_cif *cif) { - cif->nfixedargs = cif->nargs; +#ifdef SPARC64 + if (cif->abi != FFI_COMPAT_V9) + cif->nfixedargs = cif->nargs; +#endif return ffi_prep_cif_machdep_core (cif); } -ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, - unsigned int ntotalargs) +ffi_status +ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, + unsigned int ntotalargs) { - cif->nfixedargs = nfixedargs; +#ifdef SPARC64 + if (cif->abi != FFI_COMPAT_V9) + cif->nfixedargs = nfixedargs; +#endif return ffi_prep_cif_machdep_core (cif); } -int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt) +#ifdef SPARC64 + +int +ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt) { ffi_type **ptr = &arg->elements[0]; @@ -380,6 +401,7 @@ int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *fl return off; } +#endif #ifdef SPARC64 extern int ffi_call_v9(void *, extended_cif *, unsigned, @@ -389,33 +411,37 @@ 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) +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; - - /* If the return value is a struct and we don't have a return */ - /* value address then we need to make one */ - 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; - if (rvalue == NULL) - ecif.rvalue = alloca(cif->rtype->size); - } + 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); @@ -430,7 +456,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) /* 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, &call_struct); + ffi_closure_alloc(32, (void **)&call_struct); if (call_struct) { unsigned long f = (unsigned long)fn; @@ -450,7 +476,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) /* 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, call_struct); + cif->flags, rvalue, (void (*)(void)) call_struct); ffi_closure_free(call_struct); } else @@ -466,12 +492,13 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) } #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); + 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); + ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, + ((char *)rval)+32); #else /* And vice versa */ FFI_ASSERT(0); @@ -502,7 +529,7 @@ ffi_prep_closure_loc (ffi_closure* closure, #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) + if (!V9_ABI_P (cif->abi)) return FFI_BAD_ABI; fn = (unsigned long) ffi_closure_v9; tramp[0] = 0x83414000; /* rd %pc, %g1 */ @@ -512,7 +539,7 @@ ffi_prep_closure_loc (ffi_closure* closure, *((unsigned long *) &tramp[4]) = fn; #else unsigned long ctx = (unsigned long) codeloc; - if (cif->abi != FFI_V8) + if (!V8_ABI_P (cif->abi)) return FFI_BAD_ABI; fn = (unsigned long) ffi_closure_v8; tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */ @@ -537,74 +564,11 @@ ffi_prep_closure_loc (ffi_closure* closure, return FFI_OK; } -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 *)); - - /* 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]; - - /* Always skip the structure return address. */ - argn = 1; - - /* 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; - } - } - - /* 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; -} +#ifdef SPARC64 int -ffi_closure_sparc_inner_v9(ffi_closure *closure, - void *rvalue, unsigned long *gpr, double *fpr) +ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue, + unsigned long *gpr, double *fpr) { ffi_cif *cif; ffi_type **arg_types; @@ -633,7 +597,8 @@ ffi_closure_sparc_inner_v9(ffi_closure *closure, { /* If the function is variadic, FP arguments are passed in FP registers only if the corresponding parameter is named. */ - const int named = (i < cif->nfixedargs); + const int named + = (cif->abi == FFI_COMPAT_V9 ? 1 : i < cif->nfixedargs); if (arg_types[i]->type == FFI_TYPE_STRUCT) { @@ -653,7 +618,8 @@ ffi_closure_sparc_inner_v9(ffi_closure *closure, ? (char *) &fpr[argn] : (char *) &gpr[argn]); avalue[i] = &gpr[argn]; - argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + argn + += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; } } else @@ -686,3 +652,72 @@ ffi_closure_sparc_inner_v9(ffi_closure *closure, /* 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 *)); + + /* 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]; + + /* Always skip the structure return address. */ + argn = 1; + + /* 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; + } + } + + /* 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; +} + +#endif |