diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index fcdf7ead9af..ab712e5435e 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -35,6 +35,10 @@ cgen(Node *n, Node *res) if(initflag && gen_as_init(n, res)) goto ret; + // inline slices + if(cgen_inline(n, res)) + goto ret; + if(n->ullman >= UINF) { if(n->op == OINDREG) fatal("cgen: this is going to misscompile"); diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h index ca90762cf72..a2896bb153e 100644 --- a/src/cmd/6g/gg.h +++ b/src/cmd/6g/gg.h @@ -93,6 +93,7 @@ Prog* gins(int, Node*, Node*); int samaddr(Node*, Node*); void naddr(Node*, Addr*); void cgen_aret(Node*, Node*); +int cgen_inline(Node*, Node*); /* * gsubr.c diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index 5c2a8953b29..8bae9491770 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -1172,3 +1172,171 @@ yes: //print("%P\n", p); return 1; } + +void +getargs(NodeList *nn, Node *reg, int n) +{ + NodeList *l; + int i; + + l = nn; + for(i=0; in->right)) { + regalloc(reg+i, l->n->right->type, N); + cgen(l->n->right, reg+i); + } else + reg[i] = *l->n->right; + l = l->next; + } + // botch - need second pass to sort by offset +} + +void +cmpandthrow(Node *nodes, int l, int r) +{ + vlong cl, cr; + Prog *p1; + int op, c; + + op = OLE; + if(smallintconst(nodes+l)) { + cl = mpgetfix((nodes+l)->val.u.xval); + if(cl == 0) + return; + if(smallintconst(nodes+r)) { + cr = mpgetfix((nodes+r)->val.u.xval); + if(cl > cr) + ginscall(throwindex, 0); + return; + } + + // put the constant on the right + op = brrev(op); + c = l; + l = r; + r = c; + } + + gins(optoas(OCMP, types[TUINT32]), nodes+l, nodes+r); + p1 = gbranch(optoas(op, types[TUINT32]), T); + ginscall(throwindex, 0); + patch(p1, pc); +} + +// generate inline code for +// slicearray +// sliceslice +// arraytoslice +int +cgen_inline(Node *n, Node *res) +{ + Node nodes[10]; + Node n1, n2; + vlong v; + int i; + + if(n->op != OCALLFUNC) + goto no; + if(n->left->op != ONAME) + goto no; + if(!res->addable) + goto no; + if(strcmp(n->left->sym->package, "sys") != 0) + goto no; + if(strcmp(n->left->sym->name, "slicearray") == 0) + goto slicearray; + if(strcmp(n->left->sym->name, "sliceslice") == 0) + goto sliceslice; + if(strcmp(n->left->sym->name, "arraytoslice") == 0) + goto arraytoslice; + goto no; + +slicearray: + getargs(n->list, nodes, 5); + + // if(hb[3] > nel[1]) goto throw + cmpandthrow(nodes, 3, 1); + + // if(lb[2] > hb[3]) goto throw + cmpandthrow(nodes, 2, 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); + 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); + gins(optoas(OSUB, types[TUINT32]), nodes+2, &n1); + gins(optoas(OAS, types[TUINT32]), &n1, &n2); + regfree(&n1); + } + + // 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); + 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); + + // ret.len = hb[3]-lb[2]; + // ret.cap = nel[1]-lb[2]; + // ret.array = old[0] + lb[3]*width[4]; + for(i=0; i<5; i++) { + if(!smallintconst(nodes+i)) + regfree(nodes+i); + } + return 1; + +sliceslice: + // if(hb > old.cap) goto throw; + // if(lb > hb) goto throw; + // ret.len = hb-lb; + // ret.cap = old.cap - lb; + // ret.array = old.array + lb*width; + goto no; + +arraytoslice: + // ret.len = nel; + // ret.cap = nel; + // ret.array = old; + goto no; + +no: + return 0; +} diff --git a/test/ken/slicearray.go b/test/ken/slicearray.go new file mode 100644 index 00000000000..31faa9c783e --- /dev/null +++ b/test/ken/slicearray.go @@ -0,0 +1,127 @@ +// $G $D/$F.go && $L $F.$A && ./$A.out + +// Copyright 2009 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 main + +var bx [10]byte +var by []byte; +var fx [10]float +var fy []float; +var lb,hb int +var t int + +func +main() +{ + // width 1 (byte) + lb = 0; hb = 10; + by = bx[lb:hb]; tstb(); + by = bx[lb:10]; tstb(); + by = bx[0:hb]; tstb(); + by = bx[0:10]; tstb(); + + lb = 2; hb = 10; + by = bx[lb:hb]; tstb(); + by = bx[lb:10]; tstb(); + by = bx[2:hb]; tstb(); + by = bx[2:10]; tstb(); + + lb = 0; hb = 8; + by = bx[lb:hb]; tstb(); + by = bx[lb:8]; tstb(); + by = bx[0:hb]; tstb(); + by = bx[0:8]; tstb(); + + lb = 2; hb = 8; + by = bx[lb:hb]; tstb(); + by = bx[lb:8]; tstb(); + by = bx[2:hb]; tstb(); + by = bx[2:8]; tstb(); + + // width 4 (float) + lb = 0; hb = 10; + fy = fx[lb:hb]; tstf(); + fy = fx[lb:10]; tstf(); + fy = fx[0:hb]; tstf(); + fy = fx[0:10]; tstf(); + + lb = 2; hb = 10; + fy = fx[lb:hb]; tstf(); + fy = fx[lb:10]; tstf(); + fy = fx[2:hb]; tstf(); + fy = fx[2:10]; tstf(); + + lb = 0; hb = 8; + fy = fx[lb:hb]; tstf(); + fy = fx[lb:8]; tstf(); + fy = fx[0:hb]; tstf(); + fy = fx[0:8]; tstf(); + + lb = 2; hb = 8; + fy = fx[lb:hb]; tstf(); + fy = fx[lb:8]; tstf(); + fy = fx[2:hb]; tstf(); + fy = fx[2:8]; tstf(); +} + +func +tstb() +{ + t++; + if len(by) != hb-lb { + panicln("t=", t, "lb=", lb, "hb=", hb, + "len=", len(by), "hb-lb=", hb-lb); + } + if cap(by) != len(bx)-lb { + panicln("t=", t, "lb=", lb, "hb=", hb, + "cap=", cap(by), "len(bx)-lb=", len(bx)-lb); + } + for i:=lb; i