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