xref: /inferno-os/utils/5c/swt.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
1 #include "gc.h"
2 
3 int
4 swcmp(const void *a1, const void *a2)
5 {
6 	C1 *p1, *p2;
7 
8 	p1 = (C1*)a1;
9 	p2 = (C1*)a2;
10 	if(p1->val < p2->val)
11 		return -1;
12 	return  p1->val > p2->val;
13 }
14 
15 void
16 doswit(Node *n)
17 {
18 	Case *c;
19 	C1 *q, *iq;
20 	long def, nc, i;
21 	Node tn;
22 
23 	def = 0;
24 	nc = 0;
25 	for(c = cases; c->link != C; c = c->link) {
26 		if(c->def) {
27 			if(def)
28 				diag(n, "more than one default in switch");
29 			def = c->label;
30 			continue;
31 		}
32 		nc++;
33 	}
34 
35 	iq = alloc(nc*sizeof(C1));
36 	q = iq;
37 	for(c = cases; c->link != C; c = c->link) {
38 		if(c->def)
39 			continue;
40 		q->label = c->label;
41 		q->val = c->val;
42 		q++;
43 	}
44 	qsort(iq, nc, sizeof(C1), swcmp);
45 	if(debug['W'])
46 		for(i=0; i<nc; i++)
47 			print("case %2ld: = %.8lux\n", i, iq[i].val);
48 	if(def == 0)
49 		def = breakpc;
50 	for(i=0; i<nc-1; i++)
51 		if(iq[i].val == iq[i+1].val)
52 			diag(n, "duplicate cases in switch %ld", iq[i].val);
53 	regalloc(&tn, &regnode, Z);
54 	swit1(iq, nc, def, n, &tn);
55 	regfree(&tn);
56 }
57 
58 void
59 swit1(C1 *q, int nc, long def, Node *n, Node *tn)
60 {
61 	C1 *r;
62 	int i;
63 	long v;
64 	Prog *sp;
65 
66 	if(nc >= 3) {
67 		i = (q+nc-1)->val - (q+0)->val;
68 		if(i > 0 && i < nc*2)
69 			goto direct;
70 	}
71 	if(nc < 5) {
72 		for(i=0; i<nc; i++) {
73 			if(debug['W'])
74 				print("case = %.8lux\n", q->val);
75 			gopcode(OEQ, nodconst(q->val), n, Z);
76 			patch(p, q->label);
77 			q++;
78 		}
79 		gbranch(OGOTO);
80 		patch(p, def);
81 		return;
82 	}
83 
84 	i = nc / 2;
85 	r = q+i;
86 	if(debug['W'])
87 		print("case > %.8lux\n", r->val);
88 	gopcode(OGT, nodconst(r->val), n, Z);
89 	sp = p;
90 	gopcode(OEQ, nodconst(r->val), n, Z);	/* just gen the B.EQ */
91 	patch(p, r->label);
92 	swit1(q, i, def, n, tn);
93 
94 	if(debug['W'])
95 		print("case < %.8lux\n", r->val);
96 	patch(sp, pc);
97 	swit1(r+1, nc-i-1, def, n, tn);
98 	return;
99 
100 direct:
101 	v = q->val;
102 	if(v != 0)
103 		gopcode(OSUB, nodconst(v), Z, n);
104 	gopcode(OCASE, nodconst((q+nc-1)->val - v), n, Z);
105 	patch(p, def);
106 	for(i=0; i<nc; i++) {
107 		if(debug['W'])
108 			print("case = %.8lux\n", q->val);
109 		while(q->val != v) {
110 			nextpc();
111 			p->as = ABCASE;
112 			patch(p, def);
113 			v++;
114 		}
115 		nextpc();
116 		p->as = ABCASE;
117 		patch(p, q->label);
118 		q++;
119 		v++;
120 	}
121 	gbranch(OGOTO);		/* so that regopt() won't be confused */
122 	patch(p, def);
123 }
124 
125 void
126 cas(void)
127 {
128 	Case *c;
129 
130 	c = alloc(sizeof(*c));
131 	c->link = cases;
132 	cases = c;
133 }
134 
135 void
136 bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
137 {
138 	int sh;
139 	long v;
140 	Node *l;
141 
142 	/*
143 	 * n1 gets adjusted/masked value
144 	 * n2 gets address of cell
145 	 * n3 gets contents of cell
146 	 */
147 	l = b->left;
148 	if(n2 != Z) {
149 		regalloc(n1, l, nn);
150 		reglcgen(n2, l, Z);
151 		regalloc(n3, l, Z);
152 		gopcode(OAS, n2, Z, n3);
153 		gopcode(OAS, n3, Z, n1);
154 	} else {
155 		regalloc(n1, l, nn);
156 		cgen(l, n1, 0);
157 	}
158 	if(b->type->shift == 0 && typeu[b->type->etype]) {
159 		v = ~0 + (1L << b->type->nbits);
160 		gopcode(OAND, nodconst(v), Z, n1);
161 	} else {
162 		sh = 32 - b->type->shift - b->type->nbits;
163 		if(sh > 0)
164 			gopcode(OASHL, nodconst(sh), Z, n1);
165 		sh += b->type->shift;
166 		if(sh > 0)
167 			if(typeu[b->type->etype])
168 				gopcode(OLSHR, nodconst(sh), Z, n1);
169 			else
170 				gopcode(OASHR, nodconst(sh), Z, n1);
171 	}
172 }
173 
174 void
175 bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
176 {
177 	long v;
178 	Node nod, *l;
179 	int sh;
180 
181 	/*
182 	 * n1 has adjusted/masked value
183 	 * n2 has address of cell
184 	 * n3 has contents of cell
185 	 */
186 	l = b->left;
187 	regalloc(&nod, l, Z);
188 	v = ~0 + (1L << b->type->nbits);
189 	gopcode(OAND, nodconst(v), Z, n1);
190 	gopcode(OAS, n1, Z, &nod);
191 	if(nn != Z)
192 		gopcode(OAS, n1, Z, nn);
193 	sh = b->type->shift;
194 	if(sh > 0)
195 		gopcode(OASHL, nodconst(sh), Z, &nod);
196 	v <<= sh;
197 	gopcode(OAND, nodconst(~v), Z, n3);
198 	gopcode(OOR, n3, Z, &nod);
199 	gopcode(OAS, &nod, Z, n2);
200 
201 	regfree(&nod);
202 	regfree(n1);
203 	regfree(n2);
204 	regfree(n3);
205 }
206 
207 long
208 outstring(char *s, long n)
209 {
210 	long r;
211 
212 	if(suppress)
213 		return nstring;
214 	r = nstring;
215 	while(n) {
216 		string[mnstring] = *s++;
217 		mnstring++;
218 		nstring++;
219 		if(mnstring >= NSNAME) {
220 			gpseudo(ADATA, symstring, nodconst(0L));
221 			p->from.offset += nstring - NSNAME;
222 			p->reg = NSNAME;
223 			p->to.type = D_SCONST;
224 			memmove(p->to.sval, string, NSNAME);
225 			mnstring = 0;
226 		}
227 		n--;
228 	}
229 	return r;
230 }
231 
232 long
233 outlstring(ushort *s, long n)
234 {
235 	char buf[2];
236 	int c;
237 	long r;
238 
239 	if(suppress)
240 		return nstring;
241 	while(nstring & 1)
242 		outstring("", 1);
243 	r = nstring;
244 	while(n > 0) {
245 		c = *s++;
246 		if(align(0, types[TCHAR], Aarg1)) {
247 			buf[0] = c>>8;
248 			buf[1] = c;
249 		} else {
250 			buf[0] = c;
251 			buf[1] = c>>8;
252 		}
253 		outstring(buf, 2);
254 		n -= sizeof(ushort);
255 	}
256 	return r;
257 }
258 
259 int
260 mulcon(Node *n, Node *nn)
261 {
262 	Node *l, *r, nod1, nod2;
263 	Multab *m;
264 	long v, vs;
265 	int o;
266 	char code[sizeof(m->code)+2], *p;
267 
268 	if(typefd[n->type->etype])
269 		return 0;
270 	l = n->left;
271 	r = n->right;
272 	if(l->op == OCONST) {
273 		l = r;
274 		r = n->left;
275 	}
276 	if(r->op != OCONST)
277 		return 0;
278 	v = convvtox(r->vconst, n->type->etype);
279 	if(v != r->vconst) {
280 		if(debug['M'])
281 			print("%L multiply conv: %lld\n", n->lineno, r->vconst);
282 		return 0;
283 	}
284 	m = mulcon0(v);
285 	if(!m) {
286 		if(debug['M'])
287 			print("%L multiply table: %lld\n", n->lineno, r->vconst);
288 		return 0;
289 	}
290 	if(debug['M'] && debug['v'])
291 		print("%L multiply: %ld\n", n->lineno, v);
292 
293 	memmove(code, m->code, sizeof(m->code));
294 	code[sizeof(m->code)] = 0;
295 
296 	p = code;
297 	if(p[1] == 'i')
298 		p += 2;
299 	regalloc(&nod1, n, nn);
300 	cgen(l, &nod1, 0);
301 	vs = v;
302 	regalloc(&nod2, n, Z);
303 
304 loop:
305 	switch(*p) {
306 	case 0:
307 		regfree(&nod2);
308 		if(vs < 0) {
309 			gopcode(OAS, &nod1, Z, &nod1);
310 			gopcode(OSUB, &nod1, nodconst(0), nn);
311 		} else
312 			gopcode(OAS, &nod1, Z, nn);
313 		regfree(&nod1);
314 		return 1;
315 	case '+':
316 		o = OADD;
317 		goto addsub;
318 	case '-':
319 		o = OSUB;
320 	addsub:	/* number is r,n,l */
321 		v = p[1] - '0';
322 		r = &nod1;
323 		if(v&4)
324 			r = &nod2;
325 		n = &nod1;
326 		if(v&2)
327 			n = &nod2;
328 		l = &nod1;
329 		if(v&1)
330 			l = &nod2;
331 		gopcode(o, l, n, r);
332 		break;
333 	default: /* op is shiftcount, number is r,l */
334 		v = p[1] - '0';
335 		r = &nod1;
336 		if(v&2)
337 			r = &nod2;
338 		l = &nod1;
339 		if(v&1)
340 			l = &nod2;
341 		v = *p - 'a';
342 		if(v < 0 || v >= 32) {
343 			diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
344 			break;
345 		}
346 		gopcode(OASHL, nodconst(v), l, r);
347 		break;
348 	}
349 	p += 2;
350 	goto loop;
351 }
352 
353 void
354 nullwarn(Node *l, Node *r)
355 {
356 	warn(Z, "result of operation not used");
357 	if(l != Z)
358 		cgen(l, Z, 0);
359 	if(r != Z)
360 		cgen(r, Z, 0);
361 }
362 
363 void
364 sextern(Sym *s, Node *a, long o, long w)
365 {
366 	long e, lw;
367 
368 	for(e=0; e<w; e+=NSNAME) {
369 		lw = NSNAME;
370 		if(w-e < lw)
371 			lw = w-e;
372 		gpseudo(ADATA, s, nodconst(0));
373 		p->from.offset += o+e;
374 		p->reg = lw;
375 		p->to.type = D_SCONST;
376 		memmove(p->to.sval, a->cstring+e, lw);
377 	}
378 }
379 
380 void
381 gextern(Sym *s, Node *a, long o, long w)
382 {
383 
384 	if(a->op == OCONST && typev[a->type->etype]) {
385 		if(align(0, types[TCHAR], Aarg1))	/* isbigendian */
386 			gpseudo(ADATA, s, nod32const(a->vconst>>32));
387 		else
388 			gpseudo(ADATA, s, nod32const(a->vconst));
389 		p->from.offset += o;
390 		p->reg = 4;
391 		if(align(0, types[TCHAR], Aarg1))	/* isbigendian */
392 			gpseudo(ADATA, s, nod32const(a->vconst));
393 		else
394 			gpseudo(ADATA, s, nod32const(a->vconst>>32));
395 		p->from.offset += o + 4;
396 		p->reg = 4;
397 		return;
398 	}
399 	gpseudo(ADATA, s, a);
400 	p->from.offset += o;
401 	p->reg = w;
402 	if(p->to.type == D_OREG)
403 		p->to.type = D_CONST;
404 }
405 
406 void	zname(Biobuf*, Sym*, int);
407 char*	zaddr(char*, Adr*, int);
408 void	zwrite(Biobuf*, Prog*, int, int);
409 void	outhist(Biobuf*);
410 
411 void
412 zwrite(Biobuf *b, Prog *p, int sf, int st)
413 {
414 	char bf[100], *bp;
415 
416 	bf[0] = p->as;
417 	bf[1] = p->scond;
418 	bf[2] = p->reg;
419 	bf[3] = p->lineno;
420 	bf[4] = p->lineno>>8;
421 	bf[5] = p->lineno>>16;
422 	bf[6] = p->lineno>>24;
423 	bp = zaddr(bf+7, &p->from, sf);
424 	bp = zaddr(bp, &p->to, st);
425 	Bwrite(b, bf, bp-bf);
426 }
427 
428 void
429 outcode(void)
430 {
431 	struct { Sym *sym; short type; } h[NSYM];
432 	Prog *p;
433 	Sym *s;
434 	int sf, st, t, sym;
435 
436 	if(debug['S']) {
437 		for(p = firstp; p != P; p = p->link)
438 			if(p->as != ADATA && p->as != AGLOBL)
439 				pc--;
440 		for(p = firstp; p != P; p = p->link) {
441 			print("%P\n", p);
442 			if(p->as != ADATA && p->as != AGLOBL)
443 				pc++;
444 		}
445 	}
446 	outhist(&outbuf);
447 	for(sym=0; sym<NSYM; sym++) {
448 		h[sym].sym = S;
449 		h[sym].type = 0;
450 	}
451 	sym = 1;
452 	for(p = firstp; p != P; p = p->link) {
453 	jackpot:
454 		sf = 0;
455 		s = p->from.sym;
456 		while(s != S) {
457 			sf = s->sym;
458 			if(sf < 0 || sf >= NSYM)
459 				sf = 0;
460 			t = p->from.name;
461 			if(h[sf].type == t)
462 			if(h[sf].sym == s)
463 				break;
464 			s->sym = sym;
465 			zname(&outbuf, s, t);
466 			h[sym].sym = s;
467 			h[sym].type = t;
468 			sf = sym;
469 			sym++;
470 			if(sym >= NSYM)
471 				sym = 1;
472 			break;
473 		}
474 		st = 0;
475 		s = p->to.sym;
476 		while(s != S) {
477 			st = s->sym;
478 			if(st < 0 || st >= NSYM)
479 				st = 0;
480 			t = p->to.name;
481 			if(h[st].type == t)
482 			if(h[st].sym == s)
483 				break;
484 			s->sym = sym;
485 			zname(&outbuf, s, t);
486 			h[sym].sym = s;
487 			h[sym].type = t;
488 			st = sym;
489 			sym++;
490 			if(sym >= NSYM)
491 				sym = 1;
492 			if(st == sf)
493 				goto jackpot;
494 			break;
495 		}
496 		zwrite(&outbuf, p, sf, st);
497 	}
498 	firstp = P;
499 	lastp = P;
500 }
501 
502 void
503 outhist(Biobuf *b)
504 {
505 	Hist *h;
506 	char *p, *q, *op, c;
507 	Prog pg;
508 	int n;
509 
510 	pg = zprog;
511 	pg.as = AHISTORY;
512 	c = pathchar();
513 	for(h = hist; h != H; h = h->link) {
514 		p = h->name;
515 		op = 0;
516 		/* on windows skip drive specifier in pathname */
517 		if(systemtype(Windows) && p && p[1] == ':'){
518 			p += 2;
519 			c = *p;
520 		}
521 		if(p && p[0] != c && h->offset == 0 && pathname){
522 			/* on windows skip drive specifier in pathname */
523 			if(systemtype(Windows) && pathname[1] == ':') {
524 				op = p;
525 				p = pathname+2;
526 				c = *p;
527 			} else if(pathname[0] == c){
528 				op = p;
529 				p = pathname;
530 			}
531 		}
532 		while(p) {
533 			q = utfrune(p, c);
534 			if(q) {
535 				n = q-p;
536 				if(n == 0){
537 					n = 1;	/* leading "/" */
538 					*p = '/';	/* don't emit "\" on windows */
539 				}
540 				q++;
541 			} else {
542 				n = strlen(p);
543 				q = 0;
544 			}
545 			if(n) {
546 				Bputc(b, ANAME);
547 				Bputc(b, D_FILE);
548 				Bputc(b, 1);
549 				Bputc(b, '<');
550 				Bwrite(b, p, n);
551 				Bputc(b, 0);
552 			}
553 			p = q;
554 			if(p == 0 && op) {
555 				p = op;
556 				op = 0;
557 			}
558 		}
559 		pg.lineno = h->line;
560 		pg.to.type = zprog.to.type;
561 		pg.to.offset = h->offset;
562 		if(h->offset)
563 			pg.to.type = D_CONST;
564 
565 		zwrite(b, &pg, 0, 0);
566 	}
567 }
568 
569 void
570 zname(Biobuf *b, Sym *s, int t)
571 {
572 	char *n, bf[7];
573 	ulong sig;
574 
575 	n = s->name;
576 	if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
577 		sig = sign(s);
578 		bf[0] = ASIGNAME;
579 		bf[1] = sig;
580 		bf[2] = sig>>8;
581 		bf[3] = sig>>16;
582 		bf[4] = sig>>24;
583 		bf[5] = t;
584 		bf[6] = s->sym;
585 		Bwrite(b, bf, 7);
586 		s->sig = SIGDONE;
587 	}
588 	else{
589 		bf[0] = ANAME;
590 		bf[1] = t;	/* type */
591 		bf[2] = s->sym;	/* sym */
592 		Bwrite(b, bf, 3);
593 	}
594 	Bwrite(b, n, strlen(n)+1);
595 }
596 
597 char*
598 zaddr(char *bp, Adr *a, int s)
599 {
600 	long l;
601 	Ieee e;
602 
603 	bp[0] = a->type;
604 	bp[1] = a->reg;
605 	bp[2] = s;
606 	bp[3] = a->name;
607 	bp += 4;
608 	switch(a->type) {
609 	default:
610 		diag(Z, "unknown type %d in zaddr", a->type);
611 
612 	case D_NONE:
613 	case D_REG:
614 	case D_FREG:
615 	case D_PSR:
616 		break;
617 
618 	case D_OREG:
619 	case D_CONST:
620 	case D_BRANCH:
621 	case D_SHIFT:
622 		l = a->offset;
623 		bp[0] = l;
624 		bp[1] = l>>8;
625 		bp[2] = l>>16;
626 		bp[3] = l>>24;
627 		bp += 4;
628 		break;
629 
630 	case D_SCONST:
631 		memmove(bp, a->sval, NSNAME);
632 		bp += NSNAME;
633 		break;
634 
635 	case D_FCONST:
636 		ieeedtod(&e, a->dval);
637 		l = e.l;
638 		bp[0] = l;
639 		bp[1] = l>>8;
640 		bp[2] = l>>16;
641 		bp[3] = l>>24;
642 		bp += 4;
643 		l = e.h;
644 		bp[0] = l;
645 		bp[1] = l>>8;
646 		bp[2] = l>>16;
647 		bp[3] = l>>24;
648 		bp += 4;
649 		break;
650 	}
651 	return bp;
652 }
653 
654 void
655 ieeedtod(Ieee *ieee, double native)
656 {
657 	double fr, ho, f;
658 	int exp;
659 
660 	if(native < 0) {
661 		ieeedtod(ieee, -native);
662 		ieee->h |= 0x80000000L;
663 		return;
664 	}
665 	if(native == 0) {
666 		ieee->l = 0;
667 		ieee->h = 0;
668 		return;
669 	}
670 	fr = frexp(native, &exp);
671 	f = 2097152L;		/* shouldnt use fp constants here */
672 	fr = modf(fr*f, &ho);
673 	ieee->h = ho;
674 	ieee->h &= 0xfffffL;
675 	ieee->h |= (exp+1022L) << 20;
676 	f = 65536L;
677 	fr = modf(fr*f, &ho);
678 	ieee->l = ho;
679 	ieee->l <<= 16;
680 	ieee->l |= (long)(fr*f);
681 }
682 
683 long
684 align(long i, Type *t, int op)
685 {
686 	long o;
687 	Type *v;
688 	int w;
689 
690 	o = i;
691 	w = 1;
692 	switch(op) {
693 	default:
694 		diag(Z, "unknown align opcode %d", op);
695 		break;
696 
697 	case Asu2:	/* padding at end of a struct */
698 		w = SZ_LONG;
699 		if(packflg)
700 			w = packflg;
701 		break;
702 
703 	case Ael1:	/* initial allign of struct element */
704 		for(v=t; v->etype==TARRAY; v=v->link)
705 			;
706 		w = ewidth[v->etype];
707 		if(w <= 0 || w >= SZ_LONG)
708 			w = SZ_LONG;
709 		if(packflg)
710 			w = packflg;
711 		break;
712 
713 	case Ael2:	/* width of a struct element */
714 		o += t->width;
715 		break;
716 
717 	case Aarg0:	/* initial passbyptr argument in arg list */
718 		if(typesuv[t->etype]) {
719 			o = align(o, types[TIND], Aarg1);
720 			o = align(o, types[TIND], Aarg2);
721 		}
722 		break;
723 
724 	case Aarg1:	/* initial allign of parameter */
725 		w = ewidth[t->etype];
726 		if(w <= 0 || w >= SZ_LONG) {
727 			w = SZ_LONG;
728 			break;
729 		}
730 		w = 1;		/* little endian no adjustment */
731 		break;
732 
733 	case Aarg2:	/* width of a parameter */
734 		o += t->width;
735 		w = SZ_LONG;
736 		break;
737 
738 	case Aaut3:	/* total allign of automatic */
739 		o = align(o, t, Ael2);
740 		o = align(o, t, Ael1);
741 		w = SZ_LONG;	/* because of a pun in cc/dcl.c:contig() */
742 		break;
743 	}
744 	o = round(o, w);
745 	if(debug['A'])
746 		print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
747 	return o;
748 }
749 
750 long
751 maxround(long max, long v)
752 {
753 	v = round(v, SZ_LONG);
754 	if(v > max)
755 		return v;
756 	return max;
757 }
758