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] Add variadic support


I think this looks fine.
Anthony, does the patch look okay to you?

Thanks,
Chung-Lin


On 2011/3/8 03:18 AM, David Gilbert wrote:
> Hi,
>   Here is a rework of the previous patch, based on the previous discussion and
> suggestions from Chung-Lin.
> 
> (This is relative libffi git rev cbb062cc35c518004f1ab45c847f8ec4f66069ad)
> 
> Dave
> 
> diff --git a/doc/libffi.texi b/doc/libffi.texi
> index 5cdd667..a7c629a 100644
> --- a/doc/libffi.texi
> +++ b/doc/libffi.texi
> @@ -133,8 +133,6 @@ This initializes @var{cif} according to the given
> parameters.
>  you want.  @ref{Multiple ABIs} for more information.
> 
>  @var{nargs} is the number of arguments that this function accepts.
> -@samp{libffi} does not yet handle varargs functions; see @ref{Missing
> -Features} for more information.
> 
>  @var{rtype} is a pointer to an @code{ffi_type} structure that
>  describes the return type of the function.  @xref{Types}.
> @@ -150,6 +148,28 @@ objects is incorrect; or @code{FFI_BAD_ABI} if
> the @var{abi} parameter
>  is invalid.
>  @end defun
> 
> +If the function being called is variadic (varargs) then @code{ffi_prep_cif_var}
> +must be used instead of @code{ffi_prep_cif}.
> +
> +@findex ffi_prep_cif_var
> +@defun ffi_status ffi_prep_cif_var (ffi_cif *@var{cif}, ffi_abi
> @var{abi}, unsigned int @var{nfixedargs}, unsigned int
> @var{ntotalargs}, ffi_type *@var{rtype}, ffi_type **@var{argtypes})
> +This initializes @var{cif} according to the given parameters for
> +a call to a variadic function.  In general it's operation is the
> +same as for @code{ffi_prep_cif} except that:
> +
> +@var{nfixedargs} is the number of fixed arguments, prior to any
> +variadic arguments.  It must be greater than zero.
> +
> +@var{ntotalargs} the total number of arguments, including variadic
> +and fixed arguments.
> +
> +Note that, different cif's must be prepped for calls to the same
> +function when different numbers of arguments are passed.
> +
> +Also note that a call to @code{ffi_prep_cif_var} with
> @var{nfixedargs}=@var{nototalargs}
> +is NOT equivalent to a call to @code{ffi_prep_cif}.
> +
> +@end defun
> 
>  To call a function using an initialized @code{ffi_cif}, use the
>  @code{ffi_call} function:
> @@ -572,9 +592,7 @@ support for these.
> 
>  @itemize @bullet
>  @item
> -There is no support for calling varargs functions.  This may work on
> -some platforms, depending on how the ABI is defined, but it is not
> -reliable.
> +Variadic closures.
> 
>  @item
>  There is no support for bit fields in structures.
> @@ -591,6 +609,7 @@ The ``raw'' API is undocumented.
>  @c anything else?
>  @end itemize
> 
> +Note that variadic support is very new and tested on a relatively
> small number of platforms.
> 
>  @node Index
>  @unnumbered Index
> diff --git a/include/ffi.h.in b/include/ffi.h.in
> index 96b8fd3..f27f4f3 100644
> --- a/include/ffi.h.in
> +++ b/include/ffi.h.in
> @@ -203,6 +203,15 @@ typedef struct {
>  #endif
>  } ffi_cif;
> 
> +/* Used internally, but overridden by some architectures */
> +ffi_status ffi_prep_cif_core(ffi_cif *cif,
> +			     ffi_abi abi,
> +			     unsigned int isvariadic,
> +			     unsigned int nfixedargs,
> +			     unsigned int ntotalargs,
> +			     ffi_type *rtype,
> +			     ffi_type **atypes);
> +
>  /* ---- Definitions for the raw API -------------------------------------- */
> 
>  #ifndef FFI_SIZEOF_ARG
> @@ -380,6 +389,13 @@ ffi_status ffi_prep_cif(ffi_cif *cif,
>  			ffi_type *rtype,
>  			ffi_type **atypes);
> 
> +ffi_status ffi_prep_cif_var(ffi_cif *cif,
> +			    ffi_abi abi,
> +			    unsigned int nfixedargs,
> +			    unsigned int ntotalargs,
> +			    ffi_type *rtype,
> +			    ffi_type **atypes);
> +
>  void ffi_call(ffi_cif *cif,
>  	      void (*fn)(void),
>  	      void *rvalue,
> diff --git a/include/ffi_common.h b/include/ffi_common.h
> index d953762..919eec2 100644
> --- a/include/ffi_common.h
> +++ b/include/ffi_common.h
> @@ -75,6 +75,8 @@ void ffi_type_test(ffi_type *a, char *file, int line);
> 
>  /* Perform machine dependent cif processing */
>  ffi_status ffi_prep_cif_machdep(ffi_cif *cif);
> +ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
> +	 unsigned int nfixedargs, unsigned int ntotalargs);
> 
>  /* Extended cif, used in callback from assembly routine */
>  typedef struct
> diff --git a/man/Makefile.am b/man/Makefile.am
> index 2519277..afcbfb6 100644
> --- a/man/Makefile.am
> +++ b/man/Makefile.am
> @@ -2,7 +2,7 @@
> 
>  AUTOMAKE_OPTIONS=foreign
> 
> -EXTRA_DIST = ffi.3 ffi_call.3 ffi_prep_cif.3
> +EXTRA_DIST = ffi.3 ffi_call.3 ffi_prep_cif.3 ffi_prep_cif_var.3
> 
> -man_MANS = ffi.3 ffi_call.3 ffi_prep_cif.3
> +man_MANS = ffi.3 ffi_call.3 ffi_prep_cif.3 ffi_prep_cif_var.3
> 
> diff --git a/man/ffi.3 b/man/ffi.3
> index 18b5d5d..1f1d303 100644
> --- a/man/ffi.3
> +++ b/man/ffi.3
> @@ -16,6 +16,15 @@ libffi, -lffi
>  .Fa "ffi_type **atypes"
>  .Fc
>  .Ft void
> +.Fo ffi_prep_cif_var
> +.Fa "ffi_cif *cif"
> +.Fa "ffi_abi abi"
> +.Fa "unsigned int nfixedargs"
> +.Fa "unsigned int ntotalargs"
> +.Fa "ffi_type *rtype"
> +.Fa "ffi_type **atypes"
> +.Fc
> +.Ft void
>  .Fo ffi_call
>  .Fa "ffi_cif *cif"
>  .Fa "void (*fn)(void)"
> @@ -28,4 +37,5 @@ generate a call to another function at runtime
> without requiring knowledge of
>  the called function's interface at compile time.
>  .Sh SEE ALSO
>  .Xr ffi_prep_cif 3 ,
> +.Xr ffi_prep_cif_var 3 ,
>  .Xr ffi_call 3
> diff --git a/man/ffi_prep_cif.3 b/man/ffi_prep_cif.3
> index 9436b31..fe66452 100644
> --- a/man/ffi_prep_cif.3
> +++ b/man/ffi_prep_cif.3
> @@ -37,7 +37,9 @@ structs that describe the data type, size and
> alignment of each argument.
>  points to an
>  .Nm ffi_type
>  that describes the data type, size and alignment of the
> -return value.
> +return value. Note that to call a variadic function
> +.Nm ffi_prep_cif_var
> +must be used instead.
>  .Sh RETURN VALUES
>  Upon successful completion,
>  .Nm ffi_prep_cif
> @@ -63,4 +65,5 @@ defined in
>  .
>  .Sh SEE ALSO
>  .Xr ffi 3 ,
> -.Xr ffi_call 3
> +.Xr ffi_call 3 ,
> +.Xr ffi_prep_cif_var 3
> diff --git a/man/ffi_prep_cif_var.3 b/man/ffi_prep_cif_var.3
> new file mode 100644
> index 0000000..1b39c03
> --- /dev/null
> +++ b/man/ffi_prep_cif_var.3
> @@ -0,0 +1,73 @@
> +.Dd January 25, 2011
> +.Dt ffi_prep_cif_var 3
> +.Sh NAME
> +.Nm ffi_prep_cif_var
> +.Nd Prepare a
> +.Nm ffi_cif
> +structure for use with
> +.Nm ffi_call
> +for variadic functions.
> +.Sh SYNOPSIS
> +.In ffi.h
> +.Ft ffi_status
> +.Fo ffi_prep_cif_var
> +.Fa "ffi_cif *cif"
> +.Fa "ffi_abi abi"
> +.Fa "unsigned int nfixedargs"
> +.Fa "unsigned int ntotalargs"
> +.Fa "ffi_type *rtype"
> +.Fa "ffi_type **atypes"
> +.Fc
> +.Sh DESCRIPTION
> +The
> +.Nm ffi_prep_cif_var
> +function prepares a
> +.Nm ffi_cif
> +structure for use with
> +.Nm ffi_call
> +for variadic functions.
> +.Fa abi
> +specifies a set of calling conventions to use.
> +.Fa atypes
> +is an array of
> +.Fa ntotalargs
> +pointers to
> +.Nm ffi_type
> +structs that describe the data type, size and alignment of each argument.
> +.Fa rtype
> +points to an
> +.Nm ffi_type
> +that describes the data type, size and alignment of the
> +return value.
> +.Fa nfixedargs
> +must contain the number of fixed (non-variadic) arguments.
> +Note that to call a non-variadic function
> +.Nm ffi_prep_cif
> +must be used.
> +.Sh RETURN VALUES
> +Upon successful completion,
> +.Nm ffi_prep_cif_var
> +returns
> +.Nm FFI_OK .
> +It will return
> +.Nm FFI_BAD_TYPEDEF
> +if
> +.Fa cif
> +is
> +.Nm NULL
> +or
> +.Fa atypes
> +or
> +.Fa rtype
> +is malformed. If
> +.Fa abi
> +does not refer to a valid ABI,
> +.Nm FFI_BAD_ABI
> +will be returned. Available ABIs are
> +defined in
> +.Nm <ffitarget.h>
> +.
> +.Sh SEE ALSO
> +.Xr ffi 3 ,
> +.Xr ffi_call 3 ,
> +.Xr ffi_prep_cif 3
> diff --git a/src/arm/ffi.c b/src/arm/ffi.c
> index 885a9cb..c226dbd 100644
> --- a/src/arm/ffi.c
> +++ b/src/arm/ffi.c
> @@ -189,6 +189,18 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
>    return FFI_OK;
>  }
> 
> +/* Perform machine dependent cif processing for variadic calls */
> +ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
> +				    unsigned int nfixedargs,
> +				    unsigned int ntotalargs)
> +{
> +  /* VFP variadic calls actually use the SYSV ABI */
> +  if (cif->abi == FFI_VFP)
> +	cif->abi = FFI_SYSV;
> +
> +  return ffi_prep_cif_machdep(cif);
> +}
> +
>  /* 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 *);
> diff --git a/src/arm/ffitarget.h b/src/arm/ffitarget.h
> index ce25b23..b9a0428 100644
> --- a/src/arm/ffitarget.h
> +++ b/src/arm/ffitarget.h
> @@ -55,6 +55,8 @@ typedef enum ffi_abi {
>  #define FFI_TYPE_STRUCT_VFP_FLOAT  (FFI_TYPE_LAST + 1)
>  #define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2)
> 
> +#define FFI_TARGET_SPECIFIC_VARIADIC
> +
>  /* ---- Definitions for closures ----------------------------------------- */
> 
>  #define FFI_CLOSURES 1
> @@ -62,4 +64,3 @@ typedef enum ffi_abi {
>  #define FFI_NATIVE_RAW_API 0
> 
>  #endif
> -
> diff --git a/src/cris/ffi.c b/src/cris/ffi.c
> index f25d7b4..aaca5b1 100644
> --- a/src/cris/ffi.c
> +++ b/src/cris/ffi.c
> @@ -153,21 +153,24 @@ ffi_prep_args (char *stack, extended_cif * ecif)
>    return (struct_count);
>  }
> 
> -ffi_status
> -ffi_prep_cif (ffi_cif * cif,
> -	      ffi_abi abi, unsigned int nargs,
> -	      ffi_type * rtype, ffi_type ** atypes)
> +ffi_status FFI_HIDDEN
> +ffi_prep_cif_core (ffi_cif * cif,
> +	           ffi_abi abi, unsigned int isvariadic,
> +		   unsigned int nfixedargs, unsigned int ntotalargs,
> +	           ffi_type * rtype, ffi_type ** atypes)
>  {
>    unsigned bytes = 0;
>    unsigned int i;
>    ffi_type **ptr;
> 
>    FFI_ASSERT (cif != NULL);
> +  FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
> +  FFI_ASSERT(nfixedargs <= ntotalargs);
>    FFI_ASSERT (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI);
> 
>    cif->abi = abi;
>    cif->arg_types = atypes;
> -  cif->nargs = nargs;
> +  cif->nargs = ntotalargs;
>    cif->rtype = rtype;
> 
>    cif->flags = 0;
> diff --git a/src/prep_cif.c b/src/prep_cif.c
> index 8548cfd..0e2e116 100644
> --- a/src/prep_cif.c
> +++ b/src/prep_cif.c
> @@ -90,20 +90,33 @@ static ffi_status initialize_aggregate(ffi_type *arg)
>  /* Perform machine independent ffi_cif preparation, then call
>     machine dependent routine. */
> 
> -ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
> -			ffi_type *rtype, ffi_type **atypes)
> +/* For non variadic functions isvariadic should be 0 and
> +   nfixedargs==ntotalargs.
> +
> +   For variadic calls, isvariadic should be 1 and nfixedargs
> +   and ntotalargs set as appropriate. nfixedargs must always be >=1 */
> +
> +
> +ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
> +			     unsigned int isvariadic,
> +                             unsigned int nfixedargs,
> +                             unsigned int ntotalargs,
> +			     ffi_type *rtype, ffi_type **atypes)
>  {
>    unsigned bytes = 0;
>    unsigned int i;
>    ffi_type **ptr;
> 
>    FFI_ASSERT(cif != NULL);
> +  FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
> +  FFI_ASSERT(nfixedargs <= ntotalargs);
> +
>    if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
>      return FFI_BAD_ABI;
> 
>    cif->abi = abi;
>    cif->arg_types = atypes;
> -  cif->nargs = nargs;
> +  cif->nargs = ntotalargs;
>    cif->rtype = rtype;
> 
>    cif->flags = 0;
> @@ -159,10 +172,31 @@ ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi
> abi, unsigned int nargs,
>    cif->bytes = bytes;
> 
>    /* Perform machine dependent cif processing */
> +#ifdef FFI_TARGET_SPECIFIC_VARIADIC
> +  if (isvariadic)
> +	return ffi_prep_cif_machdep_var(cif, nfixedargs, ntotalargs);
> +#endif
> +
>    return ffi_prep_cif_machdep(cif);
>  }
>  #endif /* not __CRIS__ */
> 
> +ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
> +			     ffi_type *rtype, ffi_type **atypes)
> +{
> +  return ffi_prep_cif_core(cif, abi, 0, nargs, nargs, rtype, atypes);
> +}
> +
> +ffi_status ffi_prep_cif_var(ffi_cif *cif,
> +                            ffi_abi abi,
> +                            unsigned int nfixedargs,
> +                            unsigned int ntotalargs,
> +                            ffi_type *rtype,
> +                            ffi_type **atypes)
> +{
> +  return ffi_prep_cif_core(cif, abi, 1, nfixedargs, ntotalargs, rtype, atypes);
> +}
> +
>  #if FFI_CLOSURES
> 
>  ffi_status
> diff --git a/testsuite/libffi.call/cls_double_va.c
> b/testsuite/libffi.call/cls_double_va.c
> index 62bebbd..1a2706e 100644
> --- a/testsuite/libffi.call/cls_double_va.c
> +++ b/testsuite/libffi.call/cls_double_va.c
> @@ -6,7 +6,6 @@
> 
>  /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
>  /* { dg-output "" { xfail avr32*-*-* } } */
> -/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */
> 
>  #include "ffitest.h"
> 
> @@ -36,7 +35,8 @@ int main (void)
>  	arg_types[1] = &ffi_type_double;
>  	arg_types[2] = NULL;
> 
> -	CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
> +	/* This printf call is variadic */
> +	CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
>  		arg_types) == FFI_OK);
> 
>  	args[0] = &format;
> @@ -48,6 +48,10 @@ int main (void)
>  	printf("res: %d\n", (int) res);
>  	// { dg-output "\nres: 4" }
> 
> +	/* The call to cls_double_va_fn is static, so have to use a normal prep_cif */
> +	CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
> +		arg_types) == FFI_OK);
> +
>  	CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL, code)
> == FFI_OK);
> 
>  	res	= ((int(*)(char*, double))(code))(format, doubleArg);
> diff --git a/testsuite/libffi.call/cls_longdouble_va.c
> b/testsuite/libffi.call/cls_longdouble_va.c
> index b33b2b7..95f9ff4 100644
> --- a/testsuite/libffi.call/cls_longdouble_va.c
> +++ b/testsuite/libffi.call/cls_longdouble_va.c
> @@ -6,7 +6,6 @@
> 
>  /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
>  /* { dg-output "" { xfail avr32*-*-* x86_64-*-mingw* } } */
> -/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */
> 
>  #include "ffitest.h"
> 
> @@ -36,7 +35,8 @@ int main (void)
>  	arg_types[1] = &ffi_type_longdouble;
>  	arg_types[2] = NULL;
> 
> -	CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
> +	/* This printf call is variadic */
> +	CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
>  		arg_types) == FFI_OK);
> 
>  	args[0] = &format;
> @@ -48,6 +48,10 @@ int main (void)
>  	printf("res: %d\n", (int) res);
>  	// { dg-output "\nres: 4" }
> 
> +	/* The call to cls_longdouble_va_fn is static, so have to use a
> normal prep_cif */
> +	CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
> +		arg_types) == FFI_OK);
> +
>  	CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL,
> code) == FFI_OK);
> 
>  	res	= ((int(*)(char*, long double))(code))(format, ldArg);
> diff --git a/testsuite/libffi.call/float_va.c b/testsuite/libffi.call/float_va.c
> new file mode 100644
> index 0000000..4611969
> --- /dev/null
> +++ b/testsuite/libffi.call/float_va.c
> @@ -0,0 +1,107 @@
> +/* Area:        fp and variadics
> +   Purpose:     check fp inputs and returns work on variadics, even
> the fixed params
> +   Limitations: None
> +   PR:          none
> +   Originator:  <david.gilbert@linaro.org> 2011-01-25
> +
> +   Intended to stress the difference in ABI on ARM vfp
> +*/
> +
> +/* { dg-do run } */
> +
> +#include <stdarg.h>
> +
> +#include "ffitest.h"
> +
> +/* prints out all the parameters, and returns the sum of them all.
> + * 'x' is the number of variadic parameters all of which are double
> in this test
> + */
> +double float_va_fn(unsigned int x, double y,...)
> +{
> +  double total=0.0;
> +  va_list ap;
> +  unsigned int i;
> +
> +  total+=(double)x;
> +  total+=y;
> +
> +  printf("%u: %.1lf :", x, y);
> +
> +  va_start(ap, y);
> +  for(i=0;i<x;i++)
> +  {
> +    double arg=va_arg(ap, double);
> +    total+=arg;
> +    printf(" %d:%.1lf ", i, arg);
> +  }
> +  va_end(ap);
> +
> +  printf(" total: %.1lf\n", total);
> +
> +  return total;
> +}
> +
> +int main (void)
> +{
> +  ffi_cif    cif;
> +
> +  ffi_type    *arg_types[5];
> +  void        *values[5];
> +  double        doubles[5];
> +  unsigned int firstarg;
> +  double        resfp;
> +
> +  /* First test, pass float_va_fn(0,2.0) - note there are no actual
> +   * variadic parameters, but it's declared variadic so the ABI may be
> +   * different. */
> +  /* Call it statically and then via ffi */
> +  resfp=float_va_fn(0,2.0);
> +  // { dg-output "0: 2.0 : total: 2.0" }
> +  printf("compiled: %.1lf\n", resfp);
> +  // { dg-output "\ncompiled: 2.0" }
> +
> +  arg_types[0] = &ffi_type_uint;
> +  arg_types[1] = &ffi_type_double;
> +  arg_types[2] = NULL;
> +  CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 2, 2,
> +        &ffi_type_double, arg_types) == FFI_OK);
> +
> +  firstarg = 0;
> +  doubles[0] = 2.0;
> +  values[0] = &firstarg;
> +  values[1] = &doubles[0];
> +  ffi_call(&cif, FFI_FN(float_va_fn), &resfp, values);
> +  // { dg-output "\n0: 2.0 : total: 2.0" }
> +  printf("ffi: %.1lf\n", resfp);
> +  // { dg-output "\nffi: 2.0" }
> +
> +  /* Second test, float_va_fn(2,2.0,3.0,4.0), now with variadic params */
> +  /* Call it statically and then via ffi */
> +  resfp=float_va_fn(2,2.0,3.0,4.0);
> +  // { dg-output "\n2: 2.0 : 0:3.0  1:4.0  total: 11.0" }
> +  printf("compiled: %.1lf\n", resfp);
> +  // { dg-output "\ncompiled: 11.0" }
> +
> +  arg_types[0] = &ffi_type_uint;
> +  arg_types[1] = &ffi_type_double;
> +  arg_types[2] = &ffi_type_double;
> +  arg_types[3] = &ffi_type_double;
> +  arg_types[4] = NULL;
> +  CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 2, 4,
> +        &ffi_type_double, arg_types) == FFI_OK);
> +
> +  firstarg = 2;
> +  doubles[0] = 2.0;
> +  doubles[1] = 3.0;
> +  doubles[2] = 4.0;
> +  values[0] = &firstarg;
> +  values[1] = &doubles[0];
> +  values[2] = &doubles[1];
> +  values[3] = &doubles[2];
> +  ffi_call(&cif, FFI_FN(float_va_fn), &resfp, values);
> +  // { dg-output "\n2: 2.0 : 0:3.0  1:4.0  total: 11.0" }
> +  printf("ffi: %.1lf\n", resfp);
> +  // { dg-output "\nffi: 11.0" }
> +
> +  exit(0);
> +}


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