tccgen: arm/i386: save_reg_upstack

tccgen.c:gv() when loading long long from lvalue, before
was saving all registers which caused problems in the arm
function call register parameter preparation, as with

    void foo(long long y, int x);
    int main(void)
    {
      unsigned int *xx[1], x;
      unsigned long long *yy[1], y;
      foo(**yy, **xx);
      return 0;
    }

Now only the modified register is saved if necessary,
as in this case where it is used to store the result
of the post-inc:

        long long *p, v, **pp;
        v = 1;
        p = &v;
        p[0]++;
        printf("another long long spill test : %lld\n", *p);

i386-gen.c :
- found a similar problem with TOK_UMULL caused by the
  vstack juggle in tccgen:gen_opl()
  (bug seen only when using EBX as 4th register)
This commit is contained in:
grischka 2016-10-04 17:36:51 +02:00
parent 1c4cf18556
commit b691585785
5 changed files with 42 additions and 23 deletions

View File

@ -1177,7 +1177,8 @@ again:
} }
} }
/* second pass to restore registers that were saved on stack by accident */ /* second pass to restore registers that were saved on stack by accident.
Maybe redundant after the "lvalue_save" patch in tccgen.c:gv() */
if (++pass < 2) if (++pass < 2)
goto again; goto again;

View File

@ -848,6 +848,8 @@ ST_FUNC void gen_opi(int op)
fr = vtop[0].r; fr = vtop[0].r;
vtop--; vtop--;
save_reg(TREG_EDX); save_reg(TREG_EDX);
/* save EAX too if used otherwise */
save_reg_upstack(TREG_EAX, 1);
if (op == TOK_UMULL) { if (op == TOK_UMULL) {
o(0xf7); /* mul fr */ o(0xf7); /* mul fr */
o(0xe0 + fr); o(0xe0 + fr);

1
tcc.h
View File

@ -1295,6 +1295,7 @@ ST_FUNC void lexpand_nr(void);
#endif #endif
ST_FUNC void vpushv(SValue *v); ST_FUNC void vpushv(SValue *v);
ST_FUNC void save_reg(int r); ST_FUNC void save_reg(int r);
ST_FUNC void save_reg_upstack(int r, int n);
ST_FUNC int get_reg(int rc); ST_FUNC int get_reg(int rc);
ST_FUNC void save_regs(int n); ST_FUNC void save_regs(int n);
ST_FUNC void gaddrof(void); ST_FUNC void gaddrof(void);

View File

@ -533,17 +533,35 @@ static void vdup(void)
vpushv(vtop); vpushv(vtop);
} }
/* save registers up to (vtop - n) stack entry */
ST_FUNC void save_regs(int n)
{
SValue *p, *p1;
for(p = vstack, p1 = vtop - n; p <= p1; p++)
save_reg(p->r);
}
/* save r to the memory stack, and mark it as being free */ /* save r to the memory stack, and mark it as being free */
ST_FUNC void save_reg(int r) ST_FUNC void save_reg(int r)
{
save_reg_upstack(r, 0);
}
/* save r to the memory stack, and mark it as being free,
if seen up to (vtop - n) stack entry */
ST_FUNC void save_reg_upstack(int r, int n)
{ {
int l, saved, size, align; int l, saved, size, align;
SValue *p, sv; SValue *p, *p1, sv;
CType *type; CType *type;
if ((r &= VT_VALMASK) >= VT_CONST)
return;
/* modify all stack values */ /* modify all stack values */
saved = 0; saved = 0;
l = 0; l = 0;
for(p=vstack;p<=vtop;p++) { for(p = vstack, p1 = vtop - n; p <= p1; p++) {
if ((p->r & VT_VALMASK) == r || if ((p->r & VT_VALMASK) == r ||
((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) { ((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) {
/* must save value on stack if not already done */ /* must save value on stack if not already done */
@ -659,20 +677,6 @@ ST_FUNC int get_reg(int rc)
return -1; return -1;
} }
/* save registers up to (vtop - n) stack entry */
ST_FUNC void save_regs(int n)
{
int r;
SValue *p, *p1;
p1 = vtop - n;
for(p = vstack;p <= p1; p++) {
r = p->r & VT_VALMASK;
if (r < VT_CONST) {
save_reg(r);
}
}
}
/* move register 's' (of type 't') to 'r', and flush previous value of r to memory /* move register 's' (of type 't') to 'r', and flush previous value of r to memory
if needed */ if needed */
static void move_reg(int r, int s, int t) static void move_reg(int r, int s, int t)
@ -859,13 +863,17 @@ ST_FUNC int gv(int rc)
vpushi(ll >> 32); /* second word */ vpushi(ll >> 32); /* second word */
} else } else
#endif #endif
if (r >= VT_CONST || /* XXX: test to VT_CONST incorrect ? */ if (vtop->r & VT_LVAL) {
(vtop->r & VT_LVAL)) {
/* We do not want to modifier the long long /* We do not want to modifier the long long
pointer here, so the safest (and less pointer here, so the safest (and less
efficient) is to save all the other registers efficient) is to save all the other registers
in the stack. XXX: totally inefficient. */ in the stack. XXX: totally inefficient. */
#if 0
save_regs(1); save_regs(1);
#else
/* lvalue_save: save only if used further down the stack */
save_reg_upstack(vtop->r, 1);
#endif
/* load from memory */ /* load from memory */
vtop->type.t = load_type; vtop->type.t = load_type;
load(r, vtop); load(r, vtop);

View File

@ -1953,6 +1953,11 @@ long long int value(struct S *v)
return ((long long int)v->item); return ((long long int)v->item);
} }
long long llfunc2(long long x, long long y, int z)
{
return x * y * z;
}
void longlong_test(void) void longlong_test(void)
{ {
long long a, b, c; long long a, b, c;
@ -1999,15 +2004,17 @@ void longlong_test(void)
} }
lloptest(0x80000000, 0); lloptest(0x80000000, 0);
/* another long long spill test */
{ {
long long *p, v; long long *p, v, **pp;
v = 1; v = 1;
p = &v; p = &v;
p[0]++; p[0]++;
printf("%lld\n", *p); printf("another long long spill test : %lld\n", *p);
} pp = &p;
v = llfunc2(**pp, **pp, ia);
printf("a long long function (arm-)reg-args test : %lld\n", v);
}
a = 68719476720LL; a = 68719476720LL;
b = 4294967295LL; b = 4294967295LL;
printf("%d %d %d %d\n", a > b, a < b, a >= b, a <= b); printf("%d %d %d %d\n", a > b, a < b, a >= b, a <= b);