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