mirror of
https://github.com/partic2/libffi
synced 2026-11-09 17:47:19 +00:00
PowerPC bugfixes (#520)
* powerpc: Silence warnings about unused labels * powerpc: Fix a couple of comments * powerpc: Fix alignment after float structs * powerpc: Don't pad rvalues copied from FP regs * powerpc: Add missing check in struct alignment * powerpc: Support homogeneous long double structs
This commit is contained in:
committed by
Anthony Green
parent
25cf9cc4a5
commit
ea9b6639c6
+3
-2
@@ -121,8 +121,9 @@ ffi_call_int (ffi_cif *cif,
|
|||||||
# endif
|
# endif
|
||||||
/* The SYSV ABI returns a structure of up to 8 bytes in size
|
/* The SYSV ABI returns a structure of up to 8 bytes in size
|
||||||
left-padded in r3/r4, and the ELFv2 ABI similarly returns a
|
left-padded in r3/r4, and the ELFv2 ABI similarly returns a
|
||||||
structure of up to 8 bytes in size left-padded in r3. */
|
structure of up to 8 bytes in size left-padded in r3. But
|
||||||
if (rsize <= 8)
|
note that a structure of a single float is not paddded. */
|
||||||
|
if (rsize <= 8 && (cif->flags & FLAG_RETURNS_FP) == 0)
|
||||||
memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize);
|
memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+58
-25
@@ -63,10 +63,30 @@ ffi_prep_types_linux64 (ffi_abi abi)
|
|||||||
|
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
|
discover_homogeneous_aggregate (ffi_abi abi,
|
||||||
|
const ffi_type *t,
|
||||||
|
unsigned int *elnum)
|
||||||
{
|
{
|
||||||
switch (t->type)
|
switch (t->type)
|
||||||
{
|
{
|
||||||
|
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||||
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
|
/* 64-bit long doubles are equivalent to doubles. */
|
||||||
|
if ((abi & FFI_LINUX_LONG_DOUBLE_128) == 0)
|
||||||
|
{
|
||||||
|
*elnum = 1;
|
||||||
|
return FFI_TYPE_DOUBLE;
|
||||||
|
}
|
||||||
|
/* IBM extended precision values use unaligned pairs
|
||||||
|
of FPRs, but according to the ABI must be considered
|
||||||
|
distinct from doubles. They are also limited to a
|
||||||
|
maximum of four members in a homogeneous aggregate. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*elnum = 2;
|
||||||
|
return FFI_TYPE_LONGDOUBLE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
case FFI_TYPE_FLOAT:
|
case FFI_TYPE_FLOAT:
|
||||||
case FFI_TYPE_DOUBLE:
|
case FFI_TYPE_DOUBLE:
|
||||||
*elnum = 1;
|
*elnum = 1;
|
||||||
@@ -79,7 +99,7 @@ discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
|
|||||||
while (*el)
|
while (*el)
|
||||||
{
|
{
|
||||||
unsigned int el_elt, el_elnum = 0;
|
unsigned int el_elt, el_elnum = 0;
|
||||||
el_elt = discover_homogeneous_aggregate (*el, &el_elnum);
|
el_elt = discover_homogeneous_aggregate (abi, *el, &el_elnum);
|
||||||
if (el_elt == 0
|
if (el_elt == 0
|
||||||
|| (base_elt && base_elt != el_elt))
|
|| (base_elt && base_elt != el_elt))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -112,7 +132,7 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
|
|||||||
unsigned bytes;
|
unsigned bytes;
|
||||||
unsigned i, fparg_count = 0, intarg_count = 0;
|
unsigned i, fparg_count = 0, intarg_count = 0;
|
||||||
unsigned flags = cif->flags;
|
unsigned flags = cif->flags;
|
||||||
unsigned int elt, elnum;
|
unsigned elt, elnum, rtype;
|
||||||
|
|
||||||
#if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
|
#if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
|
||||||
/* If compiled without long double support.. */
|
/* If compiled without long double support.. */
|
||||||
@@ -138,7 +158,11 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Return value handling. */
|
/* Return value handling. */
|
||||||
switch (cif->rtype->type)
|
rtype = cif->rtype->type;
|
||||||
|
#if _CALL_ELF == 2
|
||||||
|
homogeneous:
|
||||||
|
#endif
|
||||||
|
switch (rtype)
|
||||||
{
|
{
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
@@ -164,19 +188,18 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
|
|||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
case FFI_TYPE_STRUCT:
|
||||||
#if _CALL_ELF == 2
|
#if _CALL_ELF == 2
|
||||||
elt = discover_homogeneous_aggregate (cif->rtype, &elnum);
|
elt = discover_homogeneous_aggregate (cif->abi, cif->rtype, &elnum);
|
||||||
if (elt)
|
if (elt)
|
||||||
{
|
{
|
||||||
if (elt == FFI_TYPE_DOUBLE)
|
flags |= FLAG_RETURNS_SMST;
|
||||||
flags |= FLAG_RETURNS_64BITS;
|
rtype = elt;
|
||||||
flags |= FLAG_RETURNS_FP | FLAG_RETURNS_SMST;
|
goto homogeneous;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
if (cif->rtype->size <= 16)
|
if (cif->rtype->size <= 16)
|
||||||
{
|
{
|
||||||
flags |= FLAG_RETURNS_SMST;
|
flags |= FLAG_RETURNS_SMST;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
intarg_count++;
|
intarg_count++;
|
||||||
flags |= FLAG_RETVAL_REFERENCE;
|
flags |= FLAG_RETVAL_REFERENCE;
|
||||||
@@ -224,7 +247,7 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
|
|||||||
intarg_count = FFI_ALIGN (intarg_count, align);
|
intarg_count = FFI_ALIGN (intarg_count, align);
|
||||||
}
|
}
|
||||||
intarg_count += ((*ptr)->size + 7) / 8;
|
intarg_count += ((*ptr)->size + 7) / 8;
|
||||||
elt = discover_homogeneous_aggregate (*ptr, &elnum);
|
elt = discover_homogeneous_aggregate (cif->abi, *ptr, &elnum);
|
||||||
if (elt)
|
if (elt)
|
||||||
{
|
{
|
||||||
fparg_count += elnum;
|
fparg_count += elnum;
|
||||||
@@ -391,7 +414,7 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||||||
valp rest;
|
valp rest;
|
||||||
valp next_arg;
|
valp next_arg;
|
||||||
|
|
||||||
/* 'fpr_base' points at the space for fpr3, and grows upwards as
|
/* 'fpr_base' points at the space for f1, and grows upwards as
|
||||||
we use FPR registers. */
|
we use FPR registers. */
|
||||||
valp fpr_base;
|
valp fpr_base;
|
||||||
unsigned int fparg_count;
|
unsigned int fparg_count;
|
||||||
@@ -492,7 +515,9 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||||||
/* Fall through. */
|
/* Fall through. */
|
||||||
#endif
|
#endif
|
||||||
case FFI_TYPE_DOUBLE:
|
case FFI_TYPE_DOUBLE:
|
||||||
|
#if _CALL_ELF != 2
|
||||||
do_double:
|
do_double:
|
||||||
|
#endif
|
||||||
double_tmp = **p_argv.d;
|
double_tmp = **p_argv.d;
|
||||||
if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
|
if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
|
||||||
{
|
{
|
||||||
@@ -511,7 +536,9 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
case FFI_TYPE_FLOAT:
|
||||||
|
#if _CALL_ELF != 2
|
||||||
do_float:
|
do_float:
|
||||||
|
#endif
|
||||||
double_tmp = **p_argv.f;
|
double_tmp = **p_argv.f;
|
||||||
if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
|
if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
|
||||||
{
|
{
|
||||||
@@ -548,9 +575,13 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||||||
if (align > 16)
|
if (align > 16)
|
||||||
align = 16;
|
align = 16;
|
||||||
if (align > 1)
|
if (align > 1)
|
||||||
next_arg.p = FFI_ALIGN (next_arg.p, align);
|
{
|
||||||
|
next_arg.p = FFI_ALIGN (next_arg.p, align);
|
||||||
|
if (next_arg.ul == gpr_end.ul)
|
||||||
|
next_arg.ul = rest.ul;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
elt = discover_homogeneous_aggregate (*ptr, &elnum);
|
elt = discover_homogeneous_aggregate (ecif->cif->abi, *ptr, &elnum);
|
||||||
if (elt)
|
if (elt)
|
||||||
{
|
{
|
||||||
#if _CALL_ELF == 2
|
#if _CALL_ELF == 2
|
||||||
@@ -576,11 +607,9 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||||||
fparg_count++;
|
fparg_count++;
|
||||||
}
|
}
|
||||||
while (--elnum != 0);
|
while (--elnum != 0);
|
||||||
if ((next_arg.p & 3) != 0)
|
if ((next_arg.p & 7) != 0)
|
||||||
{
|
if (++next_arg.f == gpr_end.f)
|
||||||
if (++next_arg.f == gpr_end.f)
|
next_arg.f = rest.f;
|
||||||
next_arg.f = rest.f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
do
|
do
|
||||||
@@ -813,7 +842,7 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
|
|||||||
if (align > 1)
|
if (align > 1)
|
||||||
pst = (unsigned long *) FFI_ALIGN ((size_t) pst, align);
|
pst = (unsigned long *) FFI_ALIGN ((size_t) pst, align);
|
||||||
}
|
}
|
||||||
elt = discover_homogeneous_aggregate (arg_types[i], &elnum);
|
elt = discover_homogeneous_aggregate (cif->abi, arg_types[i], &elnum);
|
||||||
if (elt)
|
if (elt)
|
||||||
{
|
{
|
||||||
#if _CALL_ELF == 2
|
#if _CALL_ELF == 2
|
||||||
@@ -915,7 +944,9 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
|
|||||||
/* Fall through. */
|
/* Fall through. */
|
||||||
#endif
|
#endif
|
||||||
case FFI_TYPE_DOUBLE:
|
case FFI_TYPE_DOUBLE:
|
||||||
|
#if _CALL_ELF != 2
|
||||||
do_double:
|
do_double:
|
||||||
|
#endif
|
||||||
/* On the outgoing stack all values are aligned to 8 */
|
/* On the outgoing stack all values are aligned to 8 */
|
||||||
/* there are 13 64bit floating point registers */
|
/* there are 13 64bit floating point registers */
|
||||||
|
|
||||||
@@ -930,7 +961,9 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
case FFI_TYPE_FLOAT:
|
||||||
|
#if _CALL_ELF != 2
|
||||||
do_float:
|
do_float:
|
||||||
|
#endif
|
||||||
if (pfr < end_pfr && i < nfixedargs)
|
if (pfr < end_pfr && i < nfixedargs)
|
||||||
{
|
{
|
||||||
/* Float values are stored as doubles in the
|
/* Float values are stored as doubles in the
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ ffi_closure_LINUX64:
|
|||||||
stfd %f12, -104+(11*8)(%r1)
|
stfd %f12, -104+(11*8)(%r1)
|
||||||
stfd %f13, -104+(12*8)(%r1)
|
stfd %f13, -104+(12*8)(%r1)
|
||||||
|
|
||||||
# load up the pointer to the saved fpr registers */
|
# load up the pointer to the saved fpr registers
|
||||||
addi %r8, %r1, -104
|
addi %r8, %r1, -104
|
||||||
|
|
||||||
# load up the pointer to the result storage
|
# load up the pointer to the result storage
|
||||||
|
|||||||
Reference in New Issue
Block a user