summaryrefslogtreecommitdiff
path: root/libffi/src/sparc/ffi.c
diff options
context:
space:
mode:
Diffstat (limited to 'libffi/src/sparc/ffi.c')
-rw-r--r--libffi/src/sparc/ffi.c401
1 files changed, 218 insertions, 183 deletions
diff --git a/libffi/src/sparc/ffi.c b/libffi/src/sparc/ffi.c
index a4ee84ec514..77e38220657 100644
--- a/libffi/src/sparc/ffi.c
+++ b/libffi/src/sparc/ffi.c
@@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2011 Anthony Green
Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc.
-
+
SPARC Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
@@ -34,93 +34,10 @@
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
-void ffi_prep_args_v8(char *stack, extended_cif *ecif)
-{
- int i;
- void **p_argv;
- char *argp;
- ffi_type **p_arg;
-
- /* Skip 16 words for the window save area */
- argp = stack + 16*sizeof(int);
-
- /* This should only really be done when we are returning a structure,
- however, it's faster just to do it all the time...
-
- if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
- *(int *) argp = (long)ecif->rvalue;
-
- /* And 1 word for the structure return value. */
- argp += sizeof(int);
-
-#ifdef USING_PURIFY
- /* Purify will probably complain in our assembly routine, unless we
- zero out this memory. */
-
- ((int*)argp)[0] = 0;
- ((int*)argp)[1] = 0;
- ((int*)argp)[2] = 0;
- ((int*)argp)[3] = 0;
- ((int*)argp)[4] = 0;
- ((int*)argp)[5] = 0;
-#endif
-
- p_argv = ecif->avalue;
-
- for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
- {
- size_t z;
-
- if ((*p_arg)->type == FFI_TYPE_STRUCT
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
-#endif
- )
- {
- *(unsigned int *) argp = (unsigned long)(* p_argv);
- z = sizeof(int);
- }
- else
- {
- z = (*p_arg)->size;
- if (z < sizeof(int))
- {
- z = sizeof(int);
- switch ((*p_arg)->type)
- {
- case FFI_TYPE_SINT8:
- *(signed int *) argp = *(SINT8 *)(* p_argv);
- break;
-
- case FFI_TYPE_UINT8:
- *(unsigned int *) argp = *(UINT8 *)(* p_argv);
- break;
-
- case FFI_TYPE_SINT16:
- *(signed int *) argp = *(SINT16 *)(* p_argv);
- break;
-
- case FFI_TYPE_UINT16:
- *(unsigned int *) argp = *(UINT16 *)(* p_argv);
- break;
-
- default:
- FFI_ASSERT(0);
- }
- }
- else
- {
- memcpy(argp, *p_argv, z);
- }
- }
- p_argv++;
- argp += z;
- }
-
- return;
-}
+#ifdef SPARC64
-int ffi_prep_args_v9(char *stack, extended_cif *ecif)
+int
+ffi_prep_args_v9(char *stack, extended_cif *ecif)
{
int i, ret = 0;
int tmp;
@@ -248,12 +165,105 @@ int ffi_prep_args_v9(char *stack, extended_cif *ecif)
return ret;
}
+#else
+
+void
+ffi_prep_args_v8(char *stack, extended_cif *ecif)
+{
+ int i;
+ void **p_argv;
+ char *argp;
+ ffi_type **p_arg;
+
+ /* Skip 16 words for the window save area */
+ argp = stack + 16*sizeof(int);
+
+ /* This should only really be done when we are returning a structure,
+ however, it's faster just to do it all the time...
+
+ if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
+ *(int *) argp = (long)ecif->rvalue;
+
+ /* And 1 word for the structure return value. */
+ argp += sizeof(int);
+
+#ifdef USING_PURIFY
+ /* Purify will probably complain in our assembly routine, unless we
+ zero out this memory. */
+
+ ((int*)argp)[0] = 0;
+ ((int*)argp)[1] = 0;
+ ((int*)argp)[2] = 0;
+ ((int*)argp)[3] = 0;
+ ((int*)argp)[4] = 0;
+ ((int*)argp)[5] = 0;
+#endif
+
+ p_argv = ecif->avalue;
+
+ for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
+ {
+ size_t z;
+
+ if ((*p_arg)->type == FFI_TYPE_STRUCT
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
+#endif
+ )
+ {
+ *(unsigned int *) argp = (unsigned long)(* p_argv);
+ z = sizeof(int);
+ }
+ else
+ {
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(signed int *) argp = *(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned int *) argp = *(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed int *) argp = *(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned int *) argp = *(UINT16 *)(* p_argv);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ }
+ else
+ {
+ memcpy(argp, *p_argv, z);
+ }
+ }
+ p_argv++;
+ argp += z;
+ }
+
+ return;
+}
+
+#endif
+
/* Perform machine dependent cif processing */
-static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
+
+static
+ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
{
int wordsize;
- if (cif->abi != FFI_V9)
+ if (!V9_ABI_P (cif->abi))
{
wordsize = 4;
@@ -303,7 +313,7 @@ static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
break;
case FFI_TYPE_STRUCT:
- if (cif->abi == FFI_V9 && cif->rtype->size > 32)
+ if (V9_ABI_P (cif->abi) && cif->rtype->size > 32)
cif->flags = FFI_TYPE_VOID;
else
cif->flags = FFI_TYPE_STRUCT;
@@ -313,7 +323,7 @@ static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
- if (cif->abi == FFI_V9)
+ if (V9_ABI_P (cif->abi))
cif->flags = FFI_TYPE_INT;
else
cif->flags = cif->rtype->type;
@@ -321,7 +331,7 @@ static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
- if (cif->abi == FFI_V9)
+ if (V9_ABI_P (cif->abi))
cif->flags = FFI_TYPE_INT;
else
cif->flags = FFI_TYPE_SINT64;
@@ -334,20 +344,31 @@ static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
return FFI_OK;
}
-ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+ffi_status
+ffi_prep_cif_machdep(ffi_cif *cif)
{
- cif->nfixedargs = cif->nargs;
+#ifdef SPARC64
+ if (cif->abi != FFI_COMPAT_V9)
+ cif->nfixedargs = cif->nargs;
+#endif
return ffi_prep_cif_machdep_core (cif);
}
-ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs,
- unsigned int ntotalargs)
+ffi_status
+ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs,
+ unsigned int ntotalargs)
{
- cif->nfixedargs = nfixedargs;
+#ifdef SPARC64
+ if (cif->abi != FFI_COMPAT_V9)
+ cif->nfixedargs = nfixedargs;
+#endif
return ffi_prep_cif_machdep_core (cif);
}
-int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
+#ifdef SPARC64
+
+int
+ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
{
ffi_type **ptr = &arg->elements[0];
@@ -380,6 +401,7 @@ int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *fl
return off;
}
+#endif
#ifdef SPARC64
extern int ffi_call_v9(void *, extended_cif *, unsigned,
@@ -389,33 +411,37 @@ extern int ffi_call_v8(void *, extended_cif *, unsigned,
unsigned, unsigned *, void (*fn)(void));
#endif
-void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+void
+ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
extended_cif ecif;
+#ifdef SPARC64
void *rval = rvalue;
+#endif
ecif.cif = cif;
ecif.avalue = avalue;
-
- /* If the return value is a struct and we don't have a return */
- /* value address then we need to make one */
-
ecif.rvalue = rvalue;
+
+ /* If the return value is a struct and we don't have a return value address,
+ then we need to make one. */
if (cif->rtype->type == FFI_TYPE_STRUCT)
{
+ if (ecif.rvalue == NULL)
+ ecif.rvalue = alloca(cif->rtype->size);
+
+#ifdef SPARC64
if (cif->rtype->size <= 32)
rval = alloca(64);
else
- {
- rval = NULL;
- if (rvalue == NULL)
- ecif.rvalue = alloca(cif->rtype->size);
- }
+ rval = NULL;
+#endif
}
switch (cif->abi)
{
case FFI_V8:
+ case FFI_V8PLUS:
#ifdef SPARC64
/* We don't yet support calling 32bit code from 64bit */
FFI_ASSERT(0);
@@ -430,7 +456,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
/* behind "call", so we alloc some executable space for it. */
/* l7 is used, we need to make sure v8.S doesn't use %l7. */
unsigned int *call_struct = NULL;
- ffi_closure_alloc(32, &call_struct);
+ ffi_closure_alloc(32, (void **)&call_struct);
if (call_struct)
{
unsigned long f = (unsigned long)fn;
@@ -450,7 +476,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
/* SPARC v8 requires 5 instructions for flush to be visible */
asm volatile ("nop; nop; nop; nop; nop");
ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
- cif->flags, rvalue, call_struct);
+ cif->flags, rvalue, (void (*)(void)) call_struct);
ffi_closure_free(call_struct);
}
else
@@ -466,12 +492,13 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}
#endif
break;
+ case FFI_COMPAT_V9:
case FFI_V9:
#ifdef SPARC64
- ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes,
- cif->flags, rval, fn);
+ ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes, cif->flags, rval, fn);
if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
- ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
+ ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval,
+ ((char *)rval)+32);
#else
/* And vice versa */
FFI_ASSERT(0);
@@ -502,7 +529,7 @@ ffi_prep_closure_loc (ffi_closure* closure,
#ifdef SPARC64
/* Trampoline address is equal to the closure address. We take advantage
of that to reduce the trampoline size by 8 bytes. */
- if (cif->abi != FFI_V9)
+ if (!V9_ABI_P (cif->abi))
return FFI_BAD_ABI;
fn = (unsigned long) ffi_closure_v9;
tramp[0] = 0x83414000; /* rd %pc, %g1 */
@@ -512,7 +539,7 @@ ffi_prep_closure_loc (ffi_closure* closure,
*((unsigned long *) &tramp[4]) = fn;
#else
unsigned long ctx = (unsigned long) codeloc;
- if (cif->abi != FFI_V8)
+ if (!V8_ABI_P (cif->abi))
return FFI_BAD_ABI;
fn = (unsigned long) ffi_closure_v8;
tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */
@@ -537,74 +564,11 @@ ffi_prep_closure_loc (ffi_closure* closure,
return FFI_OK;
}
-int
-ffi_closure_sparc_inner_v8(ffi_closure *closure,
- void *rvalue, unsigned long *gpr, unsigned long *scratch)
-{
- ffi_cif *cif;
- ffi_type **arg_types;
- void **avalue;
- int i, argn;
-
- cif = closure->cif;
- arg_types = cif->arg_types;
- avalue = alloca(cif->nargs * sizeof(void *));
-
- /* Copy the caller's structure return address so that the closure
- returns the data directly to the caller. */
- if (cif->flags == FFI_TYPE_STRUCT
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- || cif->flags == FFI_TYPE_LONGDOUBLE
-#endif
- )
- rvalue = (void *) gpr[0];
-
- /* Always skip the structure return address. */
- argn = 1;
-
- /* Grab the addresses of the arguments from the stack frame. */
- for (i = 0; i < cif->nargs; i++)
- {
- if (arg_types[i]->type == FFI_TYPE_STRUCT
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
-#endif
- )
- {
- /* Straight copy of invisible reference. */
- avalue[i] = (void *)gpr[argn++];
- }
- else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
- || arg_types[i]->type == FFI_TYPE_SINT64
- || arg_types[i]->type == FFI_TYPE_UINT64)
- /* gpr is 8-byte aligned. */
- && (argn % 2) != 0)
- {
- /* Align on a 8-byte boundary. */
- scratch[0] = gpr[argn];
- scratch[1] = gpr[argn+1];
- avalue[i] = scratch;
- scratch -= 2;
- argn += 2;
- }
- else
- {
- /* Always right-justify. */
- argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
- avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
- }
- }
-
- /* Invoke the closure. */
- (closure->fun) (cif, rvalue, avalue, closure->user_data);
-
- /* Tell ffi_closure_sparc how to perform return type promotions. */
- return cif->rtype->type;
-}
+#ifdef SPARC64
int
-ffi_closure_sparc_inner_v9(ffi_closure *closure,
- void *rvalue, unsigned long *gpr, double *fpr)
+ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue,
+ unsigned long *gpr, double *fpr)
{
ffi_cif *cif;
ffi_type **arg_types;
@@ -633,7 +597,8 @@ ffi_closure_sparc_inner_v9(ffi_closure *closure,
{
/* If the function is variadic, FP arguments are passed in FP
registers only if the corresponding parameter is named. */
- const int named = (i < cif->nfixedargs);
+ const int named
+ = (cif->abi == FFI_COMPAT_V9 ? 1 : i < cif->nfixedargs);
if (arg_types[i]->type == FFI_TYPE_STRUCT)
{
@@ -653,7 +618,8 @@ ffi_closure_sparc_inner_v9(ffi_closure *closure,
? (char *) &fpr[argn]
: (char *) &gpr[argn]);
avalue[i] = &gpr[argn];
- argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ argn
+ += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
}
}
else
@@ -686,3 +652,72 @@ ffi_closure_sparc_inner_v9(ffi_closure *closure,
/* Tell ffi_closure_sparc how to perform return type promotions. */
return cif->rtype->type;
}
+
+#else
+
+int
+ffi_closure_sparc_inner_v8(ffi_closure *closure, void *rvalue,
+ unsigned long *gpr, unsigned long *scratch)
+{
+ ffi_cif *cif;
+ ffi_type **arg_types;
+ void **avalue;
+ int i, argn;
+
+ cif = closure->cif;
+ arg_types = cif->arg_types;
+ avalue = alloca(cif->nargs * sizeof(void *));
+
+ /* Copy the caller's structure return address so that the closure
+ returns the data directly to the caller. */
+ if (cif->flags == FFI_TYPE_STRUCT
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ || cif->flags == FFI_TYPE_LONGDOUBLE
+#endif
+ )
+ rvalue = (void *) gpr[0];
+
+ /* Always skip the structure return address. */
+ argn = 1;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ for (i = 0; i < cif->nargs; i++)
+ {
+ if (arg_types[i]->type == FFI_TYPE_STRUCT
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
+#endif
+ )
+ {
+ /* Straight copy of invisible reference. */
+ avalue[i] = (void *)gpr[argn++];
+ }
+ else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
+ || arg_types[i]->type == FFI_TYPE_SINT64
+ || arg_types[i]->type == FFI_TYPE_UINT64)
+ /* gpr is 8-byte aligned. */
+ && (argn % 2) != 0)
+ {
+ /* Align on a 8-byte boundary. */
+ scratch[0] = gpr[argn];
+ scratch[1] = gpr[argn+1];
+ avalue[i] = scratch;
+ scratch -= 2;
+ argn += 2;
+ }
+ else
+ {
+ /* Always right-justify. */
+ argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
+ }
+ }
+
+ /* Invoke the closure. */
+ closure->fun (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_sparc how to perform return type promotions. */
+ return cif->rtype->type;
+}
+
+#endif