Fix allocation of struct in registers on ARM
Allocation of struct in core and/or VFP registers on ARM is made by manipulating the value stack to create 3 distinct zones: parameters allocated on stack, parameters of type struct allocated in core registers and parameters of type struct allocated in VFP registers. Parameters of primitive type can be in any zone. This commit change the order of the zones from stack, VFP, core to stack, core, VFP (from highest addresses to lowest ones) in order to correctly deal the situation when structures are allocated both in core and VFP registers.
This commit is contained in:
90
arm-gen.c
90
arm-gen.c
@ -826,7 +826,7 @@ void gfunc_call(int nb_args)
|
|||||||
int size, align, r, args_size, i, ncrn, ncprn, argno, vfp_argno;
|
int size, align, r, args_size, i, ncrn, ncprn, argno, vfp_argno;
|
||||||
signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
|
signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
|
||||||
SValue *before_stack = NULL; /* SValue before first on stack argument */
|
SValue *before_stack = NULL; /* SValue before first on stack argument */
|
||||||
SValue *before_vfpreg_hfa = NULL; /* SValue before first in VFP reg hfa argument */
|
SValue *before_creg = NULL; /* SValue before first argument of type struct in core register */
|
||||||
#ifdef TCC_ARM_HARDFLOAT
|
#ifdef TCC_ARM_HARDFLOAT
|
||||||
struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
|
struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
|
||||||
signed char vfp_plan[16];
|
signed char vfp_plan[16];
|
||||||
@ -865,12 +865,12 @@ void gfunc_call(int nb_args)
|
|||||||
(core or VFP) are free for the current argument, assign them to it, else
|
(core or VFP) are free for the current argument, assign them to it, else
|
||||||
allocate on stack with correct alignment. Whenever a structure is allocated
|
allocate on stack with correct alignment. Whenever a structure is allocated
|
||||||
in registers or on stack, it is always put on the stack at this stage. The
|
in registers or on stack, it is always put on the stack at this stage. The
|
||||||
stack is divided in 3 zones. The zone are, from low addresses to high
|
stack is divided in 3 zones. The zone are, from high addresses to low
|
||||||
addresses: structures to be loaded in core registers, structures to be
|
addresses: structures to be loaded in core registers, structures to be
|
||||||
loaded in VFP registers, argument allocated to stack. SValue's representing
|
loaded in VFP registers, argument allocated to stack. SValue's representing
|
||||||
structures in the first zone are moved just after the SValue pointed by
|
structures in the first zone are moved just after the SValue pointed by
|
||||||
before_vfpreg_hfa. SValue's representing structures in the second zone are
|
before_stack. SValue's representing structures in the second zone are
|
||||||
moved just after the SValue pointer by before_stack. */
|
moved just after the SValue pointer by before_creg. */
|
||||||
for(i = nb_args; i-- ;) {
|
for(i = nb_args; i-- ;) {
|
||||||
int j, assigned_vfpreg = 0;
|
int j, assigned_vfpreg = 0;
|
||||||
size = type_size(&vtop[-i].type, &align);
|
size = type_size(&vtop[-i].type, &align);
|
||||||
@ -892,14 +892,15 @@ void gfunc_call(int nb_args)
|
|||||||
if (assigned_vfpreg >= 0) {
|
if (assigned_vfpreg >= 0) {
|
||||||
vfp_plan[vfp_argno++]=TREG_F0 + assigned_vfpreg/2;
|
vfp_plan[vfp_argno++]=TREG_F0 + assigned_vfpreg/2;
|
||||||
if (hfa) {
|
if (hfa) {
|
||||||
/* before_stack can only have been set because all core registers
|
/* if before_creg is not set, it means that no parameter has been
|
||||||
are assigned, so no need to care about before_vfpreg_hfa if
|
* allocated in core register. This implied that no argument has
|
||||||
before_stack is set */
|
* been allocated on stack neither because a VFP was available for
|
||||||
if (before_stack) {
|
* this parameter. */
|
||||||
vrote(&vtop[-i], &vtop[-i] - before_stack);
|
if (before_creg) {
|
||||||
before_stack++;
|
/* before_creg already exists and we just update it */
|
||||||
} else if (!before_vfpreg_hfa)
|
vrote(&vtop[-i], &vtop[-i] - before_creg);
|
||||||
before_vfpreg_hfa = &vtop[-i-1];
|
before_creg++;
|
||||||
|
}
|
||||||
for (j = assigned_vfpreg; j <= end_reg; j++)
|
for (j = assigned_vfpreg; j <= end_reg; j++)
|
||||||
vfp_todo|=(1<<j);
|
vfp_todo|=(1<<j);
|
||||||
}
|
}
|
||||||
@ -907,10 +908,8 @@ void gfunc_call(int nb_args)
|
|||||||
} else {
|
} else {
|
||||||
if (!hfa)
|
if (!hfa)
|
||||||
vfp_argno++;
|
vfp_argno++;
|
||||||
/* No need to update before_stack as no more hfa can be allocated in
|
if (!before_stack)
|
||||||
VFP regs */
|
before_stack = &vtop[-i-1];
|
||||||
if (!before_vfpreg_hfa)
|
|
||||||
before_vfpreg_hfa = &vtop[-i-1];
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -919,14 +918,14 @@ void gfunc_call(int nb_args)
|
|||||||
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 && assigned_vfpreg != -1)) {
|
if (ncrn + size/4 <= 4 || (ncrn < 4 && assigned_vfpreg != -1)) {
|
||||||
/* Either there is HFA in VFP registers, or there is arguments on stack,
|
if (before_stack) {
|
||||||
it cannot be both. Hence either before_stack already points after
|
vrote(&vtop[-i], &vtop[-i] - before_stack);
|
||||||
the slot where the vtop[-i] SValue is moved, or before_stack will not
|
before_stack++;
|
||||||
be used */
|
/* before_stack can only have been set because all VFP registers are
|
||||||
if (before_vfpreg_hfa) {
|
* assigned, so no need to care about before_creg if before_stack is
|
||||||
vrote(&vtop[-i], &vtop[-i] - before_vfpreg_hfa);
|
* set since no more argument will be allocated in a VFP register. */
|
||||||
before_vfpreg_hfa++;
|
} else if (!before_creg)
|
||||||
}
|
before_creg = &vtop[-i];
|
||||||
for (j = ncrn; j < 4 && j < ncrn + size / 4; j++)
|
for (j = ncrn; j < 4 && j < ncrn + size / 4; j++)
|
||||||
todo|=(1<<j);
|
todo|=(1<<j);
|
||||||
ncrn+=size/4;
|
ncrn+=size/4;
|
||||||
@ -935,11 +934,10 @@ void gfunc_call(int nb_args)
|
|||||||
if (!before_stack)
|
if (!before_stack)
|
||||||
before_stack = &vtop[-i-1];
|
before_stack = &vtop[-i-1];
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ncrn = 4;
|
ncrn = 4;
|
||||||
/* No need to set before_vfpreg_hfa if not set since there will no
|
/* No need to set before_creg since it has already been set when
|
||||||
longer be any structure assigned to core registers */
|
* assigning argument to core registers */
|
||||||
if (!before_stack)
|
if (!before_stack)
|
||||||
before_stack = &vtop[-i-1];
|
before_stack = &vtop[-i-1];
|
||||||
break;
|
break;
|
||||||
@ -1092,24 +1090,6 @@ void gfunc_call(int nb_args)
|
|||||||
}
|
}
|
||||||
save_regs(keep); /* save used temporary registers */
|
save_regs(keep); /* save used temporary registers */
|
||||||
keep++;
|
keep++;
|
||||||
if(ncrn) {
|
|
||||||
int nb_regs=0;
|
|
||||||
if (ncrn>4)
|
|
||||||
ncrn=4;
|
|
||||||
todo&=((1<<ncrn)-1);
|
|
||||||
if(todo) {
|
|
||||||
int i;
|
|
||||||
o(0xE8BD0000|todo);
|
|
||||||
for(i=0;i<4;i++)
|
|
||||||
if(todo&(1<<i)) {
|
|
||||||
vpushi(0);
|
|
||||||
vtop->r=i;
|
|
||||||
keep++;
|
|
||||||
nb_regs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
args_size-=nb_regs*4;
|
|
||||||
}
|
|
||||||
if(vfp_todo) {
|
if(vfp_todo) {
|
||||||
int nb_fregs=0;
|
int nb_fregs=0;
|
||||||
|
|
||||||
@ -1129,6 +1109,24 @@ save_regs(keep); /* save used temporary registers */
|
|||||||
args_size-=nb_fregs*4;
|
args_size-=nb_fregs*4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(ncrn) {
|
||||||
|
int nb_regs=0;
|
||||||
|
if (ncrn>4)
|
||||||
|
ncrn=4;
|
||||||
|
todo&=((1<<ncrn)-1);
|
||||||
|
if(todo) {
|
||||||
|
int i;
|
||||||
|
o(0xE8BD0000|todo);
|
||||||
|
for(i=0;i<4;i++)
|
||||||
|
if(todo&(1<<i)) {
|
||||||
|
vpushi(0);
|
||||||
|
vtop->r=i;
|
||||||
|
keep++;
|
||||||
|
nb_regs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args_size-=nb_regs*4;
|
||||||
|
}
|
||||||
vrotb(keep);
|
vrotb(keep);
|
||||||
gcall_or_jmp(0);
|
gcall_or_jmp(0);
|
||||||
if (args_size)
|
if (args_size)
|
||||||
|
|||||||
Reference in New Issue
Block a user