From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 24521 invoked by alias); 13 Nov 2013 15:16:26 -0000 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 Received: (qmail 24511 invoked by uid 89); 13 Nov 2013 15:16:25 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.6 required=5.0 tests=AWL,BAYES_50,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,RDNS_NONE,SPF_PASS autolearn=no version=3.3.2 X-HELO: mail-pb0-f47.google.com Received: from Unknown (HELO mail-pb0-f47.google.com) (209.85.160.47) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Wed, 13 Nov 2013 15:15:54 +0000 Received: by mail-pb0-f47.google.com with SMTP id rq2so543546pbb.34 for ; Wed, 13 Nov 2013 07:15:46 -0800 (PST) X-Received: by 10.68.197.73 with SMTP id is9mr41594926pbc.75.1384355746412; Wed, 13 Nov 2013 07:15:46 -0800 (PST) Received: from bubble.grove.modra.org ([101.166.26.37]) by mx.google.com with ESMTPSA id qv8sm4889601pbc.31.2013.11.13.07.15.44 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 13 Nov 2013 07:15:45 -0800 (PST) Received: by bubble.grove.modra.org (Postfix, from userid 1000) id B8381EA006D; Thu, 14 Nov 2013 01:45:39 +1030 (CST) Date: Wed, 13 Nov 2013 15:16:00 -0000 From: Alan Modra To: libffi-discuss@sourceware.org Subject: Pass floating point values on powerpc64 as per ABI Message-ID: <20131113151539.GC20756@bubble.grove.modra.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-SW-Source: 2013/txt/msg00201.txt.bz2 The powerpc64 support opted to pass floating point values both in the fpr area and the parameter save area, necessary when the backend doesn't know if a function argument corresponds to the ellipsis arguments of a variadic function. This patch adds powerpc support for variadic functions, and changes the code to only pass fp in the ABI mandated area. ELFv2 needs this change since the parameter save area may not exist there. This also fixes two faulty tests that used a non-variadic function cast to call a variadic function, and spuriously reasoned that this is somehow necessary for static functions.. * src/powerpc/ffitarget.h (FFI_TARGET_SPECIFIC_VARIADIC): Define. (FFI_EXTRA_CIF_FIELDS): Define. * src/powerpc/ffi.c (ffi_prep_args64): Save fprs as per the ABI, not to both fpr and param save area. (ffi_prep_cif_machdep_core): Renamed from ffi_prep_cif_machdep. Keep initial flags. Formatting. Remove dead FFI_LINUX_SOFT_FLOAT code. (ffi_prep_cif_machdep, ffi_prep_cif_machdep_var): New functions. (ffi_closure_helper_LINUX64): Pass floating point as per ABI, not to both fpr and parameter save areas. * libffi/testsuite/libffi.call/cls_double_va.c (main): Correct function cast and don't call ffi_prep_cif. * libffi/testsuite/libffi.call/cls_longdouble_va.c (main): Likewise. diff --git a/src/powerpc/ffi.c b/src/powerpc/ffi.c index a260c74..094ee9c 100644 --- a/src/powerpc/ffi.c +++ b/src/powerpc/ffi.c @@ -449,9 +449,9 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack) /* 'fpr_base' points at the space for fpr3, and grows upwards as we use FPR registers. */ valp fpr_base; - int fparg_count; + unsigned int fparg_count; - int i, words; + unsigned int i, words, nargs, nfixedargs; ffi_type **ptr; double double_tmp; union { @@ -488,30 +488,34 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack) /* Now for the arguments. */ p_argv.v = ecif->avalue; - for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; - i > 0; - i--, ptr++, p_argv.v++) + nargs = ecif->cif->nargs; + nfixedargs = ecif->cif->nfixedargs; + for (ptr = ecif->cif->arg_types, i = 0; + i < nargs; + i++, ptr++, p_argv.v++) { switch ((*ptr)->type) { case FFI_TYPE_FLOAT: double_tmp = **p_argv.f; - *next_arg.f = (float) double_tmp; + if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) + *fpr_base.d++ = double_tmp; + else + *next_arg.f = (float) double_tmp; if (++next_arg.ul == gpr_end.ul) next_arg.ul = rest.ul; - if (fparg_count < NUM_FPR_ARG_REGISTERS64) - *fpr_base.d++ = double_tmp; fparg_count++; FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); break; case FFI_TYPE_DOUBLE: double_tmp = **p_argv.d; - *next_arg.d = double_tmp; + if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) + *fpr_base.d++ = double_tmp; + else + *next_arg.d = double_tmp; if (++next_arg.ul == gpr_end.ul) next_arg.ul = rest.ul; - if (fparg_count < NUM_FPR_ARG_REGISTERS64) - *fpr_base.d++ = double_tmp; fparg_count++; FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); break; @@ -519,18 +523,20 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack) #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: double_tmp = (*p_argv.d)[0]; - *next_arg.d = double_tmp; + if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) + *fpr_base.d++ = double_tmp; + else + *next_arg.d = double_tmp; if (++next_arg.ul == gpr_end.ul) next_arg.ul = rest.ul; - if (fparg_count < NUM_FPR_ARG_REGISTERS64) - *fpr_base.d++ = double_tmp; fparg_count++; double_tmp = (*p_argv.d)[1]; - *next_arg.d = double_tmp; + if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) + *fpr_base.d++ = double_tmp; + else + *next_arg.d = double_tmp; if (++next_arg.ul == gpr_end.ul) next_arg.ul = rest.ul; - if (fparg_count < NUM_FPR_ARG_REGISTERS64) - *fpr_base.d++ = double_tmp; fparg_count++; FFI_ASSERT (__LDBL_MANT_DIG__ == 106); FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); @@ -603,15 +609,14 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack) /* Perform machine dependent cif processing */ -ffi_status -ffi_prep_cif_machdep (ffi_cif *cif) +static ffi_status +ffi_prep_cif_machdep_core (ffi_cif *cif) { /* All this is for the SYSV and LINUX64 ABI. */ - int i; ffi_type **ptr; unsigned bytes; - int fparg_count = 0, intarg_count = 0; - unsigned flags = 0; + unsigned i, fparg_count = 0, intarg_count = 0; + unsigned flags = cif->flags; unsigned struct_copy_size = 0; unsigned type = cif->rtype->type; unsigned size = cif->rtype->size; @@ -656,19 +661,23 @@ ffi_prep_cif_machdep (ffi_cif *cif) - soft-float float/doubles are treated as UINT32/UINT64 respectivley. - soft-float long doubles are returned in gpr3-gpr6. */ /* First translate for softfloat/nonlinux */ - if (cif->abi == FFI_LINUX_SOFT_FLOAT) { - if (type == FFI_TYPE_FLOAT) - type = FFI_TYPE_UINT32; - if (type == FFI_TYPE_DOUBLE) - type = FFI_TYPE_UINT64; - if (type == FFI_TYPE_LONGDOUBLE) - type = FFI_TYPE_UINT128; - } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) { + if (cif->abi == FFI_LINUX_SOFT_FLOAT) + { + if (type == FFI_TYPE_FLOAT) + type = FFI_TYPE_UINT32; + if (type == FFI_TYPE_DOUBLE) + type = FFI_TYPE_UINT64; + if (type == FFI_TYPE_LONGDOUBLE) + type = FFI_TYPE_UINT128; + } + else if (cif->abi != FFI_LINUX + && cif->abi != FFI_LINUX64) + { #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - if (type == FFI_TYPE_LONGDOUBLE) - type = FFI_TYPE_STRUCT; + if (type == FFI_TYPE_LONGDOUBLE) + type = FFI_TYPE_STRUCT; #endif - } + } switch (type) { @@ -829,13 +838,8 @@ ffi_prep_cif_machdep (ffi_cif *cif) { #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: - if (cif->abi == FFI_LINUX_SOFT_FLOAT) - intarg_count += 4; - else - { - fparg_count += 2; - intarg_count += 2; - } + fparg_count += 2; + intarg_count += 2; break; #endif case FFI_TYPE_FLOAT: @@ -917,6 +921,22 @@ ffi_prep_cif_machdep (ffi_cif *cif) return FFI_OK; } +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + cif->nfixedargs = cif->nargs; + return ffi_prep_cif_machdep_core (cif); +} + +ffi_status +ffi_prep_cif_machdep_var (ffi_cif *cif, + unsigned int nfixedargs, + unsigned int ntotalargs MAYBE_UNUSED) +{ + cif->nfixedargs = nfixedargs; + return ffi_prep_cif_machdep_core (cif); +} + extern void ffi_call_SYSV(extended_cif *, unsigned, unsigned, unsigned *, void (*fn)(void)); extern void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, unsigned long, @@ -1366,7 +1386,7 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, void **avalue; ffi_type **arg_types; - long i, avn; + unsigned long i, avn, nfixedargs; ffi_cif *cif; ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64; @@ -1383,6 +1403,7 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, i = 0; avn = cif->nargs; + nfixedargs = cif->nfixedargs; arg_types = cif->arg_types; /* Grab the addresses of the arguments from the stack frame. */ @@ -1441,7 +1462,7 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, /* there are 13 64bit floating point registers */ - if (pfr < end_pfr) + if (pfr < end_pfr && i < nfixedargs) { double temp = pfr->d; pfr->f = (float) temp; @@ -1457,7 +1478,7 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, /* On the outgoing stack all values are aligned to 8 */ /* there are 13 64bit floating point registers */ - if (pfr < end_pfr) + if (pfr < end_pfr && i < nfixedargs) { avalue[i] = pfr; pfr++; @@ -1469,14 +1490,14 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: - if (pfr + 1 < end_pfr) + if (pfr + 1 < end_pfr && i + 1 < nfixedargs) { avalue[i] = pfr; pfr += 2; } else { - if (pfr < end_pfr) + if (pfr < end_pfr && i < nfixedargs) { /* Passed partly in f13 and partly on the stack. Move it all to the stack. */ diff --git a/src/powerpc/ffitarget.h b/src/powerpc/ffitarget.h index 3c9db49..2a7e9a1 100644 --- a/src/powerpc/ffitarget.h +++ b/src/powerpc/ffitarget.h @@ -106,6 +106,10 @@ typedef enum ffi_abi { #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 +#if defined (POWERPC) || defined (POWERPC_FREEBSD) +# define FFI_TARGET_SPECIFIC_VARIADIC 1 +# define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs +#endif /* For additional types like the below, take care about the order in ppc_closures.S. They must follow after the FFI_TYPE_LAST. */ diff --git a/testsuite/libffi.call/cls_double_va.c b/testsuite/libffi.call/cls_double_va.c index 43167b6..e077f92 100644 --- a/testsuite/libffi.call/cls_double_va.c +++ b/testsuite/libffi.call/cls_double_va.c @@ -38,7 +38,7 @@ int main (void) /* This printf call is variadic */ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint, - arg_types) == FFI_OK); + arg_types) == FFI_OK); args[0] = &format; args[1] = &doubleArg; @@ -49,12 +49,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); - CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL, code) == FFI_OK); - - res = ((int(*)(char*, double))(code))(format, doubleArg); + res = ((int(*)(char*, ...))(code))(format, doubleArg); /* { dg-output "\n7.0" } */ printf("res: %d\n", (int) res); /* { dg-output "\nres: 4" } */ diff --git a/testsuite/libffi.call/cls_longdouble_va.c b/testsuite/libffi.call/cls_longdouble_va.c index 7126b13..39b438b 100644 --- a/testsuite/libffi.call/cls_longdouble_va.c +++ b/testsuite/libffi.call/cls_longdouble_va.c @@ -38,7 +38,7 @@ int main (void) /* This printf call is variadic */ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint, - arg_types) == FFI_OK); + arg_types) == FFI_OK); args[0] = &format; args[1] = &ldArg; @@ -49,13 +49,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); - CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL, code) == FFI_OK); - - res = ((int(*)(char*, long double))(code))(format, ldArg); + res = ((int(*)(char*, ...))(code))(format, ldArg); /* { dg-output "\n7.0" } */ printf("res: %d\n", (int) res); /* { dg-output "\nres: 4" } */ -- Alan Modra Australia Development Lab, IBM