Skip to content

Commit 11de69d

Browse files
author
Sergei Trofimovich
committed
ia64: fix variadic function closures with FP arguments
libffi test framework already flagged failures as: ``` FAIL: libffi.call/cls_double_va.c -W -Wall -Wno-psabi -O0 output pattern test, is 7.0 res: 4 0.0 res: 4 ? should match 7.0 ?es: 4 ?.0 res: 4 ``` Failure happens here at ```c // testsuite/libffi.call/cls_double_va.c ... char* format = "%.1f\n"; double doubleArg = 7; ... CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL, code) == FFI_OK); res = ((int(*)(char*, ...))(code))(format, doubleArg); ``` libffi expects 'doubleArg' to be located in 'f9' (second FP argument) but gcc placed it to 'r33' (second GR). ia64 software [1] manual described argument passing ABI in "8.5.2 Register Parameters" as: """ If an actual parameter is known to correspond to a floating-point formal parameter, the following rules apply: a) The actual parameter is passed in the next available floating-point parameter register, if one is available. Floating-point parameter registers are allocated as needed from the range f8-f15, starting with f8. b) If all available floating-point parameter registers have been used, the actual parameter is passed in the appropriate general register(s). (This case can occur only as a result of homogeneous floating-point aggregates, described below.) If a floating-point actual parameter is known to correspond to a variable-argument specification in the formal parameter list, the following rule applies: c) The actual parameter is passed in the appropriate general register(s). If the compiler cannot determine, at the point of call, whether the corresponding formal parameter is a varargs parameter, it must generate code that satisfies both of the above conditions. (The compiler’s determination may be based on prototype declarations, language standard assumptions, analysis, or other user options or information.) """ We have [c] case here and gcc uses only GR for parameter passing. The change binds known variadic arguments ro GRs instead of FPs as those are always expected to be initialized for all variadic call types. This fixes all 10 failures on ia64-unknown-linux-gnu: ``` === libffi Summary === -# of expected passes 1945 -# of unexpected failures 10 + +# of expected passes 1955 ``` [1]: https://www.intel.com/content/dam/www/public/us/en/documents/guides/itanium-software-runtime-architecture-guide.pdf Signed-off-by: Sergei Trofimovich <slyfox@gentoo.org>
1 parent 9429968 commit 11de69d

File tree

2 files changed

+26
-7
lines changed

2 files changed

+26
-7
lines changed

src/ia64/ffi.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ hfa_element_type (ffi_type *type, int nested)
220220

221221
/* Perform machine dependent cif processing. */
222222

223-
ffi_status
224-
ffi_prep_cif_machdep(ffi_cif *cif)
223+
static ffi_status
224+
ffi_prep_cif_machdep_core(ffi_cif *cif)
225225
{
226226
int flags;
227227

@@ -271,6 +271,22 @@ ffi_prep_cif_machdep(ffi_cif *cif)
271271
return FFI_OK;
272272
}
273273

274+
ffi_status
275+
ffi_prep_cif_machdep(ffi_cif *cif)
276+
{
277+
cif->nfixedargs = cif->nargs;
278+
return ffi_prep_cif_machdep_core(cif);
279+
}
280+
281+
ffi_status
282+
ffi_prep_cif_machdep_var(ffi_cif *cif,
283+
unsigned int nfixedargs,
284+
unsigned int ntotalargs MAYBE_UNUSED)
285+
{
286+
cif->nfixedargs = nfixedargs;
287+
return ffi_prep_cif_machdep_core(cif);
288+
}
289+
274290
extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
275291

276292
void
@@ -454,10 +470,11 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
454470
ffi_cif *cif;
455471
void **avalue;
456472
ffi_type **p_arg;
457-
long i, avn, gpcount, fpcount;
473+
long i, avn, gpcount, fpcount, nfixedargs;
458474

459475
cif = closure->cif;
460476
avn = cif->nargs;
477+
nfixedargs = cif->nfixedargs;
461478
avalue = alloca (avn * sizeof (void *));
462479

463480
/* If the structure return value is passed in memory get that location
@@ -468,6 +485,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
468485
gpcount = fpcount = 0;
469486
for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
470487
{
488+
int named = i < nfixedargs;
471489
switch ((*p_arg)->type)
472490
{
473491
case FFI_TYPE_SINT8:
@@ -491,7 +509,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
491509
break;
492510

493511
case FFI_TYPE_FLOAT:
494-
if (gpcount < 8 && fpcount < 8)
512+
if (named && gpcount < 8 && fpcount < 8)
495513
{
496514
fpreg *addr = &stack->fp_regs[fpcount++];
497515
float result;
@@ -505,7 +523,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
505523
break;
506524

507525
case FFI_TYPE_DOUBLE:
508-
if (gpcount < 8 && fpcount < 8)
526+
if (named && gpcount < 8 && fpcount < 8)
509527
{
510528
fpreg *addr = &stack->fp_regs[fpcount++];
511529
double result;
@@ -521,7 +539,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
521539
case FFI_TYPE_LONGDOUBLE:
522540
if (gpcount & 1)
523541
gpcount++;
524-
if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
542+
if (LDBL_MANT_DIG == 64 && named && gpcount < 8 && fpcount < 8)
525543
{
526544
fpreg *addr = &stack->fp_regs[fpcount++];
527545
__float80 result;

src/ia64/ffitarget.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ typedef enum ffi_abi {
5050
#define FFI_TRAMPOLINE_SIZE 24 /* Really the following struct, which */
5151
/* can be interpreted as a C function */
5252
/* descriptor: */
53+
#define FFI_TARGET_SPECIFIC_VARIADIC 1
54+
#define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs
5355

5456
#endif
55-

0 commit comments

Comments
 (0)