aboutsummaryrefslogtreecommitdiff
path: root/libffi/src/sparc
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2015-01-12 08:19:59 -0800
committerRichard Henderson <rth@gcc.gnu.org>2015-01-12 08:19:59 -0800
commitb1760f7f915a36ee9b4636fb54719c9b3ae59356 (patch)
tree1a64d747b069bdebf651d856989dd40a54daf0cc /libffi/src/sparc
parent62e22fcb7985349b93646b86351033e1fb09c46c (diff)
downloadgcc-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.c913
-rw-r--r--libffi/src/sparc/ffi64.c608
-rw-r--r--libffi/src/sparc/ffitarget.h32
-rw-r--r--libffi/src/sparc/internal.h26
-rw-r--r--libffi/src/sparc/v8.S535
-rw-r--r--libffi/src/sparc/v9.S504
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