xref: /inferno-os/utils/cc/pgen.c (revision e45fa0eb0763b57d6fb0649c064bc3b95ccdea6c)
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 	hasdoubled = 0;
13 
14 	/*
15 	 * isolate name
16 	 */
17 	for(n1 = nn;; n1 = n1->left) {
18 		if(n1 == Z) {
19 			diag(nn, "cant find function name");
20 			return;
21 		}
22 		if(n1->op == ONAME)
23 			break;
24 	}
25 	nearln = nn->lineno;
26 	gpseudo(ATEXT, n1->sym, nodconst(stkoff));
27 	sp = p;
28 
29 	if(typecmplx[thisfn->link->etype]) {
30 		if(nodret == nil) {
31 			nodret = new(ONAME, Z, Z);
32 			nodret->sym = slookup(".ret");
33 			nodret->class = CPARAM;
34 			nodret->type = types[TIND];
35 			nodret->etype = TIND;
36 			nodret = new(OIND, nodret, Z);
37 		}
38 		n1 = nodret->left;
39 		if(n1->type == T || n1->type->link != thisfn->link) {
40 			n1->type = typ(TIND, thisfn->link);
41 			n1->etype = n1->type->etype;
42 			nodret = new(OIND, n1, Z);
43 			complex(nodret);
44 		}
45 	}
46 
47 	/*
48 	 * isolate first argument
49 	 */
50 	if(REGARG >= 0) {
51 		if(typecmplx[thisfn->link->etype]) {
52 			nod1 = *nodret->left;
53 			nodreg(&nod, &nod1, REGARG);
54 			gmove(&nod, &nod1);
55 		} else
56 		if(firstarg && typeword[firstargtype->etype]) {
57 			nod1 = znode;
58 			nod1.op = ONAME;
59 			nod1.sym = firstarg;
60 			nod1.type = firstargtype;
61 			nod1.class = CPARAM;
62 			nod1.xoffset = align(0, firstargtype, Aarg1);
63 			nod1.etype = firstargtype->etype;
64 			xcom(&nod1);
65 			nodreg(&nod, &nod1, REGARG);
66 			gmove(&nod, &nod1);
67 		}
68 	}
69 
70 	canreach = 1;
71 	warnreach = 1;
72 	gen(n);
73 	if(canreach && thisfn->link->etype != TVOID){
74 		if(debug['B'])
75 			warn(Z, "no return at end of function: %s", n1->sym->name);
76 		else
77 			diag(Z, "no return at end of function: %s", n1->sym->name);
78 	}
79 	noretval(3);
80 	gbranch(ORETURN);
81 
82 	if(!debug['N'] || debug['R'] || debug['P'])
83 		regopt(sp);
84 
85 	if(thechar=='6' || thechar=='7' || thechar=='9' || hasdoubled)	/* [sic] */
86 		maxargsafe = round(maxargsafe, 8);
87 	sp->to.offset += maxargsafe;
88 }
89 
90 void
91 supgen(Node *n)
92 {
93 	int owarn;
94 	long spc;
95 	Prog *sp;
96 
97 	if(n == Z)
98 		return;
99 	suppress++;
100 	owarn = warnreach;
101 	warnreach = 0;
102 	spc = pc;
103 	sp = lastp;
104 	gen(n);
105 	lastp = sp;
106 	pc = spc;
107 	sp->link = nil;
108 	suppress--;
109 	warnreach = owarn;
110 }
111 
112 Node*
113 uncomma(Node *n)
114 {
115 	while(n != Z && n->op == OCOMMA) {
116 		cgen(n->left, Z);
117 		n = n->right;
118 	}
119 	return n;
120 }
121 
122 void
123 gen(Node *n)
124 {
125 	Node *l, nod, rn;
126 	Prog *sp, *spc, *spb;
127 	Case *cn;
128 	long sbc, scc;
129 	int snbreak, sncontin;
130 	int f, o, oldreach;
131 
132 loop:
133 	if(n == Z)
134 		return;
135 	nearln = n->lineno;
136 	o = n->op;
137 	if(debug['G'])
138 		if(o != OLIST)
139 			print("%L %O\n", nearln, o);
140 
141 	if(!canreach) {
142 		switch(o) {
143 		case OLABEL:
144 		case OCASE:
145 		case OLIST:
146 		case OCOMMA:
147 		case OBREAK:
148 		case OFOR:
149 		case OWHILE:
150 		case ODWHILE:
151 			/* all handled specially - see switch body below */
152 			break;
153 		default:
154 			if(warnreach) {
155 				warn(n, "unreachable code %O", o);
156 				warnreach = 0;
157 			}
158 		}
159 	}
160 
161 	switch(o) {
162 
163 	default:
164 		complex(n);
165 		cgen(n, Z);
166 		break;
167 
168 	case OLIST:
169 	case OCOMMA:
170 		gen(n->left);
171 
172 	rloop:
173 		n = n->right;
174 		goto loop;
175 
176 	case ORETURN:
177 		canreach = 0;
178 		warnreach = !suppress;
179 		complex(n);
180 		if(n->type == T)
181 			break;
182 		l = uncomma(n->left);
183 		if(l == Z) {
184 			noretval(3);
185 			gbranch(ORETURN);
186 			break;
187 		}
188 		if(typecmplx[n->type->etype]) {
189 			nod = znode;
190 			nod.op = OAS;
191 			nod.left = nodret;
192 			nod.right = l;
193 			nod.type = n->type;
194 			nod.complex = l->complex;
195 			cgen(&nod, Z);
196 			noretval(3);
197 			gbranch(ORETURN);
198 			break;
199 		}
200 		if(newvlongcode && !typefd[n->type->etype]){
201 			regret(&rn, n);
202 			regfree(&rn);
203 			nod = znode;
204 			nod.op = OAS;
205 			nod.left = &rn;
206 			nod.right = l;
207 			nod.type = n->type;
208 			nod.complex = l->complex;
209 			cgen(&nod, Z);
210 			noretval(2);
211 			gbranch(ORETURN);
212 			break;
213 		}
214 		regret(&nod, n);
215 		cgen(l, &nod);
216 		regfree(&nod);
217 		if(typefd[n->type->etype])
218 			noretval(1);
219 		else
220 			noretval(2);
221 		gbranch(ORETURN);
222 		break;
223 
224 	case OLABEL:
225 		canreach = 1;
226 		l = n->left;
227 		if(l) {
228 			l->pc = pc;
229 			if(l->label)
230 				patch(l->label, pc);
231 		}
232 		gbranch(OGOTO);	/* prevent self reference in reg */
233 		patch(p, pc);
234 		goto rloop;
235 
236 	case OGOTO:
237 		canreach = 0;
238 		warnreach = !suppress;
239 		n = n->left;
240 		if(n == Z)
241 			return;
242 		if(n->complex == 0) {
243 			diag(Z, "label undefined: %s", n->sym->name);
244 			return;
245 		}
246 		if(suppress)
247 			return;
248 		gbranch(OGOTO);
249 		if(n->pc) {
250 			patch(p, n->pc);
251 			return;
252 		}
253 		if(n->label)
254 			patch(n->label, pc-1);
255 		n->label = p;
256 		return;
257 
258 	case OCASE:
259 		canreach = 1;
260 		l = n->left;
261 		if(cases == C)
262 			diag(n, "case/default outside a switch");
263 		if(l == Z) {
264 			casf();
265 			cases->val = 0;
266 			cases->def = 1;
267 			cases->label = pc;
268 			cases->isv = 0;
269 			goto rloop;
270 		}
271 		complex(l);
272 		if(l->type == T)
273 			goto rloop;
274 		if(l->op != OCONST || !typeswitch[l->type->etype]) {
275 			diag(n, "case expression must be integer constant");
276 			goto rloop;
277 		}
278 		casf();
279 		cases->val = l->vconst;
280 		cases->def = 0;
281 		cases->label = pc;
282 		cases->isv = typev[l->type->etype];
283 		goto rloop;
284 
285 	case OSWITCH:
286 		l = n->left;
287 		complex(l);
288 		if(l->type == T)
289 			break;
290 		if(!typeswitch[l->type->etype]) {
291 			diag(n, "switch expression must be integer");
292 			break;
293 		}
294 
295 		gbranch(OGOTO);		/* entry */
296 		sp = p;
297 
298 		cn = cases;
299 		cases = C;
300 		casf();
301 
302 		sbc = breakpc;
303 		breakpc = pc;
304 		snbreak = nbreak;
305 		nbreak = 0;
306 		gbranch(OGOTO);
307 		spb = p;
308 
309 		gen(n->right);		/* body */
310 		if(canreach){
311 			gbranch(OGOTO);
312 			patch(p, breakpc);
313 			nbreak++;
314 		}
315 
316 		patch(sp, pc);
317 		regalloc(&nod, l, Z);
318 		/* always signed */
319 		if(typev[l->type->etype])
320 			nod.type = types[TVLONG];
321 		else
322 			nod.type = types[TLONG];
323 		cgen(l, &nod);
324 		doswit(&nod);
325 		regfree(&nod);
326 		patch(spb, pc);
327 
328 		cases = cn;
329 		breakpc = sbc;
330 		canreach = nbreak!=0;
331 		if(canreach == 0)
332 			warnreach = !suppress;
333 		nbreak = snbreak;
334 		break;
335 
336 	case OWHILE:
337 	case ODWHILE:
338 		l = n->left;
339 		gbranch(OGOTO);		/* entry */
340 		sp = p;
341 
342 		scc = continpc;
343 		continpc = pc;
344 		gbranch(OGOTO);
345 		spc = p;
346 
347 		sbc = breakpc;
348 		breakpc = pc;
349 		snbreak = nbreak;
350 		nbreak = 0;
351 		gbranch(OGOTO);
352 		spb = p;
353 
354 		patch(spc, pc);
355 		if(n->op == OWHILE)
356 			patch(sp, pc);
357 		bcomplex(l, Z);		/* test */
358 		patch(p, breakpc);
359 		if(l->op != OCONST || vconst(l) == 0)
360 			nbreak++;
361 
362 		if(n->op == ODWHILE)
363 			patch(sp, pc);
364 		gen(n->right);		/* body */
365 		gbranch(OGOTO);
366 		patch(p, continpc);
367 
368 		patch(spb, pc);
369 		continpc = scc;
370 		breakpc = sbc;
371 		canreach = nbreak!=0;
372 		if(canreach == 0)
373 			warnreach = !suppress;
374 		nbreak = snbreak;
375 		break;
376 
377 	case OFOR:
378 		l = n->left;
379 		if(!canreach && l->right->left && warnreach) {
380 			warn(n, "unreachable code FOR");
381 			warnreach = 0;
382 		}
383 		gen(l->right->left);	/* init */
384 		gbranch(OGOTO);		/* entry */
385 		sp = p;
386 
387 		/*
388 		 * if there are no incoming labels in the
389 		 * body and the top's not reachable, warn
390 		 */
391 		if(!canreach && warnreach && deadheads(n)) {
392 			warn(n, "unreachable code %O", o);
393 			warnreach = 0;
394 		}
395 
396 		scc = continpc;
397 		continpc = pc;
398 		gbranch(OGOTO);
399 		spc = p;
400 
401 		sbc = breakpc;
402 		breakpc = pc;
403 		snbreak = nbreak;
404 		nbreak = 0;
405 		sncontin = ncontin;
406 		ncontin = 0;
407 		gbranch(OGOTO);
408 		spb = p;
409 
410 		patch(spc, pc);
411 		gen(l->right->right);	/* inc */
412 		patch(sp, pc);
413 		if(l->left != Z) {	/* test */
414 			bcomplex(l->left, Z);
415 			patch(p, breakpc);
416 			if(l->left->op != OCONST || vconst(l->left) == 0)
417 				nbreak++;
418 		}
419 		canreach = 1;
420 		gen(n->right);		/* body */
421 		if(canreach){
422 			gbranch(OGOTO);
423 			patch(p, continpc);
424 			ncontin++;
425 		}
426 		if(!ncontin && l->right->right && warnreach) {
427 			warn(l->right->right, "unreachable FOR inc");
428 			warnreach = 0;
429 		}
430 
431 		patch(spb, pc);
432 		continpc = scc;
433 		breakpc = sbc;
434 		canreach = nbreak!=0;
435 		if(canreach == 0)
436 			warnreach = !suppress;
437 		nbreak = snbreak;
438 		ncontin = sncontin;
439 		break;
440 
441 	case OCONTINUE:
442 		if(continpc < 0) {
443 			diag(n, "continue not in a loop");
444 			break;
445 		}
446 		gbranch(OGOTO);
447 		patch(p, continpc);
448 		ncontin++;
449 		canreach = 0;
450 		warnreach = !suppress;
451 		break;
452 
453 	case OBREAK:
454 		if(breakpc < 0) {
455 			diag(n, "break not in a loop");
456 			break;
457 		}
458 		/*
459 		 * Don't complain about unreachable break statements.
460 		 * There are breaks hidden in yacc's output and some people
461 		 * write return; break; in their switch statements out of habit.
462 		 * However, don't confuse the analysis by inserting an
463 		 * unreachable reference to breakpc either.
464 		 */
465 		if(!canreach)
466 			break;
467 		gbranch(OGOTO);
468 		patch(p, breakpc);
469 		nbreak++;
470 		canreach = 0;
471 		warnreach = !suppress;
472 		break;
473 
474 	case OIF:
475 		l = n->left;
476 		if(bcomplex(l, n->right)) {
477 			if(typefd[l->type->etype])
478 				f = !l->fconst;
479 			else
480 				f = !l->vconst;
481 			if(debug['c'])
482 				print("%L const if %s\n", nearln, f ? "false" : "true");
483 			if(f) {
484 				canreach = 1;
485 				supgen(n->right->left);
486 				oldreach = canreach;
487 				canreach = 1;
488 				gen(n->right->right);
489 				/*
490 				 * treat constant ifs as regular ifs for
491 				 * reachability warnings.
492 				 */
493 				if(!canreach && oldreach && debug['w'] < 2)
494 					warnreach = 0;
495 			}
496 			else {
497 				canreach = 1;
498 				gen(n->right->left);
499 				oldreach = canreach;
500 				canreach = 1;
501 				supgen(n->right->right);
502 				/*
503 				 * treat constant ifs as regular ifs for
504 				 * reachability warnings.
505 				 */
506 				if(!oldreach && canreach && debug['w'] < 2)
507 					warnreach = 0;
508 				canreach = oldreach;
509 			}
510 		}
511 		else {
512 			sp = p;
513 			canreach = 1;
514 			if(n->right->left != Z)
515 				gen(n->right->left);
516 			oldreach = canreach;
517 			canreach = 1;
518 			if(n->right->right != Z) {
519 				gbranch(OGOTO);
520 				patch(sp, pc);
521 				sp = p;
522 				gen(n->right->right);
523 			}
524 			patch(sp, pc);
525 			canreach = canreach || oldreach;
526 			if(canreach == 0)
527 				warnreach = !suppress;
528 		}
529 		break;
530 
531 	case OSET:
532 	case OUSED:
533 		usedset(n->left, o);
534 		break;
535 	}
536 }
537 
538 void
539 usedset(Node *n, int o)
540 {
541 	if(n->op == OLIST) {
542 		usedset(n->left, o);
543 		usedset(n->right, o);
544 		return;
545 	}
546 	complex(n);
547 	switch(n->op) {
548 	case OADDR:	/* volatile */
549 		gins(ANOP, n, Z);
550 		break;
551 	case ONAME:
552 		if(o == OSET)
553 			gins(ANOP, Z, n);
554 		else
555 			gins(ANOP, n, Z);
556 		break;
557 	}
558 }
559 
560 int
561 bcomplex(Node *n, Node *c)
562 {
563 	Node *b, nod;
564 
565 
566 	complex(n);
567 	if(n->type != T)
568 	if(tcompat(n, T, n->type, tnot))
569 		n->type = T;
570 	if(n->type == T) {
571 		gbranch(OGOTO);
572 		return 0;
573 	}
574 	if(c != Z && n->op == OCONST && deadheads(c))
575 		return 1;
576 	if(newvlongcode && typev[n->type->etype] && machcap(Z)) {
577 		nod = znode;
578 		b = &nod;
579 		b->op = ONE;
580 		b->left = n;
581 		b->right = new(0, Z, Z);
582 		*b->right = *nodconst(0);
583 		b->right->type = n->type;
584 		b->type = types[TLONG];
585 		xcom(b);
586 		boolgen(b, 1, Z);
587 		return 0;
588 	}
589 	bool64(n);
590 	boolgen(n, 1, Z);
591 	return 0;
592 }
593