x[lo:] - gc and runtime.
* add runtime sliceslice1 for x[lo:]
* remove runtime arraytoslice, rewriting &arr into arr[0:len(arr)].
* port cgen_inline into 8g, 5g.
* use native memmove in maps
R=ken2
https://golang.org/cl/157106
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
index 98e5278..6477452 100644
--- a/src/cmd/5g/gg.h
+++ b/src/cmd/5g/gg.h
@@ -61,6 +61,7 @@
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
EXTERN Node* throwindex;
+EXTERN Node* throwslice;
EXTERN Node* throwreturn;
EXTERN long unmappedzero;
EXTERN int maxstksize;
@@ -78,6 +79,7 @@
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);
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index a224320..e859f05 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -22,6 +22,7 @@
deferproc = sysfunc("deferproc");
deferreturn = sysfunc("deferreturn");
throwindex = sysfunc("throwindex");
+ throwslice = sysfunc("throwslice");
throwreturn = sysfunc("throwreturn");
}
@@ -685,3 +686,382 @@
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;
+
+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, cr;
+ 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)) {
+ cr = mpgetfix(nr->val.u.xval);
+ if(cl > cr) {
+ if(throwpc == nil) {
+ throwpc = pc;
+ ginscall(throwslice, 0);
+ } else
+ patch(gbranch(AB, T), throwpc);
+ }
+ 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(throwslice, 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, nnode0, ntemp;
+ vlong v;
+ int i, narg, bad;
+
+ if(n->op != OCALLFUNC)
+ goto no;
+ if(!n->left->addable)
+ goto no;
+ if(strcmp(n->left->sym->package, "runtime") != 0)
+ 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;
+ 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:
+ getargs(n->list, nodes, narg);
+
+ nres = *res; // result
+ nnode0 = nodes[0]; // input slice
+ if(!sleasy(res) || !sleasy(&nodes[0])) {
+ bad = 0;
+ if(res->ullman >= UINF)
+ bad = 1;
+ for(i=0; i<narg; i++) {
+ if(nodes[i].ullman >= UINF)
+ bad = 1;
+ if(nodes[i].op == OREGISTER)
+ regfree(&nodes[i]);
+ }
+
+ if(bad)
+ goto no;
+
+ tempname(&ntemp, res->type);
+ if(!sleasy(&nodes[0])) {
+ cgen(&nodes[0], &ntemp);
+ nnode0 = ntemp;
+ }
+ getargs(n->list, nodes, narg);
+ if(!sleasy(res))
+ 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 = nnode0;
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+ cmpandthrow(&nodes[1], &n2);
+
+ // ret.nel = old.nel[0]-lb[1];
+ n2 = nnode0;
+ 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 = nnode0;
+ 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 = nnode0;
+ 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 = nnode0;
+ 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/6g/ggen.c b/src/cmd/6g/ggen.c
index 5c0a221..cf56148 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -1131,7 +1131,7 @@
Node nodes[5];
Node n1, n2, nres, nnode0, ntemp;
vlong v;
- int i, bad;
+ int i, narg, bad;
if(n->op != OCALLFUNC)
goto no;
@@ -1141,10 +1141,14 @@
goto no;
if(strcmp(n->left->sym->name, "slicearray") == 0)
goto slicearray;
- if(strcmp(n->left->sym->name, "sliceslice") == 0)
+ if(strcmp(n->left->sym->name, "sliceslice") == 0) {
+ narg = 4;
goto sliceslice;
- if(strcmp(n->left->sym->name, "arraytoslice") == 0)
- goto arraytoslice;
+ }
+ if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
+ narg = 3;
+ goto sliceslice;
+ }
goto no;
slicearray:
@@ -1231,44 +1235,8 @@
}
return 1;
-arraytoslice:
- if(!sleasy(res))
- goto no;
- getargs(n->list, nodes, 2);
-
- // ret.len = nel[1];
- n2 = *res;
- n2.xoffset += Array_nel;
- gins(optoas(OAS, types[TUINT32]), &nodes[1], &n2);
-
- // ret.cap = nel[1];
- n2 = *res;
- n2.xoffset += Array_cap;
- gins(optoas(OAS, types[TUINT32]), &nodes[1], &n2);
-
- // ret.array = old[0];
- n2 = *res;
- n2.xoffset += Array_array;
- gins(optoas(OAS, types[tptr]), &nodes[0], &n2);
-
- // 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];
- gins(ATESTB, nodintconst(0), &n2);
- }
-
- for(i=0; i<2; i++) {
- if(nodes[i].op == OREGISTER)
- regfree(&nodes[i]);
- }
- return 1;
-
sliceslice:
- getargs(n->list, nodes, 4);
+ getargs(n->list, nodes, narg);
nres = *res; // result
nnode0 = nodes[0]; // input slice
@@ -1276,7 +1244,7 @@
bad = 0;
if(res->ullman >= UINF)
bad = 1;
- for(i=0; i<4; i++) {
+ for(i=0; i<narg; i++) {
if(nodes[i].ullman >= UINF)
bad = 1;
if(nodes[i].op == OREGISTER)
@@ -1291,35 +1259,60 @@
cgen(&nodes[0], &ntemp);
nnode0 = ntemp;
}
- getargs(n->list, nodes, 4);
+ getargs(n->list, nodes, narg);
if(!sleasy(res))
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 = nnode0;
+ n2.xoffset += Array_nel;
+ cmpandthrow(&nodes[1], &n2);
- // if(hb[2] > old.cap[0]) goto throw;
- n2 = nnode0;
- n2.xoffset += Array_cap;
- 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.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);
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[2]);
- gmove(&nodes[2], &n1);
+ // ret.nel = old.nel[0]-lb[1];
+ n2 = nnode0;
+ n2.xoffset += Array_nel;
+
+ regalloc(&n1, types[TUINT32], N);
+ gins(optoas(OAS, types[TUINT32]), &n2, &n1);
if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
+
+ n2 = nres;
+ n2.xoffset += Array_nel;
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
regfree(&n1);
+ } else { // old[lb:hb]
+ // if(hb[2] > old.cap[0]) goto throw;
+ n2 = nnode0;
+ n2.xoffset += Array_cap;
+ 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.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);
+ gins(optoas(OAS, types[TUINT32]), &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);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+ }
}
// ret.cap = old.cap[0]-lb[1]; (uses hb[2])
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index ee4df87..b6b855d 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -61,6 +61,10 @@
if(res == N || res->type == T)
fatal("cgen: res nil");
+ // inline slices
+ if(cgen_inline(n, res))
+ return;
+
while(n->op == OCONVNOP)
n = n->left;
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
index b36d073..3c0292c 100644
--- a/src/cmd/8g/gg.h
+++ b/src/cmd/8g/gg.h
@@ -65,6 +65,7 @@
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
EXTERN Node* throwindex;
+EXTERN Node* throwslice;
EXTERN Node* throwreturn;
EXTERN int maxstksize;
extern uint32 unmappedzero;
@@ -106,6 +107,7 @@
int samaddr(Node*, Node*);
void naddr(Node*, Addr*, int);
void cgen_aret(Node*, Node*);
+int cgen_inline(Node*, Node*);
Node* ncon(uint32);
/*
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index 7fc0aab..c0a917b 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -22,6 +22,7 @@
deferproc = sysfunc("deferproc");
deferreturn = sysfunc("deferreturn");
throwindex = sysfunc("throwindex");
+ throwslice = sysfunc("throwslice");
throwreturn = sysfunc("throwreturn");
}
@@ -740,4 +741,348 @@
regfree(&n2b);
}
+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;
+
+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)) {
+ if(i < 3) // AX CX DX
+ nodreg(reg+i, l->n->right->type, D_AX+i);
+ else
+ reg[i].op = OXXX;
+ regalloc(reg+i, l->n->right->type, reg+i);
+ 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, cr;
+ Prog *p1;
+ int op;
+ Node *c;
+
+ op = OLE;
+ if(smallintconst(nl)) {
+ cl = mpgetfix(nl->val.u.xval);
+ if(cl == 0)
+ return;
+ if(smallintconst(nr)) {
+ cr = mpgetfix(nr->val.u.xval);
+ if(cl > cr) {
+ if(throwpc == nil) {
+ throwpc = pc;
+ ginscall(throwslice, 0);
+ } else
+ patch(gbranch(AJMP, T), throwpc);
+ }
+ return;
+ }
+
+ // put the constant on the right
+ op = brrev(op);
+ c = nl;
+ nl = nr;
+ nr = c;
+ }
+
+ gins(optoas(OCMP, types[TUINT32]), nl, nr);
+ if(throwpc == nil) {
+ p1 = gbranch(optoas(op, types[TUINT32]), T);
+ throwpc = pc;
+ ginscall(throwslice, 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, nres, nnode0, ntemp;
+ vlong v;
+ int i, narg, bad;
+
+ if(n->op != OCALLFUNC)
+ goto no;
+ if(!n->left->addable)
+ goto no;
+ if(strcmp(n->left->sym->package, "runtime") != 0)
+ 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;
+ 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.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);
+ gins(optoas(OAS, types[TUINT32]), &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);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+ }
+
+ // cap = nel[1] - lb[2] (destroys nel)
+ n2 = *res;
+ 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);
+ gins(optoas(OAS, types[TUINT32]), &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);
+ gins(optoas(OAS, types[TUINT32]), &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];
+ gins(ATESTB, nodintconst(0), &n2);
+ }
+
+ // ary = old[0] + (lb[2] * width[4]) (destroys old)
+ n2 = *res;
+ 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)
+ gins(optoas(OMUL, types[tptr]), &nodes[4], &n1);
+ gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
+ regfree(&n1);
+ }
+ gins(optoas(OAS, types[tptr]), &nodes[0], &n2);
+
+ for(i=0; i<5; i++) {
+ if(nodes[i].op == OREGISTER)
+ regfree(&nodes[i]);
+ }
+ return 1;
+
+sliceslice:
+ getargs(n->list, nodes, narg);
+
+ nres = *res; // result
+ nnode0 = nodes[0]; // input slice
+ ntemp.op = OXXX;
+ if(!sleasy(res) || !sleasy(&nodes[0])) {
+ bad = 0;
+ if(res->ullman >= UINF)
+ bad = 1;
+ for(i=0; i<narg; i++) {
+ if(nodes[i].ullman >= UINF)
+ bad = 1;
+ if(nodes[i].op == OREGISTER)
+ regfree(&nodes[i]);
+ }
+
+ if(bad)
+ goto no;
+
+ tempalloc(&ntemp, res->type);
+ if(!sleasy(&nodes[0])) {
+ cgen(&nodes[0], &ntemp);
+ nnode0 = ntemp;
+ }
+ getargs(n->list, nodes, narg);
+ if(!sleasy(res))
+ 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 = nnode0;
+ n2.xoffset += Array_nel;
+ cmpandthrow(&nodes[1], &n2);
+
+ // ret.nel = old.nel[0]-lb[1];
+ n2 = nnode0;
+ n2.xoffset += Array_nel;
+
+ regalloc(&n1, types[TUINT32], N);
+ gins(optoas(OAS, types[TUINT32]), &n2, &n1);
+ if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
+
+ n2 = nres;
+ n2.xoffset += Array_nel;
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+ } else { // old[lb:hb]
+ // if(hb[2] > old.cap[0]) goto throw;
+ n2 = nnode0;
+ n2.xoffset += Array_cap;
+ 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.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);
+ gins(optoas(OAS, types[TUINT32]), &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);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+ }
+ }
+
+ // ret.cap = old.cap[0]-lb[1]; (uses hb[2])
+ n2 = nnode0;
+ n2.xoffset += Array_cap;
+
+ regalloc(&n1, types[TUINT32], &nodes[2]);
+ gins(optoas(OAS, types[TUINT32]), &n2, &n1);
+ if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
+
+ n2 = nres;
+ n2.xoffset += Array_cap;
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+
+ // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
+ n2 = nnode0;
+ n2.xoffset += Array_array;
+
+ regalloc(&n1, types[tptr], &nodes[1]);
+ if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
+ gins(optoas(OAS, types[tptr]), &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]), &n2, &n1);
+ }
+ } else {
+ gmove(&nodes[1], &n1);
+ if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1)
+ gins(optoas(OMUL, types[tptr]), &nodes[3], &n1);
+ gins(optoas(OADD, types[tptr]), &n2, &n1);
+ }
+
+ n2 = nres;
+ n2.xoffset += Array_array;
+ gins(optoas(OAS, types[tptr]), &n1, &n2);
+ regfree(&n1);
+
+ for(i=0; i<4; i++) {
+ if(nodes[i].op == OREGISTER)
+ regfree(&nodes[i]);
+ }
+
+ if(!sleasy(res)) {
+ cgen(&nres, res);
+ }
+ if(ntemp.op != OXXX)
+ tempfree(&ntemp);
+ return 1;
+
+no:
+ return 0;
+}
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
index 8b794efd..58d6f9e 100644
--- a/src/cmd/gc/builtin.c.boot
+++ b/src/cmd/gc/builtin.c.boot
@@ -64,9 +64,9 @@
"func runtime.selectdefault (sel *uint8) (selected bool)\n"
"func runtime.selectgo (sel *uint8)\n"
"func runtime.makeslice (nel int, cap int, width int) (ary []any)\n"
+ "func runtime.sliceslice1 (old []any, lb int, width int) (ary []any)\n"
"func runtime.sliceslice (old []any, lb int, hb int, width int) (ary []any)\n"
"func runtime.slicearray (old *any, nel int, lb int, hb int, width int) (ary []any)\n"
- "func runtime.arraytoslice (old *any, nel int) (ary []any)\n"
"func runtime.closure ()\n"
"func runtime.int64div (? int64, ? int64) (? int64)\n"
"func runtime.uint64div (? uint64, ? uint64) (? uint64)\n"
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 921ff1e..8413df6 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -831,9 +831,13 @@
{
$$ = nod(OINDEX, $1, $3);
}
-| pexpr '[' keyval ']'
+| pexpr '[' expr ':' ']'
{
- $$ = nod(OSLICE, $1, $3);
+ $$ = nod(OSLICE, $1, nod(OKEY, $3, N));
+ }
+| pexpr '[' expr ':' expr ']'
+ {
+ $$ = nod(OSLICE, $1, nod(OKEY, $3, $5));
}
| pseudocall
| convtype '(' expr ')'
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 1f078f2..ea40840 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -79,9 +79,9 @@
func selectgo(sel *byte)
func makeslice(nel int, cap int, width int) (ary []any)
+func sliceslice1(old []any, lb int, width int) (ary []any)
func sliceslice(old []any, lb int, hb int, width int) (ary []any)
func slicearray(old *any, nel int, lb int, hb int, width int) (ary []any)
-func arraytoslice(old *any, nel int) (ary []any)
func closure() // has args, but compiler fills in
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 6dab9d7..fb96221 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -587,7 +587,7 @@
defaultlit(&n->right->left, types[TUINT]);
defaultlit(&n->right->right, types[TUINT]);
implicitstar(&n->left);
- if(n->right->left == N || n->right->right == N) {
+ if(n->right->left == N) {
yyerror("missing slice bounds?");
goto error;
}
@@ -597,11 +597,13 @@
yyerror("invalid slice index %#N (type %T)", n->right->left, t);
goto error;
}
- if((t = n->right->right->type) == T)
- goto error;
- if(!isint[t->etype]) {
- yyerror("invalid slice index %#N (type %T)", n->right->right, t);
- goto error;
+ if(n->right->right != N) {
+ if((t = n->right->right->type) == T)
+ goto error;
+ if(!isint[t->etype]) {
+ yyerror("invalid slice index %#N (type %T)", n->right->right, t);
+ goto error;
+ }
}
l = n->left;
if((t = l->type) == T)
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 9f3c81e..bf35b38 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -808,15 +808,26 @@
walkexpr(&n->right->right, init);
// dynamic slice
// sliceslice(old []any, lb int, hb int, width int) (ary []any)
+ // sliceslice1(old []any, lb int, width int) (ary []any)
t = n->type;
- fn = syslook("sliceslice", 1);
- argtype(fn, t->type); // any-1
- argtype(fn, t->type); // any-2
- n = mkcall1(fn, t, init,
- n->left,
- conv(n->right->left, types[TINT]),
- conv(n->right->right, types[TINT]),
- nodintconst(t->type->width));
+ if(n->right->right != N) {
+ fn = syslook("sliceslice", 1);
+ argtype(fn, t->type); // any-1
+ argtype(fn, t->type); // any-2
+ n = mkcall1(fn, t, init,
+ n->left,
+ conv(n->right->left, types[TINT]),
+ conv(n->right->right, types[TINT]),
+ nodintconst(t->type->width));
+ } else {
+ fn = syslook("sliceslice1", 1);
+ argtype(fn, t->type); // any-1
+ argtype(fn, t->type); // any-2
+ n = mkcall1(fn, t, init,
+ n->left,
+ conv(n->right->left, types[TINT]),
+ nodintconst(t->type->width));
+ }
goto ret;
case OSLICEARR:
@@ -829,13 +840,29 @@
fn = syslook("slicearray", 1);
argtype(fn, n->left->type); // any-1
argtype(fn, t->type); // any-2
+ if(n->right->right == N)
+ r = nodintconst(n->left->type->bound);
+ else
+ r = conv(n->right->right, types[TINT]);
n = mkcall1(fn, t, init,
nod(OADDR, n->left, N), nodintconst(n->left->type->bound),
conv(n->right->left, types[TINT]),
- conv(n->right->right, types[TINT]),
+ r,
nodintconst(t->type->width));
goto ret;
+ case OCONVSLICE:
+ // slicearray(old *any, nel int, lb int, hb int, width int) (ary []any)
+ fn = syslook("slicearray", 1);
+ argtype(fn, n->left->type->type); // any-1
+ argtype(fn, n->type->type); // any-2
+ n = mkcall1(fn, n->type, init, n->left,
+ nodintconst(n->left->type->type->bound),
+ nodintconst(0),
+ nodintconst(n->left->type->type->bound),
+ nodintconst(n->type->type->width));
+ goto ret;
+
case OADDR:;
Node *nvar, *nstar;
@@ -1014,14 +1041,6 @@
n = ifacecvt(n->type, n->left, n->etype, init);
goto ret;
- case OCONVSLICE:
- // arraytoslice(old *any, nel int) (ary []any)
- fn = syslook("arraytoslice", 1);
- argtype(fn, n->left->type->type); // any-1
- argtype(fn, n->type->type); // any-2
- n = mkcall1(fn, n->type, init, n->left, nodintconst(n->left->type->type->bound));
- goto ret;
-
case OCLOSURE:
n = walkclosure(n, init);
goto ret;
diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h
index 984b80c..9d821da 100644
--- a/src/pkg/runtime/hashmap.h
+++ b/src/pkg/runtime/hashmap.h
@@ -67,7 +67,6 @@
#define free(a) USED(a)
#define offsetof(s,m) (uint32)(&(((s*)0)->m))
#define memset(a,b,c) runtime·memclr((byte*)(a), (uint32)(c))
-#define memmove(a,b,c) mmov((byte*)(a),(byte*)(b),(uint32)(c))
#define memcpy(a,b,c) mcpy((byte*)(a),(byte*)(b),(uint32)(c))
#define assert(a) if(!(a)) throw("assert")
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index 39fda98..4a0309e 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -104,28 +104,6 @@
}
-void
-mmov(byte *t, byte *f, uint32 n)
-{
- if(t < f) {
- while(n > 0) {
- *t = *f;
- t++;
- f++;
- n--;
- }
- } else {
- t += n;
- f += n;
- while(n > 0) {
- t--;
- f--;
- *t = *f;
- n--;
- }
- }
-}
-
byte*
mchr(byte *p, byte c, byte *ep)
{
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index df1c45a..11dc489 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -342,7 +342,7 @@
byte* mchr(byte*, byte, byte*);
void mcpy(byte*, byte*, uint32);
int32 mcmp(byte*, byte*, uint32);
-void mmov(byte*, byte*, uint32);
+void memmove(void*, void*, uint32);
void* mal(uint32);
uint32 cmpstring(String, String);
String gostring(byte*);
diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.c
index 02839e2..17762ae 100644
--- a/src/pkg/runtime/slice.c
+++ b/src/pkg/runtime/slice.c
@@ -52,7 +52,6 @@
void
runtime·sliceslice(Slice old, uint32 lb, uint32 hb, uint32 width, Slice ret)
{
-
if(hb > old.cap || lb > hb) {
if(debug) {
prints("runtime·sliceslice: old=");
@@ -75,7 +74,7 @@
}
// new array is inside old array
- ret.len = hb-lb;
+ ret.len = hb - lb;
ret.cap = old.cap - lb;
ret.array = old.array + lb*width;
@@ -96,6 +95,49 @@
}
}
+// sliceslice1(old []any, lb int, width int) (ary []any);
+void
+runtime·sliceslice1(Slice old, uint32 lb, uint32 width, Slice ret)
+{
+ if(lb > old.len) {
+ if(debug) {
+ prints("runtime·sliceslice: old=");
+ runtime·printslice(old);
+ prints("; lb=");
+ runtime·printint(lb);
+ prints("; width=");
+ runtime·printint(width);
+ prints("\n");
+
+ prints("oldarray: nel=");
+ runtime·printint(old.len);
+ prints("; cap=");
+ runtime·printint(old.cap);
+ prints("\n");
+ }
+ throwslice(lb, old.len, old.cap);
+ }
+
+ // new array is inside old array
+ ret.len = old.len - lb;
+ ret.cap = old.cap - lb;
+ ret.array = old.array + lb*width;
+
+ FLUSH(&ret);
+
+ if(debug) {
+ prints("runtime·sliceslice: old=");
+ runtime·printslice(old);
+ prints("; lb=");
+ runtime·printint(lb);
+ prints("; width=");
+ runtime·printint(width);
+ prints("; ret=");
+ runtime·printslice(ret);
+ prints("\n");
+ }
+}
+
// slicearray(old *any, nel int, lb int, hb int, width int) (ary []any);
void
runtime·slicearray(byte* old, uint32 nel, uint32 lb, uint32 hb, uint32 width, Slice ret)
@@ -149,34 +191,6 @@
}
}
-// arraytoslice(old *any, nel int) (ary []any)
-void
-runtime·arraytoslice(byte* old, uint32 nel, Slice ret)
-{
- if(nel > 0 && old == nil) {
- // crash if old == nil.
- // could give a better message
- // but this is consistent with all the in-line checks
- // that the compiler inserts for other uses.
- *old = 0;
- }
-
- // new dope to old array
- ret.len = nel;
- ret.cap = nel;
- ret.array = old;
-
- FLUSH(&ret);
-
- if(debug) {
- prints("runtime·slicearrayp: old=");
- runtime·printpointer(old);
- prints("; ret=");
- runtime·printslice(ret);
- prints("\n");
- }
-}
-
// slicecopy(to any, fr any, wid uint32) int
void
runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret)