if(res == N || res->type == T)
fatal("cgen: res nil");
+ switch(n->op) {
+ case OSLICE:
+ case OSLICEARR:
+ case OSLICESTR:
+ if (res->op != ONAME || !res->addable) {
+ tempname(&n1, n->type);
+ cgen_slice(n, &n1);
+ cgen(&n1, res);
+ } else
+ cgen_slice(n, res);
+ return;
+ }
+
while(n->op == OCONVNOP)
n = n->left;
cgen_aret(n, res);
break;
+ case OSLICE:
+ case OSLICEARR:
+ case OSLICESTR:
+ tempname(&n1, n->type);
+ cgen_slice(n, &n1);
+ agen(&n1, res);
+ break;
+
case OINDEX:
p2 = nil; // to be patched to panicindex.
w = n->type->width;
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);
break;
case 0: // normal call
+ case -1: // normal call but no return
p = gins(ABL, N, f);
afunclit(&p->to);
+ if(proc == -1 || noreturn(p))
+ gins(AUNDEF, N, N);
break;
case 1: // call in new proc (go)
regfree(&dst);
regfree(&nz);
}
-
-static int
-regcmp(const void *va, const void *vb)
-{
- Node *ra, *rb;
-
- ra = (Node*)va;
- rb = (Node*)vb;
- return ra->local - rb->local;
-}
-
-static Prog* throwpc;
-
-// We're only going to bother inlining if we can
-// convert all the arguments to 32 bits safely. Can we?
-static int
-fix64(NodeList *nn, int n)
-{
- NodeList *l;
- Node *r;
- int i;
-
- l = nn;
- for(i=0; i<n; i++) {
- r = l->n->right;
- if(is64(r->type) && !smallintconst(r)) {
- if(r->op == OCONV)
- r = r->left;
- if(is64(r->type))
- return 0;
- }
- l = l->next;
- }
- return 1;
-}
-
-void
-getargs(NodeList *nn, Node *reg, int n)
-{
- NodeList *l;
- int i;
-
- throwpc = nil;
-
- l = nn;
- for(i=0; i<n; i++) {
- if(!smallintconst(l->n->right) && !isslice(l->n->right->type)) {
- regalloc(reg+i, l->n->right->type, N);
- cgen(l->n->right, reg+i);
- } else
- reg[i] = *l->n->right;
- if(reg[i].local != 0)
- yyerror("local used");
- reg[i].local = l->n->left->xoffset;
- l = l->next;
- }
- qsort((void*)reg, n, sizeof(*reg), regcmp);
- for(i=0; i<n; i++)
- reg[i].local = 0;
-}
-
-void
-cmpandthrow(Node *nl, Node *nr)
-{
- vlong cl;
- Prog *p1;
- int op;
- Node *c, n1, n2;
-
- op = OLE;
- if(smallintconst(nl)) {
- cl = mpgetfix(nl->val.u.xval);
- if(cl == 0)
- return;
- if(smallintconst(nr))
- return;
-
- // put the constant on the right
- op = brrev(op);
- c = nl;
- nl = nr;
- nr = c;
- }
-
- n1.op = OXXX;
- if(nr->op != OREGISTER) {
- regalloc(&n1, types[TUINT32], N);
- gmove(nr, &n1);
- nr = &n1;
- }
- n2.op = OXXX;
- if(nl->op != OREGISTER) {
- regalloc(&n2, types[TUINT32], N);
- gmove(nl, &n2);
- nl = &n2;
- }
- gcmp(optoas(OCMP, types[TUINT32]), nl, nr);
- if(nr == &n1)
- regfree(&n1);
- if(nl == &n2)
- regfree(&n2);
- if(throwpc == nil) {
- p1 = gbranch(optoas(op, types[TUINT32]), T, +1);
- throwpc = pc;
- ginscall(panicslice, 0);
- patch(p1, pc);
- } else {
- op = brcom(op);
- p1 = gbranch(optoas(op, types[TUINT32]), T, -1);
- patch(p1, throwpc);
- }
-}
-
-int
-sleasy(Node *n)
-{
- if(n->op != ONAME)
- return 0;
- if(!n->addable)
- return 0;
- return 1;
-}
-
-// generate inline code for
-// slicearray
-// sliceslice
-// arraytoslice
-int
-cgen_inline(Node *n, Node *res)
-{
- Node nodes[5];
- Node n1, n2, n3, nres, ntemp;
- vlong v;
- int i, narg;
-
- if(n->op != OCALLFUNC)
- goto no;
- if(!n->left->addable)
- goto no;
- if(n->left->sym == S)
- goto no;
- if(n->left->sym->pkg != runtimepkg)
- goto no;
- if(strcmp(n->left->sym->name, "slicearray") == 0)
- goto slicearray;
- if(strcmp(n->left->sym->name, "sliceslice") == 0) {
- narg = 4;
- goto sliceslice;
- }
- if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
- narg = 3;
- goto sliceslice;
- }
- goto no;
-
-slicearray:
- if(!sleasy(res))
- goto no;
- if(!fix64(n->list, 5))
- goto no;
- getargs(n->list, nodes, 5);
-
- // if(hb[3] > nel[1]) goto throw
- cmpandthrow(&nodes[3], &nodes[1]);
-
- // if(lb[2] > hb[3]) goto throw
- cmpandthrow(&nodes[2], &nodes[3]);
-
- // len = hb[3] - lb[2] (destroys hb)
- n2 = *res;
- n2.type = types[TUINT32];
- n2.xoffset += Array_nel;
-
- if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
- v = mpgetfix(nodes[3].val.u.xval) -
- mpgetfix(nodes[2].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gmove(&n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[3]);
- gmove(&nodes[3], &n1);
- if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
- gmove(&n1, &n2);
- regfree(&n1);
- }
-
- // cap = nel[1] - lb[2] (destroys nel)
- n2 = *res;
- n2.type = types[TUINT32];
- n2.xoffset += Array_cap;
-
- if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
- v = mpgetfix(nodes[1].val.u.xval) -
- mpgetfix(nodes[2].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gmove(&n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[1]);
- gmove(&nodes[1], &n1);
- if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
- gmove(&n1, &n2);
- regfree(&n1);
- }
-
- // if slice could be too big, dereference to
- // catch nil array pointer.
- if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
- n2 = nodes[0];
- n2.xoffset = 0;
- n2.op = OINDREG;
- n2.type = types[TUINT8];
- regalloc(&n1, types[TUINT32], N);
- gins(AMOVB, &n2, &n1);
- regfree(&n1);
- }
-
- // ary = old[0] + (lb[2] * width[4]) (destroys old)
- n2 = *res;
- n2.type = types[tptr];
- n2.xoffset += Array_array;
-
- if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
- v = mpgetfix(nodes[2].val.u.xval) *
- mpgetfix(nodes[4].val.u.xval);
- if(v != 0) {
- nodconst(&n1, types[tptr], v);
- gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
- }
- } else {
- regalloc(&n1, types[tptr], &nodes[2]);
- gmove(&nodes[2], &n1);
- if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1) {
- regalloc(&n3, types[tptr], N);
- gmove(&nodes[4], &n3);
- gins(optoas(OMUL, types[tptr]), &n3, &n1);
- regfree(&n3);
- }
- gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
- regfree(&n1);
- }
- gmove(&nodes[0], &n2);
-
- for(i=0; i<5; i++) {
- if(nodes[i].op == OREGISTER)
- regfree(&nodes[i]);
- }
- return 1;
-
-sliceslice:
- if(!fix64(n->list, narg))
- goto no;
- ntemp.op = OXXX;
- if(!sleasy(n->list->n->right)) {
- Node *n0;
-
- n0 = n->list->n->right;
- tempname(&ntemp, res->type);
- cgen(n0, &ntemp);
- n->list->n->right = &ntemp;
- getargs(n->list, nodes, narg);
- n->list->n->right = n0;
- } else
- getargs(n->list, nodes, narg);
-
- nres = *res; // result
- if(!sleasy(res)) {
- if(ntemp.op == OXXX)
- tempname(&ntemp, res->type);
- nres = ntemp;
- }
-
- if(narg == 3) { // old[lb:]
- // move width to where it would be for old[lb:hb]
- nodes[3] = nodes[2];
- nodes[2].op = OXXX;
-
- // if(lb[1] > old.nel[0]) goto throw;
- n2 = nodes[0];
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
- cmpandthrow(&nodes[1], &n2);
-
- // ret.nel = old.nel[0]-lb[1];
- n2 = nodes[0];
- n2.type = types[TUINT32];
- n2.xoffset += Array_nel;
-
- regalloc(&n1, types[TUINT32], N);
- gmove(&n2, &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
-
- n2 = nres;
- n2.type = types[TUINT32];
- n2.xoffset += Array_nel;
- gmove(&n1, &n2);
- regfree(&n1);
- } else { // old[lb:hb]
- // if(hb[2] > old.cap[0]) goto throw;
- n2 = nodes[0];
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
- cmpandthrow(&nodes[2], &n2);
-
- // if(lb[1] > hb[2]) goto throw;
- cmpandthrow(&nodes[1], &nodes[2]);
-
- // ret.len = hb[2]-lb[1]; (destroys hb[2])
- n2 = nres;
- n2.type = types[TUINT32];
- n2.xoffset += Array_nel;
-
- if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
- v = mpgetfix(nodes[2].val.u.xval) -
- mpgetfix(nodes[1].val.u.xval);
- nodconst(&n1, types[TUINT32], v);
- gmove(&n1, &n2);
- } else {
- regalloc(&n1, types[TUINT32], &nodes[2]);
- gmove(&nodes[2], &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
- gmove(&n1, &n2);
- regfree(&n1);
- }
- }
-
- // ret.cap = old.cap[0]-lb[1]; (uses hb[2])
- n2 = nodes[0];
- n2.type = types[TUINT32];
- n2.xoffset += Array_cap;
-
- regalloc(&n1, types[TUINT32], &nodes[2]);
- gmove(&n2, &n1);
- if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
- gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
-
- n2 = nres;
- n2.type = types[TUINT32];
- n2.xoffset += Array_cap;
- gmove(&n1, &n2);
- regfree(&n1);
-
- // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
- n2 = nodes[0];
- n2.type = types[tptr];
- n2.xoffset += Array_array;
- regalloc(&n3, types[tptr], N);
- gmove(&n2, &n3);
-
- regalloc(&n1, types[tptr], &nodes[1]);
- if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
- gmove(&n2, &n1);
- v = mpgetfix(nodes[1].val.u.xval) *
- mpgetfix(nodes[3].val.u.xval);
- if(v != 0) {
- nodconst(&n2, types[tptr], v);
- gins(optoas(OADD, types[tptr]), &n3, &n1);
- }
- } else {
- gmove(&nodes[1], &n1);
- if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1) {
- regalloc(&n2, types[tptr], N);
- gmove(&nodes[3], &n2);
- gins(optoas(OMUL, types[tptr]), &n2, &n1);
- regfree(&n2);
- }
- gins(optoas(OADD, types[tptr]), &n3, &n1);
- }
- regfree(&n3);
-
- n2 = nres;
- n2.type = types[tptr];
- n2.xoffset += Array_array;
- gmove(&n1, &n2);
- regfree(&n1);
-
- for(i=0; i<4; i++) {
- if(nodes[i].op == OREGISTER)
- regfree(&nodes[i]);
- }
-
- if(!sleasy(res)) {
- cgen(&nres, res);
- }
- return 1;
-
-no:
- return 0;
-}
return p;
}
+// Generate an instruction referencing *n
+// to force segv on nil pointer dereference.
+bsdvoid
+checkref(Node *n)
+{
+ Node m1, m2;
+
+ if(n->type->type->width < unmappedzero)
+ return;
+
+ regalloc(&m1, types[TUINTPTR], n);
+ regalloc(&m2, types[TUINT8], n);
+ cgen(n, &m1);
+ m1.xoffset = 0;
+ m1.op = OINDREG;
+ m1.type = types[TUINT8];
+ gins(AMOVBU, &m1, &m2);
+ regfree(&m2);
+ regfree(&m1);
+}
+
static void
checkoffset(Addr *a, int canemitcode)
{
while(n->op == OCONVNOP)
n = n->left;
- // inline slices
- if(cgen_inline(n, res))
+ switch(n->op) {
+ case OSLICE:
+ case OSLICEARR:
+ case OSLICESTR:
+ if (res->op != ONAME || !res->addable) {
+ tempname(&n1, n->type);
+ cgen_slice(n, &n1);
+ cgen(&n1, res);
+ } else
+ cgen_slice(n, res);
goto ret;
+ }
if(n->ullman >= UINF) {
if(n->op == OINDREG)
cgen_aret(n, res);
break;
+ case OSLICE:
+ case OSLICEARR:
+ case OSLICESTR:
+ tempname(&n1, n->type);
+ cgen_slice(n, &n1);
+ agen(&n1, res);
+ break;
+
case OINDEX:
w = n->type->width;
if(nr->addable)
int samaddr(Node*, Node*);
void naddr(Node*, Addr*, int);
void cgen_aret(Node*, Node*);
-int cgen_inline(Node*, Node*);
void restx(Node*, Node*);
void savex(int, Node*, Node*, Node*, Type*);
int componentgen(Node*, Node*);
case -1: // normal call but no return
p = gins(ACALL, N, f);
afunclit(&p->to);
- if(proc == -1)
+ if(proc == -1 || noreturn(p))
gins(AUNDEF, N, N);
break;
restx(&n1, &oldn1);
restx(&ax, &oldax);
}
-
-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;
- Prog *p1;
- int op;
- Node *c;
- Type *t;
- Node n1;
-
- if(nl->op == OCONV && is64(nl->type))
- nl = nl->left;
- if(nr->op == OCONV && is64(nr->type))
- nr = nr->left;
-
- op = OLE;
- if(smallintconst(nl)) {
- cl = mpgetfix(nl->val.u.xval);
- if(cl == 0)
- return;
- if(smallintconst(nr))
- return;
- // put the constant on the right
- op = brrev(op);
- c = nl;
- nl = nr;
- nr = c;
- }
- if(is64(nr->type) && smallintconst(nr))
- nr->type = types[TUINT32];
-
- n1.op = OXXX;
- t = types[TUINT32];
- if(nl->type->width != t->width || nr->type->width != t->width) {
- if((is64(nl->type) && nl->op != OLITERAL) || (is64(nr->type) && nr->op != OLITERAL))
- t = types[TUINT64];
-
- // Check if we need to use a temporary.
- // At least one of the arguments is 32 bits
- // (the len or cap) so one temporary suffices.
- if(nl->type->width != t->width && nl->op != OLITERAL) {
- regalloc(&n1, t, nl);
- gmove(nl, &n1);
- nl = &n1;
- } else if(nr->type->width != t->width && nr->op != OLITERAL) {
- regalloc(&n1, t, nr);
- gmove(nr, &n1);
- nr = &n1;
- }
- }
- gins(optoas(OCMP, t), nl, nr);
- if(n1.op != OXXX)
- regfree(&n1);
- if(throwpc == nil) {
- p1 = gbranch(optoas(op, t), T, +1);
- throwpc = pc;
- ginscall(panicslice, -1);
- patch(p1, pc);
- } else {
- op = brcom(op);
- p1 = gbranch(optoas(op, t), T, -1);
- 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, ntemp;
- vlong v;
- int i, narg, nochk;
-
- if(n->op != OCALLFUNC)
- goto no;
- if(!n->left->addable)
- goto no;
- if(n->left->sym == S)
- goto no;
- if(n->left->sym->pkg != runtimepkg)
- goto no;
- if(strcmp(n->left->sym->name, "slicearray") == 0)
- goto slicearray;
- if(strcmp(n->left->sym->name, "sliceslice") == 0) {
- narg = 4;
- goto sliceslice;
- }
- if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
- narg = 3;
- goto sliceslice;
- }
- goto no;
-
-slicearray:
- if(!sleasy(res))
- goto no;
- 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;
- n2.type = types[TUINT32];
-
- 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;
- n2.type = types[TUINT32];
-
- 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;
- n2.type = types[tptr];
-
- if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
- v = mpgetfix(nodes[2].val.u.xval) *
- mpgetfix(nodes[4].val.u.xval);
- if(v != 0)
- ginscon(optoas(OADD, types[tptr]), v, &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:
- nochk = n->etype; // skip bounds checking
- ntemp.op = OXXX;
- if(!sleasy(n->list->n->right)) {
- Node *n0;
-
- n0 = n->list->n->right;
- tempname(&ntemp, res->type);
- cgen(n0, &ntemp);
- n->list->n->right = &ntemp;
- getargs(n->list, nodes, narg);
- n->list->n->right = n0;
- } else
- getargs(n->list, nodes, narg);
-
- nres = *res; // result
- if(!sleasy(res)) {
- if(ntemp.op == OXXX)
- tempname(&ntemp, res->type);
- nres = ntemp;
- }
-
- if(narg == 3) { // old[lb:]
- // move width to where it would be for old[lb:hb]
- nodes[3] = nodes[2];
- nodes[2].op = OXXX;
-
- // if(lb[1] > old.nel[0]) goto throw;
- n2 = nodes[0];
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
- if(!nochk)
- cmpandthrow(&nodes[1], &n2);
-
- // ret.nel = old.nel[0]-lb[1];
- n2 = nodes[0];
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
-
- 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;
- n2.type = types[TUINT32];
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
- } else { // old[lb:hb]
- n2 = nodes[0];
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
- if(!nochk) {
- // if(hb[2] > old.cap[0]) goto throw;
- 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;
- n2.type = types[TUINT32];
-
- 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 = nodes[0];
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
-
- 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;
- n2.type = types[TUINT32];
-
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
-
- // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
- n2 = nodes[0];
- n2.xoffset += Array_array;
- n2.type = types[tptr];
- 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)
- ginscon(optoas(OADD, types[tptr]), v, &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;
- n2.type = types[tptr];
- 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);
- }
- return 1;
-
-no:
- return 0;
-}
return p;
}
+// Generate an instruction referencing *n
+// to force segv on nil pointer dereference.
+void
+checkref(Node *n)
+{
+ Node m;
+
+ if(n->type->type->width < unmappedzero)
+ return;
+
+ regalloc(&m, types[TUINTPTR], n);
+ cgen(n, &m);
+ m.xoffset = 0;
+ m.op = OINDREG;
+ m.type = types[TUINT8];
+ gins(ATESTB, nodintconst(0), &m);
+ regfree(&m);
+}
+
static void
checkoffset(Addr *a, int canemitcode)
{
if(res == N || res->type == T)
fatal("cgen: res nil");
- // inline slices
- if(cgen_inline(n, res))
+ switch(n->op) {
+ case OSLICE:
+ case OSLICEARR:
+ case OSLICESTR:
+ if (res->op != ONAME || !res->addable) {
+ tempname(&n1, n->type);
+ cgen_slice(n, &n1);
+ cgen(&n1, res);
+ } else
+ cgen_slice(n, res);
return;
+ }
while(n->op == OCONVNOP)
n = n->left;
cgen_aret(n, res);
break;
+ case OSLICE:
+ case OSLICEARR:
+ case OSLICESTR:
+ tempname(&n1, n->type);
+ cgen_slice(n, &n1);
+ agen(&n1, res);
+ break;
+
case OINDEX:
p2 = nil; // to be patched to panicindex.
w = n->type->width;
int samaddr(Node*, Node*);
void naddr(Node*, Addr*, int);
void cgen_aret(Node*, Node*);
-int cgen_inline(Node*, Node*);
Node* ncon(uint32);
void mgen(Node*, Node*, Node*);
void mfree(Node*);
case -1: // normal call but no return
p = gins(ACALL, N, f);
afunclit(&p->to);
- if(proc == -1)
+ if(proc == -1 || noreturn(p))
gins(AUNDEF, N, N);
break;
regfree(&n1b);
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;
-
-// We're only going to bother inlining if we can
-// convert all the arguments to 32 bits safely. Can we?
-static int
-fix64(NodeList *nn, int n)
-{
- NodeList *l;
- Node *r;
- int i;
-
- l = nn;
- for(i=0; i<n; i++) {
- r = l->n->right;
- if(is64(r->type) && !smallintconst(r)) {
- if(r->op == OCONV)
- r = r->left;
- if(is64(r->type))
- return 0;
- }
- l = l->next;
- }
- return 1;
-}
-
-void
-getargs(NodeList *nn, Node *reg, int n)
-{
- NodeList *l;
- Node *r;
- int i;
-
- throwpc = nil;
-
- l = nn;
- for(i=0; i<n; i++) {
- r = l->n->right;
- if(is64(r->type)) {
- if(r->op == OCONV)
- r = r->left;
- else if(smallintconst(r))
- r->type = types[TUINT32];
- if(is64(r->type))
- fatal("getargs");
- }
- if(!smallintconst(r) && !isslice(r->type)) {
- if(i < 3) // AX CX DX
- nodreg(reg+i, r->type, D_AX+i);
- else
- reg[i].op = OXXX;
- regalloc(reg+i, r->type, reg+i);
- cgen(r, reg+i);
- } else
- reg[i] = *r;
- if(reg[i].local != 0)
- yyerror("local used");
- reg[i].local = l->n->left->xoffset;
- l = l->next;
- }
- qsort((void*)reg, n, sizeof(*reg), regcmp);
- for(i=0; i<n; i++)
- reg[i].local = 0;
-}
-
-void
-cmpandthrow(Node *nl, Node *nr)
-{
- vlong cl;
- Prog *p1;
- int op;
- Node *c, n1;
- Type *t;
-
- op = OLE;
- if(smallintconst(nl)) {
- cl = mpgetfix(nl->val.u.xval);
- if(cl == 0)
- return;
- if(smallintconst(nr))
- return;
- // put the constant on the right
- op = brrev(op);
- c = nl;
- nl = nr;
- nr = c;
- }
-
- // Arguments are known not to be 64-bit,
- // but they might be smaller than 32 bits.
- // Check if we need to use a temporary.
- // At least one of the arguments is 32 bits
- // (the len or cap) so one temporary suffices.
- n1.op = OXXX;
- t = types[TUINT32];
- if(nl->type->width != t->width) {
- regalloc(&n1, t, nl);
- gmove(nl, &n1);
- nl = &n1;
- } else if(nr->type->width != t->width) {
- regalloc(&n1, t, nr);
- gmove(nr, &n1);
- nr = &n1;
- }
- gins(optoas(OCMP, t), nl, nr);
- if(n1.op != OXXX)
- regfree(&n1);
- if(throwpc == nil) {
- p1 = gbranch(optoas(op, t), T, +1);
- throwpc = pc;
- ginscall(panicslice, -1);
- patch(p1, pc);
- } else {
- op = brcom(op);
- p1 = gbranch(optoas(op, t), T, -1);
- 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, ntemp;
- vlong v;
- int i, narg, nochk;
-
- if(n->op != OCALLFUNC)
- goto no;
- if(!n->left->addable)
- goto no;
- if(n->left->sym == S)
- goto no;
- if(n->left->sym->pkg != runtimepkg)
- goto no;
- if(strcmp(n->left->sym->name, "slicearray") == 0)
- goto slicearray;
- if(strcmp(n->left->sym->name, "sliceslice") == 0) {
- narg = 4;
- goto sliceslice;
- }
- if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
- narg = 3;
- goto sliceslice;
- }
- goto no;
-
-slicearray:
- if(!sleasy(res))
- goto no;
- if(!fix64(n->list, 5))
- goto no;
- getargs(n->list, nodes, 5);
-
- // if(hb[3] > nel[1]) goto throw
- cmpandthrow(&nodes[3], &nodes[1]);
-
- // if(lb[2] > hb[3]) goto throw
- cmpandthrow(&nodes[2], &nodes[3]);
-
- // len = hb[3] - lb[2] (destroys hb)
- n2 = *res;
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
-
- 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;
- n2.type = types[TUINT32];
-
- 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;
- n2.type = types[tptr];
-
- 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:
- if(!fix64(n->list, narg))
- goto no;
- nochk = n->etype; // skip bounds checking
- ntemp.op = OXXX;
- if(!sleasy(n->list->n->right)) {
- Node *n0;
-
- n0 = n->list->n->right;
- tempname(&ntemp, res->type);
- cgen(n0, &ntemp);
- n->list->n->right = &ntemp;
- getargs(n->list, nodes, narg);
- n->list->n->right = n0;
- } else
- getargs(n->list, nodes, narg);
-
- nres = *res; // result
- if(!sleasy(res)) {
- if(ntemp.op == OXXX)
- tempname(&ntemp, res->type);
- nres = ntemp;
- }
-
- if(narg == 3) { // old[lb:]
- // move width to where it would be for old[lb:hb]
- nodes[3] = nodes[2];
- nodes[2].op = OXXX;
-
- // if(lb[1] > old.nel[0]) goto throw;
- n2 = nodes[0];
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
- if(!nochk)
- cmpandthrow(&nodes[1], &n2);
-
- // ret.nel = old.nel[0]-lb[1];
- n2 = nodes[0];
- n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
-
- 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;
- n2.type = types[TUINT32];
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
- } else { // old[lb:hb]
- n2 = nodes[0];
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
- if (!nochk) {
- // if(hb[2] > old.cap[0]) goto throw;
- 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;
- n2.type = types[TUINT32];
-
- 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 = nodes[0];
- n2.xoffset += Array_cap;
- n2.type = types[TUINT32];
-
- 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;
- n2.type = types[TUINT32];
- gins(optoas(OAS, types[TUINT32]), &n1, &n2);
- regfree(&n1);
-
- // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
- n2 = nodes[0];
- n2.xoffset += Array_array;
- n2.type = types[tptr];
-
- 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;
- n2.type = types[tptr];
- 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);
- }
- return 1;
-
-no:
- return 0;
-}
return p;
}
+// Generate an instruction referencing *n
+// to force segv on nil pointer dereference.
+void
+checkref(Node *n)
+{
+ Node m;
+
+ if(n->type->type->width < unmappedzero)
+ return;
+
+ regalloc(&m, types[TUINTPTR], n);
+ cgen(n, &m);
+ m.xoffset = 0;
+ m.op = OINDREG;
+ m.type = types[TUINT8];
+ gins(ATESTB, nodintconst(0), &m);
+ regfree(&m);
+}
+
static void
checkoffset(Addr *a, int canemitcode)
{
"func @\"\".block()\n"
"func @\"\".makeslice(@\"\".typ *byte, @\"\".nel int64, @\"\".cap int64) (@\"\".ary []any)\n"
"func @\"\".growslice(@\"\".typ *byte, @\"\".old []any, @\"\".n int64) (@\"\".ary []any)\n"
- "func @\"\".sliceslice1(@\"\".old []any, @\"\".lb uint64, @\"\".width uint64) (@\"\".ary []any)\n"
- "func @\"\".sliceslice(@\"\".old []any, @\"\".lb uint64, @\"\".hb uint64, @\"\".width uint64) (@\"\".ary []any)\n"
- "func @\"\".slicearray(@\"\".old *any, @\"\".nel uint64, @\"\".lb uint64, @\"\".hb uint64, @\"\".width uint64) (@\"\".ary []any)\n"
"func @\"\".closure()\n"
"func @\"\".memequal(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n"
"func @\"\".memequal8(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n"
;
}
+
+/*
+ * generate:
+ * res = s[lo, hi];
+ * n->left is s
+ * n->list is (cap(s)-lo(TUINT32), hi-lo(TUINT32)[, lo*width(TUINTPTR)])
+ * caller (cgen) guarantees res is an addable ONAME.
+ *
+ */
+void
+cgen_slice(Node *n, Node *res)
+{
+ Node src, dst, *cap, *len, *offs, *add;
+
+// print("cgen_slice: %N = %+N\n", res, n);
+
+ cap = n->list->n;
+ len = n->list->next->n;
+ offs = N;
+ if(n->list->next->next)
+ offs = n->list->next->next->n;
+
+ // dst.len = hi [ - lo ]
+ dst = *res;
+ dst.xoffset += Array_nel;
+ dst.type = types[TUINT32];
+ cgen(len, &dst);
+
+ if(n->op != OSLICESTR) {
+ // dst.cap = cap [ - lo ]
+ dst = *res;
+ dst.xoffset += Array_cap;
+ dst.type = types[TUINT32];
+ cgen(cap, &dst);
+ }
+
+ // dst.array = src.array [ + lo *width ]
+ dst = *res;
+ dst.xoffset += Array_array;
+ dst.type = types[TUINTPTR];
+
+ if(n->op == OSLICEARR) {
+ if(!isptr[n->left->type->etype])
+ fatal("slicearr is supposed to work on pointer: %+N\n", n);
+ checkref(n->left);
+ }
+
+ src = *n->left;
+ src.xoffset += Array_array;
+ src.type = types[TUINTPTR];
+
+ if(offs == N) {
+ cgen(&src, &dst);
+ } else {
+ add = nod(OADD, &src, offs);
+ typecheck(&add, Erv);
+ cgen(add, &dst);
+ }
+}
+
/*
* gather series of offsets
* >=0 is direct addressed field
void addrescapes(Node *n);
void cgen_as(Node *nl, Node *nr);
void cgen_callmeth(Node *n, int proc);
+void cgen_slice(Node* n, Node* res);
void clearlabels(void);
void checklabels(void);
int dotoffset(Node *n, int *oary, Node **nn);
int anyregalloc(void);
void betypeinit(void);
void bgen(Node *n, int true, int likely, Prog *to);
+void checkref(Node*);
void cgen(Node*, Node*);
void cgen_asop(Node *n);
void cgen_call(Node *n, int proc);
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 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 closure() // has args, but compiler fills in
static Node* addstr(Node*, NodeList**);
static Node* appendslice(Node*, NodeList**);
static Node* append(Node*, NodeList**);
+static Node* sliceany(Node*, NodeList**);
static void walkcompare(Node**, NodeList**);
static void walkrotate(Node**);
static int bounded(Node*, int64);
NodeList *ll, *lr, *lpost;
Type *t;
int et;
- int64 v, v1, v2, len;
+ int64 v;
int32 lno;
Node *n, *fn;
char buf[100], *p;
goto ret;
case OSLICE:
+ if(n->right != N && n->right->left == N && n->right->right == N) { // noop
+ walkexpr(&n->left, init);
+ n = n->left;
+ goto ret;
+ }
+ // fallthrough
case OSLICEARR:
+ case OSLICESTR:
+ if(n->right == N) // already processed
+ goto ret;
+
walkexpr(&n->left, init);
- n->left = safeexpr(n->left, init);
+ // cgen_slice can't handle string literals as source
+ // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi]
+ if((n->op == OSLICESTR && n->left->op == OLITERAL) || (n->left->op == OINDEX))
+ n->left = copyexpr(n->left, n->left->type, init);
+ else
+ n->left = safeexpr(n->left, init);
walkexpr(&n->right->left, init);
n->right->left = safeexpr(n->right->left, init);
walkexpr(&n->right->right, init);
n->right->right = safeexpr(n->right->right, init);
-
- len = 1LL<<60;
- t = n->left->type;
- if(t != T && isptr[t->etype])
- t = t->type;
- if(isfixedarray(t))
- len = t->bound;
-
- // check for static out of bounds
- // NOTE: v > len not v >= len.
- v1 = -1;
- v2 = -1;
- if(isconst(n->right->left, CTINT)) {
- v1 = mpgetfix(n->right->left->val.u.xval);
- if(v1 < 0 || v1 >= (1LL<<31) || v1 > len) {
- yyerror("slice index out of bounds");
- v1 = -1;
- }
- }
- if(isconst(n->right->right, CTINT)) {
- v2 = mpgetfix(n->right->right->val.u.xval);
- if(v2 < 0 || v2 >= (1LL<<31) || v2 > len) {
- yyerror("slice index out of bounds");
- v2 = -1;
- }
- }
- if(v1 >= 0 && v2 >= 0 && v1 > v2)
- yyerror("inverted slice range");
-
- if(n->op == OSLICEARR)
- goto slicearray;
-
- // dynamic slice
- // sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
- // sliceslice1(old []any, lb uint64, width uint64) (ary []any)
- t = n->type;
- et = n->bounded;
- if(n->right->left == N)
- l = nodintconst(0);
- else
- l = conv(n->right->left, types[TUINT64]);
- 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,
- l,
- conv(n->right->right, types[TUINT64]),
- 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,
- l,
- nodintconst(t->type->width));
- }
- n->bounded = et; // preserve flag from OSLICE to the slice* call.
- goto ret;
-
- slicearray:
- // static slice
- // slicearray(old *any, uint64 nel, lb uint64, hb uint64, width uint64) (ary []any)
- t = n->type;
- fn = syslook("slicearray", 1);
- argtype(fn, n->left->type->type); // any-1
- argtype(fn, t->type); // any-2
- if(n->right->left == N)
- l = nodintconst(0);
- else
- l = conv(n->right->left, types[TUINT64]);
- if(n->right->right == N)
- r = nodintconst(n->left->type->type->bound);
- else
- r = conv(n->right->right, types[TUINT64]);
- n = mkcall1(fn, t, init,
- n->left, nodintconst(n->left->type->type->bound),
- l,
- r,
- nodintconst(t->type->width));
+ n = sliceany(n, init); // chops n->right, sets n->list
goto ret;
case OADDR:
case OADDSTR:
n = addstr(n, init);
goto ret;
-
- case OSLICESTR:
- // sys_slicestring(s, lb, hb)
- if(n->right->left == N)
- l = nodintconst(0);
- else
- l = conv(n->right->left, types[TINT]);
- if(n->right->right) {
- n = mkcall("slicestring", n->type, init,
- conv(n->left, types[TSTRING]),
- l,
- conv(n->right->right, types[TINT]));
- } else {
- n = mkcall("slicestring1", n->type, init,
- conv(n->left, types[TSTRING]),
- l);
- }
- goto ret;
-
+
case OAPPEND:
if(n->isddd) {
if(istype(n->type->type, TUINT8) && istype(n->list->next->n->type, TSTRING))
return ns;
}
+
+// Generate frontend part for OSLICE[ARR|STR]
+//
+static Node*
+sliceany(Node* n, NodeList **init)
+{
+ int bounded;
+ Node *src, *lb, *hb, *bound, *chk, *chk1, *chk2;
+ int64 lbv, hbv, bv, w;
+ Type *bt;
+
+// print("before sliceany: %+N\n", n);
+
+ src = n->left;
+ lb = n->right->left;
+ hb = n->right->right;
+
+ bounded = n->etype;
+
+ if(n->op == OSLICESTR)
+ bound = nod(OLEN, src, N);
+ else
+ bound = nod(OCAP, src, N);
+
+ typecheck(&bound, Erv);
+ walkexpr(&bound, init); // if src is an array, bound will be a const now.
+
+ // static checks if possible
+ bv = 1LL<<50;
+ if(isconst(bound, CTINT)) {
+ if(!smallintconst(bound))
+ yyerror("array len too large");
+ else
+ bv = mpgetfix(bound->val.u.xval);
+ }
+ lbv = -1;
+ hbv = -1;
+
+ if(isconst(hb, CTINT)) {
+ hbv = mpgetfix(hb->val.u.xval);
+ if(hbv < 0 || hbv > bv || !smallintconst(hb)) {
+ yyerror("slice index out of bounds");
+ hbv = -1;
+ }
+ }
+ if(isconst(lb, CTINT)) {
+ lbv = mpgetfix(lb->val.u.xval);
+ if(lbv < 0 || lbv > bv || !smallintconst(lb)) {
+ yyerror("slice index out of bounds");
+ lbv = -1;
+ }
+ if(lbv == 0)
+ lb = N;
+ }
+ if(lbv >= 0 && hbv >= 0 && lbv > hbv)
+ yyerror("inverted slice range");
+
+ // dynamic checks convert all bounds to unsigned to save us the bound < 0 comparison
+ // generate
+ // if hb > bound || lb > hb { panicslice() }
+ chk = N;
+ chk1 = N;
+ chk2 = N;
+
+ bt = types[TUINT32];
+ if(hb != N && hb->type->width > 4)
+ bt = types[TUINT64];
+ if(lb != N && lb->type->width > 4)
+ bt = types[TUINT64];
+
+ bound = cheapexpr(conv(bound, bt), init);
+
+ if(hb != N) {
+ hb = cheapexpr(conv(hb, bt), init);
+ if(!bounded)
+ chk1 = nod(OLT, bound, hb);
+ } else if(n->op == OSLICEARR) {
+ hb = bound;
+ } else {
+ hb = nod(OLEN, src, N);
+ typecheck(&hb, Erv);
+ walkexpr(&hb, init);
+ hb = cheapexpr(conv(hb, bt), init);
+ }
+
+ if(lb != N) {
+ lb = cheapexpr(conv(lb, bt), init);
+ if(!bounded)
+ chk2 = nod(OLT, hb, lb);
+ }
+
+ if(chk1 != N || chk2 != N) {
+ chk = nod(OIF, N, N);
+ chk->nbody = list1(mkcall("panicslice", T, init));
+ if(chk1 != N)
+ chk->ntest = chk1;
+ if(chk2 != N) {
+ if(chk->ntest == N)
+ chk->ntest = chk2;
+ else
+ chk->ntest = nod(OOROR, chk->ntest, chk2);
+ }
+ typecheck(&chk, Etop);
+ walkstmt(&chk);
+ *init = concat(*init, chk->ninit);
+ chk->ninit = nil;
+ *init = list(*init, chk);
+ }
+
+ // prepare new cap, len and offs for backend cgen_slice
+ // cap = bound [ - lo ]
+ n->right = N;
+ n->list = nil;
+ if(lb == N)
+ bound = conv(bound, types[TUINT32]);
+ else
+ bound = nod(OSUB, conv(bound, types[TUINT32]), conv(lb, types[TUINT32]));
+ typecheck(&bound, Erv);
+ walkexpr(&bound, init);
+ n->list = list(n->list, bound);
+
+ // len = hi [ - lo]
+ if(lb == N)
+ hb = conv(hb, types[TUINT32]);
+ else
+ hb = nod(OSUB, conv(hb, types[TUINT32]), conv(lb, types[TUINT32]));
+ typecheck(&hb, Erv);
+ walkexpr(&hb, init);
+ n->list = list(n->list, hb);
+
+ // offs = [width *] lo, but omit if zero
+ if(lb != N) {
+ if(n->op == OSLICESTR)
+ w = 1;
+ else
+ w = n->type->type->width;
+ lb = conv(lb, types[TUINTPTR]);
+ if(w > 1)
+ lb = nod(OMUL, nodintconst(w), lb);
+ typecheck(&lb, Erv);
+ walkexpr(&lb, init);
+ n->list = list(n->list, lb);
+ }
+
+// print("after sliceany: %+N\n", n);
+
+ return n;
+}
+
static Node*
eqfor(Type *t)
{
runtime·memmove(ret->array, x.array, ret->len * t->elem->size);
}
-// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any);
-void
-runtime·sliceslice(Slice old, uint64 lb, uint64 hb, uint64 width, Slice ret)
-{
- if(hb > old.cap || lb > hb) {
- if(debug) {
- runtime·prints("runtime.sliceslice: old=");
- runtime·printslice(old);
- runtime·prints("; lb=");
- runtime·printint(lb);
- runtime·prints("; hb=");
- runtime·printint(hb);
- runtime·prints("; width=");
- runtime·printint(width);
- runtime·prints("\n");
-
- runtime·prints("oldarray: nel=");
- runtime·printint(old.len);
- runtime·prints("; cap=");
- runtime·printint(old.cap);
- runtime·prints("\n");
- }
- runtime·panicslice();
- }
-
- // new array is inside old array
- ret.len = hb - lb;
- ret.cap = old.cap - lb;
- ret.array = old.array + lb*width;
-
- FLUSH(&ret);
-
- if(debug) {
- runtime·prints("runtime.sliceslice: old=");
- runtime·printslice(old);
- runtime·prints("; lb=");
- runtime·printint(lb);
- runtime·prints("; hb=");
- runtime·printint(hb);
- runtime·prints("; width=");
- runtime·printint(width);
- runtime·prints("; ret=");
- runtime·printslice(ret);
- runtime·prints("\n");
- }
-}
-
-// sliceslice1(old []any, lb uint64, width uint64) (ary []any);
-void
-runtime·sliceslice1(Slice old, uint64 lb, uint64 width, Slice ret)
-{
- if(lb > old.len) {
- if(debug) {
- runtime·prints("runtime.sliceslice: old=");
- runtime·printslice(old);
- runtime·prints("; lb=");
- runtime·printint(lb);
- runtime·prints("; width=");
- runtime·printint(width);
- runtime·prints("\n");
-
- runtime·prints("oldarray: nel=");
- runtime·printint(old.len);
- runtime·prints("; cap=");
- runtime·printint(old.cap);
- runtime·prints("\n");
- }
- runtime·panicslice();
- }
-
- // 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) {
- runtime·prints("runtime.sliceslice: old=");
- runtime·printslice(old);
- runtime·prints("; lb=");
- runtime·printint(lb);
- runtime·prints("; width=");
- runtime·printint(width);
- runtime·prints("; ret=");
- runtime·printslice(ret);
- runtime·prints("\n");
- }
-}
-
-// slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any);
-void
-runtime·slicearray(byte* old, uint64 nel, uint64 lb, uint64 hb, uint64 width, 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;
- }
-
- if(hb > nel || lb > hb) {
- if(debug) {
- runtime·prints("runtime.slicearray: old=");
- runtime·printpointer(old);
- runtime·prints("; nel=");
- runtime·printint(nel);
- runtime·prints("; lb=");
- runtime·printint(lb);
- runtime·prints("; hb=");
- runtime·printint(hb);
- runtime·prints("; width=");
- runtime·printint(width);
- runtime·prints("\n");
- }
- runtime·panicslice();
- }
-
- // new array is inside old array
- ret.len = hb-lb;
- ret.cap = nel-lb;
- ret.array = old + lb*width;
-
- FLUSH(&ret);
-
- if(debug) {
- runtime·prints("runtime.slicearray: old=");
- runtime·printpointer(old);
- runtime·prints("; nel=");
- runtime·printint(nel);
- runtime·prints("; lb=");
- runtime·printint(lb);
- runtime·prints("; hb=");
- runtime·printint(hb);
- runtime·prints("; width=");
- runtime·printint(width);
- runtime·prints("; ret=");
- runtime·printslice(ret);
- runtime·prints("\n");
- }
-}
-
// copy(to any, fr any, wid uint32) int
void
runtime·copy(Slice to, Slice fm, uintptr width, int32 ret)
return nil;
}
-func slicestring(si String, lindex int32, hindex int32) (so String) {
- int32 l;
-
- if(lindex < 0 || lindex > si.len ||
- hindex < lindex || hindex > si.len) {
- runtime·panicslice();
- }
-
- l = hindex-lindex;
- so.str = si.str + lindex;
- so.len = l;
-}
-
-func slicestring1(si String, lindex int32) (so String) {
- int32 l;
-
- if(lindex < 0 || lindex > si.len) {
- runtime·panicslice();
- }
-
- l = si.len-lindex;
- so.str = si.str + lindex;
- so.len = l;
-}
-
func intstring(v int64) (s String) {
s = gostringsize(8);
s.len = runtime·runetochar(s.str, v);