summaryrefslogtreecommitdiff
path: root/libffi/src
diff options
context:
space:
mode:
authorgreen <green@138bc75d-0d04-0410-961f-82ee72b054a4>2000-04-17 02:15:32 +0000
committergreen <green@138bc75d-0d04-0410-961f-82ee72b054a4>2000-04-17 02:15:32 +0000
commitd7a35c6c8ed56febd7ecab5f2248fe633ccb5b48 (patch)
tree5eee77be9c61a0f60260a8f47e6085ac5e0738a5 /libffi/src
parent95b21bb9da597abff55397a5477b5b01211dc9ca (diff)
downloadgcc-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.c4
-rw-r--r--libffi/src/prep_cif.c13
-rw-r--r--libffi/src/sparc/ffi.c296
-rw-r--r--libffi/src/sparc/v8.S10
-rw-r--r--libffi/src/sparc/v9.S127
-rw-r--r--libffi/src/types.c19
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);