extend ffi_prepare_args for FFI_VFP (hard-float ABI), fixing an issue with passing VFP arguments in VFP registers and the stack, while at the same time not using all core registers.
This commit is contained in:
@@ -153,6 +153,76 @@ int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space)
|
|||||||
{
|
{
|
||||||
// make sure we are using FFI_VFP
|
// make sure we are using FFI_VFP
|
||||||
FFI_ASSERT(ecif->cif->abi == FFI_VFP);
|
FFI_ASSERT(ecif->cif->abi == FFI_VFP);
|
||||||
|
|
||||||
|
register unsigned int i, vi = 0;
|
||||||
|
register void **p_argv;
|
||||||
|
register char *argp, *regp, *eo_regp;
|
||||||
|
register ffi_type **p_arg;
|
||||||
|
char stack_used = 0;
|
||||||
|
char done_with_regs = 0;
|
||||||
|
char is_vfp_type;
|
||||||
|
|
||||||
|
/* the first 4 words on the stack are used for values passed in core
|
||||||
|
* registers. */
|
||||||
|
regp = stack;
|
||||||
|
eo_regp = argp = regp + 16;
|
||||||
|
|
||||||
|
|
||||||
|
/* if the function returns an FFI_TYPE_STRUCT in memory, that address is
|
||||||
|
* passed in r0 to the function */
|
||||||
|
if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
|
||||||
|
*(void **) regp = ecif->rvalue;
|
||||||
|
regp += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_argv = ecif->avalue;
|
||||||
|
|
||||||
|
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
|
||||||
|
(i != 0);
|
||||||
|
i--, p_arg++, p_argv++)
|
||||||
|
{
|
||||||
|
is_vfp_type = vfp_type_p (*p_arg);
|
||||||
|
|
||||||
|
/* Allocated in VFP registers. */
|
||||||
|
if(vi < ecif->cif->vfp_nargs && is_vfp_type)
|
||||||
|
{
|
||||||
|
char *vfp_slot = (char *)(vfp_space + ecif->cif->vfp_args[vi++]);
|
||||||
|
ffi_put_arg(p_arg, p_argv, vfp_slot);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Try allocating in core registers. */
|
||||||
|
else if (!done_with_regs && !is_vfp_type)
|
||||||
|
{
|
||||||
|
char *tregp = ffi_align(p_arg, regp);
|
||||||
|
size_t size = (*p_arg)->size;
|
||||||
|
size = (size < 4)? 4 : size; // pad
|
||||||
|
/* Check if there is space left in the aligned register area to place
|
||||||
|
* the argument */
|
||||||
|
if(tregp + size <= eo_regp)
|
||||||
|
{
|
||||||
|
regp = tregp + ffi_put_arg(p_arg, p_argv, tregp);
|
||||||
|
done_with_regs = (regp == argp);
|
||||||
|
// ensure we did not write into the stack area
|
||||||
|
FFI_ASSERT(regp <= argp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* In case there are no arguments in the stack area yet,
|
||||||
|
the argument is passed in the remaining core registers and on the
|
||||||
|
stack. */
|
||||||
|
else if (!stack_used)
|
||||||
|
{
|
||||||
|
stack_used = 1;
|
||||||
|
done_with_regs = 1;
|
||||||
|
argp = tregp + ffi_put_arg(p_arg, p_argv, tregp);
|
||||||
|
FFI_ASSERT(eo_regp < argp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Base case, arguments are passed on the stack */
|
||||||
|
stack_used = 1;
|
||||||
|
argp = ffi_align(p_arg, argp);
|
||||||
|
argp += ffi_put_arg(p_arg, p_argv, argp);
|
||||||
|
}
|
||||||
/* Indicate the VFP registers used. */
|
/* Indicate the VFP registers used. */
|
||||||
return ecif->cif->vfp_used;
|
return ecif->cif->vfp_used;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user