diff options
Diffstat (limited to 'src/cmd/8g')
-rw-r--r-- | src/cmd/8g/cgen.c | 43 | ||||
-rw-r--r-- | src/cmd/8g/galign.c | 9 | ||||
-rw-r--r-- | src/cmd/8g/gg.h | 47 | ||||
-rw-r--r-- | src/cmd/8g/ggen.c | 175 | ||||
-rw-r--r-- | src/cmd/8g/gobj.c | 259 | ||||
-rw-r--r-- | src/cmd/8g/gsubr.c | 69 | ||||
-rw-r--r-- | src/cmd/8g/list.c | 316 | ||||
-rw-r--r-- | src/cmd/8g/opt.h | 3 | ||||
-rw-r--r-- | src/cmd/8g/peep.c | 24 | ||||
-rw-r--r-- | src/cmd/8g/prog.c | 21 | ||||
-rw-r--r-- | src/cmd/8g/reg.c | 261 |
11 files changed, 439 insertions, 788 deletions
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c index cc28a3145..d626c2eb0 100644 --- a/src/cmd/8g/cgen.c +++ b/src/cmd/8g/cgen.c @@ -242,6 +242,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) { @@ -522,6 +523,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(ALEAL, &n1, &n2); @@ -934,6 +936,13 @@ bgen(Node *n, int true, int likely, Prog *to) patch(gins(AEND, N, N), to); return; } + + while(n->op == OCONVNOP) { + n = n->left; + if(n->ninit != nil) + genlist(n->ninit); + } + nl = n->left; nr = N; @@ -1203,6 +1212,8 @@ sgen(Node *n, Node *res, int64 w) { Node dst, src, tdst, tsrc; int32 c, q, odst, osrc; + NodeList *l; + Prog *p; if(debug['g']) { print("\nsgen w=%lld\n", w); @@ -1223,6 +1234,13 @@ sgen(Node *n, Node *res, int64 w) return; } + // If copying .args, that's all the results, so record definition sites + // for them for the liveness analysis. + if(res->op == ONAME && strcmp(res->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, res)) return; @@ -1255,6 +1273,10 @@ sgen(Node *n, Node *res, int64 w) agen(n, &src); else gmove(&tsrc, &src); + + if(res->op == ONAME) + gvardef(res); + if(res->addable) agen(res, &dst); else @@ -1294,10 +1316,16 @@ sgen(Node *n, Node *res, int64 w) } else { gins(ACLD, N, N); // paranoia. TODO(rsc): remove? // normal direction - if(q >= 4) { + if(q > 128 || (q >= 4 && nacl)) { gconreg(AMOVL, q, D_CX); gins(AREP, N, N); // repeat gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+ + } else if(q >= 4) { + p = gins(ADUFFCOPY, N, N); + p->to.type = D_ADDR; + p->to.sym = linksym(pkglookup("duffcopy", runtimepkg)); + // 10 and 128 = magic constants: see ../../pkg/runtime/asm_386.s + p->to.offset = 10*(128-q); } else while(q > 0) { gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+ @@ -1369,8 +1397,17 @@ componentgen(Node *nr, Node *nl) } } + // 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: + if(nl->op == ONAME) + gvardef(nl); nodl.xoffset += Array_array; nodl.type = ptrto(nl->type->type); @@ -1404,6 +1441,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]); @@ -1427,6 +1466,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]); diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c index 2c8aaa0a4..fbd2e9ad3 100644 --- a/src/cmd/8g/galign.c +++ b/src/cmd/8g/galign.c @@ -8,6 +8,12 @@ int thechar = '8'; char* thestring = "386"; +LinkArch* thelinkarch = &link386; + +void +linkarchinit(void) +{ +} vlong MAXWIDTH = (1LL<<32) - 1; @@ -28,6 +34,7 @@ betypeinit(void) { widthptr = 4; widthint = 4; + widthreg = 4; zprog.link = P; zprog.as = AGOK; @@ -36,5 +43,5 @@ betypeinit(void) zprog.from.scale = 0; zprog.to = zprog.from; - listinit(); + listinit8(); } diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h index 55fdded0b..bdefa93b5 100644 --- a/src/cmd/8g/gg.h +++ b/src/cmd/8g/gg.h @@ -9,42 +9,6 @@ #include "../gc/go.h" #include "../8l/8.out.h" -typedef struct Addr Addr; - -struct Addr -{ - int32 offset; - int32 offset2; - - union { - double dval; - vlong vval; - Prog* branch; - char sval[NSNAME]; - } u; - - Sym* gotype; - Sym* sym; - Node* node; - int 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 // foptoas flags @@ -59,15 +23,14 @@ 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 int maxstksize; extern uint32 unmappedzero; @@ -168,14 +131,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/8g/ggen.c b/src/cmd/8g/ggen.c index fa5ed00dd..2285a04e6 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -9,61 +9,100 @@ #include "gg.h" #include "opt.h" -static Prog* appendp(Prog*, int, int, int32, int, int32); +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) { - uint32 frame; + uint32 frame, ax; Prog *p; - int i, j; + vlong lo, hi; + NodeList *l; + Node *n; // fill in argument size ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr); // fill in final stack size - if(stksize > maxstksize) - maxstksize = stksize; - frame = rnd(maxstksize+maxarg, widthptr); + frame = rnd(stksize+maxarg, widthptr); ptxt->to.offset = frame; - maxstksize = 0; - - // 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, AMOVL, D_CONST, 0, D_AX, 0); - p = appendp(p, AMOVL, D_CONST, stkzerosize/widthptr, D_CX, 0); - p = appendp(p, ALEAL, D_SP+D_INDIR, frame-stkzerosize, D_DI, 0); - p = appendp(p, AREP, D_NONE, 0, D_NONE, 0); - appendp(p, ASTOSL, 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, AMOVL, D_CONST, 0, D_SP+D_INDIR, frame-stkzerosize+i); - j += 2; + hi = 0; + lo = hi; + ax = 0; + 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*widthptr) { + // 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, int32 foffset, int ttype, int32 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, AMOVL, D_CONST, 0, D_AX, 0); + *ax = 1; + } + if(cnt <= 4*widthreg) { + for(i = 0; i < cnt; i += widthreg) { + p = appendpp(p, AMOVL, D_AX, 0, D_SP+D_INDIR, frame+lo+i); + } + } else if(!nacl && cnt <= 128*widthreg) { + p = appendpp(p, ALEAL, D_SP+D_INDIR, frame+lo, D_DI, 0); + p = appendpp(p, ADUFFZERO, D_NONE, 0, D_ADDR, 1*(128-cnt/widthreg)); + p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); + } else { + p = appendpp(p, AMOVL, D_CONST, cnt/widthreg, D_CX, 0); + p = appendpp(p, ALEAL, D_SP+D_INDIR, frame+lo, D_DI, 0); + p = appendpp(p, AREP, D_NONE, 0, D_NONE, 0); + p = appendpp(p, ASTOSL, 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. @@ -71,13 +110,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; } } @@ -93,6 +132,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; @@ -109,6 +158,7 @@ clearfat(Node *nl) { uint32 w, c, q; Node n1; + Prog *p; /* clear a fat object */ if(debug['g']) @@ -126,21 +176,22 @@ clearfat(Node *nl) agen(nl, &n1); gconreg(AMOVL, 0, D_AX); - if(q >= 4) { + if(q > 128 || (q >= 4 && nacl)) { gconreg(AMOVL, q, D_CX); gins(AREP, N, N); // repeat gins(ASTOSL, N, N); // STOL AL,*(DI)+ + } else if(q >= 4) { + p = gins(ADUFFZERO, N, N); + p->to.type = D_ADDR; + p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); + // 1 and 128 = magic constants: see ../../pkg/runtime/asm_386.s + p->to.offset = 1*(128-q); } else while(q > 0) { gins(ASTOSL, N, N); // STOL AL,*(DI)+ q--; } - if(c >= 4) { - gconreg(AMOVL, c, D_CX); - gins(AREP, N, N); // repeat - gins(ASTOSB, N, N); // STOB AL,*(DI)+ - } else while(c > 0) { gins(ASTOSB, N, N); // STOB AL,*(DI)+ c--; @@ -236,7 +287,9 @@ ginscall(Node *f, int proc) if(proc == 2) { nodreg(®, types[TINT64], D_AX); gins(ATESTL, ®, ®); - patch(gbranch(AJNE, T, -1), retpc); + p = gbranch(AJEQ, T, +1); + cgen_ret(N); + patch(p, pc); } break; } @@ -437,15 +490,15 @@ cgen_ret(Node *n) { Prog *p; - genlist(n->list); // copy out args - if(retpc) { - 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); } } @@ -663,6 +716,18 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx) gmove(&t2, &n1); gmove(&t1, ax); 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), &n1, &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), &n1, &n4); @@ -1246,8 +1311,8 @@ expandchecks(Prog *firstp) p->link = p1; p1->lineno = p->lineno; p2->lineno = p->lineno; - p1->loc = 9999; - p2->loc = 9999; + p1->pc = 9999; + p2->pc = 9999; p->as = ACMPL; p->to.type = D_CONST; p->to.offset = 0; diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c index 0517824e0..fa0605e6c 100644 --- a/src/cmd/8g/gobj.c +++ b/src/cmd/8g/gobj.c @@ -32,229 +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; - if(a->offset2 != 0) - t |= T_OFFSET2; - 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_OFFSET2) { /* implies offset */ - l = a->offset2; - 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) { @@ -265,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; @@ -284,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+4; // skip header a->etype = TINT32; @@ -301,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; @@ -386,7 +163,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; @@ -411,7 +188,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); @@ -439,28 +216,6 @@ dgostringptr(Sym *s, int off, char *str) return dgostrlitptr(s, off, lit); } - -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) { @@ -471,12 +226,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/8g/gsubr.c b/src/cmd/8g/gsubr.c index 34703ba6e..2f3cb28c8 100644 --- a/src/cmd/8g/gsubr.c +++ b/src/cmd/8g/gsubr.c @@ -48,7 +48,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++; } @@ -137,7 +137,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* @@ -161,13 +161,8 @@ 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); pl->firstpc = pc; @@ -199,8 +194,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) @@ -227,7 +222,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; @@ -245,7 +240,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); } int @@ -273,7 +268,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); } } @@ -437,6 +432,7 @@ optoas(int op, Type *t) case CASE(OADD, TINT32): case CASE(OADD, TUINT32): case CASE(OADD, TPTR32): + case CASE(OADDPTR, TPTR32): a = AADDL; break; @@ -1048,6 +1044,7 @@ Node* nodarg(Type *t, int fp) { Node *n; + NodeList *l; Type *first; Iter savet; @@ -1072,6 +1069,14 @@ nodarg(Type *t, int fp) break; case TFIELD: + if(fp == 1 && t->sym != S && !isblanksym(t->sym)) { + for(l=curfn->dcl; l; l=l->next) { + n = l->n; + if((n->class == PPARAM || n->class == PPARAMOUT) && n->sym == t->sym) + return n; + } + } + n = nod(ONAME, N, N); n->type = t->type; n->sym = t->sym; @@ -1692,7 +1697,6 @@ floatmove(Node *f, Node *t) gins(ACMPL, &thi, ncon(0)); p1 = gbranch(AJLT, T, 0); // native - t1.type = types[TINT64]; nodreg(&r1, types[tt], D_F0); gins(AFMOVV, &t1, &r1); if(tt == TFLOAT32) @@ -2178,10 +2182,12 @@ gins(int as, Node *f, Node *t) 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; if(n == N) return; @@ -2193,12 +2199,12 @@ naddr(Node *n, Addr *a, int canemitcode) case OREGISTER: a->type = n->val.u.reg; - a->sym = S; + a->sym = nil; break; case OINDREG: a->type = n->val.u.reg+D_INDIR; - a->sym = n->sym; + a->sym = linksym(n->sym); a->offset = n->xoffset; break; @@ -2208,20 +2214,22 @@ naddr(Node *n, Addr *a, int canemitcode) a->etype = 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->offset = n->xoffset; - a->sym = S; + a->sym = nil; break; case OCFUNC: naddr(n->left, a, canemitcode); - a->sym = n->left->sym; + a->sym = linksym(n->left->sym); break; case ONAME: @@ -2233,17 +2241,17 @@ naddr(Node *n, Addr *a, int canemitcode) a->width = n->type->width; } 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) { @@ -2262,9 +2270,10 @@ naddr(Node *n, Addr *a, int canemitcode) case PFUNC: a->index = D_EXTERN; a->type = D_ADDR; - a->sym = funcsym(a->sym); + s = funcsym(s); break; } + a->sym = linksym(s); break; case OLITERAL: @@ -2278,7 +2287,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; @@ -2286,12 +2295,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; @@ -2327,7 +2336,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; diff --git a/src/cmd/8g/list.c b/src/cmd/8g/list.c deleted file mode 100644 index ec02ba5c5..000000000 --- a/src/cmd/8g/list.c +++ /dev/null @@ -1,316 +0,0 @@ -// Derived from Inferno utils/8c/list.c -// http://code.google.com/p/inferno-os/source/browse/utils/8c/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), "%d(%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), "$%d,%R", a->offset, i); - else - snprint(str, sizeof(str), "%R", i); - break; - - case D_NONE: - str[0] = 0; - break; - - case D_BRANCH: - snprint(str, sizeof(str), "%d", a->u.branch->loc); - break; - - case D_EXTERN: - snprint(str, sizeof(str), "%S+%d(SB)", a->sym, a->offset); - break; - - case D_STATIC: - snprint(str, sizeof(str), "%S<>+%d(SB)", a->sym, a->offset); - break; - - case D_AUTO: - snprint(str, sizeof(str), "%S+%d(SP)", a->sym, a->offset); - break; - - case D_PARAM: - snprint(str, sizeof(str), "%S+%d(FP)", a->sym, a->offset); - break; - - case D_CONST: - if(fp->flags & FmtLong) { - d1 = a->offset; - d2 = a->offset2; - snprint(str, sizeof(str), "$%lud-%lud", (ulong)d1, (ulong)d2); - break; - } - snprint(str, sizeof(str), "$%d", 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", - - "AH", /* [D_AH] */ - "CH", - "DH", - "BH", - - "AX", /* [D_AX] */ - "CX", - "DX", - "BX", - "SP", - "BP", - "SI", - "DI", - - "F0", /* [D_F0] */ - "F1", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - - "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", - - "DR0", /* [D_DR] */ - "DR1", - "DR2", - "DR3", - "DR4", - "DR5", - "DR6", - "DR7", - - "TR0", /* [D_TR] */ - "TR1", - "TR2", - "TR3", - "TR4", - "TR5", - "TR6", - "TR7", - - "X0", /* [D_X0] */ - "X1", - "X2", - "X3", - "X4", - "X5", - "X6", - "X7", - - "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/8g/opt.h b/src/cmd/8g/opt.h index 0d99bdb97..77a69e13a 100644 --- a/src/cmd/8g/opt.h +++ b/src/cmd/8g/opt.h @@ -109,6 +109,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; @@ -155,8 +156,6 @@ int32 FtoB(int); int BtoR(int32); int BtoF(int32); -#pragma varargck type "D" Adr* - /* * prog.c */ diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c index 966c0421b..a4e516dd3 100644 --- a/src/cmd/8g/peep.c +++ b/src/cmd/8g/peep.c @@ -107,7 +107,7 @@ peep(Prog *firstp) switch(p->as) { case ALEAL: 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; @@ -387,6 +387,8 @@ subprop(Flow *r0) if(uniqs(r) == nil) break; p = r->prog; + if(p->as == AVARDEF || p->as == AVARKILL) + continue; proginfo(&info, p); if(info.flags & Call) return 0; @@ -478,7 +480,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']) @@ -516,7 +518,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']) @@ -547,7 +549,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; @@ -557,7 +559,7 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; case ARET: - if(s != A) + if(s != nil) return 1; return 3; @@ -569,7 +571,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; @@ -584,6 +586,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)) @@ -599,7 +603,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; @@ -608,7 +612,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); @@ -727,7 +731,7 @@ loop: return; p = r->prog; - t = copyu(p, v0, A); + t = copyu(p, v0, nil); switch(t) { case 0: // miss case 1: // use @@ -743,7 +747,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/8g/prog.c b/src/cmd/8g/prog.c index 14f197b6a..8eed67f6d 100644 --- a/src/cmd/8g/prog.c +++ b/src/cmd/8g/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. @@ -136,11 +138,16 @@ static ProgInfo progtable[ALAST] = { [AFMOVW]= {SizeW | LeftAddr | RightWrite}, [AFMOVV]= {SizeQ | LeftAddr | RightWrite}, - [AFMOVDP]= {SizeD | LeftRead | RightAddr}, - [AFMOVFP]= {SizeF | LeftRead | RightAddr}, - [AFMOVLP]= {SizeL | LeftRead | RightAddr}, - [AFMOVWP]= {SizeW | LeftRead | RightAddr}, - [AFMOVVP]= {SizeQ | LeftRead | RightAddr}, + // These instructions are marked as RightAddr + // so that the register optimizer does not try to replace the + // memory references with integer register references. + // But they do not use the previous value at the address, so + // we also mark them RightWrite. + [AFMOVDP]= {SizeD | LeftRead | RightWrite | RightAddr}, + [AFMOVFP]= {SizeF | LeftRead | RightWrite | RightAddr}, + [AFMOVLP]= {SizeL | LeftRead | RightWrite | RightAddr}, + [AFMOVWP]= {SizeW | LeftRead | RightWrite | RightAddr}, + [AFMOVVP]= {SizeQ | LeftRead | RightWrite | RightAddr}, [AFMULD]= {SizeD | LeftAddr | RightRdwr}, [AFMULDP]= {SizeD | LeftAddr | RightRdwr}, @@ -193,6 +200,7 @@ static ProgInfo progtable[ALAST] = { [AMOVSB]= {OK, DI|SI, DI|SI}, [AMOVSL]= {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}, @@ -285,6 +293,7 @@ static ProgInfo progtable[ALAST] = { [ASTOSB]= {OK, AX|DI, DI}, [ASTOSL]= {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/8g/reg.c b/src/cmd/8g/reg.c index a85c6608a..fd610f87a 100644 --- a/src/cmd/8g/reg.c +++ b/src/cmd/8g/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; @@ -108,6 +84,8 @@ static char* regname[] = { static Node* regnodes[NREGVAR]; +static void walkvardef(Node *n, Reg *r, int active); + void regopt(Prog *firstp) { @@ -115,7 +93,7 @@ regopt(Prog *firstp) Prog *p; Graph *g; ProgInfo info; - int i, z; + int i, z, active; uint32 vreg; Bits bit; @@ -124,8 +102,7 @@ regopt(Prog *firstp) exregoffset = D_DI; // no externals first = 0; } - - fixjmp(firstp); + mergetemp(firstp); /* @@ -147,12 +124,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 @@ -160,12 +135,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. @@ -228,6 +209,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 @@ -367,6 +368,8 @@ brk: /* * free aux structures. peep allocates new ones. */ + for(i=0; i<nvar; i++) + var[i].node->opt = nil; flowend(g); firstr = R; @@ -423,6 +426,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 @@ -436,7 +465,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; @@ -450,7 +479,7 @@ 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 @@ -618,6 +647,16 @@ mkvar(Reg *r, Adr *a) if(nvar >= NVAR) { if(debug['w'] > 1 && node != N) fatal("variable not optimized: %D", a); + + // 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; } @@ -630,10 +669,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+%d %#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) @@ -642,6 +684,46 @@ mkvar(Reg *r, Adr *a) if(n == D_PARAM) 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=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); + ostats.nvar++; return bit; @@ -653,7 +735,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++) { @@ -672,10 +755,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: @@ -691,17 +825,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]) | @@ -824,18 +947,19 @@ paint1(Reg *r, int bn) r->act.b[z] |= bb; p = r->f.prog; - if(r->use1.b[z] & bb) { - change += CREF * r->f.loop; - if(p->as == AFMOVL || p->as == AFMOVW) - if(BtoR(bb) != D_F0) - change = -CINF; - } - - if((r->use2.b[z]|r->set.b[z]) & bb) { - change += CREF * r->f.loop; - if(p->as == AFMOVL || p->as == AFMOVW) - if(BtoR(bb) != D_F0) - change = -CINF; + if(r->f.prog->as != ANOP) { // don't give credit for NOPs + if(r->use1.b[z] & bb) { + change += CREF * r->f.loop; + if(p->as == AFMOVL || p->as == AFMOVW) + if(BtoR(bb) != D_F0) + change = -CINF; + } + if((r->use2.b[z]|r->set.b[z]) & bb) { + change += CREF * r->f.loop; + if(p->as == AFMOVL || p->as == AFMOVW) + if(BtoR(bb) != D_F0) + change = -CINF; + } } if(STORE(r) & r->regdiff.b[z] & bb) { @@ -877,7 +1001,7 @@ regset(Reg *r, uint32 bb) v = zprog.from; while(b = bb & ~(bb-1)) { v.type = b & 0xFF ? BtoR(b): BtoF(b); - c = copyu(r->f.prog, &v, A); + c = copyu(r->f.prog, &v, nil); if(c == 3) set |= b; bb &= ~b; @@ -896,7 +1020,7 @@ reguse(Reg *r, uint32 bb) v = zprog.from; while(b = bb & ~(bb-1)) { v.type = b & 0xFF ? 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; @@ -1038,8 +1162,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; @@ -1140,15 +1263,15 @@ dumpit(char *str, Flow *r0, int isreg) r1 = r->p2; if(r1 != nil) { print(" pred:"); - for(; r1 != nil; r1 = r->p2link) - print(" %.4ud", r1->prog->loc); + for(; r1 != nil; r1 = r1->p2link) + print(" %.4ud", (int)r1->prog->pc); print("\n"); } // r1 = r->s1; // if(r1 != nil) { // print(" succ:"); // for(; r1 != R; r1 = r1->s1) -// print(" %.4ud", r1->prog->loc); +// print(" %.4ud", (int)r1->prog->pc); // print("\n"); // } } |