diff options
| author | Russ Cox <rsc@golang.org> | 2009-11-20 09:11:46 -0800 | 
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2009-11-20 09:11:46 -0800 | 
| commit | 0b471c4c0fdf44a4e354f21fcee1af058f95d31c (patch) | |
| tree | 500beae567fa23d8e061ccac78ba85f82a29c091 /src | |
| parent | ead3d7280bc61be1f5729b4c4b3e719c853d52ff (diff) | |
| download | golang-0b471c4c0fdf44a4e354f21fcee1af058f95d31c.tar.gz | |
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
http://codereview.appspot.com/157106
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/5g/gg.h | 2 | ||||
| -rw-r--r-- | src/cmd/5g/ggen.c | 380 | ||||
| -rw-r--r-- | src/cmd/6g/ggen.c | 121 | ||||
| -rw-r--r-- | src/cmd/8g/cgen.c | 4 | ||||
| -rw-r--r-- | src/cmd/8g/gg.h | 2 | ||||
| -rw-r--r-- | src/cmd/8g/ggen.c | 345 | ||||
| -rw-r--r-- | src/cmd/gc/builtin.c.boot | 2 | ||||
| -rw-r--r-- | src/cmd/gc/go.y | 8 | ||||
| -rw-r--r-- | src/cmd/gc/runtime.go | 2 | ||||
| -rw-r--r-- | src/cmd/gc/typecheck.c | 14 | ||||
| -rw-r--r-- | src/cmd/gc/walk.c | 53 | ||||
| -rw-r--r-- | src/pkg/runtime/hashmap.h | 1 | ||||
| -rw-r--r-- | src/pkg/runtime/runtime.c | 22 | ||||
| -rw-r--r-- | src/pkg/runtime/runtime.h | 2 | ||||
| -rw-r--r-- | src/pkg/runtime/slice.c | 74 | 
15 files changed, 887 insertions, 145 deletions
| diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h index 98e52788f..6477452b9 100644 --- a/src/cmd/5g/gg.h +++ b/src/cmd/5g/gg.h @@ -61,6 +61,7 @@ EXTERN	Node*	newproc;  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_callinter(Node*, Node*, int);  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 a22432009..e859f0578 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -22,6 +22,7 @@ compile(Node *fn)  		deferproc = sysfunc("deferproc");  		deferreturn = sysfunc("deferreturn");  		throwindex = sysfunc("throwindex"); +		throwslice = sysfunc("throwslice");  		throwreturn = sysfunc("throwreturn");  	} @@ -685,3 +686,382 @@ clearfat(Node *nl)  	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 5c0a22114..cf5614861 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -1131,7 +1131,7 @@ cgen_inline(Node *n, Node *res)  	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 @@ cgen_inline(Node *n, Node *res)  		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 @@ slicearray:  	}  	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 @@ sliceslice:  		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 @@ sliceslice:  			cgen(&nodes[0], &ntemp);  			nnode0 = ntemp;  		} -		getargs(n->list, nodes, 4); +		getargs(n->list, nodes, narg);  		if(!sleasy(res))  			nres = ntemp;  	} - -	// 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(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]) diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c index ee4df870a..b6b855de8 100644 --- a/src/cmd/8g/cgen.c +++ b/src/cmd/8g/cgen.c @@ -61,6 +61,10 @@ cgen(Node *n, Node *res)  	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 b36d0730b..3c0292cca 100644 --- a/src/cmd/8g/gg.h +++ b/src/cmd/8g/gg.h @@ -65,6 +65,7 @@ EXTERN	Node*	newproc;  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 @@ Prog*	gins(int, Node*, Node*);  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 7fc0aab70..c0a917be2 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -22,6 +22,7 @@ compile(Node *fn)  		deferproc = sysfunc("deferproc");  		deferreturn = sysfunc("deferreturn");  		throwindex = sysfunc("throwindex"); +		throwslice = sysfunc("throwslice");  		throwreturn = sysfunc("throwreturn");  	} @@ -740,4 +741,348 @@ cgen_bmul(int op, Node *nl, Node *nr, Node *res)  	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 8b794efdb..58d6f9e82 100644 --- a/src/cmd/gc/builtin.c.boot +++ b/src/cmd/gc/builtin.c.boot @@ -64,9 +64,9 @@ char *runtimeimport =  	"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 921ff1ed4..8413df64f 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -831,9 +831,13 @@ pexpr:  	{  		$$ = 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 1f078f2da..ea4084012 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -79,9 +79,9 @@ func selectdefault(sel *byte) (selected bool)  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 6dab9d761..fb96221bd 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -587,7 +587,7 @@ reswitch:  		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 @@ reswitch:  			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 9f3c81e19..bf35b3891 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -808,15 +808,26 @@ walkexpr(Node **np, NodeList **init)  		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 @@ walkexpr(Node **np, NodeList **init)  		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 @@ walkexpr(Node **np, NodeList **init)  		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 984b80cbd..9d821da6c 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 39fda9828..4a0309e0c 100644 --- a/src/pkg/runtime/runtime.c +++ b/src/pkg/runtime/runtime.c @@ -104,28 +104,6 @@ mcmp(byte *s1, byte *s2, uint32 n)  } -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 df1c45ae1..11dc489f2 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -342,7 +342,7 @@ void	printf(int8*, ...);  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 02839e27c..17762ae26 100644 --- a/src/pkg/runtime/slice.c +++ b/src/pkg/runtime/slice.c @@ -52,7 +52,6 @@ throwslice(uint32 lb, uint32 hb, uint32 n)  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 @@ runtime·sliceslice(Slice old, uint32 lb, uint32 hb, uint32 width, Slice ret)  	}  	// 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 @@ runtime·sliceslice(Slice old, uint32 lb, uint32 hb, uint32 width, Slice ret)  	}  } +// 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 @@ runtime·slicearray(byte* old, uint32 nel, uint32 lb, uint32 hb, uint32 width, S  	}  } -// 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) | 
