mirror of git://gcc.gnu.org/git/gcc.git
parent
f17aa4adf8
commit
46e0720d66
|
@ -1,3 +1,41 @@
|
||||||
|
2010-10-28 Chung-Lin Tang <cltang@codesourcery.com>
|
||||||
|
|
||||||
|
* src/arm/ffi.c (ffi_prep_args): Add VFP register argument handling
|
||||||
|
code, new parameter, and return value. Update comments.
|
||||||
|
(ffi_prep_cif_machdep): Add case for VFP struct return values. Add
|
||||||
|
call to layout_vfp_args().
|
||||||
|
(ffi_call_SYSV): Update declaration.
|
||||||
|
(ffi_call_VFP): New declaration.
|
||||||
|
(ffi_call): Add VFP struct return conditions. Call ffi_call_VFP()
|
||||||
|
when ABI is FFI_VFP.
|
||||||
|
(ffi_closure_VFP): New declaration.
|
||||||
|
(ffi_closure_SYSV_inner): Add new vfp_args parameter, update call to
|
||||||
|
ffi_prep_incoming_args_SYSV().
|
||||||
|
(ffi_prep_incoming_args_SYSV): Update parameters. Add VFP argument
|
||||||
|
case handling.
|
||||||
|
(ffi_prep_closure_loc): Pass ffi_closure_VFP to trampoline
|
||||||
|
construction under VFP hard-float.
|
||||||
|
(rec_vfp_type_p): New function.
|
||||||
|
(vfp_type_p): Same.
|
||||||
|
(place_vfp_arg): Same.
|
||||||
|
(layout_vfp_args): Same.
|
||||||
|
* src/arm/ffitarget.h (ffi_abi): Add FFI_VFP. Define FFI_DEFAULT_ABI
|
||||||
|
based on __ARM_PCS_VFP.
|
||||||
|
(FFI_EXTRA_CIF_FIELDS): Define for adding VFP hard-float specific
|
||||||
|
fields.
|
||||||
|
(FFI_TYPE_STRUCT_VFP_FLOAT): Define internally used type code.
|
||||||
|
(FFI_TYPE_STRUCT_VFP_DOUBLE): Same.
|
||||||
|
* src/arm/sysv.S (ffi_call_SYSV): Change call of ffi_prep_args() to
|
||||||
|
direct call. Move function pointer load upwards.
|
||||||
|
(ffi_call_VFP): New function.
|
||||||
|
(ffi_closure_VFP): Same.
|
||||||
|
|
||||||
|
* testsuite/lib/libffi-dg.exp (check-flags): New function.
|
||||||
|
(dg-skip-if): New function.
|
||||||
|
* testsuite/libffi.call/cls_double_va.c: Skip if target is arm*-*-*
|
||||||
|
and compiler options include -mfloat-abi=hard.
|
||||||
|
* testsuite/libffi.call/cls_longdouble_va.c: Same.
|
||||||
|
|
||||||
2010-10-01 Jakub Jelinek <jakub@redhat.com>
|
2010-10-01 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
PR libffi/45677
|
PR libffi/45677
|
||||||
|
|
|
@ -29,12 +29,20 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
/* ffi_prep_args is called by the assembly routine once stack space
|
/* Forward declares. */
|
||||||
has been allocated for the function's arguments */
|
static int vfp_type_p (ffi_type *);
|
||||||
|
static void layout_vfp_args (ffi_cif *);
|
||||||
|
|
||||||
void ffi_prep_args(char *stack, extended_cif *ecif)
|
/* ffi_prep_args is called by the assembly routine once stack space
|
||||||
|
has been allocated for the function's arguments
|
||||||
|
|
||||||
|
The vfp_space parameter is the load area for VFP regs, the return
|
||||||
|
value is cif->vfp_used (word bitset of VFP regs used for passing
|
||||||
|
arguments). These are only used for the VFP hard-float ABI.
|
||||||
|
*/
|
||||||
|
int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space)
|
||||||
{
|
{
|
||||||
register unsigned int i;
|
register unsigned int i, vi = 0;
|
||||||
register void **p_argv;
|
register void **p_argv;
|
||||||
register char *argp;
|
register char *argp;
|
||||||
register ffi_type **p_arg;
|
register ffi_type **p_arg;
|
||||||
|
@ -54,6 +62,21 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
|
||||||
{
|
{
|
||||||
size_t z;
|
size_t z;
|
||||||
|
|
||||||
|
/* Allocated in VFP registers. */
|
||||||
|
if (ecif->cif->abi == FFI_VFP
|
||||||
|
&& vi < ecif->cif->vfp_nargs && vfp_type_p (*p_arg))
|
||||||
|
{
|
||||||
|
float* vfp_slot = vfp_space + ecif->cif->vfp_args[vi++];
|
||||||
|
if ((*p_arg)->type == FFI_TYPE_FLOAT)
|
||||||
|
*((float*)vfp_slot) = *((float*)*p_argv);
|
||||||
|
else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
|
||||||
|
*((double*)vfp_slot) = *((double*)*p_argv);
|
||||||
|
else
|
||||||
|
memcpy(vfp_slot, *p_argv, (*p_arg)->size);
|
||||||
|
p_argv++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Align if necessary */
|
/* Align if necessary */
|
||||||
if (((*p_arg)->alignment - 1) & (unsigned) argp) {
|
if (((*p_arg)->alignment - 1) & (unsigned) argp) {
|
||||||
argp = (char *) ALIGN(argp, (*p_arg)->alignment);
|
argp = (char *) ALIGN(argp, (*p_arg)->alignment);
|
||||||
|
@ -103,13 +126,15 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
|
||||||
p_argv++;
|
p_argv++;
|
||||||
argp += z;
|
argp += z;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
/* Indicate the VFP registers used. */
|
||||||
|
return ecif->cif->vfp_used;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform machine dependent cif processing */
|
/* Perform machine dependent cif processing */
|
||||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||||
{
|
{
|
||||||
|
int type_code;
|
||||||
/* Round the stack up to a multiple of 8 bytes. This isn't needed
|
/* Round the stack up to a multiple of 8 bytes. This isn't needed
|
||||||
everywhere, but it is on some platforms, and it doesn't harm anything
|
everywhere, but it is on some platforms, and it doesn't harm anything
|
||||||
when it isn't needed. */
|
when it isn't needed. */
|
||||||
|
@ -130,7 +155,14 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
case FFI_TYPE_STRUCT:
|
||||||
if (cif->rtype->size <= 4)
|
if (cif->abi == FFI_VFP
|
||||||
|
&& (type_code = vfp_type_p (cif->rtype)) != 0)
|
||||||
|
{
|
||||||
|
/* A Composite Type passed in VFP registers, either
|
||||||
|
FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */
|
||||||
|
cif->flags = (unsigned) type_code;
|
||||||
|
}
|
||||||
|
else if (cif->rtype->size <= 4)
|
||||||
/* A Composite Type not larger than 4 bytes is returned in r0. */
|
/* A Composite Type not larger than 4 bytes is returned in r0. */
|
||||||
cif->flags = (unsigned)FFI_TYPE_INT;
|
cif->flags = (unsigned)FFI_TYPE_INT;
|
||||||
else
|
else
|
||||||
|
@ -145,11 +177,18 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Map out the register placements of VFP register args.
|
||||||
|
The VFP hard-float calling conventions are slightly more sophisticated than
|
||||||
|
the base calling conventions, so we do it here instead of in ffi_prep_args(). */
|
||||||
|
if (cif->abi == FFI_VFP)
|
||||||
|
layout_vfp_args (cif);
|
||||||
|
|
||||||
return FFI_OK;
|
return FFI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
|
/* Prototypes for assembly functions, in sysv.S */
|
||||||
unsigned, unsigned, unsigned *, void (*fn)(void));
|
extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
|
||||||
|
extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -157,6 +196,8 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||||
|
|
||||||
int small_struct = (cif->flags == FFI_TYPE_INT
|
int small_struct = (cif->flags == FFI_TYPE_INT
|
||||||
&& cif->rtype->type == FFI_TYPE_STRUCT);
|
&& cif->rtype->type == FFI_TYPE_STRUCT);
|
||||||
|
int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT
|
||||||
|
|| cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE);
|
||||||
|
|
||||||
ecif.cif = cif;
|
ecif.cif = cif;
|
||||||
ecif.avalue = avalue;
|
ecif.avalue = avalue;
|
||||||
|
@ -173,38 +214,51 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||||
}
|
}
|
||||||
else if (small_struct)
|
else if (small_struct)
|
||||||
ecif.rvalue = &temp;
|
ecif.rvalue = &temp;
|
||||||
|
else if (vfp_struct)
|
||||||
|
{
|
||||||
|
/* Largest case is double x 4. */
|
||||||
|
ecif.rvalue = alloca(32);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
ecif.rvalue = rvalue;
|
ecif.rvalue = rvalue;
|
||||||
|
|
||||||
switch (cif->abi)
|
switch (cif->abi)
|
||||||
{
|
{
|
||||||
case FFI_SYSV:
|
case FFI_SYSV:
|
||||||
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
|
ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
|
||||||
fn);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FFI_VFP:
|
||||||
|
ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
FFI_ASSERT(0);
|
FFI_ASSERT(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (small_struct)
|
if (small_struct)
|
||||||
memcpy (rvalue, &temp, cif->rtype->size);
|
memcpy (rvalue, &temp, cif->rtype->size);
|
||||||
|
else if (vfp_struct)
|
||||||
|
memcpy (rvalue, ecif.rvalue, cif->rtype->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** private members **/
|
/** private members **/
|
||||||
|
|
||||||
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
|
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
|
||||||
void** args, ffi_cif* cif);
|
void** args, ffi_cif* cif, float *vfp_stack);
|
||||||
|
|
||||||
void ffi_closure_SYSV (ffi_closure *);
|
void ffi_closure_SYSV (ffi_closure *);
|
||||||
|
|
||||||
|
void ffi_closure_VFP (ffi_closure *);
|
||||||
|
|
||||||
/* This function is jumped to by the trampoline */
|
/* This function is jumped to by the trampoline */
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
ffi_closure_SYSV_inner (closure, respp, args)
|
ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
|
||||||
ffi_closure *closure;
|
ffi_closure *closure;
|
||||||
void **respp;
|
void **respp;
|
||||||
void *args;
|
void *args;
|
||||||
|
void *vfp_args;
|
||||||
{
|
{
|
||||||
// our various things...
|
// our various things...
|
||||||
ffi_cif *cif;
|
ffi_cif *cif;
|
||||||
|
@ -219,7 +273,7 @@ ffi_closure_SYSV_inner (closure, respp, args)
|
||||||
* a structure, it will re-set RESP to point to the
|
* a structure, it will re-set RESP to point to the
|
||||||
* structure return address. */
|
* structure return address. */
|
||||||
|
|
||||||
ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
|
ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
|
||||||
|
|
||||||
(closure->fun) (cif, *respp, arg_area, closure->user_data);
|
(closure->fun) (cif, *respp, arg_area, closure->user_data);
|
||||||
|
|
||||||
|
@ -229,10 +283,12 @@ ffi_closure_SYSV_inner (closure, respp, args)
|
||||||
/*@-exportheader@*/
|
/*@-exportheader@*/
|
||||||
static void
|
static void
|
||||||
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
|
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
|
||||||
void **avalue, ffi_cif *cif)
|
void **avalue, ffi_cif *cif,
|
||||||
|
/* Used only under VFP hard-float ABI. */
|
||||||
|
float *vfp_stack)
|
||||||
/*@=exportheader@*/
|
/*@=exportheader@*/
|
||||||
{
|
{
|
||||||
register unsigned int i;
|
register unsigned int i, vi = 0;
|
||||||
register void **p_argv;
|
register void **p_argv;
|
||||||
register char *argp;
|
register char *argp;
|
||||||
register ffi_type **p_arg;
|
register ffi_type **p_arg;
|
||||||
|
@ -249,8 +305,16 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
|
||||||
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
|
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
|
||||||
{
|
{
|
||||||
size_t z;
|
size_t z;
|
||||||
|
size_t alignment;
|
||||||
|
|
||||||
|
if (cif->abi == FFI_VFP
|
||||||
|
&& vi < cif->vfp_nargs && vfp_type_p (*p_arg))
|
||||||
|
{
|
||||||
|
*p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
size_t alignment = (*p_arg)->alignment;
|
alignment = (*p_arg)->alignment;
|
||||||
if (alignment < 4)
|
if (alignment < 4)
|
||||||
alignment = 4;
|
alignment = 4;
|
||||||
/* Align if necessary */
|
/* Align if necessary */
|
||||||
|
@ -295,10 +359,17 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
||||||
void *user_data,
|
void *user_data,
|
||||||
void *codeloc)
|
void *codeloc)
|
||||||
{
|
{
|
||||||
FFI_ASSERT (cif->abi == FFI_SYSV);
|
void (*closure_func)(ffi_closure*) = NULL;
|
||||||
|
|
||||||
|
if (cif->abi == FFI_SYSV)
|
||||||
|
closure_func = &ffi_closure_SYSV;
|
||||||
|
else if (cif->abi == FFI_VFP)
|
||||||
|
closure_func = &ffi_closure_VFP;
|
||||||
|
else
|
||||||
|
FFI_ASSERT (0);
|
||||||
|
|
||||||
FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
|
FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
|
||||||
&ffi_closure_SYSV, \
|
closure_func, \
|
||||||
codeloc);
|
codeloc);
|
||||||
|
|
||||||
closure->cif = cif;
|
closure->cif = cif;
|
||||||
|
@ -307,3 +378,123 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
||||||
|
|
||||||
return FFI_OK;
|
return FFI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Below are routines for VFP hard-float support. */
|
||||||
|
|
||||||
|
static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum)
|
||||||
|
{
|
||||||
|
switch (t->type)
|
||||||
|
{
|
||||||
|
case FFI_TYPE_FLOAT:
|
||||||
|
case FFI_TYPE_DOUBLE:
|
||||||
|
*elt = (int) t->type;
|
||||||
|
*elnum = 1;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case FFI_TYPE_STRUCT_VFP_FLOAT:
|
||||||
|
*elt = FFI_TYPE_FLOAT;
|
||||||
|
*elnum = t->size / sizeof (float);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case FFI_TYPE_STRUCT_VFP_DOUBLE:
|
||||||
|
*elt = FFI_TYPE_DOUBLE;
|
||||||
|
*elnum = t->size / sizeof (double);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case FFI_TYPE_STRUCT:;
|
||||||
|
{
|
||||||
|
int base_elt = 0, total_elnum = 0;
|
||||||
|
ffi_type **el = t->elements;
|
||||||
|
while (*el)
|
||||||
|
{
|
||||||
|
int el_elt = 0, el_elnum = 0;
|
||||||
|
if (! rec_vfp_type_p (*el, &el_elt, &el_elnum)
|
||||||
|
|| (base_elt && base_elt != el_elt)
|
||||||
|
|| total_elnum + el_elnum > 4)
|
||||||
|
return 0;
|
||||||
|
base_elt = el_elt;
|
||||||
|
total_elnum += el_elnum;
|
||||||
|
el++;
|
||||||
|
}
|
||||||
|
*elnum = total_elnum;
|
||||||
|
*elt = base_elt;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vfp_type_p (ffi_type *t)
|
||||||
|
{
|
||||||
|
int elt, elnum;
|
||||||
|
if (rec_vfp_type_p (t, &elt, &elnum))
|
||||||
|
{
|
||||||
|
if (t->type == FFI_TYPE_STRUCT)
|
||||||
|
{
|
||||||
|
if (elnum == 1)
|
||||||
|
t->type = elt;
|
||||||
|
else
|
||||||
|
t->type = (elt == FFI_TYPE_FLOAT
|
||||||
|
? FFI_TYPE_STRUCT_VFP_FLOAT
|
||||||
|
: FFI_TYPE_STRUCT_VFP_DOUBLE);
|
||||||
|
}
|
||||||
|
return (int) t->type;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void place_vfp_arg (ffi_cif *cif, ffi_type *t)
|
||||||
|
{
|
||||||
|
int reg = cif->vfp_reg_free;
|
||||||
|
int nregs = t->size / sizeof (float);
|
||||||
|
int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT
|
||||||
|
|| t->type == FFI_TYPE_FLOAT) ? 1 : 2);
|
||||||
|
/* Align register number. */
|
||||||
|
if ((reg & 1) && align == 2)
|
||||||
|
reg++;
|
||||||
|
while (reg + nregs <= 16)
|
||||||
|
{
|
||||||
|
int s, new_used = 0;
|
||||||
|
for (s = reg; s < reg + nregs; s++)
|
||||||
|
{
|
||||||
|
new_used |= (1 << s);
|
||||||
|
if (cif->vfp_used & (1 << s))
|
||||||
|
{
|
||||||
|
reg += align;
|
||||||
|
goto next_reg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Found regs to allocate. */
|
||||||
|
cif->vfp_used |= new_used;
|
||||||
|
cif->vfp_args[cif->vfp_nargs++] = reg;
|
||||||
|
|
||||||
|
/* Update vfp_reg_free. */
|
||||||
|
if (cif->vfp_used & (1 << cif->vfp_reg_free))
|
||||||
|
{
|
||||||
|
reg += nregs;
|
||||||
|
while (cif->vfp_used & (1 << reg))
|
||||||
|
reg += 1;
|
||||||
|
cif->vfp_reg_free = reg;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
next_reg: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void layout_vfp_args (ffi_cif *cif)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
/* Init VFP fields */
|
||||||
|
cif->vfp_used = 0;
|
||||||
|
cif->vfp_nargs = 0;
|
||||||
|
cif->vfp_reg_free = 0;
|
||||||
|
memset (cif->vfp_args, -1, 16); /* Init to -1. */
|
||||||
|
|
||||||
|
for (i = 0; i < cif->nargs; i++)
|
||||||
|
{
|
||||||
|
ffi_type *t = cif->arg_types[i];
|
||||||
|
if (vfp_type_p (t))
|
||||||
|
place_vfp_arg (cif, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
/* -----------------------------------------------------------------*-C-*-
|
/* -----------------------------------------------------------------*-C-*-
|
||||||
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
|
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
|
||||||
|
Copyright (c) 2010 CodeSourcery
|
||||||
|
|
||||||
Target configuration macros for ARM.
|
Target configuration macros for ARM.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
@ -34,11 +36,25 @@ typedef signed long ffi_sarg;
|
||||||
typedef enum ffi_abi {
|
typedef enum ffi_abi {
|
||||||
FFI_FIRST_ABI = 0,
|
FFI_FIRST_ABI = 0,
|
||||||
FFI_SYSV,
|
FFI_SYSV,
|
||||||
|
FFI_VFP,
|
||||||
|
FFI_LAST_ABI,
|
||||||
|
#ifdef __ARM_PCS_VFP
|
||||||
|
FFI_DEFAULT_ABI = FFI_VFP,
|
||||||
|
#else
|
||||||
FFI_DEFAULT_ABI = FFI_SYSV,
|
FFI_DEFAULT_ABI = FFI_SYSV,
|
||||||
FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
|
#endif
|
||||||
} ffi_abi;
|
} ffi_abi;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FFI_EXTRA_CIF_FIELDS \
|
||||||
|
int vfp_used; \
|
||||||
|
short vfp_reg_free, vfp_nargs; \
|
||||||
|
signed char vfp_args[16] \
|
||||||
|
|
||||||
|
/* Internally used. */
|
||||||
|
#define FFI_TYPE_STRUCT_VFP_FLOAT (FFI_TYPE_LAST + 1)
|
||||||
|
#define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2)
|
||||||
|
|
||||||
/* ---- Definitions for closures ----------------------------------------- */
|
/* ---- Definitions for closures ----------------------------------------- */
|
||||||
|
|
||||||
#define FFI_CLOSURES 1
|
#define FFI_CLOSURES 1
|
||||||
|
|
|
@ -142,12 +142,11 @@ _L__\name:
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
|
||||||
@ r0: ffi_prep_args
|
@ r0: fn
|
||||||
@ r1: &ecif
|
@ r1: &ecif
|
||||||
@ r2: cif->bytes
|
@ r2: cif->bytes
|
||||||
@ r3: fig->flags
|
@ r3: fig->flags
|
||||||
@ sp+0: ecif.rvalue
|
@ sp+0: ecif.rvalue
|
||||||
@ sp+4: fn
|
|
||||||
|
|
||||||
@ This assumes we are using gas.
|
@ This assumes we are using gas.
|
||||||
ARM_FUNC_START ffi_call_SYSV
|
ARM_FUNC_START ffi_call_SYSV
|
||||||
|
@ -162,24 +161,23 @@ ARM_FUNC_START ffi_call_SYSV
|
||||||
sub sp, fp, r2
|
sub sp, fp, r2
|
||||||
|
|
||||||
@ Place all of the ffi_prep_args in position
|
@ Place all of the ffi_prep_args in position
|
||||||
mov ip, r0
|
|
||||||
mov r0, sp
|
mov r0, sp
|
||||||
@ r1 already set
|
@ r1 already set
|
||||||
|
|
||||||
@ Call ffi_prep_args(stack, &ecif)
|
@ Call ffi_prep_args(stack, &ecif)
|
||||||
call_reg(ip)
|
bl ffi_prep_args
|
||||||
|
|
||||||
@ move first 4 parameters in registers
|
@ move first 4 parameters in registers
|
||||||
ldmia sp, {r0-r3}
|
ldmia sp, {r0-r3}
|
||||||
|
|
||||||
@ and adjust stack
|
@ and adjust stack
|
||||||
ldr ip, [fp, #8]
|
sub lr, fp, sp @ cif->bytes == fp - sp
|
||||||
cmp ip, #16
|
ldr ip, [fp] @ load fn() in advance
|
||||||
movhs ip, #16
|
cmp lr, #16
|
||||||
add sp, sp, ip
|
movhs lr, #16
|
||||||
|
add sp, sp, lr
|
||||||
|
|
||||||
@ call (fn) (...)
|
@ call (fn) (...)
|
||||||
ldr ip, [fp, #28]
|
|
||||||
call_reg(ip)
|
call_reg(ip)
|
||||||
|
|
||||||
@ Remove the space we pushed for the args
|
@ Remove the space we pushed for the args
|
||||||
|
@ -230,6 +228,101 @@ LSYM(Lepilogue):
|
||||||
UNWIND .fnend
|
UNWIND .fnend
|
||||||
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
|
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
|
||||||
|
|
||||||
|
|
||||||
|
@ r0: fn
|
||||||
|
@ r1: &ecif
|
||||||
|
@ r2: cif->bytes
|
||||||
|
@ r3: fig->flags
|
||||||
|
@ sp+0: ecif.rvalue
|
||||||
|
|
||||||
|
ARM_FUNC_START ffi_call_VFP
|
||||||
|
@ Save registers
|
||||||
|
stmfd sp!, {r0-r3, fp, lr}
|
||||||
|
UNWIND .save {r0-r3, fp, lr}
|
||||||
|
mov fp, sp
|
||||||
|
UNWIND .setfp fp, sp
|
||||||
|
|
||||||
|
@ Make room for all of the new args.
|
||||||
|
sub sp, sp, r2
|
||||||
|
|
||||||
|
@ Make room for loading VFP args
|
||||||
|
sub sp, sp, #64
|
||||||
|
|
||||||
|
@ Place all of the ffi_prep_args in position
|
||||||
|
mov r0, sp
|
||||||
|
@ r1 already set
|
||||||
|
sub r2, fp, #64 @ VFP scratch space
|
||||||
|
|
||||||
|
@ Call ffi_prep_args(stack, &ecif, vfp_space)
|
||||||
|
bl ffi_prep_args
|
||||||
|
|
||||||
|
@ Load VFP register args if needed
|
||||||
|
cmp r0, #0
|
||||||
|
beq LSYM(Lbase_args)
|
||||||
|
|
||||||
|
@ Load only d0 if possible
|
||||||
|
cmp r0, #3
|
||||||
|
sub ip, fp, #64
|
||||||
|
flddle d0, [ip]
|
||||||
|
fldmiadgt ip, {d0-d7}
|
||||||
|
|
||||||
|
LSYM(Lbase_args):
|
||||||
|
@ move first 4 parameters in registers
|
||||||
|
ldmia sp, {r0-r3}
|
||||||
|
|
||||||
|
@ and adjust stack
|
||||||
|
sub lr, ip, sp @ cif->bytes == (fp - 64) - sp
|
||||||
|
ldr ip, [fp] @ load fn() in advance
|
||||||
|
cmp lr, #16
|
||||||
|
movhs lr, #16
|
||||||
|
add sp, sp, lr
|
||||||
|
|
||||||
|
@ call (fn) (...)
|
||||||
|
call_reg(ip)
|
||||||
|
|
||||||
|
@ Remove the space we pushed for the args
|
||||||
|
mov sp, fp
|
||||||
|
|
||||||
|
@ Load r2 with the pointer to storage for
|
||||||
|
@ the return value
|
||||||
|
ldr r2, [sp, #24]
|
||||||
|
|
||||||
|
@ Load r3 with the return type code
|
||||||
|
ldr r3, [sp, #12]
|
||||||
|
|
||||||
|
@ If the return value pointer is NULL,
|
||||||
|
@ assume no return value.
|
||||||
|
cmp r2, #0
|
||||||
|
beq LSYM(Lepilogue_vfp)
|
||||||
|
|
||||||
|
cmp r3, #FFI_TYPE_INT
|
||||||
|
streq r0, [r2]
|
||||||
|
beq LSYM(Lepilogue_vfp)
|
||||||
|
|
||||||
|
cmp r3, #FFI_TYPE_SINT64
|
||||||
|
stmeqia r2, {r0, r1}
|
||||||
|
beq LSYM(Lepilogue_vfp)
|
||||||
|
|
||||||
|
cmp r3, #FFI_TYPE_FLOAT
|
||||||
|
fstseq s0, [r2]
|
||||||
|
beq LSYM(Lepilogue_vfp)
|
||||||
|
|
||||||
|
cmp r3, #FFI_TYPE_DOUBLE
|
||||||
|
fstdeq d0, [r2]
|
||||||
|
beq LSYM(Lepilogue_vfp)
|
||||||
|
|
||||||
|
cmp r3, #FFI_TYPE_STRUCT_VFP_FLOAT
|
||||||
|
cmpne r3, #FFI_TYPE_STRUCT_VFP_DOUBLE
|
||||||
|
fstmiadeq r2, {d0-d3}
|
||||||
|
|
||||||
|
LSYM(Lepilogue_vfp):
|
||||||
|
RETLDM "r0-r3,fp"
|
||||||
|
|
||||||
|
.ffi_call_VFP_end:
|
||||||
|
UNWIND .fnend
|
||||||
|
.size CNAME(ffi_call_VFP),.ffi_call_VFP_end-CNAME(ffi_call_VFP)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
unsigned int FFI_HIDDEN
|
unsigned int FFI_HIDDEN
|
||||||
ffi_closure_SYSV_inner (closure, respp, args)
|
ffi_closure_SYSV_inner (closure, respp, args)
|
||||||
|
@ -302,6 +395,68 @@ ARM_FUNC_START ffi_closure_SYSV
|
||||||
UNWIND .fnend
|
UNWIND .fnend
|
||||||
.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
|
.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
|
||||||
|
|
||||||
|
|
||||||
|
ARM_FUNC_START ffi_closure_VFP
|
||||||
|
fstmfdd sp!, {d0-d7}
|
||||||
|
@ r0-r3, then d0-d7
|
||||||
|
UNWIND .pad #80
|
||||||
|
add ip, sp, #80
|
||||||
|
stmfd sp!, {ip, lr}
|
||||||
|
UNWIND .save {r0, lr}
|
||||||
|
add r2, sp, #72
|
||||||
|
add r3, sp, #8
|
||||||
|
.pad #72
|
||||||
|
sub sp, sp, #72
|
||||||
|
str sp, [sp, #64]
|
||||||
|
add r1, sp, #64
|
||||||
|
bl ffi_closure_SYSV_inner
|
||||||
|
|
||||||
|
cmp r0, #FFI_TYPE_INT
|
||||||
|
beq .Lretint_vfp
|
||||||
|
|
||||||
|
cmp r0, #FFI_TYPE_FLOAT
|
||||||
|
beq .Lretfloat_vfp
|
||||||
|
|
||||||
|
cmp r0, #FFI_TYPE_DOUBLE
|
||||||
|
cmpne r0, #FFI_TYPE_LONGDOUBLE
|
||||||
|
beq .Lretdouble_vfp
|
||||||
|
|
||||||
|
cmp r0, #FFI_TYPE_SINT64
|
||||||
|
beq .Lretlonglong_vfp
|
||||||
|
|
||||||
|
cmp r0, #FFI_TYPE_STRUCT_VFP_FLOAT
|
||||||
|
beq .Lretfloat_struct_vfp
|
||||||
|
|
||||||
|
cmp r0, #FFI_TYPE_STRUCT_VFP_DOUBLE
|
||||||
|
beq .Lretdouble_struct_vfp
|
||||||
|
|
||||||
|
.Lclosure_epilogue_vfp:
|
||||||
|
add sp, sp, #72
|
||||||
|
ldmfd sp, {sp, pc}
|
||||||
|
|
||||||
|
.Lretfloat_vfp:
|
||||||
|
flds s0, [sp]
|
||||||
|
b .Lclosure_epilogue_vfp
|
||||||
|
.Lretdouble_vfp:
|
||||||
|
fldd d0, [sp]
|
||||||
|
b .Lclosure_epilogue_vfp
|
||||||
|
.Lretint_vfp:
|
||||||
|
ldr r0, [sp]
|
||||||
|
b .Lclosure_epilogue_vfp
|
||||||
|
.Lretlonglong_vfp:
|
||||||
|
ldmia sp, {r0, r1}
|
||||||
|
b .Lclosure_epilogue_vfp
|
||||||
|
.Lretfloat_struct_vfp:
|
||||||
|
fldmiad sp, {d0-d1}
|
||||||
|
b .Lclosure_epilogue_vfp
|
||||||
|
.Lretdouble_struct_vfp:
|
||||||
|
fldmiad sp, {d0-d3}
|
||||||
|
b .Lclosure_epilogue_vfp
|
||||||
|
|
||||||
|
.ffi_closure_VFP_end:
|
||||||
|
UNWIND .fnend
|
||||||
|
.size CNAME(ffi_closure_VFP),.ffi_closure_VFP_end-CNAME(ffi_closure_VFP)
|
||||||
|
|
||||||
#if defined __ELF__ && defined __linux__
|
#if defined __ELF__ && defined __linux__
|
||||||
.section .note.GNU-stack,"",%progbits
|
.section .note.GNU-stack,"",%progbits
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -272,6 +272,56 @@ proc dg-xfail-if { args } {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc check-flags { args } {
|
||||||
|
|
||||||
|
# The args are within another list; pull them out.
|
||||||
|
set args [lindex $args 0]
|
||||||
|
|
||||||
|
# The next two arguments are optional. If they were not specified,
|
||||||
|
# use the defaults.
|
||||||
|
if { [llength $args] == 2 } {
|
||||||
|
lappend $args [list "*"]
|
||||||
|
}
|
||||||
|
if { [llength $args] == 3 } {
|
||||||
|
lappend $args [list ""]
|
||||||
|
}
|
||||||
|
|
||||||
|
# If the option strings are the defaults, or the same as the
|
||||||
|
# defaults, there is no need to call check_conditional_xfail to
|
||||||
|
# compare them to the actual options.
|
||||||
|
if { [string compare [lindex $args 2] "*"] == 0
|
||||||
|
&& [string compare [lindex $args 3] "" ] == 0 } {
|
||||||
|
set result 1
|
||||||
|
} else {
|
||||||
|
# The target list might be an effective-target keyword, so replace
|
||||||
|
# the original list with "*-*-*", since we already know it matches.
|
||||||
|
set result [check_conditional_xfail [lreplace $args 1 1 "*-*-*"]]
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result
|
||||||
|
}
|
||||||
|
|
||||||
|
proc dg-skip-if { args } {
|
||||||
|
# Verify the number of arguments. The last two are optional.
|
||||||
|
set args [lreplace $args 0 0]
|
||||||
|
if { [llength $args] < 2 || [llength $args] > 4 } {
|
||||||
|
error "dg-skip-if 2: need 2, 3, or 4 arguments"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Don't bother if we're already skipping the test.
|
||||||
|
upvar dg-do-what dg-do-what
|
||||||
|
if { [lindex ${dg-do-what} 1] == "N" } {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
set selector [list target [lindex $args 1]]
|
||||||
|
if { [dg-process-target $selector] == "S" } {
|
||||||
|
if [check-flags $args] {
|
||||||
|
upvar dg-do-what dg-do-what
|
||||||
|
set dg-do-what [list [lindex ${dg-do-what} 0] "N" "P"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# We need to make sure that additional_files and additional_sources
|
# We need to make sure that additional_files and additional_sources
|
||||||
# are both cleared out after every test. It is not enough to clear
|
# are both cleared out after every test. It is not enough to clear
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
|
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
|
||||||
/* { dg-output "" { xfail avr32*-*-* } } */
|
/* { dg-output "" { xfail avr32*-*-* } } */
|
||||||
|
/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */
|
||||||
|
|
||||||
#include "ffitest.h"
|
#include "ffitest.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
|
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
|
||||||
/* { dg-output "" { xfail avr32*-*-* x86_64-*-mingw* } } */
|
/* { dg-output "" { xfail avr32*-*-* x86_64-*-mingw* } } */
|
||||||
|
/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */
|
||||||
|
|
||||||
#include "ffitest.h"
|
#include "ffitest.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in New Issue