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