diff options
| author | Michael Stapelberg <stapelberg@debian.org> | 2013-03-04 21:27:36 +0100 | 
|---|---|---|
| committer | Michael Stapelberg <michael@stapelberg.de> | 2013-03-04 21:27:36 +0100 | 
| commit | 04b08da9af0c450d645ab7389d1467308cfc2db8 (patch) | |
| tree | db247935fa4f2f94408edc3acd5d0d4f997aa0d8 /src/cmd/8g/cgen.c | |
| parent | 917c5fb8ec48e22459d77e3849e6d388f93d3260 (diff) | |
| download | golang-04b08da9af0c450d645ab7389d1467308cfc2db8.tar.gz | |
Imported Upstream version 1.1~hg20130304upstream/1.1_hg20130304
Diffstat (limited to 'src/cmd/8g/cgen.c')
| -rw-r--r-- | src/cmd/8g/cgen.c | 703 | 
1 files changed, 449 insertions, 254 deletions
| diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c index 48619ac73..0b2f2b76e 100644 --- a/src/cmd/8g/cgen.c +++ b/src/cmd/8g/cgen.c @@ -49,7 +49,7 @@ mfree(Node *n)  void  cgen(Node *n, Node *res)  { -	Node *nl, *nr, *r, n1, n2, nt, f0, f1; +	Node *nl, *nr, *r, n1, n2, nt;  	Prog *p1, *p2, *p3;  	int a; @@ -63,9 +63,26 @@ cgen(Node *n, Node *res)  	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; +	case OEFACE: +		if (res->op != ONAME || !res->addable) { +			tempname(&n1, n->type); +			cgen_eface(n, &n1); +			cgen(&n1, res); +		} else +			cgen_eface(n, res);  		return; +	}  	while(n->op == OCONVNOP)  		n = n->left; @@ -160,6 +177,7 @@ cgen(Node *n, Node *res)  		case OADD:  		case OSUB:  		case OMUL: +		case OLROT:  		case OLSH:  		case ORSH:  		case OAND: @@ -170,8 +188,10 @@ cgen(Node *n, Node *res)  		}  	} -	if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) -		goto flt; +	if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) { +		cgen_float(n, res); +		return; +	}  	switch(n->op) {  	default: @@ -195,12 +215,12 @@ cgen(Node *n, Node *res)  	case OGE:  	case OGT:  	case ONOT: -		p1 = gbranch(AJMP, T); +		p1 = gbranch(AJMP, T, 0);  		p2 = pc;  		gmove(nodbool(1), res); -		p3 = gbranch(AJMP, T); +		p3 = gbranch(AJMP, T, 0);  		patch(p1, pc); -		bgen(n, 1, p2); +		bgen(n, 1, 0, p2);  		gmove(nodbool(0), res);  		patch(p3, pc);  		return; @@ -232,6 +252,10 @@ cgen(Node *n, Node *res)  		a = optoas(n->op, nl->type);  		goto abop; +	case OHMUL: +		cgen_hmul(nl, nr, res); +		break; +  	case OCONV:  		if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {  			cgen(nl, res); @@ -274,7 +298,7 @@ cgen(Node *n, Node *res)  			nodconst(&n2, types[tptr], 0);  			gins(optoas(OCMP, types[tptr]), &n1, &n2); -			p1 = gbranch(optoas(OEQ, types[tptr]), T); +			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);  			n2 = n1;  			n2.op = OINDREG; @@ -308,7 +332,7 @@ cgen(Node *n, Node *res)  			nodconst(&n2, types[tptr], 0);  			gins(optoas(OCMP, types[tptr]), &n1, &n2); -			p1 = gbranch(optoas(OEQ, types[tptr]), T); +			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);  			n2 = n1;  			n2.op = OINDREG; @@ -324,9 +348,8 @@ cgen(Node *n, Node *res)  		}  		if(isslice(nl->type)) {  			igen(nl, &n1, res); -			n1.op = OINDREG;  			n1.type = types[TUINT32]; -			n1.xoffset = Array_cap; +			n1.xoffset += Array_cap;  			gmove(&n1, res);  			regfree(&n1);  			break; @@ -360,20 +383,29 @@ cgen(Node *n, Node *res)  	case OLSH:  	case ORSH: -		cgen_shift(n->op, nl, nr, res); +	case OLROT: +		cgen_shift(n->op, n->bounded, nl, nr, res);  		break;  	}  	return;  sbop:	// symmetric binary -	if(nl->ullman < nr->ullman) { +	if(nl->ullman < nr->ullman || nl->op == OLITERAL) {  		r = nl;  		nl = nr;  		nr = r;  	}  abop:	// asymmetric binary -	if(nl->ullman >= nr->ullman) { +	if(smallintconst(nr)) { +		mgen(nl, &n1, res); +		regalloc(&n2, nl->type, &n1); +		gmove(&n1, &n2); +		gins(a, nr, &n2); +		gmove(&n2, res); +		regfree(&n2); +		mfree(&n1); +	} else if(nl->ullman >= nr->ullman) {  		tempname(&nt, nl->type);  		cgen(nl, &nt);  		mgen(nr, &n2, N); @@ -401,69 +433,42 @@ uop:	// unary  	gins(a, N, &n1);  	gmove(&n1, res);  	return; - -flt:	// floating-point.  387 (not SSE2) to interoperate with 8c -	nodreg(&f0, nl->type, D_F0); -	nodreg(&f1, n->type, D_F0+1); -	if(nr != N) -		goto flt2; - -	// unary -	cgen(nl, &f0); -	if(n->op != OCONV && n->op != OPLUS) -		gins(foptoas(n->op, n->type, 0), N, N); -	gmove(&f0, res); -	return; - -flt2:	// binary -	if(nl->ullman >= nr->ullman) { -		cgen(nl, &f0); -		if(nr->addable) -			gins(foptoas(n->op, n->type, 0), nr, &f0); -		else { -			cgen(nr, &f0); -			gins(foptoas(n->op, n->type, Fpop), &f0, &f1); -		} -	} else { -		cgen(nr, &f0); -		if(nl->addable) -			gins(foptoas(n->op, n->type, Frev), nl, &f0); -		else { -			cgen(nl, &f0); -			gins(foptoas(n->op, n->type, Frev|Fpop), &f0, &f1); -		} -	} -	gmove(&f0, res); -	return;  }  /* - * generate array index into res. - * n might be any size; res is 32-bit. + * generate an addressable node in res, containing the value of n. + * n is an array index, and might be any size; res width is <= 32-bit.   * returns Prog* to patch to panic call.   */ -Prog* -cgenindex(Node *n, Node *res) +static Prog* +igenindex(Node *n, Node *res, int bounded)  {  	Node tmp, lo, hi, zero;  	if(!is64(n->type)) { -		cgen(n, res); +		if(n->addable) { +			// nothing to do. +			*res = *n; +		} else { +			tempname(res, types[TUINT32]); +			cgen(n, res); +		}  		return nil;  	}  	tempname(&tmp, types[TINT64]);  	cgen(n, &tmp);  	split64(&tmp, &lo, &hi); +	tempname(res, types[TUINT32]);  	gmove(&lo, res); -	if(debug['B']) { +	if(bounded) {  		splitclean();  		return nil;  	}  	nodconst(&zero, types[TINT32], 0);  	gins(ACMPL, &hi, &zero);  	splitclean(); -	return gbranch(AJNE, T); +	return gbranch(AJNE, T, +1);  }  /* @@ -474,11 +479,12 @@ void  agen(Node *n, Node *res)  {  	Node *nl, *nr; -	Node n1, n2, n3, n4, tmp; +	Node n1, n2, n3, n4, tmp, nlen;  	Type *t;  	uint32 w;  	uint64 v;  	Prog *p1, *p2; +	int bounded;  	if(debug['g']) {  		dump("\nagen-res", res); @@ -490,6 +496,20 @@ agen(Node *n, Node *res)  	while(n->op == OCONVNOP)  		n = n->left; +	if(isconst(n, CTNIL) && n->type->width > widthptr) { +		// Use of a nil interface or nil slice. +		// Create a temporary we can take the address of and read. +		// The generated code is just going to panic, so it need not +		// be terribly efficient. See issue 3670. +		tempname(&n1, n->type); +		clearfat(&n1); +		regalloc(&n2, types[tptr], res); +		gins(ALEAL, &n1, &n2); +		gmove(&n2, res); +		regfree(&n2); +		return; +	} +		  	// addressable var is easy  	if(n->addable) {  		if(n->op == OREGISTER) @@ -524,113 +544,136 @@ agen(Node *n, Node *res)  		cgen_aret(n, res);  		break; +	case OSLICE: +	case OSLICEARR: +	case OSLICESTR: +		tempname(&n1, n->type); +		cgen_slice(n, &n1); +		agen(&n1, res); +		break; + +	case OEFACE: +		tempname(&n1, n->type); +		cgen_eface(n, &n1); +		agen(&n1, res); +		break; +  	case OINDEX:  		p2 = nil;  // to be patched to panicindex.  		w = n->type->width; +		bounded = debug['B'] || n->bounded;  		if(nr->addable) { -			if(!isconst(nr, CTINT)) -				tempname(&tmp, types[TINT32]); +			// Generate &nl first, and move nr into register.  			if(!isconst(nl, CTSTR)) -				agenr(nl, &n3, res); +				igen(nl, &n3, res);  			if(!isconst(nr, CTINT)) { -				p2 = cgenindex(nr, &tmp); +				p2 = igenindex(nr, &tmp, bounded);  				regalloc(&n1, tmp.type, N);  				gmove(&tmp, &n1);  			}  		} else if(nl->addable) { +			// Generate nr first, and move &nl into register.  			if(!isconst(nr, CTINT)) { -				tempname(&tmp, types[TINT32]); -				p2 = cgenindex(nr, &tmp); +				p2 = igenindex(nr, &tmp, bounded);  				regalloc(&n1, tmp.type, N);  				gmove(&tmp, &n1);  			} -			if(!isconst(nl, CTSTR)) { -				regalloc(&n3, types[tptr], res); -				agen(nl, &n3); -			} +			if(!isconst(nl, CTSTR)) +				igen(nl, &n3, res);  		} else { -			tempname(&tmp, types[TINT32]); -			p2 = cgenindex(nr, &tmp); +			p2 = igenindex(nr, &tmp, bounded);  			nr = &tmp;  			if(!isconst(nl, CTSTR)) -				agenr(nl, &n3, res); +				igen(nl, &n3, res);  			regalloc(&n1, tmp.type, N);  			gins(optoas(OAS, tmp.type), &tmp, &n1);  		} -		// &a is in &n3 (allocated in res) -		// i is in &n1 (if not constant) +		// For fixed array we really want the pointer in n3. +		if(isfixedarray(nl->type)) { +			regalloc(&n2, types[tptr], &n3); +			agen(&n3, &n2); +			regfree(&n3); +			n3 = n2; +		} + +		// &a[0] is in n3 (allocated in res) +		// i is in n1 (if not constant) +		// len(a) is in nlen (if needed)  		// w is width  		// explicit check for nil if array is large enough  		// that we might derive too big a pointer.  		if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) { -			regalloc(&n4, types[tptr], &n3); -			gmove(&n3, &n4); +			n4 = n3;  			n4.op = OINDREG;  			n4.type = types[TUINT8];  			n4.xoffset = 0;  			gins(ATESTB, nodintconst(0), &n4); -			regfree(&n4);  		}  		// constant index  		if(isconst(nr, CTINT)) {  			if(isconst(nl, CTSTR)) -				fatal("constant string constant index"); +				fatal("constant string constant index");  // front end should handle  			v = mpgetfix(nr->val.u.xval);  			if(isslice(nl->type) || nl->type->etype == TSTRING) { -				if(!debug['B'] && !n->etype) { -					n1 = n3; -					n1.op = OINDREG; -					n1.type = types[tptr]; -					n1.xoffset = Array_nel; +				if(!debug['B'] && !n->bounded) { +					nlen = n3; +					nlen.type = types[TUINT32]; +					nlen.xoffset += Array_nel;  					nodconst(&n2, types[TUINT32], v); -					gins(optoas(OCMP, types[TUINT32]), &n1, &n2); -					p1 = gbranch(optoas(OGT, types[TUINT32]), T); -					ginscall(panicindex, 0); +					gins(optoas(OCMP, types[TUINT32]), &nlen, &n2); +					p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1); +					ginscall(panicindex, -1);  					patch(p1, pc);  				} - -				n1 = n3; -				n1.op = OINDREG; -				n1.type = types[tptr]; -				n1.xoffset = Array_array; -				gmove(&n1, &n3);  			} +			// Load base pointer in n2 = n3. +			regalloc(&n2, types[tptr], &n3); +			n3.type = types[tptr]; +			n3.xoffset += Array_array; +			gmove(&n3, &n2); +			regfree(&n3);  			if (v*w != 0) { -				nodconst(&n2, types[tptr], v*w); -				gins(optoas(OADD, types[tptr]), &n2, &n3); +				nodconst(&n1, types[tptr], v*w); +				gins(optoas(OADD, types[tptr]), &n1, &n2);  			} -			gmove(&n3, res); -			regfree(&n3); +			gmove(&n2, res); +			regfree(&n2);  			break;  		} -		regalloc(&n2, types[TINT32], &n1);			// i +		// i is in register n1, extend to 32 bits. +		t = types[TUINT32]; +		if(issigned[n1.type->etype]) +			t = types[TINT32]; + +		regalloc(&n2, t, &n1);			// i  		gmove(&n1, &n2);  		regfree(&n1); -		if(!debug['B'] && !n->etype) { +		if(!debug['B'] && !n->bounded) {  			// check bounds -			if(isconst(nl, CTSTR)) -				nodconst(&n1, types[TUINT32], nl->val.u.sval->len); -			else if(isslice(nl->type) || nl->type->etype == TSTRING) { -				n1 = n3; -				n1.op = OINDREG; -				n1.type = types[tptr]; -				n1.xoffset = Array_nel; -			} else -				nodconst(&n1, types[TUINT32], nl->type->bound); -			gins(optoas(OCMP, types[TUINT32]), &n2, &n1); -			p1 = gbranch(optoas(OLT, types[TUINT32]), T); +			t = types[TUINT32]; +			if(isconst(nl, CTSTR)) { +				nodconst(&nlen, t, nl->val.u.sval->len); +			} else if(isslice(nl->type) || nl->type->etype == TSTRING) { +				nlen = n3; +				nlen.type = t; +				nlen.xoffset += Array_nel; +			} else { +				nodconst(&nlen, t, nl->type->bound); +			} +			gins(optoas(OCMP, t), &n2, &nlen); +			p1 = gbranch(optoas(OLT, t), T, +1);  			if(p2)  				patch(p2, pc); -			ginscall(panicindex, 0); +			ginscall(panicindex, -1);  			patch(p1, pc);  		} -		 +  		if(isconst(nl, CTSTR)) {  			regalloc(&n3, types[tptr], res);  			p1 = gins(ALEAL, N, &n3); @@ -640,24 +683,27 @@ agen(Node *n, Node *res)  			goto indexdone;  		} +		// Load base pointer in n3. +		regalloc(&tmp, types[tptr], &n3);  		if(isslice(nl->type) || nl->type->etype == TSTRING) { -			n1 = n3; -			n1.op = OINDREG; -			n1.type = types[tptr]; -			n1.xoffset = Array_array; -			gmove(&n1, &n3); +			n3.type = types[tptr]; +			n3.xoffset += Array_array; +			gmove(&n3, &tmp);  		} +		regfree(&n3); +		n3 = tmp;  		if(w == 0) {  			// nothing to do  		} else if(w == 1 || w == 2 || w == 4 || w == 8) { +			// LEAL (n3)(n2*w), n3  			p1 = gins(ALEAL, &n2, &n3);  			p1->from.scale = w;  			p1->from.index = p1->from.type;  			p1->from.type = p1->to.type + D_INDIR;  		} else { -			nodconst(&n1, types[TUINT32], w); -			gins(optoas(OMUL, types[TUINT32]), &n1, &n2); +			nodconst(&tmp, types[TUINT32], w); +			gins(optoas(OMUL, types[TUINT32]), &tmp, &n2);  			gins(optoas(OADD, types[tptr]), &n2, &n3);  		} @@ -734,20 +780,82 @@ agen(Node *n, Node *res)  void  igen(Node *n, Node *a, Node *res)  { -	Node n1;  	Type *fp;  	Iter flist; -   +	Node n1; + +	if(debug['g']) { +		dump("\nigen-n", n); +	}  	switch(n->op) {  	case ONAME:  		if((n->class&PHEAP) || n->class == PPARAMREF)  			break;  		*a = *n;  		return; -  + +	case OINDREG: +		// Increase the refcount of the register so that igen's caller +		// has to call regfree. +		if(n->val.u.reg != D_SP) +			reg[n->val.u.reg]++; +		*a = *n; +		return; + +	case ODOT: +		igen(n->left, a, res); +		a->xoffset += n->xoffset; +		a->type = n->type; +		return; + +	case ODOTPTR: +		switch(n->left->op) { +		case ODOT: +		case ODOTPTR: +		case OCALLFUNC: +		case OCALLMETH: +		case OCALLINTER: +			// igen-able nodes. +			igen(n->left, &n1, res); +			regalloc(a, types[tptr], &n1); +			gmove(&n1, a); +			regfree(&n1); +			break; +		default: +			regalloc(a, types[tptr], res); +			cgen(n->left, a); +		} +		if(n->xoffset != 0) { +			// explicit check for nil if struct is large enough +			// that we might derive too big a pointer. +			if(n->left->type->type->width >= unmappedzero) { +				n1 = *a; +				n1.op = OINDREG; +				n1.type = types[TUINT8]; +				n1.xoffset = 0; +				gins(ATESTB, nodintconst(0), &n1); +			} +		} +		a->op = OINDREG; +		a->xoffset += n->xoffset; +		a->type = n->type; +		return; +  	case OCALLFUNC: +	case OCALLMETH: +	case OCALLINTER: +		switch(n->op) { +		case OCALLFUNC: +			cgen_call(n, 0); +			break; +		case OCALLMETH: +			cgen_callmeth(n, 0); +			break; +		case OCALLINTER: +			cgen_callinter(n, N, 0); +			break; +		}  		fp = structfirst(&flist, getoutarg(n->left->type)); -		cgen_call(n, 0);  		memset(a, 0, sizeof *a);  		a->op = OINDREG;  		a->val.u.reg = D_SP; @@ -771,33 +879,15 @@ igen(Node *n, Node *a, Node *res)  }  /* - * generate: - *	newreg = &n; - * - * caller must regfree(a). - */ -void -agenr(Node *n, Node *a, Node *res) -{ -	Node n1; - -	tempname(&n1, types[tptr]); -	agen(n, &n1); -	regalloc(a, types[tptr], res); -	gmove(&n1, a); -} - -/*   * branch gen   *	if(n == true) goto to;   */  void -bgen(Node *n, int true, Prog *to) +bgen(Node *n, int true, int likely, Prog *to)  {  	int et, a;  	Node *nl, *nr, *r; -	Node n1, n2, tmp, t1, t2, ax; -	NodeList *ll; +	Node n1, n2, tmp;  	Prog *p1, *p2;  	if(debug['g']) { @@ -822,8 +912,14 @@ bgen(Node *n, int true, Prog *to)  		patch(gins(AEND, N, N), to);  		return;  	} +	nl = n->left;  	nr = N; +	if(nl != N && isfloat[nl->type->etype]) { +		bgen_float(n, true, likely, to); +		return; +	} +  	switch(n->op) {  	default:  	def: @@ -834,14 +930,14 @@ bgen(Node *n, int true, Prog *to)  		a = AJNE;  		if(!true)  			a = AJEQ; -		patch(gbranch(a, n->type), to); +		patch(gbranch(a, n->type, likely), to);  		regfree(&n1);  		return;  	case OLITERAL:  		// need to ask if it is bool?  		if(!true == !n->val.u.bval) -			patch(gbranch(AJMP, T), to); +			patch(gbranch(AJMP, T, 0), to);  		return;  	case ONAME: @@ -852,7 +948,7 @@ bgen(Node *n, int true, Prog *to)  		a = AJNE;  		if(!true)  			a = AJEQ; -		patch(gbranch(a, n->type), to); +		patch(gbranch(a, n->type, likely), to);  		return;  	case OANDAND: @@ -860,12 +956,12 @@ bgen(Node *n, int true, Prog *to)  			goto caseor;  	caseand: -		p1 = gbranch(AJMP, T); -		p2 = gbranch(AJMP, T); +		p1 = gbranch(AJMP, T, 0); +		p2 = gbranch(AJMP, T, 0);  		patch(p1, pc); -		bgen(n->left, !true, p2); -		bgen(n->right, !true, p2); -		p1 = gbranch(AJMP, T); +		bgen(n->left, !true, -likely, p2); +		bgen(n->right, !true, -likely, p2); +		p1 = gbranch(AJMP, T, 0);  		patch(p1, to);  		patch(p2, pc);  		return; @@ -875,8 +971,8 @@ bgen(Node *n, int true, Prog *to)  			goto caseand;  	caseor: -		bgen(n->left, true, to); -		bgen(n->right, true, to); +		bgen(n->left, true, likely, to); +		bgen(n->right, true, likely, to);  		return;  	case OEQ: @@ -897,7 +993,7 @@ bgen(Node *n, int true, Prog *to)  	switch(n->op) {  	case ONOT: -		bgen(nl, !true, to); +		bgen(nl, !true, likely, to);  		break;  	case OEQ: @@ -908,19 +1004,6 @@ bgen(Node *n, int true, Prog *to)  	case OGE:  		a = n->op;  		if(!true) { -			if(isfloat[nl->type->etype]) { -				// brcom is not valid on floats when NaN is involved. -				p1 = gbranch(AJMP, T); -				p2 = gbranch(AJMP, T); -				patch(p1, pc); -				ll = n->ninit;  // avoid re-genning ninit -				n->ninit = nil; -				bgen(n, 1, p2); -				n->ninit = ll; -				patch(gbranch(AJMP, T), to); -				patch(p2, pc); -				break; -			}				  			a = brcom(a);  			true = !true;  		} @@ -936,19 +1019,16 @@ bgen(Node *n, int true, Prog *to)  		if(isslice(nl->type)) {  			// front end should only leave cmp to literal nil  			if((a != OEQ && a != ONE) || nr->op != OLITERAL) { -				yyerror("illegal array comparison"); +				yyerror("illegal slice comparison");  				break;  			}  			a = optoas(a, types[tptr]); -			regalloc(&n1, types[tptr], N); -			agen(nl, &n1); -			n2 = n1; -			n2.op = OINDREG; -			n2.xoffset = Array_array; -			n2.type = types[tptr]; +			igen(nl, &n1, N); +			n1.xoffset += Array_array; +			n1.type = types[tptr];  			nodconst(&tmp, types[tptr], 0); -			gins(optoas(OCMP, types[tptr]), &n2, &tmp); -			patch(gbranch(a, types[tptr]), to); +			gins(optoas(OCMP, types[tptr]), &n1, &tmp); +			patch(gbranch(a, types[tptr], likely), to);  			regfree(&n1);  			break;  		} @@ -960,75 +1040,17 @@ bgen(Node *n, int true, Prog *to)  				break;  			}  			a = optoas(a, types[tptr]); -			regalloc(&n1, types[tptr], N); -			agen(nl, &n1); -			n2 = n1; -			n2.op = OINDREG; -			n2.xoffset = 0; +			igen(nl, &n1, N); +			n1.type = types[tptr];  			nodconst(&tmp, types[tptr], 0); -			gins(optoas(OCMP, types[tptr]), &n2, &tmp); -			patch(gbranch(a, types[tptr]), to); +			gins(optoas(OCMP, types[tptr]), &n1, &tmp); +			patch(gbranch(a, types[tptr], likely), to);  			regfree(&n1);  			break;  		} -		if(isfloat[nr->type->etype]) { -			a = brrev(a);	// because the args are stacked -			if(a == OGE || a == OGT) { -				// only < and <= work right with NaN; reverse if needed -				r = nr; -				nr = nl; -				nl = r; -				a = brrev(a); -			} -			nodreg(&tmp, nr->type, D_F0); -			nodreg(&n2, nr->type, D_F0 + 1); -			nodreg(&ax, types[TUINT16], D_AX); -			et = simsimtype(nr->type); -			if(et == TFLOAT64) { -				if(nl->ullman > nr->ullman) { -					cgen(nl, &tmp); -					cgen(nr, &tmp); -					gins(AFXCHD, &tmp, &n2); -				} else { -					cgen(nr, &tmp); -					cgen(nl, &tmp); -				} -				gins(AFUCOMIP, &tmp, &n2); -				gins(AFMOVDP, &tmp, &tmp);	// annoying pop but still better than STSW+SAHF -			} else { -				// TODO(rsc): The moves back and forth to memory -				// here are for truncating the value to 32 bits. -				// This handles 32-bit comparison but presumably -				// all the other ops have the same problem. -				// We need to figure out what the right general -				// solution is, besides telling people to use float64. -				tempname(&t1, types[TFLOAT32]); -				tempname(&t2, types[TFLOAT32]); -				cgen(nr, &t1); -				cgen(nl, &t2); -				gmove(&t2, &tmp); -				gins(AFCOMFP, &t1, &tmp); -				gins(AFSTSW, N, &ax); -				gins(ASAHF, N, N); -			} -			if(a == OEQ) { -				// neither NE nor P -				p1 = gbranch(AJNE, T); -				p2 = gbranch(AJPS, T); -				patch(gbranch(AJMP, T), to); -				patch(p1, pc); -				patch(p2, pc); -			} else if(a == ONE) { -				// either NE or P -				patch(gbranch(AJNE, T), to); -				patch(gbranch(AJPS, T), to); -			} else -				patch(gbranch(optoas(a, nr->type), T), to); -			break; -		}  		if(iscomplex[nl->type->etype]) { -			complexbool(a, nl, nr, true, to); +			complexbool(a, nl, nr, true, likely, to);  			break;  		} @@ -1043,40 +1065,55 @@ bgen(Node *n, int true, Prog *to)  				cgen(nr, &n2);  				nr = &n2;  			} -			cmp64(nl, nr, a, to); +			cmp64(nl, nr, a, likely, to);  			break;  		} -		a = optoas(a, nr->type); -  		if(nr->ullman >= UINF) { -			tempname(&n1, nl->type); -			tempname(&tmp, nr->type); -			cgen(nl, &n1); -			cgen(nr, &tmp); +			if(!nl->addable) { +				tempname(&n1, nl->type); +				cgen(nl, &n1); +				nl = &n1; +			} +			if(!nr->addable) { +				tempname(&tmp, nr->type); +				cgen(nr, &tmp); +				nr = &tmp; +			}  			regalloc(&n2, nr->type, N); -			cgen(&tmp, &n2); +			cgen(nr, &n2); +			nr = &n2;  			goto cmp;  		} -		tempname(&n1, nl->type); -		cgen(nl, &n1); +		if(!nl->addable) { +			tempname(&n1, nl->type); +			cgen(nl, &n1); +			nl = &n1; +		}  		if(smallintconst(nr)) { -			gins(optoas(OCMP, nr->type), &n1, nr); -			patch(gbranch(a, nr->type), to); +			gins(optoas(OCMP, nr->type), nl, nr); +			patch(gbranch(optoas(a, nr->type), nr->type, likely), to);  			break;  		} -		tempname(&tmp, nr->type); -		cgen(nr, &tmp); +		if(!nr->addable) { +			tempname(&tmp, nr->type); +			cgen(nr, &tmp); +			nr = &tmp; +		}  		regalloc(&n2, nr->type, N); -		gmove(&tmp, &n2); +		gmove(nr, &n2); +		nr = &n2;  cmp: -		gins(optoas(OCMP, nr->type), &n1, &n2); -		patch(gbranch(a, nr->type), to); -		regfree(&n2); +		gins(optoas(OCMP, nr->type), nl, nr); +		patch(gbranch(optoas(a, nr->type), nr->type, likely), to); + +		if(nl->op == OREGISTER) +			regfree(nl); +		regfree(nr);  		break;  	}  } @@ -1164,6 +1201,10 @@ sgen(Node *n, Node *res, int64 w)  		return;  	} +	// Avoid taking the address for simple enough types. +	if(componentgen(n, res)) +		return; +  	// offset on the stack  	osrc = stkof(n);  	odst = stkof(res); @@ -1247,3 +1288,157 @@ sgen(Node *n, Node *res, int64 w)  	}  } +static int +cadable(Node *n) +{ +	if(!n->addable) { +		// dont know how it happens, +		// but it does +		return 0; +	} + +	switch(n->op) { +	case ONAME: +		return 1; +	} +	return 0; +} + +/* + * copy a composite value by moving its individual components. + * Slices, strings and interfaces are supported. + * nr is N when assigning a zero value. + * return 1 if can do, 0 if cant. + */ +int +componentgen(Node *nr, Node *nl) +{ +	Node nodl, nodr; +	int freel, freer; + +	freel = 0; +	freer = 0; + +	switch(nl->type->etype) { +	default: +		goto no; + +	case TARRAY: +		if(!isslice(nl->type)) +			goto no; +	case TSTRING: +	case TINTER: +		break; +	} + +	nodl = *nl; +	if(!cadable(nl)) { +		if(nr == N || !cadable(nr)) +			goto no; +		igen(nl, &nodl, N); +		freel = 1; +	} + +	if(nr != N) { +		nodr = *nr; +		if(!cadable(nr)) { +			igen(nr, &nodr, N); +			freer = 1; +		} +	} + +	switch(nl->type->etype) { +	case TARRAY: +		nodl.xoffset += Array_array; +		nodl.type = ptrto(nl->type->type); + +		if(nr != N) { +			nodr.xoffset += Array_array; +			nodr.type = nodl.type; +		} else +			nodconst(&nodr, nodl.type, 0); +		gmove(&nodr, &nodl); + +		nodl.xoffset += Array_nel-Array_array; +		nodl.type = types[TUINT32]; + +		if(nr != N) { +			nodr.xoffset += Array_nel-Array_array; +			nodr.type = nodl.type; +		} else +			nodconst(&nodr, nodl.type, 0); +		gmove(&nodr, &nodl); + +		nodl.xoffset += Array_cap-Array_nel; +		nodl.type = types[TUINT32]; + +		if(nr != N) { +			nodr.xoffset += Array_cap-Array_nel; +			nodr.type = nodl.type; +		} else +			nodconst(&nodr, nodl.type, 0); +		gmove(&nodr, &nodl); + +		goto yes; + +	case TSTRING: +		nodl.xoffset += Array_array; +		nodl.type = ptrto(types[TUINT8]); + +		if(nr != N) { +			nodr.xoffset += Array_array; +			nodr.type = nodl.type; +		} else +			nodconst(&nodr, nodl.type, 0); +		gmove(&nodr, &nodl); + +		nodl.xoffset += Array_nel-Array_array; +		nodl.type = types[TUINT32]; + +		if(nr != N) { +			nodr.xoffset += Array_nel-Array_array; +			nodr.type = nodl.type; +		} else +			nodconst(&nodr, nodl.type, 0); +		gmove(&nodr, &nodl); + +		goto yes; + +	case TINTER: +		nodl.xoffset += Array_array; +		nodl.type = ptrto(types[TUINT8]); + +		if(nr != N) { +			nodr.xoffset += Array_array; +			nodr.type = nodl.type; +		} else +			nodconst(&nodr, nodl.type, 0); +		gmove(&nodr, &nodl); + +		nodl.xoffset += Array_nel-Array_array; +		nodl.type = ptrto(types[TUINT8]); + +		if(nr != N) { +			nodr.xoffset += Array_nel-Array_array; +			nodr.type = nodl.type; +		} else +			nodconst(&nodr, nodl.type, 0); +		gmove(&nodr, &nodl); + +		goto yes; +	} + +no: +	if(freer) +		regfree(&nodr); +	if(freel) +		regfree(&nodl); +	return 0; + +yes: +	if(freer) +		regfree(&nodr); +	if(freel) +		regfree(&nodl); +	return 1; +} | 
