summaryrefslogtreecommitdiff
path: root/src/cmd/6g/cgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/6g/cgen.c')
-rw-r--r--src/cmd/6g/cgen.c746
1 files changed, 550 insertions, 196 deletions
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index 00334e71b..a51c0ca58 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -33,9 +33,26 @@ cgen(Node *n, Node *res)
while(n->op == OCONVNOP)
n = n->left;
- // inline slices
- if(cgen_inline(n, res))
+ 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);
goto ret;
+ case OEFACE:
+ if (res->op != ONAME || !res->addable) {
+ tempname(&n1, n->type);
+ cgen_eface(n, &n1);
+ cgen(&n1, res);
+ } else
+ cgen_eface(n, res);
+ goto ret;
+ }
if(n->ullman >= UINF) {
if(n->op == OINDREG)
@@ -174,7 +191,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;
// these call bgen to get a bool value
@@ -187,12 +204,12 @@ cgen(Node *n, Node *res)
case OGE:
case OGT:
case ONOT:
- p1 = gbranch(AJMP, T);
+ p1 = gbranch(AJMP, T, 0);
p2 = pc;
gmove(nodbool(1), res);
- p3 = gbranch(AJMP, T);
+ p3 = gbranch(AJMP, T, 0);
patch(p1, pc);
- bgen(n, 1, p2);
+ bgen(n, 1, 0, p2);
gmove(nodbool(0), res);
patch(p3, pc);
goto ret;
@@ -229,17 +246,41 @@ cgen(Node *n, Node *res)
case OADD:
case OMUL:
a = optoas(n->op, nl->type);
- if(a != AIMULB)
- goto sbop;
- cgen_bmul(n->op, nl, nr, res);
- break;
+ if(a == AIMULB) {
+ cgen_bmul(n->op, nl, nr, res);
+ break;
+ }
+ goto sbop;
// asymmetric binary
case OSUB:
a = optoas(n->op, nl->type);
goto abop;
+ case OHMUL:
+ cgen_hmul(nl, nr, res);
+ break;
+
case OCONV:
+ if(n->type->width > nl->type->width) {
+ // If loading from memory, do conversion during load,
+ // so as to avoid use of 8-bit register in, say, int(*byteptr).
+ switch(nl->op) {
+ case ODOT:
+ case ODOTPTR:
+ case OINDEX:
+ case OIND:
+ case ONAME:
+ igen(nl, &n1, res);
+ regalloc(&n2, n->type, res);
+ gmove(&n1, &n2);
+ gmove(&n2, res);
+ regfree(&n2);
+ regfree(&n1);
+ goto ret;
+ }
+ }
+
regalloc(&n1, nl->type, res);
regalloc(&n2, n->type, &n1);
cgen(nl, &n1);
@@ -273,18 +314,18 @@ cgen(Node *n, Node *res)
case OLEN:
if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
- // map and chan have len in the first 32-bit word.
+ // map and chan have len in the first int-sized word.
// a zero pointer means zero length
regalloc(&n1, types[tptr], res);
cgen(nl, &n1);
nodconst(&n2, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T, 0);
n2 = n1;
n2.op = OINDREG;
- n2.type = types[TINT32];
+ n2.type = types[simtype[TINT]];
gmove(&n2, &n1);
patch(p1, pc);
@@ -297,7 +338,7 @@ cgen(Node *n, Node *res)
// both slice and string have len one pointer into the struct.
// a zero pointer means zero length
igen(nl, &n1, res);
- n1.type = types[TUINT32];
+ n1.type = types[simtype[TUINT]];
n1.xoffset += Array_nel;
gmove(&n1, res);
regfree(&n1);
@@ -308,19 +349,19 @@ cgen(Node *n, Node *res)
case OCAP:
if(istype(nl->type, TCHAN)) {
- // chan has cap in the second 32-bit word.
+ // chan has cap in the second int-sized word.
// a zero pointer means zero length
regalloc(&n1, types[tptr], res);
cgen(nl, &n1);
nodconst(&n2, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T, 0);
n2 = n1;
n2.op = OINDREG;
- n2.xoffset = 4;
- n2.type = types[TINT32];
+ n2.xoffset = widthint;
+ n2.type = types[simtype[TINT]];
gmove(&n2, &n1);
patch(p1, pc);
@@ -331,7 +372,7 @@ cgen(Node *n, Node *res)
}
if(isslice(nl->type)) {
igen(nl, &n1, res);
- n1.type = types[TUINT32];
+ n1.type = types[simtype[TUINT]];
n1.xoffset += Array_cap;
gmove(&n1, res);
regfree(&n1);
@@ -365,18 +406,53 @@ cgen(Node *n, Node *res)
a = optoas(n->op, nl->type);
goto abop;
}
- cgen_div(n->op, nl, nr, res);
+
+ if(nl->ullman >= nr->ullman) {
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ cgen_div(n->op, &n1, nr, res);
+ regfree(&n1);
+ } else {
+ if(!smallintconst(nr)) {
+ regalloc(&n2, nr->type, res);
+ cgen(nr, &n2);
+ } else {
+ n2 = *nr;
+ }
+ cgen_div(n->op, nl, &n2, res);
+ if(n2.op != OLITERAL)
+ regfree(&n2);
+ }
break;
case OLSH:
case ORSH:
- cgen_shift(n->op, nl, nr, res);
+ case OLROT:
+ cgen_shift(n->op, n->bounded, nl, nr, res);
break;
}
goto ret;
sbop: // symmetric binary
- if(nl->ullman < nr->ullman) {
+ /*
+ * put simplest on right - we'll generate into left
+ * and then adjust it using the computation of right.
+ * constants and variables have the same ullman
+ * count, so look for constants specially.
+ *
+ * an integer constant we can use as an immediate
+ * is simpler than a variable - we can use the immediate
+ * in the adjustment instruction directly - so it goes
+ * on the right.
+ *
+ * other constants, like big integers or floating point
+ * constants, require a mov into a register, so those
+ * might as well go on the left, so we can reuse that
+ * register for the computation.
+ */
+ if(nl->ullman < nr->ullman ||
+ (nl->ullman == nr->ullman &&
+ (smallintconst(nl) || (nr->op == OLITERAL && !smallintconst(nr))))) {
r = nl;
nl = nr;
nr = r;
@@ -386,7 +462,13 @@ abop: // asymmetric binary
if(nl->ullman >= nr->ullman) {
regalloc(&n1, nl->type, res);
cgen(nl, &n1);
-
+ /*
+ * This generates smaller code - it avoids a MOV - but it's
+ * easily 10% slower due to not being able to
+ * optimize/manipulate the move.
+ * To see, run: go test -bench . crypto/md5
+ * with and without.
+ *
if(sudoaddable(a, nr, &addr)) {
p1 = gins(a, N, &n1);
p1->from = addr;
@@ -395,18 +477,30 @@ abop: // asymmetric binary
regfree(&n1);
goto ret;
}
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
+ *
+ */
+
+ if(smallintconst(nr))
+ n2 = *nr;
+ else {
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ }
} else {
- regalloc(&n2, nr->type, res);
- cgen(nr, &n2);
+ if(smallintconst(nr))
+ n2 = *nr;
+ else {
+ 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;
uop: // unary
@@ -422,93 +516,142 @@ ret:
}
/*
- * generate:
- * res = &n;
+ * allocate a register in res and generate
+ * newreg = &n
+ * The caller must call regfree(a).
*/
void
-agen(Node *n, Node *res)
+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, n->type, 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;
+ }
+}
+
+/*
+ * allocate a register in res and generate
+ * res = &n
+ */
+void
+agenr(Node *n, Node *a, Node *res)
{
Node *nl, *nr;
- Node n1, n2, n3, tmp, n4, n5;
+ Node n1, n2, n3, n4, n5, tmp, tmp2, nlen;
Prog *p1;
+ Type *t;
uint32 w;
uint64 v;
- Type *t;
+ int freelen;
if(debug['g']) {
- dump("\nagen-res", res);
- dump("agen-r", n);
- }
- if(n == N || n->type == T)
- return;
-
- while(n->op == OCONVNOP)
- n = n->left;
-
- if(n->addable) {
- regalloc(&n1, types[tptr], res);
- gins(ALEAQ, n, &n1);
- gmove(&n1, res);
- regfree(&n1);
- goto ret;
+ dump("\nagenr-n", n);
}
nl = n->left;
nr = n->right;
switch(n->op) {
- default:
- fatal("agen: unknown op %N", n);
- break;
-
+ case ODOT:
+ case ODOTPTR:
+ case OCALLFUNC:
case OCALLMETH:
- cgen_callmeth(n, 0);
- cgen_aret(n, res);
- break;
-
case OCALLINTER:
- cgen_callinter(n, res, 0);
- cgen_aret(n, res);
+ igen(n, &n1, res);
+ regalloc(a, types[tptr], &n1);
+ agen(&n1, a);
+ regfree(&n1);
break;
- case OCALLFUNC:
- cgen_call(n, 0);
- cgen_aret(n, res);
+ case OIND:
+ cgenr(n->left, a, res);
break;
case OINDEX:
+ freelen = 0;
w = n->type->width;
+ // Generate the non-addressable child first.
if(nr->addable)
goto irad;
if(nl->addable) {
- if(!isconst(nr, CTINT)) {
- regalloc(&n1, nr->type, N);
- cgen(nr, &n1);
- }
+ cgenr(nr, &n1, N);
if(!isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
+ if(isfixedarray(nl->type)) {
+ agenr(nl, &n3, res);
+ } else {
+ igen(nl, &nlen, res);
+ freelen = 1;
+ nlen.type = types[tptr];
+ nlen.xoffset += Array_array;
+ regalloc(&n3, types[tptr], res);
+ gmove(&nlen, &n3);
+ nlen.type = types[simtype[TUINT]];
+ nlen.xoffset += Array_nel-Array_array;
+ }
}
goto index;
}
tempname(&tmp, nr->type);
cgen(nr, &tmp);
nr = &tmp;
-
irad:
if(!isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
+ if(isfixedarray(nl->type)) {
+ agenr(nl, &n3, res);
+ } else {
+ if(!nl->addable) {
+ // igen will need an addressable node.
+ tempname(&tmp2, nl->type);
+ cgen(nl, &tmp2);
+ nl = &tmp2;
+ }
+ igen(nl, &nlen, res);
+ freelen = 1;
+ nlen.type = types[tptr];
+ nlen.xoffset += Array_array;
+ regalloc(&n3, types[tptr], res);
+ gmove(&nlen, &n3);
+ nlen.type = types[simtype[TUINT]];
+ nlen.xoffset += Array_nel-Array_array;
+ }
}
if(!isconst(nr, CTINT)) {
- regalloc(&n1, nr->type, N);
- cgen(nr, &n1);
+ cgenr(nr, &n1, N);
}
goto index;
index:
// &a is in &n3 (allocated in res)
// i is in &n1 (if not constant)
+ // len(a) is in nlen (if needed)
// w is width
// explicit check for nil if array is large enough
@@ -529,29 +672,26 @@ agen(Node *n, Node *res)
fatal("constant string constant index"); // front end should handle
v = mpgetfix(nr->val.u.xval);
if(isslice(nl->type) || nl->type->etype == TSTRING) {
- if(!debug['B'] && !n->etype) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- nodconst(&n2, types[TUINT32], v);
- gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
- ginscall(panicindex, 0);
+ if(!debug['B'] && !n->bounded) {
+ nodconst(&n2, types[simtype[TUINT]], v);
+ if(smallintconst(nr)) {
+ gins(optoas(OCMP, types[simtype[TUINT]]), &nlen, &n2);
+ } else {
+ regalloc(&tmp, types[simtype[TUINT]], N);
+ gmove(&n2, &tmp);
+ gins(optoas(OCMP, types[simtype[TUINT]]), &nlen, &tmp);
+ regfree(&tmp);
+ }
+ p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1);
+ ginscall(panicindex, -1);
patch(p1, pc);
}
-
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_array;
- gmove(&n1, &n3);
+ regfree(&nlen);
}
if (v*w != 0)
ginscon(optoas(OADD, types[tptr]), v*w, &n3);
- gmove(&n3, res);
- regfree(&n3);
+ *a = n3;
break;
}
@@ -564,32 +704,32 @@ agen(Node *n, Node *res)
gmove(&n1, &n2);
regfree(&n1);
- if(!debug['B'] && !n->etype) {
+ if(!debug['B'] && !n->bounded) {
// check bounds
- n5.op = OXXX;
- t = types[TUINT32];
+ t = types[simtype[TUINT]];
if(is64(nr->type))
t = types[TUINT64];
if(isconst(nl, CTSTR)) {
- nodconst(&n1, t, nl->val.u.sval->len);
+ nodconst(&nlen, t, nl->val.u.sval->len);
} else if(isslice(nl->type) || nl->type->etype == TSTRING) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[TUINT32];
- n1.xoffset = Array_nel;
if(is64(nr->type)) {
regalloc(&n5, t, N);
- gmove(&n1, &n5);
- n1 = n5;
+ gmove(&nlen, &n5);
+ regfree(&nlen);
+ nlen = n5;
}
} else {
- nodconst(&n1, t, nl->type->bound);
+ nodconst(&nlen, t, nl->type->bound);
+ if(!smallintconst(&nlen)) {
+ regalloc(&n5, t, N);
+ gmove(&nlen, &n5);
+ nlen = n5;
+ freelen = 1;
+ }
}
- gins(optoas(OCMP, t), &n2, &n1);
- p1 = gbranch(optoas(OLT, t), T);
- if(n5.op != OXXX)
- regfree(&n5);
- ginscall(panicindex, 0);
+ gins(optoas(OCMP, t), &n2, &nlen);
+ p1 = gbranch(optoas(OLT, t), T, +1);
+ ginscall(panicindex, -1);
patch(p1, pc);
}
@@ -597,19 +737,15 @@ agen(Node *n, Node *res)
regalloc(&n3, types[tptr], res);
p1 = gins(ALEAQ, N, &n3);
datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
- p1->from.scale = 1;
- p1->from.index = n2.val.u.reg;
+ if(flag_largemodel) {
+ gins(AADDQ, &n2, &n3);
+ } else {
+ p1->from.scale = 1;
+ p1->from.index = n2.val.u.reg;
+ }
goto indexdone;
}
- if(isslice(nl->type) || nl->type->etype == TSTRING) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_array;
- gmove(&n1, &n3);
- }
-
if(w == 0) {
// nothing to do
} else if(w == 1 || w == 2 || w == 4 || w == 8) {
@@ -623,9 +759,103 @@ agen(Node *n, Node *res)
}
indexdone:
- gmove(&n3, res);
+ *a = n3;
regfree(&n2);
- regfree(&n3);
+ if(freelen)
+ regfree(&nlen);
+ break;
+
+ default:
+ regalloc(a, types[tptr], res);
+ agen(n, a);
+ break;
+ }
+}
+
+/*
+ * generate:
+ * res = &n;
+ */
+void
+agen(Node *n, Node *res)
+{
+ Node *nl, *nr;
+ Node n1, n2;
+
+ if(debug['g']) {
+ dump("\nagen-res", res);
+ dump("agen-r", n);
+ }
+ if(n == N || n->type == T)
+ return;
+
+ 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(ALEAQ, &n1, &n2);
+ gmove(&n2, res);
+ regfree(&n2);
+ goto ret;
+ }
+
+ if(n->addable) {
+ regalloc(&n1, types[tptr], res);
+ gins(ALEAQ, n, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ goto ret;
+ }
+
+ nl = n->left;
+ nr = n->right;
+ USED(nr);
+
+ switch(n->op) {
+ default:
+ fatal("agen: unknown op %+hN", n);
+ break;
+
+ case OCALLMETH:
+ cgen_callmeth(n, 0);
+ cgen_aret(n, res);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n, res, 0);
+ cgen_aret(n, res);
+ break;
+
+ case OCALLFUNC:
+ cgen_call(n, 0);
+ 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:
@@ -692,7 +922,11 @@ igen(Node *n, Node *a, Node *res)
{
Type *fp;
Iter flist;
-
+ Node n1;
+
+ if(debug['g']) {
+ dump("\nigen-n", n);
+ }
switch(n->op) {
case ONAME:
if((n->class&PHEAP) || n->class == PPARAMREF)
@@ -700,9 +934,53 @@ igen(Node *n, Node *a, Node *res)
*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 != D_SP)
+ 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:
+ cgenr(n->left, a, res);
+ 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) {
+ n1 = *a;
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n1);
+ }
+ }
+ a->op = OINDREG;
+ a->xoffset += n->xoffset;
+ a->type = n->type;
+ return;
+
case OCALLFUNC:
+ case OCALLMETH:
+ case OCALLINTER:
+ switch(n->op) {
+ case OCALLFUNC:
+ cgen_call(n, 0);
+ break;
+ case OCALLMETH:
+ cgen_callmeth(n, 0);
+ break;
+ case OCALLINTER:
+ cgen_callinter(n, N, 0);
+ break;
+ }
fp = structfirst(&flist, getoutarg(n->left->type));
- cgen_call(n, 0);
memset(a, 0, sizeof *a);
a->op = OINDREG;
a->val.u.reg = D_SP;
@@ -710,10 +988,34 @@ igen(Node *n, Node *a, Node *res)
a->xoffset = fp->width;
a->type = n->type;
return;
+
+ case OINDEX:
+ // Index of fixed-size array by constant can
+ // put the offset in the addressing.
+ // Could do the same for slice except that we need
+ // to use the real index for the bounds checking.
+ if(isfixedarray(n->left->type) ||
+ (isptr[n->left->type->etype] && isfixedarray(n->left->left->type)))
+ if(isconst(n->right, CTINT)) {
+ // Compute &a.
+ if(!isptr[n->left->type->etype])
+ igen(n->left, a, res);
+ else {
+ igen(n->left, &n1, res);
+ regalloc(a, types[tptr], res);
+ gmove(&n1, a);
+ regfree(&n1);
+ a->op = OINDREG;
+ }
+
+ // Compute &a[i] as &a + i*width.
+ a->type = n->type;
+ a->xoffset += mpgetfix(n->right->val.u.xval)*n->type->width;
+ return;
+ }
}
-
- regalloc(a, types[tptr], res);
- agen(n, a);
+
+ agenr(n, a, res);
a->op = OINDREG;
a->type = n->type;
}
@@ -723,7 +1025,7 @@ igen(Node *n, Node *a, Node *res)
* 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, *l, *r;
@@ -765,14 +1067,14 @@ bgen(Node *n, int true, Prog *to)
a = AJNE;
if(!true)
a = AJEQ;
- patch(gbranch(a, n->type), to);
+ patch(gbranch(a, n->type, likely), to);
regfree(&n1);
goto ret;
case OLITERAL:
// need to ask if it is bool?
if(!true == !n->val.u.bval)
- patch(gbranch(AJMP, T), to);
+ patch(gbranch(AJMP, T, likely), to);
goto ret;
case ONAME:
@@ -783,7 +1085,7 @@ bgen(Node *n, int true, Prog *to)
a = AJNE;
if(!true)
a = AJEQ;
- patch(gbranch(a, n->type), to);
+ patch(gbranch(a, n->type, likely), to);
goto ret;
case OANDAND:
@@ -791,12 +1093,12 @@ bgen(Node *n, int true, Prog *to)
goto caseor;
caseand:
- p1 = gbranch(AJMP, T);
- p2 = gbranch(AJMP, T);
+ p1 = gbranch(AJMP, T, 0);
+ p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
- bgen(n->left, !true, p2);
- bgen(n->right, !true, p2);
- p1 = gbranch(AJMP, T);
+ bgen(n->left, !true, -likely, p2);
+ bgen(n->right, !true, -likely, p2);
+ p1 = gbranch(AJMP, T, 0);
patch(p1, to);
patch(p2, pc);
goto ret;
@@ -806,8 +1108,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:
@@ -830,7 +1132,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:
@@ -843,14 +1145,14 @@ bgen(Node *n, int true, Prog *to)
if(!true) {
if(isfloat[nr->type->etype]) {
// brcom is not valid on floats when NaN is involved.
- p1 = gbranch(AJMP, T);
- p2 = gbranch(AJMP, T);
+ p1 = gbranch(AJMP, T, 0);
+ p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
ll = n->ninit; // avoid re-genning ninit
n->ninit = nil;
- bgen(n, 1, p2);
+ bgen(n, 1, -likely, p2);
n->ninit = ll;
- patch(gbranch(AJMP, T), to);
+ patch(gbranch(AJMP, T, 0), to);
patch(p2, pc);
goto ret;
}
@@ -865,47 +1167,41 @@ bgen(Node *n, int true, Prog *to)
nl = nr;
nr = r;
}
-
+
if(isslice(nl->type)) {
- // only valid to cmp darray to literal nil
+ // front end should only leave cmp to literal nil
if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
- yyerror("illegal array comparison");
+ yyerror("illegal slice comparison");
break;
}
a = optoas(a, types[tptr]);
- regalloc(&n1, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = Array_array;
- n2.type = types[tptr];
+ igen(nl, &n1, N);
+ n1.xoffset += Array_array;
+ n1.type = types[tptr];
nodconst(&tmp, types[tptr], 0);
- gins(optoas(OCMP, types[tptr]), &n2, &tmp);
- patch(gbranch(a, types[tptr]), to);
+ gins(optoas(OCMP, types[tptr]), &n1, &tmp);
+ patch(gbranch(a, types[tptr], likely), to);
regfree(&n1);
break;
}
if(isinter(nl->type)) {
- // front end shold only leave cmp to literal nil
+ // front end should only leave cmp to literal nil
if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
yyerror("illegal interface comparison");
break;
}
a = optoas(a, types[tptr]);
- regalloc(&n1, types[tptr], N);
- agen(nl, &n1);
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 0;
+ igen(nl, &n1, N);
+ n1.type = types[tptr];
nodconst(&tmp, types[tptr], 0);
- gins(optoas(OCMP, types[tptr]), &n2, &tmp);
- patch(gbranch(a, types[tptr]), to);
+ gins(optoas(OCMP, types[tptr]), &n1, &tmp);
+ patch(gbranch(a, types[tptr], likely), to);
regfree(&n1);
break;
}
if(iscomplex[nl->type->etype]) {
- complexbool(a, nl, nr, true, to);
+ complexbool(a, nl, nr, true, likely, to);
break;
}
@@ -931,7 +1227,7 @@ bgen(Node *n, int true, Prog *to)
if(smallintconst(nr)) {
gins(optoas(OCMP, nr->type), &n1, nr);
- patch(gbranch(optoas(a, nr->type), nr->type), to);
+ patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
regfree(&n1);
break;
}
@@ -953,18 +1249,18 @@ bgen(Node *n, int true, Prog *to)
if(isfloat[nr->type->etype] && (n->op == OEQ || n->op == ONE)) {
if(n->op == OEQ) {
// neither NE nor P
- p1 = gbranch(AJNE, T);
- p2 = gbranch(AJPS, T);
- patch(gbranch(AJMP, T), to);
+ p1 = gbranch(AJNE, T, -likely);
+ p2 = gbranch(AJPS, T, -likely);
+ patch(gbranch(AJMP, T, 0), to);
patch(p1, pc);
patch(p2, pc);
} else {
// either NE or P
- patch(gbranch(AJNE, T), to);
- patch(gbranch(AJPS, T), to);
+ patch(gbranch(AJNE, T, likely), to);
+ patch(gbranch(AJPS, T, likely), to);
}
} else
- patch(gbranch(optoas(a, nr->type), nr->type), to);
+ patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
regfree(&n1);
regfree(&n2);
break;
@@ -1036,8 +1332,8 @@ stkof(Node *n)
void
sgen(Node *n, Node *ns, int64 w)
{
- Node nodl, nodr, oldl, oldr, cx, oldcx, tmp;
- int32 c, q, odst, osrc;
+ Node nodl, nodr, nodsi, noddi, cx, oldcx, tmp;
+ vlong c, q, odst, osrc;
if(debug['g']) {
print("\nsgen w=%lld\n", w);
@@ -1051,9 +1347,9 @@ sgen(Node *n, Node *ns, int64 w)
if(w < 0)
fatal("sgen copy %lld", w);
- if(w == 16)
- if(componentgen(n, ns))
- return;
+ // Avoid taking the address for simple enough types.
+ if(componentgen(n, ns))
+ return;
if(w == 0) {
// evaluate side effects only
@@ -1080,22 +1376,18 @@ sgen(Node *n, Node *ns, int64 w)
}
if(n->ullman >= ns->ullman) {
- savex(D_SI, &nodr, &oldr, N, types[tptr]);
- agen(n, &nodr);
-
- regalloc(&nodr, types[tptr], &nodr); // mark nodr as live
- savex(D_DI, &nodl, &oldl, N, types[tptr]);
- agen(ns, &nodl);
- regfree(&nodr);
+ agenr(n, &nodr, N);
+ agenr(ns, &nodl, N);
} else {
- savex(D_DI, &nodl, &oldl, N, types[tptr]);
- agen(ns, &nodl);
-
- regalloc(&nodl, types[tptr], &nodl); // mark nodl as live
- savex(D_SI, &nodr, &oldr, N, types[tptr]);
- agen(n, &nodr);
- regfree(&nodl);
+ agenr(ns, &nodl, N);
+ agenr(n, &nodr, N);
}
+ nodreg(&noddi, types[tptr], D_DI);
+ nodreg(&nodsi, types[tptr], D_SI);
+ gmove(&nodl, &noddi);
+ gmove(&nodr, &nodsi);
+ regfree(&nodl);
+ regfree(&nodr);
c = w % 8; // bytes
q = w / 8; // quads
@@ -1152,9 +1444,6 @@ sgen(Node *n, Node *ns, int64 w)
}
}
-
- restx(&nodl, &oldl);
- restx(&nodr, &oldr);
restx(&cx, &oldcx);
}
@@ -1175,15 +1464,21 @@ cadable(Node *n)
}
/*
- * copy a structure component by component
+ * copy a composite value by moving its individual components.
+ * Slices, strings and interfaces are supported.
+ * Small structs or arrays with elements of basic type are
+ * also supported.
+ * nr is N when assigning a zero value.
* return 1 if can do, 0 if cant.
- * nr is N for copy zero
*/
int
componentgen(Node *nr, Node *nl)
{
Node nodl, nodr;
+ Type *t;
int freel, freer;
+ vlong fldcount;
+ vlong loffset, roffset;
freel = 0;
freer = 0;
@@ -1193,8 +1488,33 @@ componentgen(Node *nr, Node *nl)
goto no;
case TARRAY:
- if(!isslice(nl->type))
+ t = nl->type;
+
+ // Slices are ok.
+ if(isslice(t))
+ break;
+ // Small arrays are ok.
+ if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
+ break;
+
+ goto no;
+
+ case TSTRUCT:
+ // Small structs with non-fat types are ok.
+ // Zero-sized structs are treated separately elsewhere.
+ fldcount = 0;
+ for(t=nl->type->type; t; t=t->down) {
+ if(isfat(t->type))
+ goto no;
+ if(t->etype != TFIELD)
+ fatal("componentgen: not a TFIELD: %lT", t);
+ fldcount++;
+ }
+ if(fldcount == 0 || fldcount > 3)
goto no;
+
+ break;
+
case TSTRING:
case TINTER:
break;
@@ -1218,9 +1538,23 @@ componentgen(Node *nr, Node *nl)
switch(nl->type->etype) {
case TARRAY:
- if(!isslice(nl->type))
- goto no;
+ // componentgen for arrays.
+ t = nl->type;
+ if(!isslice(t)) {
+ nodl.type = t->type;
+ nodr.type = nodl.type;
+ for(fldcount=0; fldcount < t->bound; fldcount++) {
+ if(nr == N)
+ clearslim(&nodl);
+ else
+ gmove(&nodr, &nodl);
+ nodl.xoffset += t->type->width;
+ nodr.xoffset += t->type->width;
+ }
+ goto yes;
+ }
+ // componentgen for slices.
nodl.xoffset += Array_array;
nodl.type = ptrto(nl->type->type);
@@ -1232,7 +1566,7 @@ componentgen(Node *nr, Node *nl)
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[TUINT32];
+ nodl.type = types[simtype[TUINT]];
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
@@ -1242,7 +1576,7 @@ componentgen(Node *nr, Node *nl)
gmove(&nodr, &nodl);
nodl.xoffset += Array_cap-Array_nel;
- nodl.type = types[TUINT32];
+ nodl.type = types[simtype[TUINT]];
if(nr != N) {
nodr.xoffset += Array_cap-Array_nel;
@@ -1265,7 +1599,7 @@ componentgen(Node *nr, Node *nl)
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[TUINT32];
+ nodl.type = types[simtype[TUINT]];
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
@@ -1300,7 +1634,27 @@ componentgen(Node *nr, Node *nl)
goto yes;
case TSTRUCT:
- goto no;
+ loffset = nodl.xoffset;
+ roffset = nodr.xoffset;
+ // funarg structs may not begin at offset zero.
+ if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
+ loffset -= nl->type->type->width;
+ if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
+ roffset -= nr->type->type->width;
+
+ for(t=nl->type->type; t; t=t->down) {
+ nodl.xoffset = loffset + t->width;
+ nodl.type = t->type;
+
+ if(nr == N)
+ clearslim(&nodl);
+ else {
+ nodr.xoffset = roffset + t->width;
+ nodr.type = nodl.type;
+ gmove(&nodr, &nodl);
+ }
+ }
+ goto yes;
}
no: