xref: /plan9-contrib/sys/src/cmd/qc/cgen.c (revision 40d015479ed36701ae6dcfd8814f849fc6285e8d)
17dd7cddfSDavid du Colombier #include "gc.h"
27dd7cddfSDavid du Colombier 
36891d857SDavid du Colombier static void cmpv(Node*, int, Node*);
46891d857SDavid du Colombier static void testv(Node*, int);
56891d857SDavid du Colombier static void cgen64(Node*, Node*);
66891d857SDavid du Colombier static int isvconstable(int, vlong);
7*40d01547SDavid du Colombier static void genasop(int, Node*, Node*, Node*);
86891d857SDavid du Colombier 
97dd7cddfSDavid du Colombier void
cgen(Node * n,Node * nn)107dd7cddfSDavid du Colombier cgen(Node *n, Node *nn)
117dd7cddfSDavid du Colombier {
127dd7cddfSDavid du Colombier 	Node *l, *r;
137dd7cddfSDavid du Colombier 	Prog *p1;
147dd7cddfSDavid du Colombier 	Node nod, nod1, nod2, nod3, nod4;
157dd7cddfSDavid du Colombier 	int o;
167dd7cddfSDavid du Colombier 	long v, curs;
177dd7cddfSDavid du Colombier 
187dd7cddfSDavid du Colombier 	if(debug['g']) {
197dd7cddfSDavid du Colombier 		prtree(nn, "cgen lhs");
207dd7cddfSDavid du Colombier 		prtree(n, "cgen");
217dd7cddfSDavid du Colombier 	}
227dd7cddfSDavid du Colombier 	if(n == Z || n->type == T)
237dd7cddfSDavid du Colombier 		return;
246891d857SDavid du Colombier 	if(typesu[n->type->etype]) {
257dd7cddfSDavid du Colombier 		sugen(n, nn, n->type->width);
267dd7cddfSDavid du Colombier 		return;
277dd7cddfSDavid du Colombier 	}
286891d857SDavid du Colombier 	if(typev[n->type->etype]) {
296891d857SDavid du Colombier 		switch(n->op) {
306891d857SDavid du Colombier 		case OCONST:
316891d857SDavid du Colombier 		case OFUNC:
326891d857SDavid du Colombier 			cgen64(n, nn);
336891d857SDavid du Colombier 			return;
346891d857SDavid du Colombier 		}
356891d857SDavid du Colombier 	}
367dd7cddfSDavid du Colombier 	l = n->left;
377dd7cddfSDavid du Colombier 	r = n->right;
387dd7cddfSDavid du Colombier 	o = n->op;
397dd7cddfSDavid du Colombier 	if(n->addable >= INDEXED) {
407dd7cddfSDavid du Colombier 		if(nn == Z) {
417dd7cddfSDavid du Colombier 			switch(o) {
427dd7cddfSDavid du Colombier 			default:
437dd7cddfSDavid du Colombier 				nullwarn(Z, Z);
447dd7cddfSDavid du Colombier 				break;
457dd7cddfSDavid du Colombier 			case OINDEX:
467dd7cddfSDavid du Colombier 				nullwarn(l, r);
477dd7cddfSDavid du Colombier 				break;
487dd7cddfSDavid du Colombier 			}
497dd7cddfSDavid du Colombier 			return;
507dd7cddfSDavid du Colombier 		}
517dd7cddfSDavid du Colombier 		gmove(n, nn);
527dd7cddfSDavid du Colombier 		return;
537dd7cddfSDavid du Colombier 	}
547dd7cddfSDavid du Colombier 	curs = cursafe;
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier 	if(n->complex >= FNX)
577dd7cddfSDavid du Colombier 	if(l->complex >= FNX)
587dd7cddfSDavid du Colombier 	if(r != Z && r->complex >= FNX)
597dd7cddfSDavid du Colombier 	switch(o) {
607dd7cddfSDavid du Colombier 	default:
616891d857SDavid du Colombier 		if(!typev[r->type->etype]) {
627dd7cddfSDavid du Colombier 			regret(&nod, r);
637dd7cddfSDavid du Colombier 			cgen(r, &nod);
647dd7cddfSDavid du Colombier 			regsalloc(&nod1, r);
656891d857SDavid du Colombier 			gmove(&nod, &nod1);
667dd7cddfSDavid du Colombier 			regfree(&nod);
676891d857SDavid du Colombier 		} else {
686891d857SDavid du Colombier 			regsalloc(&nod1, r);
696891d857SDavid du Colombier 			cgen(r, &nod1);
706891d857SDavid du Colombier 		}
716891d857SDavid du Colombier 
727dd7cddfSDavid du Colombier 		nod = *n;
737dd7cddfSDavid du Colombier 		nod.right = &nod1;
747dd7cddfSDavid du Colombier 		cgen(&nod, nn);
757dd7cddfSDavid du Colombier 		return;
767dd7cddfSDavid du Colombier 
777dd7cddfSDavid du Colombier 	case OFUNC:
787dd7cddfSDavid du Colombier 	case OCOMMA:
797dd7cddfSDavid du Colombier 	case OANDAND:
807dd7cddfSDavid du Colombier 	case OOROR:
817dd7cddfSDavid du Colombier 	case OCOND:
827dd7cddfSDavid du Colombier 	case ODOT:
837dd7cddfSDavid du Colombier 		break;
847dd7cddfSDavid du Colombier 	}
857dd7cddfSDavid du Colombier 
867dd7cddfSDavid du Colombier 	switch(o) {
877dd7cddfSDavid du Colombier 	default:
887dd7cddfSDavid du Colombier 		diag(n, "unknown op in cgen: %O", o);
897dd7cddfSDavid du Colombier 		break;
907dd7cddfSDavid du Colombier 
916891d857SDavid du Colombier 	case ONEG:
926891d857SDavid du Colombier 	case OCOM:
936891d857SDavid du Colombier 		if(nn == Z) {
946891d857SDavid du Colombier 			nullwarn(l, Z);
956891d857SDavid du Colombier 			break;
966891d857SDavid du Colombier 		}
976891d857SDavid du Colombier 		regalloc(&nod, l, nn);
986891d857SDavid du Colombier 		cgen(l, &nod);
996891d857SDavid du Colombier 		gopcode(o, &nod, Z, &nod);
1006891d857SDavid du Colombier 		gmove(&nod, nn);
1016891d857SDavid du Colombier 		regfree(&nod);
1026891d857SDavid du Colombier 		break;
1036891d857SDavid du Colombier 
1047dd7cddfSDavid du Colombier 	case OAS:
1057dd7cddfSDavid du Colombier 		if(l->op == OBIT)
1067dd7cddfSDavid du Colombier 			goto bitas;
1077dd7cddfSDavid du Colombier 		if(l->addable >= INDEXED) {
1087dd7cddfSDavid du Colombier 			if(nn != Z || r->addable < INDEXED) {
1097dd7cddfSDavid du Colombier 				regalloc(&nod, r, nn);
1107dd7cddfSDavid du Colombier 				cgen(r, &nod);
1117dd7cddfSDavid du Colombier 				gmove(&nod, l);
1127dd7cddfSDavid du Colombier 				regfree(&nod);
1137dd7cddfSDavid du Colombier 			} else
1147dd7cddfSDavid du Colombier 				gmove(r, l);
1157dd7cddfSDavid du Colombier 			break;
1167dd7cddfSDavid du Colombier 		}
1177dd7cddfSDavid du Colombier 		if(l->complex >= r->complex) {
1187dd7cddfSDavid du Colombier 			reglcgen(&nod1, l, Z);
1197dd7cddfSDavid du Colombier 			if(r->addable >= INDEXED) {
1207dd7cddfSDavid du Colombier 				gmove(r, &nod1);
1217dd7cddfSDavid du Colombier 				if(nn != Z)
1227dd7cddfSDavid du Colombier 					gmove(r, nn);
1237dd7cddfSDavid du Colombier 				regfree(&nod1);
1247dd7cddfSDavid du Colombier 				break;
1257dd7cddfSDavid du Colombier 			}
1267dd7cddfSDavid du Colombier 			regalloc(&nod, r, nn);
1277dd7cddfSDavid du Colombier 			cgen(r, &nod);
1287dd7cddfSDavid du Colombier 		} else {
1297dd7cddfSDavid du Colombier 			regalloc(&nod, r, nn);
1307dd7cddfSDavid du Colombier 			cgen(r, &nod);
1317dd7cddfSDavid du Colombier 			reglcgen(&nod1, l, Z);
1327dd7cddfSDavid du Colombier 		}
1337dd7cddfSDavid du Colombier 		gmove(&nod, &nod1);
1347dd7cddfSDavid du Colombier 		regfree(&nod);
1357dd7cddfSDavid du Colombier 		regfree(&nod1);
1367dd7cddfSDavid du Colombier 		break;
1377dd7cddfSDavid du Colombier 
1387dd7cddfSDavid du Colombier 	bitas:
1397dd7cddfSDavid du Colombier 		n = l->left;
1407dd7cddfSDavid du Colombier 		regalloc(&nod, r, nn);
1417dd7cddfSDavid du Colombier 		if(l->complex >= r->complex) {
1427dd7cddfSDavid du Colombier 			reglcgen(&nod1, n, Z);
1437dd7cddfSDavid du Colombier 			cgen(r, &nod);
1447dd7cddfSDavid du Colombier 		} else {
1457dd7cddfSDavid du Colombier 			cgen(r, &nod);
1467dd7cddfSDavid du Colombier 			reglcgen(&nod1, n, Z);
1477dd7cddfSDavid du Colombier 		}
1487dd7cddfSDavid du Colombier 		regalloc(&nod2, n, Z);
1497dd7cddfSDavid du Colombier 		gopcode(OAS, &nod1, Z, &nod2);
1507dd7cddfSDavid du Colombier 		bitstore(l, &nod, &nod1, &nod2, nn);
1517dd7cddfSDavid du Colombier 		break;
1527dd7cddfSDavid du Colombier 
1537dd7cddfSDavid du Colombier 	case OBIT:
1547dd7cddfSDavid du Colombier 		if(nn == Z) {
1557dd7cddfSDavid du Colombier 			nullwarn(l, Z);
1567dd7cddfSDavid du Colombier 			break;
1577dd7cddfSDavid du Colombier 		}
1587dd7cddfSDavid du Colombier 		bitload(n, &nod, Z, Z, nn);
1597dd7cddfSDavid du Colombier 		gopcode(OAS, &nod, Z, nn);
1607dd7cddfSDavid du Colombier 		regfree(&nod);
1617dd7cddfSDavid du Colombier 		break;
1627dd7cddfSDavid du Colombier 
1637dd7cddfSDavid du Colombier 	case OXOR:
1647dd7cddfSDavid du Colombier 		if(nn != Z)
1657dd7cddfSDavid du Colombier 		if(r->op == OCONST && r->vconst == -1){
1666891d857SDavid du Colombier 			regalloc(&nod, l, nn);
1676891d857SDavid du Colombier 			cgen(l, &nod);
1686891d857SDavid du Colombier 			gopcode(OCOM, &nod, Z, &nod);
1696891d857SDavid du Colombier 			gmove(&nod, nn);
1706891d857SDavid du Colombier 			regfree(&nod);
1717dd7cddfSDavid du Colombier 			break;
1727dd7cddfSDavid du Colombier 		}
1737dd7cddfSDavid du Colombier 
1747dd7cddfSDavid du Colombier 	case OADD:
1757dd7cddfSDavid du Colombier 	case OSUB:
1767dd7cddfSDavid du Colombier 	case OAND:
1777dd7cddfSDavid du Colombier 	case OOR:
1787dd7cddfSDavid du Colombier 	case OLSHR:
1797dd7cddfSDavid du Colombier 	case OASHL:
1807dd7cddfSDavid du Colombier 	case OASHR:
1817dd7cddfSDavid du Colombier 		/*
1827dd7cddfSDavid du Colombier 		 * immediate operands
1837dd7cddfSDavid du Colombier 		 */
1846891d857SDavid du Colombier 		if(nn != Z && r->op == OCONST && !typefd[n->type->etype] &&
1856891d857SDavid du Colombier 		    (!typev[n->type->etype] || isvconstable(o, r->vconst))) {
1866891d857SDavid du Colombier 			regalloc(&nod, l, nn);
1876891d857SDavid du Colombier 			cgen(l, &nod);
1886891d857SDavid du Colombier 			if(o == OAND || r->vconst != 0)
1896891d857SDavid du Colombier 				gopcode(o, r, Z, &nod);
1906891d857SDavid du Colombier 			gmove(&nod, nn);
1916891d857SDavid du Colombier 			regfree(&nod);
1927dd7cddfSDavid du Colombier 			break;
1937dd7cddfSDavid du Colombier 		}
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier 	case OMUL:
1967dd7cddfSDavid du Colombier 	case OLMUL:
1977dd7cddfSDavid du Colombier 	case OLDIV:
1987dd7cddfSDavid du Colombier 	case OLMOD:
1997dd7cddfSDavid du Colombier 	case ODIV:
2007dd7cddfSDavid du Colombier 	case OMOD:
2017dd7cddfSDavid du Colombier 		if(nn == Z) {
2027dd7cddfSDavid du Colombier 			nullwarn(l, r);
2037dd7cddfSDavid du Colombier 			break;
2047dd7cddfSDavid du Colombier 		}
2056891d857SDavid du Colombier 		if((o == OMUL || o == OLMUL) && !typev[n->type->etype]) {
2067dd7cddfSDavid du Colombier 			if(mulcon(n, nn))
2077dd7cddfSDavid du Colombier 				break;
2087dd7cddfSDavid du Colombier 			if(debug['M'])
2097dd7cddfSDavid du Colombier 				print("%L multiply\n", n->lineno);
2107dd7cddfSDavid du Colombier 		}
2117dd7cddfSDavid du Colombier 		if(l->complex >= r->complex) {
2127dd7cddfSDavid du Colombier 			regalloc(&nod, l, nn);
2137dd7cddfSDavid du Colombier 			cgen(l, &nod);
2146891d857SDavid du Colombier 			if(o != OMUL || typev[n->type->etype] || !sconst(r)) {
2157dd7cddfSDavid du Colombier 				regalloc(&nod1, r, Z);
2167dd7cddfSDavid du Colombier 				cgen(r, &nod1);
2177dd7cddfSDavid du Colombier 				gopcode(o, &nod1, Z, &nod);
2186891d857SDavid du Colombier 				regfree(&nod1);
2196891d857SDavid du Colombier 			} else
2206891d857SDavid du Colombier 				gopcode(o, r, Z, &nod);
2217dd7cddfSDavid du Colombier 		} else {
2226891d857SDavid du Colombier 			regalloc(&nod1, r, nn);
2236891d857SDavid du Colombier 			cgen(r, &nod1);
2246891d857SDavid du Colombier 			regalloc(&nod, l, Z);
2256891d857SDavid du Colombier 			cgen(l, &nod);
2266891d857SDavid du Colombier 			gopcode(o, &nod1, Z, &nod);
2276891d857SDavid du Colombier 			regfree(&nod1);
2287dd7cddfSDavid du Colombier 		}
2297dd7cddfSDavid du Colombier 		gopcode(OAS, &nod, Z, nn);
2307dd7cddfSDavid du Colombier 		regfree(&nod);
2317dd7cddfSDavid du Colombier 		break;
2327dd7cddfSDavid du Colombier 
2337dd7cddfSDavid du Colombier 	case OASLSHR:
2347dd7cddfSDavid du Colombier 	case OASASHL:
2357dd7cddfSDavid du Colombier 	case OASASHR:
2367dd7cddfSDavid du Colombier 	case OASAND:
2377dd7cddfSDavid du Colombier 	case OASADD:
2387dd7cddfSDavid du Colombier 	case OASSUB:
2397dd7cddfSDavid du Colombier 	case OASXOR:
2407dd7cddfSDavid du Colombier 	case OASOR:
2417dd7cddfSDavid du Colombier 		if(l->op == OBIT)
2427dd7cddfSDavid du Colombier 			goto asbitop;
2436891d857SDavid du Colombier 		if(r->op == OCONST && !typefd[r->type->etype] && !typefd[n->type->etype] &&
2446891d857SDavid du Colombier 		   (!typev[n->type->etype] || isvconstable(o, r->vconst))) {
2457dd7cddfSDavid du Colombier 			if(l->addable < INDEXED)
2467dd7cddfSDavid du Colombier 				reglcgen(&nod2, l, Z);
2477dd7cddfSDavid du Colombier 			else
2487dd7cddfSDavid du Colombier 				nod2 = *l;
2496891d857SDavid du Colombier 			regalloc(&nod, l, nn);
2507dd7cddfSDavid du Colombier 			gopcode(OAS, &nod2, Z, &nod);
2517dd7cddfSDavid du Colombier 			gopcode(o, r, Z, &nod);
2527dd7cddfSDavid du Colombier 			gopcode(OAS, &nod, Z, &nod2);
2537dd7cddfSDavid du Colombier 
2547dd7cddfSDavid du Colombier 			regfree(&nod);
2557dd7cddfSDavid du Colombier 			if(l->addable < INDEXED)
2567dd7cddfSDavid du Colombier 				regfree(&nod2);
2577dd7cddfSDavid du Colombier 			break;
2587dd7cddfSDavid du Colombier 		}
259*40d01547SDavid du Colombier 		genasop(o, l, r, nn);
260*40d01547SDavid du Colombier 		break;
2617dd7cddfSDavid du Colombier 
2627dd7cddfSDavid du Colombier 	case OASLMUL:
2637dd7cddfSDavid du Colombier 	case OASLDIV:
2647dd7cddfSDavid du Colombier 	case OASLMOD:
2657dd7cddfSDavid du Colombier 	case OASMUL:
2667dd7cddfSDavid du Colombier 	case OASDIV:
2677dd7cddfSDavid du Colombier 	case OASMOD:
2687dd7cddfSDavid du Colombier 		if(l->op == OBIT)
2697dd7cddfSDavid du Colombier 			goto asbitop;
270*40d01547SDavid du Colombier 		genasop(o, l, r, nn);
2717dd7cddfSDavid du Colombier 		break;
2727dd7cddfSDavid du Colombier 
2737dd7cddfSDavid du Colombier 	asbitop:
2747dd7cddfSDavid du Colombier 		regalloc(&nod4, n, nn);
2757dd7cddfSDavid du Colombier 		regalloc(&nod3, r, Z);
2767dd7cddfSDavid du Colombier 		if(l->complex >= r->complex) {
2777dd7cddfSDavid du Colombier 			bitload(l, &nod, &nod1, &nod2, &nod4);
2787dd7cddfSDavid du Colombier 			cgen(r, &nod3);
2797dd7cddfSDavid du Colombier 		} else {
2807dd7cddfSDavid du Colombier 			cgen(r, &nod3);
2817dd7cddfSDavid du Colombier 			bitload(l, &nod, &nod1, &nod2, &nod4);
2827dd7cddfSDavid du Colombier 		}
2837dd7cddfSDavid du Colombier 		gmove(&nod, &nod4);
2847dd7cddfSDavid du Colombier 		gopcode(n->op, &nod3, Z, &nod4);
2857dd7cddfSDavid du Colombier 		regfree(&nod3);
2867dd7cddfSDavid du Colombier 		gmove(&nod4, &nod);
2877dd7cddfSDavid du Colombier 		regfree(&nod4);
2887dd7cddfSDavid du Colombier 		bitstore(l, &nod, &nod1, &nod2, nn);
2897dd7cddfSDavid du Colombier 		break;
2907dd7cddfSDavid du Colombier 
2917dd7cddfSDavid du Colombier 	case OADDR:
2927dd7cddfSDavid du Colombier 		if(nn == Z) {
2937dd7cddfSDavid du Colombier 			nullwarn(l, Z);
2947dd7cddfSDavid du Colombier 			break;
2957dd7cddfSDavid du Colombier 		}
2967dd7cddfSDavid du Colombier 		lcgen(l, nn);
2977dd7cddfSDavid du Colombier 		break;
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier 	case OFUNC:
3007dd7cddfSDavid du Colombier 		if(l->complex >= FNX) {
3017dd7cddfSDavid du Colombier 			if(l->op != OIND)
3027dd7cddfSDavid du Colombier 				diag(n, "bad function call");
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier 			regret(&nod, l->left);
3057dd7cddfSDavid du Colombier 			cgen(l->left, &nod);
3067dd7cddfSDavid du Colombier 			regsalloc(&nod1, l->left);
3077dd7cddfSDavid du Colombier 			gopcode(OAS, &nod, Z, &nod1);
3087dd7cddfSDavid du Colombier 			regfree(&nod);
3097dd7cddfSDavid du Colombier 
3107dd7cddfSDavid du Colombier 			nod = *n;
3117dd7cddfSDavid du Colombier 			nod.left = &nod2;
3127dd7cddfSDavid du Colombier 			nod2 = *l;
3137dd7cddfSDavid du Colombier 			nod2.left = &nod1;
3147dd7cddfSDavid du Colombier 			nod2.complex = 1;
3157dd7cddfSDavid du Colombier 			cgen(&nod, nn);
3167dd7cddfSDavid du Colombier 
3177dd7cddfSDavid du Colombier 			return;
3187dd7cddfSDavid du Colombier 		}
3197dd7cddfSDavid du Colombier 		o = reg[REGARG];
3207dd7cddfSDavid du Colombier 		gargs(r, &nod, &nod1);
3217dd7cddfSDavid du Colombier 		if(l->addable < INDEXED) {
3227dd7cddfSDavid du Colombier 			reglcgen(&nod, l, Z);
3237dd7cddfSDavid du Colombier 			gopcode(OFUNC, Z, Z, &nod);
3247dd7cddfSDavid du Colombier 			regfree(&nod);
3257dd7cddfSDavid du Colombier 		} else
3267dd7cddfSDavid du Colombier 			gopcode(OFUNC, Z, Z, l);
3277dd7cddfSDavid du Colombier 		if(REGARG)
3287dd7cddfSDavid du Colombier 			if(o != reg[REGARG])
3297dd7cddfSDavid du Colombier 				reg[REGARG]--;
3307dd7cddfSDavid du Colombier 		if(nn != Z) {
3317dd7cddfSDavid du Colombier 			regret(&nod, n);
3327dd7cddfSDavid du Colombier 			gopcode(OAS, &nod, Z, nn);
3337dd7cddfSDavid du Colombier 			regfree(&nod);
3347dd7cddfSDavid du Colombier 		}
3357dd7cddfSDavid du Colombier 		break;
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier 	case OIND:
3387dd7cddfSDavid du Colombier 		if(nn == Z) {
3397dd7cddfSDavid du Colombier 			cgen(l, nn);
3407dd7cddfSDavid du Colombier 			break;
3417dd7cddfSDavid du Colombier 		}
3427dd7cddfSDavid du Colombier 		regialloc(&nod, n, nn);
3437dd7cddfSDavid du Colombier 		r = l;
3447dd7cddfSDavid du Colombier 		while(r->op == OADD)
3457dd7cddfSDavid du Colombier 			r = r->right;
3467dd7cddfSDavid du Colombier 		if(sconst(r)) {
3477dd7cddfSDavid du Colombier 			v = r->vconst;
3487dd7cddfSDavid du Colombier 			r->vconst = 0;
3497dd7cddfSDavid du Colombier 			cgen(l, &nod);
3507dd7cddfSDavid du Colombier 			nod.xoffset += v;
3517dd7cddfSDavid du Colombier 			r->vconst = v;
3527dd7cddfSDavid du Colombier 		} else
3537dd7cddfSDavid du Colombier 			cgen(l, &nod);
3547dd7cddfSDavid du Colombier 		regind(&nod, n);
3556891d857SDavid du Colombier 		gmove(&nod, nn);
3567dd7cddfSDavid du Colombier 		regfree(&nod);
3577dd7cddfSDavid du Colombier 		break;
3587dd7cddfSDavid du Colombier 
3597dd7cddfSDavid du Colombier 	case OEQ:
3607dd7cddfSDavid du Colombier 	case ONE:
3617dd7cddfSDavid du Colombier 	case OLE:
3627dd7cddfSDavid du Colombier 	case OLT:
3637dd7cddfSDavid du Colombier 	case OGE:
3647dd7cddfSDavid du Colombier 	case OGT:
3657dd7cddfSDavid du Colombier 	case OLO:
3667dd7cddfSDavid du Colombier 	case OLS:
3677dd7cddfSDavid du Colombier 	case OHI:
3687dd7cddfSDavid du Colombier 	case OHS:
3697dd7cddfSDavid du Colombier 		if(nn == Z) {
3707dd7cddfSDavid du Colombier 			nullwarn(l, r);
3717dd7cddfSDavid du Colombier 			break;
3727dd7cddfSDavid du Colombier 		}
3737dd7cddfSDavid du Colombier 		boolgen(n, 1, nn);
3747dd7cddfSDavid du Colombier 		break;
3757dd7cddfSDavid du Colombier 
3767dd7cddfSDavid du Colombier 	case OANDAND:
3777dd7cddfSDavid du Colombier 	case OOROR:
3787dd7cddfSDavid du Colombier 		boolgen(n, 1, nn);
3797dd7cddfSDavid du Colombier 		if(nn == Z)
3807dd7cddfSDavid du Colombier 			patch(p, pc);
3817dd7cddfSDavid du Colombier 		break;
3827dd7cddfSDavid du Colombier 
3837dd7cddfSDavid du Colombier 	case ONOT:
3847dd7cddfSDavid du Colombier 		if(nn == Z) {
3857dd7cddfSDavid du Colombier 			nullwarn(l, Z);
3867dd7cddfSDavid du Colombier 			break;
3877dd7cddfSDavid du Colombier 		}
3887dd7cddfSDavid du Colombier 		boolgen(n, 1, nn);
3897dd7cddfSDavid du Colombier 		break;
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier 	case OCOMMA:
3927dd7cddfSDavid du Colombier 		cgen(l, Z);
3937dd7cddfSDavid du Colombier 		cgen(r, nn);
3947dd7cddfSDavid du Colombier 		break;
3957dd7cddfSDavid du Colombier 
3967dd7cddfSDavid du Colombier 	case OCAST:
3977dd7cddfSDavid du Colombier 		if(nn == Z) {
3987dd7cddfSDavid du Colombier 			nullwarn(l, Z);
3997dd7cddfSDavid du Colombier 			break;
4007dd7cddfSDavid du Colombier 		}
4017dd7cddfSDavid du Colombier 		/*
4027dd7cddfSDavid du Colombier 		 * convert from types l->n->nn
4037dd7cddfSDavid du Colombier 		 */
4047dd7cddfSDavid du Colombier 		if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
4057dd7cddfSDavid du Colombier 			/* both null, gen l->nn */
4067dd7cddfSDavid du Colombier 			cgen(l, nn);
4077dd7cddfSDavid du Colombier 			break;
4087dd7cddfSDavid du Colombier 		}
4096891d857SDavid du Colombier 		if(typev[l->type->etype] || typev[n->type->etype]) {
4106891d857SDavid du Colombier 			cgen64(n, nn);
4116891d857SDavid du Colombier 			break;
4126891d857SDavid du Colombier 		}
4137dd7cddfSDavid du Colombier 		regalloc(&nod, l, nn);
4147dd7cddfSDavid du Colombier 		cgen(l, &nod);
4157dd7cddfSDavid du Colombier 		regalloc(&nod1, n, &nod);
4166891d857SDavid du Colombier 		gmove(&nod, &nod1);
4176891d857SDavid du Colombier 		gmove(&nod1, nn);
4187dd7cddfSDavid du Colombier 		regfree(&nod1);
4197dd7cddfSDavid du Colombier 		regfree(&nod);
4207dd7cddfSDavid du Colombier 		break;
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier 	case ODOT:
4237dd7cddfSDavid du Colombier 		sugen(l, nodrat, l->type->width);
4247dd7cddfSDavid du Colombier 		if(nn != Z) {
4257dd7cddfSDavid du Colombier 			warn(n, "non-interruptable temporary");
4267dd7cddfSDavid du Colombier 			nod = *nodrat;
4277dd7cddfSDavid du Colombier 			if(!r || r->op != OCONST) {
4287dd7cddfSDavid du Colombier 				diag(n, "DOT and no offset");
4297dd7cddfSDavid du Colombier 				break;
4307dd7cddfSDavid du Colombier 			}
4317dd7cddfSDavid du Colombier 			nod.xoffset += (long)r->vconst;
4327dd7cddfSDavid du Colombier 			nod.type = n->type;
4337dd7cddfSDavid du Colombier 			cgen(&nod, nn);
4347dd7cddfSDavid du Colombier 		}
4357dd7cddfSDavid du Colombier 		break;
4367dd7cddfSDavid du Colombier 
4377dd7cddfSDavid du Colombier 	case OCOND:
4387dd7cddfSDavid du Colombier 		bcgen(l, 1);
4397dd7cddfSDavid du Colombier 		p1 = p;
4407dd7cddfSDavid du Colombier 		cgen(r->left, nn);
4417dd7cddfSDavid du Colombier 		gbranch(OGOTO);
4427dd7cddfSDavid du Colombier 		patch(p1, pc);
4437dd7cddfSDavid du Colombier 		p1 = p;
4447dd7cddfSDavid du Colombier 		cgen(r->right, nn);
4457dd7cddfSDavid du Colombier 		patch(p1, pc);
4467dd7cddfSDavid du Colombier 		break;
4477dd7cddfSDavid du Colombier 
4487dd7cddfSDavid du Colombier 	case OPOSTINC:
4497dd7cddfSDavid du Colombier 	case OPOSTDEC:
4507dd7cddfSDavid du Colombier 		v = 1;
4517dd7cddfSDavid du Colombier 		if(l->type->etype == TIND)
4527dd7cddfSDavid du Colombier 			v = l->type->link->width;
4537dd7cddfSDavid du Colombier 		if(o == OPOSTDEC)
4547dd7cddfSDavid du Colombier 			v = -v;
4557dd7cddfSDavid du Colombier 		if(l->op == OBIT)
4567dd7cddfSDavid du Colombier 			goto bitinc;
4577dd7cddfSDavid du Colombier 		if(nn == Z)
4587dd7cddfSDavid du Colombier 			goto pre;
4597dd7cddfSDavid du Colombier 
4607dd7cddfSDavid du Colombier 		if(l->addable < INDEXED)
4617dd7cddfSDavid du Colombier 			reglcgen(&nod2, l, Z);
4627dd7cddfSDavid du Colombier 		else
4637dd7cddfSDavid du Colombier 			nod2 = *l;
4647dd7cddfSDavid du Colombier 
4657dd7cddfSDavid du Colombier 		regalloc(&nod, l, nn);
4667dd7cddfSDavid du Colombier 		gopcode(OAS, &nod2, Z, &nod);
4677dd7cddfSDavid du Colombier 		regalloc(&nod1, l, Z);
4687dd7cddfSDavid du Colombier 		if(typefd[l->type->etype]) {
4697dd7cddfSDavid du Colombier 			regalloc(&nod3, l, Z);
4707dd7cddfSDavid du Colombier 			if(v < 0) {
4717dd7cddfSDavid du Colombier 				gopcode(OAS, nodfconst(-v), Z, &nod3);
4727dd7cddfSDavid du Colombier 				gopcode(OSUB, &nod3, &nod, &nod1);
4737dd7cddfSDavid du Colombier 			} else {
4747dd7cddfSDavid du Colombier 				gopcode(OAS, nodfconst(v), Z, &nod3);
4757dd7cddfSDavid du Colombier 				gopcode(OADD, &nod3, &nod, &nod1);
4767dd7cddfSDavid du Colombier 			}
4777dd7cddfSDavid du Colombier 			regfree(&nod3);
4787dd7cddfSDavid du Colombier 		} else
4797dd7cddfSDavid du Colombier 			gopcode(OADD, nodconst(v), &nod, &nod1);
4807dd7cddfSDavid du Colombier 		gopcode(OAS, &nod1, Z, &nod2);
4817dd7cddfSDavid du Colombier 
4827dd7cddfSDavid du Colombier 		regfree(&nod);
4837dd7cddfSDavid du Colombier 		regfree(&nod1);
4847dd7cddfSDavid du Colombier 		if(l->addable < INDEXED)
4857dd7cddfSDavid du Colombier 			regfree(&nod2);
4867dd7cddfSDavid du Colombier 		break;
4877dd7cddfSDavid du Colombier 
4887dd7cddfSDavid du Colombier 	case OPREINC:
4897dd7cddfSDavid du Colombier 	case OPREDEC:
4907dd7cddfSDavid du Colombier 		v = 1;
4917dd7cddfSDavid du Colombier 		if(l->type->etype == TIND)
4927dd7cddfSDavid du Colombier 			v = l->type->link->width;
4937dd7cddfSDavid du Colombier 		if(o == OPREDEC)
4947dd7cddfSDavid du Colombier 			v = -v;
4957dd7cddfSDavid du Colombier 		if(l->op == OBIT)
4967dd7cddfSDavid du Colombier 			goto bitinc;
4977dd7cddfSDavid du Colombier 
4987dd7cddfSDavid du Colombier 	pre:
4997dd7cddfSDavid du Colombier 		if(l->addable < INDEXED)
5007dd7cddfSDavid du Colombier 			reglcgen(&nod2, l, Z);
5017dd7cddfSDavid du Colombier 		else
5027dd7cddfSDavid du Colombier 			nod2 = *l;
5037dd7cddfSDavid du Colombier 
5047dd7cddfSDavid du Colombier 		regalloc(&nod, l, nn);
5057dd7cddfSDavid du Colombier 		gopcode(OAS, &nod2, Z, &nod);
5067dd7cddfSDavid du Colombier 		if(typefd[l->type->etype]) {
5077dd7cddfSDavid du Colombier 			regalloc(&nod3, l, Z);
5087dd7cddfSDavid du Colombier 			if(v < 0) {
5097dd7cddfSDavid du Colombier 				gopcode(OAS, nodfconst(-v), Z, &nod3);
5107dd7cddfSDavid du Colombier 				gopcode(OSUB, &nod3, Z, &nod);
5117dd7cddfSDavid du Colombier 			} else {
5127dd7cddfSDavid du Colombier 				gopcode(OAS, nodfconst(v), Z, &nod3);
5137dd7cddfSDavid du Colombier 				gopcode(OADD, &nod3, Z, &nod);
5147dd7cddfSDavid du Colombier 			}
5157dd7cddfSDavid du Colombier 			regfree(&nod3);
5167dd7cddfSDavid du Colombier 		} else
5177dd7cddfSDavid du Colombier 			gopcode(OADD, nodconst(v), Z, &nod);
5187dd7cddfSDavid du Colombier 		gopcode(OAS, &nod, Z, &nod2);
5194ac975e2SDavid du Colombier 		if(nn && l->op == ONAME)	/* in x=++i, emit USED(i) */
5204ac975e2SDavid du Colombier 			gins(ANOP, l, Z);
5217dd7cddfSDavid du Colombier 
5227dd7cddfSDavid du Colombier 		regfree(&nod);
5237dd7cddfSDavid du Colombier 		if(l->addable < INDEXED)
5247dd7cddfSDavid du Colombier 			regfree(&nod2);
5257dd7cddfSDavid du Colombier 		break;
5267dd7cddfSDavid du Colombier 
5277dd7cddfSDavid du Colombier 	bitinc:
5287dd7cddfSDavid du Colombier 		if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
5297dd7cddfSDavid du Colombier 			bitload(l, &nod, &nod1, &nod2, Z);
5307dd7cddfSDavid du Colombier 			gopcode(OAS, &nod, Z, nn);
5317dd7cddfSDavid du Colombier 			gopcode(OADD, nodconst(v), Z, &nod);
5327dd7cddfSDavid du Colombier 			bitstore(l, &nod, &nod1, &nod2, Z);
5337dd7cddfSDavid du Colombier 			break;
5347dd7cddfSDavid du Colombier 		}
5357dd7cddfSDavid du Colombier 		bitload(l, &nod, &nod1, &nod2, nn);
5367dd7cddfSDavid du Colombier 		gopcode(OADD, nodconst(v), Z, &nod);
5377dd7cddfSDavid du Colombier 		bitstore(l, &nod, &nod1, &nod2, nn);
5387dd7cddfSDavid du Colombier 		break;
5397dd7cddfSDavid du Colombier 	}
5407dd7cddfSDavid du Colombier 	cursafe = curs;
5417dd7cddfSDavid du Colombier }
5427dd7cddfSDavid du Colombier 
543*40d01547SDavid du Colombier static void
genasop(int o,Node * l,Node * r,Node * nn)544*40d01547SDavid du Colombier genasop(int o, Node *l, Node *r, Node *nn)
545*40d01547SDavid du Colombier {
546*40d01547SDavid du Colombier 	Node nod, nod1, nod2;
547*40d01547SDavid du Colombier 	int hardleft;
548*40d01547SDavid du Colombier 
549*40d01547SDavid du Colombier 	hardleft = l->addable < INDEXED || l->complex >= FNX;
550*40d01547SDavid du Colombier 	if(l->complex >= r->complex) {
551*40d01547SDavid du Colombier 		if(hardleft)
552*40d01547SDavid du Colombier 			reglcgen(&nod2, l, Z);
553*40d01547SDavid du Colombier 		else
554*40d01547SDavid du Colombier 			nod2 = *l;
555*40d01547SDavid du Colombier 		regalloc(&nod1, r, Z);
556*40d01547SDavid du Colombier 		cgen(r, &nod1);
557*40d01547SDavid du Colombier 	} else {
558*40d01547SDavid du Colombier 		regalloc(&nod1, r, Z);
559*40d01547SDavid du Colombier 		cgen(r, &nod1);
560*40d01547SDavid du Colombier 		if(hardleft)
561*40d01547SDavid du Colombier 			reglcgen(&nod2, l, Z);
562*40d01547SDavid du Colombier 		else
563*40d01547SDavid du Colombier 			nod2 = *l;
564*40d01547SDavid du Colombier 	}
565*40d01547SDavid du Colombier 	if(nod1.type == nod2.type || !typefd[nod1.type->etype])
566*40d01547SDavid du Colombier 		regalloc(&nod, &nod2, nn);
567*40d01547SDavid du Colombier 	else
568*40d01547SDavid du Colombier 		regalloc(&nod, &nod1, Z);
569*40d01547SDavid du Colombier 	gmove(&nod2, &nod);
570*40d01547SDavid du Colombier 	gopcode(o, &nod1, Z, &nod);
571*40d01547SDavid du Colombier 	gmove(&nod, &nod2);
572*40d01547SDavid du Colombier 	if(nn != Z)
573*40d01547SDavid du Colombier 		gmove(&nod2, nn);
574*40d01547SDavid du Colombier 	regfree(&nod);
575*40d01547SDavid du Colombier 	regfree(&nod1);
576*40d01547SDavid du Colombier 	if(hardleft)
577*40d01547SDavid du Colombier 		regfree(&nod2);
578*40d01547SDavid du Colombier }
579*40d01547SDavid du Colombier 
5807dd7cddfSDavid du Colombier void
reglcgen(Node * t,Node * n,Node * nn)5817dd7cddfSDavid du Colombier reglcgen(Node *t, Node *n, Node *nn)
5827dd7cddfSDavid du Colombier {
5837dd7cddfSDavid du Colombier 	Node *r;
5847dd7cddfSDavid du Colombier 	long v;
5857dd7cddfSDavid du Colombier 
5867dd7cddfSDavid du Colombier 	regialloc(t, n, nn);
5877dd7cddfSDavid du Colombier 	if(n->op == OIND) {
5887dd7cddfSDavid du Colombier 		r = n->left;
5897dd7cddfSDavid du Colombier 		while(r->op == OADD)
5907dd7cddfSDavid du Colombier 			r = r->right;
5917dd7cddfSDavid du Colombier 		if(sconst(r)) {
5927dd7cddfSDavid du Colombier 			v = r->vconst;
5937dd7cddfSDavid du Colombier 			r->vconst = 0;
5947dd7cddfSDavid du Colombier 			lcgen(n, t);
5957dd7cddfSDavid du Colombier 			t->xoffset += v;
5967dd7cddfSDavid du Colombier 			r->vconst = v;
5977dd7cddfSDavid du Colombier 			regind(t, n);
5987dd7cddfSDavid du Colombier 			return;
5997dd7cddfSDavid du Colombier 		}
6007dd7cddfSDavid du Colombier 	}
6017dd7cddfSDavid du Colombier 	lcgen(n, t);
6027dd7cddfSDavid du Colombier 	regind(t, n);
6037dd7cddfSDavid du Colombier }
6047dd7cddfSDavid du Colombier 
6057dd7cddfSDavid du Colombier void
lcgen(Node * n,Node * nn)6067dd7cddfSDavid du Colombier lcgen(Node *n, Node *nn)
6077dd7cddfSDavid du Colombier {
6087dd7cddfSDavid du Colombier 	Prog *p1;
6097dd7cddfSDavid du Colombier 	Node nod;
6107dd7cddfSDavid du Colombier 
6117dd7cddfSDavid du Colombier 	if(debug['g']) {
6127dd7cddfSDavid du Colombier 		prtree(nn, "lcgen lhs");
6137dd7cddfSDavid du Colombier 		prtree(n, "lcgen");
6147dd7cddfSDavid du Colombier 	}
6157dd7cddfSDavid du Colombier 	if(n == Z || n->type == T)
6167dd7cddfSDavid du Colombier 		return;
6177dd7cddfSDavid du Colombier 	if(nn == Z) {
6187dd7cddfSDavid du Colombier 		nn = &nod;
6197dd7cddfSDavid du Colombier 		regalloc(&nod, n, Z);
6207dd7cddfSDavid du Colombier 	}
6217dd7cddfSDavid du Colombier 	switch(n->op) {
6227dd7cddfSDavid du Colombier 	default:
6237dd7cddfSDavid du Colombier 		if(n->addable < INDEXED) {
6247dd7cddfSDavid du Colombier 			diag(n, "unknown op in lcgen: %O", n->op);
6257dd7cddfSDavid du Colombier 			break;
6267dd7cddfSDavid du Colombier 		}
6277dd7cddfSDavid du Colombier 		nod = *n;
6287dd7cddfSDavid du Colombier 		nod.op = OADDR;
6297dd7cddfSDavid du Colombier 		nod.left = n;
6307dd7cddfSDavid du Colombier 		nod.right = Z;
6317dd7cddfSDavid du Colombier 		nod.type = types[TIND];
6327dd7cddfSDavid du Colombier 		gopcode(OAS, &nod, Z, nn);
6337dd7cddfSDavid du Colombier 		break;
6347dd7cddfSDavid du Colombier 
6357dd7cddfSDavid du Colombier 	case OCOMMA:
6367dd7cddfSDavid du Colombier 		cgen(n->left, n->left);
6377dd7cddfSDavid du Colombier 		lcgen(n->right, nn);
6387dd7cddfSDavid du Colombier 		break;
6397dd7cddfSDavid du Colombier 
6407dd7cddfSDavid du Colombier 	case OIND:
6417dd7cddfSDavid du Colombier 		cgen(n->left, nn);
6427dd7cddfSDavid du Colombier 		break;
6437dd7cddfSDavid du Colombier 
6447dd7cddfSDavid du Colombier 	case OCOND:
6457dd7cddfSDavid du Colombier 		bcgen(n->left, 1);
6467dd7cddfSDavid du Colombier 		p1 = p;
6477dd7cddfSDavid du Colombier 		lcgen(n->right->left, nn);
6487dd7cddfSDavid du Colombier 		gbranch(OGOTO);
6497dd7cddfSDavid du Colombier 		patch(p1, pc);
6507dd7cddfSDavid du Colombier 		p1 = p;
6517dd7cddfSDavid du Colombier 		lcgen(n->right->right, nn);
6527dd7cddfSDavid du Colombier 		patch(p1, pc);
6537dd7cddfSDavid du Colombier 		break;
6547dd7cddfSDavid du Colombier 	}
6557dd7cddfSDavid du Colombier }
6567dd7cddfSDavid du Colombier 
6577dd7cddfSDavid du Colombier void
bcgen(Node * n,int true)6587dd7cddfSDavid du Colombier bcgen(Node *n, int true)
6597dd7cddfSDavid du Colombier {
6607dd7cddfSDavid du Colombier 
6617dd7cddfSDavid du Colombier 	if(n->type == T)
6627dd7cddfSDavid du Colombier 		gbranch(OGOTO);
6637dd7cddfSDavid du Colombier 	else
6647dd7cddfSDavid du Colombier 		boolgen(n, true, Z);
6657dd7cddfSDavid du Colombier }
6667dd7cddfSDavid du Colombier 
6677dd7cddfSDavid du Colombier void
boolgen(Node * n,int true,Node * nn)6687dd7cddfSDavid du Colombier boolgen(Node *n, int true, Node *nn)
6697dd7cddfSDavid du Colombier {
6706891d857SDavid du Colombier 	int o, uns;
6717dd7cddfSDavid du Colombier 	Prog *p1, *p2;
6727dd7cddfSDavid du Colombier 	Node *l, *r, nod, nod1;
6737dd7cddfSDavid du Colombier 	long curs;
6747dd7cddfSDavid du Colombier 
6757dd7cddfSDavid du Colombier 	if(debug['g']) {
6767dd7cddfSDavid du Colombier 		prtree(nn, "boolgen lhs");
6777dd7cddfSDavid du Colombier 		prtree(n, "boolgen");
6787dd7cddfSDavid du Colombier 	}
6796891d857SDavid du Colombier 	uns = 0;
6807dd7cddfSDavid du Colombier 	curs = cursafe;
6817dd7cddfSDavid du Colombier 	l = n->left;
6827dd7cddfSDavid du Colombier 	r = n->right;
6837dd7cddfSDavid du Colombier 	switch(n->op) {
6847dd7cddfSDavid du Colombier 
6857dd7cddfSDavid du Colombier 	default:
6867dd7cddfSDavid du Colombier 		if(n->op == OCONST) {
6877dd7cddfSDavid du Colombier 			o = vconst(n);
6887dd7cddfSDavid du Colombier 			if(!true)
6897dd7cddfSDavid du Colombier 				o = !o;
6907dd7cddfSDavid du Colombier 			gbranch(OGOTO);
6917dd7cddfSDavid du Colombier 			if(o) {
6927dd7cddfSDavid du Colombier 				p1 = p;
6937dd7cddfSDavid du Colombier 				gbranch(OGOTO);
6947dd7cddfSDavid du Colombier 				patch(p1, pc);
6957dd7cddfSDavid du Colombier 			}
6967dd7cddfSDavid du Colombier 			goto com;
6977dd7cddfSDavid du Colombier 		}
6986891d857SDavid du Colombier 		if(typev[n->type->etype]) {
6996891d857SDavid du Colombier 			testv(n, true);
7006891d857SDavid du Colombier 			goto com;
7016891d857SDavid du Colombier 		}
7027dd7cddfSDavid du Colombier 		regalloc(&nod, n, nn);
7037dd7cddfSDavid du Colombier 		cgen(n, &nod);
7047dd7cddfSDavid du Colombier 		o = ONE;
7057dd7cddfSDavid du Colombier 		if(true)
7067dd7cddfSDavid du Colombier 			o = comrel[relindex(o)];
7077dd7cddfSDavid du Colombier 		if(typefd[n->type->etype]) {
7087dd7cddfSDavid du Colombier 			nodreg(&nod1, n, NREG+FREGZERO);
7097dd7cddfSDavid du Colombier 			gopcode(o, &nod, Z, &nod1);
7107dd7cddfSDavid du Colombier 		} else
7117dd7cddfSDavid du Colombier 			gopcode(o, &nod, Z, nodconst(0));
7127dd7cddfSDavid du Colombier 		regfree(&nod);
7137dd7cddfSDavid du Colombier 		goto com;
7147dd7cddfSDavid du Colombier 
7157dd7cddfSDavid du Colombier 	case OCOMMA:
7167dd7cddfSDavid du Colombier 		cgen(l, Z);
7177dd7cddfSDavid du Colombier 		boolgen(r, true, nn);
7187dd7cddfSDavid du Colombier 		break;
7197dd7cddfSDavid du Colombier 
7207dd7cddfSDavid du Colombier 	case ONOT:
7217dd7cddfSDavid du Colombier 		boolgen(l, !true, nn);
7227dd7cddfSDavid du Colombier 		break;
7237dd7cddfSDavid du Colombier 
7247dd7cddfSDavid du Colombier 	case OCOND:
7257dd7cddfSDavid du Colombier 		bcgen(l, 1);
7267dd7cddfSDavid du Colombier 		p1 = p;
7277dd7cddfSDavid du Colombier 		bcgen(r->left, true);
7287dd7cddfSDavid du Colombier 		p2 = p;
7297dd7cddfSDavid du Colombier 		gbranch(OGOTO);
7307dd7cddfSDavid du Colombier 		patch(p1, pc);
7317dd7cddfSDavid du Colombier 		p1 = p;
7327dd7cddfSDavid du Colombier 		bcgen(r->right, !true);
7337dd7cddfSDavid du Colombier 		patch(p2, pc);
7347dd7cddfSDavid du Colombier 		p2 = p;
7357dd7cddfSDavid du Colombier 		gbranch(OGOTO);
7367dd7cddfSDavid du Colombier 		patch(p1, pc);
7377dd7cddfSDavid du Colombier 		patch(p2, pc);
7387dd7cddfSDavid du Colombier 		goto com;
7397dd7cddfSDavid du Colombier 
7407dd7cddfSDavid du Colombier 	case OANDAND:
7417dd7cddfSDavid du Colombier 		if(!true)
7427dd7cddfSDavid du Colombier 			goto caseor;
7437dd7cddfSDavid du Colombier 
7447dd7cddfSDavid du Colombier 	caseand:
7457dd7cddfSDavid du Colombier 		bcgen(l, true);
7467dd7cddfSDavid du Colombier 		p1 = p;
7477dd7cddfSDavid du Colombier 		bcgen(r, !true);
7487dd7cddfSDavid du Colombier 		p2 = p;
7497dd7cddfSDavid du Colombier 		patch(p1, pc);
7507dd7cddfSDavid du Colombier 		gbranch(OGOTO);
7517dd7cddfSDavid du Colombier 		patch(p2, pc);
7527dd7cddfSDavid du Colombier 		goto com;
7537dd7cddfSDavid du Colombier 
7547dd7cddfSDavid du Colombier 	case OOROR:
7557dd7cddfSDavid du Colombier 		if(!true)
7567dd7cddfSDavid du Colombier 			goto caseand;
7577dd7cddfSDavid du Colombier 
7587dd7cddfSDavid du Colombier 	caseor:
7597dd7cddfSDavid du Colombier 		bcgen(l, !true);
7607dd7cddfSDavid du Colombier 		p1 = p;
7617dd7cddfSDavid du Colombier 		bcgen(r, !true);
7627dd7cddfSDavid du Colombier 		p2 = p;
7637dd7cddfSDavid du Colombier 		gbranch(OGOTO);
7647dd7cddfSDavid du Colombier 		patch(p1, pc);
7657dd7cddfSDavid du Colombier 		patch(p2, pc);
7667dd7cddfSDavid du Colombier 		goto com;
7677dd7cddfSDavid du Colombier 
7686891d857SDavid du Colombier 	case OHI:
7696891d857SDavid du Colombier 	case OHS:
7706891d857SDavid du Colombier 	case OLO:
7716891d857SDavid du Colombier 	case OLS:
7726891d857SDavid du Colombier 		uns = 1;
7736891d857SDavid du Colombier 		/* fall through */
7747dd7cddfSDavid du Colombier 	case OEQ:
7757dd7cddfSDavid du Colombier 	case ONE:
7767dd7cddfSDavid du Colombier 	case OLE:
7777dd7cddfSDavid du Colombier 	case OLT:
7787dd7cddfSDavid du Colombier 	case OGE:
7797dd7cddfSDavid du Colombier 	case OGT:
7806891d857SDavid du Colombier 		if(typev[l->type->etype]){
7816891d857SDavid du Colombier 			cmpv(n, true, Z);
7826891d857SDavid du Colombier 			goto com;
7836891d857SDavid du Colombier 		}
7847dd7cddfSDavid du Colombier 		o = n->op;
7857dd7cddfSDavid du Colombier 		if(true)
7867dd7cddfSDavid du Colombier 			o = comrel[relindex(o)];
7877dd7cddfSDavid du Colombier 		if(l->complex >= FNX && r->complex >= FNX) {
7887dd7cddfSDavid du Colombier 			regret(&nod, r);
7897dd7cddfSDavid du Colombier 			cgen(r, &nod);
7907dd7cddfSDavid du Colombier 			regsalloc(&nod1, r);
7917dd7cddfSDavid du Colombier 			gopcode(OAS, &nod, Z, &nod1);
7927dd7cddfSDavid du Colombier 			regfree(&nod);
7937dd7cddfSDavid du Colombier 			nod = *n;
7947dd7cddfSDavid du Colombier 			nod.right = &nod1;
7957dd7cddfSDavid du Colombier 			boolgen(&nod, true, nn);
7967dd7cddfSDavid du Colombier 			break;
7977dd7cddfSDavid du Colombier 		}
7986891d857SDavid du Colombier 		if(!uns && sconst(r) || (uns || o == OEQ || o == ONE) && uconst(r)) {
7997dd7cddfSDavid du Colombier 			regalloc(&nod, l, nn);
8007dd7cddfSDavid du Colombier 			cgen(l, &nod);
8017dd7cddfSDavid du Colombier 			gopcode(o, &nod, Z, r);
8027dd7cddfSDavid du Colombier 			regfree(&nod);
8037dd7cddfSDavid du Colombier 			goto com;
8047dd7cddfSDavid du Colombier 		}
8057dd7cddfSDavid du Colombier 		if(l->complex >= r->complex) {
8067dd7cddfSDavid du Colombier 			regalloc(&nod1, l, nn);
8077dd7cddfSDavid du Colombier 			cgen(l, &nod1);
8087dd7cddfSDavid du Colombier 			regalloc(&nod, r, Z);
8097dd7cddfSDavid du Colombier 			cgen(r, &nod);
8107dd7cddfSDavid du Colombier 		} else {
8117dd7cddfSDavid du Colombier 			regalloc(&nod, r, nn);
8127dd7cddfSDavid du Colombier 			cgen(r, &nod);
8137dd7cddfSDavid du Colombier 			regalloc(&nod1, l, Z);
8147dd7cddfSDavid du Colombier 			cgen(l, &nod1);
8157dd7cddfSDavid du Colombier 		}
8167dd7cddfSDavid du Colombier 		gopcode(o, &nod1, Z, &nod);
8177dd7cddfSDavid du Colombier 		regfree(&nod);
8187dd7cddfSDavid du Colombier 		regfree(&nod1);
8197dd7cddfSDavid du Colombier 
8207dd7cddfSDavid du Colombier 	com:
8217dd7cddfSDavid du Colombier 		if(nn != Z) {
8227dd7cddfSDavid du Colombier 			p1 = p;
8237dd7cddfSDavid du Colombier 			gopcode(OAS, nodconst(1L), Z, nn);
8247dd7cddfSDavid du Colombier 			gbranch(OGOTO);
8257dd7cddfSDavid du Colombier 			p2 = p;
8267dd7cddfSDavid du Colombier 			patch(p1, pc);
8277dd7cddfSDavid du Colombier 			gopcode(OAS, nodconst(0L), Z, nn);
8287dd7cddfSDavid du Colombier 			patch(p2, pc);
8297dd7cddfSDavid du Colombier 		}
8307dd7cddfSDavid du Colombier 		break;
8317dd7cddfSDavid du Colombier 	}
8327dd7cddfSDavid du Colombier 	cursafe = curs;
8337dd7cddfSDavid du Colombier }
8347dd7cddfSDavid du Colombier 
8357dd7cddfSDavid du Colombier void
sugen(Node * n,Node * nn,long w)8367dd7cddfSDavid du Colombier sugen(Node *n, Node *nn, long w)
8377dd7cddfSDavid du Colombier {
8387dd7cddfSDavid du Colombier 	Prog *p1;
8397dd7cddfSDavid du Colombier 	Node nod0, nod1, nod2, nod3, nod4, *l, *r;
8407dd7cddfSDavid du Colombier 	Type *t;
8417dd7cddfSDavid du Colombier 	long pc1;
8427dd7cddfSDavid du Colombier 	int i, m, c;
8437dd7cddfSDavid du Colombier 
8447dd7cddfSDavid du Colombier 	if(n == Z || n->type == T)
8457dd7cddfSDavid du Colombier 		return;
8466891d857SDavid du Colombier 	if(nn == nodrat)
8476891d857SDavid du Colombier 		if(w > nrathole)
8486891d857SDavid du Colombier 			nrathole = w;
8497dd7cddfSDavid du Colombier 	if(debug['g']) {
8507dd7cddfSDavid du Colombier 		prtree(nn, "sugen lhs");
8517dd7cddfSDavid du Colombier 		prtree(n, "sugen");
8527dd7cddfSDavid du Colombier 	}
8536891d857SDavid du Colombier 	if(typev[n->type->etype]) {
8546891d857SDavid du Colombier 		diag(n, "old vlong sugen: %O", n->op);
8556891d857SDavid du Colombier 		return;
8566891d857SDavid du Colombier 	}
8577dd7cddfSDavid du Colombier 	switch(n->op) {
8587dd7cddfSDavid du Colombier 	case OIND:
8597dd7cddfSDavid du Colombier 		if(nn == Z) {
8607dd7cddfSDavid du Colombier 			nullwarn(n->left, Z);
8617dd7cddfSDavid du Colombier 			break;
8627dd7cddfSDavid du Colombier 		}
8637dd7cddfSDavid du Colombier 
8647dd7cddfSDavid du Colombier 	default:
8657dd7cddfSDavid du Colombier 		goto copy;
8667dd7cddfSDavid du Colombier 
8677dd7cddfSDavid du Colombier 	case ODOT:
8687dd7cddfSDavid du Colombier 		l = n->left;
8697dd7cddfSDavid du Colombier 		sugen(l, nodrat, l->type->width);
8707dd7cddfSDavid du Colombier 		if(nn != Z) {
8717dd7cddfSDavid du Colombier 			warn(n, "non-interruptable temporary");
8727dd7cddfSDavid du Colombier 			nod1 = *nodrat;
8737dd7cddfSDavid du Colombier 			r = n->right;
8747dd7cddfSDavid du Colombier 			if(!r || r->op != OCONST) {
8757dd7cddfSDavid du Colombier 				diag(n, "DOT and no offset");
8767dd7cddfSDavid du Colombier 				break;
8777dd7cddfSDavid du Colombier 			}
8787dd7cddfSDavid du Colombier 			nod1.xoffset += (long)r->vconst;
8797dd7cddfSDavid du Colombier 			nod1.type = n->type;
8807dd7cddfSDavid du Colombier 			sugen(&nod1, nn, w);
8817dd7cddfSDavid du Colombier 		}
8827dd7cddfSDavid du Colombier 		break;
8837dd7cddfSDavid du Colombier 
8847dd7cddfSDavid du Colombier 	case OSTRUCT:
8857dd7cddfSDavid du Colombier 		/*
8867dd7cddfSDavid du Colombier 		 * rewrite so lhs has no side effects
8877dd7cddfSDavid du Colombier 		 */
8887dd7cddfSDavid du Colombier 		if(nn != Z && side(nn)) {
8897dd7cddfSDavid du Colombier 			nod1 = *n;
8907dd7cddfSDavid du Colombier 			nod1.type = typ(TIND, n->type);
8917dd7cddfSDavid du Colombier 			regalloc(&nod2, &nod1, Z);
8927dd7cddfSDavid du Colombier 			lcgen(nn, &nod2);
8937dd7cddfSDavid du Colombier 			regsalloc(&nod0, &nod1);
8947dd7cddfSDavid du Colombier 			gopcode(OAS, &nod2, Z, &nod0);
8957dd7cddfSDavid du Colombier 			regfree(&nod2);
8967dd7cddfSDavid du Colombier 
8977dd7cddfSDavid du Colombier 			nod1 = *n;
8987dd7cddfSDavid du Colombier 			nod1.op = OIND;
8997dd7cddfSDavid du Colombier 			nod1.left = &nod0;
9007dd7cddfSDavid du Colombier 			nod1.right = Z;
9017dd7cddfSDavid du Colombier 			nod1.complex = 1;
9027dd7cddfSDavid du Colombier 
9037dd7cddfSDavid du Colombier 			sugen(n, &nod1, w);
9047dd7cddfSDavid du Colombier 			return;
9057dd7cddfSDavid du Colombier 		}
9067dd7cddfSDavid du Colombier 
9077dd7cddfSDavid du Colombier 		r = n->left;
9087dd7cddfSDavid du Colombier 		for(t = n->type->link; t != T; t = t->down) {
9097dd7cddfSDavid du Colombier 			l = r;
9107dd7cddfSDavid du Colombier 			if(r->op == OLIST) {
9117dd7cddfSDavid du Colombier 				l = r->left;
9127dd7cddfSDavid du Colombier 				r = r->right;
9137dd7cddfSDavid du Colombier 			}
9147dd7cddfSDavid du Colombier 			if(nn == Z) {
9157dd7cddfSDavid du Colombier 				cgen(l, nn);
9167dd7cddfSDavid du Colombier 				continue;
9177dd7cddfSDavid du Colombier 			}
9187dd7cddfSDavid du Colombier 			/*
9197dd7cddfSDavid du Colombier 			 * hand craft *(&nn + o) = l
9207dd7cddfSDavid du Colombier 			 */
9217dd7cddfSDavid du Colombier 			nod0 = znode;
9227dd7cddfSDavid du Colombier 			nod0.op = OAS;
9237dd7cddfSDavid du Colombier 			nod0.type = t;
9247dd7cddfSDavid du Colombier 			nod0.left = &nod1;
9257dd7cddfSDavid du Colombier 			nod0.right = l;
9267dd7cddfSDavid du Colombier 
9277dd7cddfSDavid du Colombier 			nod1 = znode;
9287dd7cddfSDavid du Colombier 			nod1.op = OIND;
9297dd7cddfSDavid du Colombier 			nod1.type = t;
9307dd7cddfSDavid du Colombier 			nod1.left = &nod2;
9317dd7cddfSDavid du Colombier 
9327dd7cddfSDavid du Colombier 			nod2 = znode;
9337dd7cddfSDavid du Colombier 			nod2.op = OADD;
9347dd7cddfSDavid du Colombier 			nod2.type = typ(TIND, t);
9357dd7cddfSDavid du Colombier 			nod2.left = &nod3;
9367dd7cddfSDavid du Colombier 			nod2.right = &nod4;
9377dd7cddfSDavid du Colombier 
9387dd7cddfSDavid du Colombier 			nod3 = znode;
9397dd7cddfSDavid du Colombier 			nod3.op = OADDR;
9407dd7cddfSDavid du Colombier 			nod3.type = nod2.type;
9417dd7cddfSDavid du Colombier 			nod3.left = nn;
9427dd7cddfSDavid du Colombier 
9437dd7cddfSDavid du Colombier 			nod4 = znode;
9447dd7cddfSDavid du Colombier 			nod4.op = OCONST;
9457dd7cddfSDavid du Colombier 			nod4.type = nod2.type;
9467dd7cddfSDavid du Colombier 			nod4.vconst = t->offset;
9477dd7cddfSDavid du Colombier 
9487dd7cddfSDavid du Colombier 			ccom(&nod0);
9497dd7cddfSDavid du Colombier 			acom(&nod0);
9507dd7cddfSDavid du Colombier 			xcom(&nod0);
9517dd7cddfSDavid du Colombier 			nod0.addable = 0;
9527dd7cddfSDavid du Colombier 
9537dd7cddfSDavid du Colombier 			/* prtree(&nod0, "hand craft"); /* */
9547dd7cddfSDavid du Colombier 			cgen(&nod0, Z);
9557dd7cddfSDavid du Colombier 		}
9567dd7cddfSDavid du Colombier 		break;
9577dd7cddfSDavid du Colombier 
9587dd7cddfSDavid du Colombier 	case OAS:
9597dd7cddfSDavid du Colombier 		if(nn == Z) {
9607dd7cddfSDavid du Colombier 			if(n->addable < INDEXED)
9617dd7cddfSDavid du Colombier 				sugen(n->right, n->left, w);
9627dd7cddfSDavid du Colombier 			break;
9637dd7cddfSDavid du Colombier 		}
9647dd7cddfSDavid du Colombier 		/* BOTCH -- functions can clobber rathole */
9657dd7cddfSDavid du Colombier 		sugen(n->right, nodrat, w);
9667dd7cddfSDavid du Colombier 		warn(n, "non-interruptable temporary");
9677dd7cddfSDavid du Colombier 		sugen(nodrat, n->left, w);
9687dd7cddfSDavid du Colombier 		sugen(nodrat, nn, w);
9697dd7cddfSDavid du Colombier 		break;
9707dd7cddfSDavid du Colombier 
9717dd7cddfSDavid du Colombier 	case OFUNC:
9726891d857SDavid du Colombier 		/* this transformation should probably be done earlier */
9737dd7cddfSDavid du Colombier 		if(nn == Z) {
9747dd7cddfSDavid du Colombier 			sugen(n, nodrat, w);
9757dd7cddfSDavid du Colombier 			break;
9767dd7cddfSDavid du Colombier 		}
9777dd7cddfSDavid du Colombier 		if(nn->op != OIND) {
9787dd7cddfSDavid du Colombier 			nn = new1(OADDR, nn, Z);
9797dd7cddfSDavid du Colombier 			nn->type = types[TIND];
9807dd7cddfSDavid du Colombier 			nn->addable = 0;
9817dd7cddfSDavid du Colombier 		} else
9827dd7cddfSDavid du Colombier 			nn = nn->left;
9837dd7cddfSDavid du Colombier 		n = new(OFUNC, n->left, new(OLIST, nn, n->right));
9846891d857SDavid du Colombier 		n->complex = FNX;
9857dd7cddfSDavid du Colombier 		n->type = types[TVOID];
9867dd7cddfSDavid du Colombier 		n->left->type = types[TVOID];
9877dd7cddfSDavid du Colombier 		cgen(n, Z);
9887dd7cddfSDavid du Colombier 		break;
9897dd7cddfSDavid du Colombier 
9907dd7cddfSDavid du Colombier 	case OCOND:
9917dd7cddfSDavid du Colombier 		bcgen(n->left, 1);
9927dd7cddfSDavid du Colombier 		p1 = p;
9937dd7cddfSDavid du Colombier 		sugen(n->right->left, nn, w);
9947dd7cddfSDavid du Colombier 		gbranch(OGOTO);
9957dd7cddfSDavid du Colombier 		patch(p1, pc);
9967dd7cddfSDavid du Colombier 		p1 = p;
9977dd7cddfSDavid du Colombier 		sugen(n->right->right, nn, w);
9987dd7cddfSDavid du Colombier 		patch(p1, pc);
9997dd7cddfSDavid du Colombier 		break;
10007dd7cddfSDavid du Colombier 
10017dd7cddfSDavid du Colombier 	case OCOMMA:
10027dd7cddfSDavid du Colombier 		cgen(n->left, Z);
10037dd7cddfSDavid du Colombier 		sugen(n->right, nn, w);
10047dd7cddfSDavid du Colombier 		break;
10057dd7cddfSDavid du Colombier 	}
10067dd7cddfSDavid du Colombier 	return;
10077dd7cddfSDavid du Colombier 
10087dd7cddfSDavid du Colombier copy:
10097dd7cddfSDavid du Colombier 	if(nn == Z)
10107dd7cddfSDavid du Colombier 		return;
10117dd7cddfSDavid du Colombier 	if(n->complex >= FNX && nn->complex >= FNX) {
10127dd7cddfSDavid du Colombier 		t = nn->type;
10137dd7cddfSDavid du Colombier 		nn->type = types[TLONG];
10147dd7cddfSDavid du Colombier 		regialloc(&nod1, nn, Z);
10157dd7cddfSDavid du Colombier 		lcgen(nn, &nod1);
10167dd7cddfSDavid du Colombier 		regsalloc(&nod2, nn);
10177dd7cddfSDavid du Colombier 		nn->type = t;
10187dd7cddfSDavid du Colombier 
10196891d857SDavid du Colombier 		gmove(&nod1, &nod2);
10207dd7cddfSDavid du Colombier 		regfree(&nod1);
10217dd7cddfSDavid du Colombier 
10227dd7cddfSDavid du Colombier 		nod2.type = typ(TIND, t);
10237dd7cddfSDavid du Colombier 
10247dd7cddfSDavid du Colombier 		nod1 = nod2;
10257dd7cddfSDavid du Colombier 		nod1.op = OIND;
10267dd7cddfSDavid du Colombier 		nod1.left = &nod2;
10277dd7cddfSDavid du Colombier 		nod1.right = Z;
10287dd7cddfSDavid du Colombier 		nod1.complex = 1;
10297dd7cddfSDavid du Colombier 		nod1.type = t;
10307dd7cddfSDavid du Colombier 
10317dd7cddfSDavid du Colombier 		sugen(n, &nod1, w);
10327dd7cddfSDavid du Colombier 		return;
10337dd7cddfSDavid du Colombier 	}
10347dd7cddfSDavid du Colombier 
10357dd7cddfSDavid du Colombier 	if(n->complex > nn->complex) {
10367dd7cddfSDavid du Colombier 		t = n->type;
10377dd7cddfSDavid du Colombier 		n->type = types[TLONG];
10387dd7cddfSDavid du Colombier 		reglcgen(&nod1, n, Z);
10397dd7cddfSDavid du Colombier 		n->type = t;
10407dd7cddfSDavid du Colombier 
10417dd7cddfSDavid du Colombier 		t = nn->type;
10427dd7cddfSDavid du Colombier 		nn->type = types[TLONG];
10437dd7cddfSDavid du Colombier 		reglcgen(&nod2, nn, Z);
10447dd7cddfSDavid du Colombier 		nn->type = t;
10457dd7cddfSDavid du Colombier 	} else {
10467dd7cddfSDavid du Colombier 		t = nn->type;
10477dd7cddfSDavid du Colombier 		nn->type = types[TLONG];
10487dd7cddfSDavid du Colombier 		reglcgen(&nod2, nn, Z);
10497dd7cddfSDavid du Colombier 		nn->type = t;
10507dd7cddfSDavid du Colombier 
10517dd7cddfSDavid du Colombier 		t = n->type;
10527dd7cddfSDavid du Colombier 		n->type = types[TLONG];
10537dd7cddfSDavid du Colombier 		reglcgen(&nod1, n, Z);
10547dd7cddfSDavid du Colombier 		n->type = t;
10557dd7cddfSDavid du Colombier 	}
10567dd7cddfSDavid du Colombier 
10577dd7cddfSDavid du Colombier 	w /= SZ_LONG;
10587dd7cddfSDavid du Colombier 	if(w <= 5) {
10597dd7cddfSDavid du Colombier 		layout(&nod1, &nod2, w, 0, Z);
10607dd7cddfSDavid du Colombier 		goto out;
10617dd7cddfSDavid du Colombier 	}
10627dd7cddfSDavid du Colombier 
10637dd7cddfSDavid du Colombier 	/*
10647dd7cddfSDavid du Colombier 	 * minimize space for unrolling loop
10657dd7cddfSDavid du Colombier 	 * 3,4,5 times. (6 or more is never minimum)
10667dd7cddfSDavid du Colombier 	 * if small structure, try 2 also.
10677dd7cddfSDavid du Colombier 	 */
10687dd7cddfSDavid du Colombier 	c = 0; /* set */
10697dd7cddfSDavid du Colombier 	m = 100;
10707dd7cddfSDavid du Colombier 	i = 3;
10717dd7cddfSDavid du Colombier 	if(w <= 15)
10727dd7cddfSDavid du Colombier 		i = 2;
10737dd7cddfSDavid du Colombier 	for(; i<=5; i++)
10747dd7cddfSDavid du Colombier 		if(i + w%i <= m) {
10757dd7cddfSDavid du Colombier 			c = i;
10767dd7cddfSDavid du Colombier 			m = c + w%c;
10777dd7cddfSDavid du Colombier 		}
10787dd7cddfSDavid du Colombier 
10797dd7cddfSDavid du Colombier 	regalloc(&nod3, &regnode, Z);
10807dd7cddfSDavid du Colombier 	layout(&nod1, &nod2, w%c, w/c, &nod3);
10817dd7cddfSDavid du Colombier 
10827dd7cddfSDavid du Colombier 	pc1 = pc;
10837dd7cddfSDavid du Colombier 	layout(&nod1, &nod2, c, 0, Z);
10847dd7cddfSDavid du Colombier 
10857dd7cddfSDavid du Colombier 	gopcode(OSUB, nodconst(1L), Z, &nod3);
10867dd7cddfSDavid du Colombier 	nod1.op = OREGISTER;
10877dd7cddfSDavid du Colombier 	gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1);
10887dd7cddfSDavid du Colombier 	nod2.op = OREGISTER;
10897dd7cddfSDavid du Colombier 	gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2);
10907dd7cddfSDavid du Colombier 
10917dd7cddfSDavid du Colombier 	gopcode(OGT, &nod3, Z, nodconst(0));
10927dd7cddfSDavid du Colombier 	patch(p, pc1);
10937dd7cddfSDavid du Colombier 
10947dd7cddfSDavid du Colombier 	regfree(&nod3);
10957dd7cddfSDavid du Colombier out:
10967dd7cddfSDavid du Colombier 	regfree(&nod1);
10977dd7cddfSDavid du Colombier 	regfree(&nod2);
10987dd7cddfSDavid du Colombier }
10997dd7cddfSDavid du Colombier 
11007dd7cddfSDavid du Colombier void
layout(Node * f,Node * t,int c,int cv,Node * cn)11017dd7cddfSDavid du Colombier layout(Node *f, Node *t, int c, int cv, Node *cn)
11027dd7cddfSDavid du Colombier {
11037dd7cddfSDavid du Colombier 	Node t1, t2;
11047dd7cddfSDavid du Colombier 
11057dd7cddfSDavid du Colombier 	while(c > 3) {
11067dd7cddfSDavid du Colombier 		layout(f, t, 2, 0, Z);
11077dd7cddfSDavid du Colombier 		c -= 2;
11087dd7cddfSDavid du Colombier 	}
11097dd7cddfSDavid du Colombier 
11107dd7cddfSDavid du Colombier 	regalloc(&t1, &regnode, Z);
11117dd7cddfSDavid du Colombier 	regalloc(&t2, &regnode, Z);
11127dd7cddfSDavid du Colombier 	if(c > 0) {
11137dd7cddfSDavid du Colombier 		gopcode(OAS, f, Z, &t1);
11147dd7cddfSDavid du Colombier 		f->xoffset += SZ_LONG;
11157dd7cddfSDavid du Colombier 	}
11167dd7cddfSDavid du Colombier 	if(cn != Z)
11177dd7cddfSDavid du Colombier 		gopcode(OAS, nodconst(cv), Z, cn);
11187dd7cddfSDavid du Colombier 	if(c > 1) {
11197dd7cddfSDavid du Colombier 		gopcode(OAS, f, Z, &t2);
11207dd7cddfSDavid du Colombier 		f->xoffset += SZ_LONG;
11217dd7cddfSDavid du Colombier 	}
11227dd7cddfSDavid du Colombier 	if(c > 0) {
11237dd7cddfSDavid du Colombier 		gopcode(OAS, &t1, Z, t);
11247dd7cddfSDavid du Colombier 		t->xoffset += SZ_LONG;
11257dd7cddfSDavid du Colombier 	}
11267dd7cddfSDavid du Colombier 	if(c > 2) {
11277dd7cddfSDavid du Colombier 		gopcode(OAS, f, Z, &t1);
11287dd7cddfSDavid du Colombier 		f->xoffset += SZ_LONG;
11297dd7cddfSDavid du Colombier 	}
11307dd7cddfSDavid du Colombier 	if(c > 1) {
11317dd7cddfSDavid du Colombier 		gopcode(OAS, &t2, Z, t);
11327dd7cddfSDavid du Colombier 		t->xoffset += SZ_LONG;
11337dd7cddfSDavid du Colombier 	}
11347dd7cddfSDavid du Colombier 	if(c > 2) {
11357dd7cddfSDavid du Colombier 		gopcode(OAS, &t1, Z, t);
11367dd7cddfSDavid du Colombier 		t->xoffset += SZ_LONG;
11377dd7cddfSDavid du Colombier 	}
11387dd7cddfSDavid du Colombier 	regfree(&t1);
11397dd7cddfSDavid du Colombier 	regfree(&t2);
11407dd7cddfSDavid du Colombier }
11416891d857SDavid du Colombier 
11426891d857SDavid du Colombier /*
11436891d857SDavid du Colombier  * is the vlong's value directly addressible?
11446891d857SDavid du Colombier  */
11456891d857SDavid du Colombier int
isvdirect(Node * n)11466891d857SDavid du Colombier isvdirect(Node *n)
11476891d857SDavid du Colombier {
11486891d857SDavid du Colombier 	return n->op == ONAME || n->op == OCONST || n->op == OINDREG;
11496891d857SDavid du Colombier }
11506891d857SDavid du Colombier 
11516891d857SDavid du Colombier /*
11526891d857SDavid du Colombier  * can the constant be used with given vlong op?
11536891d857SDavid du Colombier  */
11546891d857SDavid du Colombier static int
isvconstable(int o,vlong v)11556891d857SDavid du Colombier isvconstable(int o, vlong v)
11566891d857SDavid du Colombier {
11576891d857SDavid du Colombier 	switch(o) {
11586891d857SDavid du Colombier 	case OADD:
11596891d857SDavid du Colombier 	case OASADD:
11606891d857SDavid du Colombier 		/* there isn't an immediate form for ADDE/SUBE, but there are special ADDME/ADDZE etc */
11616891d857SDavid du Colombier 		return v == 0 || v == -1;
11626891d857SDavid du Colombier 	case OAND:
11636891d857SDavid du Colombier 	case OOR:
11646891d857SDavid du Colombier 	case OXOR:
11656891d857SDavid du Colombier 	case OLSHR:
11666891d857SDavid du Colombier 	case OASHL:
11676891d857SDavid du Colombier 	case OASHR:
11686891d857SDavid du Colombier 	case OASLSHR:
11696891d857SDavid du Colombier 	case OASASHL:
11706891d857SDavid du Colombier 	case OASASHR:
11716891d857SDavid du Colombier 		return 1;
11726891d857SDavid du Colombier 	}
11736891d857SDavid du Colombier 	return 0;
11746891d857SDavid du Colombier }
11756891d857SDavid du Colombier 
11766891d857SDavid du Colombier /*
11776891d857SDavid du Colombier  * most 64-bit operations: cgen into a register pair, then operate.
11786891d857SDavid du Colombier  * 64-bit comparisons are handled a little differently because the two underlying
11796891d857SDavid du Colombier  * comparisons can be compiled separately, since the calculations don't interact.
11806891d857SDavid du Colombier  */
11816891d857SDavid du Colombier 
11826891d857SDavid du Colombier static void
vcgen(Node * n,Node * o,int * f)11836891d857SDavid du Colombier vcgen(Node *n, Node *o, int *f)
11846891d857SDavid du Colombier {
11856891d857SDavid du Colombier 	*f = 0;
11866891d857SDavid du Colombier 	if(!isvdirect(n)) {
11876891d857SDavid du Colombier 		if(n->complex >= FNX) {
11886891d857SDavid du Colombier 			regsalloc(o, n);
11896891d857SDavid du Colombier 			cgen(n, o);
11906891d857SDavid du Colombier 			return;
11916891d857SDavid du Colombier 		}
11926891d857SDavid du Colombier 		*f = 1;
11936891d857SDavid du Colombier 		if(n->addable < INDEXED && n->op != OIND && n->op != OINDEX) {
11946891d857SDavid du Colombier 			regalloc(o, n, Z);
11956891d857SDavid du Colombier 			cgen(n, o);
11966891d857SDavid du Colombier 		} else
11976891d857SDavid du Colombier 			reglcgen(o, n, Z);
11986891d857SDavid du Colombier 	} else
11996891d857SDavid du Colombier 		*o = *n;
12006891d857SDavid du Colombier }
12016891d857SDavid du Colombier 
12026891d857SDavid du Colombier static int
isuns(int op)12036891d857SDavid du Colombier isuns(int op)
12046891d857SDavid du Colombier {
12056891d857SDavid du Colombier 	switch(op){
12066891d857SDavid du Colombier 	case OLO:
12076891d857SDavid du Colombier 	case OLS:
12086891d857SDavid du Colombier 	case OHI:
12096891d857SDavid du Colombier 	case OHS:
12106891d857SDavid du Colombier 		return 1;
12116891d857SDavid du Colombier 	default:
12126891d857SDavid du Colombier 		return 0;
12136891d857SDavid du Colombier 	}
12146891d857SDavid du Colombier }
12156891d857SDavid du Colombier 
12166891d857SDavid du Colombier static void
gcmpv(Node * l,Node * r,void (* mov)(Node *,Node *,int),int op)12176891d857SDavid du Colombier gcmpv(Node *l, Node *r, void (*mov)(Node*, Node*, int), int op)
12186891d857SDavid du Colombier {
12196891d857SDavid du Colombier 	Node vl, vr;
12206891d857SDavid du Colombier 
12216891d857SDavid du Colombier 	regalloc(&vl, &regnode, Z);
12226891d857SDavid du Colombier 	mov(l, &vl, 0);
12236891d857SDavid du Colombier 	regalloc(&vr, &regnode, Z);
12246891d857SDavid du Colombier 	mov(r, &vr, 1+isuns(op));
12256891d857SDavid du Colombier 	gopcode(op, &vl, Z, &vr);
12266891d857SDavid du Colombier 	if(vl.op == OREGISTER)
12276891d857SDavid du Colombier 		regfree(&vl);
12286891d857SDavid du Colombier 	if(vr.op == OREGISTER)
12296891d857SDavid du Colombier 		regfree(&vr);
12306891d857SDavid du Colombier }
12316891d857SDavid du Colombier 
12326891d857SDavid du Colombier static void
brcondv(Node * l,Node * r,int chi,int clo)12336891d857SDavid du Colombier brcondv(Node *l, Node *r, int chi, int clo)
12346891d857SDavid du Colombier {
12356891d857SDavid du Colombier 	Prog *p1, *p2, *p3, *p4;
12366891d857SDavid du Colombier 
12376891d857SDavid du Colombier 	gcmpv(l, r, gloadhi, chi);
12386891d857SDavid du Colombier 	p1 = p;
12396891d857SDavid du Colombier 	gins(ABNE, Z, Z);
12406891d857SDavid du Colombier 	p2 = p;
12416891d857SDavid du Colombier 	gcmpv(l, r, gloadlo, clo);
12426891d857SDavid du Colombier 	p3 = p;
12436891d857SDavid du Colombier 	gbranch(OGOTO);
12446891d857SDavid du Colombier 	p4 = p;
12456891d857SDavid du Colombier 	patch(p1, pc);
12466891d857SDavid du Colombier 	patch(p3, pc);
12476891d857SDavid du Colombier 	gbranch(OGOTO);
12486891d857SDavid du Colombier 	patch(p2, pc);
12496891d857SDavid du Colombier 	patch(p4, pc);
12506891d857SDavid du Colombier }
12516891d857SDavid du Colombier 
12526891d857SDavid du Colombier static void
testv(Node * n,int true)12536891d857SDavid du Colombier testv(Node *n, int true)
12546891d857SDavid du Colombier {
12556891d857SDavid du Colombier 	Node nod;
12566891d857SDavid du Colombier 
12576891d857SDavid du Colombier 	nod = znode;
12586891d857SDavid du Colombier 	nod.op = ONE;
12596891d857SDavid du Colombier 	nod.left = n;
12606891d857SDavid du Colombier 	nod.right = new1(0, Z, Z);
12616891d857SDavid du Colombier 	*nod.right = *nodconst(0);
12626891d857SDavid du Colombier 	nod.right->type = n->type;
12636891d857SDavid du Colombier 	nod.type = types[TLONG];
12646891d857SDavid du Colombier 	cmpv(&nod, true, Z);
12656891d857SDavid du Colombier }
12666891d857SDavid du Colombier 
12676891d857SDavid du Colombier /*
12686891d857SDavid du Colombier  * comparison for vlong does high and low order parts separately,
12696891d857SDavid du Colombier  * which saves loading the latter if the high order comparison suffices
12706891d857SDavid du Colombier  */
12716891d857SDavid du Colombier static void
cmpv(Node * n,int true,Node * nn)12726891d857SDavid du Colombier cmpv(Node *n, int true, Node *nn)
12736891d857SDavid du Colombier {
12746891d857SDavid du Colombier 	Node *l, *r, nod, nod1;
12756891d857SDavid du Colombier 	int o, f1, f2;
12766891d857SDavid du Colombier 	Prog *p1, *p2;
12776891d857SDavid du Colombier 	long curs;
12786891d857SDavid du Colombier 
12796891d857SDavid du Colombier 	if(debug['g']) {
12806891d857SDavid du Colombier 		if(nn != nil)
12816891d857SDavid du Colombier 			prtree(nn, "cmpv lhs");
12826891d857SDavid du Colombier 		prtree(n, "cmpv");
12836891d857SDavid du Colombier 	}
12846891d857SDavid du Colombier 	curs = cursafe;
12856891d857SDavid du Colombier 	l = n->left;
12866891d857SDavid du Colombier 	r = n->right;
12876891d857SDavid du Colombier 	if(l->complex >= FNX && r->complex >= FNX) {
12886891d857SDavid du Colombier 		regsalloc(&nod1, r);
12896891d857SDavid du Colombier 		cgen(r, &nod1);
12906891d857SDavid du Colombier 		nod = *n;
12916891d857SDavid du Colombier 		nod.right = &nod1;
12926891d857SDavid du Colombier 		cmpv(&nod, true, nn);
12936891d857SDavid du Colombier 		cursafe = curs;
12946891d857SDavid du Colombier 		return;
12956891d857SDavid du Colombier 	}
12966891d857SDavid du Colombier 	if(l->complex >= r->complex) {
12976891d857SDavid du Colombier 		vcgen(l, &nod1, &f1);
12986891d857SDavid du Colombier 		vcgen(r, &nod, &f2);
12996891d857SDavid du Colombier 	} else {
13006891d857SDavid du Colombier 		vcgen(r, &nod, &f2);
13016891d857SDavid du Colombier 		vcgen(l, &nod1, &f1);
13026891d857SDavid du Colombier 	}
13036891d857SDavid du Colombier 	nod.type = types[TLONG];
13046891d857SDavid du Colombier 	nod1.type = types[TLONG];
13056891d857SDavid du Colombier 	o = n->op;
13066891d857SDavid du Colombier 	if(true)
13076891d857SDavid du Colombier 		o = comrel[relindex(o)];
13086891d857SDavid du Colombier 	switch(o){
13096891d857SDavid du Colombier 	case OEQ:
13106891d857SDavid du Colombier 		gcmpv(&nod1, &nod, gloadhi, ONE);
13116891d857SDavid du Colombier 		p1 = p;
13126891d857SDavid du Colombier 		gcmpv(&nod1, &nod, gloadlo, ONE);
13136891d857SDavid du Colombier 		p2 = p;
13146891d857SDavid du Colombier 		gbranch(OGOTO);
13156891d857SDavid du Colombier 		patch(p1, pc);
13166891d857SDavid du Colombier 		patch(p2, pc);
13176891d857SDavid du Colombier 		break;
13186891d857SDavid du Colombier 	case ONE:
13196891d857SDavid du Colombier 		gcmpv(&nod1, &nod, gloadhi, ONE);
13206891d857SDavid du Colombier 		p1 = p;
13216891d857SDavid du Colombier 		gcmpv(&nod1, &nod, gloadlo, OEQ);
13226891d857SDavid du Colombier 		p2 = p;
13236891d857SDavid du Colombier 		patch(p1, pc);
13246891d857SDavid du Colombier 		gbranch(OGOTO);
13256891d857SDavid du Colombier 		patch(p2, pc);
13266891d857SDavid du Colombier 		break;
13276891d857SDavid du Colombier 	case OLE:
13286891d857SDavid du Colombier 		brcondv(&nod1, &nod, OLT, OLS);
13296891d857SDavid du Colombier 		break;
13306891d857SDavid du Colombier 	case OGT:
13316891d857SDavid du Colombier 		brcondv(&nod1, &nod, OGT, OHI);
13326891d857SDavid du Colombier 		break;
13336891d857SDavid du Colombier 	case OLS:
13346891d857SDavid du Colombier 		brcondv(&nod1, &nod, OLO, OLS);
13356891d857SDavid du Colombier 		break;
13366891d857SDavid du Colombier 	case OHI:
13376891d857SDavid du Colombier 		brcondv(&nod1, &nod, OHI, OHI);
13386891d857SDavid du Colombier 		break;
13396891d857SDavid du Colombier 	case OLT:
13406891d857SDavid du Colombier 		brcondv(&nod1, &nod, OLT, OLO);
13416891d857SDavid du Colombier 		break;
13426891d857SDavid du Colombier 	case OGE:
13436891d857SDavid du Colombier 		brcondv(&nod1, &nod, OGT, OHS);
13446891d857SDavid du Colombier 		break;
13456891d857SDavid du Colombier 	case OLO:
13466891d857SDavid du Colombier 		brcondv(&nod1, &nod, OLO, OLO);
13476891d857SDavid du Colombier 		break;
13486891d857SDavid du Colombier 	case OHS:
13496891d857SDavid du Colombier 		brcondv(&nod1, &nod, OHI, OHS);
13506891d857SDavid du Colombier 		break;
13516891d857SDavid du Colombier 	default:
13526891d857SDavid du Colombier 		diag(n, "bad cmpv");
13536891d857SDavid du Colombier 		return;
13546891d857SDavid du Colombier 	}
13556891d857SDavid du Colombier 	if(f1)
13566891d857SDavid du Colombier 		regfree(&nod1);
13576891d857SDavid du Colombier 	if(f2)
13586891d857SDavid du Colombier 		regfree(&nod);
13596891d857SDavid du Colombier 	cursafe = curs;
13606891d857SDavid du Colombier }
13616891d857SDavid du Colombier 
13626891d857SDavid du Colombier static void
cgen64(Node * n,Node * nn)13636891d857SDavid du Colombier cgen64(Node *n, Node *nn)
13646891d857SDavid du Colombier {
13656891d857SDavid du Colombier 	Node *l, *r, *d;
13666891d857SDavid du Colombier 	Node nod, nod1;
13676891d857SDavid du Colombier 	long curs;
13686891d857SDavid du Colombier 	Type *t;
13696891d857SDavid du Colombier 	int o, m;
13706891d857SDavid du Colombier 
13716891d857SDavid du Colombier 	curs = cursafe;
13726891d857SDavid du Colombier 	l = n->left;
13736891d857SDavid du Colombier 	r = n->right;
13746891d857SDavid du Colombier 	o = n->op;
13756891d857SDavid du Colombier 	switch(o) {
13766891d857SDavid du Colombier 
13776891d857SDavid du Colombier 	case OCONST:
13786891d857SDavid du Colombier 		if(nn == Z) {
13796891d857SDavid du Colombier 			nullwarn(n->left, Z);
13806891d857SDavid du Colombier 			break;
13816891d857SDavid du Colombier 		}
13826891d857SDavid du Colombier 		if(nn->op != OREGPAIR) {
13836891d857SDavid du Colombier //prtree(n, "cgen64 const");
13846891d857SDavid du Colombier 			t = nn->type;
13856891d857SDavid du Colombier 			nn->type = types[TLONG];
13866891d857SDavid du Colombier 			reglcgen(&nod1, nn, Z);
13876891d857SDavid du Colombier 			nn->type = t;
13886891d857SDavid du Colombier 
13896891d857SDavid du Colombier 			if(align(0, types[TCHAR], Aarg1))	/* isbigendian */
13906891d857SDavid du Colombier 				gmove(nod32const(n->vconst>>32), &nod1);
13916891d857SDavid du Colombier 			else
13926891d857SDavid du Colombier 				gmove(nod32const(n->vconst), &nod1);
13936891d857SDavid du Colombier 			nod1.xoffset += SZ_LONG;
13946891d857SDavid du Colombier 			if(align(0, types[TCHAR], Aarg1))	/* isbigendian */
13956891d857SDavid du Colombier 				gmove(nod32const(n->vconst), &nod1);
13966891d857SDavid du Colombier 			else
13976891d857SDavid du Colombier 				gmove(nod32const(n->vconst>>32), &nod1);
13986891d857SDavid du Colombier 
13996891d857SDavid du Colombier 			regfree(&nod1);
14006891d857SDavid du Colombier 		} else
14016891d857SDavid du Colombier 			gmove(n, nn);
14026891d857SDavid du Colombier 		break;
14036891d857SDavid du Colombier 
14046891d857SDavid du Colombier 	case OCAST:
14056891d857SDavid du Colombier 		/*
14066891d857SDavid du Colombier 		 * convert from types l->n->nn
14076891d857SDavid du Colombier 		 */
14086891d857SDavid du Colombier 		if(typev[l->type->etype]){
14096891d857SDavid du Colombier 			/* vlong to non-vlong */
14106891d857SDavid du Colombier 			if(!isvdirect(l)) {
14116891d857SDavid du Colombier 				if(l->addable < INDEXED && l->op != OIND && l->op != OINDEX) {
14126891d857SDavid du Colombier 					regalloc(&nod, l, l);
14136891d857SDavid du Colombier 					cgen(l, &nod);
14146891d857SDavid du Colombier 					regalloc(&nod1, n, nn);
14156891d857SDavid du Colombier 					gmove(nod.right, &nod1);
14166891d857SDavid du Colombier 				} else {
14176891d857SDavid du Colombier 					reglcgen(&nod, l, Z);
14186891d857SDavid du Colombier 					regalloc(&nod1, n, nn);
14196891d857SDavid du Colombier 					gloadlo(&nod, &nod1, 0);	/* TO DO: not correct for typefd */
14206891d857SDavid du Colombier 				}
14216891d857SDavid du Colombier 				regfree(&nod);
14226891d857SDavid du Colombier 			} else {
14236891d857SDavid du Colombier 				regalloc(&nod1, n, nn);
14246891d857SDavid du Colombier 				gloadlo(l, &nod1, 0);	/* TO DO: not correct for typefd */
14256891d857SDavid du Colombier 			}
14266891d857SDavid du Colombier 		}else{
14276891d857SDavid du Colombier 			/* non-vlong to vlong */
14286891d857SDavid du Colombier 			regalloc(&nod, l, Z);
14296891d857SDavid du Colombier 			cgen(l, &nod);
14306891d857SDavid du Colombier 			regalloc(&nod1, n, nn);
14316891d857SDavid du Colombier 			gmove(&nod, nod1.right);
14326891d857SDavid du Colombier 			if(typeu[l->type->etype])
14336891d857SDavid du Colombier 				gmove(nodconst(0), nod1.left);
14346891d857SDavid du Colombier 			else
14356891d857SDavid du Colombier 				gopcode(OASHR, nodconst(31), nod1.right, nod1.left);
14366891d857SDavid du Colombier 			regfree(&nod);
14376891d857SDavid du Colombier 		}
14386891d857SDavid du Colombier 		gmove(&nod1, nn);
14396891d857SDavid du Colombier 		regfree(&nod1);
14406891d857SDavid du Colombier 		break;
14416891d857SDavid du Colombier 
14426891d857SDavid du Colombier 	case OFUNC:
14436891d857SDavid du Colombier 		/* this transformation should probably be done earlier */
14446891d857SDavid du Colombier 		if(nn == Z) {
14456891d857SDavid du Colombier 			regsalloc(&nod1, n);
14466891d857SDavid du Colombier 			nn = &nod1;
14476891d857SDavid du Colombier 		}
14486891d857SDavid du Colombier 		m = 0;
14496891d857SDavid du Colombier 		if(nn->op != OIND) {
14506891d857SDavid du Colombier 			if(nn->op == OREGPAIR) {
14516891d857SDavid du Colombier 				m = 1;
14526891d857SDavid du Colombier 				regsalloc(&nod1, nn);
14536891d857SDavid du Colombier 				d = &nod1;
14546891d857SDavid du Colombier 			}else
14556891d857SDavid du Colombier 				d = nn;
14566891d857SDavid du Colombier 			d = new1(OADDR, d, Z);
14576891d857SDavid du Colombier 			d->type = types[TIND];
14586891d857SDavid du Colombier 			d->addable = 0;
14596891d857SDavid du Colombier 		} else
14606891d857SDavid du Colombier 			d = nn->left;
14616891d857SDavid du Colombier 		n = new(OFUNC, l, new(OLIST, d, r));
14626891d857SDavid du Colombier 		n->complex = FNX;
14636891d857SDavid du Colombier 		n->type = types[TVOID];
14646891d857SDavid du Colombier 		n->left->type = types[TVOID];
14656891d857SDavid du Colombier 		cgen(n, Z);
14666891d857SDavid du Colombier 		if(m)
14676891d857SDavid du Colombier 			gmove(&nod1, nn);
14686891d857SDavid du Colombier 		break;
14696891d857SDavid du Colombier 
14706891d857SDavid du Colombier 	default:
14716891d857SDavid du Colombier 		diag(n, "bad cgen64 %O", o);
14726891d857SDavid du Colombier 		break;
14736891d857SDavid du Colombier 	}
14746891d857SDavid du Colombier 	cursafe = curs;
14756891d857SDavid du Colombier }
1476