Support special calling convention for runtime ABI
Add infrastructure to support special calling convention for runtime ABI function no matter what is the current calling convention. This involve 2 changes: - behave as per base standard in gfunc_call - move result back in VFP register in gen_cvt_itof1
This commit is contained in:
49
arm-gen.c
49
arm-gen.c
@ -746,7 +746,6 @@ static void gcall_or_jmp(int is_jmp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TCC_ARM_HARDFLOAT
|
|
||||||
/* Return whether a structure is an homogeneous float aggregate or not.
|
/* Return whether a structure is an homogeneous float aggregate or not.
|
||||||
The answer is true if all the elements of the structure are of the same
|
The answer is true if all the elements of the structure are of the same
|
||||||
primitive float type and there is less than 4 elements.
|
primitive float type and there is less than 4 elements.
|
||||||
@ -811,7 +810,32 @@ int assign_vfpreg(struct avail_regs *avregs, int align, int size)
|
|||||||
avregs->first_free_reg = -1;
|
avregs->first_free_reg = -1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns whether all params need to be passed in core registers or not.
|
||||||
|
This is the case for function part of the runtime ABI. */
|
||||||
|
int floats_in_core_regs(SValue *sval)
|
||||||
|
{
|
||||||
|
if (!sval->sym)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (sval->sym->v) {
|
||||||
|
case TOK___floatundisf:
|
||||||
|
case TOK___floatundidf:
|
||||||
|
case TOK___fixunssfdi:
|
||||||
|
case TOK___fixunsdfdi:
|
||||||
|
#ifndef TCC_ARM_VFP
|
||||||
|
case TOK___fixunsxfdi:
|
||||||
#endif
|
#endif
|
||||||
|
case TOK___floatdisf:
|
||||||
|
case TOK___floatdidf:
|
||||||
|
case TOK___fixsfdi:
|
||||||
|
case TOK___fixdfdi:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the number of registers needed to return the struct, or 0 if
|
/* Return the number of registers needed to return the struct, or 0 if
|
||||||
returning via struct pointer. */
|
returning via struct pointer. */
|
||||||
@ -885,7 +909,7 @@ struct plan {
|
|||||||
definition of union reg_class).
|
definition of union reg_class).
|
||||||
|
|
||||||
nb_args: number of parameters of the function for which a call is generated
|
nb_args: number of parameters of the function for which a call is generated
|
||||||
variadic: whether the function is a variadic function or not
|
corefloat: whether to pass float via core registers or not
|
||||||
plan: the structure where the overall assignment is recorded
|
plan: the structure where the overall assignment is recorded
|
||||||
todo: a bitmap that record which core registers hold a parameter
|
todo: a bitmap that record which core registers hold a parameter
|
||||||
|
|
||||||
@ -894,15 +918,13 @@ struct plan {
|
|||||||
Note: this function allocated an array in plan->pplans with tcc_malloc. It
|
Note: this function allocated an array in plan->pplans with tcc_malloc. It
|
||||||
is the responsability of the caller to free this array once used (ie not
|
is the responsability of the caller to free this array once used (ie not
|
||||||
before copy_params). */
|
before copy_params). */
|
||||||
static int assign_regs(int nb_args, int variadic, struct plan *plan, int *todo)
|
static int assign_regs(int nb_args, int corefloat, struct plan *plan, int *todo)
|
||||||
{
|
{
|
||||||
int i, size, align;
|
int i, size, align;
|
||||||
int ncrn /* next core register number */, nsaa /* next stacked argument address*/;
|
int ncrn /* next core register number */, nsaa /* next stacked argument address*/;
|
||||||
int plan_nb = 0;
|
int plan_nb = 0;
|
||||||
struct param_plan pplan;
|
struct param_plan pplan;
|
||||||
#ifdef TCC_ARM_HARDFLOAT
|
|
||||||
struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
|
struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
|
||||||
#endif
|
|
||||||
|
|
||||||
ncrn = nsaa = 0;
|
ncrn = nsaa = 0;
|
||||||
*todo = 0;
|
*todo = 0;
|
||||||
@ -916,8 +938,7 @@ static int assign_regs(int nb_args, int variadic, struct plan *plan, int *todo)
|
|||||||
case VT_FLOAT:
|
case VT_FLOAT:
|
||||||
case VT_DOUBLE:
|
case VT_DOUBLE:
|
||||||
case VT_LDOUBLE:
|
case VT_LDOUBLE:
|
||||||
#ifdef TCC_ARM_HARDFLOAT
|
if (!corefloat) {
|
||||||
if (!variadic) {
|
|
||||||
int is_hfa = 0; /* Homogeneous float aggregate */
|
int is_hfa = 0; /* Homogeneous float aggregate */
|
||||||
|
|
||||||
if (is_float(vtop[-i].type.t)
|
if (is_float(vtop[-i].type.t)
|
||||||
@ -937,7 +958,6 @@ static int assign_regs(int nb_args, int variadic, struct plan *plan, int *todo)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
ncrn = (ncrn + (align-1)/4) & -(align/4);
|
ncrn = (ncrn + (align-1)/4) & -(align/4);
|
||||||
size = (size + 3) & -4;
|
size = (size + 3) & -4;
|
||||||
if (ncrn + size/4 <= 4 || (ncrn < 4 && start_vfpreg != -1)) {
|
if (ncrn + size/4 <= 4 || (ncrn < 4 && start_vfpreg != -1)) {
|
||||||
@ -1149,11 +1169,14 @@ static int copy_params(int nb_args, struct plan *plan, int todo)
|
|||||||
void gfunc_call(int nb_args)
|
void gfunc_call(int nb_args)
|
||||||
{
|
{
|
||||||
int r, args_size;
|
int r, args_size;
|
||||||
int variadic;
|
int variadic, corefloat = 1;
|
||||||
int todo;
|
int todo;
|
||||||
struct plan plan;
|
struct plan plan;
|
||||||
|
|
||||||
|
#ifdef TCC_ARM_HARDFLOAT
|
||||||
variadic = (vtop[-nb_args].type.ref->c == FUNC_ELLIPSIS);
|
variadic = (vtop[-nb_args].type.ref->c == FUNC_ELLIPSIS);
|
||||||
|
corefloat = variadic || floats_in_core_regs(&vtop[-nb_args]);
|
||||||
|
#endif
|
||||||
/* cannot let cpu flags if other instruction are generated. Also avoid leaving
|
/* cannot let cpu flags if other instruction are generated. Also avoid leaving
|
||||||
VT_JMP anywhere except on the top of the stack because it would complicate
|
VT_JMP anywhere except on the top of the stack because it would complicate
|
||||||
the code generator. */
|
the code generator. */
|
||||||
@ -1161,7 +1184,7 @@ void gfunc_call(int nb_args)
|
|||||||
if (r == VT_CMP || (r & ~1) == VT_JMP)
|
if (r == VT_CMP || (r & ~1) == VT_JMP)
|
||||||
gv(RC_INT);
|
gv(RC_INT);
|
||||||
|
|
||||||
args_size = assign_regs(nb_args, variadic, &plan, &todo);
|
args_size = assign_regs(nb_args, corefloat, &plan, &todo);
|
||||||
|
|
||||||
#ifdef TCC_ARM_EABI
|
#ifdef TCC_ARM_EABI
|
||||||
if (args_size & 7) { /* Stack must be 8 byte aligned at fct call for EABI */
|
if (args_size & 7) { /* Stack must be 8 byte aligned at fct call for EABI */
|
||||||
@ -1180,11 +1203,7 @@ void gfunc_call(int nb_args)
|
|||||||
gadd_sp(args_size); /* pop all parameters passed on the stack */
|
gadd_sp(args_size); /* pop all parameters passed on the stack */
|
||||||
#ifdef TCC_ARM_EABI
|
#ifdef TCC_ARM_EABI
|
||||||
#ifdef TCC_ARM_VFP
|
#ifdef TCC_ARM_VFP
|
||||||
#ifdef TCC_ARM_HARDFLOAT
|
if(corefloat && is_float(vtop->type.ref->type.t)) {
|
||||||
if(variadic && is_float(vtop->type.ref->type.t)) {
|
|
||||||
#else
|
|
||||||
rf(is_float(vtop->type.ref->type.t)) {
|
|
||||||
#endif
|
|
||||||
if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) {
|
if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) {
|
||||||
o(0xEE000A10); /*vmov s0, r0 */
|
o(0xEE000A10); /*vmov s0, r0 */
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user