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>
This commit is contained in:
@@ -220,8 +220,8 @@ hfa_element_type (ffi_type *type, int nested)
|
|||||||
|
|
||||||
/* Perform machine dependent cif processing. */
|
/* Perform machine dependent cif processing. */
|
||||||
|
|
||||||
ffi_status
|
static ffi_status
|
||||||
ffi_prep_cif_machdep(ffi_cif *cif)
|
ffi_prep_cif_machdep_core(ffi_cif *cif)
|
||||||
{
|
{
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
@@ -271,6 +271,22 @@ ffi_prep_cif_machdep(ffi_cif *cif)
|
|||||||
return FFI_OK;
|
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 int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
|
extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -454,10 +470,11 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||||||
ffi_cif *cif;
|
ffi_cif *cif;
|
||||||
void **avalue;
|
void **avalue;
|
||||||
ffi_type **p_arg;
|
ffi_type **p_arg;
|
||||||
long i, avn, gpcount, fpcount;
|
long i, avn, gpcount, fpcount, nfixedargs;
|
||||||
|
|
||||||
cif = closure->cif;
|
cif = closure->cif;
|
||||||
avn = cif->nargs;
|
avn = cif->nargs;
|
||||||
|
nfixedargs = cif->nfixedargs;
|
||||||
avalue = alloca (avn * sizeof (void *));
|
avalue = alloca (avn * sizeof (void *));
|
||||||
|
|
||||||
/* If the structure return value is passed in memory get that location
|
/* 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,
|
|||||||
gpcount = fpcount = 0;
|
gpcount = fpcount = 0;
|
||||||
for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
|
for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
|
||||||
{
|
{
|
||||||
|
int named = i < nfixedargs;
|
||||||
switch ((*p_arg)->type)
|
switch ((*p_arg)->type)
|
||||||
{
|
{
|
||||||
case FFI_TYPE_SINT8:
|
case FFI_TYPE_SINT8:
|
||||||
@@ -491,7 +509,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
case FFI_TYPE_FLOAT:
|
||||||
if (gpcount < 8 && fpcount < 8)
|
if (named && gpcount < 8 && fpcount < 8)
|
||||||
{
|
{
|
||||||
fpreg *addr = &stack->fp_regs[fpcount++];
|
fpreg *addr = &stack->fp_regs[fpcount++];
|
||||||
float result;
|
float result;
|
||||||
@@ -505,7 +523,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_DOUBLE:
|
case FFI_TYPE_DOUBLE:
|
||||||
if (gpcount < 8 && fpcount < 8)
|
if (named && gpcount < 8 && fpcount < 8)
|
||||||
{
|
{
|
||||||
fpreg *addr = &stack->fp_regs[fpcount++];
|
fpreg *addr = &stack->fp_regs[fpcount++];
|
||||||
double result;
|
double result;
|
||||||
@@ -521,7 +539,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||||||
case FFI_TYPE_LONGDOUBLE:
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
if (gpcount & 1)
|
if (gpcount & 1)
|
||||||
gpcount++;
|
gpcount++;
|
||||||
if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
|
if (LDBL_MANT_DIG == 64 && named && gpcount < 8 && fpcount < 8)
|
||||||
{
|
{
|
||||||
fpreg *addr = &stack->fp_regs[fpcount++];
|
fpreg *addr = &stack->fp_regs[fpcount++];
|
||||||
__float80 result;
|
__float80 result;
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ typedef enum ffi_abi {
|
|||||||
#define FFI_TRAMPOLINE_SIZE 24 /* Really the following struct, which */
|
#define FFI_TRAMPOLINE_SIZE 24 /* Really the following struct, which */
|
||||||
/* can be interpreted as a C function */
|
/* can be interpreted as a C function */
|
||||||
/* descriptor: */
|
/* descriptor: */
|
||||||
|
#define FFI_TARGET_SPECIFIC_VARIADIC 1
|
||||||
|
#define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user