xref: /plan9-contrib/sys/src/cmd/vc/cgen.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include "gc.h"
2 
3 void
4 cgen(Node *n, Node *nn)
5 {
6 	Node *l, *r;
7 	Prog *p1;
8 	Node nod, nod1, nod2, nod3, nod4;
9 	int o;
10 	long v, curs;
11 
12 	if(debug['g']) {
13 		prtree(nn, "cgen lhs");
14 		prtree(n, "cgen");
15 	}
16 	if(n == Z || n->type == T)
17 		return;
18 	if(typesu[n->type->etype] || typev[n->type->etype]) {
19 		sugen(n, nn, n->type->width);
20 		return;
21 	}
22 	if(n->addable > INDEXED) {
23 		if(nn != Z)
24 			gmove(n, nn);
25 		return;
26 	}
27 	curs = cursafe;
28 	l = n->left;
29 	r = n->right;
30 	o = n->op;
31 
32 	if(n->complex >= FNX)
33 	if(l->complex >= FNX)
34 	if(r != Z && r->complex >= FNX)
35 	switch(o) {
36 	default:
37 		regret(&nod, r);
38 		cgen(r, &nod);
39 
40 		regsalloc(&nod1, r);
41 		gopcode(OAS, &nod, Z, &nod1);
42 
43 		regfree(&nod);
44 		nod = *n;
45 		nod.right = &nod1;
46 		cgen(&nod, nn);
47 		return;
48 
49 	case OFUNC:
50 	case OCOMMA:
51 	case OANDAND:
52 	case OOROR:
53 	case OCOND:
54 	case ODOT:
55 		break;
56 	}
57 
58 	switch(o) {
59 	default:
60 		diag(n, "unknown op in cgen: %O", o);
61 		break;
62 
63 	case OAS:
64 		if(l->op == OBIT)
65 			goto bitas;
66 		if(l->addable >= INDEXED && l->complex < FNX) {
67 			if(nn != Z || r->addable < INDEXED) {
68 				regalloc(&nod, r, nn);
69 				cgen(r, &nod);
70 				gmove(&nod, l);
71 				regfree(&nod);
72 			} else
73 				gmove(r, l);
74 			break;
75 		}
76 		if(l->complex >= r->complex) {
77 			reglcgen(&nod1, l, Z);
78 			if(r->addable >= INDEXED) {
79 				gmove(r, &nod1);
80 				if(nn != Z)
81 					gmove(r, nn);
82 				regfree(&nod1);
83 				break;
84 			}
85 			regalloc(&nod, r, nn);
86 			cgen(r, &nod);
87 		} else {
88 			regalloc(&nod, r, nn);
89 			cgen(r, &nod);
90 			reglcgen(&nod1, l, Z);
91 		}
92 		gmove(&nod, &nod1);
93 		regfree(&nod);
94 		regfree(&nod1);
95 		break;
96 
97 	bitas:
98 		n = l->left;
99 		regalloc(&nod, r, nn);
100 		if(l->complex >= r->complex) {
101 			reglcgen(&nod1, n, Z);
102 			cgen(r, &nod);
103 		} else {
104 			cgen(r, &nod);
105 			reglcgen(&nod1, n, Z);
106 		}
107 		regalloc(&nod2, n, Z);
108 		gopcode(OAS, &nod1, Z, &nod2);
109 		bitstore(l, &nod, &nod1, &nod2, nn);
110 		break;
111 
112 	case OBIT:
113 		if(nn == Z) {
114 			nullwarn(l, Z);
115 			break;
116 		}
117 		bitload(n, &nod, Z, Z, nn);
118 		gopcode(OAS, &nod, Z, nn);
119 		regfree(&nod);
120 		break;
121 
122 	case OADD:
123 	case OSUB:
124 	case OAND:
125 	case OOR:
126 	case OXOR:
127 	case OLSHR:
128 	case OASHL:
129 	case OASHR:
130 		/*
131 		 * immediate operands
132 		 */
133 		if(nn != Z)
134 		if(r->op == OCONST)
135 		if(!typefd[n->type->etype]) {
136 			cgen(l, nn);
137 			if(r->vconst == 0)
138 			if(o != OAND)
139 				break;
140 			if(nn != Z)
141 				gopcode(o, r, Z, nn);
142 			break;
143 		}
144 
145 	case OLMUL:
146 	case OLDIV:
147 	case OLMOD:
148 	case OMUL:
149 	case ODIV:
150 	case OMOD:
151 		if(nn == Z) {
152 			nullwarn(l, r);
153 			break;
154 		}
155 		if(o == OMUL || o == OLMUL) {
156 			if(mulcon(n, nn))
157 				break;
158 		}
159 		if(l->complex >= r->complex) {
160 			regalloc(&nod, l, nn);
161 			cgen(l, &nod);
162 			regalloc(&nod1, r, Z);
163 			cgen(r, &nod1);
164 			gopcode(o, &nod1, Z, &nod);
165 		} else {
166 			regalloc(&nod, r, nn);
167 			cgen(r, &nod);
168 			regalloc(&nod1, l, Z);
169 			cgen(l, &nod1);
170 			gopcode(o, &nod, &nod1, &nod);
171 		}
172 		gopcode(OAS, &nod, Z, nn);
173 		regfree(&nod);
174 		regfree(&nod1);
175 		break;
176 
177 	case OASLSHR:
178 	case OASASHL:
179 	case OASASHR:
180 	case OASAND:
181 	case OASADD:
182 	case OASSUB:
183 	case OASXOR:
184 	case OASOR:
185 		if(l->op == OBIT)
186 			goto asbitop;
187 		if(r->op == OCONST)
188 		if(!typefd[n->type->etype]) {
189 			if(l->addable < INDEXED)
190 				reglcgen(&nod2, l, Z);
191 			else
192 				nod2 = *l;
193 			regalloc(&nod, r, nn);
194 			gopcode(OAS, &nod2, Z, &nod);
195 			gopcode(o, r, Z, &nod);
196 			gopcode(OAS, &nod, Z, &nod2);
197 
198 			regfree(&nod);
199 			if(l->addable < INDEXED)
200 				regfree(&nod2);
201 			break;
202 		}
203 
204 	case OASLMUL:
205 	case OASLDIV:
206 	case OASLMOD:
207 	case OASMUL:
208 	case OASDIV:
209 	case OASMOD:
210 		if(l->op == OBIT)
211 			goto asbitop;
212 		if(l->complex >= r->complex) {
213 			if(l->addable < INDEXED)
214 				reglcgen(&nod2, l, Z);
215 			else
216 				nod2 = *l;
217 			regalloc(&nod1, r, Z);
218 			cgen(r, &nod1);
219 		} else {
220 			regalloc(&nod1, r, Z);
221 			cgen(r, &nod1);
222 			if(l->addable < INDEXED)
223 				reglcgen(&nod2, l, Z);
224 			else
225 				nod2 = *l;
226 		}
227 
228 		regalloc(&nod, n, nn);
229 		gmove(&nod2, &nod);
230 		gopcode(o, &nod1, Z, &nod);
231 		gmove(&nod, &nod2);
232 		if(nn != Z)
233 			gopcode(OAS, &nod, Z, nn);
234 		regfree(&nod);
235 		regfree(&nod1);
236 		if(l->addable < INDEXED)
237 			regfree(&nod2);
238 		break;
239 
240 	asbitop:
241 		regalloc(&nod4, n, nn);
242 		if(l->complex >= r->complex) {
243 			bitload(l, &nod, &nod1, &nod2, &nod4);
244 			regalloc(&nod3, r, Z);
245 			cgen(r, &nod3);
246 		} else {
247 			regalloc(&nod3, r, Z);
248 			cgen(r, &nod3);
249 			bitload(l, &nod, &nod1, &nod2, &nod4);
250 		}
251 		gmove(&nod, &nod4);
252 		gopcode(o, &nod3, Z, &nod4);
253 		regfree(&nod3);
254 		gmove(&nod4, &nod);
255 		regfree(&nod4);
256 		bitstore(l, &nod, &nod1, &nod2, nn);
257 		break;
258 
259 	case OADDR:
260 		if(nn == Z) {
261 			nullwarn(l, Z);
262 			break;
263 		}
264 		lcgen(l, nn);
265 		break;
266 
267 	case OFUNC:
268 		if(l->complex >= FNX) {
269 			if(l->op != OIND)
270 				diag(n, "bad function call");
271 
272 			regret(&nod, l->left);
273 			cgen(l->left, &nod);
274 			regsalloc(&nod1, l->left);
275 			gopcode(OAS, &nod, Z, &nod1);
276 			regfree(&nod);
277 
278 			nod = *n;
279 			nod.left = &nod2;
280 			nod2 = *l;
281 			nod2.left = &nod1;
282 			nod2.complex = 1;
283 			cgen(&nod, nn);
284 
285 			return;
286 		}
287 		o = reg[REGARG];
288 		gargs(r, &nod, &nod1);
289 		if(l->addable < INDEXED) {
290 			reglcgen(&nod, l, Z);
291 			gopcode(OFUNC, Z, Z, &nod);
292 			regfree(&nod);
293 		} else
294 			gopcode(OFUNC, Z, Z, l);
295 		if(REGARG)
296 			if(o != reg[REGARG])
297 				reg[REGARG]--;
298 		if(nn != Z) {
299 			regret(&nod, n);
300 			gopcode(OAS, &nod, Z, nn);
301 			regfree(&nod);
302 		}
303 		break;
304 
305 	case OIND:
306 		if(nn == Z) {
307 			nullwarn(l, Z);
308 			break;
309 		}
310 		regialloc(&nod, n, nn);
311 		r = l;
312 		while(r->op == OADD)
313 			r = r->right;
314 		if(sconst(r)) {
315 			v = r->vconst;
316 			r->vconst = 0;
317 			cgen(l, &nod);
318 			nod.xoffset += v;
319 			r->vconst = v;
320 		} else
321 			cgen(l, &nod);
322 		regind(&nod, n);
323 		gopcode(OAS, &nod, Z, nn);
324 		regfree(&nod);
325 		break;
326 
327 	case OEQ:
328 	case ONE:
329 	case OLE:
330 	case OLT:
331 	case OGE:
332 	case OGT:
333 	case OLO:
334 	case OLS:
335 	case OHI:
336 	case OHS:
337 		if(nn == Z) {
338 			nullwarn(l, r);
339 			break;
340 		}
341 		boolgen(n, 1, nn);
342 		break;
343 
344 	case OANDAND:
345 	case OOROR:
346 		boolgen(n, 1, nn);
347 		if(nn == Z)
348 			patch(p, pc);
349 		break;
350 
351 	case ONOT:
352 		if(nn == Z) {
353 			nullwarn(l, Z);
354 			break;
355 		}
356 		boolgen(n, 1, nn);
357 		break;
358 
359 	case OCOMMA:
360 		cgen(l, Z);
361 		cgen(r, nn);
362 		break;
363 
364 	case OCAST:
365 		if(nn == Z) {
366 			nullwarn(l, Z);
367 			break;
368 		}
369 		/*
370 		 * convert from types l->n->nn
371 		 */
372 		if(nocast(l->type, n->type)) {
373 			if(nocast(n->type, nn->type)) {
374 				cgen(l, nn);
375 				break;
376 			}
377 		}
378 		regalloc(&nod, l, nn);
379 		cgen(l, &nod);
380 		regalloc(&nod1, n, &nod);
381 		gopcode(OAS, &nod, Z, &nod1);
382 		gopcode(OAS, &nod1, Z, nn);
383 		regfree(&nod1);
384 		regfree(&nod);
385 		break;
386 
387 	case ODOT:
388 		sugen(l, nodrat, l->type->width);
389 		if(nn != Z) {
390 			warn(n, "non-interruptable temporary");
391 			nod = *nodrat;
392 			if(!r || r->op != OCONST) {
393 				diag(n, "DOT and no offset");
394 				break;
395 			}
396 			nod.xoffset += (long)r->vconst;
397 			nod.type = n->type;
398 			cgen(&nod, nn);
399 		}
400 		break;
401 
402 	case OCOND:
403 		bcgen(l, 1);
404 		p1 = p;
405 		cgen(r->left, nn);
406 		gbranch(OGOTO);
407 		patch(p1, pc);
408 		p1 = p;
409 		cgen(r->right, nn);
410 		patch(p1, pc);
411 		break;
412 
413 	case OPOSTINC:
414 	case OPOSTDEC:
415 		v = 1;
416 		if(l->type->etype == TIND)
417 			v = l->type->link->width;
418 		if(o == OPOSTDEC)
419 			v = -v;
420 		if(l->op == OBIT)
421 			goto bitinc;
422 		if(nn == Z)
423 			goto pre;
424 
425 		if(l->addable < INDEXED)
426 			reglcgen(&nod2, l, Z);
427 		else
428 			nod2 = *l;
429 
430 		regalloc(&nod, l, nn);
431 		gopcode(OAS, &nod2, Z, &nod);
432 		regalloc(&nod1, l, Z);
433 		if(typefd[l->type->etype]) {
434 			regalloc(&nod3, l, Z);
435 			if(v < 0) {
436 				gopcode(OAS, nodfconst(-v), Z, &nod3);
437 				gopcode(OSUB, &nod3, &nod, &nod1);
438 			} else {
439 				gopcode(OAS, nodfconst(v), Z, &nod3);
440 				gopcode(OADD, &nod3, &nod, &nod1);
441 			}
442 			regfree(&nod3);
443 		} else
444 			gopcode(OADD, nodconst(v), &nod, &nod1);
445 		gopcode(OAS, &nod1, Z, &nod2);
446 
447 		regfree(&nod);
448 		regfree(&nod1);
449 		if(l->addable < INDEXED)
450 			regfree(&nod2);
451 		break;
452 
453 	case OPREINC:
454 	case OPREDEC:
455 		v = 1;
456 		if(l->type->etype == TIND)
457 			v = l->type->link->width;
458 		if(o == OPREDEC)
459 			v = -v;
460 		if(l->op == OBIT)
461 			goto bitinc;
462 
463 	pre:
464 		if(l->addable < INDEXED)
465 			reglcgen(&nod2, l, Z);
466 		else
467 			nod2 = *l;
468 
469 		regalloc(&nod, l, nn);
470 		gopcode(OAS, &nod2, Z, &nod);
471 		if(typefd[l->type->etype]) {
472 			regalloc(&nod3, l, Z);
473 			if(v < 0) {
474 				gopcode(OAS, nodfconst(-v), Z, &nod3);
475 				gopcode(OSUB, &nod3, Z, &nod);
476 			} else {
477 				gopcode(OAS, nodfconst(v), Z, &nod3);
478 				gopcode(OADD, &nod3, Z, &nod);
479 			}
480 			regfree(&nod3);
481 		} else
482 			gopcode(OADD, nodconst(v), Z, &nod);
483 		gopcode(OAS, &nod, Z, &nod2);
484 
485 		regfree(&nod);
486 		if(l->addable < INDEXED)
487 			regfree(&nod2);
488 		break;
489 
490 	bitinc:
491 		if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
492 			bitload(l, &nod, &nod1, &nod2, Z);
493 			gopcode(OAS, &nod, Z, nn);
494 			gopcode(OADD, nodconst(v), Z, &nod);
495 			bitstore(l, &nod, &nod1, &nod2, Z);
496 			break;
497 		}
498 		bitload(l, &nod, &nod1, &nod2, nn);
499 		gopcode(OADD, nodconst(v), Z, &nod);
500 		bitstore(l, &nod, &nod1, &nod2, nn);
501 		break;
502 	}
503 	cursafe = curs;
504 	return;
505 
506 bad:
507 	cursafe = curs;
508 	diag(n, "%O not implemented", o);
509 }
510 
511 void
512 reglcgen(Node *t, Node *n, Node *nn)
513 {
514 	Node *r;
515 	long v;
516 
517 	regialloc(t, n, nn);
518 	if(n->op == OIND) {
519 		r = n->left;
520 		while(r->op == OADD)
521 			r = r->right;
522 		if(sconst(r)) {
523 			v = r->vconst;
524 			r->vconst = 0;
525 			lcgen(n, t);
526 			t->xoffset += v;
527 			r->vconst = v;
528 			regind(t, n);
529 			return;
530 		}
531 	}
532 	lcgen(n, t);
533 	regind(t, n);
534 }
535 
536 void
537 lcgen(Node *n, Node *nn)
538 {
539 	Prog *p1;
540 	Node nod;
541 
542 	if(debug['g']) {
543 		prtree(nn, "lcgen lhs");
544 		prtree(n, "lcgen");
545 	}
546 	if(n == Z || n->type == T)
547 		return;
548 	if(nn == Z) {
549 		nn = &nod;
550 		regalloc(&nod, n, Z);
551 	}
552 	switch(n->op) {
553 	default:
554 		if(n->addable < INDEXED) {
555 			diag(n, "unknown op in lcgen: %O", n->op);
556 			break;
557 		}
558 		nod = *n;
559 		nod.op = OADDR;
560 		nod.left = n;
561 		nod.right = Z;
562 		nod.type = types[TIND];
563 		gopcode(OAS, &nod, Z, nn);
564 		break;
565 
566 	case OCOMMA:
567 		cgen(n->left, n->left);
568 		lcgen(n->right, nn);
569 		break;
570 
571 	case OIND:
572 		cgen(n->left, nn);
573 		break;
574 
575 	case OCOND:
576 		bcgen(n->left, 1);
577 		p1 = p;
578 		lcgen(n->right->left, nn);
579 		gbranch(OGOTO);
580 		patch(p1, pc);
581 		p1 = p;
582 		lcgen(n->right->right, nn);
583 		patch(p1, pc);
584 		break;
585 	}
586 }
587 
588 void
589 bcgen(Node *n, int true)
590 {
591 
592 	if(n->type == T)
593 		gbranch(OGOTO);
594 	else
595 		boolgen(n, true, Z);
596 }
597 
598 void
599 boolgen(Node *n, int true, Node *nn)
600 {
601 	int o;
602 	Prog *p1, *p2;
603 	Node *l, *r, nod, nod1;
604 	long curs;
605 
606 	if(debug['g']) {
607 		prtree(nn, "boolgen lhs");
608 		prtree(n, "boolgen");
609 	}
610 	curs = cursafe;
611 	l = n->left;
612 	r = n->right;
613 	switch(n->op) {
614 
615 	default:
616 		regalloc(&nod, n, nn);
617 		cgen(n, &nod);
618 		o = ONE;
619 		if(true)
620 			o = comrel[relindex(o)];
621 		if(typefd[n->type->etype]) {
622 			nodreg(&nod1, n, NREG+FREGZERO);
623 			gopcode(o, &nod, &nod1, Z);
624 		} else
625 			gopcode(o, &nod, Z, Z);
626 		regfree(&nod);
627 		goto com;
628 
629 	case OCONST:
630 		o = vconst(n);
631 		if(!true)
632 			o = !o;
633 		gbranch(OGOTO);
634 		if(o) {
635 			p1 = p;
636 			gbranch(OGOTO);
637 			patch(p1, pc);
638 		}
639 		goto com;
640 
641 	case OCOMMA:
642 		cgen(l, Z);
643 		boolgen(r, true, nn);
644 		break;
645 
646 	case ONOT:
647 		boolgen(l, !true, nn);
648 		break;
649 
650 	case OCOND:
651 		bcgen(l, 1);
652 		p1 = p;
653 		bcgen(r->left, true);
654 		p2 = p;
655 		gbranch(OGOTO);
656 		patch(p1, pc);
657 		p1 = p;
658 		bcgen(r->right, !true);
659 		patch(p2, pc);
660 		p2 = p;
661 		gbranch(OGOTO);
662 		patch(p1, pc);
663 		patch(p2, pc);
664 		goto com;
665 
666 	case OANDAND:
667 		if(!true)
668 			goto caseor;
669 
670 	caseand:
671 		bcgen(l, true);
672 		p1 = p;
673 		bcgen(r, !true);
674 		p2 = p;
675 		patch(p1, pc);
676 		gbranch(OGOTO);
677 		patch(p2, pc);
678 		goto com;
679 
680 	case OOROR:
681 		if(!true)
682 			goto caseand;
683 
684 	caseor:
685 		bcgen(l, !true);
686 		p1 = p;
687 		bcgen(r, !true);
688 		p2 = p;
689 		gbranch(OGOTO);
690 		patch(p1, pc);
691 		patch(p2, pc);
692 		goto com;
693 
694 	case OEQ:
695 	case ONE:
696 	case OLE:
697 	case OLT:
698 	case OGE:
699 	case OGT:
700 	case OHI:
701 	case OHS:
702 	case OLO:
703 	case OLS:
704 		o = n->op;
705 		if(true)
706 			o = comrel[relindex(o)];
707 		if(l->complex >= FNX && r->complex >= FNX) {
708 			regret(&nod, r);
709 			cgen(r, &nod);
710 			regsalloc(&nod1, r);
711 			gopcode(OAS, &nod, Z, &nod1);
712 			regfree(&nod);
713 			nod = *n;
714 			nod.right = &nod1;
715 			boolgen(&nod, true, nn);
716 			break;
717 		}
718 		if(sconst(l)) {
719 			switch(o) {
720 			default:
721 				if(l->vconst != 0)
722 					break;
723 
724 			case OGT:
725 			case OHI:
726 			case OLE:
727 			case OLS:
728 				regalloc(&nod, r, nn);
729 				cgen(r, &nod);
730 				gopcode(o, l, &nod, Z);
731 				regfree(&nod);
732 				goto com;
733 			}
734 		}
735 		if(sconst(r)) {
736 			switch(o) {
737 			default:
738 				if(r->vconst != 0)
739 					break;
740 
741 			case OGE:
742 			case OHS:
743 			case OLT:
744 			case OLO:
745 				regalloc(&nod, l, nn);
746 				cgen(l, &nod);
747 				gopcode(o, &nod, r, Z);
748 				regfree(&nod);
749 				goto com;
750 			}
751 		}
752 		if(l->complex >= r->complex) {
753 			regalloc(&nod1, l, nn);
754 			cgen(l, &nod1);
755 			regalloc(&nod, r, Z);
756 			cgen(r, &nod);
757 		} else {
758 			regalloc(&nod, r, nn);
759 			cgen(r, &nod);
760 			regalloc(&nod1, l, Z);
761 			cgen(l, &nod1);
762 		}
763 		gopcode(o, &nod1, &nod, Z);
764 		regfree(&nod);
765 		regfree(&nod1);
766 
767 	com:
768 		if(nn != Z) {
769 			p1 = p;
770 			gopcode(OAS, nodconst(1), Z, nn);
771 			gbranch(OGOTO);
772 			p2 = p;
773 			patch(p1, pc);
774 			gopcode(OAS, nodconst(0), Z, nn);
775 			patch(p2, pc);
776 		}
777 		break;
778 	}
779 	cursafe = curs;
780 }
781 
782 void
783 sugen(Node *n, Node *nn, long w)
784 {
785 	Prog *p1;
786 	Node nod0, nod1, nod2, nod3, nod4, *l, *r;
787 	Type *t;
788 	long pc1;
789 	int i, m, c;
790 
791 	if(n == Z || n->type == T)
792 		return;
793 	if(debug['g']) {
794 		prtree(nn, "sugen lhs");
795 		prtree(n, "sugen");
796 	}
797 	if(nn == nodrat)
798 		if(w > nrathole)
799 			nrathole = w;
800 	switch(n->op) {
801 	case OIND:
802 		if(nn == Z) {
803 			nullwarn(n->left, Z);
804 			break;
805 		}
806 
807 	default:
808 		goto copy;
809 
810 	case OCONST:
811 		if(n->type && typev[n->type->etype]) {
812 			if(nn == Z) {
813 				nullwarn(n->left, Z);
814 				break;
815 			}
816 
817 			t = nn->type;
818 			nn->type = types[TLONG];
819 			reglcgen(&nod1, nn, Z);
820 			nn->type = t;
821 
822 			gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
823 			nod1.xoffset += SZ_LONG;
824 			gopcode(OAS, nod32const(n->vconst), Z, &nod1);
825 
826 			regfree(&nod1);
827 			break;
828 		}
829 		goto copy;
830 
831 	case ODOT:
832 		l = n->left;
833 		sugen(l, nodrat, l->type->width);
834 		if(nn != Z) {
835 			warn(n, "non-interruptable temporary");
836 			nod1 = *nodrat;
837 			r = n->right;
838 			if(!r || r->op != OCONST) {
839 				diag(n, "DOT and no offset");
840 				break;
841 			}
842 			nod1.xoffset += (long)r->vconst;
843 			nod1.type = n->type;
844 			sugen(&nod1, nn, w);
845 		}
846 		break;
847 
848 	case OSTRUCT:
849 		/*
850 		 * rewrite so lhs has no fn call
851 		 */
852 		if(nn != Z && nn->complex >= FNX) {
853 			nod1 = *n;
854 			nod1.type = typ(TIND, n->type);
855 			regret(&nod2, &nod1);
856 			lcgen(nn, &nod2);
857 			regsalloc(&nod0, &nod1);
858 			gopcode(OAS, &nod2, Z, &nod0);
859 			regfree(&nod2);
860 
861 			nod1 = *n;
862 			nod1.op = OIND;
863 			nod1.left = &nod0;
864 			nod1.right = Z;
865 			nod1.complex = 1;
866 
867 			sugen(n, &nod1, w);
868 			return;
869 		}
870 
871 		r = n->left;
872 		for(t = n->type->link; t != T; t = t->down) {
873 			l = r;
874 			if(r->op == OLIST) {
875 				l = r->left;
876 				r = r->right;
877 			}
878 			if(nn == Z) {
879 				cgen(l, nn);
880 				continue;
881 			}
882 			/*
883 			 * hand craft *(&nn + o) = l
884 			 */
885 			nod0 = znode;
886 			nod0.op = OAS;
887 			nod0.type = t;
888 			nod0.left = &nod1;
889 			nod0.right = l;
890 
891 			nod1 = znode;
892 			nod1.op = OIND;
893 			nod1.type = t;
894 			nod1.left = &nod2;
895 
896 			nod2 = znode;
897 			nod2.op = OADD;
898 			nod2.type = typ(TIND, t);
899 			nod2.left = &nod3;
900 			nod2.right = &nod4;
901 
902 			nod3 = znode;
903 			nod3.op = OADDR;
904 			nod3.type = nod2.type;
905 			nod3.left = nn;
906 
907 			nod4 = znode;
908 			nod4.op = OCONST;
909 			nod4.type = nod2.type;
910 			nod4.vconst = t->offset;
911 
912 			ccom(&nod0);
913 			acom(&nod0);
914 			xcom(&nod0);
915 			nod0.addable = 0;
916 
917 			/* prtree(&nod0, "hand craft"); /* */
918 			cgen(&nod0, Z);
919 		}
920 		break;
921 
922 	case OAS:
923 		if(nn == Z) {
924 			if(n->addable < INDEXED)
925 				sugen(n->right, n->left, w);
926 			break;
927 		}
928 		sugen(n->right, nodrat, w);
929 		warn(n, "non-interruptable temporary");
930 		sugen(nodrat, n->left, w);
931 		sugen(nodrat, nn, w);
932 		break;
933 
934 	case OFUNC:
935 		if(nn == Z) {
936 			sugen(n, nodrat, w);
937 			break;
938 		}
939 		if(nn->op != OIND) {
940 			nn = new1(OADDR, nn, Z);
941 			nn->type = types[TIND];
942 			nn->addable = 0;
943 		} else
944 			nn = nn->left;
945 		n = new(OFUNC, n->left, new(OLIST, nn, n->right));
946 		n->type = types[TVOID];
947 		n->left->type = types[TVOID];
948 		cgen(n, Z);
949 		break;
950 
951 	case OCOND:
952 		bcgen(n->left, 1);
953 		p1 = p;
954 		sugen(n->right->left, nn, w);
955 		gbranch(OGOTO);
956 		patch(p1, pc);
957 		p1 = p;
958 		sugen(n->right->right, nn, w);
959 		patch(p1, pc);
960 		break;
961 
962 	case OCOMMA:
963 		cgen(n->left, Z);
964 		sugen(n->right, nn, w);
965 		break;
966 	}
967 	return;
968 
969 copy:
970 	if(nn == Z)
971 		return;
972 	if(n->complex >= FNX && nn->complex >= FNX) {
973 		t = nn->type;
974 		nn->type = types[TLONG];
975 		regialloc(&nod1, nn, Z);
976 		lcgen(nn, &nod1);
977 		regsalloc(&nod2, nn);
978 		nn->type = t;
979 
980 		gopcode(OAS, &nod1, Z, &nod2);
981 		regfree(&nod1);
982 
983 		nod2.type = typ(TIND, t);
984 
985 		nod1 = nod2;
986 		nod1.op = OIND;
987 		nod1.left = &nod2;
988 		nod1.right = Z;
989 		nod1.complex = 1;
990 		nod1.type = t;
991 
992 		sugen(n, &nod1, w);
993 		return;
994 	}
995 
996 	if(n->complex > nn->complex) {
997 		t = n->type;
998 		n->type = types[TLONG];
999 		reglcgen(&nod1, n, Z);
1000 		n->type = t;
1001 
1002 		t = nn->type;
1003 		nn->type = types[TLONG];
1004 		reglcgen(&nod2, nn, Z);
1005 		nn->type = t;
1006 	} else {
1007 		t = nn->type;
1008 		nn->type = types[TLONG];
1009 		reglcgen(&nod2, nn, Z);
1010 		nn->type = t;
1011 
1012 		t = n->type;
1013 		n->type = types[TLONG];
1014 		reglcgen(&nod1, n, Z);
1015 		n->type = t;
1016 	}
1017 
1018 	w /= SZ_LONG;
1019 	if(w <= 5) {
1020 		layout(&nod1, &nod2, w, 0, Z);
1021 		goto out;
1022 	}
1023 
1024 	/*
1025 	 * minimize space for unrolling loop
1026 	 * 3,4,5 times. (6 or more is never minimum)
1027 	 * if small structure, try 2 also.
1028 	 */
1029 	c = 0; /* set */
1030 	m = 100;
1031 	i = 3;
1032 	if(w <= 15)
1033 		i = 2;
1034 	for(; i<=5; i++)
1035 		if(i + w%i <= m) {
1036 			c = i;
1037 			m = c + w%c;
1038 		}
1039 
1040 	regalloc(&nod3, &regnode, Z);
1041 	layout(&nod1, &nod2, w%c, w/c, &nod3);
1042 
1043 	pc1 = pc;
1044 	layout(&nod1, &nod2, c, 0, Z);
1045 
1046 	gopcode(OSUB, nodconst(1), Z, &nod3);
1047 	nod1.op = OREGISTER;
1048 	gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1);
1049 	nod2.op = OREGISTER;
1050 	gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2);
1051 
1052 	gopcode(OEQ, &nod3, Z, Z);
1053 	p->as = ABGTZ;
1054 	patch(p, pc1);
1055 
1056 	regfree(&nod3);
1057 out:
1058 	regfree(&nod1);
1059 	regfree(&nod2);
1060 }
1061 
1062 void
1063 layout(Node *f, Node *t, int c, int cv, Node *cn)
1064 {
1065 	Node t1, t2;
1066 
1067 	while(c > 3) {
1068 		layout(f, t, 2, 0, Z);
1069 		c -= 2;
1070 	}
1071 
1072 	regalloc(&t1, &regnode, Z);
1073 	regalloc(&t2, &regnode, Z);
1074 	if(c > 0) {
1075 		gopcode(OAS, f, Z, &t1);
1076 		f->xoffset += SZ_LONG;
1077 	}
1078 	if(cn != Z)
1079 		gopcode(OAS, nodconst(cv), Z, cn);
1080 	if(c > 1) {
1081 		gopcode(OAS, f, Z, &t2);
1082 		f->xoffset += SZ_LONG;
1083 	}
1084 	if(c > 0) {
1085 		gopcode(OAS, &t1, Z, t);
1086 		t->xoffset += SZ_LONG;
1087 	}
1088 	if(c > 2) {
1089 		gopcode(OAS, f, Z, &t1);
1090 		f->xoffset += SZ_LONG;
1091 	}
1092 	if(c > 1) {
1093 		gopcode(OAS, &t2, Z, t);
1094 		t->xoffset += SZ_LONG;
1095 	}
1096 	if(c > 2) {
1097 		gopcode(OAS, &t1, Z, t);
1098 		t->xoffset += SZ_LONG;
1099 	}
1100 	regfree(&t1);
1101 	regfree(&t2);
1102 }
1103