Commit 0b2353ed authored by Rémy Oudompheng's avatar Rémy Oudompheng

cmd/5g, cmd/6g: fix out of registers with array indexing.

Compiling expressions like:
    s[s[s[s[s[s[s[s[s[s[s[s[i]]]]]]]]]]]]
make 5g and 6g run out of registers. Such expressions can arise
if a slice is used to represent a permutation and the user wants
to iterate it.

This is due to the usual problem of allocating registers before
going down the expression tree, instead of allocating them in a
postfix way.

The functions cgenr and agenr (that generate a value to a newly
allocated register instead of an existing location), are either
introduced or modified when they already existed to allocate
the new register as late as possible, and sudoaddable is disabled
for OINDEX nodes so that igen/agenr is used instead.

Update #4207.

R=dave, daniel.morsing, rsc
CC=golang-dev
https://golang.org/cl/6733055
parent d659633a
...@@ -553,11 +553,9 @@ cgenindex(Node *n, Node *res) ...@@ -553,11 +553,9 @@ cgenindex(Node *n, Node *res)
void void
agen(Node *n, Node *res) agen(Node *n, Node *res)
{ {
Node *nl, *nr; Node *nl;
Node n1, n2, n3, n4, tmp; Node n1, n2, n3;
Prog *p1, *p2; Prog *p1;
uint32 w;
uint64 v;
int r; int r;
if(debug['g']) { if(debug['g']) {
...@@ -597,7 +595,6 @@ agen(Node *n, Node *res) ...@@ -597,7 +595,6 @@ agen(Node *n, Node *res)
} }
nl = n->left; nl = n->left;
nr = n->right;
switch(n->op) { switch(n->op) {
default: default:
...@@ -644,150 +641,9 @@ agen(Node *n, Node *res) ...@@ -644,150 +641,9 @@ agen(Node *n, Node *res)
break; break;
case OINDEX: case OINDEX:
p2 = nil; // to be patched to panicindex. agenr(n, &n1, res);
w = n->type->width; gmove(&n1, res);
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);
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
} else
if(nl->addable) {
if(!isconst(nr, CTINT)) {
tempname(&tmp, types[TINT32]);
p2 = cgenindex(nr, &tmp);
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
if(!isconst(nl, CTSTR)) {
regalloc(&n3, types[tptr], res);
agen(nl, &n3);
}
} else {
tempname(&tmp, types[TINT32]);
p2 = cgenindex(nr, &tmp);
nr = &tmp;
if(!isconst(nl, CTSTR))
agenr(nl, &n3, res);
regalloc(&n1, tmp.type, N);
gins(optoas(OAS, tmp.type), &tmp, &n1);
}
// &a is in &n3 (allocated in res)
// i is in &n1 (if not constant)
// w is width
// 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->bounded) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
n1.xoffset = Array_nel;
regalloc(&n4, n1.type, N);
cgen(&n1, &n4);
nodconst(&n2, types[TUINT32], v);
gcmp(optoas(OCMP, types[TUINT32]), &n4, &n2);
regfree(&n4);
p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
ginscall(panicindex, 0);
patch(p1, pc);
}
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
n1.xoffset = Array_array;
gmove(&n1, &n3);
}
nodconst(&n2, types[tptr], v*w);
gins(optoas(OADD, types[tptr]), &n2, &n3);
gmove(&n3, res);
regfree(&n3);
break;
}
regalloc(&n2, types[TINT32], &n1); // i
gmove(&n1, &n2);
regfree(&n1); regfree(&n1);
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);
} 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);
gmove(&n1, &n4);
}
gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
regfree(&n4);
p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
if(p2)
patch(p2, pc);
ginscall(panicindex, 0);
patch(p1, pc);
}
if(isconst(nl, CTSTR)) {
regalloc(&n3, types[tptr], res);
p1 = gins(AMOVW, N, &n3);
datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
p1->from.type = D_CONST;
} else
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) {
memset(&n4, 0, sizeof n4);
n4.op = OADDR;
n4.left = &n2;
cgen(&n4, &n3);
if (w == 1)
gins(AADD, &n2, &n3);
else if(w == 2)
gshift(AADD, &n2, SHIFT_LL, 1, &n3);
else if(w == 4)
gshift(AADD, &n2, SHIFT_LL, 2, &n3);
else if(w == 8)
gshift(AADD, &n2, SHIFT_LL, 3, &n3);
} else {
regalloc(&n4, types[TUINT32], N);
nodconst(&n1, types[TUINT32], w);
gmove(&n1, &n4);
gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
gins(optoas(OADD, types[tptr]), &n2, &n3);
regfree(&n4);
gmove(&n3, res);
}
gmove(&n3, res);
regfree(&n2);
regfree(&n3);
break; break;
case ONAME: case ONAME:
...@@ -968,12 +824,53 @@ igen(Node *n, Node *a, Node *res) ...@@ -968,12 +824,53 @@ igen(Node *n, Node *a, Node *res)
return; return;
} }
regalloc(a, types[tptr], res); agenr(n, a, res);
agen(n, a);
a->op = OINDREG; a->op = OINDREG;
a->type = n->type; 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: * generate:
* newreg = &n; * newreg = &n;
...@@ -983,12 +880,178 @@ igen(Node *n, Node *a, Node *res) ...@@ -983,12 +880,178 @@ igen(Node *n, Node *a, Node *res)
void void
agenr(Node *n, Node *a, Node *res) agenr(Node *n, Node *a, Node *res)
{ {
Node n1; Node *nl, *nr;
Node n1, n2, n3, n4, tmp;
Prog *p1, *p2;
uint32 w;
uint64 v;
igen(n, &n1, res); if(debug['g'])
regalloc(a, types[tptr], N); dump("agenr-n", n);
agen(&n1, a);
regfree(&n1); nl = n->left;
nr = n->right;
switch(n->op) {
case OINDEX:
p2 = nil; // to be patched to panicindex.
w = n->type->width;
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);
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
} else
if(nl->addable) {
if(!isconst(nr, CTINT)) {
tempname(&tmp, types[TINT32]);
p2 = cgenindex(nr, &tmp);
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
if(!isconst(nl, CTSTR)) {
agenr(nl, &n3, res);
}
} else {
tempname(&tmp, types[TINT32]);
p2 = cgenindex(nr, &tmp);
nr = &tmp;
if(!isconst(nl, CTSTR))
agenr(nl, &n3, res);
regalloc(&n1, tmp.type, N);
gins(optoas(OAS, tmp.type), &tmp, &n1);
}
// &a is in &n3 (allocated in 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);
p1 = gins(AMOVW, &n4, &n4);
p1->from.type = D_OREG;
p1->from.offset = 0;
regfree(&n4);
}
// 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->bounded) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
n1.xoffset = Array_nel;
regalloc(&n4, n1.type, N);
gmove(&n1, &n4);
nodconst(&n2, types[TUINT32], v);
gcmp(optoas(OCMP, types[TUINT32]), &n4, &n2);
regfree(&n4);
p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
ginscall(panicindex, 0);
patch(p1, pc);
}
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
n1.xoffset = Array_array;
gmove(&n1, &n3);
}
nodconst(&n2, types[tptr], v*w);
gins(optoas(OADD, types[tptr]), &n2, &n3);
*a = n3;
break;
}
regalloc(&n2, types[TINT32], &n1); // i
gmove(&n1, &n2);
regfree(&n1);
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);
} else if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
n1.xoffset = Array_nel;
gmove(&n1, &n4);
} else {
nodconst(&n1, types[TUINT32], nl->type->bound);
gmove(&n1, &n4);
}
gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
regfree(&n4);
p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
if(p2)
patch(p2, pc);
ginscall(panicindex, 0);
patch(p1, pc);
}
if(isconst(nl, CTSTR)) {
regalloc(&n3, types[tptr], res);
p1 = gins(AMOVW, N, &n3);
datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
p1->from.type = D_CONST;
} else
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) {
memset(&n4, 0, sizeof n4);
n4.op = OADDR;
n4.left = &n2;
cgen(&n4, &n3);
if (w == 1)
gins(AADD, &n2, &n3);
else if(w == 2)
gshift(AADD, &n2, SHIFT_LL, 1, &n3);
else if(w == 4)
gshift(AADD, &n2, SHIFT_LL, 2, &n3);
else if(w == 8)
gshift(AADD, &n2, SHIFT_LL, 3, &n3);
} else {
regalloc(&n4, types[TUINT32], N);
nodconst(&n1, types[TUINT32], w);
gmove(&n1, &n4);
gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
gins(optoas(OADD, types[tptr]), &n2, &n3);
regfree(&n4);
}
*a = n3;
regfree(&n2);
break;
default:
regalloc(a, types[tptr], res);
agen(n, a);
break;
}
} }
void void
...@@ -1403,16 +1466,14 @@ sgen(Node *n, Node *res, int64 w) ...@@ -1403,16 +1466,14 @@ sgen(Node *n, Node *res, int64 w)
if(osrc < odst && odst < osrc+w) if(osrc < odst && odst < osrc+w)
dir = -dir; dir = -dir;
regalloc(&dst, types[tptr], res);
if(n->ullman >= res->ullman) { if(n->ullman >= res->ullman) {
agen(n, &dst); // temporarily use dst agenr(n, &dst, res); // temporarily use dst
regalloc(&src, types[tptr], N); regalloc(&src, types[tptr], N);
gins(AMOVW, &dst, &src); gins(AMOVW, &dst, &src);
agen(res, &dst); agen(res, &dst);
} else { } else {
agen(res, &dst); agenr(res, &dst, res);
regalloc(&src, types[tptr], N); agenr(n, &src, N);
agen(n, &src);
} }
regalloc(&tmp, types[TUINT32], N); regalloc(&tmp, types[TUINT32], N);
......
...@@ -1816,6 +1816,9 @@ sudoaddable(int as, Node *n, Addr *a, int *w) ...@@ -1816,6 +1816,9 @@ sudoaddable(int as, Node *n, Addr *a, int *w)
goto odot; goto odot;
case OINDEX: 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) if(n->left->type->etype == TSTRING)
return 0; return 0;
cleani += 2; cleani += 2;
......
...@@ -512,102 +512,79 @@ ret: ...@@ -512,102 +512,79 @@ ret:
} }
/* /*
* generate: * allocate a register in res and generate
* res = &n; * newreg = &n
* The caller must call regfree(a).
*/ */
void void
agen(Node *n, Node *res) cgenr(Node *n, Node *a, Node *res)
{ {
Node *nl, *nr; Node n1;
Node n1, n2, n3, tmp, tmp2, n4, n5, nlen;
Prog *p1;
uint32 w;
uint64 v;
Type *t;
if(debug['g']) { if(debug['g'])
dump("\nagen-res", res); dump("cgenr-n", n);
dump("agen-r", n);
}
if(n == N || n->type == T)
return;
while(n->op == OCONVNOP) if(isfat(n->type))
n = n->left; fatal("cgenr on fat node");
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) { if(n->addable) {
regalloc(&n1, types[tptr], res); regalloc(a, types[tptr], res);
gins(ALEAQ, n, &n1); gmove(n, a);
gmove(&n1, res); return;
regfree(&n1);
goto ret;
} }
nl = n->left;
nr = n->right;
switch(n->op) { switch(n->op) {
default: case ONAME:
fatal("agen: unknown op %N", n); case ODOT:
break; case ODOTPTR:
case OINDEX:
case OCALLFUNC:
case OCALLMETH: case OCALLMETH:
cgen_callmeth(n, 0);
cgen_aret(n, res);
break;
case OCALLINTER: case OCALLINTER:
cgen_callinter(n, res, 0); igen(n, &n1, res);
cgen_aret(n, res); regalloc(a, types[tptr], &n1);
gmove(&n1, a);
regfree(&n1);
break; break;
default:
case OCALLFUNC: regalloc(a, n->type, res);
cgen_call(n, 0); cgen(n, a);
cgen_aret(n, res);
break; break;
}
}
case OSLICE: /*
case OSLICEARR: * allocate a register in res and generate
case OSLICESTR: * res = &n
tempname(&n1, n->type); */
cgen_slice(n, &n1); void
agen(&n1, res); agenr(Node *n, Node *a, Node *res)
break; {
Node *nl, *nr;
Node n1, n2, n3, n4, n5, tmp, tmp2, nlen;
Prog *p1;
Type *t;
uint32 w;
uint64 v;
case OEFACE: if(debug['g']) {
tempname(&n1, n->type); dump("\nagenr-n", n);
cgen_eface(n, &n1); }
agen(&n1, res);
break;
nl = n->left;
nr = n->right;
switch(n->op) {
case OINDEX: case OINDEX:
w = n->type->width; w = n->type->width;
// Generate the non-addressable child first. // Generate the non-addressable child first.
if(nr->addable) if(nr->addable)
goto irad; goto irad;
if(nl->addable) { if(nl->addable) {
if(!isconst(nr, CTINT)) { cgenr(nr, &n1, N);
regalloc(&n1, nr->type, N);
cgen(nr, &n1);
}
if(!isconst(nl, CTSTR)) { if(!isconst(nl, CTSTR)) {
if(isfixedarray(nl->type)) { if(isfixedarray(nl->type)) {
regalloc(&n3, types[tptr], res); agenr(nl, &n3, res);
agen(nl, &n3);
} else { } else {
igen(nl, &nlen, res); igen(nl, &nlen, res);
nlen.type = types[tptr]; nlen.type = types[tptr];
...@@ -626,8 +603,7 @@ agen(Node *n, Node *res) ...@@ -626,8 +603,7 @@ agen(Node *n, Node *res)
irad: irad:
if(!isconst(nl, CTSTR)) { if(!isconst(nl, CTSTR)) {
if(isfixedarray(nl->type)) { if(isfixedarray(nl->type)) {
regalloc(&n3, types[tptr], res); agenr(nl, &n3, res);
agen(nl, &n3);
} else { } else {
if(!nl->addable) { if(!nl->addable) {
// igen will need an addressable node. // igen will need an addressable node.
...@@ -645,8 +621,7 @@ agen(Node *n, Node *res) ...@@ -645,8 +621,7 @@ agen(Node *n, Node *res)
} }
} }
if(!isconst(nr, CTINT)) { if(!isconst(nr, CTINT)) {
regalloc(&n1, nr->type, N); cgenr(nr, &n1, N);
cgen(nr, &n1);
} }
goto index; goto index;
...@@ -686,8 +661,7 @@ agen(Node *n, Node *res) ...@@ -686,8 +661,7 @@ agen(Node *n, Node *res)
if (v*w != 0) if (v*w != 0)
ginscon(optoas(OADD, types[tptr]), v*w, &n3); ginscon(optoas(OADD, types[tptr]), v*w, &n3);
gmove(&n3, res); *a = n3;
regfree(&n3);
break; break;
} }
...@@ -745,13 +719,105 @@ agen(Node *n, Node *res) ...@@ -745,13 +719,105 @@ agen(Node *n, Node *res)
} }
indexdone: indexdone:
gmove(&n3, res); *a = n3;
regfree(&n2); regfree(&n2);
regfree(&n3);
if(!isconst(nl, CTSTR) && !isfixedarray(nl->type)) if(!isconst(nl, CTSTR) && !isfixedarray(nl->type))
regfree(&nlen); regfree(&nlen);
break; 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 %N", 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: case ONAME:
// should only get here with names in this func. // should only get here with names in this func.
if(n->funcdepth > 0 && n->funcdepth != funcdepth) { if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
...@@ -843,19 +909,7 @@ igen(Node *n, Node *a, Node *res) ...@@ -843,19 +909,7 @@ igen(Node *n, Node *a, Node *res)
return; return;
case ODOTPTR: case ODOTPTR:
if(n->left->addable cgenr(n->left, a, res);
|| 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) { if(n->xoffset != 0) {
// explicit check for nil if struct is large enough // explicit check for nil if struct is large enough
// that we might derive too big a pointer. // that we might derive too big a pointer.
...@@ -921,8 +975,7 @@ igen(Node *n, Node *a, Node *res) ...@@ -921,8 +975,7 @@ igen(Node *n, Node *a, Node *res)
} }
} }
regalloc(a, types[tptr], res); agenr(n, a, res);
agen(n, a);
a->op = OINDREG; a->op = OINDREG;
a->type = n->type; a->type = n->type;
} }
......
...@@ -84,6 +84,7 @@ int gen_as_init(Node*); ...@@ -84,6 +84,7 @@ int gen_as_init(Node*);
* cgen.c * cgen.c
*/ */
void agen(Node*, Node*); void agen(Node*, Node*);
void agenr(Node*, Node*, Node*);
void igen(Node*, Node*, Node*); void igen(Node*, Node*, Node*);
vlong fieldoffset(Type*, Node*); vlong fieldoffset(Type*, Node*);
void sgen(Node*, Node*, int64); void sgen(Node*, Node*, int64);
......
...@@ -1960,6 +1960,9 @@ sudoaddable(int as, Node *n, Addr *a) ...@@ -1960,6 +1960,9 @@ sudoaddable(int as, Node *n, Addr *a)
goto odot; goto odot;
case OINDEX: 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) if(n->left->type->etype == TSTRING)
return 0; return 0;
goto oindex; goto oindex;
...@@ -2103,23 +2106,11 @@ oindex: ...@@ -2103,23 +2106,11 @@ oindex:
n2 = *l; n2 = *l;
n2.xoffset += Array_nel; n2.xoffset += Array_nel;
n2.type = types[simtype[TUINT]]; n2.type = types[simtype[TUINT]];
if(is64(r->type)) {
t = types[TUINT64];
regalloc(&n4, t, N);
gmove(&n2, &n4);
n2 = n4;
}
} else { } else {
n2 = *reg; n2 = *reg;
n2.xoffset = Array_nel; n2.xoffset = Array_nel;
n2.op = OINDREG; n2.op = OINDREG;
n2.type = types[simtype[TUINT]]; n2.type = types[simtype[TUINT]];
if(is64(r->type)) {
t = types[TUINT64];
regalloc(&n4, t, N);
gmove(&n2, &n4);
n2 = n4;
}
} }
} else { } else {
if(is64(r->type)) if(is64(r->type))
......
...@@ -1426,6 +1426,7 @@ nodedump(Fmt *fp, Node *n) ...@@ -1426,6 +1426,7 @@ nodedump(Fmt *fp, Node *n)
fmtprint(fp, "%O%J", n->op, n); fmtprint(fp, "%O%J", n->op, n);
break; break;
case OREGISTER: case OREGISTER:
case OINDREG:
fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n); fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n);
break; break;
case OLITERAL: case OLITERAL:
......
...@@ -116,6 +116,23 @@ func determinantByte(m [4][4]byte) byte { ...@@ -116,6 +116,23 @@ func determinantByte(m [4][4]byte) byte {
m[0][3]*m[1][2]*m[2][1]*m[3][0] m[0][3]*m[1][2]*m[2][1]*m[3][0]
} }
type A []A
// A sequence of constant indexings.
func IndexChain1(s A) A {
return s[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]
}
// A sequence of non-constant indexings.
func IndexChain2(s A, i int) A {
return s[i][i][i][i][i][i][i][i][i][i][i][i][i][i][i][i]
}
// Another sequence of indexings.
func IndexChain3(s []int) int {
return s[s[s[s[s[s[s[s[s[s[s[s[s[s[s[s[s[s[s[s[s[0]]]]]]]]]]]]]]]]]]]]]
}
// A right-leaning tree of byte multiplications. // A right-leaning tree of byte multiplications.
func righttree(a, b, c, d uint8) uint8 { func righttree(a, b, c, d uint8) uint8 {
return a * (b * (c * (d * return a * (b * (c * (d *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment