This is the mail archive of the libffi-discuss@sourceware.org mailing list for the libffi project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch, ARM] VFP hard-float calling convention support


Chung-Lin Tang <cltang@codesourcery.com> writes:

> Hi,
> this patch implements VFP hard-float calling conventions, as a new ABI
> for ARM. Asides from VFP calling convention bits, some additional
> optimizations have been added to the current softfp assembly code
> paths too.

Thanks.  I'll review this shortly.  Sorry for the delay!

AG


>
> The FFI_DEFAULT_ABI value is now defined depending on a new GCC
> built-in preprocessor symbol __ARM_PCS_VFP, which was only recently
> added into GCC trunk; this seems to be the only reliable way of
> detecting the FP calling convention from within the source.
>
> Variadic function tests (cls_double_va.c and cls_longdouble_va.c in
> testsuite/libffi.call) has been disabled for VFP hard-float; the rules
> of AAPCS states that variadic functions switch back to the base
> (softfp) ABI, a condition on function type that seems not currently
> detectable within libffi.
>
> Testsuite patches have been added to support a dg-skip-if option
> (adapted from the GCC testsuite), to turn off the above two mentioned
> tests based on compiler options (skip on -mfloat-abi=hard). Patch was
> regression tested under both -mfloat-abi=hard and softfp with no
> unexpected failures.
>
> Comments on the patch are of course welcome.
> If approved, please help to commit to git head and GCC trunk.
>
> Thanks,
> Chung-Lin
>
>
> 2010-08-16  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.
>
> diff --git a/src/arm/ffi.c b/src/arm/ffi.c
> index f6a6475..9a0a53c 100644
> --- a/src/arm/ffi.c
> +++ b/src/arm/ffi.c
> @@ -29,12 +29,20 @@
>  
>  #include <stdlib.h>
>  
> -/* ffi_prep_args is called by the assembly routine once stack space
> -   has been allocated for the function's arguments */
> +/* Forward declares. */
> +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 char *argp;
>    register ffi_type **p_arg;
> @@ -54,6 +62,21 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
>      {
>        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 */
>        if (((*p_arg)->alignment - 1) & (unsigned) argp) {
>  	argp = (char *) ALIGN(argp, (*p_arg)->alignment);
> @@ -103,13 +126,15 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
>  	  p_argv++;
>  	  argp += z;
>      }
> -  
> -  return;
> +
> +  /* Indicate the VFP registers used. */
> +  return ecif->cif->vfp_used;
>  }
>  
>  /* Perform machine dependent cif processing */
>  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 
>       everywhere, but it is on some platforms, and it doesn't harm anything
>       when it isn't needed.  */
> @@ -130,7 +155,14 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
>        break;
>  
>      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.  */
>  	cif->flags = (unsigned)FFI_TYPE_INT;
>        else
> @@ -145,11 +177,18 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
>        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;
>  }
>  
> -extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
> -			  unsigned, unsigned, unsigned *, void (*fn)(void));
> +/* Prototypes for assembly functions, in sysv.S */
> +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)
>  {
> @@ -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 
>  		      && 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.avalue = avalue;
> @@ -173,38 +214,51 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
>      }
>    else if (small_struct)
>      ecif.rvalue = &temp;
> +  else if (vfp_struct)
> +    {
> +      /* Largest case is double x 4. */
> +      ecif.rvalue = alloca(32);
> +    }
>    else
>      ecif.rvalue = rvalue;
>  
>    switch (cif->abi) 
>      {
>      case FFI_SYSV:
> -      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
> -		    fn);
> +      ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
> +      break;
>  
> +    case FFI_VFP:
> +      ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
>        break;
> +
>      default:
>        FFI_ASSERT(0);
>        break;
>      }
>    if (small_struct)
>      memcpy (rvalue, &temp, cif->rtype->size);
> +  else if (vfp_struct)
> +    memcpy (rvalue, ecif.rvalue, cif->rtype->size);
>  }
>  
>  /** private members **/
>  
>  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_VFP (ffi_closure *);
> +
>  /* This function is jumped to by the trampoline */
>  
>  unsigned int
> -ffi_closure_SYSV_inner (closure, respp, args)
> +ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
>       ffi_closure *closure;
>       void **respp;
>       void *args;
> +     void *vfp_args;
>  {
>    // our various things...
>    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
>     * 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);
>  
> @@ -229,10 +283,12 @@ ffi_closure_SYSV_inner (closure, respp, args)
>  /*@-exportheader@*/
>  static void 
>  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@*/
>  {
> -  register unsigned int i;
> +  register unsigned int i, vi = 0;
>    register void **p_argv;
>    register char *argp;
>    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++)
>      {
>        size_t z;
> -
> -      size_t alignment = (*p_arg)->alignment;
> +      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;
> +	}
> +
> +      alignment = (*p_arg)->alignment;
>        if (alignment < 4)
>  	alignment = 4;
>        /* Align if necessary */
> @@ -295,10 +359,17 @@ ffi_prep_closure_loc (ffi_closure* closure,
>  		      void *user_data,
>  		      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_closure_SYSV,  \
> +		       closure_func,  \
>  		       codeloc);
>      
>    closure->cif  = cif;
> @@ -307,3 +378,123 @@ ffi_prep_closure_loc (ffi_closure* closure,
>  
>    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);
> +    }
> +}
> diff --git a/src/arm/ffitarget.h b/src/arm/ffitarget.h
> index eede79f..aceb10b 100644
> --- a/src/arm/ffitarget.h
> +++ b/src/arm/ffitarget.h
> @@ -34,11 +34,25 @@ typedef signed long            ffi_sarg;
>  typedef enum ffi_abi {
>    FFI_FIRST_ABI = 0,
>    FFI_SYSV,
> +  FFI_VFP,
>    FFI_LAST_ABI,
> -  FFI_DEFAULT_ABI = FFI_SYSV
> +#ifdef __ARM_PCS_VFP
> +  FFI_DEFAULT_ABI = FFI_VFP,
> +#else
> +  FFI_DEFAULT_ABI = FFI_SYSV,
> +#endif
>  } ffi_abi;
>  #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 ----------------------------------------- */
>  
>  #define FFI_CLOSURES 1
> diff --git a/src/arm/sysv.S b/src/arm/sysv.S
> index 9064318..7bce727 100644
> --- a/src/arm/sysv.S
> +++ b/src/arm/sysv.S
> @@ -142,12 +142,11 @@ _L__\name:
>  .endm
>  
>  
> -	@ r0:   ffi_prep_args
> +	@ r0:   fn
>  	@ r1:   &ecif
>  	@ r2:   cif->bytes
>  	@ r3:   fig->flags
>  	@ sp+0: ecif.rvalue
> -	@ sp+4: fn
>  
>  	@ This assumes we are using gas.
>  ARM_FUNC_START ffi_call_SYSV
> @@ -162,24 +161,23 @@ ARM_FUNC_START ffi_call_SYSV
>  	sub	sp, fp, r2
>  
>  	@ Place all of the ffi_prep_args in position
> -	mov	ip, r0
>  	mov	r0, sp
>  	@     r1 already set
>  
>  	@ Call ffi_prep_args(stack, &ecif)
> -	call_reg(ip)
> +	bl	ffi_prep_args
>  
>  	@ move first 4 parameters in registers
>  	ldmia	sp, {r0-r3}
>  
>  	@ and adjust stack
> -	ldr	ip, [fp, #8]
> -        cmp	ip, #16
> -	movhs	ip, #16
> -        add	sp, sp, ip
> +	sub	lr, fp, sp	@ cif->bytes == fp - sp
> +	ldr	ip, [fp]	@ load fn() in advance
> +	cmp	lr, #16
> +	movhs	lr, #16
> +	add	sp, sp, lr
>  
>  	@ call (fn) (...)
> -	ldr	ip, [fp, #28]
>  	call_reg(ip)
>  	
>  	@ Remove the space we pushed for the args
> @@ -230,6 +228,101 @@ LSYM(Lepilogue):
>  	UNWIND .fnend
>          .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
>  	ffi_closure_SYSV_inner (closure, respp, args)
> @@ -302,6 +395,68 @@ ARM_FUNC_START ffi_closure_SYSV
>  	UNWIND .fnend
>          .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__
>  	.section	.note.GNU-stack,"",%progbits
>  #endif
> diff --git a/testsuite/lib/libffi-dg.exp b/testsuite/lib/libffi-dg.exp
> index 838a306..ca5f751 100644
> --- a/testsuite/lib/libffi-dg.exp
> +++ b/testsuite/lib/libffi-dg.exp
> @@ -266,6 +266,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
>  # are both cleared out after every test.  It is not enough to clear
> diff --git a/testsuite/libffi.call/cls_double_va.c b/testsuite/libffi.call/cls_double_va.c
> index 0695874..62bebbd 100644
> --- a/testsuite/libffi.call/cls_double_va.c
> +++ b/testsuite/libffi.call/cls_double_va.c
> @@ -6,6 +6,8 @@
>  
>  /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
>  /* { dg-output "" { xfail avr32*-*-* } } */
> +/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */
> +
>  #include "ffitest.h"
>  
>  static void
> diff --git a/testsuite/libffi.call/cls_longdouble_va.c b/testsuite/libffi.call/cls_longdouble_va.c
> index 38564cb..b33b2b7 100644
> --- a/testsuite/libffi.call/cls_longdouble_va.c
> +++ b/testsuite/libffi.call/cls_longdouble_va.c
> @@ -6,6 +6,8 @@
>  
>  /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
>  /* { dg-output "" { xfail avr32*-*-* x86_64-*-mingw* } } */
> +/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */
> +
>  #include "ffitest.h"
>  
>  static void


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]