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