Commit 2204cfdd authored by Russ Cox's avatar Russ Cox

fix bug206.

delay calls to savex as long as possible.

R=ken
OCL=34535
CL=34546
parent 93b1dcbf
...@@ -898,7 +898,7 @@ stkof(Node *n) ...@@ -898,7 +898,7 @@ stkof(Node *n)
void void
sgen(Node *n, Node *ns, int32 w) sgen(Node *n, Node *ns, int32 w)
{ {
Node nodl, nodr; Node nodl, nodr, oldl, oldr, cx, oldcx;
int32 c, q, odst, osrc; int32 c, q, odst, osrc;
if(debug['g']) { if(debug['g']) {
...@@ -919,20 +919,30 @@ sgen(Node *n, Node *ns, int32 w) ...@@ -919,20 +919,30 @@ sgen(Node *n, Node *ns, int32 w)
osrc = stkof(n); osrc = stkof(n);
odst = stkof(ns); odst = stkof(ns);
nodreg(&nodl, types[tptr], D_DI);
nodreg(&nodr, types[tptr], D_SI);
if(n->ullman >= ns->ullman) { if(n->ullman >= ns->ullman) {
savex(D_SI, &nodr, &oldr, N, types[tptr]);
agen(n, &nodr); agen(n, &nodr);
regalloc(&nodr, types[tptr], &nodr); // mark nodr as live
savex(D_DI, &nodl, &oldl, N, types[tptr]);
agen(ns, &nodl); agen(ns, &nodl);
regfree(&nodr);
} else { } else {
savex(D_DI, &nodl, &oldl, N, types[tptr]);
agen(ns, &nodl); agen(ns, &nodl);
regalloc(&nodl, types[tptr], &nodl); // mark nodl as live
savex(D_SI, &nodr, &oldr, N, types[tptr]);
agen(n, &nodr); agen(n, &nodr);
regfree(&nodl);
} }
c = w % 8; // bytes c = w % 8; // bytes
q = w / 8; // quads q = w / 8; // quads
savex(D_CX, &cx, &oldcx, N, types[TINT64]);
// if we are copying forward on the stack and // if we are copying forward on the stack and
// the src and dst overlap, then reverse direction // the src and dst overlap, then reverse direction
if(osrc < odst && odst < osrc+w) { if(osrc < odst && odst < osrc+w) {
...@@ -982,4 +992,9 @@ sgen(Node *n, Node *ns, int32 w) ...@@ -982,4 +992,9 @@ sgen(Node *n, Node *ns, int32 w)
c--; c--;
} }
} }
restx(&nodl, &oldl);
restx(&nodr, &oldr);
restx(&cx, &oldcx);
} }
...@@ -95,6 +95,8 @@ int samaddr(Node*, Node*); ...@@ -95,6 +95,8 @@ int samaddr(Node*, Node*);
void naddr(Node*, Addr*); void naddr(Node*, Addr*);
void cgen_aret(Node*, Node*); void cgen_aret(Node*, Node*);
int cgen_inline(Node*, Node*); int cgen_inline(Node*, Node*);
void restx(Node*, Node*);
void savex(int, Node*, Node*, Node*, Type*);
/* /*
* gsubr.c * gsubr.c
......
...@@ -461,6 +461,8 @@ ret: ...@@ -461,6 +461,8 @@ ret:
int int
samereg(Node *a, Node *b) samereg(Node *a, Node *b)
{ {
if(a == N || b == N)
return 0;
if(a->op != OREGISTER) if(a->op != OREGISTER)
return 0; return 0;
if(b->op != OREGISTER) if(b->op != OREGISTER)
...@@ -481,11 +483,12 @@ samereg(Node *a, Node *b) ...@@ -481,11 +483,12 @@ samereg(Node *a, Node *b)
* according to op. * according to op.
*/ */
void void
dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx) dodiv(int op, Node *nl, Node *nr, Node *res)
{ {
int a; int a;
Node n3, n4; Node n3, n4;
Type *t; Type *t;
Node ax, dx, oldax, olddx;
t = nl->type; t = nl->type;
if(t->width == 1) { if(t->width == 1) {
...@@ -495,62 +498,73 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx) ...@@ -495,62 +498,73 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
t = types[TUINT32]; t = types[TUINT32];
} }
a = optoas(op, t); a = optoas(op, t);
ax->type = t;
dx->type = t;
regalloc(&n3, t, N); regalloc(&n3, t, N);
if(nl->ullman >= nr->ullman) { if(nl->ullman >= nr->ullman) {
cgen(nl, ax); savex(D_AX, &ax, &oldax, res, t);
if(!issigned[t->etype]) { cgen(nl, &ax);
nodconst(&n4, t, 0); regalloc(&ax, t, &ax); // mark ax live during cgen
gmove(&n4, dx);
} else
gins(optoas(OEXTEND, t), N, N);
cgen(nr, &n3); cgen(nr, &n3);
regfree(&ax);
} else { } else {
cgen(nr, &n3); cgen(nr, &n3);
cgen(nl, ax); savex(D_AX, &ax, &oldax, res, t);
if(!issigned[t->etype]) { cgen(nl, &ax);
nodconst(&n4, t, 0);
gmove(&n4, dx);
} else
gins(optoas(OEXTEND, t), N, N);
} }
savex(D_DX, &dx, &olddx, res, t);
if(!issigned[t->etype]) {
nodconst(&n4, t, 0);
gmove(&n4, &dx);
} else
gins(optoas(OEXTEND, t), N, N);
gins(a, &n3, N); gins(a, &n3, N);
regfree(&n3); regfree(&n3);
if(op == ODIV) if(op == ODIV)
gmove(ax, res); gmove(&ax, res);
else else
gmove(dx, res); gmove(&dx, res);
restx(&ax, &oldax);
restx(&dx, &olddx);
} }
static void /*
* register dr is one of the special ones (AX, CX, DI, SI, etc.).
* we need to use it. if it is already allocated as a temporary
* (r > 1; can only happen if a routine like sgen passed a
* special as cgen's res and then cgen used regalloc to reuse
* it as its own temporary), then move it for now to another
* register. caller must call restx to move it back.
* the move is not necessary if dr == res, because res is
* known to be dead.
*/
void
savex(int dr, Node *x, Node *oldx, Node *res, Type *t) savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
{ {
int r; int r;
r = reg[dr]; r = reg[dr];
nodreg(x, types[TINT64], dr);
// save current ax and dx if they are live // save current ax and dx if they are live
// and not the destination // and not the destination
memset(oldx, 0, sizeof *oldx); memset(oldx, 0, sizeof *oldx);
if(r > 0 && !samereg(x, res)) { nodreg(x, t, dr);
if(r > 1 && !samereg(x, res)) {
regalloc(oldx, types[TINT64], N); regalloc(oldx, types[TINT64], N);
x->type = types[TINT64];
gmove(x, oldx); gmove(x, oldx);
x->type = t;
oldx->ostk = r; // squirrel away old r value
reg[dr] = 1;
} }
regalloc(x, t, x);
} }
static void void
restx(Node *x, Node *oldx) restx(Node *x, Node *oldx)
{ {
regfree(x);
if(oldx->op != 0) { if(oldx->op != 0) {
x->type = types[TINT64]; x->type = types[TINT64];
reg[x->val.u.reg] = oldx->ostk;
gmove(oldx, x); gmove(oldx, x);
regfree(oldx); regfree(oldx);
} }
...@@ -564,8 +578,8 @@ restx(Node *x, Node *oldx) ...@@ -564,8 +578,8 @@ restx(Node *x, Node *oldx)
void void
cgen_div(int op, Node *nl, Node *nr, Node *res) cgen_div(int op, Node *nl, Node *nr, Node *res)
{ {
Node ax, dx, oldax, olddx;
Node n1, n2, n3, savl, savr; Node n1, n2, n3, savl, savr;
Node ax, dx, oldax, olddx;
int n, w, s, a; int n, w, s, a;
Magic m; Magic m;
...@@ -701,12 +715,12 @@ divbymul: ...@@ -701,12 +715,12 @@ divbymul:
if(op == OMOD) if(op == OMOD)
goto longmod; goto longmod;
savex(D_AX, &ax, &oldax, res, nl->type);
savex(D_DX, &dx, &olddx, res, nl->type);
regalloc(&n1, nl->type, N); regalloc(&n1, nl->type, N);
cgen(nl, &n1); // num -> reg(n1) cgen(nl, &n1); // num -> reg(n1)
savex(D_AX, &ax, &oldax, res, nl->type);
savex(D_DX, &dx, &olddx, res, nl->type);
nodconst(&n2, nl->type, m.um); nodconst(&n2, nl->type, m.um);
gmove(&n2, &ax); // const->ax gmove(&n2, &ax); // const->ax
...@@ -751,12 +765,12 @@ divbymul: ...@@ -751,12 +765,12 @@ divbymul:
if(op == OMOD) if(op == OMOD)
goto longmod; goto longmod;
savex(D_AX, &ax, &oldax, res, nl->type);
savex(D_DX, &dx, &olddx, res, nl->type);
regalloc(&n1, nl->type, N); regalloc(&n1, nl->type, N);
cgen(nl, &n1); // num -> reg(n1) cgen(nl, &n1); // num -> reg(n1)
savex(D_AX, &ax, &oldax, res, nl->type);
savex(D_DX, &dx, &olddx, res, nl->type);
nodconst(&n2, nl->type, m.sm); nodconst(&n2, nl->type, m.sm);
gmove(&n2, &ax); // const->ax gmove(&n2, &ax); // const->ax
...@@ -798,11 +812,7 @@ divbymul: ...@@ -798,11 +812,7 @@ divbymul:
longdiv: longdiv:
// division and mod using (slow) hardware instruction // division and mod using (slow) hardware instruction
savex(D_AX, &ax, &oldax, res, nl->type); dodiv(op, nl, nr, res);
savex(D_DX, &dx, &olddx, res, nl->type);
dodiv(op, nl, nr, res, &ax, &dx);
restx(&ax, &oldax);
restx(&dx, &olddx);
return; return;
longmod: longmod:
...@@ -979,7 +989,7 @@ void ...@@ -979,7 +989,7 @@ void
clearfat(Node *nl) clearfat(Node *nl)
{ {
uint32 w, c, q; uint32 w, c, q;
Node n1; Node n1, oldn1, ax, oldax;
/* clear a fat object */ /* clear a fat object */
if(debug['g']) if(debug['g'])
...@@ -989,10 +999,12 @@ clearfat(Node *nl) ...@@ -989,10 +999,12 @@ clearfat(Node *nl)
c = w % 8; // bytes c = w % 8; // bytes
q = w / 8; // quads q = w / 8; // quads
gconreg(AMOVQ, 0, D_AX); savex(D_DI, &n1, &oldn1, N, types[tptr]);
nodreg(&n1, types[tptr], D_DI);
agen(nl, &n1); agen(nl, &n1);
savex(D_AX, &ax, &oldax, N, types[tptr]);
gconreg(AMOVQ, 0, D_AX);
if(q >= 4) { if(q >= 4) {
gconreg(AMOVQ, q, D_CX); gconreg(AMOVQ, q, D_CX);
gins(AREP, N, N); // repeat gins(AREP, N, N); // repeat
...@@ -1012,6 +1024,9 @@ clearfat(Node *nl) ...@@ -1012,6 +1024,9 @@ clearfat(Node *nl)
gins(ASTOSB, N, N); // STOB AL,*(DI)+ gins(ASTOSB, N, N); // STOB AL,*(DI)+
c--; c--;
} }
restx(&n1, &oldn1);
restx(&ax, &oldax);
} }
int int
......
...@@ -192,8 +192,8 @@ afunclit(Addr *a) ...@@ -192,8 +192,8 @@ afunclit(Addr *a)
static int resvd[] = static int resvd[] =
{ {
// D_DI, // for movstring D_DI, // for movstring
// D_SI, // for movstring D_SI, // for movstring
D_AX, // for divide D_AX, // for divide
D_CX, // for shift D_CX, // for shift
......
...@@ -174,6 +174,3 @@ bugs/bug198.go:8: T is not a type ...@@ -174,6 +174,3 @@ bugs/bug198.go:8: T is not a type
bugs/bug198.go:8: too many arguments to return bugs/bug198.go:8: too many arguments to return
bugs/bug198.go:10: too many arguments to CALL bugs/bug198.go:10: too many arguments to CALL
BUG: errchk: compiler crashed BUG: errchk: compiler crashed
=========== bugs/bug206.go
BUG: bug206
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment