diff options
author | green <green@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-04-17 02:15:32 +0000 |
---|---|---|
committer | green <green@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-04-17 02:15:32 +0000 |
commit | d7a35c6c8ed56febd7ecab5f2248fe633ccb5b48 (patch) | |
tree | 5eee77be9c61a0f60260a8f47e6085ac5e0738a5 /libffi/src | |
parent | 95b21bb9da597abff55397a5477b5b01211dc9ca (diff) | |
download | gcc-d7a35c6c8ed56febd7ecab5f2248fe633ccb5b48.tar.gz |
Port to sparc 32 and 64 Linux.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@33196 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libffi/src')
-rw-r--r-- | libffi/src/ffitest.c | 4 | ||||
-rw-r--r-- | libffi/src/prep_cif.c | 13 | ||||
-rw-r--r-- | libffi/src/sparc/ffi.c | 296 | ||||
-rw-r--r-- | libffi/src/sparc/v8.S | 10 | ||||
-rw-r--r-- | libffi/src/sparc/v9.S | 127 | ||||
-rw-r--r-- | libffi/src/types.c | 19 |
6 files changed, 418 insertions, 51 deletions
diff --git a/libffi/src/ffitest.c b/libffi/src/ffitest.c index 3dd0989783c..d4a687c6d53 100644 --- a/libffi/src/ffitest.c +++ b/libffi/src/ffitest.c @@ -224,7 +224,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) signed int si1; signed int si2; -#if defined(ALPHA) || defined(IA64) || (defined(MIPS) && (_MIPS_SIM == _ABIN32)) +#if defined(ALPHA) || defined(IA64) || defined(SPARC64) || (defined(MIPS) && (_MIPS_SIM == _ABIN32)) long long rint; #else int rint; @@ -295,7 +295,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) /* return value tests */ { -#if defined(MIPS) || defined(SPARC) /* || defined(ARM) */ +#if defined(MIPS) /* || defined(ARM) */ puts ("long long tests not run. This is a known bug on this architecture."); #else args[0] = &ffi_type_sint64; diff --git a/libffi/src/prep_cif.c b/libffi/src/prep_cif.c index 4c731b99455..3f21411a6cb 100644 --- a/libffi/src/prep_cif.c +++ b/libffi/src/prep_cif.c @@ -107,7 +107,11 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, #ifndef M68K /* Make space for the return structure pointer */ - if (cif->rtype->type == FFI_TYPE_STRUCT) + if (cif->rtype->type == FFI_TYPE_STRUCT +#ifdef SPARC + && (cif->abi != FFI_V9 || cif->rtype->size > 32) +#endif + ) bytes = STACK_ARG_SIZE(sizeof(void*)); #endif @@ -121,8 +125,10 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, return FFI_BAD_TYPEDEF; #ifdef SPARC - if ((*ptr)->type == FFI_TYPE_STRUCT - || (*ptr)->type == FFI_TYPE_LONGDOUBLE) + 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 @@ -140,4 +146,3 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, /* Perform machine dependent cif processing */ return ffi_prep_cif_machdep(cif); } - diff --git a/libffi/src/sparc/ffi.c b/libffi/src/sparc/ffi.c index 8ca6710c94a..647063686b9 100644 --- a/libffi/src/sparc/ffi.c +++ b/libffi/src/sparc/ffi.c @@ -33,7 +33,7 @@ /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments */ -void ffi_prep_args(char *stack, extended_cif *ecif) +void ffi_prep_args_v8(char *stack, extended_cif *ecif) { int i; int tmp; @@ -45,16 +45,16 @@ void ffi_prep_args(char *stack, extended_cif *ecif) tmp = 0; /* Skip 16 words for the window save area */ - argp = stack + 16*sizeof(void*); + 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 ) */ - *(void **) argp = ecif->rvalue; + *(int *) argp = (long)ecif->rvalue; /* And 1 word for the structure return value. */ - argp += sizeof(void*); + argp += sizeof(int); #ifdef USING_PURIFY /* Purify will probably complain in our assembly routine, unless we @@ -81,10 +81,13 @@ void ffi_prep_args(char *stack, extended_cif *ecif) { avn--; if ((*p_arg)->type == FFI_TYPE_STRUCT - || (*p_arg)->type == FFI_TYPE_LONGDOUBLE) +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || (*p_arg)->type == FFI_TYPE_LONGDOUBLE +#endif + ) { - *(unsigned int *) argp = (unsigned int)(* p_argv); - z = sizeof(void*); + *(unsigned int *) argp = (unsigned long)(* p_argv); + z = sizeof(int); } else { @@ -109,15 +112,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif) case FFI_TYPE_UINT16: *(unsigned int *) argp = *(UINT16 *)(* p_argv); break; - - case FFI_TYPE_SINT32: - *(signed int *) argp = *(SINT32 *)(* p_argv); - break; - - case FFI_TYPE_UINT32: - *(unsigned int *) argp = *(UINT32 *)(* p_argv); - break; - + default: FFI_ASSERT(0); } @@ -135,82 +130,295 @@ void ffi_prep_args(char *stack, extended_cif *ecif) return; } +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; +#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; + 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: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + 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_prep_cif_machdep(ffi_cif *cif) { - /* 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! */ + int wordsize; + + if (cif->abi != FFI_V9) + { + wordsize = 4; - if (cif->rtype->type != FFI_TYPE_STRUCT) - cif->bytes += sizeof(void*); + /* 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! */ - /* sparc call frames require that space is allocated for 6 args, - even if they aren't used. Make that space if necessary. */ + 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; + 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 += 64; + cif->bytes += 16 * wordsize; - /* The stack must be double word aligned, so round bytes up + /* The stack must be 2 word aligned, so round bytes up appropriately. */ - cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*)); + cif->bytes = ALIGN(cif->bytes, 2 * wordsize); /* Set the return type flag */ switch (cif->rtype->type) { case FFI_TYPE_VOID: - case FFI_TYPE_STRUCT: - cif->flags = cif->rtype->type; - break; - case FFI_TYPE_FLOAT: - cif->flags = 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; - case FFI_TYPE_DOUBLE: - cif->flags = FFI_TYPE_DOUBLE; + case FFI_TYPE_STRUCT: + if (cif->abi == FFI_V9 && cif->rtype->size > 32) + cif->flags = FFI_TYPE_VOID; + else + cif->flags = FFI_TYPE_STRUCT; break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + if (cif->abi != FFI_V9) + { + cif->flags = FFI_TYPE_SINT64; + break; + } + /* FALLTHROUGH */ default: cif->flags = FFI_TYPE_INT; break; } - return FFI_OK; } +int ffi_V9_return_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt) +{ + 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_return_struct(*ptr, off, ret, intg, flt); + break; + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + memcpy(ret + off, flt + off, (*ptr)->size); + off += (*ptr)->size; + break; + default: + memcpy(ret + off, intg + off, (*ptr)->size); + off += (*ptr)->size; + break; + } + ptr++; + } + return off; +} + extern int ffi_call_V8(void *, extended_cif *, unsigned, unsigned, unsigned *, void (*fn)()); +extern int ffi_call_V9(void *, extended_cif *, unsigned, + unsigned, unsigned *, void (*fn)()); void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) { extended_cif ecif; + void *rval = rvalue; 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 */ - - if ((rvalue == NULL) && - (cif->rtype->type == FFI_TYPE_STRUCT)) - ecif.rvalue = alloca(cif->rtype->size); - else - ecif.rvalue = rvalue; - + + 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: - ffi_call_V8(ffi_prep_args, &ecif, cif->bytes, +#ifdef SPARC64 + /* We don't yet support calling 32bit code from 64bit */ + FFI_ASSERT(0); +#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_return_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; } + } diff --git a/libffi/src/sparc/v8.S b/libffi/src/sparc/v8.S index da0dbe694b4..e4b2ba96a6c 100644 --- a/libffi/src/sparc/v8.S +++ b/libffi/src/sparc/v8.S @@ -56,6 +56,7 @@ _ffi_call_V8: 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 @@ -70,6 +71,9 @@ _ffi_call_V8: be,a done st %f0, [%i4+0] ! (delay) + cmp %i3, FFI_TYPE_SINT64 + be longlong + cmp %i3, FFI_TYPE_DOUBLE bne done nop @@ -80,6 +84,12 @@ done: ret restore +longlong: + st %o0, [%i4+0] + st %o1, [%i4+4] + ret + restore + .ffi_call_V8_end: .size ffi_call_V8,.ffi_call_V8_end-ffi_call_V8 diff --git a/libffi/src/sparc/v9.S b/libffi/src/sparc/v9.S new file mode 100644 index 00000000000..38494344dbb --- /dev/null +++ b/libffi/src/sparc/v9.S @@ -0,0 +1,127 @@ +/* ----------------------------------------------------------------------- + v9.S - Copyright (c) 2000 Cygnus Solutions + + Sparc 64bit Foreign Function Interface + + $Id:$ + + 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 CYGNUS SOLUTIONS 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. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <ffi.h> + +#ifdef SPARC64 +/* Only compile this in for 64bit builds, because otherwise the object file + will have inproper architecture due to used instructions. */ + +#define STACKFRAME 128 /* Minimum stack framesize for SPARC */ +#define STACK_BIAS 2047 +#define ARGS (128) /* Offset of register area in frame */ + +.text + .align 8 +.globl ffi_call_V9 +.globl _ffi_call_V9 + +ffi_call_V9: +_ffi_call_V9: + save %sp, -STACKFRAME, %sp + + 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 + nop + + cmp %i3, FFI_TYPE_INT + be,a,pt %icc, done + stx %o0, [%i4] ! (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 + 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 + +.ffi_call_V9_end: + .size ffi_call_V9,.ffi_call_V9_end-ffi_call_V9 + +#endif diff --git a/libffi/src/types.c b/libffi/src/types.c index abf276d5cdd..43aab913130 100644 --- a/libffi/src/types.c +++ b/libffi/src/types.c @@ -42,9 +42,17 @@ FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16); FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16); FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32); FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32); -FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER); FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); +#if defined ALPHA || defined SPARC64 + +FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); + +#else + +FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER); + +#endif #ifdef X86 @@ -87,8 +95,17 @@ FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); #elif defined SPARC FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); + +#ifdef SPARC64 + +FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); + +#else + FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE); +#endif + #else FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); |