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