xref: /inferno-os/utils/8c/sgen.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
1 #include "gc.h"
2 
3 void
4 codgen(Node *n, Node *nn)
5 {
6 	Prog *sp;
7 	Node *n1, nod, nod1;
8 
9 	cursafe = 0;
10 	curarg = 0;
11 	maxargsafe = 0;
12 
13 	/*
14 	 * isolate name
15 	 */
16 	for(n1 = nn;; n1 = n1->left) {
17 		if(n1 == Z) {
18 			diag(nn, "cant find function name");
19 			return;
20 		}
21 		if(n1->op == ONAME)
22 			break;
23 	}
24 	nearln = nn->lineno;
25 	gpseudo(ATEXT, n1->sym, nodconst(stkoff));
26 
27 	/*
28 	 * isolate first argument
29 	 */
30 	if(REGARG) {
31 		if(typesuv[thisfn->link->etype]) {
32 			nod1 = *nodret->left;
33 			nodreg(&nod, &nod1, REGARG);
34 			gmove(&nod, &nod1);
35 		} else
36 		if(firstarg && typechlp[firstargtype->etype]) {
37 			nod1 = *nodret->left;
38 			nod1.sym = firstarg;
39 			nod1.type = firstargtype;
40 			nod1.xoffset = align(0, firstargtype, Aarg1);
41 			nod1.etype = firstargtype->etype;
42 			nodreg(&nod, &nod1, REGARG);
43 			gmove(&nod, &nod1);
44 		}
45 	}
46 
47 	sp = p;
48 	retok = 0;
49 	gen(n);
50 	if(!retok)
51 		if(thisfn->link->etype != TVOID)
52 			warn(Z, "no return at end of function: %s", n1->sym->name);
53 	noretval(3);
54 	if(thisfn && thisfn->link && typefd[thisfn->link->etype])
55 		gins(AFLDZ, Z, Z);
56 	gbranch(ORETURN);
57 
58 	if(!debug['N'] || debug['R'] || debug['P'])
59 		regopt(sp);
60 	sp->to.offset += maxargsafe;
61 }
62 
63 void
64 supgen(Node *n)
65 {
66 	long spc;
67 	Prog *sp;
68 
69 	if(n == Z)
70 		return;
71 	suppress++;
72 	spc = pc;
73 	sp = lastp;
74 	gen(n);
75 	lastp = sp;
76 	pc = spc;
77 	sp->link = nil;
78 	suppress--;
79 }
80 
81 void
82 gen(Node *n)
83 {
84 	Node *l, nod;
85 	Prog *sp, *spc, *spb;
86 	Case *cn;
87 	long sbc, scc;
88 	int f, o;
89 
90 loop:
91 	if(n == Z)
92 		return;
93 	nearln = n->lineno;
94 	o = n->op;
95 	if(debug['G'])
96 		if(o != OLIST)
97 			print("%L %O\n", nearln, o);
98 
99 	retok = 0;
100 	switch(o) {
101 
102 	default:
103 		complex(n);
104 		cgen(n, Z);
105 		break;
106 
107 	case OLIST:
108 		gen(n->left);
109 
110 	rloop:
111 		n = n->right;
112 		goto loop;
113 
114 	case ORETURN:
115 		retok = 1;
116 		complex(n);
117 		if(n->type == T)
118 			break;
119 		l = n->left;
120 		if(l == Z) {
121 			noretval(3);
122 			if(typefd[n->type->etype])
123 				gins(AFLDZ, Z, Z);
124 			gbranch(ORETURN);
125 			break;
126 		}
127 		if(typesuv[n->type->etype]) {
128 			sugen(l, nodret, n->type->width);
129 			noretval(3);
130 			gbranch(ORETURN);
131 			break;
132 		}
133 		regret(&nod, n);
134 		cgen(l, &nod);
135 		regfree(&nod);
136 		if(typefd[n->type->etype])
137 			noretval(1);
138 		else
139 			noretval(2);
140 		gbranch(ORETURN);
141 		break;
142 
143 	case OLABEL:
144 		l = n->left;
145 		if(l) {
146 			l->xoffset = pc;
147 			if(l->label)
148 				patch(l->label, pc);
149 		}
150 		gbranch(OGOTO);	/* prevent self reference in reg */
151 		patch(p, pc);
152 		goto rloop;
153 
154 	case OGOTO:
155 		retok = 1;
156 		n = n->left;
157 		if(n == Z)
158 			return;
159 		if(n->complex == 0) {
160 			diag(Z, "label undefined: %s", n->sym->name);
161 			return;
162 		}
163 		if(suppress)
164 			return;
165 		gbranch(OGOTO);
166 		if(n->xoffset) {
167 			patch(p, n->xoffset);
168 			return;
169 		}
170 		if(n->label)
171 			patch(n->label, pc-1);
172 		n->label = p;
173 		return;
174 
175 	case OCASE:
176 		l = n->left;
177 		if(cases == C)
178 			diag(n, "case/default outside a switch");
179 		if(l == Z) {
180 			cas();
181 			cases->val = 0;
182 			cases->def = 1;
183 			cases->label = pc;
184 			goto rloop;
185 		}
186 		complex(l);
187 		if(l->type == T)
188 			goto rloop;
189 		if(l->op == OCONST)
190 		if(typechl[l->type->etype]) {
191 			cas();
192 			cases->val = l->vconst;
193 			cases->def = 0;
194 			cases->label = pc;
195 			goto rloop;
196 		}
197 		diag(n, "case expression must be integer constant");
198 		goto rloop;
199 
200 	case OSWITCH:
201 		l = n->left;
202 		complex(l);
203 		if(l->type == T)
204 			break;
205 		if(!typechl[l->type->etype]) {
206 			diag(n, "switch expression must be integer");
207 			break;
208 		}
209 
210 		gbranch(OGOTO);		/* entry */
211 		sp = p;
212 
213 		cn = cases;
214 		cases = C;
215 		cas();
216 
217 		sbc = breakpc;
218 		breakpc = pc;
219 		gbranch(OGOTO);
220 		spb = p;
221 
222 		gen(n->right);
223 		gbranch(OGOTO);
224 		patch(p, breakpc);
225 
226 		patch(sp, pc);
227 		regalloc(&nod, l, Z);
228 		nod.type = types[TLONG];
229 		cgen(l, &nod);
230 		doswit(&nod);
231 		regfree(&nod);
232 		patch(spb, pc);
233 
234 		cases = cn;
235 		breakpc = sbc;
236 		break;
237 
238 	case OWHILE:
239 	case ODWHILE:
240 		l = n->left;
241 		gbranch(OGOTO);		/* entry */
242 		sp = p;
243 
244 		scc = continpc;
245 		continpc = pc;
246 		gbranch(OGOTO);
247 		spc = p;
248 
249 		sbc = breakpc;
250 		breakpc = pc;
251 		gbranch(OGOTO);
252 		spb = p;
253 
254 		patch(spc, pc);
255 		if(n->op == OWHILE)
256 			patch(sp, pc);
257 		bcomplex(l, Z);		/* test */
258 		patch(p, breakpc);
259 
260 		if(n->op == ODWHILE)
261 			patch(sp, pc);
262 		gen(n->right);		/* body */
263 		gbranch(OGOTO);
264 		patch(p, continpc);
265 
266 		patch(spb, pc);
267 		continpc = scc;
268 		breakpc = sbc;
269 		break;
270 
271 	case OFOR:
272 		l = n->left;
273 		gen(l->right->left);	/* init */
274 		gbranch(OGOTO);		/* entry */
275 		sp = p;
276 
277 		scc = continpc;
278 		continpc = pc;
279 		gbranch(OGOTO);
280 		spc = p;
281 
282 		sbc = breakpc;
283 		breakpc = pc;
284 		gbranch(OGOTO);
285 		spb = p;
286 
287 		patch(spc, pc);
288 		gen(l->right->right);	/* inc */
289 		patch(sp, pc);
290 		if(l->left != Z) {	/* test */
291 			bcomplex(l->left, Z);
292 			patch(p, breakpc);
293 		}
294 		gen(n->right);		/* body */
295 		gbranch(OGOTO);
296 		patch(p, continpc);
297 
298 		patch(spb, pc);
299 		continpc = scc;
300 		breakpc = sbc;
301 		break;
302 
303 	case OCONTINUE:
304 		if(continpc < 0) {
305 			diag(n, "continue not in a loop");
306 			break;
307 		}
308 		gbranch(OGOTO);
309 		patch(p, continpc);
310 		break;
311 
312 	case OBREAK:
313 		if(breakpc < 0) {
314 			diag(n, "break not in a loop");
315 			break;
316 		}
317 		gbranch(OGOTO);
318 		patch(p, breakpc);
319 		break;
320 
321 	case OIF:
322 		l = n->left;
323 		if(bcomplex(l, n->right)) {
324 			if(typefd[l->type->etype])
325 				f = !l->fconst;
326 			else
327 				f = !l->vconst;
328 			if(debug['c'])
329 				print("%L const if %s\n", nearln, f ? "false" : "true");
330 			if(f) {
331 				supgen(n->right->left);
332 				gen(n->right->right);
333 			}
334 			else {
335 				gen(n->right->left);
336 				supgen(n->right->right);
337 			}
338 		}
339 		else {
340 			sp = p;
341 			if(n->right->left != Z)
342 				gen(n->right->left);
343 			if(n->right->right != Z) {
344 				gbranch(OGOTO);
345 				patch(sp, pc);
346 				sp = p;
347 				gen(n->right->right);
348 			}
349 			patch(sp, pc);
350 		}
351 		break;
352 
353 	case OSET:
354 	case OUSED:
355 		usedset(n->left, o);
356 		break;
357 	}
358 }
359 
360 void
361 usedset(Node *n, int o)
362 {
363 	if(n->op == OLIST) {
364 		usedset(n->left, o);
365 		usedset(n->right, o);
366 		return;
367 	}
368 	complex(n);
369 	switch(n->op) {
370 	case OADDR:	/* volatile */
371 		gins(ANOP, n, Z);
372 		break;
373 	case ONAME:
374 		if(o == OSET)
375 			gins(ANOP, Z, n);
376 		else
377 			gins(ANOP, n, Z);
378 		break;
379 	}
380 }
381 
382 void
383 noretval(int n)
384 {
385 
386 	if(n & 1) {
387 		gins(ANOP, Z, Z);
388 		p->to.type = REGRET;
389 	}
390 	if(n & 2) {
391 		gins(ANOP, Z, Z);
392 		p->to.type = FREGRET;
393 	}
394 }
395 
396 /* welcome to commute */
397 static void
398 commute(Node *n)
399 {
400 	Node *l, *r;
401 
402 	l = n->left;
403 	r = n->right;
404 	if(r->complex > l->complex) {
405 		n->left = r;
406 		n->right = l;
407 	}
408 }
409 
410 void
411 indexshift(Node *n)
412 {
413 	int g;
414 
415 	if(!typechlp[n->type->etype])
416 		return;
417 	simplifyshift(n);
418 	if(n->op == OASHL && n->right->op == OCONST){
419 		g = vconst(n->right);
420 		if(g >= 0 && g < 4)
421 			n->addable = 7;
422 	}
423 }
424 
425 /*
426  *	calculate addressability as follows
427  *		NAME ==> 10/11		name+value(SB/SP)
428  *		REGISTER ==> 12		register
429  *		CONST ==> 20		$value
430  *		*(20) ==> 21		value
431  *		&(10) ==> 13		$name+value(SB)
432  *		&(11) ==> 1		$name+value(SP)
433  *		(13) + (20) ==> 13	fold constants
434  *		(1) + (20) ==> 1	fold constants
435  *		*(13) ==> 10		back to name
436  *		*(1) ==> 11		back to name
437  *
438  *		(20) * (X) ==> 7	multiplier in indexing
439  *		(X,7) + (13,1) ==> 8	adder in indexing (addresses)
440  *		(8) ==> &9(OINDEX)	index, almost addressable
441  *
442  *	calculate complexity (number of registers)
443  */
444 void
445 xcom(Node *n)
446 {
447 	Node *l, *r;
448 	int g;
449 
450 	if(n == Z)
451 		return;
452 	l = n->left;
453 	r = n->right;
454 	n->complex = 0;
455 	n->addable = 0;
456 	switch(n->op) {
457 	case OCONST:
458 		n->addable = 20;
459 		break;
460 
461 	case ONAME:
462 		n->addable = 10;
463 		if(n->class == CPARAM || n->class == CAUTO)
464 			n->addable = 11;
465 		break;
466 
467 	case OREGISTER:
468 		n->addable = 12;
469 		break;
470 
471 	case OINDREG:
472 		n->addable = 12;
473 		break;
474 
475 	case OADDR:
476 		xcom(l);
477 		if(l->addable == 10)
478 			n->addable = 13;
479 		else
480 		if(l->addable == 11)
481 			n->addable = 1;
482 		break;
483 
484 	case OADD:
485 		xcom(l);
486 		xcom(r);
487 		if(n->type->etype != TIND)
488 			break;
489 
490 		switch(r->addable) {
491 		case 20:
492 			switch(l->addable) {
493 			case 1:
494 			case 13:
495 			commadd:
496 				l->type = n->type;
497 				*n = *l;
498 				l = new(0, Z, Z);
499 				*l = *(n->left);
500 				l->xoffset += r->vconst;
501 				n->left = l;
502 				r = n->right;
503 				goto brk;
504 			}
505 			break;
506 
507 		case 1:
508 		case 13:
509 		case 10:
510 		case 11:
511 			/* l is the base, r is the index */
512 			if(l->addable != 20)
513 				n->addable = 8;
514 			break;
515 		}
516 		switch(l->addable) {
517 		case 20:
518 			switch(r->addable) {
519 			case 13:
520 			case 1:
521 				r = n->left;
522 				l = n->right;
523 				n->left = l;
524 				n->right = r;
525 				goto commadd;
526 			}
527 			break;
528 
529 		case 13:
530 		case 1:
531 		case 10:
532 		case 11:
533 			/* r is the base, l is the index */
534 			if(r->addable != 20)
535 				n->addable = 8;
536 			break;
537 		}
538 		if(n->addable == 8 && !side(n)) {
539 			indx(n);
540 			l = new1(OINDEX, idx.basetree, idx.regtree);
541 			l->scale = idx.scale;
542 			l->addable = 9;
543 			l->complex = l->right->complex;
544 			l->type = l->left->type;
545 			n->op = OADDR;
546 			n->left = l;
547 			n->right = Z;
548 			n->addable = 8;
549 			break;
550 		}
551 		break;
552 
553 	case OINDEX:
554 		xcom(l);
555 		xcom(r);
556 		n->addable = 9;
557 		break;
558 
559 	case OIND:
560 		xcom(l);
561 		if(l->op == OADDR) {
562 			l = l->left;
563 			l->type = n->type;
564 			*n = *l;
565 			return;
566 		}
567 		switch(l->addable) {
568 		case 20:
569 			n->addable = 21;
570 			break;
571 		case 1:
572 			n->addable = 11;
573 			break;
574 		case 13:
575 			n->addable = 10;
576 			break;
577 		}
578 		break;
579 
580 	case OASHL:
581 		xcom(l);
582 		xcom(r);
583 		indexshift(n);
584 		break;
585 
586 	case OMUL:
587 	case OLMUL:
588 		xcom(l);
589 		xcom(r);
590 		g = vlog(l);
591 		if(g >= 0) {
592 			n->left = r;
593 			n->right = l;
594 			l = r;
595 			r = n->right;
596 		}
597 		g = vlog(r);
598 		if(g >= 0) {
599 			n->op = OASHL;
600 			r->vconst = g;
601 			r->type = types[TINT];
602 			indexshift(n);
603 			break;
604 		}
605 commute(n);
606 		break;
607 
608 	case OASLDIV:
609 		xcom(l);
610 		xcom(r);
611 		g = vlog(r);
612 		if(g >= 0) {
613 			n->op = OASLSHR;
614 			r->vconst = g;
615 			r->type = types[TINT];
616 		}
617 		break;
618 
619 	case OLDIV:
620 		xcom(l);
621 		xcom(r);
622 		g = vlog(r);
623 		if(g >= 0) {
624 			n->op = OLSHR;
625 			r->vconst = g;
626 			r->type = types[TINT];
627 			indexshift(n);
628 			break;
629 		}
630 		break;
631 
632 	case OASLMOD:
633 		xcom(l);
634 		xcom(r);
635 		g = vlog(r);
636 		if(g >= 0) {
637 			n->op = OASAND;
638 			r->vconst--;
639 		}
640 		break;
641 
642 	case OLMOD:
643 		xcom(l);
644 		xcom(r);
645 		g = vlog(r);
646 		if(g >= 0) {
647 			n->op = OAND;
648 			r->vconst--;
649 		}
650 		break;
651 
652 	case OASMUL:
653 	case OASLMUL:
654 		xcom(l);
655 		xcom(r);
656 		g = vlog(r);
657 		if(g >= 0) {
658 			n->op = OASASHL;
659 			r->vconst = g;
660 		}
661 		break;
662 
663 	case OLSHR:
664 	case OASHR:
665 		xcom(l);
666 		xcom(r);
667 		indexshift(n);
668 		break;
669 
670 	default:
671 		if(l != Z)
672 			xcom(l);
673 		if(r != Z)
674 			xcom(r);
675 		break;
676 	}
677 brk:
678 	if(n->addable >= 10)
679 		return;
680 	if(l != Z)
681 		n->complex = l->complex;
682 	if(r != Z) {
683 		if(r->complex == n->complex)
684 			n->complex = r->complex+1;
685 		else
686 		if(r->complex > n->complex)
687 			n->complex = r->complex;
688 	}
689 	if(n->complex == 0)
690 		n->complex++;
691 
692 	if(com64(n))
693 		return;
694 
695 	switch(n->op) {
696 
697 	case OFUNC:
698 		n->complex = FNX;
699 		break;
700 
701 	case OLMOD:
702 	case OMOD:
703 	case OLMUL:
704 	case OLDIV:
705 	case OMUL:
706 	case ODIV:
707 	case OASLMUL:
708 	case OASLDIV:
709 	case OASLMOD:
710 	case OASMUL:
711 	case OASDIV:
712 	case OASMOD:
713 		if(r->complex >= l->complex) {
714 			n->complex = l->complex + 3;
715 			if(r->complex > n->complex)
716 				n->complex = r->complex;
717 		} else {
718 			n->complex = r->complex + 3;
719 			if(l->complex > n->complex)
720 				n->complex = l->complex;
721 		}
722 		break;
723 
724 	case OLSHR:
725 	case OASHL:
726 	case OASHR:
727 	case OASLSHR:
728 	case OASASHL:
729 	case OASASHR:
730 		if(r->complex >= l->complex) {
731 			n->complex = l->complex + 2;
732 			if(r->complex > n->complex)
733 				n->complex = r->complex;
734 		} else {
735 			n->complex = r->complex + 2;
736 			if(l->complex > n->complex)
737 				n->complex = l->complex;
738 		}
739 		break;
740 
741 	case OADD:
742 	case OXOR:
743 	case OAND:
744 	case OOR:
745 		/*
746 		 * immediate operators, make const on right
747 		 */
748 		if(l->op == OCONST) {
749 			n->left = r;
750 			n->right = l;
751 		}
752 		break;
753 
754 	case OEQ:
755 	case ONE:
756 	case OLE:
757 	case OLT:
758 	case OGE:
759 	case OGT:
760 	case OHI:
761 	case OHS:
762 	case OLO:
763 	case OLS:
764 		/*
765 		 * compare operators, make const on left
766 		 */
767 		if(r->op == OCONST) {
768 			n->left = r;
769 			n->right = l;
770 			n->op = invrel[relindex(n->op)];
771 		}
772 		break;
773 	}
774 }
775 
776 void
777 indx(Node *n)
778 {
779 	Node *l, *r;
780 
781 	if(debug['x'])
782 		prtree(n, "indx");
783 
784 	l = n->left;
785 	r = n->right;
786 	if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
787 		n->right = l;
788 		n->left = r;
789 		l = r;
790 		r = n->right;
791 	}
792 	if(l->addable != 7) {
793 		idx.regtree = l;
794 		idx.scale = 1;
795 	} else
796 	if(l->right->addable == 20) {
797 		idx.regtree = l->left;
798 		idx.scale = 1 << l->right->vconst;
799 	} else
800 	if(l->left->addable == 20) {
801 		idx.regtree = l->right;
802 		idx.scale = 1 << l->left->vconst;
803 	} else
804 		diag(n, "bad index");
805 
806 	idx.basetree = r;
807 	if(debug['x']) {
808 		print("scale = %d\n", idx.scale);
809 		prtree(idx.regtree, "index");
810 		prtree(idx.basetree, "base");
811 	}
812 }
813 
814 int
815 bcomplex(Node *n, Node *c)
816 {
817 	Node *b, nod;
818 
819 	complex(n);
820 	if(n->type != T)
821 	if(tcompat(n, T, n->type, tnot))
822 		n->type = T;
823 	if(n->type != T) {
824 		if(c != Z && n->op == OCONST && deadheads(c))
825 			return 1;
826 		if(typev[n->type->etype] && machcap(Z)) {
827 			b = &nod;
828 			b->op = ONE;
829 			b->left = n;
830 			b->right = new(0, Z, Z);
831 			*b->right = *nodconst(0);
832 			b->right->type = n->type;
833 			b->type = types[TLONG];
834 			cgen64(b, Z);
835 			return 0;
836 		}
837 		bool64(n);
838 		boolgen(n, 1, Z);
839 	} else
840 		gbranch(OGOTO);
841 	return 0;
842 }
843