summaryrefslogtreecommitdiff
path: root/src/cmd/5g
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/5g')
-rw-r--r--src/cmd/5g/cgen.c66
-rw-r--r--src/cmd/5g/galign.c9
-rw-r--r--src/cmd/5g/gg.h50
-rw-r--r--src/cmd/5g/ggen.c195
-rw-r--r--src/cmd/5g/gobj.c264
-rw-r--r--src/cmd/5g/gsubr.c66
-rw-r--r--src/cmd/5g/list.c342
-rw-r--r--src/cmd/5g/opt.h1
-rw-r--r--src/cmd/5g/peep.c156
-rw-r--r--src/cmd/5g/prog.c10
-rw-r--r--src/cmd/5g/reg.c267
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");
// }
}