diff options
author | Michael Stapelberg <stapelberg@debian.org> | 2014-06-19 09:23:02 +0200 |
---|---|---|
committer | Michael Stapelberg <stapelberg@debian.org> | 2014-06-19 09:23:02 +0200 |
commit | 8fcc691d6fa80c9ddf38bf0d34b803bab0e421d5 (patch) | |
tree | ba71646a10b518372d110532d86fcf0b98edc14f /src/cmd/6g | |
parent | 3bb719bbf3cdb97b3901f3baaa2da9d02a5c3cdb (diff) | |
parent | 8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 (diff) | |
download | golang-8fcc691d6fa80c9ddf38bf0d34b803bab0e421d5.tar.gz |
Merge tag 'upstream/1.3' into debian-sid
Upstream version 1.3
Diffstat (limited to 'src/cmd/6g')
-rw-r--r-- | src/cmd/6g/cgen.c | 100 | ||||
-rw-r--r-- | src/cmd/6g/galign.c | 28 | ||||
-rw-r--r-- | src/cmd/6g/gg.h | 49 | ||||
-rw-r--r-- | src/cmd/6g/ggen.c | 236 | ||||
-rw-r--r-- | src/cmd/6g/gobj.c | 260 | ||||
-rw-r--r-- | src/cmd/6g/gsubr.c | 104 | ||||
-rw-r--r-- | src/cmd/6g/list.c | 364 | ||||
-rw-r--r-- | src/cmd/6g/opt.h | 1 | ||||
-rw-r--r-- | src/cmd/6g/peep.c | 26 | ||||
-rw-r--r-- | src/cmd/6g/prog.c | 7 | ||||
-rw-r--r-- | src/cmd/6g/reg.c | 253 |
11 files changed, 567 insertions, 861 deletions
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index ada2baa81..4dd505b08 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -247,6 +247,7 @@ cgen(Node *n, Node *res) case OOR: case OXOR: case OADD: + case OADDPTR: case OMUL: a = optoas(n->op, nl->type); if(a == AIMULB) { @@ -813,6 +814,7 @@ agen(Node *n, Node *res) // The generated code is just going to panic, so it need not // be terribly efficient. See issue 3670. tempname(&n1, n->type); + gvardef(&n1); clearfat(&n1); regalloc(&n2, types[tptr], res); gins(ALEAQ, &n1, &n2); @@ -1060,6 +1062,12 @@ bgen(Node *n, int true, int likely, Prog *to) } nr = N; + while(n->op == OCONVNOP) { + n = n->left; + if(n->ninit != nil) + genlist(n->ninit); + } + switch(n->op) { default: def: @@ -1337,6 +1345,8 @@ sgen(Node *n, Node *ns, int64 w) { Node nodl, nodr, nodsi, noddi, cx, oldcx, tmp; vlong c, q, odst, osrc; + NodeList *l; + Prog *p; if(debug['g']) { print("\nsgen w=%lld\n", w); @@ -1349,6 +1359,13 @@ sgen(Node *n, Node *ns, int64 w) if(w < 0) fatal("sgen copy %lld", w); + + // If copying .args, that's all the results, so record definition sites + // for them for the liveness analysis. + if(ns->op == ONAME && strcmp(ns->sym->name, ".args") == 0) + for(l = curfn->dcl; l != nil; l = l->next) + if(l->n->class == PPARAMOUT) + gvardef(l->n); // Avoid taking the address for simple enough types. if(componentgen(n, ns)) @@ -1380,11 +1397,16 @@ sgen(Node *n, Node *ns, int64 w) if(n->ullman >= ns->ullman) { agenr(n, &nodr, N); + if(ns->op == ONAME) + gvardef(ns); agenr(ns, &nodl, N); } else { + if(ns->op == ONAME) + gvardef(ns); agenr(ns, &nodl, N); agenr(n, &nodr, N); } + nodreg(&noddi, types[tptr], D_DI); nodreg(&nodsi, types[tptr], D_SI); gmove(&nodl, &noddi); @@ -1403,23 +1425,23 @@ sgen(Node *n, Node *ns, int64 w) // reverse direction gins(ASTD, N, N); // set direction flag if(c > 0) { - gconreg(AADDQ, w-1, D_SI); - gconreg(AADDQ, w-1, D_DI); + gconreg(addptr, w-1, D_SI); + gconreg(addptr, w-1, D_DI); - gconreg(AMOVQ, c, D_CX); + gconreg(movptr, c, D_CX); gins(AREP, N, N); // repeat gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)- } if(q > 0) { if(c > 0) { - gconreg(AADDQ, -7, D_SI); - gconreg(AADDQ, -7, D_DI); + gconreg(addptr, -7, D_SI); + gconreg(addptr, -7, D_DI); } else { - gconreg(AADDQ, w-8, D_SI); - gconreg(AADDQ, w-8, D_DI); + gconreg(addptr, w-8, D_SI); + gconreg(addptr, w-8, D_DI); } - gconreg(AMOVQ, q, D_CX); + gconreg(movptr, q, D_CX); gins(AREP, N, N); // repeat gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)- } @@ -1427,23 +1449,48 @@ sgen(Node *n, Node *ns, int64 w) gins(ACLD, N, N); } else { // normal direction - if(q >= 4) { - gconreg(AMOVQ, q, D_CX); + if(q > 128 || (nacl && q >= 4)) { + gconreg(movptr, q, D_CX); gins(AREP, N, N); // repeat gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+ + } else if (q >= 4) { + p = gins(ADUFFCOPY, N, N); + p->to.type = D_ADDR; + p->to.sym = linksym(pkglookup("duffcopy", runtimepkg)); + // 14 and 128 = magic constants: see ../../pkg/runtime/asm_amd64.s + p->to.offset = 14*(128-q); } else while(q > 0) { gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+ q--; } - - if(c >= 4) { - gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+ - c -= 4; - } - while(c > 0) { - gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+ - c--; + // copy the remaining c bytes + if(w < 4 || c <= 1 || (odst < osrc && osrc < odst+w)) { + while(c > 0) { + gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+ + c--; + } + } else if(w < 8 || c <= 4) { + nodsi.op = OINDREG; + noddi.op = OINDREG; + nodsi.type = types[TINT32]; + noddi.type = types[TINT32]; + if(c > 4) { + nodsi.xoffset = 0; + noddi.xoffset = 0; + gmove(&nodsi, &noddi); + } + nodsi.xoffset = c-4; + noddi.xoffset = c-4; + gmove(&nodsi, &noddi); + } else { + nodsi.op = OINDREG; + noddi.op = OINDREG; + nodsi.type = types[TINT64]; + noddi.type = types[TINT64]; + nodsi.xoffset = c-8; + noddi.xoffset = c-8; + gmove(&nodsi, &noddi); } } @@ -1513,7 +1560,7 @@ componentgen(Node *nr, Node *nl) fatal("componentgen: not a TFIELD: %lT", t); fldcount++; } - if(fldcount == 0 || fldcount > 3) + if(fldcount == 0 || fldcount > 4) goto no; break; @@ -1538,10 +1585,19 @@ componentgen(Node *nr, Node *nl) freer = 1; } } + + // nl and nr are 'cadable' which basically means they are names (variables) now. + // If they are the same variable, don't generate any code, because the + // VARDEF we generate will mark the old value as dead incorrectly. + // (And also the assignments are useless.) + if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr) + goto yes; switch(nl->type->etype) { case TARRAY: // componentgen for arrays. + if(nl->op == ONAME) + gvardef(nl); t = nl->type; if(!isslice(t)) { nodl.type = t->type; @@ -1591,6 +1647,8 @@ componentgen(Node *nr, Node *nl) goto yes; case TSTRING: + if(nl->op == ONAME) + gvardef(nl); nodl.xoffset += Array_array; nodl.type = ptrto(types[TUINT8]); @@ -1614,6 +1672,8 @@ componentgen(Node *nr, Node *nl) goto yes; case TINTER: + if(nl->op == ONAME) + gvardef(nl); nodl.xoffset += Array_array; nodl.type = ptrto(types[TUINT8]); @@ -1637,6 +1697,8 @@ componentgen(Node *nr, Node *nl) goto yes; case TSTRUCT: + if(nl->op == ONAME) + gvardef(nl); loffset = nodl.xoffset; roffset = nodr.xoffset; // funarg structs may not begin at offset zero. diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c index 526c04c06..1d32c5a61 100644 --- a/src/cmd/6g/galign.c +++ b/src/cmd/6g/galign.c @@ -8,9 +8,22 @@ int thechar = '6'; char* thestring = "amd64"; +LinkArch* thelinkarch = &linkamd64; + +void +linkarchinit(void) +{ + if(strcmp(getgoarch(), "amd64p32") == 0) + thelinkarch = &linkamd64p32; +} vlong MAXWIDTH = 1LL<<50; +int addptr = AADDQ; +int movptr = AMOVQ; +int leaptr = ALEAQ; +int cmpptr = ACMPQ; + /* * go declares several platform-specific type aliases: * int, uint, float, and uintptr @@ -28,6 +41,19 @@ betypeinit(void) { widthptr = 8; widthint = 8; + widthreg = 8; + if(strcmp(getgoarch(), "amd64p32") == 0) { + widthptr = 4; + widthint = 4; + addptr = AADDL; + movptr = AMOVL; + leaptr = ALEAL; + cmpptr = ACMPL; + typedefs[0].sameas = TINT32; + typedefs[1].sameas = TUINT32; + typedefs[2].sameas = TUINT32; + + } zprog.link = P; zprog.as = AGOK; @@ -36,5 +62,5 @@ betypeinit(void) zprog.from.scale = 0; zprog.to = zprog.from; - listinit(); + listinit6(); } diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h index 3ef59c788..a5da17d61 100644 --- a/src/cmd/6g/gg.h +++ b/src/cmd/6g/gg.h @@ -9,56 +9,25 @@ #include "../gc/go.h" #include "../6l/6.out.h" -typedef struct Addr Addr; - -struct Addr -{ - vlong offset; - - union { - double dval; - vlong vval; - Prog* branch; - char sval[NSNAME]; - } u; - - Sym* gotype; - Sym* sym; - Node* node; - int64 width; - uchar type; - uchar index; - uchar etype; - uchar scale; /* doubles as width in DATA op */ -}; -#define A ((Addr*)0) - -struct Prog -{ - short as; // opcode - uint32 loc; // pc offset in this func - uint32 lineno; // source line that generated this - Addr from; // src address - Addr to; // dst address - Prog* link; // next instruction in this func - void* opt; // for optimizer passes -}; - #define TEXTFLAG from.scale EXTERN int32 dynloc; EXTERN uchar reg[D_NONE]; EXTERN int32 pcloc; // instruction counter EXTERN Strlit emptystring; -extern char* anames[]; EXTERN Prog zprog; EXTERN Node* newproc; EXTERN Node* deferproc; EXTERN Node* deferreturn; EXTERN Node* panicindex; EXTERN Node* panicslice; +EXTERN Node* panicdiv; EXTERN Node* throwreturn; extern vlong unmappedzero; +extern int addptr; +extern int cmpptr; +extern int movptr; +extern int leaptr; /* * ggen.c @@ -150,14 +119,6 @@ void datagostring(Strlit*, Addr*); /* * list.c */ -int Aconv(Fmt*); -int Dconv(Fmt*); -int Pconv(Fmt*); -int Rconv(Fmt*); -int Yconv(Fmt*); void listinit(void); void zaddr(Biobuf*, Addr*, int, int); - -#pragma varargck type "D" Addr* -#pragma varargck type "lD" Addr* 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; diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c index a9bd5e833..04e837b13 100644 --- a/src/cmd/6g/gobj.c +++ b/src/cmd/6g/gobj.c @@ -32,231 +32,6 @@ #include <libc.h> #include "gg.h" -void -zname(Biobuf *b, Sym *s, int t) -{ - BPUTLE2(b, ANAME); /* as */ - BPUTC(b, t); /* type */ - BPUTC(b, s->sym); /* sym */ - - Bputname(b, s); -} - -void -zfile(Biobuf *b, char *p, int n) -{ - BPUTLE2(b, ANAME); - BPUTC(b, D_FILE); - BPUTC(b, 1); - BPUTC(b, '<'); - Bwrite(b, p, n); - BPUTC(b, 0); -} - -void -zhist(Biobuf *b, int line, vlong offset) -{ - Addr a; - - BPUTLE2(b, AHISTORY); - BPUTLE4(b, line); - zaddr(b, &zprog.from, 0, 0); - a = zprog.to; - if(offset != 0) { - a.offset = offset; - a.type = D_CONST; - } - zaddr(b, &a, 0, 0); -} - -void -zaddr(Biobuf *b, Addr *a, int s, int gotype) -{ - int32 l; - uint64 e; - int i, t; - char *n; - - t = 0; - if(a->index != D_NONE || a->scale != 0) - t |= T_INDEX; - if(s != 0) - t |= T_SYM; - if(gotype != 0) - t |= T_GOTYPE; - - switch(a->type) { - - case D_BRANCH: - if(a->u.branch == nil) - fatal("unpatched branch"); - a->offset = a->u.branch->loc; - - default: - t |= T_TYPE; - - case D_NONE: - if(a->offset != 0) { - t |= T_OFFSET; - l = a->offset; - if((vlong)l != a->offset) - t |= T_64; - } - break; - case D_FCONST: - t |= T_FCONST; - break; - case D_SCONST: - t |= T_SCONST; - break; - } - BPUTC(b, t); - - if(t & T_INDEX) { /* implies index, scale */ - BPUTC(b, a->index); - BPUTC(b, a->scale); - } - if(t & T_OFFSET) { /* implies offset */ - l = a->offset; - BPUTLE4(b, l); - if(t & T_64) { - l = a->offset>>32; - BPUTLE4(b, l); - } - } - if(t & T_SYM) /* implies sym */ - BPUTC(b, s); - if(t & T_FCONST) { - ieeedtod(&e, a->u.dval); - BPUTLE4(b, e); - BPUTLE4(b, e >> 32); - return; - } - if(t & T_SCONST) { - n = a->u.sval; - for(i=0; i<NSNAME; i++) { - BPUTC(b, *n); - n++; - } - return; - } - if(t & T_TYPE) - BPUTC(b, a->type); - if(t & T_GOTYPE) - BPUTC(b, gotype); -} - -static struct { - struct { Sym *sym; short type; } h[NSYM]; - int sym; -} z; - -static void -zsymreset(void) -{ - for(z.sym=0; z.sym<NSYM; z.sym++) { - z.h[z.sym].sym = S; - z.h[z.sym].type = 0; - } - z.sym = 1; -} - -static int -zsym(Sym *s, int t, int *new) -{ - int i; - - *new = 0; - if(s == S) - return 0; - - i = s->sym; - if(i < 0 || i >= NSYM) - i = 0; - if(z.h[i].type == t && z.h[i].sym == s) - return i; - i = z.sym; - s->sym = i; - zname(bout, s, t); - z.h[i].sym = s; - z.h[i].type = t; - if(++z.sym >= NSYM) - z.sym = 1; - *new = 1; - return i; -} - -static int -zsymaddr(Addr *a, int *new) -{ - int t; - - t = a->type; - if(t == D_ADDR) - t = a->index; - return zsym(a->sym, t, new); -} - -void -dumpfuncs(void) -{ - Plist *pl; - int sf, st, gf, gt, new; - Sym *s; - Prog *p; - - zsymreset(); - - // fix up pc - pcloc = 0; - for(pl=plist; pl!=nil; pl=pl->link) { - if(isblank(pl->name)) - continue; - for(p=pl->firstpc; p!=P; p=p->link) { - p->loc = pcloc; - if(p->as != ADATA && p->as != AGLOBL) - pcloc++; - } - } - - // put out functions - for(pl=plist; pl!=nil; pl=pl->link) { - if(isblank(pl->name)) - continue; - - // -S prints code; -SS prints code and data - if(debug['S'] && (pl->name || debug['S']>1)) { - s = S; - if(pl->name != N) - s = pl->name->sym; - print("\n--- prog list \"%S\" ---\n", s); - for(p=pl->firstpc; p!=P; p=p->link) - print("%P\n", p); - } - - for(p=pl->firstpc; p!=P; p=p->link) { - for(;;) { - sf = zsymaddr(&p->from, &new); - gf = zsym(p->from.gotype, D_EXTERN, &new); - if(new && sf == gf) - continue; - st = zsymaddr(&p->to, &new); - if(new && (st == sf || st == gf)) - continue; - gt = zsym(p->to.gotype, D_EXTERN, &new); - if(new && (gt == sf || gt == gf || gt == st)) - continue; - break; - } - - BPUTLE2(bout, p->as); - BPUTLE4(bout, p->lineno); - zaddr(bout, &p->from, sf, gf); - zaddr(bout, &p->to, st, gt); - } - } -} - int dsname(Sym *s, int off, char *t, int n) { @@ -267,7 +42,7 @@ dsname(Sym *s, int off, char *t, int n) p->from.index = D_NONE; p->from.offset = off; p->from.scale = n; - p->from.sym = s; + p->from.sym = linksym(s); p->to.type = D_SCONST; p->to.index = D_NONE; @@ -286,7 +61,7 @@ datastring(char *s, int len, Addr *a) sym = stringsym(s, len); a->type = D_EXTERN; - a->sym = sym; + a->sym = linksym(sym); a->node = sym->def; a->offset = widthptr+widthint; // skip header a->etype = simtype[TINT]; @@ -303,7 +78,7 @@ datagostring(Strlit *sval, Addr *a) sym = stringsym(sval->s, sval->len); a->type = D_EXTERN; - a->sym = sym; + a->sym = linksym(sym); a->node = sym->def; a->offset = 0; // header a->etype = TINT32; @@ -377,7 +152,7 @@ dstringptr(Sym *s, int off, char *str) p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->from.scale = widthptr; @@ -402,7 +177,7 @@ dgostrlitptr(Sym *s, int off, Strlit *lit) p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->from.scale = widthptr; datagostring(lit, &p->to); @@ -431,27 +206,6 @@ dgostringptr(Sym *s, int off, char *str) } int -duintxx(Sym *s, int off, uint64 v, int wid) -{ - Prog *p; - - off = rnd(off, wid); - - p = gins(ADATA, N, N); - p->from.type = D_EXTERN; - p->from.index = D_NONE; - p->from.sym = s; - p->from.offset = off; - p->from.scale = wid; - p->to.type = D_CONST; - p->to.index = D_NONE; - p->to.offset = v; - off += wid; - - return off; -} - -int dsymptr(Sym *s, int off, Sym *x, int xoff) { Prog *p; @@ -461,12 +215,12 @@ dsymptr(Sym *s, int off, Sym *x, int xoff) p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->from.scale = widthptr; p->to.type = D_ADDR; p->to.index = D_EXTERN; - p->to.sym = x; + p->to.sym = linksym(x); p->to.offset = xoff; off += widthptr; diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index 7318909bb..e4d00bf41 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -46,7 +46,7 @@ clearp(Prog *p) p->from.index = D_NONE; p->to.type = D_NONE; p->to.index = D_NONE; - p->loc = pcloc; + p->pc = pcloc; pcloc++; } @@ -136,7 +136,7 @@ patch(Prog *p, Prog *to) if(p->to.type != D_BRANCH) fatal("patch: not a branch"); p->to.u.branch = to; - p->to.offset = to->loc; + p->to.offset = to->pc; } Prog* @@ -160,12 +160,7 @@ newplist(void) { Plist *pl; - pl = mal(sizeof(*pl)); - if(plist == nil) - plist = pl; - else - plast->link = pl; - plast = pl; + pl = linknewplist(ctxt); pc = mal(sizeof(*pc)); clearp(pc); @@ -198,8 +193,8 @@ ggloblnod(Node *nam) p = gins(AGLOBL, nam, N); p->lineno = nam->lineno; - p->from.gotype = ngotype(nam); - p->to.sym = S; + p->from.sym->gotype = linksym(ngotype(nam)); + p->to.sym = nil; p->to.type = D_CONST; p->to.offset = nam->type->width; if(nam->readonly) @@ -216,7 +211,7 @@ gtrack(Sym *s) p = gins(AUSEFIELD, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); } void @@ -237,7 +232,7 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata) p = gins(AGLOBL, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); p->to.type = D_CONST; p->to.index = D_NONE; p->to.offset = width; @@ -272,7 +267,7 @@ afunclit(Addr *a, Node *n) if(a->type == D_ADDR && a->index == D_EXTERN) { a->type = D_EXTERN; a->index = D_NONE; - a->sym = n->sym; + a->sym = linksym(n->sym); } } @@ -301,6 +296,11 @@ ginit(void) for(i=0; i<nelem(resvd); i++) reg[resvd[i]]++; + + if(nacl) { + reg[D_BP]++; + reg[D_R15]++; + } } void @@ -310,6 +310,11 @@ gclean(void) for(i=0; i<nelem(resvd); i++) reg[resvd[i]]--; + if(nacl) { + reg[D_BP]--; + reg[D_R15]--; + } + for(i=D_AX; i<=D_R15; i++) if(reg[i]) @@ -457,6 +462,7 @@ Node* nodarg(Type *t, int fp) { Node *n; + NodeList *l; Type *first; Iter savet; @@ -477,6 +483,14 @@ nodarg(Type *t, int fp) if(t->etype != TFIELD) fatal("nodarg: not field %T", t); + + if(fp == 1) { + for(l=curfn->dcl; l; l=l->next) { + n = l->n; + if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym) + return n; + } + } n = nod(ONAME, N, N); n->type = t->type; @@ -525,7 +539,16 @@ gconreg(int as, vlong c, int reg) { Node nr; - nodreg(&nr, types[TINT64], reg); + switch(as) { + case AADDL: + case AMOVL: + case ALEAL: + nodreg(&nr, types[TINT32], reg); + break; + default: + nodreg(&nr, types[TINT64], reg); + } + ginscon(as, c, &nr); } @@ -538,10 +561,18 @@ ginscon(int as, vlong c, Node *n2) { Node n1, ntmp; - nodconst(&n1, types[TINT64], c); + switch(as) { + case AADDL: + case AMOVL: + case ALEAL: + nodconst(&n1, types[TINT32], c); + break; + default: + nodconst(&n1, types[TINT64], c); + } if(as != AMOVQ && (c < -(1LL<<31) || c >= 1LL<<31)) { - // cannot have 64-bit immediokate in ADD, etc. + // cannot have 64-bit immediate in ADD, etc. // instead, MOV into register first. regalloc(&ntmp, types[TINT64], N); gins(AMOVQ, &n1, &ntmp); @@ -1098,10 +1129,12 @@ fixlargeoffset(Node *n) void naddr(Node *n, Addr *a, int canemitcode) { + Sym *s; + a->scale = 0; a->index = D_NONE; a->type = D_NONE; - a->gotype = S; + a->gotype = nil; a->node = N; a->width = 0; if(n == N) @@ -1119,7 +1152,7 @@ naddr(Node *n, Addr *a, int canemitcode) case OREGISTER: a->type = n->val.u.reg; - a->sym = S; + a->sym = nil; break; // case OINDEX: @@ -1144,7 +1177,7 @@ naddr(Node *n, Addr *a, int canemitcode) case OINDREG: a->type = n->val.u.reg+D_INDIR; - a->sym = n->sym; + a->sym = linksym(n->sym); a->offset = n->xoffset; if(a->offset != (int32)a->offset) yyerror("offset %lld too large for OINDREG", a->offset); @@ -1156,20 +1189,22 @@ naddr(Node *n, Addr *a, int canemitcode) a->etype = simtype[n->left->type->etype]; a->width = n->left->type->width; a->offset = n->xoffset; - a->sym = n->left->sym; + a->sym = linksym(n->left->sym); a->type = D_PARAM; a->node = n->left->orig; break; case OCLOSUREVAR: + if(!curfn->needctxt) + fatal("closurevar without needctxt"); a->type = D_DX+D_INDIR; - a->sym = S; + a->sym = nil; a->offset = n->xoffset; break; case OCFUNC: naddr(n->left, a, canemitcode); - a->sym = n->left->sym; + a->sym = linksym(n->left->sym); break; case ONAME: @@ -1177,17 +1212,17 @@ naddr(Node *n, Addr *a, int canemitcode) if(n->type != T) a->etype = simtype[n->type->etype]; a->offset = n->xoffset; - a->sym = n->sym; + s = n->sym; a->node = n->orig; //if(a->node >= (Node*)&n) // fatal("stack node"); - if(a->sym == S) - a->sym = lookup(".noname"); + if(s == S) + s = lookup(".noname"); if(n->method) { if(n->type != T) if(n->type->sym != S) if(n->type->sym->pkg != nil) - a->sym = pkglookup(a->sym->name, n->type->sym->pkg); + s = pkglookup(s->name, n->type->sym->pkg); } switch(n->class) { @@ -1207,9 +1242,10 @@ naddr(Node *n, Addr *a, int canemitcode) a->index = D_EXTERN; a->type = D_ADDR; a->width = widthptr; - a->sym = funcsym(a->sym); + s = funcsym(s); break; } + a->sym = linksym(s); break; case OLITERAL: @@ -1223,7 +1259,7 @@ naddr(Node *n, Addr *a, int canemitcode) break; case CTINT: case CTRUNE: - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = mpgetfix(n->val.u.xval); break; @@ -1231,12 +1267,12 @@ naddr(Node *n, Addr *a, int canemitcode) datagostring(n->val.u.sval, a); break; case CTBOOL: - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = n->val.u.bval; break; case CTNIL: - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = 0; break; @@ -1273,7 +1309,7 @@ naddr(Node *n, Addr *a, int canemitcode) naddr(n->left, a, canemitcode); if(a->type == D_CONST && a->offset == 0) break; // ptr(nil) - a->etype = simtype[TUINTPTR]; + a->etype = simtype[tptr]; a->offset += Array_array; a->width = widthptr; break; @@ -1506,12 +1542,14 @@ optoas(int op, Type *t) case CASE(OADD, TINT32): case CASE(OADD, TUINT32): case CASE(OADD, TPTR32): + case CASE(OADDPTR, TPTR32): a = AADDL; break; case CASE(OADD, TINT64): case CASE(OADD, TUINT64): case CASE(OADD, TPTR64): + case CASE(OADDPTR, TPTR64): a = AADDQ; break; @@ -2042,7 +2080,7 @@ odot: for(i=1; i<o; i++) { if(oary[i] >= 0) fatal("can't happen"); - gins(AMOVQ, &n1, reg); + gins(movptr, &n1, reg); cgen_checknil(reg); n1.xoffset = -(oary[i]+1); } @@ -2254,7 +2292,7 @@ oindex_const_sudo: if(reg->op == OEMPTY) regalloc(reg, types[tptr], N); - p1 = gins(AMOVQ, N, reg); + p1 = gins(movptr, N, reg); p1->from = *a; n2 = *reg; diff --git a/src/cmd/6g/list.c b/src/cmd/6g/list.c deleted file mode 100644 index 9d27a6a09..000000000 --- a/src/cmd/6g/list.c +++ /dev/null @@ -1,364 +0,0 @@ -// Derived from Inferno utils/6c/list.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include <u.h> -#include <libc.h> -#include "gg.h" - -static int sconsize; -void -listinit(void) -{ - - fmtinstall('A', Aconv); // as - fmtinstall('P', Pconv); // Prog* - fmtinstall('D', Dconv); // Addr* - fmtinstall('R', Rconv); // reg - fmtinstall('Y', Yconv); // sconst -} - -int -Pconv(Fmt *fp) -{ - char str[STRINGSZ]; - Prog *p; - char scale[40]; - - p = va_arg(fp->args, Prog*); - sconsize = 8; - scale[0] = '\0'; - if(p->from.scale != 0 && (p->as == AGLOBL || p->as == ATEXT)) - snprint(scale, sizeof scale, "%d,", p->from.scale); - switch(p->as) { - default: - snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%D", - p->loc, p->lineno, p->as, &p->from, scale, &p->to); - break; - - case ADATA: - sconsize = p->from.scale; - snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D", - p->loc, p->lineno, p->as, &p->from, sconsize, &p->to); - break; - - case ATEXT: - snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%lD", - p->loc, p->lineno, p->as, &p->from, scale, &p->to); - break; - } - return fmtstrcpy(fp, str); -} - -int -Dconv(Fmt *fp) -{ - char str[STRINGSZ], s[STRINGSZ]; - Addr *a; - int i; - uint32 d1, d2; - - a = va_arg(fp->args, Addr*); - i = a->type; - if(i >= D_INDIR) { - if(a->offset) - snprint(str, sizeof(str), "%lld(%R)", a->offset, i-D_INDIR); - else - snprint(str, sizeof(str), "(%R)", i-D_INDIR); - goto brk; - } - switch(i) { - - default: - if(a->offset) - snprint(str, sizeof(str), "$%lld,%R", a->offset, i); - else - snprint(str, sizeof(str), "%R", i); - break; - - case D_NONE: - str[0] = 0; - break; - - case D_BRANCH: - if(a->u.branch == nil) - snprint(str, sizeof(str), "<nil>"); - else - snprint(str, sizeof(str), "%d", a->u.branch->loc); - break; - - case D_EXTERN: - snprint(str, sizeof(str), "%S+%lld(SB)", a->sym, a->offset); - break; - - case D_STATIC: - snprint(str, sizeof(str), "%S<>+%lld(SB)", a->sym, a->offset); - break; - - case D_AUTO: - snprint(str, sizeof(str), "%S+%lld(SP)", a->sym, a->offset); - break; - - case D_PARAM: - snprint(str, sizeof(str), "%S+%lld(FP)", a->sym, a->offset); - break; - - case D_CONST: - if(fp->flags & FmtLong) { - d1 = a->offset & 0xffffffffLL; - d2 = (a->offset>>32) & 0xffffffffLL; - snprint(str, sizeof(str), "$%lud-%lud", (ulong)d1, (ulong)d2); - break; - } - snprint(str, sizeof(str), "$%lld", a->offset); - break; - - case D_FCONST: - snprint(str, sizeof(str), "$(%.17e)", a->u.dval); - break; - - case D_SCONST: - snprint(str, sizeof(str), "$\"%Y\"", a->u.sval); - break; - - case D_ADDR: - a->type = a->index; - a->index = D_NONE; - snprint(str, sizeof(str), "$%D", a); - a->index = a->type; - a->type = D_ADDR; - goto conv; - } -brk: - if(a->index != D_NONE) { - snprint(s, sizeof(s), "(%R*%d)", (int)a->index, (int)a->scale); - strcat(str, s); - } -conv: - fmtstrcpy(fp, str); - if(a->gotype) - fmtprint(fp, "{%s}", a->gotype->name); - return 0; -} - -static char* regstr[] = -{ - "AL", /* [D_AL] */ - "CL", - "DL", - "BL", - "SPB", - "BPB", - "SIB", - "DIB", - "R8B", - "R9B", - "R10B", - "R11B", - "R12B", - "R13B", - "R14B", - "R15B", - - "AX", /* [D_AX] */ - "CX", - "DX", - "BX", - "SP", - "BP", - "SI", - "DI", - "R8", - "R9", - "R10", - "R11", - "R12", - "R13", - "R14", - "R15", - - "AH", - "CH", - "DH", - "BH", - - "F0", /* [D_F0] */ - "F1", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - - "M0", - "M1", - "M2", - "M3", - "M4", - "M5", - "M6", - "M7", - - "X0", - "X1", - "X2", - "X3", - "X4", - "X5", - "X6", - "X7", - "X8", - "X9", - "X10", - "X11", - "X12", - "X13", - "X14", - "X15", - - "CS", /* [D_CS] */ - "SS", - "DS", - "ES", - "FS", - "GS", - - "GDTR", /* [D_GDTR] */ - "IDTR", /* [D_IDTR] */ - "LDTR", /* [D_LDTR] */ - "MSW", /* [D_MSW] */ - "TASK", /* [D_TASK] */ - - "CR0", /* [D_CR] */ - "CR1", - "CR2", - "CR3", - "CR4", - "CR5", - "CR6", - "CR7", - "CR8", - "CR9", - "CR10", - "CR11", - "CR12", - "CR13", - "CR14", - "CR15", - - "DR0", /* [D_DR] */ - "DR1", - "DR2", - "DR3", - "DR4", - "DR5", - "DR6", - "DR7", - - "TR0", /* [D_TR] */ - "TR1", - "TR2", - "TR3", - "TR4", - "TR5", - "TR6", - "TR7", - - "NONE", /* [D_NONE] */ -}; - -int -Rconv(Fmt *fp) -{ - char str[STRINGSZ]; - int r; - - r = va_arg(fp->args, int); - if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) { - snprint(str, sizeof(str), "BAD_R(%d)", r); - return fmtstrcpy(fp, str); - } - return fmtstrcpy(fp, regstr[r]); -} - -int -Aconv(Fmt *fp) -{ - int i; - - i = va_arg(fp->args, int); - return fmtstrcpy(fp, anames[i]); -} - - -int -Yconv(Fmt *fp) -{ - int i, c; - char str[STRINGSZ], *p, *a; - - a = va_arg(fp->args, char*); - p = str; - for(i=0; i<sconsize; i++) { - c = a[i] & 0xff; - if((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9')) { - *p++ = c; - continue; - } - *p++ = '\\'; - switch(c) { - default: - if(c < 040 || c >= 0177) - break; /* not portable */ - p[-1] = c; - continue; - case 0: - *p++ = 'z'; - continue; - case '\\': - case '"': - *p++ = c; - continue; - case '\n': - *p++ = 'n'; - continue; - case '\t': - *p++ = 't'; - continue; - } - *p++ = (c>>6) + '0'; - *p++ = ((c>>3) & 7) + '0'; - *p++ = (c & 7) + '0'; - } - *p = 0; - return fmtstrcpy(fp, str); -} diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h index 3dcc3d747..bf356af0c 100644 --- a/src/cmd/6g/opt.h +++ b/src/cmd/6g/opt.h @@ -94,6 +94,7 @@ EXTERN Bits externs; EXTERN Bits params; EXTERN Bits consts; EXTERN Bits addrs; +EXTERN Bits ivar; EXTERN Bits ovar; EXTERN int change; EXTERN int32 maxnr; diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c index 5ccf90103..0f2720443 100644 --- a/src/cmd/6g/peep.c +++ b/src/cmd/6g/peep.c @@ -109,7 +109,7 @@ peep(Prog *firstp) case ALEAL: case ALEAQ: if(regtyp(&p->to)) - if(p->from.sym != S) + if(p->from.sym != nil) if(p->from.index == D_NONE || p->from.index == D_CONST) conprop(r); break; @@ -306,7 +306,7 @@ pushback(Flow *r0) if(p->as != ANOP) { if(!regconsttyp(&p->from) || !regtyp(&p->to)) break; - if(copyu(p, &p0->to, A) || copyu(p0, &p->to, A)) + if(copyu(p, &p0->to, nil) || copyu(p0, &p->to, nil)) break; } if(p->as == ACALL) @@ -573,6 +573,8 @@ subprop(Flow *r0) break; } p = r->prog; + if(p->as == AVARDEF || p->as == AVARKILL) + continue; proginfo(&info, p); if(info.flags & Call) { if(debug['P'] && debug['v']) @@ -682,7 +684,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f) if(debug['P']) print("; merge; f=%d", f); } - t = copyu(p, v2, A); + t = copyu(p, v2, nil); switch(t) { case 2: /* rar, can't split */ if(debug['P']) @@ -720,7 +722,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f) break; } if(!f) { - t = copyu(p, v1, A); + t = copyu(p, v1, nil); if(!f && (t == 2 || t == 3 || t == 4)) { f = 1; if(debug['P']) @@ -751,7 +753,7 @@ copyu(Prog *p, Adr *v, Adr *s) switch(p->as) { case AJMP: - if(s != A) { + if(s != nil) { if(copysub(&p->to, v, s, 1)) return 1; return 0; @@ -761,7 +763,7 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; case ARET: - if(s != A) + if(s != nil) return 1; return 3; @@ -773,7 +775,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(v->type == p->from.type) return 2; - if(s != A) { + if(s != nil) { if(copysub(&p->to, v, s, 1)) return 1; return 0; @@ -788,6 +790,8 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; } + if(p->as == AVARDEF || p->as == AVARKILL) + return 0; proginfo(&info, p); if((info.reguse|info.regset) & RtoB(v->type)) @@ -803,7 +807,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(info.flags & RightWrite) { if(copyas(&p->to, v)) { - if(s != A) + if(s != nil) return copysub(&p->from, v, s, 1); if(copyau(&p->from, v)) return 4; @@ -812,7 +816,7 @@ copyu(Prog *p, Adr *v, Adr *s) } if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) { - if(s != A) { + if(s != nil) { if(copysub(&p->from, v, s, 1)) return 1; return copysub(&p->to, v, s, 1); @@ -940,7 +944,7 @@ loop: return; p = r->prog; - t = copyu(p, v0, A); + t = copyu(p, v0, nil); switch(t) { case 0: // miss case 1: // use @@ -956,7 +960,7 @@ loop: if(p->from.node == p0->from.node) if(p->from.offset == p0->from.offset) if(p->from.scale == p0->from.scale) - if(p->from.u.vval == p0->from.u.vval) + if(p->from.type == D_FCONST && p->from.u.dval == p0->from.u.dval) if(p->from.index == p0->from.index) { excise(r); goto loop; diff --git a/src/cmd/6g/prog.c b/src/cmd/6g/prog.c index 90571a21a..ee68399d5 100644 --- a/src/cmd/6g/prog.c +++ b/src/cmd/6g/prog.c @@ -38,9 +38,11 @@ static ProgInfo progtable[ALAST] = { [ATEXT]= {Pseudo}, [AFUNCDATA]= {Pseudo}, [APCDATA]= {Pseudo}, - [AUNDEF]= {OK}, + [AUNDEF]= {Break}, [AUSEFIELD]= {OK}, [ACHECKNIL]= {LeftRead}, + [AVARDEF]= {Pseudo | RightWrite}, + [AVARKILL]= {Pseudo | RightWrite}, // NOP is an internal no-op that also stands // for USED and SET annotations, not the Intel opcode. @@ -142,6 +144,7 @@ static ProgInfo progtable[ALAST] = { [AJMP]= {Jump | Break | KillCarry}, + [ALEAL]= {LeftAddr | RightWrite}, [ALEAQ]= {LeftAddr | RightWrite}, [AMOVBLSX]= {SizeL | LeftRead | RightWrite | Conv}, @@ -167,6 +170,7 @@ static ProgInfo progtable[ALAST] = { [AMOVSL]= {OK, DI|SI, DI|SI}, [AMOVSQ]= {OK, DI|SI, DI|SI}, [AMOVSW]= {OK, DI|SI, DI|SI}, + [ADUFFCOPY]= {OK, DI|SI, DI|SI|CX}, [AMOVSD]= {SizeD | LeftRead | RightWrite | Move}, [AMOVSS]= {SizeF | LeftRead | RightWrite | Move}, @@ -254,6 +258,7 @@ static ProgInfo progtable[ALAST] = { [ASTOSL]= {OK, AX|DI, DI}, [ASTOSQ]= {OK, AX|DI, DI}, [ASTOSW]= {OK, AX|DI, DI}, + [ADUFFZERO]= {OK, AX|DI, DI}, [ASUBB]= {SizeB | LeftRead | RightRdwr | SetCarry}, [ASUBL]= {SizeL | LeftRead | RightRdwr | SetCarry}, diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c index 63fd0deca..f3b1e55de 100644 --- a/src/cmd/6g/reg.c +++ b/src/cmd/6g/reg.c @@ -55,30 +55,6 @@ rcmp(const void *a1, const void *a2) } static void -setoutvar(void) -{ - Type *t; - Node *n; - Addr a; - Iter save; - Bits bit; - int z; - - t = structfirst(&save, getoutarg(curfn->type)); - while(t != T) { - n = nodarg(t, 1); - a = zprog.from; - naddr(n, &a, 0); - bit = mkvar(R, &a); - for(z=0; z<BITS; z++) - ovar.b[z] |= bit.b[z]; - t = structnext(&save); - } -//if(bany(&ovar)) -//print("ovars = %Q\n", ovar); -} - -static void setaddrs(Bits bit) { int i, n; @@ -138,6 +114,8 @@ static char* regname[] = { static Node* regnodes[NREGVAR]; +static void walkvardef(Node *n, Reg *r, int active); + void regopt(Prog *firstp) { @@ -145,7 +123,7 @@ regopt(Prog *firstp) Prog *p; Graph *g; ProgInfo info; - int i, z; + int i, z, active; uint32 vreg; Bits bit; @@ -155,9 +133,8 @@ regopt(Prog *firstp) first = 0; } - fixjmp(firstp); mergetemp(firstp); - + /* * control flow is more complicated in generated go code * than in generated c code. define pseudo-variables for @@ -177,12 +154,10 @@ regopt(Prog *firstp) params.b[z] = 0; consts.b[z] = 0; addrs.b[z] = 0; + ivar.b[z] = 0; ovar.b[z] = 0; } - // build list of return variables - setoutvar(); - /* * pass 1 * build aux data structure @@ -190,12 +165,18 @@ regopt(Prog *firstp) * find use and set of variables */ g = flowstart(firstp, sizeof(Reg)); - if(g == nil) + if(g == nil) { + for(i=0; i<nvar; i++) + var[i].node->opt = nil; return; + } + firstr = (Reg*)g->start; for(r = firstr; r != R; r = (Reg*)r->f.link) { p = r->f.prog; + if(p->as == AVARDEF || p->as == AVARKILL) + continue; proginfo(&info, p); // Avoid making variables for direct-called functions. @@ -256,6 +237,26 @@ regopt(Prog *firstp) dumpit("pass2", &firstr->f, 1); /* + * pass 2.5 + * iterate propagating fat vardef covering forward + * r->act records vars with a VARDEF since the last CALL. + * (r->act will be reused in pass 5 for something else, + * but we'll be done with it by then.) + */ + active = 0; + for(r = firstr; r != R; r = (Reg*)r->f.link) { + r->f.active = 0; + r->act = zbits; + } + for(r = firstr; r != R; r = (Reg*)r->f.link) { + p = r->f.prog; + if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) { + active++; + walkvardef(p->to.node, r, active); + } + } + + /* * pass 3 * iterate propagating usage * back until flow graph is complete @@ -406,6 +407,8 @@ brk: /* * free aux structures. peep allocates new ones. */ + for(i=0; i<nvar; i++) + var[i].node->opt = nil; flowend(g); firstr = R; @@ -454,6 +457,32 @@ brk: } } +static void +walkvardef(Node *n, Reg *r, int active) +{ + Reg *r1, *r2; + int bn; + Var *v; + + for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) { + if(r1->f.active == active) + break; + r1->f.active = active; + if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n) + break; + for(v=n->opt; v!=nil; v=v->nextinnode) { + bn = v - var; + r1->act.b[bn/32] |= 1L << (bn%32); + } + if(r1->f.prog->as == ACALL) + break; + } + + for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1) + if(r2->f.s2 != nil) + walkvardef(n, (Reg*)r2->f.s2, active); +} + /* * add mov b,rn * just after r @@ -467,7 +496,7 @@ addmove(Reg *r, int bn, int rn, int f) p1 = mal(sizeof(*p1)); clearp(p1); - p1->loc = 9999; + p1->pc = 9999; p = r->f.prog; p1->link = p->link; @@ -481,12 +510,12 @@ addmove(Reg *r, int bn, int rn, int f) a->etype = v->etype; a->type = v->name; a->node = v->node; - a->sym = v->node->sym; + a->sym = linksym(v->node->sym); // need to clean this up with wptr and // some of the defaults p1->as = AMOVL; - switch(v->etype) { + switch(simtype[(uchar)v->etype]) { default: fatal("unknown type %E", v->etype); case TINT8: @@ -500,7 +529,6 @@ addmove(Reg *r, int bn, int rn, int f) break; case TINT64: case TUINT64: - case TUINTPTR: case TPTR64: p1->as = AMOVQ; break; @@ -510,8 +538,6 @@ addmove(Reg *r, int bn, int rn, int f) case TFLOAT64: p1->as = AMOVSD; break; - case TINT: - case TUINT: case TINT32: case TUINT32: case TPTR32: @@ -655,6 +681,16 @@ mkvar(Reg *r, Adr *a) if(nvar >= NVAR) { if(debug['w'] > 1 && node != N) fatal("variable not optimized: %#N", node); + + // If we're not tracking a word in a variable, mark the rest as + // having its address taken, so that we keep the whole thing + // live at all calls. otherwise we might optimize away part of + // a variable but not all of it. + for(i=0; i<nvar; i++) { + v = var+i; + if(v->node == node) + v->addr = 1; + } goto none; } @@ -667,11 +703,13 @@ mkvar(Reg *r, Adr *a) v->width = w; v->addr = flag; // funny punning v->node = node; - - if(debug['R']) - print("bit=%2d et=%2E w=%d+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); - - ostats.nvar++; + + // node->opt is the head of a linked list + // of Vars within the given Node, so that + // we can start at a Var and find all the other + // Vars in the same Go variable. + v->nextinnode = node->opt; + node->opt = v; bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) @@ -681,6 +719,46 @@ mkvar(Reg *r, Adr *a) for(z=0; z<BITS; z++) params.b[z] |= bit.b[z]; + if(node->class == PPARAM) + for(z=0; z<BITS; z++) + ivar.b[z] |= bit.b[z]; + if(node->class == PPARAMOUT) + for(z=0; z<BITS; z++) + ovar.b[z] |= bit.b[z]; + + // Treat values with their address taken as live at calls, + // because the garbage collector's liveness analysis in ../gc/plive.c does. + // These must be consistent or else we will elide stores and the garbage + // collector will see uninitialized data. + // The typical case where our own analysis is out of sync is when the + // node appears to have its address taken but that code doesn't actually + // get generated and therefore doesn't show up as an address being + // taken when we analyze the instruction stream. + // One instance of this case is when a closure uses the same name as + // an outer variable for one of its own variables declared with :=. + // The parser flags the outer variable as possibly shared, and therefore + // sets addrtaken, even though it ends up not being actually shared. + // If we were better about _ elision, _ = &x would suffice too. + // The broader := in a closure problem is mentioned in a comment in + // closure.c:/^typecheckclosure and dcl.c:/^oldname. + if(node->addrtaken) + v->addr = 1; + + // Disable registerization for globals, because: + // (1) we might panic at any time and we want the recovery code + // to see the latest values (issue 1304). + // (2) we don't know what pointers might point at them and we want + // loads via those pointers to see updated values and vice versa (issue 7995). + // + // Disable registerization for results if using defer, because the deferred func + // might recover and return, causing the current values to be used. + if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT)) + v->addr = 1; + + if(debug['R']) + print("bit=%2d et=%2E w=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); + ostats.nvar++; + return bit; none: @@ -691,7 +769,8 @@ void prop(Reg *r, Bits ref, Bits cal) { Reg *r1, *r2; - int z; + int z, i, j; + Var *v, *v1; for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) { for(z=0; z<BITS; z++) { @@ -710,10 +789,61 @@ prop(Reg *r, Bits ref, Bits cal) case ACALL: if(noreturn(r1->f.prog)) break; + + // Mark all input variables (ivar) as used, because that's what the + // liveness bitmaps say. The liveness bitmaps say that so that a + // panic will not show stale values in the parameter dump. + // Mark variables with a recent VARDEF (r1->act) as used, + // so that the optimizer flushes initializations to memory, + // so that if a garbage collection happens during this CALL, + // the collector will see initialized memory. Again this is to + // match what the liveness bitmaps say. for(z=0; z<BITS; z++) { - cal.b[z] |= ref.b[z] | externs.b[z]; + cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z]; ref.b[z] = 0; } + + // cal.b is the current approximation of what's live across the call. + // Every bit in cal.b is a single stack word. For each such word, + // find all the other tracked stack words in the same Go variable + // (struct/slice/string/interface) and mark them live too. + // This is necessary because the liveness analysis for the garbage + // collector works at variable granularity, not at word granularity. + // It is fundamental for slice/string/interface: the garbage collector + // needs the whole value, not just some of the words, in order to + // interpret the other bits correctly. Specifically, slice needs a consistent + // ptr and cap, string needs a consistent ptr and len, and interface + // needs a consistent type word and data word. + for(z=0; z<BITS; z++) { + if(cal.b[z] == 0) + continue; + for(i=0; i<32; i++) { + if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0) + continue; + v = var+z*32+i; + if(v->node->opt == nil) // v represents fixed register, not Go variable + continue; + + // v->node->opt is the head of a linked list of Vars + // corresponding to tracked words from the Go variable v->node. + // Walk the list and set all the bits. + // For a large struct this could end up being quadratic: + // after the first setting, the outer loop (for z, i) would see a 1 bit + // for all of the remaining words in the struct, and for each such + // word would go through and turn on all the bits again. + // To avoid the quadratic behavior, we only turn on the bits if + // v is the head of the list or if the head's bit is not yet turned on. + // This will set the bits at most twice, keeping the overall loop linear. + v1 = v->node->opt; + j = v1 - var; + if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) { + for(; v1 != nil; v1 = v1->nextinnode) { + j = v1 - var; + cal.b[j/32] |= 1<<(j&31); + } + } + } + } break; case ATEXT: @@ -729,17 +859,6 @@ prop(Reg *r, Bits ref, Bits cal) ref.b[z] = 0; } break; - - default: - // Work around for issue 1304: - // flush modified globals before each instruction. - for(z=0; z<BITS; z++) { - cal.b[z] |= externs.b[z]; - // issue 4066: flush modified return variables in case of panic - if(hasdefer) - cal.b[z] |= ovar.b[z]; - } - break; } for(z=0; z<BITS; z++) { ref.b[z] = (ref.b[z] & ~r1->set.b[z]) | @@ -860,12 +979,11 @@ paint1(Reg *r, int bn) for(;;) { r->act.b[z] |= bb; - if(r->use1.b[z] & bb) { - change += CREF * r->f.loop; - } - - if((r->use2.b[z]|r->set.b[z]) & bb) { - change += CREF * r->f.loop; + if(r->f.prog->as != ANOP) { // don't give credit for NOPs + if(r->use1.b[z] & bb) + change += CREF * r->f.loop; + if((r->use2.b[z]|r->set.b[z]) & bb) + change += CREF * r->f.loop; } if(STORE(r) & r->regdiff.b[z] & bb) { @@ -906,7 +1024,7 @@ regset(Reg *r, uint32 bb) v.type = b & 0xFFFF? BtoR(b): BtoF(b); if(v.type == 0) fatal("zero v.type for %#ux", b); - c = copyu(r->f.prog, &v, A); + c = copyu(r->f.prog, &v, nil); if(c == 3) set |= b; bb &= ~b; @@ -925,7 +1043,7 @@ reguse(Reg *r, uint32 bb) v = zprog.from; while(b = bb & ~(bb-1)) { v.type = b & 0xFFFF? BtoR(b): BtoF(b); - c = copyu(r->f.prog, &v, A); + c = copyu(r->f.prog, &v, nil); if(c == 1 || c == 2 || c == 4) set |= b; bb &= ~b; @@ -1067,8 +1185,7 @@ paint3(Reg *r, int bn, int32 rb, int rn) void addreg(Adr *a, int rn) { - - a->sym = 0; + a->sym = nil; a->offset = 0; a->type = rn; @@ -1088,6 +1205,8 @@ int BtoR(int32 b) { b &= 0xffffL; + if(nacl) + b &= ~((1<<(D_BP-D_AX)) | (1<<(D_R15-D_AX))); if(b == 0) return 0; return bitno(b) + D_AX; @@ -1176,14 +1295,14 @@ dumpit(char *str, Flow *r0, int isreg) if(r1 != nil) { print(" pred:"); for(; r1 != nil; r1 = r1->p2link) - print(" %.4ud", r1->prog->loc); + print(" %.4ud", (int)r1->prog->pc); print("\n"); } // r1 = r->s1; // if(r1 != R) { // print(" succ:"); // for(; r1 != R; r1 = r1->s1) -// print(" %.4ud", r1->prog->loc); +// print(" %.4ud", (int)r1->prog->pc); // print("\n"); // } } |