xref: /inferno-os/limbo/com.c (revision 2b69dba5038ffd0b59cf30a4c44bce549e5097f8)
1 #include "limbo.h"
2 
3 static	Inst	**breaks;
4 static	Inst	**conts;
5 static	Decl	**labels;
6 static	Node **bcscps;
7 static	int	labdep;
8 static	Inst	nocont;
9 
10 static	int scp;
11 static	Node *scps[MaxScope];
12 
13 static	int trcom(Node*, Node*, int);
14 
15 static void
16 pushscp(Node *n)
17 {
18 	if (scp >= MaxScope)
19 		fatal("scope too deep");
20 	scps[scp++] = n;
21 }
22 
23 static void
24 popscp(void)
25 {
26 	scp--;
27 }
28 
29 static Node *
30 curscp(void)
31 {
32 	if (scp == 0)
33 		return nil;
34 	return scps[scp-1];
35 }
36 
37 static void
38 zeroscopes(Node *stop)
39 {
40 	int i;
41 	Node *cs;
42 
43 	for (i = scp-1; i >= 0; i--) {
44 		cs = scps[i];
45 		if (cs == stop)
46 			break;
47 		zcom(cs->left, nil);
48 	}
49 }
50 
51 static void
52 zeroallscopes(Node *n, Node **nn)
53 {
54 	if(n == nil)
55 		return;
56 	for(; n != nil; n = n->right){
57 		switch(n->op){
58 		case Oscope:
59 			zeroallscopes(n->right, nn);
60 			zcom(n->left, nn);
61 			return;
62 		case Olabel:
63 		case Odo:
64 			zeroallscopes(n->right, nn);
65 			return;
66 		case Oif:
67 		case Ofor:
68 			zeroallscopes(n->right->left, nn);
69 			zeroallscopes(n->right->right, nn);
70 			return;
71 		case Oalt:
72 		case Ocase:
73 		case Opick:
74 		case Oexcept:
75 			for(n = n->right; n != nil; n = n->right)
76 				zeroallscopes(n->left->right, nn);
77 			return;
78 		case Oseq:
79 			zeroallscopes(n->left, nn);
80 			break;
81 		case Oexstmt:
82 			zeroallscopes(n->left, nn);
83 			zeroallscopes(n->right, nn);
84 			return;
85 		default:
86 			return;
87 		}
88 	}
89 }
90 
91 static Except *excs;
92 
93 static void
94 installexc(Node *en, Inst *p1, Inst *p2, Node *zn)
95 {
96 	int i, ne;
97 	Except *e;
98 	Case *c;
99 	Label *lab;
100 
101 	e = allocmem(sizeof(Except));
102 	e->p1 = p1;
103 	e->p2 = p2;
104 	e->c = en->ty->cse;
105 	e->d = en->left->decl;
106 	e->zn = zn;
107 	e->desc = nil;
108 	e->next = excs;
109 	excs = e;
110 
111 	ne = 0;
112 	c = e->c;
113 	for(i = 0; i < c->nlab; i++){
114 		lab = &c->labs[i];
115 		if(lab->start->ty->kind == Texception)
116 			ne++;
117 	}
118 	e->ne = ne;
119 }
120 
121 static int
122 inlist(Decl *d, Decl *dd)
123 {
124 	for( ; dd != nil; dd = dd->next)
125 		if(d == dd)
126 			return 1;
127 	return 0;
128 }
129 
130 static void
131 excdesc(void)
132 {
133 	ulong o, maxo;
134 	Except *e;
135 	Node *n;
136 	Decl *d, *dd, *nd;
137 
138 	for(e = excs; e != nil; e = e->next){
139 		if(e->zn != nil){
140 			/* set up a decl list for gendesc */
141 			dd = nil;
142 			maxo = 0;
143 			for(n = e->zn ; n != nil; n = n->right){
144 				d = n->decl;
145 				d->locals = d->next;
146 				if(!inlist(d, dd)){
147 					d->next = dd;
148 					dd = d;
149 					o = d->offset+d->ty->size;
150 					if(o > maxo)
151 						maxo = o;
152 				}
153 			}
154 			e->desc = gendesc(e->d, align(maxo, MaxAlign), dd);
155 			for(d = dd; d != nil; d = nd){
156 				nd = d->next;
157 				d->next = d->locals;
158 				d->locals = nil;
159 			}
160 			e->zn = nil;
161 		}
162 	}
163 }
164 
165 static Except*
166 reve(Except *e)
167 {
168 	Except *l, *n;
169 
170 	l = nil;
171 	for( ; e != nil; e = n){
172 		n = e->next;
173 		e->next = l;
174 		l = e;
175 	}
176 	return l;
177 }
178 
179 static int
180 ckinline0(Node *n, Decl *d)
181 {
182 	Decl *dd;
183 
184 	if(n == nil)
185 		return 1;
186 	if(n->op == Oname){
187 		dd = n->decl;
188 		if(d == dd)
189 			return 0;
190 		if(dd->caninline == 1)
191 			return ckinline0(dd->init->right, d);
192 		return 1;
193 	}
194 	return ckinline0(n->left, d) && ckinline0(n->right, d);
195 }
196 
197 static void
198 ckinline(Decl *d)
199 {
200 	d->caninline = ckinline0(d->init->right, d);
201 }
202 
203 void
204 modcom(Decl *entry)
205 {
206 	Decl *globals, *m, *nils, *d, *ldts;
207 	long ninst, ndata, ndesc, nlink, offset, ldtoff;
208 	int ok, i, hints;
209 	Dlist *dl;
210 
211 	if(errors)
212 		return;
213 
214 	if(emitcode || emitstub || emittab != nil){
215 		emit(curscope());
216 		popscope();
217 		return;
218 	}
219 
220 	/*
221 	 * scom introduces global variables for case statements
222 	 * and unaddressable constants, so it must be done before
223 	 * popping the global scope
224 	 */
225 	nlabel = 0;
226 	maxstack = MaxTemp;
227 	genstart();
228 
229 	for(i = 0; i < nfns; i++)
230 		if(fns[i]->caninline == 1)
231 			ckinline(fns[i]);
232 
233 	ok = 0;
234 	for(i = 0; i < nfns; i++){
235 		d = fns[i];
236 if(debug['v']) print("fncom: %s %d %p\n", d->sym->name, d->refs, d);
237 		if(d->refs > 1 && !(d->caninline == 1 && local(d) && d->iface == nil)){
238 			fns[ok++] = d;
239 			fncom(d);
240 		}
241 	}
242 	nfns = ok;
243 	if(blocks != -1)
244 		fatal("blocks not nested correctly");
245 	firstinst = firstinst->next;
246 	if(errors)
247 		return;
248 
249 	globals = popscope();
250 	checkrefs(globals);
251 	if(errors)
252 		return;
253 	globals = vars(globals);
254 	moddataref();
255 
256 	nils = popscope();
257 	m = nil;
258 	for(d = nils; d != nil; d = d->next){
259 		if(debug['n'])
260 			print("nil '%s' ref %d\n", d->sym->name, d->refs);
261 		if(d->refs && m == nil)
262 			m = dupdecl(d);
263 		d->offset = 0;
264 	}
265 	globals = appdecls(m, globals);
266 	globals = namesort(globals);
267 	globals = modglobals(impdecls->d, globals);
268 	vcom(globals);
269 	narrowmods();
270 	ldts = nil;
271 	if(LDT)
272 		globals = resolveldts(globals, &ldts);
273 	offset = idoffsets(globals, 0, IBY2WD);
274 	if(LDT)
275 		ldtoff = idindices(ldts);	/* ldtoff = idoffsets(ldts, 0, IBY2WD); */
276 	for(d = nils; d != nil; d = d->next){
277 		if(debug['n'])
278 			print("nil '%s' ref %d\n", d->sym->name, d->refs);
279 		if(d->refs)
280 			d->offset = m->offset;
281 	}
282 
283 	if(debug['g']){
284 		print("globals:\n");
285 		printdecls(globals);
286 	}
287 
288 	ndata = 0;
289 	for(d = globals; d != nil; d = d->next)
290 		ndata++;
291 	ndesc = resolvedesc(impdecls->d, offset, globals);
292 	ninst = resolvepcs(firstinst);
293 	modresolve();
294 	if(impdecls->next != nil)
295 		for(dl = impdecls; dl != nil; dl = dl->next)
296 			resolvemod(dl->d);
297 	nlink = resolvemod(impdecl);
298 
299 	maxstack *= 10;
300 	if(fixss != 0)
301 		maxstack = fixss;
302 
303 	if(debug['s'])
304 		print("%ld instructions\n%ld data elements\n%ld type descriptors\n%ld functions exported\n%ld stack size\n",
305 			ninst, ndata, ndesc, nlink, maxstack);
306 
307 	excs = reve(excs);
308 
309 	if(gendis){
310 		discon(XMAGIC);
311 		hints = 0;
312 		if(mustcompile)
313 			hints |= MUSTCOMPILE;
314 		if(dontcompile)
315 			hints |= DONTCOMPILE;
316 		if(LDT)
317 			hints |= HASLDT;
318 		if(excs != nil)
319 			hints |= HASEXCEPT;
320 		discon(hints);		/* runtime hints */
321 		discon(maxstack);	/* minimum stack extent size */
322 		discon(ninst);
323 		discon(offset);
324 		discon(ndesc);
325 		discon(nlink);
326 		disentry(entry);
327 		disinst(firstinst);
328 		disdesc(descriptors);
329 		disvar(offset, globals);
330 		dismod(impdecl);
331 		if(LDT)
332 			disldt(ldtoff, ldts);
333 		if(excs != nil)
334 			disexc(excs);
335 		dispath();
336 	}else{
337 		asminst(firstinst);
338 		asmentry(entry);
339 		asmdesc(descriptors);
340 		asmvar(offset, globals);
341 		asmmod(impdecl);
342 		if(LDT)
343 			asmldt(ldtoff, ldts);
344 		if(excs != nil)
345 			asmexc(excs);
346 		asmpath();
347 	}
348 	if(bsym != nil){
349 		sblmod(impdecl);
350 
351 		sblfiles();
352 		sblinst(firstinst, ninst);
353 		sblty(adts, nadts);
354 		sblfn(fns, nfns);
355 		sblvar(globals);
356 	}
357 
358 	firstinst = nil;
359 	lastinst = nil;
360 
361 	excs = nil;
362 }
363 
364 void
365 fncom(Decl *decl)
366 {
367 	Src src;
368 	Node *n;
369 	Decl *loc, *last;
370 	Inst *in;
371 	int valued;
372 
373 	curfn = decl;
374 	if(ispoly(decl))
375 		addfnptrs(decl, 1);
376 
377 	/*
378 	 * pick up the function body and compile it
379 	 * this code tries to clean up the parse nodes as fast as possible
380 	 * function is Ofunc(name, body)
381 	 */
382 	decl->pc = nextinst();
383 	tinit();
384 	labdep = 0;
385 	scp = 0;
386 	breaks = allocmem(maxlabdep * sizeof breaks[0]);
387 	conts = allocmem(maxlabdep * sizeof conts[0]);
388 	labels = allocmem(maxlabdep * sizeof labels[0]);
389 	bcscps = allocmem(maxlabdep * sizeof bcscps[0]);
390 	n = decl->init;
391 	if(decl->caninline == 1)
392 		decl->init = dupn(0, nil, n);
393 	else
394 		decl->init = n->left;
395 	src = n->right->src;
396 	src.start.line = src.stop.line;
397 	src.start.pos = src.stop.pos - 1;
398 	for(n = n->right; n != nil; n = n->right){
399 		if(n->op != Oseq){
400 			if(n->op == Ocall && trcom(n, nil, 1))
401 				break;
402 			scom(n);
403 			break;
404 		}
405 		if(n->left->op == Ocall && trcom(n->left, n->right, 1)){
406 			n = n->right;
407 			if(n == nil || n->op != Oseq)
408 				break;
409 		}
410 		else
411 			scom(n->left);
412 	}
413 	pushblock();
414 	valued = decl->ty->tof != tnone;
415 	in = genrawop(&src, valued? IRAISE: IRET, nil, nil, nil);
416 	popblock();
417 	reach(decl->pc);
418 	if(valued && in->reach)
419 		error(src.start, "no return at end of function %D", decl);
420 	/* decl->endpc = lastinst; */
421 	if(labdep != 0)
422 		fatal("unbalanced label stack");
423 	free(breaks);
424 	free(conts);
425 	free(labels);
426 	free(bcscps);
427 
428 	loc = declsort(appdecls(vars(decl->locals), tdecls()));
429 	decl->offset = idoffsets(loc, decl->offset, MaxAlign);
430 	for(last = decl->ty->ids; last != nil && last->next != nil; last = last->next)
431 		;
432 	if(last != nil)
433 		last->next = loc;
434 	else
435 		decl->ty->ids = loc;
436 
437 	if(debug['f']){
438 		print("fn: %s\n", decl->sym->name);
439 		printdecls(decl->ty->ids);
440 	}
441 
442 	decl->desc = gendesc(decl, decl->offset, decl->ty->ids);
443 	decl->locals = loc;
444 	excdesc();
445 	if(decl->offset > maxstack)
446 		maxstack = decl->offset;
447 	if(optims)
448 		optim(decl->pc, decl);
449 	if(last != nil)
450 		last->next = nil;
451 	else
452 		decl->ty->ids = nil;
453 }
454 
455 /*
456  * statement compiler
457  */
458 void
459 scom(Node *n)
460 {
461 	Inst *p, *pp, *p1, *p2, *p3;
462 	Node tret, *left, *zn;
463 
464 	for(; n != nil; n = n->right){
465 		switch(n->op){
466 		case Ocondecl:
467 		case Otypedecl:
468 		case Ovardecl:
469 		case Oimport:
470 		case Oexdecl:
471 			return;
472 		case Ovardecli:
473 			break;
474 		case Oscope:
475 			pushscp(n);
476 			scom(n->right);
477 			popscp();
478 			zcom(n->left, nil);
479 			return;
480 		case Olabel:
481 			scom(n->right);
482 			return;
483 		case Oif:
484 			pushblock();
485 			left = simplify(n->left);
486 			if(left->op == Oconst && left->ty == tint){
487 				if(left->val != 0)
488 					scom(n->right->left);
489 				else
490 					scom(n->right->right);
491 				popblock();
492 				return;
493 			}
494 			sumark(left);
495 			pushblock();
496 			p = bcom(left, 1, nil);
497 			tfreenow();
498 			popblock();
499 			scom(n->right->left);
500 			if(n->right->right != nil){
501 				pp = p;
502 				p = genrawop(&lastinst->src, IJMP, nil, nil, nil);
503 				patch(pp, nextinst());
504 				scom(n->right->right);
505 			}
506 			patch(p, nextinst());
507 			popblock();
508 			return;
509 		case Ofor:
510 			n->left = left = simplify(n->left);
511 			if(left->op == Oconst && left->ty == tint){
512 				if(left->val == 0)
513 					return;
514 				left->op = Onothing;
515 				left->ty = tnone;
516 				left->decl = nil;
517 			}
518 			pp = nextinst();
519 			pushblock();
520 			/* b = pushblock(); */
521 			sumark(left);
522 			p = bcom(left, 1, nil);
523 			tfreenow();
524 			popblock();
525 
526 			if(labdep >= maxlabdep)
527 				fatal("label stack overflow");
528 			breaks[labdep] = nil;
529 			conts[labdep] = nil;
530 			labels[labdep] = n->decl;
531 			bcscps[labdep] = curscp();
532 			labdep++;
533 			scom(n->right->left);
534 			labdep--;
535 
536 			patch(conts[labdep], nextinst());
537 			if(n->right->right != nil){
538 				pushblock();
539 				scom(n->right->right);
540 				popblock();
541 			}
542 			repushblock(lastinst->block);	/* was b */
543 			patch(genrawop(&lastinst->src, IJMP, nil, nil, nil), pp);	/* for cprof: was &left->src */
544 			popblock();
545 			patch(p, nextinst());
546 			patch(breaks[labdep], nextinst());
547 			return;
548 		case Odo:
549 			pp = nextinst();
550 
551 			if(labdep >= maxlabdep)
552 				fatal("label stack overflow");
553 			breaks[labdep] = nil;
554 			conts[labdep] = nil;
555 			labels[labdep] = n->decl;
556 			bcscps[labdep] = curscp();
557 			labdep++;
558 			scom(n->right);
559 			labdep--;
560 
561 			patch(conts[labdep], nextinst());
562 
563 			left = simplify(n->left);
564 			if(left->op == Onothing
565 			|| left->op == Oconst && left->ty == tint){
566 				if(left->op == Onothing || left->val != 0){
567 					pushblock();
568 					p = genrawop(&left->src, IJMP, nil, nil, nil);
569 					popblock();
570 				}else
571 					p = nil;
572 			}else{
573 				pushblock();
574 				p = bcom(sumark(left), 0, nil);
575 				tfreenow();
576 				popblock();
577 			}
578 			patch(p, pp);
579 			patch(breaks[labdep], nextinst());
580 			return;
581 		case Oalt:
582 		case Ocase:
583 		case Opick:
584 		case Oexcept:
585 /* need push/pop blocks for alt guards */
586 			pushblock();
587 			if(labdep >= maxlabdep)
588 				fatal("label stack overflow");
589 			breaks[labdep] = nil;
590 			conts[labdep] = &nocont;
591 			labels[labdep] = n->decl;
592 			bcscps[labdep] = curscp();
593 			labdep++;
594 			switch(n->op){
595 			case Oalt:
596 				altcom(n);
597 				break;
598 			case Ocase:
599 			case Opick:
600 				casecom(n);
601 				break;
602 			case Oexcept:
603 				excom(n);
604 				break;
605 			}
606 			labdep--;
607 			patch(breaks[labdep], nextinst());
608 			popblock();
609 			return;
610 		case Obreak:
611 			pushblock();
612 			bccom(n, breaks);
613 			popblock();
614 			break;
615 		case Ocont:
616 			pushblock();
617 			bccom(n, conts);
618 			popblock();
619 			break;
620 		case Oseq:
621 			if(n->left->op == Ocall && trcom(n->left, n->right, 0)){
622 				n = n->right;
623 				if(n == nil || n->op != Oseq)
624 					return;
625 			}
626 			else
627 				scom(n->left);
628 			break;
629 		case Oret:
630 			if(n->left != nil && n->left->op == Ocall && trcom(n->left, nil, 1))
631 				return;
632 			pushblock();
633 			if(n->left != nil){
634 				n->left = simplify(n->left);
635 				sumark(n->left);
636 				ecom(&n->left->src, retalloc(&tret, n->left), n->left);
637 				tfreenow();
638 			}
639 			genrawop(&n->src, IRET, nil, nil, nil);
640 			popblock();
641 			return;
642 		case Oexit:
643 			pushblock();
644 			genrawop(&n->src, IEXIT, nil, nil, nil);
645 			popblock();
646 			return;
647 		case Onothing:
648 			return;
649 		case Ofunc:
650 			fatal("Ofunc");
651 			return;
652 		case Oexstmt:
653 			pushblock();
654 			pp = genrawop(&n->right->src, IEXC0, nil, nil, nil);	/* marker */
655 			p1 = nextinst();
656 			scom(n->left);
657 			p2 = nextinst();
658 			p3 = genrawop(&n->right->src, IJMP, nil, nil, nil);
659 			p = genrawop(&n->right->src, IEXC, nil, nil, nil);	/* marker */
660 			p->d.decl = mkdecl(&n->src, 0, n->right->ty);
661 			zn = nil;
662 			zeroallscopes(n->left, &zn);
663 			scom(n->right);
664 			patch(p3, nextinst());
665 			installexc(n->right, p1, p2, zn);
666 			patch(pp, p);
667 			popblock();
668 			return;
669 		default:
670 			pushblock();
671 			n = simplify(n);
672 			sumark(n);
673 			ecom(&n->src, nil, n);
674 			tfreenow();
675 			popblock();
676 			return;
677 		}
678 	}
679 }
680 
681 /*
682  * compile a break, continue
683  */
684 void
685 bccom(Node *n, Inst **bs)
686 {
687 	Sym *s;
688 	Inst *p;
689 	int i, ok;
690 
691 	s = nil;
692 	if(n->decl != nil)
693 		s = n->decl->sym;
694 	ok = -1;
695 	for(i = 0; i < labdep; i++){
696 		if(bs[i] == &nocont)
697 			continue;
698 		if(s == nil || labels[i] != nil && labels[i]->sym == s)
699 			ok = i;
700 	}
701 	if(ok < 0){
702 		nerror(n, "no appropriate target for %V", n);
703 		return;
704 	}
705 	zeroscopes(bcscps[ok]);
706 	p = genrawop(&n->src, IJMP, nil, nil, nil);
707 	p->branch = bs[ok];
708 	bs[ok] = p;
709 }
710 
711 static int
712 dogoto(Case *c)
713 {
714 	int i, j, k, n, r, q, v;
715 	Label *l, *nl;
716 	Src *src;
717 
718 	l = c->labs;
719 	n = c->nlab;
720 	if(n == 0)
721 		return 0;
722 	r = l[n-1].stop->val - l[0].start->val+1;
723 	if(r >= 3 && r <= 3*n){
724 		if(r != n){
725 			/* remove ranges, fill in gaps */
726 			c->nlab = r;
727 			nl = c->labs = allocmem(r*sizeof(*nl));
728 			k = 0;
729 			v = l[0].start->val-1;
730 			for(i = 0; i < n; i++){
731 				/* p = l[i].start->val; */
732 				q = l[i].stop->val;
733 				src = &l[i].start->src;
734 				for(j = v+1; j <= q; j++){
735 					nl[k] = l[i];
736 					nl[k].start = nl[k].stop = mkconst(src, j);
737 					k++;
738 				}
739 				v = q;
740 			}
741 			if(k != r)
742 				fatal("bad case expansion");
743 		}
744 		l = c->labs;
745 		for(i = 0; i < r; i++)
746 			l[i].inst = nil;
747 		return 1;
748 	}
749 	return 0;
750 }
751 
752 static void
753 fillrange(Case *c, Node *nn, Inst *in)
754 {
755 	int i, j, n, p, q;
756 	Label *l;
757 
758 	l = c->labs;
759 	n = c->nlab;
760 	p = nn->left->val;
761 	q = nn->right->val;
762 	for(i = 0; i < n; i++)
763 		if(l[i].start->val == p)
764 			break;
765 	if(i == n)
766 		fatal("fillrange fails");
767 	for(j = p; j <= q; j++)
768 		l[i++].inst = in;
769 }
770 
771 static int
772 nconstqual(Node *s1)
773 {
774 	Node *s2;
775 	int n;
776 
777 	n = 0;
778 	for(; s1 != nil; s1 = s1->right){
779 		for(s2 = s1->left->left; s2 != nil; s2 = s2->right)
780 			if(s2->left->op == Oconst)
781 				n++;
782 	}
783 	return n;
784 }
785 
786 void
787 casecom(Node *cn)
788 {
789 	Src *src;
790 	Case *c;
791 	Decl *d;
792 	Type *ctype;
793 	Inst *j, *jmps, *wild, *k, *j1, *j2;
794 	Node *n, *p, *left, tmp, nto, tmpc;
795 	Label *labs;
796 	char buf[32];
797 	int i, nlab, op, needwild, igoto;
798 
799 	c = cn->ty->cse;
800 
801 	needwild = cn->op != Opick || nconstqual(cn->right) != cn->left->right->ty->tof->decl->tag;
802 	igoto = cn->left->ty == tint && dogoto(c);
803 	j1 = j2 = nil;
804 
805 	/*
806 	 * generate global which has case labels
807 	 */
808 	if(igoto){
809 		seprint(buf, buf+sizeof(buf), ".g%d", nlabel++);
810 		cn->ty->kind = Tgoto;
811 	}
812 	else
813 		seprint(buf, buf+sizeof(buf), ".c%d", nlabel++);
814 	d = mkids(&cn->src, enter(buf, 0), cn->ty, nil);
815 	d->init = mkdeclname(&cn->src, d);
816 
817 	nto.addable = Rmreg;
818 	nto.left = nil;
819 	nto.right = nil;
820 	nto.op = Oname;
821 	nto.ty = d->ty;
822 	nto.decl = d;
823 
824 	tmp.decl = tmpc.decl = nil;
825 	left = cn->left;
826 	left = simplify(left);
827 	cn->left = left;
828 	sumark(left);
829 	if(debug['c'])
830 		print("case %n\n", left);
831 	ctype = cn->left->ty;
832 	if(left->addable >= Rcant){
833 		if(cn->op == Opick){
834 			ecom(&left->src, nil, left);
835 			tfreenow();
836 			left = mkunary(Oind, dupn(1, &left->src, left->left));
837 			left->ty = tint;
838 			sumark(left);
839 			ctype = tint;
840 		}else{
841 			left = eacom(left, &tmp, nil);
842 			tfreenow();
843 		}
844 	}
845 
846 	labs = c->labs;
847 	nlab = c->nlab;
848 
849 	if(igoto){
850 		if(labs[0].start->val != 0){
851 			talloc(&tmpc, left->ty, nil);
852 			if(left->addable == Radr || left->addable == Rmadr){
853 				genrawop(&left->src, IMOVW, left, nil, &tmpc);
854 				left = &tmpc;
855 			}
856 			genrawop(&left->src, ISUBW, sumark(labs[0].start), left, &tmpc);
857 			left = &tmpc;
858 		}
859 		if(needwild){
860 			j1 = genrawop(&left->src, IBLTW, left, sumark(mkconst(&left->src, 0)), nil);
861 			j2 = genrawop(&left->src, IBGTW, left, sumark(mkconst(&left->src, labs[nlab-1].start->val-labs[0].start->val)), nil);
862 		}
863 		j = nextinst();
864 		genrawop(&left->src, IGOTO, left, nil, &nto);
865 		j->d.reg = IBY2WD;
866 	}
867 	else{
868 		op = ICASE;
869 		if(ctype == tbig)
870 			op = ICASEL;
871 		else if(ctype == tstring)
872 			op = ICASEC;
873 		genrawop(&left->src, op, left, nil, &nto);
874 	}
875 	tfree(&tmp);
876 	tfree(&tmpc);
877 
878 	jmps = nil;
879 	wild = nil;
880 	for(n = cn->right; n != nil; n = n->right){
881 		j = nextinst();
882 		for(p = n->left->left; p != nil; p = p->right){
883 			if(debug['c'])
884 				print("case qualifier %n\n", p->left);
885 			switch(p->left->op){
886 			case Oconst:
887 				labs[findlab(ctype, p->left, labs, nlab)].inst = j;
888 				break;
889 			case Orange:
890 				labs[findlab(ctype, p->left->left, labs, nlab)].inst = j;
891 				if(igoto)
892 					fillrange(c, p->left, j);
893 				break;
894 			case Owild:
895 				if(needwild)
896 					wild = j;
897 /*
898 				else
899 					nwarn(p->left, "default case redundant");
900 */
901 				break;
902 			}
903 		}
904 
905 		if(debug['c'])
906 			print("case body for %V: %n\n", n->left->left, n->left->right);
907 
908 		k = nextinst();
909 		scom(n->left->right);
910 
911 		src = &lastinst->src;
912 		// if(n->left->right == nil || n->left->right->op == Onothing)
913 		if(k == nextinst())
914 			src = &n->left->left->src;
915 		j = genrawop(src, IJMP, nil, nil, nil);
916 		j->branch = jmps;
917 		jmps = j;
918 	}
919 	patch(jmps, nextinst());
920 	if(wild == nil && needwild)
921 		wild = nextinst();
922 
923 	if(igoto){
924 		if(needwild){
925 			patch(j1, wild);
926 			patch(j2, wild);
927 		}
928 		for(i = 0; i < nlab; i++)
929 			if(labs[i].inst == nil)
930 				labs[i].inst = wild;
931 	}
932 
933 	c->iwild = wild;
934 
935 	d->ty->cse = c;
936 	usetype(d->ty);
937 	installids(Dglobal, d);
938 }
939 
940 void
941 altcom(Node *nalt)
942 {
943 	Src altsrc;
944 	Case *c;
945 	Decl *d;
946 	Type *talt;
947 	Node *n, *p, *left, tab, slot, off, add, which, nto, adr;
948 	Node **comm, *op, *tmps;
949 	Inst *j, *tj, *jmps, *me, *wild;
950 	Label *labs;
951 	char buf[32];
952 	int i, is, ir, nlab, nsnd, altop, isptr;
953 	Inst *pp;
954 
955 	talt = nalt->ty;
956 	c = talt->cse;
957 	nlab = c->nlab;
958 	nsnd = c->nsnd;
959 	comm = allocmem(nlab * sizeof *comm);
960 	labs = allocmem(nlab * sizeof *labs);
961 	tmps = allocmem(nlab * sizeof *tmps);
962 	c->labs = labs;
963 
964 	/*
965 	 * built the type of the alt channel table
966 	 * note that we lie to the garbage collector
967 	 * if we know that another reference exists for the channel
968 	 */
969 	is = 0;
970 	ir = nsnd;
971 	i = 0;
972 	for(n = nalt->left; n != nil; n = n->right){
973 		for(p = n->left->right->left; p != nil; p = p->right){
974 			left = simplify(p->left);
975 			p->left = left;
976 			if(left->op == Owild)
977 				continue;
978 			comm[i] = hascomm(left);
979 			left = comm[i]->left;
980 			sumark(left);
981 			isptr = left->addable >= Rcant;
982 			if(comm[i]->op == Osnd)
983 				labs[is++].isptr = isptr;
984 			else
985 				labs[ir++].isptr = isptr;
986 			i++;
987 		}
988 	}
989 
990 	talloc(&which, tint, nil);
991 	talloc(&tab, talt, nil);
992 
993 	/*
994 	 * build the node for the address of each channel,
995 	 * the values to send, and the storage fro values received
996 	 */
997 	off = znode;
998 	off.op = Oconst;
999 	off.ty = tint;
1000 	off.addable = Rconst;
1001 	adr = znode;
1002 	adr.op = Oadr;
1003 	adr.left = &tab;
1004 	adr.ty = tint;
1005 	add = znode;
1006 	add.op = Oadd;
1007 	add.left = &adr;
1008 	add.right = &off;
1009 	add.ty = tint;
1010 	slot = znode;
1011 	slot.op = Oind;
1012 	slot.left = &add;
1013 	sumark(&slot);
1014 
1015 	/*
1016 	 * compile the sending and receiving channels and values
1017 	 */
1018 	is = 2*IBY2WD;
1019 	ir = is + nsnd*2*IBY2WD;
1020 	i = 0;
1021 	for(n = nalt->left; n != nil; n = n->right){
1022 		for(p = n->left->right->left; p != nil; p = p->right){
1023 			if(p->left->op == Owild)
1024 				continue;
1025 
1026 			/*
1027 			 * gen channel
1028 			 */
1029 			op = comm[i];
1030 			if(op->op == Osnd){
1031 				off.val = is;
1032 				is += 2*IBY2WD;
1033 			}else{
1034 				off.val = ir;
1035 				ir += 2*IBY2WD;
1036 			}
1037 			left = op->left;
1038 
1039 			/*
1040 			 * this sleaze is lying to the garbage collector
1041 			 */
1042 			if(left->addable < Rcant)
1043 				genmove(&left->src, Mas, tint, left, &slot);
1044 			else{
1045 				slot.ty = left->ty;
1046 				ecom(&left->src, &slot, left);
1047 				tfreenow();
1048 				slot.ty = nil;
1049 			}
1050 
1051 			/*
1052 			 * gen value
1053 			 */
1054 			off.val += IBY2WD;
1055 			tmps[i].decl = nil;
1056 			p->left = rewritecomm(p->left, comm[i], &tmps[i], &slot);
1057 
1058 			i++;
1059 		}
1060 	}
1061 
1062 	/*
1063 	 * stuff the number of send & receive channels into the table
1064 	 */
1065 	altsrc = nalt->src;
1066 	altsrc.stop.pos += 3;
1067 	off.val = 0;
1068 	genmove(&altsrc, Mas, tint, sumark(mkconst(&altsrc, nsnd)), &slot);
1069 	off.val += IBY2WD;
1070 	genmove(&altsrc, Mas, tint, sumark(mkconst(&altsrc, nlab-nsnd)), &slot);
1071 	off.val += IBY2WD;
1072 
1073 	altop = IALT;
1074 	if(c->wild != nil)
1075 		altop = INBALT;
1076 	pp = genrawop(&altsrc, altop, &tab, nil, &which);
1077 	pp->m.offset = talt->size;	/* for optimizer */
1078 
1079 	seprint(buf, buf+sizeof(buf), ".g%d", nlabel++);
1080 	d = mkids(&nalt->src, enter(buf, 0), mktype(&nalt->src.start, &nalt->src.stop, Tgoto, nil, nil), nil);
1081 	d->ty->cse = c;
1082 	d->init = mkdeclname(&nalt->src, d);
1083 
1084 	nto.addable = Rmreg;
1085 	nto.left = nil;
1086 	nto.right = nil;
1087 	nto.op = Oname;
1088 	nto.decl = d;
1089 	nto.ty = d->ty;
1090 
1091 	me = nextinst();
1092 	genrawop(&altsrc, IGOTO, &which, nil, &nto);
1093 	me->d.reg = IBY2WD;		/* skip the number of cases field */
1094 	tfree(&tab);
1095 	tfree(&which);
1096 
1097 	/*
1098 	 * compile the guard expressions and bodies
1099 	 */
1100 	i = 0;
1101 	is = 0;
1102 	ir = nsnd;
1103 	jmps = nil;
1104 	wild = nil;
1105 	for(n = nalt->left; n != nil; n = n->right){
1106 		j = nil;
1107 		for(p = n->left->right->left; p != nil; p = p->right){
1108 			tj = nextinst();
1109 			if(p->left->op == Owild){
1110 				wild = nextinst();
1111 			}else{
1112 				if(comm[i]->op == Osnd)
1113 					labs[is++].inst = tj;
1114 				else{
1115 					labs[ir++].inst = tj;
1116 					tacquire(&tmps[i]);
1117 				}
1118 				sumark(p->left);
1119 				if(debug['a'])
1120 					print("alt guard %n\n", p->left);
1121 				ecom(&p->left->src, nil, p->left);
1122 				tfree(&tmps[i]);
1123 				tfreenow();
1124 				i++;
1125 			}
1126 			if(p->right != nil){
1127 				tj = genrawop(&lastinst->src, IJMP, nil, nil, nil);
1128 				tj->branch = j;
1129 				j = tj;
1130 			}
1131 		}
1132 
1133 		patch(j, nextinst());
1134 		if(debug['a'])
1135 			print("alt body %n\n", n->left->right);
1136 		scom(n->left);
1137 
1138 		j = genrawop(&lastinst->src, IJMP, nil, nil, nil);
1139 		j->branch = jmps;
1140 		jmps = j;
1141 	}
1142 	patch(jmps, nextinst());
1143 	free(comm);
1144 
1145 	c->iwild = wild;
1146 
1147 	usetype(d->ty);
1148 	installids(Dglobal, d);
1149 }
1150 
1151 void
1152 excom(Node *en)
1153 {
1154 	Src *src;
1155 	Decl *ed;
1156 	Type *qt;
1157 	Case *c;
1158 	Inst *j, *jmps, *wild, *k;
1159 	Node *n, *p;
1160 	Label *labs;
1161 	int nlab;
1162 
1163 	ed = en->left->decl;
1164 	ed->ty = rtexception;
1165 	c = en->ty->cse;
1166 	labs = c->labs;
1167 	nlab = c->nlab;
1168 	jmps = nil;
1169 	wild = nil;
1170 	for(n = en->right; n != nil; n = n->right){
1171 		qt = nil;
1172 		j = nextinst();
1173 		for(p = n->left->left; p != nil; p = p->right){
1174 			switch(p->left->op){
1175 			case Oconst:
1176 				labs[findlab(texception, p->left, labs, nlab)].inst = j;
1177 				break;
1178 			case Owild:
1179 				wild = j;
1180 				break;
1181 			}
1182 			if(qt == nil)
1183 				qt = p->left->ty;
1184 			else if(!tequal(qt, p->left->ty))
1185 				qt = texception;
1186 		}
1187 		if(qt != nil)
1188 			ed->ty = qt;
1189 		k = nextinst();
1190 		scom(n->left->right);
1191 		src = &lastinst->src;
1192 		if(k == nextinst())
1193 			src = &n->left->left->src;
1194 		j = genrawop(src, IJMP, nil, nil, nil);
1195 		j->branch = jmps;
1196 		jmps = j;
1197 	}
1198 	ed->ty = rtexception;
1199 	patch(jmps, nextinst());
1200 	c->iwild = wild;
1201 }
1202 
1203 /*
1204  * rewrite the communication operand
1205  * allocate any temps needed for holding value to send or receive
1206  */
1207 Node*
1208 rewritecomm(Node *n, Node *comm, Node *tmp, Node *slot)
1209 {
1210 	Node *adr;
1211 	Inst *p;
1212 
1213 	if(n == nil)
1214 		return nil;
1215 	adr = nil;
1216 	if(n == comm){
1217 		if(comm->op == Osnd && sumark(n->right)->addable < Rcant)
1218 			adr = n->right;
1219 		else{
1220 			adr = talloc(tmp, n->ty, nil);
1221 			tmp->src = n->src;
1222 			if(comm->op == Osnd){
1223 				ecom(&n->right->src, tmp, n->right);
1224 				tfreenow();
1225 			}
1226 			else
1227 				trelease(tmp);
1228 		}
1229 	}
1230 	if(n->right == comm && n->op == Oas && comm->op == Orcv
1231 	&& sumark(n->left)->addable < Rcant && (n->left->op != Oname || n->left->decl != nildecl))
1232 		adr = n->left;
1233 	if(adr != nil){
1234 		p = genrawop(&comm->left->src, ILEA, adr, nil, slot);
1235 		p->m.offset = adr->ty->size;	/* for optimizer */
1236 		if(comm->op == Osnd)
1237 			p->m.reg = 1;	/* for optimizer */
1238 		return adr;
1239 	}
1240 	n->left = rewritecomm(n->left, comm, tmp, slot);
1241 	n->right = rewritecomm(n->right, comm, tmp, slot);
1242 	return n;
1243 }
1244 
1245 /*
1246  * merge together two sorted lists, yielding a sorted list
1247  */
1248 static Decl*
1249 declmerge(Decl *e, Decl *f)
1250 {
1251 	Decl rock, *d;
1252 	int es, fs, v;
1253 
1254 	d = &rock;
1255 	while(e != nil && f != nil){
1256 		fs = f->ty->size;
1257 		es = e->ty->size;
1258 		/* v = 0; */
1259 		v = (e->link == nil) - (f->link == nil);
1260 		if(v == 0 && (es <= IBY2WD || fs <= IBY2WD))
1261 			v = fs - es;
1262 		if(v == 0)
1263 			v = e->refs - f->refs;
1264 		if(v == 0)
1265 			v = fs - es;
1266 		if(v == 0)
1267 			v = -strcmp(e->sym->name, f->sym->name);
1268 		if(v >= 0){
1269 			d->next = e;
1270 			d = e;
1271 			e = e->next;
1272 			while(e != nil && e->nid == 0){
1273 				d = e;
1274 				e = e->next;
1275 			}
1276 		}else{
1277 			d->next = f;
1278 			d = f;
1279 			f = f->next;
1280 			while(f != nil && f->nid == 0){
1281 				d = f;
1282 				f = f->next;
1283 			}
1284 		}
1285 		/* d = d->next; */
1286 	}
1287 	if(e != nil)
1288 		d->next = e;
1289 	else
1290 		d->next = f;
1291 	return rock.next;
1292 }
1293 
1294 /*
1295  * recursively split lists and remerge them after they are sorted
1296  */
1297 static Decl*
1298 recdeclsort(Decl *d, int n)
1299 {
1300 	Decl *r, *dd;
1301 	int i, m;
1302 
1303 	if(n <= 1)
1304 		return d;
1305 	m = n / 2 - 1;
1306 	dd = d;
1307 	for(i = 0; i < m; i++){
1308 		dd = dd->next;
1309 		while(dd->nid == 0)
1310 			dd = dd->next;
1311 	}
1312 	r = dd->next;
1313 	while(r->nid == 0){
1314 		dd = r;
1315 		r = r->next;
1316 	}
1317 	dd->next = nil;
1318 	return declmerge(recdeclsort(d, n / 2),
1319 			recdeclsort(r, (n + 1) / 2));
1320 }
1321 
1322 /*
1323  * sort the ids by size and number of references
1324  */
1325 Decl*
1326 declsort(Decl *d)
1327 {
1328 	Decl *dd;
1329 	int n;
1330 
1331 	n = 0;
1332 	for(dd = d; dd != nil; dd = dd->next)
1333 		if(dd->nid > 0)
1334 			n++;
1335 	return recdeclsort(d, n);
1336 }
1337 
1338 Src nilsrc;
1339 
1340 /* Do we finally
1341   * 	(a) pick off pointers as in the code below
1342   *	(b) generate a block move from zeroed memory as in tfree() in gen.b in limbo version
1343   *	(c) add a new block zero instruction to dis
1344   *	(d) reorganize the locals/temps in a frame
1345   */
1346 void
1347 zcom1(Node *n, Node **nn)
1348 {
1349 	Type *ty;
1350 	Decl *d;
1351 	Node *e, *dn;
1352 	Src src;
1353 
1354 	ty = n->ty;
1355 	if (!tmustzero(ty))
1356 		return;
1357 	if (n->op == Oname && n->decl->refs == 0)
1358 		return;
1359 	if (nn) {
1360 		if(n->op != Oname)
1361 			nerror(n, "fatal: bad op in zcom1 map");
1362 		n->right = *nn;
1363 		*nn = n;
1364 		return;
1365 	}
1366 	if (debug['Z'])
1367 		print("zcom1 : %n\n", n);
1368 	if (ty->kind == Tadtpick)
1369 		ty = ty->tof;
1370 	if (ty->kind == Ttuple || ty->kind == Tadt) {
1371 		for (d = ty->ids; d != nil; d = d->next) {
1372 			if (tmustzero(d->ty)) {
1373 				if (d->next != nil)
1374 					dn = dupn(0, nil, n);
1375 				else
1376 					dn = n;
1377 				e = mkbin(Odot, dn, mkname(&nilsrc, d->sym));
1378 				e->right->decl = d;
1379 				e->ty = e->right->ty = d->ty;
1380 				zcom1(e, nn);
1381 			}
1382 		}
1383 	}
1384 	else {
1385 		src = n->src;
1386 		n->src = nilsrc;
1387 		e = mkbin(Oas, n, mknil(&nilsrc));
1388 		e->ty = e->right->ty = ty;
1389 /*
1390 		if (debug['Z'])
1391 			print("ecom %n\n", e);
1392 */
1393 		pushblock();
1394 		e = simplify(e);
1395 		sumark(e);
1396 		ecom(&e->src, nil, e);
1397 		popblock();
1398 		n->src = src;
1399 	}
1400 }
1401 
1402 void
1403 zcom0(Decl *id, Node **nn)
1404 {
1405 	Node *e;
1406 
1407 	e = mkname(&nilsrc, id->sym);
1408 	e->decl = id;
1409 	e->ty = id->ty;
1410 	zcom1(e, nn);
1411 }
1412 
1413 /* end of scope */
1414 void
1415 zcom(Node *n, Node **nn)
1416 {
1417 	Decl *ids, *last;
1418 	Node *r, *nt;
1419 
1420 	for ( ; n != nil; n = r) {
1421 		r = n->right;
1422 		n->right = nil;
1423 		switch (n->op) {
1424 			case Ovardecl :
1425 				last = n->left->decl;
1426 				for (ids = n->decl; ids != last->next; ids = ids->next)
1427 					zcom0(ids, nn);
1428 				break;
1429 			case Oname :
1430 				if (n->decl != nildecl)
1431 					zcom1(dupn(0, nil, n), nn);
1432 				break;
1433 			case Otuple :
1434 				for (nt = n->left; nt != nil; nt = nt->right)
1435 					zcom(nt->left, nn);
1436 				break;
1437 			default :
1438 				fatal("bad node in zcom()");
1439 				break;
1440 		}
1441 		n->right = r;
1442 	}
1443 }
1444 
1445 static int
1446 ret(Node *n, int nilret)
1447 {
1448 	if(n == nil)
1449 		return nilret;
1450 	if(n->op == Oseq)
1451 		n = n->left;
1452 	return n->op == Oret && n->left == nil;
1453 }
1454 
1455 /*
1456  * tail-recursive call
1457  */
1458 static int
1459 trcom(Node *e, Node *ne, int nilret)
1460 {
1461 	Decl *d, *id;
1462 	Node *as, *a, *f, *n;
1463 	Inst *p;
1464 
1465 	if(1)
1466 		return 0;	/* TO DO: should we enable this? */
1467 	if(e->op != Ocall || e->left->op != Oname)
1468 		return 0;
1469 	d = e->left->decl;
1470 	if(d != curfn || d->handler || ispoly(d))
1471 		return 0;
1472 	if(!ret(ne, nilret))
1473 		return 0;
1474 	pushblock();
1475 	id = d->ty->ids;
1476 	/* evaluate args in same order as normal calls */
1477 	for(as = e->right; as != nil; as = as->right){
1478 		a = as->left;
1479 		if(!(a->op == Oname && id == a->decl)){
1480 			if(occurs(id, as->right)){
1481 				f = talloc(mkn(0, nil, nil), id->ty, nil);
1482 				f->flags |= TEMP;
1483 			}
1484 			else
1485 				f = mkdeclname(&as->src, id);
1486 			n = mkbin(Oas, f, a);
1487 			n->ty = id->ty;
1488 			scom(n);
1489 			if(f->flags&TEMP)
1490 				as->left = f;
1491 		}
1492 		id = id->next;
1493 	}
1494 	id = d->ty->ids;
1495 	for(as = e->right; as != nil; as = as->right){
1496 		a = as->left;
1497 		if(a->flags&TEMP){
1498 			f = mkdeclname(&as->src, id);
1499 			n = mkbin(Oas, f, a);
1500 			n->ty = id->ty;
1501 			scom(n);
1502 			tfree(a);
1503 		}
1504 		id = id->next;
1505 	}
1506 	p = genrawop(&e->src, IJMP, nil, nil, nil);
1507 	patch(p, d->pc);
1508 	popblock();
1509 	return 1;
1510 }
1511