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