diff --git a/arm-gen.c b/arm-gen.c index eccfdd8..c9d4e55 100644 --- a/arm-gen.c +++ b/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; 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<4) - ncrn=4; - todo&=((1<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<r=i; + keep++; + nb_regs++; + } + } + args_size-=nb_regs*4; + } vrotb(keep); gcall_or_jmp(0); if (args_size)