diff options
Diffstat (limited to 'src/cmd/5g')
-rw-r--r-- | src/cmd/5g/Makefile | 35 | ||||
-rw-r--r-- | src/cmd/5g/cgen.c | 68 | ||||
-rw-r--r-- | src/cmd/5g/cgen64.c | 12 | ||||
-rw-r--r-- | src/cmd/5g/doc.go | 2 | ||||
-rw-r--r-- | src/cmd/5g/galign.c | 2 | ||||
-rw-r--r-- | src/cmd/5g/gg.h | 21 | ||||
-rw-r--r-- | src/cmd/5g/ggen.c | 9 | ||||
-rw-r--r-- | src/cmd/5g/gobj.c | 63 | ||||
-rw-r--r-- | src/cmd/5g/gsubr.c | 94 | ||||
-rw-r--r-- | src/cmd/5g/list.c | 4 | ||||
-rw-r--r-- | src/cmd/5g/peep.c | 10 | ||||
-rw-r--r-- | src/cmd/5g/reg.c | 177 |
12 files changed, 339 insertions, 158 deletions
diff --git a/src/cmd/5g/Makefile b/src/cmd/5g/Makefile index b47014a4e..3f528d751 100644 --- a/src/cmd/5g/Makefile +++ b/src/cmd/5g/Makefile @@ -1,36 +1,5 @@ -# Copyright 2009 The Go Authors. All rights reserved. +# Copyright 2012 The Go Authors. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -include ../../Make.inc -O:=$(HOST_O) - -TARG=5g - -HFILES=\ - ../gc/go.h\ - ../5l/5.out.h\ - gg.h\ - opt.h\ - -OFILES=\ - ../5l/enam.$O\ - cgen.$O\ - cgen64.$O\ - cplx.$O\ - galign.$O\ - ggen.$O\ - gobj.$O\ - gsubr.$O\ - list.$O\ - peep.$O\ - pgen.$O\ - reg.$O\ - -LIB=\ - ../gc/gc.a\ - -include ../../Make.ccmd - -%.$O: ../gc/%.c - $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c +include ../../Make.dist diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c index 6e2fbe20f..cccef94c9 100644 --- a/src/cmd/5g/cgen.c +++ b/src/cmd/5g/cgen.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "gg.h" /* @@ -62,6 +64,9 @@ cgen(Node *n, Node *res) if(isslice(n->left->type)) n->addable = n->left->addable; break; + case OITAB: + n->addable = n->left->addable; + break; } // if both are addressable, move @@ -211,11 +216,11 @@ cgen(Node *n, Node *res) goto ret; case OMINUS: + regalloc(&n1, nl->type, N); + cgen(nl, &n1); nodconst(&n3, nl->type, 0); regalloc(&n2, nl->type, res); - regalloc(&n1, nl->type, N); gmove(&n3, &n2); - cgen(nl, &n1); gins(optoas(OSUB, nl->type), &n1, &n2); gmove(&n2, res); regfree(&n1); @@ -278,6 +283,20 @@ cgen(Node *n, Node *res) regfree(&n1); break; + case OITAB: + // itable of interface value + igen(nl, &n1, res); + n1.op = OREGISTER; // was OINDREG + regalloc(&n2, n->type, &n1); + n1.op = OINDREG; + n1.type = n->type; + n1.xoffset = 0; + gmove(&n1, &n2); + gmove(&n2, res); + regfree(&n1); + regfree(&n2); + break; + case OLEN: if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) { // map has len in the first 32-bit word. @@ -400,9 +419,9 @@ abop: // asymmetric binary regalloc(&n2, nr->type, N); cgen(nr, &n2); } else { - regalloc(&n2, nr->type, N); + regalloc(&n2, nr->type, res); cgen(nr, &n2); - regalloc(&n1, nl->type, res); + regalloc(&n1, nl->type, N); cgen(nl, &n1); } gins(a, &n2, &n1); @@ -848,8 +867,10 @@ bgen(Node *n, int true, Prog *to) int et, a; Node *nl, *nr, *r; Node n1, n2, n3, n4, tmp; + NodeList *ll; Prog *p1, *p2; + USED(n4); // in unreachable code below if(debug['g']) { dump("\nbgen", n); } @@ -860,9 +881,6 @@ bgen(Node *n, int true, Prog *to) if(n->ninit != nil) genlist(n->ninit); - nl = n->left; - nr = n->right; - if(n->type == T) { convlit(&n, types[TBOOL]); if(n->type == T) @@ -875,7 +893,6 @@ bgen(Node *n, int true, Prog *to) patch(gins(AEND, N, N), to); goto ret; } - nl = N; nr = N; switch(n->op) { @@ -951,7 +968,10 @@ bgen(Node *n, int true, Prog *to) p1 = gbranch(AB, T); p2 = gbranch(AB, T); patch(p1, pc); + ll = n->ninit; + n->ninit = nil; bgen(n, 1, p2); + n->ninit = ll; patch(gbranch(AB, T), to); patch(p2, pc); goto ret; @@ -984,6 +1004,7 @@ bgen(Node *n, int true, Prog *to) regfree(&n1); break; +#ifdef NOTDEF a = optoas(a, types[tptr]); regalloc(&n1, types[tptr], N); regalloc(&n3, types[tptr], N); @@ -1001,6 +1022,7 @@ bgen(Node *n, int true, Prog *to) regfree(&n3); regfree(&n1); break; +#endif } if(isinter(nl->type)) { @@ -1019,6 +1041,7 @@ bgen(Node *n, int true, Prog *to) regfree(&n1); break; +#ifdef NOTDEF a = optoas(a, types[tptr]); regalloc(&n1, types[tptr], N); regalloc(&n3, types[tptr], N); @@ -1036,6 +1059,7 @@ bgen(Node *n, int true, Prog *to) regfree(&n3); regfree(&n4); break; +#endif } if(iscomplex[nl->type->etype]) { @@ -1059,7 +1083,7 @@ bgen(Node *n, int true, Prog *to) } if(nr->op == OLITERAL) { - if(nr->val.ctype == CTINT && mpgetfix(nr->val.u.xval) == 0) { + if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) == 0) { gencmp0(nl, nl->type, a, to); break; } @@ -1186,7 +1210,7 @@ stkof(Node *n) * NB: character copy assumed little endian architecture */ void -sgen(Node *n, Node *res, int32 w) +sgen(Node *n, Node *res, int64 w) { Node dst, src, tmp, nend; int32 c, odst, osrc; @@ -1194,25 +1218,34 @@ sgen(Node *n, Node *res, int32 w) Prog *p, *ploop; if(debug['g']) { - print("\nsgen w=%d\n", w); + print("\nsgen w=%lld\n", w); dump("r", n); dump("res", res); } - if(w == 0) - return; - if(w < 0) - fatal("sgen copy %d", w); + if(n->ullman >= UINF && res->ullman >= UINF) fatal("sgen UINF"); + + if(w < 0 || (int32)w != w) + fatal("sgen copy %lld", w); + if(n->type == T) fatal("sgen: missing type"); + if(w == 0) { + // evaluate side effects only. + regalloc(&dst, types[tptr], N); + agen(res, &dst); + agen(n, &dst); + regfree(&dst); + return; + } + // determine alignment. // want to avoid unaligned access, so have to use // smaller operations for less aligned types. // for example moving [4]byte must use 4 MOVB not 1 MOVW. align = n->type->align; - op = 0; switch(align) { default: fatal("sgen: invalid alignment %d for %T", align, n->type); @@ -1227,7 +1260,7 @@ sgen(Node *n, Node *res, int32 w) break; } if(w%align) - fatal("sgen: unaligned size %d (align=%d) for %T", w, align, n->type); + fatal("sgen: unaligned size %lld (align=%d) for %T", w, align, n->type); c = w / align; // offset on the stack @@ -1313,7 +1346,6 @@ sgen(Node *n, Node *res, int32 w) p->from.type = D_OREG; p->from.offset = dir; p->scond |= C_PBIT; - ploop = p; p = gins(op, &tmp, &dst); p->to.type = D_OREG; diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c index b56df765b..1235d1ace 100644 --- a/src/cmd/5g/cgen64.c +++ b/src/cmd/5g/cgen64.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "gg.h" /* @@ -240,7 +242,7 @@ cgen64(Node *n, Node *res) // shift is >= 1<<32 split64(r, &cl, &ch); gmove(&ch, &s); - p1 = gins(ATST, &s, N); + gins(ATST, &s, N); p6 = gbranch(ABNE, T); gmove(&cl, &s); splitclean(); @@ -248,7 +250,7 @@ cgen64(Node *n, Node *res) gmove(r, &s); p6 = P; } - p1 = gins(ATST, &s, N); + gins(ATST, &s, N); // shift == 0 p1 = gins(AMOVW, &bl, &al); @@ -411,7 +413,7 @@ olsh_break: gmove(r, &s); p6 = P; } - p1 = gins(ATST, &s, N); + gins(ATST, &s, N); // shift == 0 p1 = gins(AMOVW, &bl, &al); @@ -453,9 +455,9 @@ olsh_break: p1 = gins(AMOVW, &bh, &al); p1->scond = C_SCOND_EQ; if(bh.type->etype == TINT32) - p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); + gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); else - p1 = gins(AEOR, &ah, &ah); + gins(AEOR, &ah, &ah); p4 = gbranch(ABEQ, T); // check if shift is < 64 diff --git a/src/cmd/5g/doc.go b/src/cmd/5g/doc.go index e86013bdd..5a4a772fb 100644 --- a/src/cmd/5g/doc.go +++ b/src/cmd/5g/doc.go @@ -9,7 +9,5 @@ The $GOARCH for these tools is arm. It reads .go files and outputs .5 files. The flags are documented in ../gc/doc.go. -There is no instruction optimizer, so the -N flag is a no-op. - */ package documentation diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c index 12766102f..070804217 100644 --- a/src/cmd/5g/galign.c +++ b/src/cmd/5g/galign.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "gg.h" int thechar = '5'; diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h index ce4558e21..7dbf3beec 100644 --- a/src/cmd/5g/gg.h +++ b/src/cmd/5g/gg.h @@ -2,16 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include <u.h> -#include <libc.h> +#ifndef EXTERN +#define EXTERN extern +#endif #include "../gc/go.h" #include "../5l/5.out.h" -#ifndef EXTERN -#define EXTERN extern -#endif - typedef struct Addr Addr; struct Addr @@ -46,27 +43,26 @@ struct Prog uchar scond; }; +#define TEXTFLAG reg + #define REGALLOC_R0 0 #define REGALLOC_RMAX REGEXT #define REGALLOC_F0 (REGALLOC_RMAX+1) #define REGALLOC_FMAX (REGALLOC_F0 + FREGEXT) -EXTERN Biobuf* bout; EXTERN int32 dynloc; EXTERN uchar reg[REGALLOC_FMAX+1]; EXTERN int32 pcloc; // instruction counter EXTERN Strlit emptystring; extern char* anames[]; -EXTERN Hist* hist; EXTERN Prog zprog; -EXTERN Node* curfn; EXTERN Node* newproc; EXTERN Node* deferproc; EXTERN Node* deferreturn; EXTERN Node* panicindex; EXTERN Node* panicslice; EXTERN Node* throwreturn; -EXTERN long unmappedzero; +extern long unmappedzero; EXTERN int maxstksize; /* @@ -98,7 +94,7 @@ void igen(Node*, Node*, Node*); void agenr(Node *n, Node *a, Node *res); vlong fieldoffset(Type*, Node*); void bgen(Node*, int, Prog*); -void sgen(Node*, Node*, int32); +void sgen(Node*, Node*, int64); void gmove(Node*, Node*); Prog* gins(int, Node*, Node*); int samaddr(Node*, Node*); @@ -169,3 +165,6 @@ int Yconv(Fmt*); void listinit(void); void zaddr(Biobuf*, Addr*, 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 3f5f47e7b..de100620b 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -4,6 +4,8 @@ #undef EXTERN #define EXTERN +#include <u.h> +#include <libc.h> #include "gg.h" #include "opt.h" @@ -12,7 +14,6 @@ defframe(Prog *ptxt) { // fill in argument size ptxt->to.type = D_CONST2; - ptxt->reg = 0; // flags ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr); // fill in final stack size @@ -28,10 +29,10 @@ markautoused(Prog* p) { for (; p; p = p->link) { if (p->from.name == D_AUTO && p->from.node) - p->from.node->used++; + p->from.node->used = 1; if (p->to.name == D_AUTO && p->to.node) - p->to.node->used++; + p->to.node->used = 1; } } @@ -544,7 +545,7 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res) } // test for shift being 0 - p1 = gins(ATST, &n1, N); + gins(ATST, &n1, N); p3 = gbranch(ABEQ, T); // test and fix up large shifts diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c index 27c8be67d..b562ba888 100644 --- a/src/cmd/5g/gobj.c +++ b/src/cmd/5g/gobj.c @@ -28,6 +28,8 @@ // 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" void @@ -266,54 +268,6 @@ dumpfuncs(void) } } -/* deferred DATA output */ -static Prog *strdat; -static Prog *estrdat; -static int gflag; -static Prog *savepc; - -void -data(void) -{ - gflag = debug['g']; - debug['g'] = 0; - - if(estrdat == nil) { - strdat = mal(sizeof(*pc)); - clearp(strdat); - estrdat = strdat; - } - if(savepc) - fatal("data phase error"); - savepc = pc; - pc = estrdat; -} - -void -text(void) -{ - if(!savepc) - fatal("text phase error"); - debug['g'] = gflag; - estrdat = pc; - pc = savepc; - savepc = nil; -} - -void -dumpdata(void) -{ - Prog *p; - - if(estrdat == nil) - return; - *pc = *strdat; - if(gflag) - for(p=pc; p!=estrdat; p=p->link) - print("%P\n", p); - pc = estrdat; -} - int dsname(Sym *sym, int off, char *t, int n) { @@ -353,6 +307,7 @@ datastring(char *s, int len, Addr *a) a->offset = widthptr+4; // skip header a->reg = NREG; a->sym = sym; + a->node = sym->def; } /* @@ -371,6 +326,7 @@ datagostring(Strlit *sval, Addr *a) a->offset = 0; // header a->reg = NREG; a->sym = sym; + a->node = sym->def; } void @@ -379,6 +335,17 @@ gdata(Node *nam, Node *nr, int wid) Prog *p; vlong v; + if(nr->op == OLITERAL) { + switch(nr->val.ctype) { + case CTCPLX: + gdatacomplex(nam, nr->val.u.cval); + return; + case CTSTR: + gdatastring(nam, nr->val.u.sval); + return; + } + } + if(wid == 8 && is64(nr->type)) { v = mpgetfix(nr->val.u.xval); p = gins(ADATA, nam, nodintconst(v)); diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index ddaf52a88..9acf93670 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -28,6 +28,8 @@ // 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): Can make this bigger if we move @@ -50,6 +52,10 @@ clearp(Prog *p) pcloc++; } +static int ddumped; +static Prog *dfirst; +static Prog *dpc; + /* * generate and return proc with p->as = as, * linked into program. pc is next instruction. @@ -59,10 +65,23 @@ prog(int as) { Prog *p; - p = pc; - pc = mal(sizeof(*pc)); - - clearp(pc); + if(as == ADATA || as == AGLOBL) { + if(ddumped) + fatal("already dumped data"); + if(dpc == nil) { + dpc = mal(sizeof(*dpc)); + dfirst = dpc; + } + p = dpc; + dpc = mal(sizeof(*dpc)); + p->link = dpc; + p->reg = 0; // used for flags + } else { + p = pc; + pc = mal(sizeof(*pc)); + clearp(pc); + p->link = pc; + } if(lineno == 0) { if(debug['K']) @@ -71,10 +90,21 @@ prog(int as) p->as = as; p->lineno = lineno; - p->link = pc; return p; } +void +dumpdata(void) +{ + ddumped = 1; + if(dfirst == nil) + return; + newplist(); + *pc = *dfirst; + pc = dpc; + clearp(pc); +} + /* * generate a branch. * t is ignored. @@ -84,6 +114,8 @@ gbranch(int as, Type *t) { Prog *p; + USED(t); + p = prog(as); p->to.type = D_BRANCH; p->to.branch = P; @@ -222,6 +254,10 @@ ggloblnod(Node *nam, int32 width) p->to.sym = S; p->to.type = D_CONST; p->to.offset = width; + if(nam->readonly) + p->reg = RODATA; + if(nam->type != T && !haspointers(nam->type)) + p->reg |= NOPTR; } void @@ -238,6 +274,7 @@ ggloblsym(Sym *s, int32 width, int dupok) p->to.offset = width; if(dupok) p->reg = DUPOK; + p->reg |= RODATA; } int @@ -315,6 +352,8 @@ anyregalloc(void) return 0; } +uintptr regpc[REGALLOC_FMAX+1]; + /* * allocate register of type t, leave in n. * if o != N, o is desired fixed register. @@ -325,7 +364,7 @@ regalloc(Node *n, Type *t, Node *o) { int i, et, fixfree, floatfree; - if(debug['r']) { + if(0 && debug['r']) { fixfree = 0; for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) if(reg[i] == 0) @@ -358,9 +397,12 @@ regalloc(Node *n, Type *t, Node *o) goto out; } for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) - if(reg[i] == 0) + if(reg[i] == 0) { + regpc[i] = (uintptr)getcallerpc(&n); goto out; - + } + for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) + print("%d %p\n", i, regpc[i]); yyerror("out of fixed registers"); goto err; @@ -398,7 +440,7 @@ regfree(Node *n) { int i, fixfree, floatfree; - if(debug['r']) { + if(0 && debug['r']) { fixfree = 0; for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) if(reg[i] == 0) @@ -415,11 +457,13 @@ regfree(Node *n) if(n->op != OREGISTER && n->op != OINDREG) fatal("regfree: not a register"); i = n->val.u.reg; - if(i < 0 || i >= sizeof(reg)) + if(i < 0 || i >= nelem(reg) || i >= nelem(regpc)) fatal("regfree: reg out of range"); if(reg[i] <= 0) fatal("regfree: reg not allocated"); reg[i]--; + if(reg[i] == 0) + regpc[i] = 0; } /* @@ -481,8 +525,15 @@ nodarg(Type *t, int fp) fatal("nodarg: offset not computed for %T", t); n->xoffset = t->width; n->addable = 1; + n->orig = t->nname; fp: + // Rewrite argument named _ to __, + // or else the assignment to _ will be + // discarded during code generation. + if(isblank(n)) + n->sym = lookup("__"); + switch(fp) { default: fatal("nodarg %T %d", t, fp); @@ -1066,7 +1117,8 @@ gins(int as, Node *f, Node *t) if(f != N) naddr(f, &af, 1); if(t != N) - naddr(t, &at, 1); p = prog(as); + naddr(t, &at, 1); + p = prog(as); if(f != N) p->from = af; if(t != N) @@ -1232,6 +1284,7 @@ naddr(Node *n, Addr *a, int canemitcode) a->sym = n->left->sym; a->type = D_OREG; a->name = D_PARAM; + a->node = n->left->orig; break; case ONAME: @@ -1242,9 +1295,11 @@ naddr(Node *n, Addr *a, int canemitcode) a->etype = simtype[n->type->etype]; a->width = n->type->width; } - a->pun = n->pun; a->offset = n->xoffset; a->sym = n->sym; + a->node = n->orig; + //if(a->node >= (Node*)&n) + // fatal("stack node"); if(a->sym == S) a->sym = lookup(".noname"); if(n->method) { @@ -1263,8 +1318,6 @@ naddr(Node *n, Addr *a, int canemitcode) break; case PAUTO: a->name = D_AUTO; - if (n->sym) - a->node = n->orig; break; case PPARAM: case PPARAMOUT: @@ -1287,6 +1340,7 @@ naddr(Node *n, Addr *a, int canemitcode) a->dval = mpgetflt(n->val.u.fval); break; case CTINT: + case CTRUNE: a->sym = S; a->type = D_CONST; a->offset = mpgetfix(n->val.u.xval); @@ -1307,6 +1361,16 @@ naddr(Node *n, Addr *a, int canemitcode) } break; + case OITAB: + // itable of interface value + naddr(n->left, a, canemitcode); + a->etype = TINT32; + if(a->type == D_CONST && a->offset == 0) + break; // len(nil) + if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero) + checkoffset(a, canemitcode); + break; + case OLEN: // len of string or slice naddr(n->left, a, canemitcode); @@ -1744,7 +1808,7 @@ sudoaddable(int as, Node *n, Addr *a, int *w) switch(n->op) { case OLITERAL: - if(n->val.ctype != CTINT) + if(!isconst(n, CTINT)) break; v = mpgetfix(n->val.u.xval); if(v >= 32000 || v <= -32000) diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c index 0c6dbbf71..9bc3a9a9a 100644 --- a/src/cmd/5g/list.c +++ b/src/cmd/5g/list.c @@ -28,6 +28,8 @@ // 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 @@ -57,7 +59,7 @@ Pconv(Fmt *fp) switch(p->as) { default: snprint(str1, sizeof(str1), "%A%C", p->as, p->scond); - if(p->reg == NREG) + 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 diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c index 6cc93db12..e87f5d697 100644 --- a/src/cmd/5g/peep.c +++ b/src/cmd/5g/peep.c @@ -29,6 +29,8 @@ // THE SOFTWARE. +#include <u.h> +#include <libc.h> #include "gg.h" #include "opt.h" @@ -45,6 +47,9 @@ peep(void) Reg *r, *r1, *r2; Prog *p, *p1; int t; + + p1 = nil; + USED(p1); // ... in unreachable code... /* * complete R structure */ @@ -115,12 +120,14 @@ loop1: } break; +#ifdef NOTDEF if(p->scond == C_SCOND_NONE) if(regtyp(&p->to)) if(isdconst(&p->from)) { constprop(&p->from, &p->to, r->s1); } break; +#endif } } if(t) @@ -128,6 +135,7 @@ loop1: return; +#ifdef NOTDEF for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { @@ -255,6 +263,7 @@ return; // } predicate(); +#endif } Reg* @@ -1159,7 +1168,6 @@ copyu(Prog *p, Adr *v, Adr *s) return 3; return 0; } - return 0; } /* diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index 2d2a6d01a..93724d032 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -29,6 +29,8 @@ // THE SOFTWARE. +#include <u.h> +#include <libc.h> #include "gg.h" #include "opt.h" @@ -40,6 +42,9 @@ int noreturn(Prog *p); static int first = 0; +static void fixjmp(Prog*); + + Reg* rega(void) { @@ -90,8 +95,8 @@ setoutvar(void) ovar.b[z] |= bit.b[z]; t = structnext(&save); } -//if(bany(b)) -//print("ovars = %Q\n", &ovar); +//if(bany(ovar)) +//print("ovar = %Q\n", ovar); } void @@ -112,19 +117,19 @@ setaddrs(Bits bit) { int i, n; Var *v; - Sym *s; + Node *node; while(bany(&bit)) { // convert each bit to a variable i = bnum(bit); - s = var[i].sym; + node = var[i].node; n = var[i].name; bit.b[i/32] &= ~(1L<<(i%32)); // disable all pieces of that variable for(i=0; i<nvar; i++) { v = var+i; - if(v->sym == s && v->name == n) + if(v->node == node && v->name == n) v->addr = 2; } } @@ -169,6 +174,8 @@ regopt(Prog *firstp) if(first == 0) { fmtinstall('Q', Qconv); } + + fixjmp(firstp); first++; if(debug['K']) { @@ -202,7 +209,7 @@ regopt(Prog *firstp) nvar = NREGVAR; memset(var, 0, NREGVAR*sizeof var[0]); for(i=0; i<NREGVAR; i++) - var[i].sym = lookup(regname[i]); + var[i].node = newname(lookup(regname[i])); regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC); for(z=0; z<BITS; z++) { @@ -750,9 +757,9 @@ addmove(Reg *r, int bn, int rn, int f) v = var + bn; a = &p1->to; - a->sym = v->sym; a->name = v->name; a->node = v->node; + a->sym = v->node->sym; a->offset = v->offset; a->etype = v->etype; a->type = D_OREG; @@ -838,11 +845,10 @@ mkvar(Reg *r, Adr *a) int i, t, n, et, z, w, flag; int32 o; Bits bit; - Sym *s; + Node *node; // mark registers used t = a->type; - n = D_NONE; flag = 0; switch(t) { @@ -909,10 +915,13 @@ mkvar(Reg *r, Adr *a) break; } - s = a->sym; - if(s == S) + node = a->node; + if(node == N || node->op != ONAME || node->orig == N) goto none; - if(s->name[0] == '.') + node = node->orig; + if(node->orig != node) + fatal("%D: bad node", a); + if(node->sym == S || node->sym->name[0] == '.') goto none; et = a->etype; o = a->offset; @@ -920,7 +929,7 @@ mkvar(Reg *r, Adr *a) for(i=0; i<nvar; i++) { v = var+i; - if(v->sym == s && v->name == n) { + if(v->node == node && v->name == n) { if(v->offset == o) if(v->etype == et) if(v->width == w) @@ -944,7 +953,7 @@ mkvar(Reg *r, Adr *a) } if(nvar >= NVAR) { - if(debug['w'] > 1 && s) + if(debug['w'] > 1 && node) fatal("variable not optimized: %D", a); goto none; } @@ -953,17 +962,16 @@ mkvar(Reg *r, Adr *a) nvar++; //print("var %d %E %D %S\n", i, et, a, s); v = var+i; - v->sym = s; v->offset = o; v->name = n; // v->gotype = a->gotype; v->etype = et; v->width = w; v->addr = flag; // funny punning - v->node = a->node; + v->node = node; if(debug['R']) - print("bit=%2d et=%2d w=%d+%d %S %D flag=%d\n", i, et, o, w, s, a, v->addr); + print("bit=%2d et=%2d w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) @@ -1021,6 +1029,13 @@ 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]; + break; } for(z=0; z<BITS; z++) { ref.b[z] = (ref.b[z] & ~r1->set.b[z]) | @@ -1156,10 +1171,12 @@ loopit(Reg *r, int32 nr) r1 = rpo2r[i]; me = r1->rpo; d = -1; - if(r1->p1 != R && r1->p1->rpo < me) + // rpo2r[r->rpo] == r protects against considering dead code, + // which has r->rpo == 0. + if(r1->p1 != R && rpo2r[r1->p1->rpo] == r1->p1 && r1->p1->rpo < me) d = r1->p1->rpo; for(r1 = r1->p2; r1 != nil; r1 = r1->p2link) - if(r1->rpo < me) + if(rpo2r[r1->rpo] == r1 && r1->rpo < me) d = rpolca(idom, d, r1->rpo); idom[i] = d; } @@ -1570,7 +1587,7 @@ dumpone(Reg *r) if(bany(&r->refahead)) print(" ra:%Q ", r->refahead); if(bany(&r->calbehind)) - print("cb:%Q ", r->calbehind); + print(" cb:%Q ", r->calbehind); if(bany(&r->calahead)) print(" ca:%Q ", r->calahead); if(bany(&r->regdiff)) @@ -1605,3 +1622,123 @@ dumpit(char *str, Reg *r0) // } } } + +/* + * the code generator depends on being able to write out JMP (B) + * instructions that it can jump to now but fill in later. + * the linker will resolve them nicely, but they make the code + * longer and more difficult to follow during debugging. + * remove them. + */ + +/* what instruction does a JMP to p eventually land on? */ +static Prog* +chasejmp(Prog *p, int *jmploop) +{ + int n; + + n = 0; + while(p != P && p->as == AB && p->to.type == D_BRANCH) { + if(++n > 10) { + *jmploop = 1; + break; + } + p = p->to.branch; + } + return p; +} + +/* + * reuse reg pointer for mark/sweep state. + * leave reg==nil at end because alive==nil. + */ +#define alive ((void*)0) +#define dead ((void*)1) + +/* mark all code reachable from firstp as alive */ +static void +mark(Prog *firstp) +{ + Prog *p; + + for(p=firstp; p; p=p->link) { + if(p->regp != dead) + break; + p->regp = alive; + if(p->as != ABL && p->to.type == D_BRANCH && p->to.branch) + mark(p->to.branch); + if(p->as == AB || p->as == ARET || (p->as == ABL && noreturn(p))) + break; + } +} + +static void +fixjmp(Prog *firstp) +{ + int jmploop; + Prog *p, *last; + + if(debug['R'] && debug['v']) + print("\nfixjmp\n"); + + // pass 1: resolve jump to B, mark all code as dead. + jmploop = 0; + for(p=firstp; p; p=p->link) { + if(debug['R'] && debug['v']) + print("%P\n", p); + if(p->as != ABL && p->to.type == D_BRANCH && p->to.branch && p->to.branch->as == AB) { + p->to.branch = chasejmp(p->to.branch, &jmploop); + if(debug['R'] && debug['v']) + print("->%P\n", p); + } + p->regp = dead; + } + if(debug['R'] && debug['v']) + print("\n"); + + // pass 2: mark all reachable code alive + mark(firstp); + + // pass 3: delete dead code (mostly JMPs). + last = nil; + for(p=firstp; p; p=p->link) { + if(p->regp == dead) { + if(p->link == P && p->as == ARET && last && last->as != ARET) { + // This is the final ARET, and the code so far doesn't have one. + // Let it stay. + } else { + if(debug['R'] && debug['v']) + print("del %P\n", p); + continue; + } + } + if(last) + last->link = p; + last = p; + } + last->link = P; + + // pass 4: elide JMP to next instruction. + // only safe if there are no jumps to JMPs anymore. + if(!jmploop) { + last = nil; + for(p=firstp; p; p=p->link) { + if(p->as == AB && p->to.type == D_BRANCH && p->to.branch == p->link) { + if(debug['R'] && debug['v']) + print("del %P\n", p); + continue; + } + if(last) + last->link = p; + last = p; + } + last->link = P; + } + + if(debug['R'] && debug['v']) { + print("\n"); + for(p=firstp; p; p=p->link) + print("%P\n", p); + print("\n"); + } +} |