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:
Thomas Preud'homme 2013-11-05 17:50:30 +08:00
parent cf02f920c1
commit b7d017dec8

View File

@ -826,7 +826,7 @@ void gfunc_call(int nb_args)
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}};
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
struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
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
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
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
loaded in VFP registers, argument allocated to stack. SValue's representing
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
moved just after the SValue pointer by before_stack. */
before_stack. SValue's representing structures in the second zone are
moved just after the SValue pointer by before_creg. */
for(i = nb_args; i-- ;) {
int j, assigned_vfpreg = 0;
size = type_size(&vtop[-i].type, &align);
@ -892,14 +892,15 @@ void gfunc_call(int nb_args)
if (assigned_vfpreg >= 0) {
vfp_plan[vfp_argno++]=TREG_F0 + assigned_vfpreg/2;
if (hfa) {
/* before_stack can only have been set because all core registers
are assigned, so no need to care about before_vfpreg_hfa if
before_stack is set */
if (before_stack) {
vrote(&vtop[-i], &vtop[-i] - before_stack);
before_stack++;
} else if (!before_vfpreg_hfa)
before_vfpreg_hfa = &vtop[-i-1];
/* if before_creg is not set, it means that no parameter has been
* allocated in core register. This implied that no argument has
* been allocated on stack neither because a VFP was available for
* this parameter. */
if (before_creg) {
/* before_creg already exists and we just update it */
vrote(&vtop[-i], &vtop[-i] - before_creg);
before_creg++;
}
for (j = assigned_vfpreg; j <= end_reg; j++)
vfp_todo|=(1<<j);
}
@ -907,10 +908,8 @@ void gfunc_call(int nb_args)
} else {
if (!hfa)
vfp_argno++;
/* No need to update before_stack as no more hfa can be allocated in
VFP regs */
if (!before_vfpreg_hfa)
before_vfpreg_hfa = &vtop[-i-1];
if (!before_stack)
before_stack = &vtop[-i-1];
break;
}
}
@ -919,14 +918,14 @@ void gfunc_call(int nb_args)
ncrn = (ncrn + (align-1)/4) & -(align/4);
size = (size + 3) & -4;
if (ncrn + size/4 <= 4 || (ncrn < 4 && assigned_vfpreg != -1)) {
/* Either there is HFA in VFP registers, or there is arguments on stack,
it cannot be both. Hence either before_stack already points after
the slot where the vtop[-i] SValue is moved, or before_stack will not
be used */
if (before_vfpreg_hfa) {
vrote(&vtop[-i], &vtop[-i] - before_vfpreg_hfa);
before_vfpreg_hfa++;
}
if (before_stack) {
vrote(&vtop[-i], &vtop[-i] - before_stack);
before_stack++;
/* before_stack can only have been set because all VFP registers are
* assigned, so no need to care about before_creg if before_stack is
* set since no more argument will be allocated in a VFP register. */
} else if (!before_creg)
before_creg = &vtop[-i];
for (j = ncrn; j < 4 && j < ncrn + size / 4; j++)
todo|=(1<<j);
ncrn+=size/4;
@ -935,11 +934,10 @@ void gfunc_call(int nb_args)
if (!before_stack)
before_stack = &vtop[-i-1];
}
}
else {
} else {
ncrn = 4;
/* No need to set before_vfpreg_hfa if not set since there will no
longer be any structure assigned to core registers */
/* No need to set before_creg since it has already been set when
* assigning argument to core registers */
if (!before_stack)
before_stack = &vtop[-i-1];
break;
@ -1092,24 +1090,6 @@ void gfunc_call(int nb_args)
}
save_regs(keep); /* save used temporary registers */
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) {
int nb_fregs=0;
@ -1129,6 +1109,24 @@ save_regs(keep); /* save used temporary registers */
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);
gcall_or_jmp(0);
if (args_size)