aboutsummaryrefslogtreecommitdiff
path: root/x86_64-gen.c
diff options
context:
space:
mode:
Diffstat (limited to 'x86_64-gen.c')
-rw-r--r--x86_64-gen.c39
1 files changed, 23 insertions, 16 deletions
diff --git a/x86_64-gen.c b/x86_64-gen.c
index 0b0e69e..49cfdd1 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -820,7 +820,6 @@ static const uint8_t arg_regs[REGN] = {
void gfunc_call(int nb_args)
{
int size, align, r, args_size, i;
- SValue *orig_vtop;
int nb_reg_args = 0;
int nb_sse_args = 0;
int sse_reg, gen_reg;
@@ -845,7 +844,6 @@ void gfunc_call(int nb_args)
/* for struct arguments, we need to call memcpy and the function
call breaks register passing arguments we are preparing.
So, we process arguments which will be passed by stack first. */
- orig_vtop = vtop;
gen_reg = nb_reg_args;
sse_reg = nb_sse_args;
@@ -861,6 +859,14 @@ void gfunc_call(int nb_args)
}
for(i = 0; i < nb_args; i++) {
+ /* Swap argument to top, it will possibly be changed here,
+ and might use more temps. All arguments must remain on the
+ stack, so that get_reg can correctly evict some of them onto
+ stack. We could use also use a vrott(nb_args) at the end
+ of this loop, but this seems faster. */
+ SValue tmp = vtop[0];
+ vtop[0] = vtop[-i];
+ vtop[-i] = tmp;
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
size = type_size(&vtop->type, &align);
/* align to stack align size */
@@ -872,18 +878,9 @@ void gfunc_call(int nb_args)
r = get_reg(RC_INT);
orex(1, r, 0, 0x89); /* mov %rsp, r */
o(0xe0 + REG_VALUE(r));
- {
- /* following code breaks vtop[1], vtop[2], and vtop[3] */
- SValue tmp1 = vtop[1];
- SValue tmp2 = vtop[2];
- SValue tmp3 = vtop[3];
- vset(&vtop->type, r | VT_LVAL, 0);
- vswap();
- vstore();
- vtop[1] = tmp1;
- vtop[2] = tmp2;
- vtop[3] = tmp3;
- }
+ vset(&vtop->type, r | VT_LVAL, 0);
+ vswap();
+ vstore();
args_size += size;
} else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
gv(RC_ST0);
@@ -913,10 +910,14 @@ void gfunc_call(int nb_args)
args_size += 8;
}
}
- vtop--;
+
+ /* And swap the argument back to it's original position. */
+ tmp = vtop[0];
+ vtop[0] = vtop[-i];
+ vtop[-i] = tmp;
}
- vtop = orig_vtop;
+ /* XXX This should be superfluous. */
save_regs(0); /* save used temporary registers */
/* then, we prepare register passing arguments.
@@ -953,6 +954,12 @@ void gfunc_call(int nb_args)
vtop--;
}
+ /* We shouldn't have many operands on the stack anymore, but the
+ call address itself is still there, and it might be in %eax
+ (or edx/ecx) currently, which the below writes would clobber.
+ So evict all remaining operands here. */
+ save_regs(0);
+
/* Copy R10 and R11 into RDX and RCX, respectively */
if (nb_reg_args > 2) {
o(0xd2894c); /* mov %r10, %rdx */