void
sgen(Node *n, Node *ns, int32 w)
{
- Node nodl, nodr;
+ Node nodl, nodr, oldl, oldr, cx, oldcx;
int32 c, q, odst, osrc;
if(debug['g']) {
osrc = stkof(n);
odst = stkof(ns);
- nodreg(&nodl, types[tptr], D_DI);
- nodreg(&nodr, types[tptr], D_SI);
if(n->ullman >= ns->ullman) {
+ savex(D_SI, &nodr, &oldr, N, types[tptr]);
agen(n, &nodr);
+
+ regalloc(&nodr, types[tptr], &nodr); // mark nodr as live
+ savex(D_DI, &nodl, &oldl, N, types[tptr]);
agen(ns, &nodl);
+ regfree(&nodr);
} else {
+ savex(D_DI, &nodl, &oldl, N, types[tptr]);
agen(ns, &nodl);
+
+ regalloc(&nodl, types[tptr], &nodl); // mark nodl as live
+ savex(D_SI, &nodr, &oldr, N, types[tptr]);
agen(n, &nodr);
+ regfree(&nodl);
}
c = w % 8; // bytes
q = w / 8; // quads
+ savex(D_CX, &cx, &oldcx, N, types[TINT64]);
+
// if we are copying forward on the stack and
// the src and dst overlap, then reverse direction
if(osrc < odst && odst < osrc+w) {
c--;
}
}
+
+
+ restx(&nodl, &oldl);
+ restx(&nodr, &oldr);
+ restx(&cx, &oldcx);
}
int
samereg(Node *a, Node *b)
{
+ if(a == N || b == N)
+ return 0;
if(a->op != OREGISTER)
return 0;
if(b->op != OREGISTER)
* according to op.
*/
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;
Node n3, n4;
Type *t;
+ Node ax, dx, oldax, olddx;
t = nl->type;
if(t->width == 1) {
t = types[TUINT32];
}
a = optoas(op, t);
- ax->type = t;
- dx->type = t;
regalloc(&n3, t, N);
if(nl->ullman >= nr->ullman) {
- cgen(nl, ax);
- if(!issigned[t->etype]) {
- nodconst(&n4, t, 0);
- gmove(&n4, dx);
- } else
- gins(optoas(OEXTEND, t), N, N);
+ savex(D_AX, &ax, &oldax, res, t);
+ cgen(nl, &ax);
+ regalloc(&ax, t, &ax); // mark ax live during cgen
cgen(nr, &n3);
+ regfree(&ax);
} else {
cgen(nr, &n3);
- cgen(nl, ax);
- if(!issigned[t->etype]) {
- nodconst(&n4, t, 0);
- gmove(&n4, dx);
- } else
- gins(optoas(OEXTEND, t), N, N);
+ savex(D_AX, &ax, &oldax, res, t);
+ cgen(nl, &ax);
}
+ 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);
regfree(&n3);
if(op == ODIV)
- gmove(ax, res);
+ gmove(&ax, res);
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)
{
int r;
r = reg[dr];
- nodreg(x, types[TINT64], dr);
// save current ax and dx if they are live
// and not the destination
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);
+ x->type = types[TINT64];
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)
{
- regfree(x);
-
if(oldx->op != 0) {
x->type = types[TINT64];
+ reg[x->val.u.reg] = oldx->ostk;
gmove(oldx, x);
regfree(oldx);
}
void
cgen_div(int op, Node *nl, Node *nr, Node *res)
{
- Node ax, dx, oldax, olddx;
Node n1, n2, n3, savl, savr;
+ Node ax, dx, oldax, olddx;
int n, w, s, a;
Magic m;
if(op == OMOD)
goto longmod;
- savex(D_AX, &ax, &oldax, res, nl->type);
- savex(D_DX, &dx, &olddx, res, nl->type);
-
regalloc(&n1, nl->type, N);
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);
gmove(&n2, &ax); // const->ax
if(op == OMOD)
goto longmod;
- savex(D_AX, &ax, &oldax, res, nl->type);
- savex(D_DX, &dx, &olddx, res, nl->type);
-
regalloc(&n1, nl->type, N);
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);
gmove(&n2, &ax); // const->ax
longdiv:
// division and mod using (slow) hardware instruction
- savex(D_AX, &ax, &oldax, res, nl->type);
- savex(D_DX, &dx, &olddx, res, nl->type);
- dodiv(op, nl, nr, res, &ax, &dx);
- restx(&ax, &oldax);
- restx(&dx, &olddx);
+ dodiv(op, nl, nr, res);
return;
longmod:
clearfat(Node *nl)
{
uint32 w, c, q;
- Node n1;
+ Node n1, oldn1, ax, oldax;
/* clear a fat object */
if(debug['g'])
c = w % 8; // bytes
q = w / 8; // quads
- gconreg(AMOVQ, 0, D_AX);
- nodreg(&n1, types[tptr], D_DI);
+ savex(D_DI, &n1, &oldn1, N, types[tptr]);
agen(nl, &n1);
+ savex(D_AX, &ax, &oldax, N, types[tptr]);
+ gconreg(AMOVQ, 0, D_AX);
+
if(q >= 4) {
gconreg(AMOVQ, q, D_CX);
gins(AREP, N, N); // repeat
gins(ASTOSB, N, N); // STOB AL,*(DI)+
c--;
}
+
+ restx(&n1, &oldn1);
+ restx(&ax, &oldax);
}
int