diff options
Diffstat (limited to 'src/cmd/6g/ggen.c')
-rw-r--r-- | src/cmd/6g/ggen.c | 236 |
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(®, 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(®, types[TINT64], D_CX); + nodconst(&r1, types[TINT64], 32); + gins(ASHLQ, &r1, ®); + gins(AORQ, &con, ®); + gins(APUSHQ, ®, N); } else { - gins(APUSHQ, f, N); + nodreg(®, types[TINT64], D_CX); + gmove(f, ®); + gins(APUSHQ, ®, 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(®, types[TINT64], D_CX); gins(APOPQ, N, ®); - gins(APOPQ, N, ®); + if(widthptr == 8) + gins(APOPQ, N, ®); if(proc == 2) { nodreg(®, types[TINT64], D_AX); gins(ATESTQ, ®, ®); - 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; |