xref: /plan9/sys/src/cmd/vc/sgen.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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(typesu[thisfn->link->etype] || typev[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 			if(firstargtype->width < tint->width)
42 				nod1.xoffset += endian(firstargtype->width);
43 			nod1.etype = firstargtype->etype;
44 			nodreg(&nod, &nod1, REGARG);
45 			gopcode(OAS, &nod, Z, &nod1);
46 		}
47 	}
48 
49 	retok = 0;
50 	gen(n);
51 	if(!retok)
52 		if(thisfn->link->etype != TVOID)
53 			warn(Z, "no return at end of function: %s", n1->sym->name);
54 	noretval(3);
55 	gbranch(ORETURN);
56 
57 	if(!debug['N'] || debug['R'] || debug['P'])
58 		regopt(sp);
59 
60 	sp->to.offset += maxargsafe;
61 }
62 
63 void
64 gen(Node *n)
65 {
66 	Node *l, nod;
67 	Prog *sp, *spc, *spb;
68 	Case *cn;
69 	long sbc, scc;
70 	int o;
71 
72 loop:
73 	if(n == Z)
74 		return;
75 	nearln = n->lineno;
76 	o = n->op;
77 	if(debug['G'])
78 		if(o != OLIST)
79 			print("%L %O\n", nearln, o);
80 
81 	retok = 0;
82 	switch(o) {
83 
84 	default:
85 		complex(n);
86 		cgen(n, Z);
87 		break;
88 
89 	case OLIST:
90 		gen(n->left);
91 
92 	rloop:
93 		n = n->right;
94 		goto loop;
95 
96 	case ORETURN:
97 		retok = 1;
98 		complex(n);
99 		if(n->type == T)
100 			break;
101 		l = n->left;
102 		if(l == Z) {
103 			noretval(3);
104 			gbranch(ORETURN);
105 			break;
106 		}
107 		if(typesu[n->type->etype] || typev[n->type->etype]) {
108 			sugen(l, nodret, n->type->width);
109 			noretval(3);
110 			gbranch(ORETURN);
111 			break;
112 		}
113 		regret(&nod, n);
114 		cgen(l, &nod);
115 		regfree(&nod);
116 		if(typefd[n->type->etype])
117 			noretval(1);
118 		else
119 			noretval(2);
120 		gbranch(ORETURN);
121 		break;
122 
123 	case OLABEL:
124 		l = n->left;
125 		if(l) {
126 			l->pc = pc;
127 			if(l->label)
128 				patch(l->label, pc);
129 		}
130 		gbranch(OGOTO);	/* prevent self reference in reg */
131 		patch(p, pc);
132 		goto rloop;
133 
134 	case OGOTO:
135 		retok = 1;
136 		n = n->left;
137 		if(n == Z)
138 			return;
139 		if(n->complex == 0) {
140 			diag(Z, "label undefined: %s", n->sym->name);
141 			return;
142 		}
143 		gbranch(OGOTO);
144 		if(n->pc) {
145 			patch(p, n->pc);
146 			return;
147 		}
148 		if(n->label)
149 			patch(n->label, pc-1);
150 		n->label = p;
151 		return;
152 
153 	case OCASE:
154 		l = n->left;
155 		if(cases == C)
156 			diag(n, "case/default outside a switch");
157 		if(l == Z) {
158 			cas();
159 			cases->val = 0;
160 			cases->def = 1;
161 			cases->label = pc;
162 			goto rloop;
163 		}
164 		complex(l);
165 		if(l->type == T)
166 			goto rloop;
167 		if(l->op == OCONST)
168 		if(typechl[l->type->etype]) {
169 			cas();
170 			cases->val = l->vconst;
171 			cases->def = 0;
172 			cases->label = pc;
173 			goto rloop;
174 		}
175 		diag(n, "case expression must be integer constant");
176 		goto rloop;
177 
178 	case OSWITCH:
179 		l = n->left;
180 		complex(l);
181 		if(l->type == T)
182 			break;
183 		if(!typechl[l->type->etype]) {
184 			diag(n, "switch expression must be integer");
185 			break;
186 		}
187 
188 		gbranch(OGOTO);		/* entry */
189 		sp = p;
190 
191 		cn = cases;
192 		cases = C;
193 		cas();
194 
195 		sbc = breakpc;
196 		breakpc = pc;
197 		gbranch(OGOTO);
198 		spb = p;
199 
200 		gen(n->right);
201 		gbranch(OGOTO);
202 		patch(p, breakpc);
203 
204 		patch(sp, pc);
205 		regalloc(&nod, l, Z);
206 		nod.type = types[TLONG];
207 		cgen(l, &nod);
208 		doswit(&nod);
209 		regfree(&nod);
210 		patch(spb, pc);
211 
212 		cases = cn;
213 		breakpc = sbc;
214 		break;
215 
216 	case OWHILE:
217 	case ODWHILE:
218 		l = n->left;
219 		gbranch(OGOTO);		/* entry */
220 		sp = p;
221 
222 		scc = continpc;
223 		continpc = pc;
224 		gbranch(OGOTO);
225 		spc = p;
226 
227 		sbc = breakpc;
228 		breakpc = pc;
229 		gbranch(OGOTO);
230 		spb = p;
231 
232 		patch(spc, pc);
233 		if(n->op == OWHILE)
234 			patch(sp, pc);
235 		bcomplex(l);		/* test */
236 		patch(p, breakpc);
237 
238 		if(n->op == ODWHILE)
239 			patch(sp, pc);
240 		gen(n->right);		/* body */
241 		gbranch(OGOTO);
242 		patch(p, continpc);
243 
244 		patch(spb, pc);
245 		continpc = scc;
246 		breakpc = sbc;
247 		break;
248 
249 	case OFOR:
250 		l = n->left;
251 		gen(l->right->left);	/* init */
252 		gbranch(OGOTO);		/* entry */
253 		sp = p;
254 
255 		scc = continpc;
256 		continpc = pc;
257 		gbranch(OGOTO);
258 		spc = p;
259 
260 		sbc = breakpc;
261 		breakpc = pc;
262 		gbranch(OGOTO);
263 		spb = p;
264 
265 		patch(spc, pc);
266 		gen(l->right->right);	/* inc */
267 		patch(sp, pc);
268 		if(l->left != Z) {	/* test */
269 			bcomplex(l->left);
270 			patch(p, breakpc);
271 		}
272 		gen(n->right);		/* body */
273 		gbranch(OGOTO);
274 		patch(p, continpc);
275 
276 		patch(spb, pc);
277 		continpc = scc;
278 		breakpc = sbc;
279 		break;
280 
281 	case OCONTINUE:
282 		if(continpc < 0) {
283 			diag(n, "continue not in a loop");
284 			break;
285 		}
286 		gbranch(OGOTO);
287 		patch(p, continpc);
288 		break;
289 
290 	case OBREAK:
291 		if(breakpc < 0) {
292 			diag(n, "break not in a loop");
293 			break;
294 		}
295 		gbranch(OGOTO);
296 		patch(p, breakpc);
297 		break;
298 
299 	case OIF:
300 		l = n->left;
301 		bcomplex(l);
302 		sp = p;
303 		if(n->right->left != Z)
304 			gen(n->right->left);
305 		if(n->right->right != Z) {
306 			gbranch(OGOTO);
307 			patch(sp, pc);
308 			sp = p;
309 			gen(n->right->right);
310 		}
311 		patch(sp, pc);
312 		break;
313 
314 	case OSET:
315 	case OUSED:
316 		n = n->left;
317 		for(;;) {
318 			if(n->op == OLIST) {
319 				l = n->right;
320 				n = n->left;
321 				complex(l);
322 				if(l->op == ONAME) {
323 					if(o == OSET)
324 						gins(ANOP, Z, l);
325 					else
326 						gins(ANOP, l, Z);
327 				}
328 			} else {
329 				complex(n);
330 				if(n->op == ONAME) {
331 					if(o == OSET)
332 						gins(ANOP, Z, n);
333 					else
334 						gins(ANOP, n, Z);
335 				}
336 				break;
337 			}
338 		}
339 		break;
340 	}
341 }
342 
343 void
344 noretval(int n)
345 {
346 
347 	if(n & 1) {
348 		gins(ANOP, Z, Z);
349 		p->to.type = D_REG;
350 		p->to.reg = REGRET;
351 	}
352 	if(n & 2) {
353 		gins(ANOP, Z, Z);
354 		p->to.type = D_FREG;
355 		p->to.reg = FREGRET;
356 	}
357 }
358 
359 /*
360  *	calculate addressability as follows
361  *		CONST ==> 20		$value
362  *		NAME ==> 10		name
363  *		REGISTER ==> 11		register
364  *		INDREG ==> 12		*[(reg)+offset]
365  *		&10 ==> 2		$name
366  *		ADD(2, 20) ==> 2	$name+offset
367  *		ADD(3, 20) ==> 3	$(reg)+offset
368  *		&12 ==> 3		$(reg)+offset
369  *		*11 ==> 11		??
370  *		*2 ==> 10		name
371  *		*3 ==> 12		*(reg)+offset
372  *	calculate complexity (number of registers)
373  */
374 void
375 xcom(Node *n)
376 {
377 	Node *l, *r;
378 	int t;
379 
380 	if(n == Z)
381 		return;
382 	l = n->left;
383 	r = n->right;
384 	n->addable = 0;
385 	n->complex = 0;
386 	switch(n->op) {
387 	case OCONST:
388 		n->addable = 20;
389 		return;
390 
391 	case OREGISTER:
392 		n->addable = 11;
393 		return;
394 
395 	case OINDREG:
396 		n->addable = 12;
397 		return;
398 
399 	case ONAME:
400 		n->addable = 10;
401 		return;
402 
403 	case OADDR:
404 		xcom(l);
405 		if(l->addable == 10)
406 			n->addable = 2;
407 		if(l->addable == 12)
408 			n->addable = 3;
409 		break;
410 
411 	case OIND:
412 		xcom(l);
413 		if(l->addable == 11)
414 			n->addable = 12;
415 		if(l->addable == 3)
416 			n->addable = 12;
417 		if(l->addable == 2)
418 			n->addable = 10;
419 		break;
420 
421 	case OADD:
422 		xcom(l);
423 		xcom(r);
424 		if(l->addable == 20) {
425 			if(r->addable == 2)
426 				n->addable = 2;
427 			if(r->addable == 3)
428 				n->addable = 3;
429 		}
430 		if(r->addable == 20) {
431 			if(l->addable == 2)
432 				n->addable = 2;
433 			if(l->addable == 3)
434 				n->addable = 3;
435 		}
436 		break;
437 
438 	case OASLMUL:
439 	case OASMUL:
440 		xcom(l);
441 		xcom(r);
442 		t = vlog(r);
443 		if(t >= 0) {
444 			n->op = OASASHL;
445 			r->vconst = t;
446 			r->type = tint;
447 		}
448 		break;
449 
450 	case OMUL:
451 	case OLMUL:
452 		xcom(l);
453 		xcom(r);
454 		t = vlog(r);
455 		if(t >= 0) {
456 			n->op = OASHL;
457 			r->vconst = t;
458 			r->type = tint;
459 		}
460 		t = vlog(l);
461 		if(t >= 0) {
462 			n->op = OASHL;
463 			n->left = r;
464 			n->right = l;
465 			r = l;
466 			l = n->left;
467 			r->vconst = t;
468 			r->type = tint;
469 		}
470 		break;
471 
472 	case OASLDIV:
473 		xcom(l);
474 		xcom(r);
475 		t = vlog(r);
476 		if(t >= 0) {
477 			n->op = OASLSHR;
478 			r->vconst = t;
479 			r->type = tint;
480 		}
481 		break;
482 
483 	case OLDIV:
484 		xcom(l);
485 		xcom(r);
486 		t = vlog(r);
487 		if(t >= 0) {
488 			n->op = OLSHR;
489 			r->vconst = t;
490 			r->type = tint;
491 		}
492 		break;
493 
494 	case OASLMOD:
495 		xcom(l);
496 		xcom(r);
497 		t = vlog(r);
498 		if(t >= 0) {
499 			n->op = OASAND;
500 			r->vconst--;
501 		}
502 		break;
503 
504 	case OLMOD:
505 		xcom(l);
506 		xcom(r);
507 		t = vlog(r);
508 		if(t >= 0) {
509 			n->op = OAND;
510 			r->vconst--;
511 		}
512 		break;
513 
514 	default:
515 		if(l != Z)
516 			xcom(l);
517 		if(r != Z)
518 			xcom(r);
519 		break;
520 	}
521 	if(n->addable >= 10)
522 		return;
523 
524 	if(l != Z)
525 		n->complex = l->complex;
526 	if(r != Z) {
527 		if(r->complex == n->complex)
528 			n->complex = r->complex+1;
529 		else
530 		if(r->complex > n->complex)
531 			n->complex = r->complex;
532 	}
533 	if(n->complex == 0)
534 		n->complex++;
535 
536 	if(com64(n))
537 		return;
538 
539 	switch(n->op) {
540 	case OFUNC:
541 		n->complex = FNX;
542 		break;
543 
544 	case OADD:
545 	case OXOR:
546 	case OAND:
547 	case OOR:
548 	case OEQ:
549 	case ONE:
550 		/*
551 		 * immediate operators, make const on right
552 		 */
553 		if(l->op == OCONST) {
554 			n->left = r;
555 			n->right = l;
556 		}
557 		break;
558 	}
559 }
560 
561 void
562 bcomplex(Node *n)
563 {
564 
565 	complex(n);
566 	if(n->type != T)
567 	if(tcompat(n, T, n->type, tnot))
568 		n->type = T;
569 	if(n->type != T) {
570 		bool64(n);
571 		boolgen(n, 1, Z);
572 	} else
573 		gbranch(OGOTO);
574 }
575