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