summaryrefslogtreecommitdiff
path: root/src/cmd/5g
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/5g')
-rw-r--r--src/cmd/5g/cgen.c922
-rw-r--r--src/cmd/5g/cgen64.c82
-rw-r--r--src/cmd/5g/doc.go4
-rw-r--r--src/cmd/5g/galign.c1
-rw-r--r--src/cmd/5g/gg.h40
-rw-r--r--src/cmd/5g/ggen.c552
-rw-r--r--src/cmd/5g/gobj.c143
-rw-r--r--src/cmd/5g/gsubr.c195
-rw-r--r--src/cmd/5g/list.c21
-rw-r--r--src/cmd/5g/opt.h22
-rw-r--r--src/cmd/5g/peep.c125
-rw-r--r--src/cmd/5g/reg.c110
12 files changed, 1250 insertions, 967 deletions
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index cccef94c9..9e35f9566 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -15,8 +15,8 @@ void
cgen(Node *n, Node *res)
{
Node *nl, *nr, *r;
- Node n1, n2, n3, f0, f1;
- int a, w;
+ Node n1, n2, f0, f1;
+ int a, w, rg;
Prog *p1, *p2, *p3;
Addr addr;
@@ -30,6 +30,27 @@ cgen(Node *n, Node *res)
if(res == N || res->type == T)
fatal("cgen: res nil");
+ switch(n->op) {
+ case OSLICE:
+ case OSLICEARR:
+ case OSLICESTR:
+ if (res->op != ONAME || !res->addable) {
+ tempname(&n1, n->type);
+ cgen_slice(n, &n1);
+ cgen(&n1, res);
+ } else
+ cgen_slice(n, res);
+ return;
+ case OEFACE:
+ if (res->op != ONAME || !res->addable) {
+ tempname(&n1, n->type);
+ cgen_eface(n, &n1);
+ cgen(&n1, res);
+ } else
+ cgen_eface(n, res);
+ return;
+ }
+
while(n->op == OCONVNOP)
n = n->left;
@@ -156,6 +177,7 @@ cgen(Node *n, Node *res)
case OADD:
case OSUB:
case OMUL:
+ case OLROT:
case OLSH:
case ORSH:
case OAND:
@@ -171,7 +193,7 @@ cgen(Node *n, Node *res)
switch(n->op) {
default:
dump("cgen", n);
- fatal("cgen: unknown op %N", n);
+ fatal("cgen: unknown op %+hN", n);
break;
case OREAL:
@@ -190,12 +212,12 @@ cgen(Node *n, Node *res)
case OGE:
case OGT:
case ONOT:
- p1 = gbranch(AB, T);
+ p1 = gbranch(AB, T, 0);
p2 = pc;
gmove(nodbool(1), res);
- p3 = gbranch(AB, T);
+ p3 = gbranch(AB, T, 0);
patch(p1, pc);
- bgen(n, 1, p2);
+ bgen(n, 1, 0, p2);
gmove(nodbool(0), res);
patch(p3, pc);
goto ret;
@@ -218,13 +240,10 @@ cgen(Node *n, Node *res)
case OMINUS:
regalloc(&n1, nl->type, N);
cgen(nl, &n1);
- nodconst(&n3, nl->type, 0);
- regalloc(&n2, nl->type, res);
- gmove(&n3, &n2);
- gins(optoas(OSUB, nl->type), &n1, &n2);
- gmove(&n2, res);
+ nodconst(&n2, nl->type, 0);
+ gins(optoas(OMINUS, nl->type), &n2, &n1);
+ gmove(&n1, res);
regfree(&n1);
- regfree(&n2);
goto ret;
// symmetric binary
@@ -241,9 +260,14 @@ cgen(Node *n, Node *res)
a = optoas(n->op, nl->type);
goto abop;
+ case OHMUL:
+ cgen_hmul(nl, nr, res);
+ break;
+
+ case OLROT:
case OLSH:
case ORSH:
- cgen_shift(n->op, nl, nr, res);
+ cgen_shift(n->op, n->bounded, nl, nr, res);
break;
case OCONV:
@@ -284,17 +308,11 @@ cgen(Node *n, Node *res)
break;
case OITAB:
- // itable of interface value
+ // interface table is first word of interface value
igen(nl, &n1, res);
- n1.op = OREGISTER; // was OINDREG
- regalloc(&n2, n->type, &n1);
- n1.op = OINDREG;
n1.type = n->type;
- n1.xoffset = 0;
- gmove(&n1, &n2);
- gmove(&n2, res);
+ gmove(&n1, res);
regfree(&n1);
- regfree(&n2);
break;
case OLEN:
@@ -305,11 +323,8 @@ cgen(Node *n, Node *res)
cgen(nl, &n1);
nodconst(&n2, types[tptr], 0);
- regalloc(&n3, n2.type, N);
- gmove(&n2, &n3);
- gcmp(optoas(OCMP, types[tptr]), &n1, &n3);
- regfree(&n3);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
+ gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
n2 = n1;
n2.op = OINDREG;
@@ -325,15 +340,10 @@ cgen(Node *n, Node *res)
if(istype(nl->type, TSTRING) || isslice(nl->type)) {
// both slice and string have len one pointer into the struct.
igen(nl, &n1, res);
- n1.op = OREGISTER; // was OINDREG
- regalloc(&n2, types[TUINT32], &n1);
- n1.op = OINDREG;
n1.type = types[TUINT32];
- n1.xoffset = Array_nel;
- gmove(&n1, &n2);
- gmove(&n2, res);
+ n1.xoffset += Array_nel;
+ gmove(&n1, res);
regfree(&n1);
- regfree(&n2);
break;
}
fatal("cgen: OLEN: unknown type %lT", nl->type);
@@ -347,11 +357,8 @@ cgen(Node *n, Node *res)
cgen(nl, &n1);
nodconst(&n2, types[tptr], 0);
- regalloc(&n3, n2.type, N);
- gmove(&n2, &n3);
- gcmp(optoas(OCMP, types[tptr]), &n1, &n3);
- regfree(&n3);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
+ gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
n2 = n1;
n2.op = OINDREG;
@@ -366,11 +373,9 @@ cgen(Node *n, Node *res)
break;
}
if(isslice(nl->type)) {
- regalloc(&n1, types[tptr], res);
- agen(nl, &n1);
- n1.op = OINDREG;
+ igen(nl, &n1, res);
n1.type = types[TUINT32];
- n1.xoffset = Array_cap;
+ n1.xoffset += Array_cap;
gmove(&n1, res);
regfree(&n1);
break;
@@ -383,7 +388,22 @@ cgen(Node *n, Node *res)
break;
case OCALLMETH:
- cgen_callmeth(n, 0);
+ case OCALLFUNC:
+ // Release res so that it is available for cgen_call.
+ // Pick it up again after the call.
+ rg = -1;
+ if(n->ullman >= UINF) {
+ if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
+ rg = res->val.u.reg;
+ reg[rg]--;
+ }
+ }
+ if(n->op == OCALLMETH)
+ cgen_callmeth(n, 0);
+ else
+ cgen_call(n, 0);
+ if(rg >= 0)
+ reg[rg]++;
cgen_callret(n, res);
break;
@@ -392,11 +412,6 @@ cgen(Node *n, Node *res)
cgen_callret(n, res);
break;
- case OCALLFUNC:
- cgen_call(n, 0);
- cgen_callret(n, res);
- break;
-
case OMOD:
case ODIV:
a = optoas(n->op, nl->type);
@@ -416,18 +431,43 @@ abop: // asymmetric binary
if(nl->ullman >= nr->ullman) {
regalloc(&n1, nl->type, res);
cgen(nl, &n1);
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
+ switch(n->op) {
+ case OADD:
+ case OSUB:
+ case OAND:
+ case OOR:
+ case OXOR:
+ if(smallintconst(nr)) {
+ n2 = *nr;
+ break;
+ }
+ default:
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ }
} else {
- regalloc(&n2, nr->type, res);
- cgen(nr, &n2);
+ switch(n->op) {
+ case OADD:
+ case OSUB:
+ case OAND:
+ case OOR:
+ case OXOR:
+ if(smallintconst(nr)) {
+ n2 = *nr;
+ break;
+ }
+ default:
+ regalloc(&n2, nr->type, res);
+ cgen(nr, &n2);
+ }
regalloc(&n1, nl->type, N);
cgen(nl, &n1);
}
gins(a, &n2, &n1);
gmove(&n1, res);
regfree(&n1);
- regfree(&n2);
+ if(n2.op != OLITERAL)
+ regfree(&n2);
goto ret;
flt: // floating-point.
@@ -478,7 +518,7 @@ ret:
* returns Prog* to patch to panic call.
*/
Prog*
-cgenindex(Node *n, Node *res)
+cgenindex(Node *n, Node *res, int bounded)
{
Node tmp, lo, hi, zero, n1, n2;
@@ -491,7 +531,7 @@ cgenindex(Node *n, Node *res)
cgen(n, &tmp);
split64(&tmp, &lo, &hi);
gmove(&lo, res);
- if(debug['B']) {
+ if(bounded) {
splitclean();
return nil;
}
@@ -504,7 +544,7 @@ cgenindex(Node *n, Node *res)
regfree(&n2);
regfree(&n1);
splitclean();
- return gbranch(ABNE, T);
+ return gbranch(ABNE, T, -1);
}
/*
@@ -514,11 +554,8 @@ cgenindex(Node *n, Node *res)
void
agen(Node *n, Node *res)
{
- Node *nl, *nr;
- Node n1, n2, n3, n4, n5, tmp;
- Prog *p1, *p2;
- uint32 w;
- uint64 v;
+ Node *nl;
+ Node n1, n2, n3;
int r;
if(debug['g']) {
@@ -531,6 +568,21 @@ agen(Node *n, Node *res)
while(n->op == OCONVNOP)
n = n->left;
+ if(isconst(n, CTNIL) && n->type->width > widthptr) {
+ // Use of a nil interface or nil slice.
+ // Create a temporary we can take the address of and read.
+ // The generated code is just going to panic, so it need not
+ // be terribly efficient. See issue 3670.
+ tempname(&n1, n->type);
+ clearfat(&n1);
+ regalloc(&n2, types[tptr], res);
+ gins(AMOVW, &n1, &n2);
+ gmove(&n2, res);
+ regfree(&n2);
+ goto ret;
+ }
+
+
if(n->addable) {
memset(&n1, 0, sizeof n1);
n1.op = OADDR;
@@ -543,11 +595,10 @@ agen(Node *n, Node *res)
}
nl = n->left;
- nr = n->right;
switch(n->op) {
default:
- fatal("agen: unknown op %N", n);
+ fatal("agen: unknown op %+hN", n);
break;
case OCALLMETH:
@@ -575,16 +626,305 @@ agen(Node *n, Node *res)
cgen_aret(n, res);
break;
+ case OSLICE:
+ case OSLICEARR:
+ case OSLICESTR:
+ tempname(&n1, n->type);
+ cgen_slice(n, &n1);
+ agen(&n1, res);
+ break;
+
+ case OEFACE:
+ tempname(&n1, n->type);
+ cgen_eface(n, &n1);
+ agen(&n1, res);
+ break;
+
+ case OINDEX:
+ agenr(n, &n1, res);
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+
+ case ONAME:
+ // should only get here with names in this func.
+ if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
+ dump("bad agen", n);
+ fatal("agen: bad ONAME funcdepth %d != %d",
+ n->funcdepth, funcdepth);
+ }
+
+ // should only get here for heap vars or paramref
+ if(!(n->class & PHEAP) && n->class != PPARAMREF) {
+ dump("bad agen", n);
+ fatal("agen: bad ONAME class %#x", n->class);
+ }
+ cgen(n->heapaddr, res);
+ if(n->xoffset != 0) {
+ nodconst(&n1, types[TINT32], n->xoffset);
+ regalloc(&n2, n1.type, N);
+ regalloc(&n3, types[TINT32], N);
+ gmove(&n1, &n2);
+ gmove(res, &n3);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ gmove(&n3, res);
+ regfree(&n2);
+ regfree(&n3);
+ }
+ break;
+
+ case OIND:
+ cgen(nl, res);
+ break;
+
+ case ODOT:
+ agen(nl, res);
+ if(n->xoffset != 0) {
+ nodconst(&n1, types[TINT32], n->xoffset);
+ regalloc(&n2, n1.type, N);
+ regalloc(&n3, types[TINT32], N);
+ gmove(&n1, &n2);
+ gmove(res, &n3);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ gmove(&n3, res);
+ regfree(&n2);
+ regfree(&n3);
+ }
+ break;
+
+ case ODOTPTR:
+ cgen(nl, res);
+ if(n->xoffset != 0) {
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(nl->type->type->width >= unmappedzero) {
+ regalloc(&n1, types[tptr], N);
+ gmove(res, &n1);
+ regalloc(&n2, types[TUINT8], &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gmove(&n1, &n2);
+ regfree(&n1);
+ regfree(&n2);
+ }
+ nodconst(&n1, types[TINT32], n->xoffset);
+ regalloc(&n2, n1.type, N);
+ regalloc(&n3, types[tptr], N);
+ gmove(&n1, &n2);
+ gmove(res, &n3);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ gmove(&n3, res);
+ regfree(&n2);
+ regfree(&n3);
+ }
+ break;
+ }
+
+ret:
+ ;
+}
+
+/*
+ * generate:
+ * newreg = &n;
+ * res = newreg
+ *
+ * on exit, a has been changed to be *newreg.
+ * caller must regfree(a).
+ */
+void
+igen(Node *n, Node *a, Node *res)
+{
+ Node n1, n2;
+ int r;
+
+ if(debug['g']) {
+ dump("\nigen-n", n);
+ }
+ switch(n->op) {
+ case ONAME:
+ if((n->class&PHEAP) || n->class == PPARAMREF)
+ break;
+ *a = *n;
+ return;
+
+ case OINDREG:
+ // Increase the refcount of the register so that igen's caller
+ // has to call regfree.
+ if(n->val.u.reg != REGSP)
+ reg[n->val.u.reg]++;
+ *a = *n;
+ return;
+
+ case ODOT:
+ igen(n->left, a, res);
+ a->xoffset += n->xoffset;
+ a->type = n->type;
+ return;
+
+ case ODOTPTR:
+ if(n->left->addable
+ || n->left->op == OCALLFUNC
+ || n->left->op == OCALLMETH
+ || n->left->op == OCALLINTER) {
+ // igen-able nodes.
+ igen(n->left, &n1, res);
+ regalloc(a, types[tptr], &n1);
+ gmove(&n1, a);
+ regfree(&n1);
+ } else {
+ regalloc(a, types[tptr], res);
+ cgen(n->left, a);
+ }
+ if(n->xoffset != 0) {
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(n->left->type->type->width >= unmappedzero) {
+ regalloc(&n1, types[tptr], N);
+ gmove(a, &n1);
+ regalloc(&n2, types[TUINT8], &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gmove(&n1, &n2);
+ regfree(&n1);
+ regfree(&n2);
+ }
+ }
+ a->op = OINDREG;
+ a->xoffset = n->xoffset;
+ a->type = n->type;
+ return;
+
+ case OCALLMETH:
+ case OCALLFUNC:
+ case OCALLINTER:
+ // Release res so that it is available for cgen_call.
+ // Pick it up again after the call.
+ r = -1;
+ if(n->ullman >= UINF) {
+ if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
+ r = res->val.u.reg;
+ reg[r]--;
+ }
+ }
+ switch(n->op) {
+ case OCALLMETH:
+ cgen_callmeth(n, 0);
+ break;
+ case OCALLFUNC:
+ cgen_call(n, 0);
+ break;
+ case OCALLINTER:
+ cgen_callinter(n, N, 0);
+ break;
+ }
+ if(r >= 0)
+ reg[r]++;
+ regalloc(a, types[tptr], res);
+ cgen_aret(n, a);
+ a->op = OINDREG;
+ a->type = n->type;
+ return;
+ }
+
+ agenr(n, a, res);
+ a->op = OINDREG;
+ a->type = n->type;
+}
+
+/*
+ * allocate a register in res and generate
+ * newreg = &n
+ * The caller must call regfree(a).
+ */
+void
+cgenr(Node *n, Node *a, Node *res)
+{
+ Node n1;
+
+ if(debug['g'])
+ dump("cgenr-n", n);
+
+ if(isfat(n->type))
+ fatal("cgenr on fat node");
+
+ if(n->addable) {
+ regalloc(a, types[tptr], res);
+ gmove(n, a);
+ return;
+ }
+
+ switch(n->op) {
+ case ONAME:
+ case ODOT:
+ case ODOTPTR:
+ case OINDEX:
+ case OCALLFUNC:
+ case OCALLMETH:
+ case OCALLINTER:
+ igen(n, &n1, res);
+ regalloc(a, types[tptr], &n1);
+ gmove(&n1, a);
+ regfree(&n1);
+ break;
+ default:
+ regalloc(a, n->type, res);
+ cgen(n, a);
+ break;
+ }
+}
+
+/*
+ * generate:
+ * newreg = &n;
+ *
+ * caller must regfree(a).
+ */
+void
+agenr(Node *n, Node *a, Node *res)
+{
+ Node *nl, *nr;
+ Node n1, n2, n3, n4, tmp;
+ Prog *p1, *p2;
+ uint32 w;
+ uint64 v;
+ int bounded;
+
+ if(debug['g'])
+ dump("agenr-n", n);
+
+ nl = n->left;
+ nr = n->right;
+
+ switch(n->op) {
+ case ODOT:
+ case ODOTPTR:
+ case OCALLFUNC:
+ case OCALLMETH:
+ case OCALLINTER:
+ igen(n, &n1, res);
+ regalloc(a, types[tptr], &n1);
+ agen(&n1, a);
+ regfree(&n1);
+ break;
+
+ case OIND:
+ cgenr(n->left, a, res);
+ break;
+
case OINDEX:
p2 = nil; // to be patched to panicindex.
w = n->type->width;
+ bounded = debug['B'] || n->bounded;
if(nr->addable) {
if(!isconst(nr, CTINT))
tempname(&tmp, types[TINT32]);
if(!isconst(nl, CTSTR))
agenr(nl, &n3, res);
if(!isconst(nr, CTINT)) {
- p2 = cgenindex(nr, &tmp);
+ p2 = cgenindex(nr, &tmp, bounded);
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
@@ -592,17 +932,16 @@ agen(Node *n, Node *res)
if(nl->addable) {
if(!isconst(nr, CTINT)) {
tempname(&tmp, types[TINT32]);
- p2 = cgenindex(nr, &tmp);
+ p2 = cgenindex(nr, &tmp, bounded);
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
if(!isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
+ agenr(nl, &n3, res);
}
} else {
tempname(&tmp, types[TINT32]);
- p2 = cgenindex(nr, &tmp);
+ p2 = cgenindex(nr, &tmp, bounded);
nr = &tmp;
if(!isconst(nl, CTSTR))
agenr(nl, &n3, res);
@@ -614,26 +953,37 @@ agen(Node *n, Node *res)
// i is in &n1 (if not constant)
// w is width
+ // explicit check for nil if array is large enough
+ // that we might derive too big a pointer.
+ if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) {
+ regalloc(&n4, types[tptr], N);
+ gmove(&n3, &n4);
+ regalloc(&tmp, types[TUINT8], &n4);
+ n4.op = OINDREG;
+ n4.type = types[TUINT8];
+ n4.xoffset = 0;
+ gmove(&n4, &tmp);
+ regfree(&n4);
+ regfree(&tmp);
+ }
+
// constant index
if(isconst(nr, CTINT)) {
if(isconst(nl, CTSTR))
fatal("constant string constant index");
v = mpgetfix(nr->val.u.xval);
if(isslice(nl->type) || nl->type->etype == TSTRING) {
- if(!debug['B'] && !n->etype) {
+ if(!debug['B'] && !n->bounded) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
n1.xoffset = Array_nel;
regalloc(&n4, n1.type, N);
- cgen(&n1, &n4);
+ gmove(&n1, &n4);
nodconst(&n2, types[TUINT32], v);
- regalloc(&n5, n2.type, N);
- gmove(&n2, &n5);
- gcmp(optoas(OCMP, types[TUINT32]), &n4, &n5);
+ gcmp(optoas(OCMP, types[TUINT32]), &n4, &n2);
regfree(&n4);
- regfree(&n5);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
ginscall(panicindex, 0);
patch(p1, pc);
}
@@ -646,13 +996,8 @@ agen(Node *n, Node *res)
}
nodconst(&n2, types[tptr], v*w);
- regalloc(&n4, n2.type, N);
- gmove(&n2, &n4);
- gins(optoas(OADD, types[tptr]), &n4, &n3);
- regfree(&n4);
-
- gmove(&n3, res);
- regfree(&n3);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ *a = n3;
break;
}
@@ -660,25 +1005,24 @@ agen(Node *n, Node *res)
gmove(&n1, &n2);
regfree(&n1);
- if(!debug['B'] && !n->etype) {
+ if(!debug['B'] && !n->bounded) {
// check bounds
- regalloc(&n4, types[TUINT32], N);
if(isconst(nl, CTSTR)) {
- nodconst(&n1, types[TUINT32], nl->val.u.sval->len);
- gmove(&n1, &n4);
+ nodconst(&n4, types[TUINT32], nl->val.u.sval->len);
} else if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
n1.xoffset = Array_nel;
- cgen(&n1, &n4);
- } else {
- nodconst(&n1, types[TUINT32], nl->type->bound);
+ regalloc(&n4, types[TUINT32], N);
gmove(&n1, &n4);
+ } else {
+ nodconst(&n4, types[TUINT32], nl->type->bound);
}
gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
- regfree(&n4);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ if(n4.op == OREGISTER)
+ regfree(&n4);
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
if(p2)
patch(p2, pc);
ginscall(panicindex, 0);
@@ -713,7 +1057,7 @@ agen(Node *n, Node *res)
else if(w == 4)
gshift(AADD, &n2, SHIFT_LL, 2, &n3);
else if(w == 8)
- gshift(AADD, &n2, SHIFT_LL, 3, &n3);
+ gshift(AADD, &n2, SHIFT_LL, 3, &n3);
} else {
regalloc(&n4, types[TUINT32], N);
nodconst(&n1, types[TUINT32], w);
@@ -721,122 +1065,21 @@ agen(Node *n, Node *res)
gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
gins(optoas(OADD, types[tptr]), &n2, &n3);
regfree(&n4);
- gmove(&n3, res);
}
- gmove(&n3, res);
+ *a = n3;
regfree(&n2);
- regfree(&n3);
break;
- case ONAME:
- // should only get here with names in this func.
- if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
- dump("bad agen", n);
- fatal("agen: bad ONAME funcdepth %d != %d",
- n->funcdepth, funcdepth);
- }
-
- // should only get here for heap vars or paramref
- if(!(n->class & PHEAP) && n->class != PPARAMREF) {
- dump("bad agen", n);
- fatal("agen: bad ONAME class %#x", n->class);
- }
- cgen(n->heapaddr, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT32], n->xoffset);
- regalloc(&n2, n1.type, N);
- regalloc(&n3, types[TINT32], N);
- gmove(&n1, &n2);
- gmove(res, &n3);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- }
- break;
-
- case OIND:
- cgen(nl, res);
- break;
-
- case ODOT:
- agen(nl, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT32], n->xoffset);
- regalloc(&n2, n1.type, N);
- regalloc(&n3, types[TINT32], N);
- gmove(&n1, &n2);
- gmove(res, &n3);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- }
- break;
-
- case ODOTPTR:
- cgen(nl, res);
- if(n->xoffset != 0) {
- // explicit check for nil if struct is large enough
- // that we might derive too big a pointer.
- if(nl->type->type->width >= unmappedzero) {
- regalloc(&n1, types[tptr], N);
- gmove(res, &n1);
- p1 = gins(AMOVW, &n1, &n1);
- p1->from.type = D_OREG;
- p1->from.offset = 0;
- regfree(&n1);
- }
- nodconst(&n1, types[TINT32], n->xoffset);
- regalloc(&n2, n1.type, N);
- regalloc(&n3, types[tptr], N);
- gmove(&n1, &n2);
- gmove(res, &n3);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- }
+ default:
+ regalloc(a, types[tptr], res);
+ agen(n, a);
break;
}
-
-ret:
- ;
}
-/*
- * generate:
- * newreg = &n;
- * res = newreg
- *
- * on exit, a has been changed to be *newreg.
- * caller must regfree(a).
- */
void
-igen(Node *n, Node *a, Node *res)
-{
- regalloc(a, types[tptr], res);
- agen(n, a);
- a->op = OINDREG;
- a->type = n->type;
-}
-
-/*
- * generate:
- * newreg = &n;
- *
- * caller must regfree(a).
- */
-void
-agenr(Node *n, Node *a, Node *res)
-{
- regalloc(a, types[tptr], res);
- agen(n, a);
-}
-
-void
-gencmp0(Node *n, Type *t, int o, Prog *to)
+gencmp0(Node *n, Type *t, int o, int likely, Prog *to)
{
Node n1, n2, n3;
int a;
@@ -853,7 +1096,7 @@ gencmp0(Node *n, Type *t, int o, Prog *to)
} else
gins(ATST, &n1, N);
a = optoas(o, t);
- patch(gbranch(a, t), to);
+ patch(gbranch(a, t, likely), to);
regfree(&n1);
}
@@ -862,7 +1105,7 @@ gencmp0(Node *n, Type *t, int o, Prog *to)
* if(n == true) goto to;
*/
void
-bgen(Node *n, int true, Prog *to)
+bgen(Node *n, int true, int likely, Prog *to)
{
int et, a;
Node *nl, *nr, *r;
@@ -900,13 +1143,13 @@ bgen(Node *n, int true, Prog *to)
a = ONE;
if(!true)
a = OEQ;
- gencmp0(n, n->type, a, to);
+ gencmp0(n, n->type, a, likely, to);
goto ret;
case OLITERAL:
// need to ask if it is bool?
if(!true == !n->val.u.bval)
- patch(gbranch(AB, T), to);
+ patch(gbranch(AB, T, 0), to);
goto ret;
case OANDAND:
@@ -914,12 +1157,12 @@ bgen(Node *n, int true, Prog *to)
goto caseor;
caseand:
- p1 = gbranch(AB, T);
- p2 = gbranch(AB, T);
+ p1 = gbranch(AB, T, 0);
+ p2 = gbranch(AB, T, 0);
patch(p1, pc);
- bgen(n->left, !true, p2);
- bgen(n->right, !true, p2);
- p1 = gbranch(AB, T);
+ bgen(n->left, !true, -likely, p2);
+ bgen(n->right, !true, -likely, p2);
+ p1 = gbranch(AB, T, 0);
patch(p1, to);
patch(p2, pc);
goto ret;
@@ -929,8 +1172,8 @@ bgen(Node *n, int true, Prog *to)
goto caseand;
caseor:
- bgen(n->left, true, to);
- bgen(n->right, true, to);
+ bgen(n->left, true, likely, to);
+ bgen(n->right, true, likely, to);
goto ret;
case OEQ:
@@ -952,7 +1195,7 @@ bgen(Node *n, int true, Prog *to)
switch(n->op) {
case ONOT:
- bgen(nl, !true, to);
+ bgen(nl, !true, likely, to);
goto ret;
case OEQ:
@@ -965,14 +1208,14 @@ bgen(Node *n, int true, Prog *to)
if(!true) {
if(isfloat[nl->type->etype]) {
// brcom is not valid on floats when NaN is involved.
- p1 = gbranch(AB, T);
- p2 = gbranch(AB, T);
+ p1 = gbranch(AB, T, 0);
+ p2 = gbranch(AB, T, 0);
patch(p1, pc);
ll = n->ninit;
n->ninit = nil;
- bgen(n, 1, p2);
+ bgen(n, 1, -likely, p2);
n->ninit = ll;
- patch(gbranch(AB, T), to);
+ patch(gbranch(AB, T, 0), to);
patch(p2, pc);
goto ret;
}
@@ -995,34 +1238,12 @@ bgen(Node *n, int true, Prog *to)
break;
}
- regalloc(&n1, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = Array_array;
- gencmp0(&n2, types[tptr], a, to);
- regfree(&n1);
- break;
-
-#ifdef NOTDEF
- a = optoas(a, types[tptr]);
- regalloc(&n1, types[tptr], N);
- regalloc(&n3, types[tptr], N);
- regalloc(&n4, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = Array_array;
- gmove(&n2, &n4);
- nodconst(&tmp, types[tptr], 0);
- gmove(&tmp, &n3);
- gcmp(optoas(OCMP, types[tptr]), &n4, &n3);
- patch(gbranch(a, types[tptr]), to);
- regfree(&n4);
- regfree(&n3);
+ igen(nl, &n1, N);
+ n1.xoffset += Array_array;
+ n1.type = types[tptr];
+ gencmp0(&n1, types[tptr], a, likely, to);
regfree(&n1);
break;
-#endif
}
if(isinter(nl->type)) {
@@ -1032,38 +1253,16 @@ bgen(Node *n, int true, Prog *to)
break;
}
- regalloc(&n1, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 0;
- gencmp0(&n2, types[tptr], a, to);
- regfree(&n1);
- break;
-
-#ifdef NOTDEF
- a = optoas(a, types[tptr]);
- regalloc(&n1, types[tptr], N);
- regalloc(&n3, types[tptr], N);
- regalloc(&n4, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 0;
- gmove(&n2, &n4);
- nodconst(&tmp, types[tptr], 0);
- gmove(&tmp, &n3);
- gcmp(optoas(OCMP, types[tptr]), &n4, &n3);
- patch(gbranch(a, types[tptr]), to);
+ igen(nl, &n1, N);
+ n1.type = types[tptr];
+ n1.xoffset += 0;
+ gencmp0(&n1, types[tptr], a, likely, to);
regfree(&n1);
- regfree(&n3);
- regfree(&n4);
break;
-#endif
}
if(iscomplex[nl->type->etype]) {
- complexbool(a, nl, nr, true, to);
+ complexbool(a, nl, nr, true, likely, to);
break;
}
@@ -1078,17 +1277,17 @@ bgen(Node *n, int true, Prog *to)
cgen(nr, &n2);
nr = &n2;
}
- cmp64(nl, nr, a, to);
+ cmp64(nl, nr, a, likely, to);
break;
}
if(nr->op == OLITERAL) {
if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) == 0) {
- gencmp0(nl, nl->type, a, to);
+ gencmp0(nl, nl->type, a, likely, to);
break;
}
if(nr->val.ctype == CTNIL) {
- gencmp0(nl, nl->type, a, to);
+ gencmp0(nl, nl->type, a, likely, to);
break;
}
}
@@ -1110,7 +1309,7 @@ bgen(Node *n, int true, Prog *to)
cgen(&tmp, &n1);
gcmp(optoas(OCMP, nr->type), &n1, &n2);
- patch(gbranch(a, nr->type), to);
+ patch(gbranch(a, nr->type, likely), to);
regfree(&n1);
regfree(&n2);
@@ -1131,14 +1330,17 @@ bgen(Node *n, int true, Prog *to)
gcmp(optoas(OCMP, nr->type), &n1, &n2);
if(isfloat[nl->type->etype]) {
- p1 = gbranch(ABVS, nr->type);
- patch(gbranch(a, nr->type), to);
- if(n->op == ONE)
+ if(n->op == ONE) {
+ p1 = gbranch(ABVS, nr->type, likely);
+ patch(gbranch(a, nr->type, likely), to);
patch(p1, to);
- else
+ } else {
+ p1 = gbranch(ABVS, nr->type, -likely);
+ patch(gbranch(a, nr->type, likely), to);
patch(p1, pc);
+ }
} else {
- patch(gbranch(a, nr->type), to);
+ patch(gbranch(a, nr->type, likely), to);
}
regfree(&n1);
regfree(&n2);
@@ -1241,6 +1443,10 @@ sgen(Node *n, Node *res, int64 w)
return;
}
+ // Avoid taking the address for simple enough types.
+ if(componentgen(n, res))
+ return;
+
// determine alignment.
// want to avoid unaligned access, so have to use
// smaller operations for less aligned types.
@@ -1284,16 +1490,14 @@ sgen(Node *n, Node *res, int64 w)
if(osrc < odst && odst < osrc+w)
dir = -dir;
- regalloc(&dst, types[tptr], res);
if(n->ullman >= res->ullman) {
- agen(n, &dst); // temporarily use dst
+ agenr(n, &dst, res); // temporarily use dst
regalloc(&src, types[tptr], N);
gins(AMOVW, &dst, &src);
agen(res, &dst);
} else {
- agen(res, &dst);
- regalloc(&src, types[tptr], N);
- agen(n, &src);
+ agenr(res, &dst, res);
+ agenr(n, &src, N);
}
regalloc(&tmp, types[TUINT32], N);
@@ -1338,7 +1542,7 @@ sgen(Node *n, Node *res, int64 w)
p = gins(ACMP, &src, N);
raddr(&nend, p);
- patch(gbranch(ABNE, T), ploop);
+ patch(gbranch(ABNE, T, 0), ploop);
regfree(&nend);
} else {
while(c-- > 0) {
@@ -1358,3 +1562,157 @@ sgen(Node *n, Node *res, int64 w)
regfree(&src);
regfree(&tmp);
}
+
+static int
+cadable(Node *n)
+{
+ if(!n->addable) {
+ // dont know how it happens,
+ // but it does
+ return 0;
+ }
+
+ switch(n->op) {
+ case ONAME:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * copy a composite value by moving its individual components.
+ * Slices, strings and interfaces are supported.
+ * nr is N when assigning a zero value.
+ * return 1 if can do, 0 if cant.
+ */
+int
+componentgen(Node *nr, Node *nl)
+{
+ Node nodl, nodr, tmp;
+ int freel, freer;
+
+ freel = 0;
+ freer = 0;
+
+ switch(nl->type->etype) {
+ default:
+ goto no;
+
+ case TARRAY:
+ if(!isslice(nl->type))
+ goto no;
+ case TSTRING:
+ case TINTER:
+ break;
+ }
+
+ nodl = *nl;
+ if(!cadable(nl)) {
+ if(nr == N || !cadable(nr))
+ goto no;
+ igen(nl, &nodl, N);
+ freel = 1;
+ }
+
+ if(nr != N) {
+ nodr = *nr;
+ if(!cadable(nr)) {
+ igen(nr, &nodr, N);
+ freer = 1;
+ }
+ } else {
+ // When zeroing, prepare a register containing zero.
+ nodconst(&tmp, nl->type, 0);
+ regalloc(&nodr, types[TUINT], N);
+ gmove(&tmp, &nodr);
+ freer = 1;
+ }
+
+ switch(nl->type->etype) {
+ case TARRAY:
+ nodl.xoffset += Array_array;
+ nodl.type = ptrto(nl->type->type);
+
+ if(nr != N) {
+ nodr.xoffset += Array_array;
+ nodr.type = nodl.type;
+ }
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_nel-Array_array;
+ nodl.type = types[simtype[TUINT]];
+
+ if(nr != N) {
+ nodr.xoffset += Array_nel-Array_array;
+ nodr.type = nodl.type;
+ }
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_cap-Array_nel;
+ nodl.type = types[simtype[TUINT]];
+
+ if(nr != N) {
+ nodr.xoffset += Array_cap-Array_nel;
+ nodr.type = nodl.type;
+ }
+ gmove(&nodr, &nodl);
+
+ goto yes;
+
+ case TSTRING:
+ nodl.xoffset += Array_array;
+ nodl.type = ptrto(types[TUINT8]);
+
+ if(nr != N) {
+ nodr.xoffset += Array_array;
+ nodr.type = nodl.type;
+ }
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_nel-Array_array;
+ nodl.type = types[simtype[TUINT]];
+
+ if(nr != N) {
+ nodr.xoffset += Array_nel-Array_array;
+ nodr.type = nodl.type;
+ }
+ gmove(&nodr, &nodl);
+
+ goto yes;
+
+ case TINTER:
+ nodl.xoffset += Array_array;
+ nodl.type = ptrto(types[TUINT8]);
+
+ if(nr != N) {
+ nodr.xoffset += Array_array;
+ nodr.type = nodl.type;
+ }
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_nel-Array_array;
+ nodl.type = ptrto(types[TUINT8]);
+
+ if(nr != N) {
+ nodr.xoffset += Array_nel-Array_array;
+ nodr.type = nodl.type;
+ }
+ gmove(&nodr, &nodl);
+
+ goto yes;
+ }
+
+no:
+ if(freer)
+ regfree(&nodr);
+ if(freel)
+ regfree(&nodl);
+ return 0;
+
+yes:
+ if(freer)
+ regfree(&nodr);
+ if(freel)
+ regfree(&nodl);
+ return 1;
+}
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c
index 1235d1ace..ef11e2adb 100644
--- a/src/cmd/5g/cgen64.c
+++ b/src/cmd/5g/cgen64.c
@@ -94,6 +94,7 @@ cgen64(Node *n, Node *res)
case OAND:
case OOR:
case OXOR:
+ case OLROT:
// binary operators.
// common setup below.
break;
@@ -175,7 +176,7 @@ cgen64(Node *n, Node *res)
p1->from.type = D_REG;
p1->from.reg = bl.val.u.reg;
p1->reg = ch.val.u.reg;
- p1->to.type = D_REGREG;
+ p1->to.type = D_REGREG2;
p1->to.reg = ah.val.u.reg;
p1->to.offset = ah.val.u.reg;
//print("%P\n", p1);
@@ -185,7 +186,7 @@ cgen64(Node *n, Node *res)
p1->from.type = D_REG;
p1->from.reg = bh.val.u.reg;
p1->reg = cl.val.u.reg;
- p1->to.type = D_REGREG;
+ p1->to.type = D_REGREG2;
p1->to.reg = ah.val.u.reg;
p1->to.offset = ah.val.u.reg;
//print("%P\n", p1);
@@ -197,6 +198,47 @@ cgen64(Node *n, Node *res)
break;
+ case OLROT:
+ // We only rotate by a constant c in [0,64).
+ // if c >= 32:
+ // lo, hi = hi, lo
+ // c -= 32
+ // if c == 0:
+ // no-op
+ // else:
+ // t = hi
+ // shld hi:lo, c
+ // shld lo:t, c
+ v = mpgetfix(r->val.u.xval);
+ regalloc(&bl, lo1.type, N);
+ regalloc(&bh, hi1.type, N);
+ if(v >= 32) {
+ // reverse during load to do the first 32 bits of rotate
+ v -= 32;
+ gins(AMOVW, &hi1, &bl);
+ gins(AMOVW, &lo1, &bh);
+ } else {
+ gins(AMOVW, &hi1, &bh);
+ gins(AMOVW, &lo1, &bl);
+ }
+ if(v == 0) {
+ gins(AMOVW, &bh, &ah);
+ gins(AMOVW, &bl, &al);
+ } else {
+ // rotate by 1 <= v <= 31
+ // MOVW bl<<v, al
+ // MOVW bh<<v, ah
+ // OR bl>>(32-v), ah
+ // OR bh>>(32-v), al
+ gshift(AMOVW, &bl, SHIFT_LL, v, &al);
+ gshift(AMOVW, &bh, SHIFT_LL, v, &ah);
+ gshift(AORR, &bl, SHIFT_LR, 32-v, &ah);
+ gshift(AORR, &bh, SHIFT_LR, 32-v, &al);
+ }
+ regfree(&bl);
+ regfree(&bh);
+ break;
+
case OLSH:
regalloc(&bl, lo1.type, N);
regalloc(&bh, hi1.type, N);
@@ -243,7 +285,7 @@ cgen64(Node *n, Node *res)
split64(r, &cl, &ch);
gmove(&ch, &s);
gins(ATST, &s, N);
- p6 = gbranch(ABNE, T);
+ p6 = gbranch(ABNE, T, 0);
gmove(&cl, &s);
splitclean();
} else {
@@ -257,7 +299,7 @@ cgen64(Node *n, Node *res)
p1->scond = C_SCOND_EQ;
p1 = gins(AMOVW, &bh, &ah);
p1->scond = C_SCOND_EQ;
- p2 = gbranch(ABEQ, T);
+ p2 = gbranch(ABEQ, T, 0);
// shift is < 32
nodconst(&n1, types[TUINT32], 32);
@@ -281,14 +323,14 @@ cgen64(Node *n, Node *res)
p1->scond = C_SCOND_LO;
// BLO end
- p3 = gbranch(ABLO, T);
+ p3 = gbranch(ABLO, T, 0);
// shift == 32
p1 = gins(AEOR, &al, &al);
p1->scond = C_SCOND_EQ;
p1 = gins(AMOVW, &bl, &ah);
p1->scond = C_SCOND_EQ;
- p4 = gbranch(ABEQ, T);
+ p4 = gbranch(ABEQ, T, 0);
// shift is < 64
nodconst(&n1, types[TUINT32], 64);
@@ -311,7 +353,7 @@ cgen64(Node *n, Node *res)
p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &ah);
p1->scond = C_SCOND_LO;
- p5 = gbranch(ABLO, T);
+ p5 = gbranch(ABLO, T, 0);
// shift >= 64
if (p6 != P) patch(p6, pc);
@@ -406,7 +448,7 @@ olsh_break:
else
p1 = gins(AEOR, &ah, &ah);
p1->scond = C_SCOND_NE;
- p6 = gbranch(ABNE, T);
+ p6 = gbranch(ABNE, T, 0);
gmove(&cl, &s);
splitclean();
} else {
@@ -420,7 +462,7 @@ olsh_break:
p1->scond = C_SCOND_EQ;
p1 = gins(AMOVW, &bh, &ah);
p1->scond = C_SCOND_EQ;
- p2 = gbranch(ABEQ, T);
+ p2 = gbranch(ABEQ, T, 0);
// check if shift is < 32
nodconst(&n1, types[TUINT32], 32);
@@ -449,7 +491,7 @@ olsh_break:
p1->scond = C_SCOND_LO;
// BLO end
- p3 = gbranch(ABLO, T);
+ p3 = gbranch(ABLO, T, 0);
// shift == 32
p1 = gins(AMOVW, &bh, &al);
@@ -458,7 +500,7 @@ olsh_break:
gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
else
gins(AEOR, &ah, &ah);
- p4 = gbranch(ABEQ, T);
+ p4 = gbranch(ABEQ, T, 0);
// check if shift is < 64
nodconst(&n1, types[TUINT32], 64);
@@ -484,7 +526,7 @@ olsh_break:
}
// BLO end
- p5 = gbranch(ABLO, T);
+ p5 = gbranch(ABLO, T, 0);
// s >= 64
if(p6 != P)
@@ -633,7 +675,7 @@ orsh_break:
* nl is memory; nr is constant or memory.
*/
void
-cmp64(Node *nl, Node *nr, int op, Prog *to)
+cmp64(Node *nl, Node *nr, int op, int likely, Prog *to)
{
Node lo1, hi1, lo2, hi2, r1, r2;
Prog *br;
@@ -663,14 +705,14 @@ cmp64(Node *nl, Node *nr, int op, Prog *to)
// cmp lo
// beq to
// L:
- br = gbranch(ABNE, T);
+ br = gbranch(ABNE, T, -likely);
break;
case ONE:
// cmp hi
// bne to
// cmp lo
// bne to
- patch(gbranch(ABNE, T), to);
+ patch(gbranch(ABNE, T, likely), to);
break;
case OGE:
case OGT:
@@ -680,8 +722,8 @@ cmp64(Node *nl, Node *nr, int op, Prog *to)
// cmp lo
// bge to (or bgt to)
// L:
- patch(gbranch(optoas(OGT, t), T), to);
- br = gbranch(optoas(OLT, t), T);
+ patch(gbranch(optoas(OGT, t), T, likely), to);
+ br = gbranch(optoas(OLT, t), T, -likely);
break;
case OLE:
case OLT:
@@ -691,8 +733,8 @@ cmp64(Node *nl, Node *nr, int op, Prog *to)
// cmp lo
// ble to (or jlt to)
// L:
- patch(gbranch(optoas(OLT, t), T), to);
- br = gbranch(optoas(OGT, t), T);
+ patch(gbranch(optoas(OLT, t), T, likely), to);
+ br = gbranch(optoas(OGT, t), T, -likely);
break;
}
@@ -707,7 +749,7 @@ cmp64(Node *nl, Node *nr, int op, Prog *to)
regfree(&r2);
// jump again
- patch(gbranch(optoas(op, t), T), to);
+ patch(gbranch(optoas(op, t), T, likely), to);
// point first branch down here if appropriate
if(br != P)
diff --git a/src/cmd/5g/doc.go b/src/cmd/5g/doc.go
index 5a4a772fb..aebdcab71 100644
--- a/src/cmd/5g/doc.go
+++ b/src/cmd/5g/doc.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build ignore
+
/*
5g is the version of the gc compiler for the ARM.
@@ -10,4 +12,4 @@ The $GOARCH for these tools is arm.
It reads .go files and outputs .5 files. The flags are documented in ../gc/doc.go.
*/
-package documentation
+package main
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
index 070804217..1fbf633f9 100644
--- a/src/cmd/5g/galign.c
+++ b/src/cmd/5g/galign.c
@@ -27,6 +27,7 @@ void
betypeinit(void)
{
widthptr = 4;
+ widthint = 4;
zprog.link = P;
zprog.as = AGOK;
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
index 7dbf3beec..45a9a887e 100644
--- a/src/cmd/5g/gg.h
+++ b/src/cmd/5g/gg.h
@@ -15,32 +15,36 @@ struct Addr
{
int32 offset;
int32 offset2;
- double dval;
- Prog* branch;
- char sval[NSNAME];
+
+ 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;
- char pun;
uchar etype;
};
#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* regp; // points to enclosing Reg struct
+ short as; // opcode
uchar reg; // doubles as width in DATA op
uchar scond;
+ Addr from; // src address
+ Addr to; // dst address
};
#define TEXTFLAG reg
@@ -78,22 +82,20 @@ void cgen_callinter(Node*, Node*, int);
void cgen_proc(Node*, int);
void cgen_callret(Node*, Node*);
void cgen_dcl(Node*);
-int cgen_inline(Node*, Node*);
int needconvert(Type*, Type*);
void genconv(Type*, Type*);
void allocparams(void);
-void checklabels();
+void checklabels(void);
void ginscall(Node*, int);
/*
* cgen
*/
void agen(Node*, Node*);
-Prog* cgenindex(Node *, Node *);
+Prog* cgenindex(Node *, Node *, int);
void igen(Node*, Node*, Node*);
void agenr(Node *n, Node *a, Node *res);
vlong fieldoffset(Type*, Node*);
-void bgen(Node*, int, Prog*);
void sgen(Node*, Node*, int64);
void gmove(Node*, Node*);
Prog* gins(int, Node*, Node*);
@@ -104,12 +106,14 @@ Prog* gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs);
Prog * gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs);
void naddr(Node*, Addr*, int);
void cgen_aret(Node*, Node*);
-void cgen_shift(int, Node*, Node*, Node*);
+void cgen_hmul(Node*, Node*, Node*);
+void cgen_shift(int, int, Node*, Node*, Node*);
+int componentgen(Node*, Node*);
/*
* cgen64.c
*/
-void cmp64(Node*, Node*, int, Prog*);
+void cmp64(Node*, Node*, int, int, Prog*);
void cgen64(Node*, Node*);
/*
@@ -117,16 +121,13 @@ void cgen64(Node*, Node*);
*/
void clearp(Prog*);
void proglist(void);
-Prog* gbranch(int, Type*);
+Prog* gbranch(int, Type*, int);
Prog* prog(int);
-void gaddoffset(Node*);
void gconv(int, int);
int conv2pt(Type*);
vlong convvtox(vlong, int);
void fnparam(Type*, int, int);
Prog* gop(int, Node*, Node*, Node*);
-void setconst(Addr*, vlong);
-void setaddr(Addr*, Node*);
int optoas(int, Type*);
void ginit(void);
void gclean(void);
@@ -141,11 +142,12 @@ int isfat(Type*);
int dotaddable(Node*, Node*);
void sudoclean(void);
int sudoaddable(int, Node*, Addr*, int*);
-void afunclit(Addr*);
+void afunclit(Addr*, Node*);
void datagostring(Strlit*, Addr*);
void split64(Node*, Node*, Node*);
void splitclean(void);
Node* ncon(uint32 i);
+void gtrack(Sym*);
/*
* obj.c
@@ -164,7 +166,7 @@ int Rconv(Fmt*);
int Yconv(Fmt*);
void listinit(void);
-void zaddr(Biobuf*, Addr*, int);
+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 de100620b..de1671bb6 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -28,6 +28,9 @@ void
markautoused(Prog* p)
{
for (; p; p = p->link) {
+ if (p->as == ATYPE)
+ continue;
+
if (p->from.name == D_AUTO && p->from.node)
p->from.node->used = 1;
@@ -40,27 +43,38 @@ markautoused(Prog* p)
void
fixautoused(Prog* p)
{
- for (; p; p = p->link) {
+ Prog **lp;
+
+ for (lp=&p; (p=*lp) != P; ) {
+ if (p->as == ATYPE && p->from.node && p->from.name == D_AUTO && !p->from.node->used) {
+ *lp = p->link;
+ continue;
+ }
+
if (p->from.name == D_AUTO && p->from.node)
p->from.offset += p->from.node->stkdelta;
if (p->to.name == D_AUTO && p->to.node)
p->to.offset += p->to.node->stkdelta;
+
+ lp = &p->link;
}
}
/*
* generate:
* call f
+ * proc=-1 normal call but no return
* proc=0 normal call
* proc=1 goroutine run in new proc
* proc=2 defer call save away stack
+ * proc=3 normal call to C pointer (not Go func value)
*/
void
ginscall(Node *f, int proc)
{
Prog *p;
- Node n1, r, con;
+ Node n1, r, r1, con;
switch(proc) {
default:
@@ -68,8 +82,26 @@ ginscall(Node *f, int proc)
break;
case 0: // normal call
- p = gins(ABL, N, f);
- afunclit(&p->to);
+ case -1: // normal call but no return
+ if(f->op == ONAME && f->class == PFUNC) {
+ p = gins(ABL, N, f);
+ afunclit(&p->to, f);
+ if(proc == -1 || noreturn(p))
+ gins(AUNDEF, N, N);
+ break;
+ }
+ nodreg(&r, types[tptr], 7);
+ nodreg(&r1, types[tptr], 1);
+ gmove(f, &r);
+ r.op = OINDREG;
+ gmove(&r, &r1);
+ r.op = OREGISTER;
+ r1.op = OINDREG;
+ gins(ABL, &r, &r1);
+ break;
+
+ case 3: // normal call of c function pointer
+ gins(ABL, N, f);
break;
case 1: // call in new proc (go)
@@ -120,7 +152,7 @@ ginscall(Node *f, int proc)
nodconst(&con, types[TINT32], 0);
p = gins(ACMP, &con, N);
p->reg = 0;
- patch(gbranch(ABNE, T), retpc);
+ patch(gbranch(ABNE, T, -1), retpc);
}
break;
}
@@ -136,6 +168,7 @@ cgen_callinter(Node *n, Node *res, int proc)
int r;
Node *i, *f;
Node tmpi, nodo, nodr, nodsp;
+ Prog *p;
i = n->left;
if(i->op != ODOTINTER)
@@ -180,7 +213,17 @@ cgen_callinter(Node *n, Node *res, int proc)
cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
- cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
+
+ if(proc == 0) {
+ // plain call: use direct c function pointer - more efficient
+ cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
+ nodr.op = OINDREG;
+ proc = 3;
+ } else {
+ // go/defer. generate go func value.
+ p = gins(AMOVW, &nodo, &nodr);
+ p->from.type = D_CONST; // REG = &(20+offset(REG)) -- i.tab->fun[f]
+ }
// BOTCH nodr.type = fntype;
nodr.type = n->left->type;
@@ -368,14 +411,19 @@ cgen_asop(Node *n)
case OOR:
a = optoas(n->etype, nl->type);
if(nl->addable) {
- regalloc(&n3, nr->type, N);
- cgen(nr, &n3);
+ if(smallintconst(nr))
+ n3 = *nr;
+ else {
+ regalloc(&n3, nr->type, N);
+ cgen(nr, &n3);
+ }
regalloc(&n2, nl->type, N);
cgen(nl, &n2);
gins(a, &n3, &n2);
cgen(&n2, nl);
regfree(&n2);
- regfree(&n3);
+ if(n3.op != OLITERAL)
+ regfree(&n3);
goto ret;
}
if(nr->ullman < UINF)
@@ -399,7 +447,9 @@ cgen_asop(Node *n)
hard:
n2.op = 0;
n1.op = 0;
- if(nr->ullman >= nl->ullman || nl->addable) {
+ if(nr->op == OLITERAL) {
+ // don't allocate a register for literals.
+ } else if(nr->ullman >= nl->ullman || nl->addable) {
regalloc(&n2, nr->type, N);
cgen(nr, &n2);
nr = &n2;
@@ -464,24 +514,99 @@ samereg(Node *a, Node *b)
}
/*
+ * generate high multiply
+ * res = (nl * nr) >> wordsize
+ */
+void
+cgen_hmul(Node *nl, Node *nr, Node *res)
+{
+ int w;
+ Node n1, n2, *tmp;
+ Type *t;
+ Prog *p;
+
+ if(nl->ullman < nr->ullman) {
+ tmp = nl;
+ nl = nr;
+ nr = tmp;
+ }
+ t = nl->type;
+ w = t->width * 8;
+ regalloc(&n1, t, res);
+ cgen(nl, &n1);
+ regalloc(&n2, t, N);
+ cgen(nr, &n2);
+ switch(simtype[t->etype]) {
+ case TINT8:
+ case TINT16:
+ gins(optoas(OMUL, t), &n2, &n1);
+ gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
+ break;
+ case TUINT8:
+ case TUINT16:
+ gins(optoas(OMUL, t), &n2, &n1);
+ gshift(AMOVW, &n1, SHIFT_LR, w, &n1);
+ break;
+ case TINT32:
+ case TUINT32:
+ // perform a long multiplication.
+ if(issigned[t->etype])
+ p = gins(AMULL, &n2, N);
+ else
+ p = gins(AMULLU, &n2, N);
+ // n2 * n1 -> (n1 n2)
+ p->reg = n1.val.u.reg;
+ p->to.type = D_REGREG;
+ p->to.reg = n1.val.u.reg;
+ p->to.offset = n2.val.u.reg;
+ break;
+ default:
+ fatal("cgen_hmul %T", t);
+ break;
+ }
+ cgen(&n1, res);
+ regfree(&n1);
+ regfree(&n2);
+}
+
+/*
* generate shift according to op, one of:
* res = nl << nr
* res = nl >> nr
*/
void
-cgen_shift(int op, Node *nl, Node *nr, Node *res)
+cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
{
Node n1, n2, n3, nt, t, lo, hi;
- int w;
+ int w, v;
Prog *p1, *p2, *p3;
Type *tr;
uvlong sc;
+ USED(bounded);
if(nl->type->width > 4)
fatal("cgen_shift %T", nl->type);
w = nl->type->width * 8;
+ if(op == OLROT) {
+ v = mpgetfix(nr->val.u.xval);
+ regalloc(&n1, nl->type, res);
+ if(w == 32) {
+ cgen(nl, &n1);
+ gshift(AMOVW, &n1, SHIFT_RR, w-v, &n1);
+ } else {
+ regalloc(&n2, nl->type, N);
+ cgen(nl, &n2);
+ gshift(AMOVW, &n2, SHIFT_LL, v, &n1);
+ gshift(AORR, &n2, SHIFT_LR, w-v, &n1);
+ regfree(&n2);
+ }
+ gmove(&n1, res);
+ regfree(&n1);
+ return;
+ }
+
if(nr->op == OLITERAL) {
regalloc(&n1, nl->type, res);
cgen(nl, &n1);
@@ -524,6 +649,7 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
regalloc(&n3, types[TUINT32], N);
gmove(&lo, &n1);
gmove(&hi, &n3);
+ splitclean();
gins(ATST, &n3, N);
nodconst(&t, types[TUINT32], w);
p1 = gins(AMOVW, &t, &n1);
@@ -546,9 +672,10 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
// test for shift being 0
gins(ATST, &n1, N);
- p3 = gbranch(ABEQ, T);
+ p3 = gbranch(ABEQ, T, -1);
// test and fix up large shifts
+ // TODO: if(!bounded), don't emit some of this.
regalloc(&n3, tr, N);
nodconst(&t, types[TUINT32], w);
gmove(&t, &n3);
@@ -589,7 +716,12 @@ clearfat(Node *nl)
if(debug['g'])
dump("\nclearfat", nl);
+
w = nl->type->width;
+ // Avoid taking the address for simple enough types.
+ if(componentgen(N, nl))
+ return;
+
c = w % 4; // bytes
q = w / 4; // quads
@@ -613,7 +745,7 @@ clearfat(Node *nl)
p = gins(ACMP, &dst, N);
raddr(&end, p);
- patch(gbranch(ABNE, T), pl);
+ patch(gbranch(ABNE, T, 0), pl);
regfree(&end);
} else
@@ -637,395 +769,3 @@ clearfat(Node *nl)
regfree(&dst);
regfree(&nz);
}
-
-static int
-regcmp(const void *va, const void *vb)
-{
- Node *ra, *rb;
-
- ra = (Node*)va;
- rb = (Node*)vb;
- return ra->local - rb->local;
-}
-
-static Prog* throwpc;
-
-// We're only going to bother inlining if we can
-// convert all the arguments to 32 bits safely. Can we?
-static int
-fix64(NodeList *nn, int n)
-{
- NodeList *l;
- Node *r;
- int i;
-
- l = nn;
- for(i=0; i<n; i++) {
- r = l->n->right;
- if(is64(r->type) && !smallintconst(r)) {
- if(r->op == OCONV)
- r = r->left;
- if(is64(r->type))
- return 0;
- }
- l = l->next;
- }
- return 1;
-}
-
-void
-getargs(NodeList *nn, Node *reg, int n)
-{
- NodeList *l;
- int i;
-
- throwpc = nil;
-
- l = nn;
- for(i=0; i<n; i++) {
- if(!smallintconst(l->n->right) && !isslice(l->n->right->type)) {
- regalloc(reg+i, l->n->right->type, N);
- cgen(l->n->right, reg+i);
- } else
- reg[i] = *l->n->right;
- if(reg[i].local != 0)
- yyerror("local used");
- reg[i].local = l->n->left->xoffset;
- l = l->next;
- }
- qsort((void*)reg, n, sizeof(*reg), regcmp);
- for(i=0; i<n; i++)
- reg[i].local = 0;
-}
-
-void
-cmpandthrow(Node *nl, Node *nr)
-{
- vlong cl;
- Prog *p1;
- int op;
- Node *c, n1, n2;
-
- op = OLE;
- if(smallintconst(nl)) {
- cl = mpgetfix(nl->val.u.xval);
- if(cl == 0)
- return;
- if(smallintconst(nr))
- return;
-
- // put the constant on the right
- op = brrev(op);
- c = nl;
- nl = nr;
- nr = c;
- }
-
- n1.op = OXXX;
- if(nr->op != OREGISTER) {
- regalloc(&n1, types[TUINT32], N);
- gmove(nr, &n1);
- nr = &n1;
- }
- n2.op = OXXX;
- if(nl->op != OREGISTER) {
- regalloc(&n2, types[TUINT32], N);
- gmove(nl, &n2);
- nl = &n2;
- }
- gcmp(optoas(OCMP, types[TUINT32]), nl, nr);
- if(nr == &n1)
- regfree(&n1);
- if(nl == &n2)
- regfree(&n2);
- if(throwpc == nil) {
- p1 = gbranch(optoas(op, types[TUINT32]), T);
- throwpc = pc;
- ginscall(panicslice, 0);
- patch(p1, pc);
- } else {
- op = brcom(op);
- p1 = gbranch(optoas(op, types[TUINT32]), T);
- patch(p1, throwpc);
- }
-}
-
-int
-sleasy(Node *n)
-{
- if(n->op != ONAME)
- return 0;
- if(!n->addable)
- return 0;
- return 1;
-}
-
-// generate inline code for
-// slicearray
-// sliceslice
-// arraytoslice
-int
-cgen_inline(Node *n, Node *res)
-{
- Node nodes[5];
- Node n1, n2, n3, nres, ntemp;
- vlong v;
- int i, narg;
-
- if(n->op != OCALLFUNC)
- goto no;
- if(!n->left->addable)
- goto no;
- if(n->left->sym == S)
- goto no;
- if(n->left->sym->pkg != runtimepkg)
- goto no;
- if(strcmp(n->left->sym->name, "slicearray") == 0)
- goto slicearray;
- if(strcmp(n->left->sym->name, "sliceslice") == 0) {
- narg = 4;
- goto sliceslice;
- }
- if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
- narg = 3;
- goto sliceslice;
- }
- goto no;
-
-slicearray:
- if(!sleasy(res))
- goto no;
- if(!fix64(n->list, 5))
- goto no;
- getargs(n->list, nodes, 5);
-
- // if(hb[3] > nel[1]) goto throw
- cmpandthrow(&nodes[3], &nodes[1]);
-
- // if(lb[2] > hb[3]) goto throw
- cmpandthrow(&nodes[2], &nodes[3]);
-
- // len = hb[3] - lb[2] (destroys hb)
- n2 = *res;
- n2.type = types[TUINT32];
- n2.xoffset += Array_nel;
-
- if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
- v = mpgetfix(nodes[3].val.u.xval) -
- mpgetfix(nodes[2].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gmove(&n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[3]);
- gmove(&nodes[3], &n1);
- if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
- gmove(&n1, &n2);
- regfree(&n1);
- }
-
- // cap = nel[1] - lb[2] (destroys nel)
- n2 = *res;
- n2.type = types[TUINT32];
- n2.xoffset += Array_cap;
-
- if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
- v = mpgetfix(nodes[1].val.u.xval) -
- mpgetfix(nodes[2].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gmove(&n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[1]);
- gmove(&nodes[1], &n1);
- if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
- gmove(&n1, &n2);
- regfree(&n1);
- }
-
- // if slice could be too big, dereference to
- // catch nil array pointer.
- if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
- n2 = nodes[0];
- n2.xoffset = 0;
- n2.op = OINDREG;
- n2.type = types[TUINT8];
- regalloc(&n1, types[TUINT32], N);
- gins(AMOVB, &n2, &n1);
- regfree(&n1);
- }
-
- // ary = old[0] + (lb[2] * width[4]) (destroys old)
- n2 = *res;
- n2.type = types[tptr];
- n2.xoffset += Array_array;
-
- if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
- v = mpgetfix(nodes[2].val.u.xval) *
- mpgetfix(nodes[4].val.u.xval);
- if(v != 0) {
- nodconst(&n1, types[tptr], v);
- gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
- }
- } else {
- regalloc(&n1, types[tptr], &nodes[2]);
- gmove(&nodes[2], &n1);
- if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1) {
- regalloc(&n3, types[tptr], N);
- gmove(&nodes[4], &n3);
- gins(optoas(OMUL, types[tptr]), &n3, &n1);
- regfree(&n3);
- }
- gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
- regfree(&n1);
- }
- gmove(&nodes[0], &n2);
-
- for(i=0; i<5; i++) {
- if(nodes[i].op == OREGISTER)
- regfree(&nodes[i]);
- }
- return 1;
-
-sliceslice:
- if(!fix64(n->list, narg))
- goto no;
- ntemp.op = OXXX;
- if(!sleasy(n->list->n->right)) {
- Node *n0;
-
- n0 = n->list->n->right;
- tempname(&ntemp, res->type);
- cgen(n0, &ntemp);
- n->list->n->right = &ntemp;
- getargs(n->list, nodes, narg);
- n->list->n->right = n0;
- } else
- getargs(n->list, nodes, narg);
-
- nres = *res; // result
- if(!sleasy(res)) {
- if(ntemp.op == OXXX)
- tempname(&ntemp, res->type);
- nres = ntemp;
- }
-
- if(narg == 3) { // old[lb:]
- // move width to where it would be for old[lb:hb]
- nodes[3] = nodes[2];
- nodes[2].op = OXXX;
-
- // if(lb[1] > old.nel[0]) goto throw;
- n2 = nodes[0];
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
- cmpandthrow(&nodes[1], &n2);
-
- // ret.nel = old.nel[0]-lb[1];
- n2 = nodes[0];
- n2.type = types[TUINT32];
- n2.xoffset += Array_nel;
-
- regalloc(&n1, types[TUINT32], N);
- gmove(&n2, &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
-
- n2 = nres;
- n2.type = types[TUINT32];
- n2.xoffset += Array_nel;
- gmove(&n1, &n2);
- regfree(&n1);
- } else { // old[lb:hb]
- // if(hb[2] > old.cap[0]) goto throw;
- n2 = nodes[0];
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
- cmpandthrow(&nodes[2], &n2);
-
- // if(lb[1] > hb[2]) goto throw;
- cmpandthrow(&nodes[1], &nodes[2]);
-
- // ret.len = hb[2]-lb[1]; (destroys hb[2])
- n2 = nres;
- n2.type = types[TUINT32];
- n2.xoffset += Array_nel;
-
- if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
- v = mpgetfix(nodes[2].val.u.xval) -
- mpgetfix(nodes[1].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gmove(&n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[2]);
- gmove(&nodes[2], &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
- gmove(&n1, &n2);
- regfree(&n1);
- }
- }
-
- // ret.cap = old.cap[0]-lb[1]; (uses hb[2])
- n2 = nodes[0];
- n2.type = types[TUINT32];
- n2.xoffset += Array_cap;
-
- regalloc(&n1, types[TUINT32], &nodes[2]);
- gmove(&n2, &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
-
- n2 = nres;
- n2.type = types[TUINT32];
- n2.xoffset += Array_cap;
- gmove(&n1, &n2);
- regfree(&n1);
-
- // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
- n2 = nodes[0];
- n2.type = types[tptr];
- n2.xoffset += Array_array;
- regalloc(&n3, types[tptr], N);
- gmove(&n2, &n3);
-
- regalloc(&n1, types[tptr], &nodes[1]);
- if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
- gmove(&n2, &n1);
- v = mpgetfix(nodes[1].val.u.xval) *
- mpgetfix(nodes[3].val.u.xval);
- if(v != 0) {
- nodconst(&n2, types[tptr], v);
- gins(optoas(OADD, types[tptr]), &n3, &n1);
- }
- } else {
- gmove(&nodes[1], &n1);
- if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1) {
- regalloc(&n2, types[tptr], N);
- gmove(&nodes[3], &n2);
- gins(optoas(OMUL, types[tptr]), &n2, &n1);
- regfree(&n2);
- }
- gins(optoas(OADD, types[tptr]), &n3, &n1);
- }
- regfree(&n3);
-
- n2 = nres;
- n2.type = types[tptr];
- n2.xoffset += Array_array;
- gmove(&n1, &n2);
- regfree(&n1);
-
- for(i=0; i<4; i++) {
- if(nodes[i].op == OREGISTER)
- regfree(&nodes[i]);
- }
-
- if(!sleasy(res)) {
- cgen(&nres, res);
- }
- return 1;
-
-no:
- return 0;
-}
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
index 2763e7b16..9c5fb2a96 100644
--- a/src/cmd/5g/gobj.c
+++ b/src/cmd/5g/gobj.c
@@ -65,17 +65,17 @@ zhist(Biobuf *b, int line, vlong offset)
Bputc(b, line>>8);
Bputc(b, line>>16);
Bputc(b, line>>24);
- zaddr(b, &zprog.from, 0);
+ zaddr(b, &zprog.from, 0, 0);
a = zprog.to;
if(offset != 0) {
a.offset = offset;
a.type = D_CONST;
}
- zaddr(b, &a, 0);
+ zaddr(b, &a, 0, 0);
}
void
-zaddr(Biobuf *b, Addr *a, int s)
+zaddr(Biobuf *b, Addr *a, int s, int gotype)
{
int32 l;
uint64 e;
@@ -95,6 +95,7 @@ zaddr(Biobuf *b, Addr *a, int s)
Bputc(b, a->reg);
Bputc(b, s);
Bputc(b, a->name);
+ Bputc(b, gotype);
}
switch(a->type) {
@@ -128,9 +129,9 @@ zaddr(Biobuf *b, Addr *a, int s)
break;
case D_BRANCH:
- if(a->branch == nil)
+ if(a->u.branch == nil)
fatal("unpatched branch");
- a->offset = a->branch->loc;
+ a->offset = a->u.branch->loc;
l = a->offset;
Bputc(b, l);
Bputc(b, l>>8);
@@ -139,7 +140,7 @@ zaddr(Biobuf *b, Addr *a, int s)
break;
case D_SCONST:
- n = a->sval;
+ n = a->u.sval;
for(i=0; i<NSNAME; i++) {
Bputc(b, *n);
n++;
@@ -147,11 +148,12 @@ zaddr(Biobuf *b, Addr *a, int s)
break;
case D_REGREG:
+ case D_REGREG2:
Bputc(b, a->offset);
break;
case D_FCONST:
- ieeedtod(&e, a->dval);
+ ieeedtod(&e, a->u.dval);
l = e;
Bputc(b, l);
Bputc(b, l>>8);
@@ -166,20 +168,66 @@ zaddr(Biobuf *b, Addr *a, int s)
}
}
+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, t, sym;
- struct { Sym *sym; short type; } h[NSYM];
+ int sf, st, gf, gt, new;
Sym *s;
Prog *p;
- for(sym=0; sym<NSYM; sym++) {
- h[sym].sym = S;
- h[sym].type = 0;
- }
- sym = 1;
+ zsymreset();
// fix up pc
pcloc = 0;
@@ -209,53 +257,20 @@ dumpfuncs(void)
}
for(p=pl->firstpc; p!=P; p=p->link) {
- jackpot:
- sf = 0;
- s = p->from.sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = p->from.name;
- if(t == D_ADDR)
- t = p->from.name;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- s->sym = sym;
- zname(bout, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = p->to.sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = p->to.name;
- if(t == D_ADDR)
- t = p->to.name;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- s->sym = sym;
- zname(bout, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
+ 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);
@@ -263,8 +278,8 @@ dumpfuncs(void)
Bputc(bout, p->lineno>>8);
Bputc(bout, p->lineno>>16);
Bputc(bout, p->lineno>>24);
- zaddr(bout, &p->from, sf);
- zaddr(bout, &p->to, st);
+ zaddr(bout, &p->from, sf, gf);
+ zaddr(bout, &p->to, st, gt);
}
}
}
@@ -288,7 +303,7 @@ dsname(Sym *sym, int off, char *t, int n)
p->to.name = D_NONE;
p->to.reg = NREG;
p->to.offset = 0;
- memmove(p->to.sval, t, n);
+ memmove(p->to.u.sval, t, n);
return off + n;
}
@@ -372,13 +387,13 @@ gdatacomplex(Node *nam, Mpcplx *cval)
p = gins(ADATA, nam, N);
p->reg = w;
p->to.type = D_FCONST;
- p->to.dval = mpgetflt(&cval->real);
+ p->to.u.dval = mpgetflt(&cval->real);
p = gins(ADATA, nam, N);
p->reg = w;
p->from.offset += w;
p->to.type = D_FCONST;
- p->to.dval = mpgetflt(&cval->imag);
+ p->to.u.dval = mpgetflt(&cval->imag);
}
void
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index 9acf93670..191c755b8 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -108,17 +108,22 @@ dumpdata(void)
/*
* generate a branch.
* t is ignored.
+ * likely values are for branch prediction:
+ * -1 unlikely
+ * 0 no opinion
+ * +1 likely
*/
Prog*
-gbranch(int as, Type *t)
+gbranch(int as, Type *t, int likely)
{
Prog *p;
USED(t);
+ USED(likely); // TODO: record this for linker
p = prog(as);
p->to.type = D_BRANCH;
- p->to.branch = P;
+ p->to.u.branch = P;
return p;
}
@@ -130,7 +135,7 @@ patch(Prog *p, Prog *to)
{
if(p->to.type != D_BRANCH)
fatal("patch: not a branch");
- p->to.branch = to;
+ p->to.u.branch = to;
p->to.offset = to->loc;
}
@@ -141,8 +146,8 @@ unpatch(Prog *p)
if(p->to.type != D_BRANCH)
fatal("unpatch: not a branch");
- q = p->to.branch;
- p->to.branch = P;
+ q = p->to.u.branch;
+ p->to.u.branch = P;
p->to.offset = 0;
return q;
}
@@ -170,64 +175,6 @@ newplist(void)
}
void
-clearstk(void)
-{
- Plist *pl;
- Prog *p, *p1, *p2, *p3;
- Node dst, end, zero, con;
-
- if(plast->firstpc->to.offset <= 0)
- return;
-
- // reestablish context for inserting code
- // at beginning of function.
- pl = plast;
- p1 = pl->firstpc;
- p2 = p1->link;
- pc = mal(sizeof(*pc));
- clearp(pc);
- p1->link = pc;
-
- // zero stack frame
-
- // MOVW $4(SP), R1
- nodreg(&dst, types[tptr], 1);
- p = gins(AMOVW, N, &dst);
- p->from.type = D_CONST;
- p->from.reg = REGSP;
- p->from.offset = 4;
-
- // MOVW $n(R1), R2
- nodreg(&end, types[tptr], 2);
- p = gins(AMOVW, N, &end);
- p->from.type = D_CONST;
- p->from.reg = 1;
- p->from.offset = p1->to.offset;
-
- // MOVW $0, R3
- nodreg(&zero, types[TUINT32], 3);
- nodconst(&con, types[TUINT32], 0);
- gmove(&con, &zero);
-
- // L:
- // MOVW.P R3, 0(R1) +4
- // CMP R1, R2
- // BNE L
- p = gins(AMOVW, &zero, &dst);
- p->to.type = D_OREG;
- p->to.offset = 4;
- p->scond |= C_PBIT;
- p3 = p;
- p = gins(ACMP, &dst, N);
- raddr(&end, p);
- patch(gbranch(ABNE, T), p3);
-
- // continue with original code.
- gins(ANOP, N, N)->link = p2;
- pc = P;
-}
-
-void
gused(Node *n)
{
gins(ANOP, n, N); // used
@@ -238,22 +185,23 @@ gjmp(Prog *to)
{
Prog *p;
- p = gbranch(AB, T);
+ p = gbranch(AB, T, 0);
if(to != P)
patch(p, to);
return p;
}
void
-ggloblnod(Node *nam, int32 width)
+ggloblnod(Node *nam)
{
Prog *p;
p = gins(AGLOBL, nam, N);
p->lineno = nam->lineno;
+ p->from.gotype = ngotype(nam);
p->to.sym = S;
p->to.type = D_CONST;
- p->to.offset = width;
+ p->to.offset = nam->type->width;
if(nam->readonly)
p->reg = RODATA;
if(nam->type != T && !haspointers(nam->type))
@@ -261,7 +209,7 @@ ggloblnod(Node *nam, int32 width)
}
void
-ggloblsym(Sym *s, int32 width, int dupok)
+ggloblsym(Sym *s, int32 width, int dupok, int rodata)
{
Prog *p;
@@ -273,8 +221,20 @@ ggloblsym(Sym *s, int32 width, int dupok)
p->to.name = D_NONE;
p->to.offset = width;
if(dupok)
- p->reg = DUPOK;
- p->reg |= RODATA;
+ p->reg |= DUPOK;
+ if(rodata)
+ p->reg |= RODATA;
+}
+
+void
+gtrack(Sym *s)
+{
+ Prog *p;
+
+ p = gins(AUSEFIELD, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
}
int
@@ -298,17 +258,20 @@ isfat(Type *t)
* also fix up direct register references to be D_OREG.
*/
void
-afunclit(Addr *a)
+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;
}
}
static int resvd[] =
{
- 9, // reserved for m
- 10, // reserved for g
+ 9, // reserved for m
+ 10, // reserved for g
+ REGSP, // reserved for SP
};
void
@@ -401,6 +364,7 @@ regalloc(Node *n, Type *t, Node *o)
regpc[i] = (uintptr)getcallerpc(&n);
goto out;
}
+ print("registers allocated at\n");
for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
print("%d %p\n", i, regpc[i]);
yyerror("out of fixed registers");
@@ -452,15 +416,17 @@ regfree(Node *n)
print("regalloc fix %d float %d\n", fixfree, floatfree);
}
- if(n->op == ONAME && iscomplex[n->type->etype])
+ if(n->op == ONAME)
return;
if(n->op != OREGISTER && n->op != OINDREG)
fatal("regfree: not a register");
i = n->val.u.reg;
+ if(i == REGSP)
+ return;
if(i < 0 || i >= nelem(reg) || i >= nelem(regpc))
fatal("regfree: reg out of range");
if(reg[i] <= 0)
- fatal("regfree: reg not allocated");
+ fatal("regfree: reg %R not allocated", i);
reg[i]--;
if(reg[i] == 0)
regpc[i] = 0;
@@ -597,9 +563,9 @@ split64(Node *n, Node *lo, Node *hi)
if(!is64(n->type))
fatal("split64 %T", n->type);
- sclean[nsclean].op = OEMPTY;
if(nsclean >= nelem(sclean))
fatal("split64 clean");
+ sclean[nsclean].op = OEMPTY;
nsclean++;
switch(n->op) {
default:
@@ -1155,7 +1121,7 @@ gcmp(int as, Node *lhs, Node *rhs)
{
Prog *p;
- if(lhs->op != OREGISTER || rhs->op != OREGISTER)
+ if(lhs->op != OREGISTER)
fatal("bad operands to gcmp: %O %O", lhs->op, rhs->op);
p = gins(as, rhs, N);
@@ -1194,6 +1160,27 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
return p;
}
+// Generate an instruction referencing *n
+// to force segv on nil pointer dereference.
+void
+checkref(Node *n)
+{
+ Node m1, m2;
+
+ if(n->type->type->width < unmappedzero)
+ return;
+
+ regalloc(&m1, types[TUINTPTR], n);
+ regalloc(&m2, types[TUINT8], n);
+ cgen(n, &m1);
+ m1.xoffset = 0;
+ m1.op = OINDREG;
+ m1.type = types[TUINT8];
+ gins(AMOVBU, &m1, &m2);
+ regfree(&m2);
+ regfree(&m1);
+}
+
static void
checkoffset(Addr *a, int canemitcode)
{
@@ -1209,7 +1196,7 @@ checkoffset(Addr *a, int canemitcode)
// reference with large offset. instead, emit explicit
// test of 0(reg).
regalloc(&n1, types[TUINTPTR], N);
- p = gins(AMOVW, N, &n1);
+ p = gins(AMOVB, N, &n1);
p->from = *a;
p->from.offset = 0;
regfree(&n1);
@@ -1222,14 +1209,22 @@ checkoffset(Addr *a, int canemitcode)
void
naddr(Node *n, Addr *a, int canemitcode)
{
+ Prog *p;
+
a->type = D_NONE;
a->name = D_NONE;
a->reg = NREG;
+ a->gotype = S;
a->node = N;
a->etype = 0;
if(n == N)
return;
+ if(n->type != T && n->type->etype != TIDEAL) {
+ dowidth(n->type);
+ a->width = n->type->width;
+ }
+
switch(n->op) {
default:
fatal("naddr: bad %O %D", n->op, a);
@@ -1286,6 +1281,25 @@ naddr(Node *n, Addr *a, int canemitcode)
a->name = D_PARAM;
a->node = n->left->orig;
break;
+
+ case OCLOSUREVAR:
+ if(!canemitcode)
+ fatal("naddr OCLOSUREVAR cannot emit code");
+ p = gins(AMOVW, N, N);
+ p->from.type = D_OREG;
+ p->from.reg = 7;
+ p->from.offset = n->xoffset;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+ a->type = D_REG;
+ a->reg = 1;
+ a->sym = S;
+ break;
+
+ case OCFUNC:
+ naddr(n->left, a, canemitcode);
+ a->sym = n->left->sym;
+ break;
case ONAME:
a->etype = 0;
@@ -1326,6 +1340,7 @@ naddr(Node *n, Addr *a, int canemitcode)
case PFUNC:
a->name = D_EXTERN;
a->type = D_CONST;
+ a->sym = funcsym(a->sym);
break;
}
break;
@@ -1337,7 +1352,7 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case CTFLT:
a->type = D_FCONST;
- a->dval = mpgetflt(n->val.u.fval);
+ a->u.dval = mpgetflt(n->val.u.fval);
break;
case CTINT:
case CTRUNE:
@@ -1409,6 +1424,9 @@ naddr(Node *n, Addr *a, int canemitcode)
fatal("naddr: OADDR %d\n", a->type);
}
}
+
+ if(a->width < 0)
+ fatal("naddr: bad width for %N -> %D", n, a);
}
/*
@@ -1619,6 +1637,16 @@ optoas(int op, Type *t)
a = ASUBD;
break;
+ case CASE(OMINUS, TINT8):
+ case CASE(OMINUS, TUINT8):
+ case CASE(OMINUS, TINT16):
+ case CASE(OMINUS, TUINT16):
+ case CASE(OMINUS, TINT32):
+ case CASE(OMINUS, TUINT32):
+ case CASE(OMINUS, TPTR32):
+ a = ARSB;
+ break;
+
case CASE(OAND, TINT8):
case CASE(OAND, TUINT8):
case CASE(OAND, TINT16):
@@ -1825,6 +1853,9 @@ sudoaddable(int as, Node *n, Addr *a, int *w)
goto odot;
case OINDEX:
+ return 0;
+ // disabled: OINDEX case is now covered by agenr
+ // for a more suitable register allocation pattern.
if(n->left->type->etype == TSTRING)
return 0;
cleani += 2;
@@ -1942,7 +1973,7 @@ oindex:
t = types[TINT32];
regalloc(reg1, t, N);
regalloc(&n3, types[TINT32], reg1);
- p2 = cgenindex(r, &n3);
+ p2 = cgenindex(r, &n3, debug['B'] || n->bounded);
gmove(&n3, reg1);
regfree(&n3);
@@ -1982,7 +2013,7 @@ oindex:
cgen(&n2, &n3);
gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3);
regfree(&n3);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
if(p2)
patch(p2, pc);
ginscall(panicindex, 0);
@@ -2032,7 +2063,7 @@ oindex_const:
v = mpgetfix(r->val.u.xval);
if(o & ODynam) {
- if(!debug['B'] && !n->etype) {
+ if(!debug['B'] && !n->bounded) {
n1 = *reg;
n1.op = OINDREG;
n1.type = types[tptr];
@@ -2045,7 +2076,7 @@ oindex_const:
gcmp(optoas(OCMP, types[TUINT32]), &n4, &n3);
regfree(&n4);
regfree(&n3);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
ginscall(panicindex, 0);
patch(p1, pc);
}
diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c
index f0da24742..6c3f1d744 100644
--- a/src/cmd/5g/list.c
+++ b/src/cmd/5g/list.c
@@ -153,6 +153,12 @@ Dconv(Fmt *fp)
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)
@@ -160,24 +166,24 @@ Dconv(Fmt *fp)
break;
case D_BRANCH:
- if(a->branch == P || a->branch->loc == 0) {
+ 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->branch->loc);
+ sprint(str, "%s+%d(APC)", a->sym->name, a->u.branch->loc);
else
- sprint(str, "%d(APC)", a->branch->loc);
+ sprint(str, "%d(APC)", a->u.branch->loc);
break;
case D_FCONST:
- snprint(str, sizeof(str), "$(%.17e)", a->dval);
+ snprint(str, sizeof(str), "$(%.17e)", a->u.dval);
break;
case D_SCONST:
- snprint(str, sizeof(str), "$\"%Y\"", a->sval);
+ snprint(str, sizeof(str), "$\"%Y\"", a->u.sval);
break;
// TODO(kaib): Add back
@@ -190,7 +196,10 @@ Dconv(Fmt *fp)
// goto conv;
}
conv:
- return fmtstrcpy(fp, str);
+ fmtstrcpy(fp, str);
+ if(a->gotype)
+ fmtprint(fp, "{%s}", a->gotype->name);
+ return 0;
}
int
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
index 7a0070fc9..af7d654de 100644
--- a/src/cmd/5g/opt.h
+++ b/src/cmd/5g/opt.h
@@ -34,8 +34,6 @@
#define D_HI D_NONE
#define D_LO D_NONE
-#define isregtype(t) ((t)>= D_AX && (t)<=D_R15)
-
#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
@@ -49,12 +47,16 @@
typedef struct Reg Reg;
typedef struct Rgn Rgn;
+// A Reg is a wrapper around a single Prog (one instruction) that holds
+// register optimization information while the optimizer runs.
+// r->prog is the instruction.
+// r->prog->regp points back to r.
struct Reg
{
- Bits set;
- Bits use1;
- Bits use2;
+ Bits set; // variables written by this instruction.
+ Bits use1; // variables read by prog->from.
+ Bits use2; // variables read by prog->to.
Bits refbehind;
Bits refahead;
@@ -70,13 +72,13 @@ struct Reg
uint16 loop; // x5 for every loop
uchar refset; // diagnostic generated
- Reg* p1;
- Reg* p2;
+ Reg* p1; // predecessors of this instruction: p1,
+ Reg* p2; // and then p2 linked though p2link.
Reg* p2link;
- Reg* s1;
+ Reg* s1; // successors of this instruction (at most two: s1 and s2).
Reg* s2;
- Reg* link;
- Prog* prog;
+ Reg* link; // next instruction in function code
+ Prog* prog; // actual instruction
};
#define R ((Reg*)0)
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
index e87f5d697..b6202a882 100644
--- a/src/cmd/5g/peep.c
+++ b/src/cmd/5g/peep.c
@@ -1,5 +1,5 @@
// Inferno utils/5c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5g/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -49,7 +49,6 @@ peep(void)
int t;
p1 = nil;
- USED(p1); // ... in unreachable code...
/*
* complete R structure
*/
@@ -77,6 +76,8 @@ peep(void)
case AGLOBL:
case ANAME:
case ASIGNAME:
+ case ALOCALS:
+ case ATYPE:
p = p->link;
}
}
@@ -120,7 +121,7 @@ loop1:
}
break;
-#ifdef NOTDEF
+#ifdef NOTDEF
if(p->scond == C_SCOND_NONE)
if(regtyp(&p->to))
if(isdconst(&p->from)) {
@@ -133,26 +134,24 @@ loop1:
if(t)
goto loop1;
-return;
-#ifdef NOTDEF
for(r=firstr; r!=R; r=r->link) {
p = r->prog;
switch(p->as) {
-// case AEOR:
-// /*
-// * EOR -1,x,y => MVN x,y
-// */
-// if(isdconst(&p->from) && p->from.offset == -1) {
-// p->as = AMVN;
-// p->from.type = D_REG;
-// if(p->reg != NREG)
-// p->from.reg = p->reg;
-// else
-// p->from.reg = p->to.reg;
-// p->reg = NREG;
-// }
-// break;
+ case AEOR:
+ /*
+ * EOR -1,x,y => MVN x,y
+ */
+ if(isdconst(&p->from) && p->from.offset == -1) {
+ p->as = AMVN;
+ p->from.type = D_REG;
+ if(p->reg != NREG)
+ p->from.reg = p->reg;
+ else
+ p->from.reg = p->to.reg;
+ p->reg = NREG;
+ }
+ break;
case AMOVH:
case AMOVHU:
@@ -161,6 +160,7 @@ return;
/*
* look for MOVB x,R; MOVB R,R
*/
+ r1 = r->link;
if(p->to.type != D_REG)
break;
if(r1 == R)
@@ -175,23 +175,22 @@ return;
excise(r1);
break;
}
- r1 = r->link;
}
-// for(r=firstr; r!=R; r=r->link) {
-// p = r->prog;
-// switch(p->as) {
-// case AMOVW:
-// case AMOVB:
-// case AMOVBU:
-// if(p->from.type == D_OREG && p->from.offset == 0)
-// xtramodes(r, &p->from);
-// else
-// if(p->to.type == D_OREG && p->to.offset == 0)
-// xtramodes(r, &p->to);
-// else
-// continue;
-// break;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case AMOVW:
+ case AMOVB:
+ case AMOVBU:
+ if(p->from.type == D_OREG && p->from.offset == 0)
+ xtramodes(r, &p->from);
+ else
+ if(p->to.type == D_OREG && p->to.offset == 0)
+ xtramodes(r, &p->to);
+ else
+ continue;
+ break;
// case ACMP:
// /*
// * elide CMP $0,x if calculation of x can set condition codes
@@ -259,13 +258,17 @@ return;
// r2->prog->as = t;
// excise(r);
// continue;
-// }
-// }
+ }
+ }
- predicate();
-#endif
+// predicate();
}
+/*
+ * uniqp returns a "unique" predecessor to instruction r.
+ * If the instruction is the first one or has multiple
+ * predecessors due to jump, R is returned.
+ */
Reg*
uniqp(Reg *r)
{
@@ -738,6 +741,11 @@ shiftprop(Reg *r)
return 1;
}
+/*
+ * findpre returns the last instruction mentioning v
+ * before r. It must be a set, and there must be
+ * a unique path from that instruction to r.
+ */
Reg*
findpre(Reg *r, Adr *v)
{
@@ -758,6 +766,10 @@ findpre(Reg *r, Adr *v)
return R;
}
+/*
+ * findinc finds ADD instructions with a constant
+ * argument which falls within the immed_12 range.
+ */
Reg*
findinc(Reg *r, Reg *r2, Adr *v)
{
@@ -848,6 +860,19 @@ finduse(Reg *r, Adr *v)
return findu1(r, v);
}
+/*
+ * xtramodes enables the ARM post increment and
+ * shift offset addressing modes to transform
+ * MOVW 0(R3),R1
+ * ADD $4,R3,R3
+ * into
+ * MOVW.P 4(R3),R1
+ * and
+ * ADD R0,R1
+ * MOVBU 0(R1),R0
+ * into
+ * MOVBU R0<<0(R1),R0
+ */
int
xtramodes(Reg *r, Adr *a)
{
@@ -856,8 +881,6 @@ xtramodes(Reg *r, Adr *a)
Adr v;
p = r->prog;
- if(debug['h'] && p->as == AMOVB && p->from.type == D_OREG) /* byte load */
- return 0;
v = *a;
v.type = D_REG;
r1 = findpre(r, &v);
@@ -866,6 +889,9 @@ xtramodes(Reg *r, Adr *a)
if(p1->to.type == D_REG && p1->to.reg == v.reg)
switch(p1->as) {
case AADD:
+ if(p1->scond & C_SBIT)
+ // avoid altering ADD.S/ADC sequences.
+ break;
if(p1->from.type == D_REG ||
(p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
(p->as != AMOVB || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
@@ -1032,6 +1058,7 @@ copyu(Prog *p, Adr *v, Adr *s)
return 0;
case AMULLU: /* read, read, write, write */
+ case AMULL:
case AMULA:
case AMVN:
return 2;
@@ -1135,12 +1162,9 @@ copyu(Prog *p, Adr *v, Adr *s)
return 0;
case ARET: /* funny */
- if(v->type == D_REG)
- if(v->reg == REGRET)
- return 2;
- if(v->type == D_FREG)
- if(v->reg == FREGRET)
- return 2;
+ if(s != A)
+ return 1;
+ return 3;
case ABL: /* funny */
if(v->type == D_REG) {
@@ -1152,6 +1176,8 @@ copyu(Prog *p, Adr *v, Adr *s)
if(v->type == D_FREG)
if(v->reg <= FREGEXT && v->reg > exfregoffset)
return 2;
+ if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg)
+ return 2;
if(s != A) {
if(copysub(&p->to, v, s, 1))
@@ -1167,6 +1193,9 @@ copyu(Prog *p, Adr *v, Adr *s)
if(v->reg == (uchar)REGARG)
return 3;
return 0;
+
+ case ALOCALS: /* funny */
+ return 0;
}
}
@@ -1213,7 +1242,7 @@ copyau(Adr *a, Adr *v)
if(a->reg == v->reg)
return 1;
} else
- if(a->type == D_REGREG) {
+ if(a->type == D_REGREG || a->type == D_REGREG2) {
if(a->reg == v->reg)
return 1;
if(a->offset == v->reg)
@@ -1276,7 +1305,7 @@ copysub(Adr *a, Adr *v, Adr *s, int f)
if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
} else
- if(a->type == D_REGREG) {
+ if(a->type == D_REGREG || a->type == D_REGREG2) {
if(a->offset == v->reg)
a->offset = s->reg;
if(a->reg == v->reg)
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index 393266973..eaaaf9be3 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -1,5 +1,5 @@
// Inferno utils/5c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5g/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -34,8 +34,8 @@
#include "gg.h"
#include "opt.h"
-#define NREGVAR 24
-#define REGBITS ((uint32)0xffffff)
+#define NREGVAR 32
+#define REGBITS ((uint32)0xffffffff)
#define P2R(p) (Reg*)(p->reg)
void addsplits(void);
@@ -95,7 +95,7 @@ setoutvar(void)
ovar.b[z] |= bit.b[z];
t = structnext(&save);
}
-//if(bany(ovar))
+//if(bany(&ovar))
//print("ovar = %Q\n", ovar);
}
@@ -160,8 +160,18 @@ static char* regname[] = {
".F5",
".F6",
".F7",
+ ".F8",
+ ".F9",
+ ".F10",
+ ".F11",
+ ".F12",
+ ".F13",
+ ".F14",
+ ".F15",
};
+static Node* regnodes[NREGVAR];
+
void
regopt(Prog *firstp)
{
@@ -197,7 +207,6 @@ regopt(Prog *firstp)
return;
}
- r1 = R;
firstr = R;
lastr = R;
@@ -208,8 +217,11 @@ regopt(Prog *firstp)
*/
nvar = NREGVAR;
memset(var, 0, NREGVAR*sizeof var[0]);
- for(i=0; i<NREGVAR; i++)
- var[i].node = newname(lookup(regname[i]));
+ for(i=0; i<NREGVAR; i++) {
+ if(regnodes[i] == N)
+ regnodes[i] = newname(lookup(regname[i]));
+ var[i].node = regnodes[i];
+ }
regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
for(z=0; z<BITS; z++) {
@@ -236,6 +248,8 @@ regopt(Prog *firstp)
case AGLOBL:
case ANAME:
case ASIGNAME:
+ case ALOCALS:
+ case ATYPE:
continue;
}
r = rega();
@@ -263,6 +277,10 @@ regopt(Prog *firstp)
}
}
+ // Avoid making variables for direct-called functions.
+ if(p->as == ABL && p->to.type == D_EXTERN)
+ continue;
+
/*
* left side always read
*/
@@ -408,10 +426,14 @@ regopt(Prog *firstp)
addrs.b[z] |= bit.b[z];
}
-// print("bit=%2d addr=%d et=%-6E w=%-2d s=%S + %lld\n",
-// i, v->addr, v->etype, v->width, v->sym, v->offset);
+ if(debug['R'] && debug['v'])
+ print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
+ i, v->addr, v->etype, v->width, v->node, v->offset);
}
+ if(debug['R'] && debug['v'])
+ dumpit("pass1", firstr);
+
/*
* pass 2
* turn branch references to pointers
@@ -420,9 +442,9 @@ regopt(Prog *firstp)
for(r=firstr; r!=R; r=r->link) {
p = r->prog;
if(p->to.type == D_BRANCH) {
- if(p->to.branch == P)
+ if(p->to.u.branch == P)
fatal("pnil %P", p);
- r1 = p->to.branch->regp;
+ r1 = p->to.u.branch->regp;
if(r1 == R)
fatal("rnil %P", p);
if(r1 == r) {
@@ -440,6 +462,9 @@ regopt(Prog *firstp)
print(" addr = %Q\n", addrs);
}
+ if(debug['R'] && debug['v'])
+ dumpit("pass2", firstr);
+
/*
* pass 2.5
* find looping structure
@@ -449,6 +474,9 @@ regopt(Prog *firstp)
change = 0;
loopit(firstr, nr);
+ if(debug['R'] && debug['v'])
+ dumpit("pass2.5", firstr);
+
/*
* pass 3
* iterate propagating usage
@@ -476,6 +504,9 @@ loop11:
if(change)
goto loop1;
+ if(debug['R'] && debug['v'])
+ dumpit("pass3", firstr);
+
/*
* pass 4
@@ -492,6 +523,9 @@ loop2:
addsplits();
+ if(debug['R'] && debug['v'])
+ dumpit("pass4", firstr);
+
if(debug['R'] > 1) {
print("\nprop structure:\n");
for(r = firstr; r != R; r = r->link) {
@@ -543,6 +577,9 @@ loop2:
r->act.b[0] &= ~REGBITS;
}
+ if(debug['R'] && debug['v'])
+ dumpit("pass4.5", firstr);
+
/*
* pass 5
* isolate regions
@@ -605,6 +642,9 @@ loop2:
brk:
qsort(region, nregion, sizeof(region[0]), rcmp);
+ if(debug['R'] && debug['v'])
+ dumpit("pass5", firstr);
+
/*
* pass 6
* determine used registers (paint2)
@@ -633,6 +673,10 @@ brk:
paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
rgp++;
}
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass6", firstr);
+
/*
* pass 7
* peep-hole on basic block
@@ -641,6 +685,9 @@ brk:
peep();
}
+ if(debug['R'] && debug['v'])
+ dumpit("pass7", firstr);
+
/*
* last pass
* eliminate nops
@@ -662,8 +709,8 @@ brk:
while(p->link != P && p->link->as == ANOP)
p->link = p->link->link;
if(p->to.type == D_BRANCH)
- while(p->to.branch != P && p->to.branch->as == ANOP)
- p->to.branch = p->to.branch->link;
+ while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
+ p->to.u.branch = p->to.u.branch->link;
if(p->as == AMOVW && p->to.reg == 13) {
if(p->scond & C_WBIT) {
vreg = -p->to.offset; // in adjust region
@@ -866,6 +913,7 @@ mkvar(Reg *r, Adr *a)
goto onereg;
case D_REGREG:
+ case D_REGREG2:
bit = zbits;
if(a->offset != NREG)
bit.b[0] |= RtoB(a->offset);
@@ -926,6 +974,8 @@ mkvar(Reg *r, Adr *a)
et = a->etype;
o = a->offset;
w = a->width;
+ if(w < 0)
+ fatal("bad width %d for %D", w, a);
for(i=0; i<nvar; i++) {
v = var+i;
@@ -947,8 +997,6 @@ mkvar(Reg *r, Adr *a)
switch(et) {
case 0:
case TFUNC:
- case TARRAY:
- case TSTRING:
goto none;
}
@@ -964,14 +1012,13 @@ mkvar(Reg *r, Adr *a)
v = var+i;
v->offset = o;
v->name = n;
-// v->gotype = a->gotype;
v->etype = et;
v->width = w;
v->addr = flag; // funny punning
v->node = node;
if(debug['R'])
- print("bit=%2d et=%2d w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
+ print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
bit = blsh(i);
if(n == D_EXTERN || n == D_STATIC)
@@ -1033,8 +1080,12 @@ prop(Reg *r, Bits ref, Bits cal)
default:
// Work around for issue 1304:
// flush modified globals before each instruction.
- for(z=0; z<BITS; z++)
+ 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++) {
@@ -1486,11 +1537,12 @@ addreg(Adr *a, int rn)
* 1 R1
* ... ...
* 10 R10
+ * 12 R12
*/
int32
RtoB(int r)
{
- if(r >= REGTMP-2) // excluded R9 and R10 for m and g
+ if(r >= REGTMP-2 && r != 12) // excluded R9 and R10 for m and g, but not R12
return 0;
return 1L << r;
}
@@ -1498,7 +1550,7 @@ RtoB(int r)
int
BtoR(int32 b)
{
- b &= 0x01fcL; // excluded R9 and R10 for m and g
+ b &= 0x11fcL; // excluded R9 and R10 for m and g, but not R12
if(b == 0)
return 0;
return bitno(b);
@@ -1509,7 +1561,7 @@ BtoR(int32 b)
* 18 F2
* 19 F3
* ... ...
- * 23 F7
+ * 31 F15
*/
int32
FtoB(int f)
@@ -1524,7 +1576,7 @@ int
BtoF(int32 b)
{
- b &= 0xfc0000L;
+ b &= 0xfffc0000L;
if(b == 0)
return 0;
return bitno(b) - 16;
@@ -1643,7 +1695,7 @@ chasejmp(Prog *p, int *jmploop)
*jmploop = 1;
break;
}
- p = p->to.branch;
+ p = p->to.u.branch;
}
return p;
}
@@ -1665,8 +1717,8 @@ mark(Prog *firstp)
if(p->regp != dead)
break;
p->regp = alive;
- if(p->as != ABL && p->to.type == D_BRANCH && p->to.branch)
- mark(p->to.branch);
+ if(p->as != ABL && p->to.type == D_BRANCH && p->to.u.branch)
+ mark(p->to.u.branch);
if(p->as == AB || p->as == ARET || (p->as == ABL && noreturn(p)))
break;
}
@@ -1686,8 +1738,8 @@ fixjmp(Prog *firstp)
for(p=firstp; p; p=p->link) {
if(debug['R'] && debug['v'])
print("%P\n", p);
- if(p->as != ABL && p->to.type == D_BRANCH && p->to.branch && p->to.branch->as == AB) {
- p->to.branch = chasejmp(p->to.branch, &jmploop);
+ if(p->as != ABL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AB) {
+ p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
if(debug['R'] && debug['v'])
print("->%P\n", p);
}
@@ -1695,7 +1747,7 @@ fixjmp(Prog *firstp)
}
if(debug['R'] && debug['v'])
print("\n");
-
+
// pass 2: mark all reachable code alive
mark(firstp);
@@ -1723,7 +1775,7 @@ fixjmp(Prog *firstp)
if(!jmploop) {
last = nil;
for(p=firstp; p; p=p->link) {
- if(p->as == AB && p->to.type == D_BRANCH && p->to.branch == p->link) {
+ if(p->as == AB && p->to.type == D_BRANCH && p->to.u.branch == p->link) {
if(debug['R'] && debug['v'])
print("del %P\n", p);
continue;