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