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