diff options
Diffstat (limited to 'src/cmd/5g')
-rw-r--r-- | src/cmd/5g/cgen.c | 66 | ||||
-rw-r--r-- | src/cmd/5g/galign.c | 9 | ||||
-rw-r--r-- | src/cmd/5g/gg.h | 50 | ||||
-rw-r--r-- | src/cmd/5g/ggen.c | 195 | ||||
-rw-r--r-- | src/cmd/5g/gobj.c | 264 | ||||
-rw-r--r-- | src/cmd/5g/gsubr.c | 66 | ||||
-rw-r--r-- | src/cmd/5g/list.c | 342 | ||||
-rw-r--r-- | src/cmd/5g/opt.h | 1 | ||||
-rw-r--r-- | src/cmd/5g/peep.c | 156 | ||||
-rw-r--r-- | src/cmd/5g/prog.c | 10 | ||||
-rw-r--r-- | src/cmd/5g/reg.c | 267 |
11 files changed, 566 insertions, 860 deletions
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c index 2d260e72d..9011b2022 100644 --- a/src/cmd/5g/cgen.c +++ b/src/cmd/5g/cgen.c @@ -254,6 +254,7 @@ cgen(Node *n, Node *res) case OOR: case OXOR: case OADD: + case OADDPTR: case OMUL: a = optoas(n->op, nl->type); goto sbop; @@ -604,6 +605,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(AMOVW, &n1, &n2); @@ -1410,10 +1412,11 @@ stkof(Node *n) void sgen(Node *n, Node *res, int64 w) { - Node dst, src, tmp, nend; + Node dst, src, tmp, nend, r0, r1, r2, *f; int32 c, odst, osrc; int dir, align, op; Prog *p, *ploop; + NodeList *l; if(debug['g']) { print("\nsgen w=%lld\n", w); @@ -1439,6 +1442,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; @@ -1480,18 +1490,59 @@ sgen(Node *n, Node *res, int64 w) } if(osrc%align != 0 || odst%align != 0) fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align); + // if we are copying forward on the stack and // the src and dst overlap, then reverse direction dir = align; if(osrc < odst && odst < osrc+w) dir = -dir; + if(op == AMOVW && dir > 0 && c >= 4 && c <= 128) { + r0.op = OREGISTER; + r0.val.u.reg = REGALLOC_R0; + r1.op = OREGISTER; + r1.val.u.reg = REGALLOC_R0 + 1; + r2.op = OREGISTER; + r2.val.u.reg = REGALLOC_R0 + 2; + + regalloc(&src, types[tptr], &r1); + regalloc(&dst, types[tptr], &r2); + if(n->ullman >= res->ullman) { + // eval n first + agen(n, &src); + if(res->op == ONAME) + gvardef(res); + agen(res, &dst); + } else { + // eval res first + if(res->op == ONAME) + gvardef(res); + agen(res, &dst); + agen(n, &src); + } + regalloc(&tmp, types[tptr], &r0); + f = sysfunc("duffcopy"); + p = gins(ADUFFCOPY, N, f); + afunclit(&p->to, f); + // 8 and 128 = magic constants: see ../../pkg/runtime/asm_arm.s + p->to.offset = 8*(128-c); + + regfree(&tmp); + regfree(&src); + regfree(&dst); + return; + } + if(n->ullman >= res->ullman) { agenr(n, &dst, res); // temporarily use dst regalloc(&src, types[tptr], N); gins(AMOVW, &dst, &src); + if(res->op == ONAME) + gvardef(res); agen(res, &dst); } else { + if(res->op == ONAME) + gvardef(res); agenr(res, &dst, res); agenr(n, &src, N); } @@ -1624,8 +1675,17 @@ 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: + if(nl->op == ONAME) + gvardef(nl); nodl.xoffset += Array_array; nodl.type = ptrto(nl->type->type); @@ -1656,6 +1716,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]); @@ -1677,6 +1739,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/5g/galign.c b/src/cmd/5g/galign.c index 1fbf633f9..a62102ef8 100644 --- a/src/cmd/5g/galign.c +++ b/src/cmd/5g/galign.c @@ -8,6 +8,12 @@ int thechar = '5'; char* thestring = "arm"; +LinkArch* thelinkarch = &linkarm; + +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; @@ -38,5 +45,5 @@ betypeinit(void) zprog.from.reg = NREG; zprog.to = zprog.from; - listinit(); + listinit5(); } diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h index 860817f69..413e93c24 100644 --- a/src/cmd/5g/gg.h +++ b/src/cmd/5g/gg.h @@ -9,44 +9,6 @@ #include "../gc/go.h" #include "../5l/5.out.h" -typedef struct Addr Addr; - -struct Addr -{ - int32 offset; - int32 offset2; - - union { - double dval; - vlong vval; - Prog* branch; - char sval[NSNAME]; - } u; - - Sym* sym; - Sym* gotype; - Node* node; - int width; - uchar type; - char name; - uchar reg; - uchar etype; -}; -#define A ((Addr*)0) - -struct Prog -{ - uint32 loc; // pc offset in this func - uint32 lineno; // source line that generated this - Prog* link; // next instruction in this func - void* opt; // for optimizer passes - short as; // opcode - uchar reg; // doubles as width in DATA op - uchar scond; - Addr from; // src address - Addr to; // dst address -}; - #define TEXTFLAG reg #define REGALLOC_R0 0 @@ -58,7 +20,6 @@ EXTERN int32 dynloc; EXTERN uchar reg[REGALLOC_FMAX+1]; EXTERN int32 pcloc; // instruction counter EXTERN Strlit emptystring; -extern char* anames[]; EXTERN Prog zprog; EXTERN Node* newproc; EXTERN Node* deferproc; @@ -67,7 +28,6 @@ EXTERN Node* panicindex; EXTERN Node* panicslice; EXTERN Node* throwreturn; extern long unmappedzero; -EXTERN int maxstksize; /* * gen.c @@ -156,16 +116,6 @@ void datastring(char*, int, Addr*); /* * list.c */ -int Aconv(Fmt*); -int Cconv(Fmt*); -int Dconv(Fmt*); -int Mconv(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 "M" Addr* diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c index 040c3d2a9..fb32c2f36 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -9,78 +9,114 @@ #include "gg.h" #include "opt.h" -static Prog* appendp(Prog*, int, int, int, int32, int, int, int32); +static Prog* appendpp(Prog*, int, int, int, int32, int, int, int32); +static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0); void -defframe(Prog *ptxt, Bvec *bv) +defframe(Prog *ptxt) { - int i, j, first; - uint32 frame; - Prog *p, *p1; - + uint32 frame, r0; + Prog *p; + vlong hi, lo; + NodeList *l; + Node *n; + // fill in argument size ptxt->to.type = D_CONST2; 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, + + // insert code to contain ambiguously live variables // so that garbage collector only sees initialized values // when it looks for pointers. p = ptxt; - while(p->link->as == AFUNCDATA || p->link->as == APCDATA || p->link->as == ATYPE) - p = p->link; - if(stkzerosize >= 8*widthptr) { - p = appendp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0); - p = appendp(p, AADD, D_CONST, NREG, 4+frame-stkzerosize, D_REG, 1, 0); + lo = hi = 0; + r0 = 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 = rnd(n->xoffset, widthptr); + continue; + } + // zero old range + p = zerorange(p, frame, lo, hi, &r0); + + // set new range + hi = n->xoffset + n->type->width; + lo = n->xoffset; + } + // zero final range + zerorange(p, frame, lo, hi, &r0); +} + +static Prog* +zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0) +{ + vlong cnt, i; + Prog *p1; + Node *f; + + cnt = hi - lo; + if(cnt == 0) + return p; + if(*r0 == 0) { + p = appendpp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0); + *r0 = 1; + } + if(cnt < 4*widthptr) { + for(i = 0; i < cnt; i += widthptr) + p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame+lo+i); + } else if(cnt <= 128*widthptr) { + p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0); p->reg = REGSP; - p = appendp(p, AADD, D_CONST, NREG, stkzerosize, D_REG, 2, 0); + p = appendpp(p, ADUFFZERO, D_NONE, NREG, 0, D_OREG, NREG, 0); + f = sysfunc("duffzero"); + naddr(f, &p->to, 1); + afunclit(&p->to, f); + p->to.offset = 4*(128-cnt/widthptr); + } else { + p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0); + p->reg = REGSP; + p = appendpp(p, AADD, D_CONST, NREG, cnt, D_REG, 2, 0); p->reg = 1; - p1 = p = appendp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4); + p1 = p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4); p->scond |= C_PBIT; - p = appendp(p, ACMP, D_REG, 1, 0, D_NONE, 0, 0); + p = appendpp(p, ACMP, D_REG, 1, 0, D_NONE, 0, 0); p->reg = 2; - p = appendp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0); + p = appendpp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0); patch(p, p1); - } else { - first = 1; - j = (stkptrsize - stkzerosize)/widthptr * 2; - for(i=0; i<stkzerosize; i+=widthptr) { - if(bvget(bv, j) || bvget(bv, j+1)) { - if(first) { - p = appendp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0); - first = 0; - } - p = appendp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame-stkzerosize+i); - } - j += 2; - } } + return p; } -static Prog* -appendp(Prog *p, int as, int ftype, int freg, int32 foffset, int ttype, int treg, int32 toffset) -{ - Prog *q; - - q = mal(sizeof(*q)); - clearp(q); - q->as = as; - q->lineno = p->lineno; - q->from.type = ftype; - q->from.reg = freg; - q->from.offset = foffset; - q->to.type = ttype; - q->to.reg = treg; - q->to.offset = toffset; - q->link = p->link; - p->link = q; - return q; +static Prog* +appendpp(Prog *p, int as, int ftype, int freg, int32 foffset, int ttype, int treg, int32 toffset) +{ + Prog *q; + + q = mal(sizeof(*q)); + clearp(q); + q->as = as; + q->lineno = p->lineno; + q->from.type = ftype; + q->from.reg = freg; + q->from.offset = foffset; + q->to.type = ttype; + q->to.reg = treg; + q->to.offset = toffset; + q->link = p->link; + p->link = q; + return q; } // Sweep the prog list to mark any used nodes. @@ -88,13 +124,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.name == D_AUTO && p->from.node) + if (p->from.node) p->from.node->used = 1; - if (p->to.name == D_AUTO && p->to.node) + if (p->to.node) p->to.node->used = 1; } } @@ -110,6 +146,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.name == D_AUTO && p->from.node) p->from.offset += p->from.node->stkdelta; @@ -245,7 +291,9 @@ ginscall(Node *f, int proc) nodconst(&con, types[TINT32], 0); p = gins(ACMP, &con, N); p->reg = 0; - patch(gbranch(ABNE, T, -1), retpc); + p = gbranch(ABEQ, T, +1); + cgen_ret(N); + patch(p, pc); } break; } @@ -459,16 +507,16 @@ 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.name = D_EXTERN; p->to.type = D_CONST; - p->to.sym = n->left->sym; + p->to.sym = linksym(n->left->sym); } } @@ -816,14 +864,13 @@ void clearfat(Node *nl) { uint32 w, c, q; - Node dst, nc, nz, end; + Node dst, nc, nz, end, r0, r1, *f; Prog *p, *pl; /* 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)) @@ -832,13 +879,17 @@ clearfat(Node *nl) c = w % 4; // bytes q = w / 4; // quads - regalloc(&dst, types[tptr], N); + r0.op = OREGISTER; + r0.val.u.reg = REGALLOC_R0; + r1.op = OREGISTER; + r1.val.u.reg = REGALLOC_R0 + 1; + regalloc(&dst, types[tptr], &r1); agen(nl, &dst); nodconst(&nc, types[TUINT32], 0); - regalloc(&nz, types[TUINT32], 0); + regalloc(&nz, types[TUINT32], &r0); cgen(&nc, &nz); - if(q >= 4) { + if(q > 128) { regalloc(&end, types[tptr], N); p = gins(AMOVW, &dst, &end); p->from.type = D_CONST; @@ -855,6 +906,12 @@ clearfat(Node *nl) patch(gbranch(ABNE, T, 0), pl); regfree(&end); + } else if(q >= 4) { + f = sysfunc("duffzero"); + p = gins(ADUFFZERO, N, f); + afunclit(&p->to, f); + // 4 and 128 = magic constants: see ../../pkg/runtime/asm_arm.s + p->to.offset = 4*(128-q); } else while(q > 0) { p = gins(AMOVW, &nz, &dst); @@ -901,7 +958,7 @@ expandchecks(Prog *firstp) p1->link = p->link; p->link = p1; p1->lineno = p->lineno; - p1->loc = 9999; + p1->pc = 9999; p1->as = AMOVW; p1->from.type = D_REG; p1->from.reg = reg; diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c index 212ffc271..5e988878f 100644 --- a/src/cmd/5g/gobj.c +++ b/src/cmd/5g/gobj.c @@ -32,235 +32,6 @@ #include <libc.h> #include "gg.h" -void -zname(Biobuf *b, Sym *s, int t) -{ - BPUTC(b, ANAME); /* as */ - BPUTC(b, t); /* type */ - BPUTC(b, s->sym); /* sym */ - - Bputname(b, s); -} - -void -zfile(Biobuf *b, char *p, int n) -{ - BPUTC(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; - - BPUTC(b, AHISTORY); - BPUTC(b, C_SCOND_NONE); - BPUTC(b, NREG); - 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; - char *n; - - switch(a->type) { - case D_STATIC: - case D_AUTO: - case D_EXTERN: - case D_PARAM: - // TODO(kaib): remove once everything seems to work - fatal("We should no longer generate these as types"); - - default: - BPUTC(b, a->type); - BPUTC(b, a->reg); - BPUTC(b, s); - BPUTC(b, a->name); - BPUTC(b, gotype); - } - - switch(a->type) { - default: - print("unknown type %d in zaddr\n", a->type); - - case D_NONE: - case D_REG: - case D_FREG: - case D_PSR: - break; - - case D_CONST2: - l = a->offset2; - BPUTLE4(b, l); // fall through - case D_OREG: - case D_CONST: - case D_SHIFT: - case D_STATIC: - case D_AUTO: - case D_EXTERN: - case D_PARAM: - l = a->offset; - BPUTLE4(b, l); - break; - - case D_BRANCH: - if(a->u.branch == nil) - fatal("unpatched branch"); - a->offset = a->u.branch->loc; - l = a->offset; - BPUTLE4(b, l); - break; - - case D_SCONST: - n = a->u.sval; - for(i=0; i<NSNAME; i++) { - BPUTC(b, *n); - n++; - } - break; - - case D_REGREG: - case D_REGREG2: - BPUTC(b, a->offset); - break; - - case D_FCONST: - ieeedtod(&e, a->u.dval); - BPUTLE4(b, e); - BPUTLE4(b, e >> 32); - break; - } -} - -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->name; - if(t == D_ADDR) - t = a->name; - 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; - } - - BPUTC(bout, p->as); - BPUTC(bout, p->scond); - BPUTC(bout, p->reg); - BPUTLE4(bout, p->lineno); - zaddr(bout, &p->from, sf, gf); - zaddr(bout, &p->to, st, gt); - } - } -} - int dsname(Sym *sym, int off, char *t, int n) { @@ -272,7 +43,7 @@ dsname(Sym *sym, int off, char *t, int n) p->from.etype = TINT32; p->from.offset = off; p->from.reg = NREG; - p->from.sym = sym; + p->from.sym = linksym(sym); p->reg = n; @@ -299,7 +70,7 @@ datastring(char *s, int len, Addr *a) a->etype = TINT32; a->offset = widthptr+4; // skip header a->reg = NREG; - a->sym = sym; + a->sym = linksym(sym); a->node = sym->def; } @@ -318,7 +89,7 @@ datagostring(Strlit *sval, Addr *a) a->etype = TINT32; a->offset = 0; // header a->reg = NREG; - a->sym = sym; + a->sym = linksym(sym); a->node = sym->def; } @@ -401,7 +172,7 @@ dstringptr(Sym *s, int off, char *str) p = gins(ADATA, N, N); p->from.type = D_OREG; p->from.name = D_EXTERN; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->reg = widthptr; @@ -425,7 +196,7 @@ dgostrlitptr(Sym *s, int off, Strlit *lit) p = gins(ADATA, N, N); p->from.type = D_OREG; p->from.name = D_EXTERN; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->reg = widthptr; datagostring(lit, &p->to); @@ -453,27 +224,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_OREG; - p->from.name = D_EXTERN; - p->from.sym = s; - p->from.offset = off; - p->reg = wid; - p->to.type = D_CONST; - p->to.name = D_NONE; - p->to.offset = v; - off += wid; - - return off; -} - -int dsymptr(Sym *s, int off, Sym *x, int xoff) { Prog *p; @@ -483,12 +233,12 @@ dsymptr(Sym *s, int off, Sym *x, int xoff) p = gins(ADATA, N, N); p->from.type = D_OREG; p->from.name = D_EXTERN; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->reg = widthptr; p->to.type = D_CONST; p->to.name = D_EXTERN; - p->to.sym = x; + p->to.sym = linksym(x); p->to.offset = xoff; off += widthptr; diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index 27749b7a7..f66c87b5a 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -50,7 +50,7 @@ clearp(Prog *p) p->to.type = D_NONE; p->to.name = D_NONE; p->to.reg = NREG; - p->loc = pcloc; + p->pc = pcloc; pcloc++; } @@ -138,7 +138,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* @@ -162,12 +162,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); @@ -200,8 +195,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) @@ -228,7 +223,7 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata) p = gins(AGLOBL, N, N); p->from.type = D_OREG; p->from.name = D_EXTERN; - p->from.sym = s; + p->from.sym = linksym(s); p->to.type = D_CONST; p->to.name = D_NONE; p->to.offset = width; @@ -246,7 +241,7 @@ gtrack(Sym *s) p = gins(AUSEFIELD, N, N); p->from.type = D_OREG; p->from.name = D_EXTERN; - p->from.sym = s; + p->from.sym = linksym(s); } int @@ -275,7 +270,7 @@ afunclit(Addr *a, Node *n) if(a->type == D_CONST && a->name == D_EXTERN || a->type == D_REG) { a->type = D_OREG; if(n->op == ONAME) - a->sym = n->sym; + a->sym = linksym(n->sym); } } @@ -475,6 +470,7 @@ Node* nodarg(Type *t, int fp) { Node *n; + NodeList *l; Type *first; Iter savet; @@ -496,6 +492,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; n->sym = t->sym; @@ -1196,10 +1200,12 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs) void naddr(Node *n, Addr *a, int canemitcode) { + Sym *s; + a->type = D_NONE; a->name = D_NONE; a->reg = NREG; - a->gotype = S; + a->gotype = nil; a->node = N; a->etype = 0; if(n == N) @@ -1223,7 +1229,7 @@ naddr(Node *n, Addr *a, int canemitcode) a->type = D_FREG; a->reg = n->val.u.reg - REGALLOC_F0; } - a->sym = S; + a->sym = nil; break; case OINDEX: @@ -1250,7 +1256,7 @@ naddr(Node *n, Addr *a, int canemitcode) case OINDREG: a->type = D_OREG; a->reg = n->val.u.reg; - a->sym = n->sym; + a->sym = linksym(n->sym); a->offset = n->xoffset; break; @@ -1260,22 +1266,24 @@ 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_OREG; a->name = D_PARAM; a->node = n->left->orig; break; case OCLOSUREVAR: + if(!curfn->needctxt) + fatal("closurevar without needctxt"); a->type = D_OREG; a->reg = 7; 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: @@ -1287,17 +1295,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); } a->type = D_OREG; @@ -1317,9 +1325,10 @@ naddr(Node *n, Addr *a, int canemitcode) case PFUNC: a->name = D_EXTERN; a->type = D_CONST; - a->sym = funcsym(a->sym); + s = funcsym(s); break; } + a->sym = linksym(s); break; case OLITERAL: @@ -1333,7 +1342,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; @@ -1341,12 +1350,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; @@ -1366,7 +1375,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; @@ -1592,6 +1601,7 @@ optoas(int op, Type *t) case CASE(OADD, TINT32): case CASE(OADD, TUINT32): case CASE(OADD, TPTR32): + case CASE(OADDPTR, TPTR32): a = AADD; break; diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c deleted file mode 100644 index 6c3f1d744..000000000 --- a/src/cmd/5g/list.c +++ /dev/null @@ -1,342 +0,0 @@ -// Derived from Inferno utils/5c/list.c -// http://code.google.com/p/inferno-os/source/browse/utils/5c/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" - -// TODO(kaib): make 5g/list.c congruent with 5l/list.c - -static int sconsize; -void -listinit(void) -{ - - fmtinstall('A', Aconv); // as - fmtinstall('C', Cconv); // conditional execution bit - fmtinstall('P', Pconv); // Prog* - fmtinstall('D', Dconv); // Addr* - fmtinstall('Y', Yconv); // sconst - fmtinstall('R', Rconv); // register - fmtinstall('M', Mconv); // names -} - -int -Pconv(Fmt *fp) -{ - char str[STRINGSZ], str1[STRINGSZ]; - Prog *p; - - p = va_arg(fp->args, Prog*); - sconsize = 8; - switch(p->as) { - default: - snprint(str1, sizeof(str1), "%A%C", p->as, p->scond); - if(p->reg == NREG && p->as != AGLOBL) - snprint(str, sizeof(str), "%.4d (%L) %-7s %D,%D", - p->loc, p->lineno, str1, &p->from, &p->to); - else - if (p->from.type != D_FREG) { - snprint(str, sizeof(str), "%.4d (%L) %-7s %D,R%d,%D", - p->loc, p->lineno, str1, &p->from, p->reg, &p->to); - } else - snprint(str, sizeof(str), "%.4d (%L) %-7A%C %D,F%d,%D", - p->loc, p->lineno, p->as, p->scond, &p->from, p->reg, &p->to); - break; - - case ADATA: - snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D", - p->loc, p->lineno, p->as, &p->from, p->reg, &p->to); - break; - } - return fmtstrcpy(fp, str); -} - -int -Dconv(Fmt *fp) -{ - char str[STRINGSZ]; - const char *op; - Addr *a; - int i; - int32 v; - - a = va_arg(fp->args, Addr*); - if(a == A) { - sprint(str, "<nil>"); - goto conv; - } - i = a->type; - switch(i) { - - default: - sprint(str, "GOK-type(%d)", a->type); - break; - - case D_NONE: - str[0] = 0; - if(a->name != D_NONE || a->reg != NREG || a->sym != S) - sprint(str, "%M(R%d)(NONE)", a, a->reg); - break; - - case D_CONST: - if(a->reg != NREG) - sprint(str, "$%M(R%d)", a, a->reg); - else - sprint(str, "$%M", a); - break; - - case D_CONST2: - sprint(str, "$%d-%d", a->offset, a->offset2); - break; - - case D_SHIFT: - v = a->offset; - op = &"<<>>->@>"[(((v>>5) & 3) << 1)]; - if(v & (1<<4)) - sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15); - else - sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31); - if(a->reg != NREG) - sprint(str+strlen(str), "(R%d)", a->reg); - break; - - case D_OCONST: - sprint(str, "$*$%M", a); - if(a->reg != NREG) - sprint(str, "%M(R%d)(CONST)", a, a->reg); - break; - - case D_OREG: - if(a->reg != NREG) - sprint(str, "%M(R%d)", a, a->reg); - else - sprint(str, "%M", a); - break; - - case D_REG: - sprint(str, "R%d", a->reg); - if(a->name != D_NONE || a->sym != S) - sprint(str, "%M(R%d)(REG)", a, a->reg); - break; - - case D_REGREG: - sprint(str, "(R%d,R%d)", a->reg, (int)a->offset); - if(a->name != D_NONE || a->sym != S) - sprint(str, "%M(R%d)(REG)", a, a->reg); - break; - - case D_REGREG2: - sprint(str, "R%d,R%d", a->reg, (int)a->offset); - if(a->name != D_NONE || a->sym != S) - sprint(str, "%M(R%d)(REG)", a, a->reg); - break; - - case D_FREG: - sprint(str, "F%d", a->reg); - if(a->name != D_NONE || a->sym != S) - sprint(str, "%M(R%d)(REG)", a, a->reg); - break; - - case D_BRANCH: - if(a->u.branch == P || a->u.branch->loc == 0) { - if(a->sym != S) - sprint(str, "%s+%d(APC)", a->sym->name, a->offset); - else - sprint(str, "%d(APC)", a->offset); - } else - if(a->sym != S) - sprint(str, "%s+%d(APC)", a->sym->name, a->u.branch->loc); - else - sprint(str, "%d(APC)", a->u.branch->loc); - 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; - - // TODO(kaib): Add back -// 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; - } -conv: - fmtstrcpy(fp, str); - if(a->gotype) - fmtprint(fp, "{%s}", a->gotype->name); - return 0; -} - -int -Aconv(Fmt *fp) -{ - int i; - - i = va_arg(fp->args, int); - return fmtstrcpy(fp, anames[i]); -} - -char* strcond[16] = -{ - ".EQ", - ".NE", - ".HS", - ".LO", - ".MI", - ".PL", - ".VS", - ".VC", - ".HI", - ".LS", - ".GE", - ".LT", - ".GT", - ".LE", - "", - ".NV" -}; - -int -Cconv(Fmt *fp) -{ - char s[STRINGSZ]; - int c; - - c = va_arg(fp->args, int); - strcpy(s, strcond[c & C_SCOND]); - if(c & C_SBIT) - strcat(s, ".S"); - if(c & C_PBIT) - strcat(s, ".P"); - if(c & C_WBIT) - strcat(s, ".W"); - if(c & C_UBIT) /* ambiguous with FBIT */ - strcat(s, ".U"); - return fmtstrcpy(fp, s); -} - -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); -} - -int -Rconv(Fmt *fp) -{ - int r; - char str[STRINGSZ]; - - r = va_arg(fp->args, int); - snprint(str, sizeof(str), "R%d", r); - return fmtstrcpy(fp, str); -} - -int -Mconv(Fmt *fp) -{ - char str[STRINGSZ]; - Addr *a; - - a = va_arg(fp->args, Addr*); - switch(a->name) { - default: - snprint(str, sizeof(str), "GOK-name(%d)", a->name); - break; - - case D_NONE: - snprint(str, sizeof(str), "%d", a->offset); - 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; - } - return fmtstrcpy(fp, str); -} diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h index 15b9d1458..e3e3f78ed 100644 --- a/src/cmd/5g/opt.h +++ b/src/cmd/5g/opt.h @@ -96,6 +96,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/5g/peep.c b/src/cmd/5g/peep.c index c78fb3d1c..4aa645206 100644 --- a/src/cmd/5g/peep.c +++ b/src/cmd/5g/peep.c @@ -287,6 +287,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; @@ -397,7 +399,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']) @@ -435,7 +437,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']) @@ -479,7 +481,7 @@ constprop(Adr *c1, Adr *v1, Flow *r) if(debug['P']) print("; sub%D/%D", &p->from, v1); p->from = *v1; - } else if(copyu(p, v1, A) > 1) { + } else if(copyu(p, v1, nil) > 1) { if(debug['P']) print("; %Dset; return\n", v1); return; @@ -592,10 +594,10 @@ shiftprop(Flow *r) p1 = r1->prog; if(debug['P']) print("\n%P", p1); - switch(copyu(p1, &p->to, A)) { + switch(copyu(p1, &p->to, nil)) { case 0: /* not used or set */ - if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) || - (a.type == D_REG && copyu(p1, &a, A) > 1)) + if((p->from.type == D_REG && copyu(p1, &p->from, nil) > 1) || + (a.type == D_REG && copyu(p1, &a, nil) > 1)) FAIL("args modified"); continue; case 3: /* set, not used */ @@ -663,7 +665,7 @@ shiftprop(Flow *r) p1 = r1->prog; if(debug['P']) print("\n%P", p1); - switch(copyu(p1, &p->to, A)) { + switch(copyu(p1, &p->to, nil)) { case 0: /* not used or set */ continue; case 3: /* set, not used */ @@ -719,7 +721,7 @@ findpre(Flow *r, Adr *v) for(r1=uniqp(r); r1!=nil; r=r1,r1=uniqp(r)) { if(uniqs(r1) != r) return nil; - switch(copyu(r1->prog, v, A)) { + switch(copyu(r1->prog, v, nil)) { case 1: /* used */ case 2: /* read-alter-rewrite */ return nil; @@ -745,7 +747,7 @@ findinc(Flow *r, Flow *r2, Adr *v) for(r1=uniqs(r); r1!=nil && r1!=r2; r=r1,r1=uniqs(r)) { if(uniqp(r1) != r) return nil; - switch(copyu(r1->prog, v, A)) { + switch(copyu(r1->prog, v, nil)) { case 0: /* not touched */ continue; case 4: /* set and used */ @@ -787,7 +789,7 @@ nochange(Flow *r, Flow *r2, Prog *p) for(; r!=nil && r!=r2; r=uniqs(r)) { p = r->prog; for(i=0; i<n; i++) - if(copyu(p, &a[i], A) > 1) + if(copyu(p, &a[i], nil) > 1) return 0; } return 1; @@ -800,7 +802,7 @@ findu1(Flow *r, Adr *v) if(r->active) return 0; r->active = 1; - switch(copyu(r->prog, v, A)) { + switch(copyu(r->prog, v, nil)) { case 1: /* used */ case 2: /* read-alter-rewrite */ case 4: /* set and used */ @@ -943,7 +945,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(v->type != D_REG) return 0; if(p->from.type == D_CONST) { /* read reglist, read/rar */ - if(s != A) { + if(s != nil) { if(p->from.offset&(1<<v->reg)) return 1; if(copysub(&p->to, v, s, 1)) @@ -958,7 +960,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(p->from.offset&(1<<v->reg)) return 1; } else { /* read/rar, write reglist */ - if(s != A) { + if(s != nil) { if(p->to.offset&(1<<v->reg)) return 1; if(copysub(&p->from, v, s, 1)) @@ -1003,7 +1005,7 @@ copyu(Prog *p, Adr *v, Adr *s) return 2; } } - if(s != A) { + if(s != nil) { if(copysub(&p->from, v, s, 1)) return 1; if(!copyas(&p->to, v)) @@ -1063,7 +1065,7 @@ copyu(Prog *p, Adr *v, Adr *s) case ACMN: case ACASE: case ATST: /* read,, */ - if(s != A) { + if(s != nil) { if(copysub(&p->from, v, s, 1)) return 1; if(copysub1(p, v, s, 1)) @@ -1108,7 +1110,7 @@ copyu(Prog *p, Adr *v, Adr *s) case ABLT: case ABGT: case ABLE: - if(s != A) { + if(s != nil) { if(copysub(&p->from, v, s, 1)) return 1; return copysub1(p, v, s, 1); @@ -1120,7 +1122,7 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; case AB: /* funny */ - if(s != A) { + if(s != nil) { if(copysub(&p->to, v, s, 1)) return 1; return 0; @@ -1130,7 +1132,7 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; case ARET: /* funny */ - if(s != A) + if(s != nil) return 1; return 3; @@ -1138,7 +1140,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(v->type == D_REG) { if(v->reg <= REGEXT && v->reg > exregoffset) return 2; - if(v->reg == (uchar)REGARG) + if(v->reg == REGARG) return 2; } if(v->type == D_FREG) @@ -1147,7 +1149,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg) return 2; - if(s != A) { + if(s != nil) { if(copysub(&p->to, v, s, 1)) return 1; return 0; @@ -1155,15 +1157,37 @@ copyu(Prog *p, Adr *v, Adr *s) if(copyau(&p->to, v)) return 4; return 3; - + case ADUFFZERO: + // R0 is zero, used by DUFFZERO, cannot be substituted. + // R1 is ptr to memory, used and set, cannot be substituted. + if(v->type == D_REG) { + if(v->reg == REGALLOC_R0) + return 1; + if(v->reg == REGALLOC_R0+1) + return 2; + } + return 0; + case ADUFFCOPY: + // R0 is scratch, set by DUFFCOPY, cannot be substituted. + // R1, R2 areptr to src, dst, used and set, cannot be substituted. + if(v->type == D_REG) { + if(v->reg == REGALLOC_R0) + return 3; + if(v->reg == REGALLOC_R0+1 || v->reg == REGALLOC_R0+2) + return 2; + } + return 0; + case ATEXT: /* funny */ if(v->type == D_REG) - if(v->reg == (uchar)REGARG) + if(v->reg == REGARG) return 3; return 0; case APCDATA: case AFUNCDATA: + case AVARDEF: + case AVARKILL: return 0; } } @@ -1241,35 +1265,79 @@ copyau(Adr *a, Adr *v) return 0; } +static int +a2type(Prog *p) +{ + if(p->reg == NREG) + return D_NONE; + + switch(p->as) { + default: + fatal("a2type: unhandled %P", p); + + case AAND: + case AEOR: + case ASUB: + case ARSB: + case AADD: + case AADC: + case ASBC: + case ARSC: + case ATST: + case ATEQ: + case ACMP: + case ACMN: + case AORR: + case ABIC: + case AMVN: + case ASRL: + case ASRA: + case ASLL: + case AMULU: + case ADIVU: + case AMUL: + case ADIV: + case AMOD: + case AMODU: + case AMULA: + case AMULL: + case AMULAL: + case AMULLU: + case AMULALU: + case AMULWT: + case AMULWB: + case AMULAWT: + case AMULAWB: + return D_REG; + + case ACMPF: + case ACMPD: + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + case ASQRTF: + case ASQRTD: + case AABSF: + case AABSD: + return D_FREG; + } +} + /* * compare v to the center * register in p (p->reg) - * the trick is that this - * register might be D_REG - * D_FREG. there are basically - * two cases, - * ADD r,r,r - * CMP r,r, */ static int copyau1(Prog *p, Adr *v) { - - if(regtyp(v)) - if(p->reg == v->reg) { - if(p->to.type != D_NONE) { - if(v->type == p->to.type) - return 1; - return 0; - } - if(p->from.type != D_NONE) { - if(v->type == p->from.type) - return 1; - return 0; - } - print("copyau1: can't tell %P\n", p); - } - return 0; + if(v->type == D_REG && v->reg == NREG) + return 0; + return p->reg == v->reg && a2type(p) == v->type; } /* diff --git a/src/cmd/5g/prog.c b/src/cmd/5g/prog.c index 5aa6163d8..797bc0718 100644 --- a/src/cmd/5g/prog.c +++ b/src/cmd/5g/prog.c @@ -26,9 +26,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. @@ -91,6 +93,12 @@ static ProgInfo progtable[ALAST] = { [AMOVF]= {SizeF | LeftRead | RightWrite | Move}, [AMOVH]= {SizeW | LeftRead | RightWrite | Move}, [AMOVW]= {SizeL | LeftRead | RightWrite | Move}, + // In addtion, duffzero reads R0,R1 and writes R1. This fact is + // encoded in peep.c + [ADUFFZERO]= {Call}, + // In addtion, duffcopy reads R1,R2 and writes R0,R1,R2. This fact is + // encoded in peep.c + [ADUFFCOPY]= {Call}, // These should be split into the two different conversions instead // of overloading the one. diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index d2a8cc488..4762df506 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -56,30 +56,6 @@ rcmp(const void *a1, const void *a2) return p2->varno - p1->varno; } -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("ovar = %Q\n", ovar); -} - void excise(Flow *r) { @@ -153,13 +129,15 @@ static char* regname[] = { static Node* regnodes[NREGVAR]; +static void walkvardef(Node *n, Reg *r, int active); + void regopt(Prog *firstp) { Reg *r, *r1; Prog *p; Graph *g; - int i, z; + int i, z, active; uint32 vreg; Bits bit; ProgInfo info; @@ -168,8 +146,7 @@ regopt(Prog *firstp) fmtinstall('Q', Qconv); first = 0; } - - fixjmp(firstp); + mergetemp(firstp); /* @@ -191,12 +168,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 @@ -204,12 +179,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. @@ -271,6 +252,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 @@ -471,6 +472,14 @@ brk: dumpit("pass6", &firstr->f, 1); /* + * free aux structures. peep allocates new ones. + */ + for(i=0; i<nvar; i++) + var[i].node->opt = nil; + flowend(g); + firstr = R; + + /* * pass 7 * peep-hole on basic block */ @@ -523,20 +532,44 @@ brk: } if(p->as == AMOVW && vreg != 0) { - if(p->from.sym != S) + if(p->from.sym != nil) if(p->from.name == D_AUTO || p->from.name == D_PARAM) { p->from.offset += vreg; // print("%P adjusting from %d %d\n", p, vreg, p->from.type); } - if(p->to.sym != S) + if(p->to.sym != nil) if(p->to.name == D_AUTO || p->to.name == D_PARAM) { p->to.offset += vreg; // print("%P adjusting to %d %d\n", p, vreg, p->from.type); } } } +} - flowend(g); +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 == ABL) + break; + } + + for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1) + if(r2->f.s2 != nil) + walkvardef(n, (Reg*)r2->f.s2, active); } void @@ -551,6 +584,10 @@ addsplits(void) continue; if(r->f.prog->as == ABL) continue; + if(r->f.prog->as == ADUFFZERO) + continue; + if(r->f.prog->as == ADUFFCOPY) + continue; for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) { if(r1->f.loop <= 1) continue; @@ -596,11 +633,11 @@ addmove(Reg *r, int bn, int rn, int f) a = &p1->to; a->name = v->name; a->node = v->node; - a->sym = v->node->sym; + a->sym = linksym(v->node->sym); a->offset = v->offset; a->etype = v->etype; a->type = D_OREG; - if(a->etype == TARRAY || a->sym == S) + if(a->etype == TARRAY || a->sym == nil) a->type = D_CONST; if(v->addr) @@ -790,6 +827,16 @@ mkvar(Reg *r, Adr *a) if(nvar >= NVAR) { if(debug['w'] > 1 && node) 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; } @@ -804,9 +851,13 @@ mkvar(Reg *r, Adr *a) 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); - + // 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) for(z=0; z<BITS; z++) @@ -815,6 +866,45 @@ 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=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); + return bit; none: @@ -825,7 +915,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++) { @@ -844,10 +935,61 @@ prop(Reg *r, Bits ref, Bits cal) case ABL: 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: @@ -863,17 +1005,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]) | @@ -1004,18 +1135,20 @@ 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(debug['R'] > 1) - print("%d%P\tu1 %Q $%d\n", r->f.loop, - p, blsh(bn), change); - } - if((r->use2.b[z]|r->set.b[z]) & bb) { - change += CREF * r->f.loop; - if(debug['R'] > 1) - print("%d%P\tu2 %Q $%d\n", r->f.loop, - p, blsh(bn), change); + if(r->f.prog->as != ANOP) { // don't give credit for NOPs + if(r->use1.b[z] & bb) { + change += CREF * r->f.loop; + if(debug['R'] > 1) + print("%d%P\tu1 %Q $%d\n", r->f.loop, + p, blsh(bn), change); + } + if((r->use2.b[z]|r->set.b[z]) & bb) { + change += CREF * r->f.loop; + if(debug['R'] > 1) + print("%d%P\tu2 %Q $%d\n", r->f.loop, + p, blsh(bn), change); + } } if(STORE(r) & r->regdiff.b[z] & bb) { @@ -1172,7 +1305,7 @@ paint3(Reg *r, int bn, int32 rb, int rn) void addreg(Adr *a, int rn) { - a->sym = 0; + a->sym = nil; a->name = D_NONE; a->type = D_REG; a->reg = rn; @@ -1292,9 +1425,9 @@ 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); if(r->p1 != nil) - print(" (and %.4ud)", r->p1->prog->loc); + print(" (and %.4ud)", (int)r->p1->prog->pc); else print(" (only)"); print("\n"); @@ -1303,7 +1436,7 @@ dumpit(char *str, Flow *r0, int isreg) // if(r1 != nil) { // print(" succ:"); // for(; r1 != R; r1 = r1->s1) -// print(" %.4ud", r1->prog->loc); +// print(" %.4ud", (int)r1->prog->pc); // print("\n"); // } } |