xref: /inferno-os/utils/vc/sgen.c (revision 556f8a312ed1b20f8ff25c104928646828e8b05c)
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 /*
359  *	calculate addressability as follows
360  *		CONST ==> 20		$value
361  *		NAME ==> 10		name
362  *		REGISTER ==> 11		register
363  *		INDREG ==> 12		*[(reg)+offset]
364  *		&10 ==> 2		$name
365  *		ADD(2, 20) ==> 2	$name+offset
366  *		ADD(3, 20) ==> 3	$(reg)+offset
367  *		&12 ==> 3		$(reg)+offset
368  *		*11 ==> 11		??
369  *		*2 ==> 10		name
370  *		*3 ==> 12		*(reg)+offset
371  *	calculate complexity (number of registers)
372  */
373 void
374 xcom(Node *n)
375 {
376 	Node *l, *r;
377 	int t;
378 
379 	if(n == Z)
380 		return;
381 	l = n->left;
382 	r = n->right;
383 	n->addable = 0;
384 	n->complex = 0;
385 	switch(n->op) {
386 	case OCONST:
387 		n->addable = 20;
388 		return;
389 
390 	case OREGISTER:
391 		n->addable = 11;
392 		return;
393 
394 	case OINDREG:
395 		n->addable = 12;
396 		return;
397 
398 	case ONAME:
399 		n->addable = 10;
400 		return;
401 
402 	case OADDR:
403 		xcom(l);
404 		if(l->addable == 10)
405 			n->addable = 2;
406 		if(l->addable == 12)
407 			n->addable = 3;
408 		break;
409 
410 	case OIND:
411 		xcom(l);
412 		if(l->addable == 11)
413 			n->addable = 12;
414 		if(l->addable == 3)
415 			n->addable = 12;
416 		if(l->addable == 2)
417 			n->addable = 10;
418 		break;
419 
420 	case OADD:
421 		xcom(l);
422 		xcom(r);
423 		if(l->addable == 20) {
424 			if(r->addable == 2)
425 				n->addable = 2;
426 			if(r->addable == 3)
427 				n->addable = 3;
428 		}
429 		if(r->addable == 20) {
430 			if(l->addable == 2)
431 				n->addable = 2;
432 			if(l->addable == 3)
433 				n->addable = 3;
434 		}
435 		break;
436 
437 	case OASLMUL:
438 	case OASMUL:
439 		xcom(l);
440 		xcom(r);
441 		t = vlog(r);
442 		if(t >= 0) {
443 			n->op = OASASHL;
444 			r->vconst = t;
445 			r->type = types[TINT];
446 		}
447 		break;
448 
449 	case OMUL:
450 	case OLMUL:
451 		xcom(l);
452 		xcom(r);
453 		t = vlog(l);
454 		if(t >= 0) {
455 			n->left = r;
456 			n->right = l;
457 			l = r;
458 			r = n->right;
459 		}
460 		t = vlog(r);
461 		if(t >= 0) {
462 			n->op = OASHL;
463 			r->vconst = t;
464 			r->type = types[TINT];
465 			simplifyshift(n);
466 		}
467 		break;
468 
469 	case OASLDIV:
470 		xcom(l);
471 		xcom(r);
472 		t = vlog(r);
473 		if(t >= 0) {
474 			n->op = OASLSHR;
475 			r->vconst = t;
476 			r->type = types[TINT];
477 		}
478 		break;
479 
480 	case OLDIV:
481 		xcom(l);
482 		xcom(r);
483 		t = vlog(r);
484 		if(t >= 0) {
485 			n->op = OLSHR;
486 			r->vconst = t;
487 			r->type = types[TINT];
488 			simplifyshift(n);
489 		}
490 		break;
491 
492 	case OASLMOD:
493 		xcom(l);
494 		xcom(r);
495 		t = vlog(r);
496 		if(t >= 0) {
497 			n->op = OASAND;
498 			r->vconst--;
499 		}
500 		break;
501 
502 	case OLMOD:
503 		xcom(l);
504 		xcom(r);
505 		t = vlog(r);
506 		if(t >= 0) {
507 			n->op = OAND;
508 			r->vconst--;
509 		}
510 		break;
511 
512 	case OLSHR:
513 	case OASHL:
514 	case OASHR:
515 		xcom(l);
516 		xcom(r);
517 		simplifyshift(n);
518 		break;
519 
520 	default:
521 		if(l != Z)
522 			xcom(l);
523 		if(r != Z)
524 			xcom(r);
525 		break;
526 	}
527 	if(n->addable >= 10)
528 		return;
529 
530 	if(l != Z)
531 		n->complex = l->complex;
532 	if(r != Z) {
533 		if(r->complex == n->complex)
534 			n->complex = r->complex+1;
535 		else
536 		if(r->complex > n->complex)
537 			n->complex = r->complex;
538 	}
539 	if(n->complex == 0)
540 		n->complex++;
541 
542 	if(com64(n))
543 		return;
544 
545 	switch(n->op) {
546 	case OFUNC:
547 		n->complex = FNX;
548 		break;
549 
550 	case OADD:
551 	case OXOR:
552 	case OAND:
553 	case OOR:
554 	case OEQ:
555 	case ONE:
556 		/*
557 		 * immediate operators, make const on right
558 		 */
559 		if(l->op == OCONST) {
560 			n->left = r;
561 			n->right = l;
562 		}
563 		break;
564 	}
565 }
566 
567 void
568 bcomplex(Node *n)
569 {
570 
571 	complex(n);
572 	if(n->type != T)
573 	if(tcompat(n, T, n->type, tnot))
574 		n->type = T;
575 	if(n->type != T) {
576 		bool64(n);
577 		boolgen(n, 1, Z);
578 	} else
579 		gbranch(OGOTO);
580 }
581