summaryrefslogtreecommitdiff
path: root/src/cmd/8g
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/8g')
-rw-r--r--src/cmd/8g/cgen.c43
-rw-r--r--src/cmd/8g/galign.c9
-rw-r--r--src/cmd/8g/gg.h47
-rw-r--r--src/cmd/8g/ggen.c175
-rw-r--r--src/cmd/8g/gobj.c259
-rw-r--r--src/cmd/8g/gsubr.c69
-rw-r--r--src/cmd/8g/list.c316
-rw-r--r--src/cmd/8g/opt.h3
-rw-r--r--src/cmd/8g/peep.c24
-rw-r--r--src/cmd/8g/prog.c21
-rw-r--r--src/cmd/8g/reg.c261
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(&reg, types[TINT64], D_AX);
gins(ATESTL, &reg, &reg);
- 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");
// }
}