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