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