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