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