summaryrefslogtreecommitdiff
path: root/src/cmd/6g/ggen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/6g/ggen.c')
-rw-r--r--src/cmd/6g/ggen.c236
1 files changed, 168 insertions, 68 deletions
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index 9fad9f7f1..c385798f2 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -9,59 +9,110 @@
#include "gg.h"
#include "opt.h"
-static Prog* appendp(Prog*, int, int, vlong, int, vlong);
+static Prog *appendpp(Prog*, int, int, vlong, int, vlong);
+static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax);
void
-defframe(Prog *ptxt, Bvec *bv)
+defframe(Prog *ptxt)
{
- int i, j;
- uint32 frame;
+ uint32 frame, ax;
Prog *p;
+ vlong hi, lo;
+ NodeList *l;
+ Node *n;
// fill in argument size
ptxt->to.offset = rnd(curfn->type->argwid, widthptr);
// fill in final stack size
ptxt->to.offset <<= 32;
- frame = rnd(stksize+maxarg, widthptr);
+ frame = rnd(stksize+maxarg, widthreg);
ptxt->to.offset |= frame;
-
- // insert code to clear pointered part of the frame,
- // so that garbage collector only sees initialized values
+
+ // insert code to zero ambiguously live variables
+ // so that the garbage collector only sees initialized values
// when it looks for pointers.
p = ptxt;
- if(stkzerosize >= 8*widthptr) {
- p = appendp(p, AMOVQ, D_CONST, 0, D_AX, 0);
- p = appendp(p, AMOVQ, D_CONST, stkzerosize/widthptr, D_CX, 0);
- p = appendp(p, ALEAQ, D_SP+D_INDIR, frame-stkzerosize, D_DI, 0);
- p = appendp(p, AREP, D_NONE, 0, D_NONE, 0);
- appendp(p, ASTOSQ, D_NONE, 0, D_NONE, 0);
- } else {
- j = (stkptrsize - stkzerosize)/widthptr * 2;
- for(i=0; i<stkzerosize; i+=widthptr) {
- if(bvget(bv, j) || bvget(bv, j+1))
- p = appendp(p, AMOVQ, D_CONST, 0, D_SP+D_INDIR, frame-stkzerosize+i);
- j += 2;
+ lo = hi = 0;
+ ax = 0;
+ // iterate through declarations - they are sorted in decreasing xoffset order.
+ for(l=curfn->dcl; l != nil; l = l->next) {
+ n = l->n;
+ if(!n->needzero)
+ continue;
+ if(n->class != PAUTO)
+ fatal("needzero class %d", n->class);
+ if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0)
+ fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset);
+
+ if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthreg) {
+ // merge with range we already have
+ lo = n->xoffset;
+ continue;
}
+ // zero old range
+ p = zerorange(p, frame, lo, hi, &ax);
+
+ // set new range
+ hi = n->xoffset + n->type->width;
+ lo = n->xoffset;
}
+ // zero final range
+ zerorange(p, frame, lo, hi, &ax);
}
static Prog*
-appendp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset)
+zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax)
+{
+ vlong cnt, i;
+
+ cnt = hi - lo;
+ if(cnt == 0)
+ return p;
+ if(*ax == 0) {
+ p = appendpp(p, AMOVQ, D_CONST, 0, D_AX, 0);
+ *ax = 1;
+ }
+ if(cnt % widthreg != 0) {
+ // should only happen with nacl
+ if(cnt % widthptr != 0)
+ fatal("zerorange count not a multiple of widthptr %d", cnt);
+ p = appendpp(p, AMOVL, D_AX, 0, D_SP+D_INDIR, frame+lo);
+ lo += widthptr;
+ cnt -= widthptr;
+ }
+ if(cnt <= 4*widthreg) {
+ for(i = 0; i < cnt; i += widthreg) {
+ p = appendpp(p, AMOVQ, D_AX, 0, D_SP+D_INDIR, frame+lo+i);
+ }
+ } else if(!nacl && (cnt <= 128*widthreg)) {
+ p = appendpp(p, leaptr, D_SP+D_INDIR, frame+lo, D_DI, 0);
+ p = appendpp(p, ADUFFZERO, D_NONE, 0, D_ADDR, 2*(128-cnt/widthreg));
+ p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
+ } else {
+ p = appendpp(p, AMOVQ, D_CONST, cnt/widthreg, D_CX, 0);
+ p = appendpp(p, leaptr, D_SP+D_INDIR, frame+lo, D_DI, 0);
+ p = appendpp(p, AREP, D_NONE, 0, D_NONE, 0);
+ p = appendpp(p, ASTOSQ, D_NONE, 0, D_NONE, 0);
+ }
+ return p;
+}
+
+static Prog*
+appendpp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset)
{
Prog *q;
-
- q = mal(sizeof(*q));
- clearp(q);
- q->as = as;
- q->lineno = p->lineno;
- q->from.type = ftype;
- q->from.offset = foffset;
- q->to.type = ttype;
- q->to.offset = toffset;
- q->link = p->link;
- p->link = q;
- return q;
+ q = mal(sizeof(*q));
+ clearp(q);
+ q->as = as;
+ q->lineno = p->lineno;
+ q->from.type = ftype;
+ q->from.offset = foffset;
+ q->to.type = ttype;
+ q->to.offset = toffset;
+ q->link = p->link;
+ p->link = q;
+ return q;
}
// Sweep the prog list to mark any used nodes.
@@ -69,13 +120,13 @@ void
markautoused(Prog* p)
{
for (; p; p = p->link) {
- if (p->as == ATYPE)
+ if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
continue;
- if (p->from.type == D_AUTO && p->from.node)
+ if (p->from.node)
p->from.node->used = 1;
- if (p->to.type == D_AUTO && p->to.node)
+ if (p->to.node)
p->to.node->used = 1;
}
}
@@ -91,6 +142,16 @@ fixautoused(Prog *p)
*lp = p->link;
continue;
}
+ if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.node->used) {
+ // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
+ // VARDEFs are interspersed with other code, and a jump might be using the
+ // VARDEF as a target. Replace with a no-op instead. A later pass will remove
+ // the no-ops.
+ p->to.type = D_NONE;
+ p->to.node = N;
+ p->as = ANOP;
+ continue;
+ }
if (p->from.type == D_AUTO && p->from.node)
p->from.offset += p->from.node->stkdelta;
@@ -179,17 +240,21 @@ ginscall(Node *f, int proc)
case 1: // call in new proc (go)
case 2: // deferred call (defer)
- nodreg(&reg, types[TINT64], D_CX);
- if(flag_largemodel) {
- regalloc(&r1, f->type, f);
+ nodconst(&con, types[TINT64], argsize(f->type));
+ if(widthptr == 4) {
+ nodreg(&r1, types[TINT32], D_CX);
gmove(f, &r1);
- gins(APUSHQ, &r1, N);
- regfree(&r1);
+ nodreg(&reg, types[TINT64], D_CX);
+ nodconst(&r1, types[TINT64], 32);
+ gins(ASHLQ, &r1, &reg);
+ gins(AORQ, &con, &reg);
+ gins(APUSHQ, &reg, N);
} else {
- gins(APUSHQ, f, N);
+ nodreg(&reg, types[TINT64], D_CX);
+ gmove(f, &reg);
+ gins(APUSHQ, &reg, N);
+ gins(APUSHQ, &con, N);
}
- nodconst(&con, types[TINT32], argsize(f->type));
- gins(APUSHQ, &con, N);
if(proc == 1)
ginscall(newproc, 0);
else {
@@ -197,12 +262,16 @@ ginscall(Node *f, int proc)
fatal("hasdefer=0 but has defer");
ginscall(deferproc, 0);
}
+ nodreg(&reg, types[TINT64], D_CX);
gins(APOPQ, N, &reg);
- gins(APOPQ, N, &reg);
+ if(widthptr == 8)
+ gins(APOPQ, N, &reg);
if(proc == 2) {
nodreg(&reg, types[TINT64], D_AX);
gins(ATESTQ, &reg, &reg);
- patch(gbranch(AJNE, T, -1), retpc);
+ p = gbranch(AJEQ, T, +1);
+ cgen_ret(N);
+ patch(p, pc);
}
break;
}
@@ -386,11 +455,11 @@ cgen_aret(Node *n, Node *res)
if(res->op != OREGISTER) {
regalloc(&nod2, types[tptr], res);
- gins(ALEAQ, &nod1, &nod2);
- gins(AMOVQ, &nod2, res);
+ gins(leaptr, &nod1, &nod2);
+ gins(movptr, &nod2, res);
regfree(&nod2);
} else
- gins(ALEAQ, &nod1, res);
+ gins(leaptr, &nod1, res);
}
/*
@@ -402,15 +471,15 @@ cgen_ret(Node *n)
{
Prog *p;
- genlist(n->list); // copy out args
- if(hasdefer || curfn->exit) {
- gjmp(retpc);
- return;
- }
+ if(n != N)
+ genlist(n->list); // copy out args
+ if(hasdefer)
+ ginscall(deferreturn, 0);
+ genlist(curfn->exit);
p = gins(ARET, N, N);
- if(n->op == ORETJMP) {
+ if(n != N && n->op == ORETJMP) {
p->to.type = D_EXTERN;
- p->to.sym = n->left->sym;
+ p->to.sym = linksym(n->left->sym);
}
}
@@ -633,6 +702,18 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
}
p2 = P;
+ if(nacl) {
+ // Native Client does not relay the divide-by-zero trap
+ // to the executing program, so we must insert a check
+ // for ourselves.
+ nodconst(&n4, t, 0);
+ gins(optoas(OCMP, t), &n3, &n4);
+ p1 = gbranch(optoas(ONE, t), T, +1);
+ if(panicdiv == N)
+ panicdiv = sysfunc("panicdivide");
+ ginscall(panicdiv, -1);
+ patch(p1, pc);
+ }
if(check) {
nodconst(&n4, t, -1);
gins(optoas(OCMP, t), &n3, &n4);
@@ -1025,13 +1106,13 @@ void
clearfat(Node *nl)
{
int64 w, c, q;
- Node n1, oldn1, ax, oldax;
+ Node n1, oldn1, ax, oldax, di, z;
+ Prog *p;
/* clear a fat object */
if(debug['g'])
dump("\nclearfat", nl);
-
w = nl->type->width;
// Avoid taking the address for simple enough types.
if(componentgen(N, nl))
@@ -1044,22 +1125,41 @@ clearfat(Node *nl)
agen(nl, &n1);
savex(D_AX, &ax, &oldax, N, types[tptr]);
- gconreg(AMOVQ, 0, D_AX);
+ gconreg(AMOVL, 0, D_AX);
- if(q >= 4) {
- gconreg(AMOVQ, q, D_CX);
+ if(q > 128 || (q >= 4 && nacl)) {
+ gconreg(movptr, q, D_CX);
gins(AREP, N, N); // repeat
gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
+ } else if(q >= 4) {
+ p = gins(ADUFFZERO, N, N);
+ p->to.type = D_ADDR;
+ p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
+ // 2 and 128 = magic constants: see ../../pkg/runtime/asm_amd64.s
+ p->to.offset = 2*(128-q);
} else
while(q > 0) {
gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
q--;
}
- if(c >= 4) {
- gconreg(AMOVQ, c, D_CX);
- gins(AREP, N, N); // repeat
- gins(ASTOSB, N, N); // STOB AL,*(DI)+
+ z = ax;
+ di = n1;
+ if(w >= 8 && c >= 4) {
+ di.op = OINDREG;
+ di.type = z.type = types[TINT64];
+ p = gins(AMOVQ, &z, &di);
+ p->to.scale = 1;
+ p->to.offset = c-8;
+ } else if(c >= 4) {
+ di.op = OINDREG;
+ di.type = z.type = types[TINT32];
+ p = gins(AMOVL, &z, &di);
+ if(c > 4) {
+ p = gins(AMOVL, &z, &di);
+ p->to.scale = 1;
+ p->to.offset = c-4;
+ }
} else
while(c > 0) {
gins(ASTOSB, N, N); // STOB AL,*(DI)+
@@ -1095,9 +1195,9 @@ expandchecks(Prog *firstp)
p->link = p1;
p1->lineno = p->lineno;
p2->lineno = p->lineno;
- p1->loc = 9999;
- p2->loc = 9999;
- p->as = ACMPQ;
+ p1->pc = 9999;
+ p2->pc = 9999;
+ p->as = cmpptr;
p->to.type = D_CONST;
p->to.offset = 0;
p1->as = AJNE;