From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25856 invoked by alias); 16 Mar 2011 14:12:36 -0000 Received: (qmail 25846 invoked by uid 22791); 16 Mar 2011 14:12:33 -0000 X-SWARE-Spam-Status: No, hits=-5.7 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_BF,TW_VF,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 16 Mar 2011 14:12:21 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p2GECCrG007916 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 16 Mar 2011 10:12:12 -0400 Received: from localhost.localdomain.redhat.com (vpn-9-13.rdu.redhat.com [10.11.9.13]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p2GEC9Dv016589; Wed, 16 Mar 2011 10:12:10 -0400 To: Chung-Lin Tang Cc: David Gilbert , libffi-discuss@sourceware.org, Marcus.Shawcroft@arm.com, markos@genesi-usa.com Subject: Re: [PATCH] Add variadic support In-Reply-To: <4D808836.60706@linaro.org> (Chung-Lin Tang's message of "Wed, 16 Mar 2011 18:51:50 +0900") References: <20110222154022.GA29862@davesworkthinkpad> <4D650ADE.6040609@linaro.org> <4D653C3D.2050107@linaro.org> <4D654655.5000503@linaro.org> <4D67AD61.9090106@linaro.org> <4D808836.60706@linaro.org> User-Agent: Gnus/5.110014 (No Gnus v0.14) Emacs/23.1 (gnu/linux) From: Anthony Green Date: Wed, 16 Mar 2011 14:12:00 -0000 Message-ID: MIME-Version: 1.0 Content-Type: text/plain X-IsSubscribed: yes Mailing-List: contact libffi-discuss-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libffi-discuss-owner@sourceware.org X-SW-Source: 2011/txt/msg00105.txt.bz2 Chung-Lin Tang writes: > I think this looks fine. > Anthony, does the patch look okay to you? Yes, I think it's fine. I was against adding a new API at first, but after talking to David about it on #libffi I was convinced that there's no reasonable alternative. I'm going to check it into a branch on git until 3.0.10 is done. The branch will be called "variadic". Thanks for you work David! AG > > 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 >> +. >> +.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: 2011-01-25 >> + >> + Intended to stress the difference in ABI on ARM vfp >> +*/ >> + >> +/* { dg-do run } */ >> + >> +#include >> + >> +#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> + { >> + 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); >> +}