Commit d6b29259 authored by Luuk van Dijk's avatar Luuk van Dijk

gc: inline append when len<cap

issue 1604

R=rsc, bradfitz
CC=golang-dev
https://golang.org/cl/4313062
parent b276293a
...@@ -283,11 +283,9 @@ cgen(Node *n, Node *res) ...@@ -283,11 +283,9 @@ cgen(Node *n, Node *res)
if(istype(nl->type, TSTRING) || isslice(nl->type)) { if(istype(nl->type, TSTRING) || isslice(nl->type)) {
// both slice and string have len one pointer into the struct. // both slice and string have len one pointer into the struct.
// a zero pointer means zero length // a zero pointer means zero length
regalloc(&n1, types[tptr], res); igen(nl, &n1, res);
agen(nl, &n1);
n1.op = OINDREG;
n1.type = types[TUINT32]; n1.type = types[TUINT32];
n1.xoffset = Array_nel; n1.xoffset += Array_nel;
gmove(&n1, res); gmove(&n1, res);
regfree(&n1); regfree(&n1);
break; break;
...@@ -319,11 +317,9 @@ cgen(Node *n, Node *res) ...@@ -319,11 +317,9 @@ cgen(Node *n, Node *res)
break; break;
} }
if(isslice(nl->type)) { if(isslice(nl->type)) {
regalloc(&n1, types[tptr], res); igen(nl, &n1, res);
agen(nl, &n1);
n1.op = OINDREG;
n1.type = types[TUINT32]; n1.type = types[TUINT32];
n1.xoffset = Array_cap; n1.xoffset += Array_cap;
gmove(&n1, res); gmove(&n1, res);
regfree(&n1); regfree(&n1);
break; break;
...@@ -542,7 +538,8 @@ agen(Node *n, Node *res) ...@@ -542,7 +538,8 @@ agen(Node *n, Node *res)
gmove(&n1, &n3); gmove(&n1, &n3);
} }
ginscon(optoas(OADD, types[tptr]), v*w, &n3); if (v*w != 0)
ginscon(optoas(OADD, types[tptr]), v*w, &n3);
gmove(&n3, res); gmove(&n3, res);
regfree(&n3); regfree(&n3);
break; break;
...@@ -682,6 +679,28 @@ ret: ...@@ -682,6 +679,28 @@ ret:
void void
igen(Node *n, Node *a, Node *res) igen(Node *n, Node *a, Node *res)
{ {
Type *fp;
Iter flist;
switch(n->op) {
case ONAME:
if((n->class&PHEAP) || n->class == PPARAMREF)
break;
*a = *n;
return;
case OCALLFUNC:
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;
a->addable = 1;
a->xoffset = fp->width;
a->type = n->type;
return;
}
regalloc(a, types[tptr], res); regalloc(a, types[tptr], res);
agen(n, a); agen(n, a);
a->op = OINDREG; a->op = OINDREG;
...@@ -848,6 +867,7 @@ bgen(Node *n, int true, Prog *to) ...@@ -848,6 +867,7 @@ bgen(Node *n, int true, Prog *to)
n2 = n1; n2 = n1;
n2.op = OINDREG; n2.op = OINDREG;
n2.xoffset = Array_array; n2.xoffset = Array_array;
n2.type = types[tptr];
nodconst(&tmp, types[tptr], 0); nodconst(&tmp, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n2, &tmp); gins(optoas(OCMP, types[tptr]), &n2, &tmp);
patch(gbranch(a, types[tptr]), to); patch(gbranch(a, types[tptr]), to);
......
...@@ -201,7 +201,7 @@ cgen_callinter(Node *n, Node *res, int proc) ...@@ -201,7 +201,7 @@ cgen_callinter(Node *n, Node *res, int proc)
regalloc(&nodo, types[tptr], &nodr); regalloc(&nodo, types[tptr], &nodr);
nodo.op = OINDREG; nodo.op = OINDREG;
agen(i, &nodr); // REG = &inter agen(i, &nodr); // REG = &inter
nodindreg(&nodsp, types[tptr], D_SP); nodindreg(&nodsp, types[tptr], D_SP);
nodo.xoffset += widthptr; nodo.xoffset += widthptr;
...@@ -1206,7 +1206,7 @@ cgen_inline(Node *n, Node *res) ...@@ -1206,7 +1206,7 @@ cgen_inline(Node *n, Node *res)
Node nodes[5]; Node nodes[5];
Node n1, n2, nres, ntemp; Node n1, n2, nres, ntemp;
vlong v; vlong v;
int i, narg; int i, narg, nochk;
if(n->op != OCALLFUNC) if(n->op != OCALLFUNC)
goto no; goto no;
...@@ -1242,6 +1242,7 @@ slicearray: ...@@ -1242,6 +1242,7 @@ slicearray:
// len = hb[3] - lb[2] (destroys hb) // len = hb[3] - lb[2] (destroys hb)
n2 = *res; n2 = *res;
n2.xoffset += Array_nel; n2.xoffset += Array_nel;
n2.type = types[TUINT32];
if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) { if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
v = mpgetfix(nodes[3].val.u.xval) - v = mpgetfix(nodes[3].val.u.xval) -
...@@ -1260,6 +1261,7 @@ slicearray: ...@@ -1260,6 +1261,7 @@ slicearray:
// cap = nel[1] - lb[2] (destroys nel) // cap = nel[1] - lb[2] (destroys nel)
n2 = *res; n2 = *res;
n2.xoffset += Array_cap; n2.xoffset += Array_cap;
n2.type = types[TUINT32];
if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) { if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
v = mpgetfix(nodes[1].val.u.xval) - v = mpgetfix(nodes[1].val.u.xval) -
...@@ -1288,6 +1290,7 @@ slicearray: ...@@ -1288,6 +1290,7 @@ slicearray:
// ary = old[0] + (lb[2] * width[4]) (destroys old) // ary = old[0] + (lb[2] * width[4]) (destroys old)
n2 = *res; n2 = *res;
n2.xoffset += Array_array; n2.xoffset += Array_array;
n2.type = types[tptr];
if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) { if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
v = mpgetfix(nodes[2].val.u.xval) * v = mpgetfix(nodes[2].val.u.xval) *
...@@ -1311,6 +1314,7 @@ slicearray: ...@@ -1311,6 +1314,7 @@ slicearray:
return 1; return 1;
sliceslice: sliceslice:
nochk = n->etype; // skip bounds checking
ntemp.op = OXXX; ntemp.op = OXXX;
if(!sleasy(n->list->n->right)) { if(!sleasy(n->list->n->right)) {
Node *n0; Node *n0;
...@@ -1340,11 +1344,13 @@ sliceslice: ...@@ -1340,11 +1344,13 @@ sliceslice:
n2 = nodes[0]; n2 = nodes[0];
n2.xoffset += Array_nel; n2.xoffset += Array_nel;
n2.type = types[TUINT32]; n2.type = types[TUINT32];
cmpandthrow(&nodes[1], &n2); if(!nochk)
cmpandthrow(&nodes[1], &n2);
// ret.nel = old.nel[0]-lb[1]; // ret.nel = old.nel[0]-lb[1];
n2 = nodes[0]; n2 = nodes[0];
n2.xoffset += Array_nel; n2.xoffset += Array_nel;
n2.type = types[TUINT32];
regalloc(&n1, types[TUINT32], N); regalloc(&n1, types[TUINT32], N);
gins(optoas(OAS, types[TUINT32]), &n2, &n1); gins(optoas(OAS, types[TUINT32]), &n2, &n1);
...@@ -1353,22 +1359,24 @@ sliceslice: ...@@ -1353,22 +1359,24 @@ sliceslice:
n2 = nres; n2 = nres;
n2.xoffset += Array_nel; n2.xoffset += Array_nel;
n2.type = types[TUINT32];
gins(optoas(OAS, types[TUINT32]), &n1, &n2); gins(optoas(OAS, types[TUINT32]), &n1, &n2);
regfree(&n1); regfree(&n1);
} else { // old[lb:hb] } else { // old[lb:hb]
// if(hb[2] > old.cap[0]) goto throw;
n2 = nodes[0]; n2 = nodes[0];
n2.xoffset += Array_cap; n2.xoffset += Array_cap;
n2.type = types[TUINT32]; n2.type = types[TUINT32];
cmpandthrow(&nodes[2], &n2); if(!nochk) {
// if(hb[2] > old.cap[0]) goto throw;
// if(lb[1] > hb[2]) goto throw; cmpandthrow(&nodes[2], &n2);
cmpandthrow(&nodes[1], &nodes[2]); // if(lb[1] > hb[2]) goto throw;
cmpandthrow(&nodes[1], &nodes[2]);
}
// ret.len = hb[2]-lb[1]; (destroys hb[2]) // ret.len = hb[2]-lb[1]; (destroys hb[2])
n2 = nres; n2 = nres;
n2.xoffset += Array_nel; n2.xoffset += Array_nel;
n2.type = types[TUINT32];
if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) { if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
v = mpgetfix(nodes[2].val.u.xval) - v = mpgetfix(nodes[2].val.u.xval) -
mpgetfix(nodes[1].val.u.xval); mpgetfix(nodes[1].val.u.xval);
...@@ -1387,6 +1395,7 @@ sliceslice: ...@@ -1387,6 +1395,7 @@ sliceslice:
// ret.cap = old.cap[0]-lb[1]; (uses hb[2]) // ret.cap = old.cap[0]-lb[1]; (uses hb[2])
n2 = nodes[0]; n2 = nodes[0];
n2.xoffset += Array_cap; n2.xoffset += Array_cap;
n2.type = types[TUINT32];
regalloc(&n1, types[TUINT32], &nodes[2]); regalloc(&n1, types[TUINT32], &nodes[2]);
gins(optoas(OAS, types[TUINT32]), &n2, &n1); gins(optoas(OAS, types[TUINT32]), &n2, &n1);
...@@ -1395,13 +1404,15 @@ sliceslice: ...@@ -1395,13 +1404,15 @@ sliceslice:
n2 = nres; n2 = nres;
n2.xoffset += Array_cap; n2.xoffset += Array_cap;
n2.type = types[TUINT32];
gins(optoas(OAS, types[TUINT32]), &n1, &n2); gins(optoas(OAS, types[TUINT32]), &n1, &n2);
regfree(&n1); regfree(&n1);
// ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1]) // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
n2 = nodes[0]; n2 = nodes[0];
n2.xoffset += Array_array; n2.xoffset += Array_array;
n2.type = types[tptr];
regalloc(&n1, types[tptr], &nodes[1]); regalloc(&n1, types[tptr], &nodes[1]);
if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) { if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
gins(optoas(OAS, types[tptr]), &n2, &n1); gins(optoas(OAS, types[tptr]), &n2, &n1);
...@@ -1418,6 +1429,7 @@ sliceslice: ...@@ -1418,6 +1429,7 @@ sliceslice:
n2 = nres; n2 = nres;
n2.xoffset += Array_array; n2.xoffset += Array_array;
n2.type = types[tptr];
gins(optoas(OAS, types[tptr]), &n1, &n2); gins(optoas(OAS, types[tptr]), &n1, &n2);
regfree(&n1); regfree(&n1);
......
...@@ -48,7 +48,7 @@ clearp(Prog *p) ...@@ -48,7 +48,7 @@ clearp(Prog *p)
/* /*
* generate and return proc with p->as = as, * generate and return proc with p->as = as,
* linked into program. pc is next instruction. * linked into program. pc is next instruction.
*/ */
Prog* Prog*
prog(int as) prog(int as)
...@@ -330,11 +330,13 @@ regfree(Node *n) ...@@ -330,11 +330,13 @@ regfree(Node *n)
{ {
int i; int i;
if(n->op == ONAME && iscomplex[n->type->etype]) if(n->op == ONAME)
return; return;
if(n->op != OREGISTER && n->op != OINDREG) if(n->op != OREGISTER && n->op != OINDREG)
fatal("regfree: not a register"); fatal("regfree: not a register");
i = n->val.u.reg; i = n->val.u.reg;
if(i == D_SP)
return;
if(i < 0 || i >= sizeof(reg)) if(i < 0 || i >= sizeof(reg))
fatal("regfree: reg out of range"); fatal("regfree: reg out of range");
if(reg[i] <= 0) if(reg[i] <= 0)
...@@ -888,7 +890,7 @@ Prog* ...@@ -888,7 +890,7 @@ Prog*
gins(int as, Node *f, Node *t) gins(int as, Node *f, Node *t)
{ {
// Node nod; // Node nod;
// int32 v; int32 w;
Prog *p; Prog *p;
Addr af, at; Addr af, at;
...@@ -933,6 +935,27 @@ gins(int as, Node *f, Node *t) ...@@ -933,6 +935,27 @@ gins(int as, Node *f, Node *t)
p->to = at; p->to = at;
if(debug['g']) if(debug['g'])
print("%P\n", p); print("%P\n", p);
w = 0;
switch(as) {
case AMOVB:
w = 1;
break;
case AMOVW:
w = 2;
break;
case AMOVL:
w = 4;
break;
case AMOVQ:
w = 8;
break;
}
if(w != 0 && f != N && (af.width > w || at.width > w)) {
fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
}
return p; return p;
} }
...@@ -947,7 +970,7 @@ checkoffset(Addr *a, int canemitcode) ...@@ -947,7 +970,7 @@ checkoffset(Addr *a, int canemitcode)
fatal("checkoffset %#llx, cannot emit code", a->offset); fatal("checkoffset %#llx, cannot emit code", a->offset);
// cannot rely on unmapped nil page at 0 to catch // cannot rely on unmapped nil page at 0 to catch
// reference with large offset. instead, emit explicit // reference with large offset. instead, emit explicit
// test of 0(reg). // test of 0(reg).
p = gins(ATESTB, nodintconst(0), N); p = gins(ATESTB, nodintconst(0), N);
p->to = *a; p->to = *a;
...@@ -1106,8 +1129,9 @@ naddr(Node *n, Addr *a, int canemitcode) ...@@ -1106,8 +1129,9 @@ naddr(Node *n, Addr *a, int canemitcode)
naddr(n->left, a, canemitcode); naddr(n->left, a, canemitcode);
if(a->type == D_CONST && a->offset == 0) if(a->type == D_CONST && a->offset == 0)
break; // len(nil) break; // len(nil)
a->etype = TUINT; a->etype = TUINT32;
a->offset += Array_nel; a->offset += Array_nel;
a->width = 4;
if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero) if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
checkoffset(a, canemitcode); checkoffset(a, canemitcode);
break; break;
...@@ -1117,8 +1141,9 @@ naddr(Node *n, Addr *a, int canemitcode) ...@@ -1117,8 +1141,9 @@ naddr(Node *n, Addr *a, int canemitcode)
naddr(n->left, a, canemitcode); naddr(n->left, a, canemitcode);
if(a->type == D_CONST && a->offset == 0) if(a->type == D_CONST && a->offset == 0)
break; // cap(nil) break; // cap(nil)
a->etype = TUINT; a->etype = TUINT32;
a->offset += Array_cap; a->offset += Array_cap;
a->width = 4;
if(a->offset >= unmappedzero && a->offset-Array_cap < unmappedzero) if(a->offset >= unmappedzero && a->offset-Array_cap < unmappedzero)
checkoffset(a, canemitcode); checkoffset(a, canemitcode);
break; break;
...@@ -1962,12 +1987,12 @@ oindex: ...@@ -1962,12 +1987,12 @@ oindex:
if(o & OAddable) { if(o & OAddable) {
n2 = *l; n2 = *l;
n2.xoffset += Array_array; n2.xoffset += Array_array;
n2.type = types[TUINT64]; n2.type = types[tptr];
gmove(&n2, reg); gmove(&n2, reg);
} else { } else {
n2 = *reg; n2 = *reg;
n2.xoffset = Array_array;
n2.op = OINDREG; n2.op = OINDREG;
n2.xoffset = Array_array;
n2.type = types[tptr]; n2.type = types[tptr];
gmove(&n2, reg); gmove(&n2, reg);
} }
......
...@@ -873,14 +873,17 @@ mkvar(Reg *r, Adr *a) ...@@ -873,14 +873,17 @@ mkvar(Reg *r, Adr *a)
// if they overlaps, disable both // if they overlaps, disable both
if(overlap(v->offset, v->width, o, w)) { if(overlap(v->offset, v->width, o, w)) {
// print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et);
v->addr = 1; v->addr = 1;
flag = 1; flag = 1;
} }
} }
} }
if(a->pun) if(a->pun) {
// print("disable pun %s\n", s->name);
flag = 1; flag = 1;
}
switch(et) { switch(et) {
case 0: case 0:
case TFUNC: case TFUNC:
......
...@@ -232,6 +232,7 @@ cgen(Node *n, Node *res) ...@@ -232,6 +232,7 @@ cgen(Node *n, Node *res)
cgen(nl, res); cgen(nl, res);
break; break;
} }
tempname(&n2, n->type); tempname(&n2, n->type);
mgen(nl, &n1, res); mgen(nl, &n1, res);
gmove(&n1, &n2); gmove(&n1, &n2);
...@@ -277,15 +278,10 @@ cgen(Node *n, Node *res) ...@@ -277,15 +278,10 @@ cgen(Node *n, Node *res)
if(istype(nl->type, TSTRING) || isslice(nl->type)) { if(istype(nl->type, TSTRING) || isslice(nl->type)) {
// both slice and string have len one pointer into the struct. // both slice and string have len one pointer into the struct.
igen(nl, &n1, res); igen(nl, &n1, res);
n1.op = OREGISTER; // was OINDREG
regalloc(&n2, types[TUINT32], &n1);
n1.op = OINDREG;
n1.type = types[TUINT32]; n1.type = types[TUINT32];
n1.xoffset = Array_nel; n1.xoffset += Array_nel;
gmove(&n1, &n2); gmove(&n1, res);
gmove(&n2, res);
regfree(&n1); regfree(&n1);
regfree(&n2);
break; break;
} }
fatal("cgen: OLEN: unknown type %lT", nl->type); fatal("cgen: OLEN: unknown type %lT", nl->type);
...@@ -594,9 +590,10 @@ agen(Node *n, Node *res) ...@@ -594,9 +590,10 @@ agen(Node *n, Node *res)
gmove(&n1, &n3); gmove(&n1, &n3);
} }
nodconst(&n2, types[tptr], v*w); if (v*w != 0) {
gins(optoas(OADD, types[tptr]), &n2, &n3); nodconst(&n2, types[tptr], v*w);
gins(optoas(OADD, types[tptr]), &n2, &n3);
}
gmove(&n3, res); gmove(&n3, res);
regfree(&n3); regfree(&n3);
break; break;
...@@ -729,7 +726,27 @@ void ...@@ -729,7 +726,27 @@ void
igen(Node *n, Node *a, Node *res) igen(Node *n, Node *a, Node *res)
{ {
Node n1; Node n1;
Type *fp;
Iter flist;
switch(n->op) {
case ONAME:
if((n->class&PHEAP) || n->class == PPARAMREF)
break;
*a = *n;
return;
case OCALLFUNC:
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;
a->addable = 1;
a->xoffset = fp->width;
a->type = n->type;
return;
}
// release register for now, to avoid // release register for now, to avoid
// confusing tempname. // confusing tempname.
if(res != N && res->op == OREGISTER) if(res != N && res->op == OREGISTER)
...@@ -919,6 +936,7 @@ bgen(Node *n, int true, Prog *to) ...@@ -919,6 +936,7 @@ bgen(Node *n, int true, Prog *to)
n2 = n1; n2 = n1;
n2.op = OINDREG; n2.op = OINDREG;
n2.xoffset = Array_array; n2.xoffset = Array_array;
n2.type = types[tptr];
nodconst(&tmp, types[tptr], 0); nodconst(&tmp, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n2, &tmp); gins(optoas(OCMP, types[tptr]), &n2, &tmp);
patch(gbranch(a, types[tptr]), to); patch(gbranch(a, types[tptr]), to);
......
...@@ -915,7 +915,7 @@ cgen_inline(Node *n, Node *res) ...@@ -915,7 +915,7 @@ cgen_inline(Node *n, Node *res)
Node nodes[5]; Node nodes[5];
Node n1, n2, nres, ntemp; Node n1, n2, nres, ntemp;
vlong v; vlong v;
int i, narg; int i, narg, nochk;
if(n->op != OCALLFUNC) if(n->op != OCALLFUNC)
goto no; goto no;
...@@ -953,6 +953,7 @@ slicearray: ...@@ -953,6 +953,7 @@ slicearray:
// len = hb[3] - lb[2] (destroys hb) // len = hb[3] - lb[2] (destroys hb)
n2 = *res; n2 = *res;
n2.xoffset += Array_nel; n2.xoffset += Array_nel;
n2.type = types[TUINT32];
if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) { if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
v = mpgetfix(nodes[3].val.u.xval) - v = mpgetfix(nodes[3].val.u.xval) -
...@@ -971,6 +972,7 @@ slicearray: ...@@ -971,6 +972,7 @@ slicearray:
// cap = nel[1] - lb[2] (destroys nel) // cap = nel[1] - lb[2] (destroys nel)
n2 = *res; n2 = *res;
n2.xoffset += Array_cap; n2.xoffset += Array_cap;
n2.type = types[TUINT32];
if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) { if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
v = mpgetfix(nodes[1].val.u.xval) - v = mpgetfix(nodes[1].val.u.xval) -
...@@ -999,6 +1001,7 @@ slicearray: ...@@ -999,6 +1001,7 @@ slicearray:
// ary = old[0] + (lb[2] * width[4]) (destroys old) // ary = old[0] + (lb[2] * width[4]) (destroys old)
n2 = *res; n2 = *res;
n2.xoffset += Array_array; n2.xoffset += Array_array;
n2.type = types[tptr];
if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) { if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
v = mpgetfix(nodes[2].val.u.xval) * v = mpgetfix(nodes[2].val.u.xval) *
...@@ -1026,6 +1029,7 @@ slicearray: ...@@ -1026,6 +1029,7 @@ slicearray:
sliceslice: sliceslice:
if(!fix64(n->list, narg)) if(!fix64(n->list, narg))
goto no; goto no;
nochk = n->etype; // skip bounds checking
ntemp.op = OXXX; ntemp.op = OXXX;
if(!sleasy(n->list->n->right)) { if(!sleasy(n->list->n->right)) {
Node *n0; Node *n0;
...@@ -1055,11 +1059,13 @@ sliceslice: ...@@ -1055,11 +1059,13 @@ sliceslice:
n2 = nodes[0]; n2 = nodes[0];
n2.xoffset += Array_nel; n2.xoffset += Array_nel;
n2.type = types[TUINT32]; n2.type = types[TUINT32];
cmpandthrow(&nodes[1], &n2); if(!nochk)
cmpandthrow(&nodes[1], &n2);
// ret.nel = old.nel[0]-lb[1]; // ret.nel = old.nel[0]-lb[1];
n2 = nodes[0]; n2 = nodes[0];
n2.xoffset += Array_nel; n2.xoffset += Array_nel;
n2.type = types[TUINT32];
regalloc(&n1, types[TUINT32], N); regalloc(&n1, types[TUINT32], N);
gins(optoas(OAS, types[TUINT32]), &n2, &n1); gins(optoas(OAS, types[TUINT32]), &n2, &n1);
...@@ -1068,22 +1074,25 @@ sliceslice: ...@@ -1068,22 +1074,25 @@ sliceslice:
n2 = nres; n2 = nres;
n2.xoffset += Array_nel; n2.xoffset += Array_nel;
n2.type = types[TUINT32];
gins(optoas(OAS, types[TUINT32]), &n1, &n2); gins(optoas(OAS, types[TUINT32]), &n1, &n2);
regfree(&n1); regfree(&n1);
} else { // old[lb:hb] } else { // old[lb:hb]
// if(hb[2] > old.cap[0]) goto throw;
n2 = nodes[0]; n2 = nodes[0];
n2.xoffset += Array_cap; n2.xoffset += Array_cap;
n2.type = types[TUINT32]; n2.type = types[TUINT32];
cmpandthrow(&nodes[2], &n2); if (!nochk) {
// if(hb[2] > old.cap[0]) goto throw;
// if(lb[1] > hb[2]) goto throw; cmpandthrow(&nodes[2], &n2);
cmpandthrow(&nodes[1], &nodes[2]); // if(lb[1] > hb[2]) goto throw;
cmpandthrow(&nodes[1], &nodes[2]);
}
// ret.len = hb[2]-lb[1]; (destroys hb[2]) // ret.len = hb[2]-lb[1]; (destroys hb[2])
n2 = nres; n2 = nres;
n2.xoffset += Array_nel; n2.xoffset += Array_nel;
n2.type = types[TUINT32];
if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) { if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
v = mpgetfix(nodes[2].val.u.xval) - v = mpgetfix(nodes[2].val.u.xval) -
mpgetfix(nodes[1].val.u.xval); mpgetfix(nodes[1].val.u.xval);
...@@ -1102,6 +1111,7 @@ sliceslice: ...@@ -1102,6 +1111,7 @@ sliceslice:
// ret.cap = old.cap[0]-lb[1]; (uses hb[2]) // ret.cap = old.cap[0]-lb[1]; (uses hb[2])
n2 = nodes[0]; n2 = nodes[0];
n2.xoffset += Array_cap; n2.xoffset += Array_cap;
n2.type = types[TUINT32];
regalloc(&n1, types[TUINT32], &nodes[2]); regalloc(&n1, types[TUINT32], &nodes[2]);
gins(optoas(OAS, types[TUINT32]), &n2, &n1); gins(optoas(OAS, types[TUINT32]), &n2, &n1);
...@@ -1110,12 +1120,14 @@ sliceslice: ...@@ -1110,12 +1120,14 @@ sliceslice:
n2 = nres; n2 = nres;
n2.xoffset += Array_cap; n2.xoffset += Array_cap;
n2.type = types[TUINT32];
gins(optoas(OAS, types[TUINT32]), &n1, &n2); gins(optoas(OAS, types[TUINT32]), &n1, &n2);
regfree(&n1); regfree(&n1);
// ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1]) // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
n2 = nodes[0]; n2 = nodes[0];
n2.xoffset += Array_array; n2.xoffset += Array_array;
n2.type = types[tptr];
regalloc(&n1, types[tptr], &nodes[1]); regalloc(&n1, types[tptr], &nodes[1]);
if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) { if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
...@@ -1135,6 +1147,7 @@ sliceslice: ...@@ -1135,6 +1147,7 @@ sliceslice:
n2 = nres; n2 = nres;
n2.xoffset += Array_array; n2.xoffset += Array_array;
n2.type = types[tptr];
gins(optoas(OAS, types[tptr]), &n1, &n2); gins(optoas(OAS, types[tptr]), &n1, &n2);
regfree(&n1); regfree(&n1);
......
...@@ -698,7 +698,6 @@ ginit(void) ...@@ -698,7 +698,6 @@ ginit(void)
reg[i] = 1; reg[i] = 1;
for(i=D_AL; i<=D_DI; i++) for(i=D_AL; i<=D_DI; i++)
reg[i] = 0; reg[i] = 0;
for(i=0; i<nelem(resvd); i++) for(i=0; i<nelem(resvd); i++)
reg[resvd[i]]++; reg[resvd[i]]++;
} }
...@@ -789,6 +788,8 @@ err: ...@@ -789,6 +788,8 @@ err:
return; return;
out: out:
if (i == D_SP)
print("alloc SP\n");
if(reg[i] == 0) { if(reg[i] == 0) {
regpc[i] = (ulong)__builtin_return_address(0); regpc[i] = (ulong)__builtin_return_address(0);
if(i == D_AX || i == D_CX || i == D_DX || i == D_SP) { if(i == D_AX || i == D_CX || i == D_DX || i == D_SP) {
...@@ -804,10 +805,14 @@ void ...@@ -804,10 +805,14 @@ void
regfree(Node *n) regfree(Node *n)
{ {
int i; int i;
if(n->op == ONAME)
return;
if(n->op != OREGISTER && n->op != OINDREG) if(n->op != OREGISTER && n->op != OINDREG)
fatal("regfree: not a register"); fatal("regfree: not a register");
i = n->val.u.reg; i = n->val.u.reg;
if(i == D_SP)
return;
if(i < 0 || i >= sizeof(reg)) if(i < 0 || i >= sizeof(reg))
fatal("regfree: reg out of range"); fatal("regfree: reg out of range");
if(reg[i] <= 0) if(reg[i] <= 0)
...@@ -1129,6 +1134,9 @@ gmove(Node *f, Node *t) ...@@ -1129,6 +1134,9 @@ gmove(Node *f, Node *t)
case CASE(TINT8, TUINT8): case CASE(TINT8, TUINT8):
case CASE(TUINT8, TINT8): case CASE(TUINT8, TINT8):
case CASE(TUINT8, TUINT8): case CASE(TUINT8, TUINT8):
a = AMOVB;
break;
case CASE(TINT16, TINT8): // truncate case CASE(TINT16, TINT8): // truncate
case CASE(TUINT16, TINT8): case CASE(TUINT16, TINT8):
case CASE(TINT32, TINT8): case CASE(TINT32, TINT8):
...@@ -1138,7 +1146,7 @@ gmove(Node *f, Node *t) ...@@ -1138,7 +1146,7 @@ gmove(Node *f, Node *t)
case CASE(TINT32, TUINT8): case CASE(TINT32, TUINT8):
case CASE(TUINT32, TUINT8): case CASE(TUINT32, TUINT8):
a = AMOVB; a = AMOVB;
break; goto rsrc;
case CASE(TINT64, TINT8): // truncate low word case CASE(TINT64, TINT8): // truncate low word
case CASE(TUINT64, TINT8): case CASE(TUINT64, TINT8):
...@@ -1146,7 +1154,7 @@ gmove(Node *f, Node *t) ...@@ -1146,7 +1154,7 @@ gmove(Node *f, Node *t)
case CASE(TUINT64, TUINT8): case CASE(TUINT64, TUINT8):
split64(f, &flo, &fhi); split64(f, &flo, &fhi);
nodreg(&r1, t->type, D_AX); nodreg(&r1, t->type, D_AX);
gins(AMOVB, &flo, &r1); gmove(&flo, &r1);
gins(AMOVB, &r1, t); gins(AMOVB, &r1, t);
splitclean(); splitclean();
return; return;
...@@ -1155,12 +1163,15 @@ gmove(Node *f, Node *t) ...@@ -1155,12 +1163,15 @@ gmove(Node *f, Node *t)
case CASE(TINT16, TUINT16): case CASE(TINT16, TUINT16):
case CASE(TUINT16, TINT16): case CASE(TUINT16, TINT16):
case CASE(TUINT16, TUINT16): case CASE(TUINT16, TUINT16):
a = AMOVW;
break;
case CASE(TINT32, TINT16): // truncate case CASE(TINT32, TINT16): // truncate
case CASE(TUINT32, TINT16): case CASE(TUINT32, TINT16):
case CASE(TINT32, TUINT16): case CASE(TINT32, TUINT16):
case CASE(TUINT32, TUINT16): case CASE(TUINT32, TUINT16):
a = AMOVW; a = AMOVW;
break; goto rsrc;
case CASE(TINT64, TINT16): // truncate low word case CASE(TINT64, TINT16): // truncate low word
case CASE(TUINT64, TINT16): case CASE(TUINT64, TINT16):
...@@ -1168,7 +1179,7 @@ gmove(Node *f, Node *t) ...@@ -1168,7 +1179,7 @@ gmove(Node *f, Node *t)
case CASE(TUINT64, TUINT16): case CASE(TUINT64, TUINT16):
split64(f, &flo, &fhi); split64(f, &flo, &fhi);
nodreg(&r1, t->type, D_AX); nodreg(&r1, t->type, D_AX);
gins(AMOVW, &flo, &r1); gmove(&flo, &r1);
gins(AMOVW, &r1, t); gins(AMOVW, &r1, t);
splitclean(); splitclean();
return; return;
...@@ -1186,7 +1197,7 @@ gmove(Node *f, Node *t) ...@@ -1186,7 +1197,7 @@ gmove(Node *f, Node *t)
case CASE(TUINT64, TUINT32): case CASE(TUINT64, TUINT32):
split64(f, &flo, &fhi); split64(f, &flo, &fhi);
nodreg(&r1, t->type, D_AX); nodreg(&r1, t->type, D_AX);
gins(AMOVL, &flo, &r1); gmove(&flo, &r1);
gins(AMOVL, &r1, t); gins(AMOVL, &r1, t);
splitclean(); splitclean();
return; return;
...@@ -1340,14 +1351,14 @@ gmove(Node *f, Node *t) ...@@ -1340,14 +1351,14 @@ gmove(Node *f, Node *t)
case TUINT8: case TUINT8:
gins(ATESTL, ncon(0xffffff00), &t1); gins(ATESTL, ncon(0xffffff00), &t1);
p1 = gbranch(AJEQ, T); p1 = gbranch(AJEQ, T);
gins(AMOVB, ncon(0), &t1); gins(AMOVL, ncon(0), &t1);
patch(p1, pc); patch(p1, pc);
gmove(&t1, t); gmove(&t1, t);
break; break;
case TUINT16: case TUINT16:
gins(ATESTL, ncon(0xffff0000), &t1); gins(ATESTL, ncon(0xffff0000), &t1);
p1 = gbranch(AJEQ, T); p1 = gbranch(AJEQ, T);
gins(AMOVW, ncon(0), &t1); gins(AMOVL, ncon(0), &t1);
patch(p1, pc); patch(p1, pc);
gmove(&t1, t); gmove(&t1, t);
break; break;
...@@ -1571,6 +1582,14 @@ gmove(Node *f, Node *t) ...@@ -1571,6 +1582,14 @@ gmove(Node *f, Node *t)
gins(a, f, t); gins(a, f, t);
return; return;
rsrc:
// requires register source
regalloc(&r1, f->type, t);
gmove(f, &r1);
gins(a, &r1, t);
regfree(&r1);
return;
rdst: rdst:
// requires register destination // requires register destination
regalloc(&r1, t->type, t); regalloc(&r1, t->type, t);
...@@ -1623,6 +1642,7 @@ gins(int as, Node *f, Node *t) ...@@ -1623,6 +1642,7 @@ gins(int as, Node *f, Node *t)
{ {
Prog *p; Prog *p;
Addr af, at; Addr af, at;
int w;
if(as == AFMOVF && f && f->op == OREGISTER && t && t->op == OREGISTER) if(as == AFMOVF && f && f->op == OREGISTER && t && t->op == OREGISTER)
fatal("gins MOVF reg, reg"); fatal("gins MOVF reg, reg");
...@@ -1648,6 +1668,26 @@ gins(int as, Node *f, Node *t) ...@@ -1648,6 +1668,26 @@ gins(int as, Node *f, Node *t)
p->to = at; p->to = at;
if(debug['g']) if(debug['g'])
print("%P\n", p); print("%P\n", p);
w = 0;
switch(as) {
case AMOVB:
w = 1;
break;
case AMOVW:
w = 2;
break;
case AMOVL:
w = 4;
break;
}
if(1 && w != 0 && f != N && (af.width > w || at.width > w)) {
dump("bad width from:", f);
dump("bad width to:", t);
fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
}
return p; return p;
} }
...@@ -1799,8 +1839,9 @@ naddr(Node *n, Addr *a, int canemitcode) ...@@ -1799,8 +1839,9 @@ naddr(Node *n, Addr *a, int canemitcode)
naddr(n->left, a, canemitcode); naddr(n->left, a, canemitcode);
if(a->type == D_CONST && a->offset == 0) if(a->type == D_CONST && a->offset == 0)
break; // len(nil) break; // len(nil)
a->etype = TUINT; a->etype = TUINT32;
a->offset += Array_nel; a->offset += Array_nel;
a->width = 4;
if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero) if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
checkoffset(a, canemitcode); checkoffset(a, canemitcode);
break; break;
...@@ -1810,8 +1851,9 @@ naddr(Node *n, Addr *a, int canemitcode) ...@@ -1810,8 +1851,9 @@ naddr(Node *n, Addr *a, int canemitcode)
naddr(n->left, a, canemitcode); naddr(n->left, a, canemitcode);
if(a->type == D_CONST && a->offset == 0) if(a->type == D_CONST && a->offset == 0)
break; // cap(nil) break; // cap(nil)
a->etype = TUINT; a->etype = TUINT32;
a->offset += Array_cap; a->offset += Array_cap;
a->width = 4;
if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero) if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
checkoffset(a, canemitcode); checkoffset(a, canemitcode);
break; break;
......
char *runtimeimport = char *runtimeimport =
"package runtime\n" "package runtime\n"
"import runtime \"runtime\"\n"
"func \"\".new (? int32) *any\n" "func \"\".new (? int32) *any\n"
"func \"\".panicindex ()\n" "func \"\".panicindex ()\n"
"func \"\".panicslice ()\n" "func \"\".panicslice ()\n"
...@@ -81,6 +82,7 @@ char *runtimeimport = ...@@ -81,6 +82,7 @@ char *runtimeimport =
"func \"\".selectgo (sel *uint8)\n" "func \"\".selectgo (sel *uint8)\n"
"func \"\".block ()\n" "func \"\".block ()\n"
"func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n" "func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n"
"func \"\".growslice (typ *uint8, old []any, cap int64) []any\n"
"func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n" "func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n"
"func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n" "func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n"
"func \"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n" "func \"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n"
...@@ -98,6 +100,7 @@ char *runtimeimport = ...@@ -98,6 +100,7 @@ char *runtimeimport =
"$$\n"; "$$\n";
char *unsafeimport = char *unsafeimport =
"package unsafe\n" "package unsafe\n"
"import runtime \"runtime\"\n"
"type \"\".Pointer uintptr\n" "type \"\".Pointer uintptr\n"
"func \"\".Offsetof (? any) int\n" "func \"\".Offsetof (? any) int\n"
"func \"\".Sizeof (? any) int\n" "func \"\".Sizeof (? any) int\n"
......
...@@ -110,6 +110,7 @@ func selectgo(sel *byte) ...@@ -110,6 +110,7 @@ func selectgo(sel *byte)
func block() func block()
func makeslice(typ *byte, nel int64, cap int64) (ary []any) func makeslice(typ *byte, nel int64, cap int64) (ary []any)
func growslice(typ *byte, old []any, n int64) (ary []any)
func sliceslice1(old []any, lb uint64, width uint64) (ary []any) func sliceslice1(old []any, lb uint64, width uint64) (ary []any)
func sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any) func sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any) func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any)
......
...@@ -1073,6 +1073,9 @@ Jconv(Fmt *fp) ...@@ -1073,6 +1073,9 @@ Jconv(Fmt *fp)
if(n->implicit != 0) if(n->implicit != 0)
fmtprint(fp, " implicit(%d)", n->implicit); fmtprint(fp, " implicit(%d)", n->implicit);
if(n->pun != 0)
fmtprint(fp, " pun(%d)", n->pun);
return 0; return 0;
} }
...@@ -1141,7 +1144,7 @@ Tpretty(Fmt *fp, Type *t) ...@@ -1141,7 +1144,7 @@ Tpretty(Fmt *fp, Type *t)
Type *t1; Type *t1;
Sym *s; Sym *s;
if(debug['r']) { if(0 && debug['r']) {
debug['r'] = 0; debug['r'] = 0;
fmtprint(fp, "%T (orig=%T)", t, t->orig); fmtprint(fp, "%T (orig=%T)", t, t->orig);
debug['r'] = 1; debug['r'] = 1;
...@@ -3109,7 +3112,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) ...@@ -3109,7 +3112,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
Type *tpad; Type *tpad;
int isddd; int isddd;
if(debug['r']) if(0 && debug['r'])
print("genwrapper rcvrtype=%T method=%T newnam=%S\n", print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
rcvr, method, newnam); rcvr, method, newnam);
...@@ -3163,7 +3166,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) ...@@ -3163,7 +3166,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
fn->nbody = list1(n); fn->nbody = list1(n);
} }
if(debug['r']) if(0 && debug['r'])
dumplist("genwrapper body", fn->nbody); dumplist("genwrapper body", fn->nbody);
funcbody(fn); funcbody(fn);
...@@ -3258,8 +3261,9 @@ implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr) ...@@ -3258,8 +3261,9 @@ implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
// the method does not exist for value types. // the method does not exist for value types.
rcvr = getthisx(tm->type)->type->type; rcvr = getthisx(tm->type)->type->type;
if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) { if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) {
if(debug['r']) if(0 && debug['r'])
yyerror("interface pointer mismatch"); yyerror("interface pointer mismatch");
*m = im; *m = im;
*samename = nil; *samename = nil;
*ptr = 1; *ptr = 1;
......
...@@ -18,12 +18,14 @@ static NodeList* paramstoheap(Type **argin, int out); ...@@ -18,12 +18,14 @@ static NodeList* paramstoheap(Type **argin, int out);
static NodeList* reorder1(NodeList*); static NodeList* reorder1(NodeList*);
static NodeList* reorder3(NodeList*); static NodeList* reorder3(NodeList*);
static Node* addstr(Node*, NodeList**); static Node* addstr(Node*, NodeList**);
static Node* appendslice(Node*, NodeList**);
static Node* append(Node*, NodeList**); static Node* append(Node*, NodeList**);
static int oasappend(Node**, NodeList**);
static NodeList* walkdefstack; static NodeList* walkdefstack;
// can this code branch reach the end // can this code branch reach the end
// without an undcontitional RETURN // without an unconditional RETURN
// this is hard, so it is conservative // this is hard, so it is conservative
static int static int
walkret(NodeList *l) walkret(NodeList *l)
...@@ -805,18 +807,20 @@ walkexpr(Node **np, NodeList **init) ...@@ -805,18 +807,20 @@ walkexpr(Node **np, NodeList **init)
n->ninit = nil; n->ninit = nil;
walkexpr(&n->left, init); walkexpr(&n->left, init);
n->left = safeexpr(n->left, init); n->left = safeexpr(n->left, init);
if(oaslit(n, init)) if(oaslit(n, init))
goto ret; goto ret;
walkexpr(&n->right, init);
l = n->left; if (oasappend(&n, init))
r = n->right;
if(l == N || r == N)
goto ret; goto ret;
r = ascompatee1(n->op, l, r, init);
if(r != N) { walkexpr(&n->right, init);
if(n->left != N && n->right != N) {
r = convas(nod(OAS, n->left, n->right), init);
r->dodata = n->dodata; r->dodata = n->dodata;
n = r; n = r;
} }
goto ret; goto ret;
case OAS2: case OAS2:
...@@ -1134,6 +1138,7 @@ walkexpr(Node **np, NodeList **init) ...@@ -1134,6 +1138,7 @@ walkexpr(Node **np, NodeList **init)
case OINDEXMAP: case OINDEXMAP:
if(n->etype == 1) if(n->etype == 1)
goto ret; goto ret;
t = n->left->type; t = n->left->type;
n = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right); n = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right);
goto ret; goto ret;
...@@ -1188,6 +1193,7 @@ walkexpr(Node **np, NodeList **init) ...@@ -1188,6 +1193,7 @@ walkexpr(Node **np, NodeList **init)
// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any) // sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
// sliceslice1(old []any, lb uint64, width uint64) (ary []any) // sliceslice1(old []any, lb uint64, width uint64) (ary []any)
t = n->type; t = n->type;
et = n->etype;
if(n->right->left == N) if(n->right->left == N)
l = nodintconst(0); l = nodintconst(0);
else else
...@@ -1210,6 +1216,7 @@ walkexpr(Node **np, NodeList **init) ...@@ -1210,6 +1216,7 @@ walkexpr(Node **np, NodeList **init)
l, l,
nodintconst(t->type->width)); nodintconst(t->type->width));
} }
n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call.
goto ret; goto ret;
slicearray: slicearray:
...@@ -1332,7 +1339,10 @@ walkexpr(Node **np, NodeList **init) ...@@ -1332,7 +1339,10 @@ walkexpr(Node **np, NodeList **init)
goto ret; goto ret;
case OAPPEND: case OAPPEND:
n = append(n, init); if(n->isddd)
n = appendslice(n, init);
else
n = append(n, init);
goto ret; goto ret;
case OCOPY: case OCOPY:
...@@ -1953,23 +1963,18 @@ callnew(Type *t) ...@@ -1953,23 +1963,18 @@ callnew(Type *t)
static Node* static Node*
convas(Node *n, NodeList **init) convas(Node *n, NodeList **init)
{ {
Node *l, *r;
Type *lt, *rt; Type *lt, *rt;
if(n->op != OAS) if(n->op != OAS)
fatal("convas: not OAS %O", n->op); fatal("convas: not OAS %O", n->op);
n->typecheck = 1;
lt = T; n->typecheck = 1;
rt = T;
l = n->left; if(n->left == N || n->right == N)
r = n->right;
if(l == N || r == N)
goto out; goto out;
lt = l->type; lt = n->left->type;
rt = r->type; rt = n->right->type;
if(lt == T || rt == T) if(lt == T || rt == T)
goto out; goto out;
...@@ -1987,7 +1992,7 @@ convas(Node *n, NodeList **init) ...@@ -1987,7 +1992,7 @@ convas(Node *n, NodeList **init)
if(eqtype(lt, rt)) if(eqtype(lt, rt))
goto out; goto out;
n->right = assignconv(r, lt, "assignment"); n->right = assignconv(n->right, lt, "assignment");
walkexpr(&n->right, init); walkexpr(&n->right, init);
out: out:
...@@ -2364,21 +2369,24 @@ addstr(Node *n, NodeList **init) ...@@ -2364,21 +2369,24 @@ addstr(Node *n, NodeList **init)
return r; return r;
} }
static Node*
appendslice(Node *n, NodeList **init)
{
Node *f;
f = syslook("appendslice", 1);
argtype(f, n->type);
argtype(f, n->type->type);
argtype(f, n->type);
return mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n);
}
static Node* static Node*
append(Node *n, NodeList **init) append(Node *n, NodeList **init)
{ {
int i, j; int i, j;
Node *f, *r; Node *f, *r;
NodeList *in, *args; NodeList *in, *args;
if(n->isddd) {
f = syslook("appendslice", 1);
argtype(f, n->type);
argtype(f, n->type->type);
argtype(f, n->type);
r = mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n);
return r;
}
j = count(n->list) - 1; j = count(n->list) - 1;
f = syslook("append", 1); f = syslook("append", 1);
...@@ -2404,3 +2412,77 @@ append(Node *n, NodeList **init) ...@@ -2404,3 +2412,77 @@ append(Node *n, NodeList **init)
return r; return r;
} }
// expand s = append(s, a [, b]* ) to
//
// const argc = len(args) - 1
// if cap(s) - len(s) < argc {
// s = growslice(s, argc)
// }
// n := len(s)
// s = s[:n+argc]
// s[n] = a
// s[n+1] = b
// ...
//
static int
oasappend(Node **np, NodeList **init)
{
NodeList *l, *a;
Node *n, *ns, *nn, *na, *nx, *fn;
int argc;
n = *np;
// Check that it's an assignment of the form s = append(s, elem), where s is ONAME.
if (n->right == N || n->right->op != OAPPEND || n->right->isddd ||
n->left == N || n->left->op != ONAME || n->left != n->right->list->n)
return 0;
ns = cheapexpr(n->left, init);
walkexprlistsafe(n->right->list, init);
argc = count(n->right->list) - 1;
if (argc < 1) {
n->op = OEMPTY;
return 1;
}
na = nodintconst(argc); // const argc
nx = nod(OIF, N, N); // if cap(s) - len(s) < argc
nx->lineno = n->lineno;
nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na);
fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T)
argtype(fn, ns->type->type); // 1 old []any
argtype(fn, ns->type->type); // 2 ret []any
nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit,
typename(ns->type),
ns,
conv(na, types[TINT64]))));
l = list1(nx);
nn = nod(OXXX, N, N); // var n
tempname(nn, types[TINT]);
l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s)
nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc]
nx->etype = 1; // disable bounds check
l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc]
for (a = n->right->list->next; a != nil; a = a->next) {
nx = nod(OINDEX, ns, nn); // s[n] ...
nx->etype = 1; // disable bounds check
l = list(l, nod(OAS, nx, a->n)); // s[n] = arg
if (a->next != nil)
l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1
}
typechecklist(l, Etop);
*np = liststmt(l);
walkstmt(np);
return 1;
}
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime_test
import "testing"
const N = 20
func BenchmarkAppend(b *testing.B) {
b.StopTimer()
x := make([]int, 0, N)
b.StartTimer()
for i := 0; i < b.N; i++ {
x = x[0:0]
for j := 0; j < N; j++ {
x = append(x, j)
}
}
}
func BenchmarkAppendSpecialCase(b *testing.B) {
b.StopTimer()
x := make([]int, 0, N)
b.StartTimer()
for i := 0; i < b.N; i++ {
x = x[0:0]
for j := 0; j < N; j++ {
if len(x) < cap(x) {
x = x[:len(x)+1]
x[len(x)-1] = j
} else {
x = append(x, j)
}
}
}
}
var x = make([]int, 0, 10)
func f() int {
x[:1][0] = 3
return 2
}
func TestSideEffectOrder(t *testing.T) {
x = append(x, 1, f())
if x[0] != 1 || x[1] != 2 {
t.Error("append failed: ", x[0], x[1])
}
}
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
static int32 debug = 0; static int32 debug = 0;
static void makeslice1(SliceType*, int32, int32, Slice*); static void makeslice1(SliceType*, int32, int32, Slice*);
static void growslice1(SliceType*, Slice, int32, Slice *);
static void appendslice1(SliceType*, Slice, Slice, Slice*);
void runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret); void runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret);
// see also unsafe·NewArray // see also unsafe·NewArray
...@@ -46,8 +48,6 @@ makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret) ...@@ -46,8 +48,6 @@ makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret)
ret->array = runtime·mal(size); ret->array = runtime·mal(size);
} }
static void appendslice1(SliceType*, Slice, Slice, Slice*);
// append(type *Type, n int, old []T, ...,) []T // append(type *Type, n int, old []T, ...,) []T
#pragma textflag 7 #pragma textflag 7
void void
...@@ -72,36 +72,69 @@ runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret) ...@@ -72,36 +72,69 @@ runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret)
static void static void
appendslice1(SliceType *t, Slice x, Slice y, Slice *ret) appendslice1(SliceType *t, Slice x, Slice y, Slice *ret)
{ {
Slice newx;
int32 m; int32 m;
uintptr w; uintptr w;
if(x.len+y.len < x.len) m = x.len+y.len;
if(m < x.len)
runtime·throw("append: slice overflow"); runtime·throw("append: slice overflow");
if(m > x.cap)
growslice1(t, x, m, ret);
else
*ret = x;
w = t->elem->size; w = t->elem->size;
if(x.len+y.len > x.cap) { runtime·memmove(ret->array + ret->len*w, y.array, y.len*w);
m = x.cap; ret->len += y.len;
if(m == 0) }
m = y.len;
else { // growslice(type *Type, x, []T, n int64) []T
do { void
if(x.len < 1024) runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
m += m; {
else int64 cap;
m += m/4;
} while(m < x.len+y.len); if(n < 1)
} runtime·panicstring("growslice: invalid n");
makeslice1(t, x.len, m, &newx);
runtime·memmove(newx.array, x.array, x.len*w); cap = old.cap + n;
x = newx;
if((int32)cap != cap || cap > ((uintptr)-1) / t->elem->size)
runtime·panicstring("growslice: cap out of range");
growslice1(t, old, cap, &ret);
FLUSH(&ret);
if(debug) {
runtime·printf("growslice(%S,", *t->string);
runtime·printslice(old);
runtime·printf(", new cap=%D) =", cap);
runtime·printslice(ret);
} }
runtime·memmove(x.array+x.len*w, y.array, y.len*w);
x.len += y.len;
*ret = x;
} }
static void
growslice1(SliceType *t, Slice x, int32 newcap, Slice *ret)
{
int32 m;
m = x.cap;
if(m == 0)
m = newcap;
else {
do {
if(x.len < 1024)
m += m;
else
m += m/4;
} while(m < newcap);
}
makeslice1(t, x.len, m, ret);
runtime·memmove(ret->array, x.array, ret->len * t->elem->size);
}
// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any); // sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any);
void void
......
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