aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/tcctest.c29
-rw-r--r--x86_64-gen.c39
2 files changed, 40 insertions, 28 deletions
diff --git a/tests/tcctest.c b/tests/tcctest.c
index afb0825..fcd9822 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -1122,25 +1122,30 @@ struct structa1 struct_assign_test2(struct structa1 s1, int t)
void struct_assign_test(void)
{
- struct structa1 lsta1, lsta2;
+ struct S {
+ struct structa1 lsta1, lsta2;
+ int i;
+ } s, *ps;
+ ps = &s;
+ ps->i = 4;
#if 0
printf("struct_assign_test:\n");
- lsta1.f1 = 1;
- lsta1.f2 = 2;
- printf("%d %d\n", lsta1.f1, lsta1.f2);
- lsta2 = lsta1;
- printf("%d %d\n", lsta2.f1, lsta2.f2);
+ s.lsta1.f1 = 1;
+ s.lsta1.f2 = 2;
+ printf("%d %d\n", s.lsta1.f1, s.lsta1.f2);
+ s.lsta2 = s.lsta1;
+ printf("%d %d\n", s.lsta2.f1, s.lsta2.f2);
#else
- lsta2.f1 = 1;
- lsta2.f2 = 2;
+ s.lsta2.f1 = 1;
+ s.lsta2.f2 = 2;
#endif
- struct_assign_test1(lsta2, 3, 4.5);
+ struct_assign_test1(ps->lsta2, 3, 4.5);
- printf("before call: %d %d\n", lsta2.f1, lsta2.f2);
- lsta2 = struct_assign_test2(lsta2, 4);
- printf("after call: %d %d\n", lsta2.f1, lsta2.f2);
+ printf("before call: %d %d\n", s.lsta2.f1, s.lsta2.f2);
+ ps->lsta2 = struct_assign_test2(ps->lsta2, ps->i);
+ printf("after call: %d %d\n", ps->lsta2.f1, ps->lsta2.f2);
static struct {
void (*elem)();
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 */