xref: /plan9/sys/src/cmd/vc/swt.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
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*, char*, int, 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 			zname(&outbuf, s->name, t, sym);
427 			s->sym = sym;
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 			zname(&outbuf, s->name, t, sym);
447 			s->sym = sym;
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 		if(p && p[0] != c && h->offset == 0 && pathname){
479 			/* on windows skip drive specifier in pathname */
480 			if(systemtype(Windows) && pathname[2] == c) {
481 				op = p;
482 				p = pathname+2;
483 				*p = '/';
484 			} else if(pathname[0] == c){
485 				op = p;
486 				p = pathname;
487 			}
488 		}
489 		while(p) {
490 			q = utfrune(p, c);
491 			if(q) {
492 				n = q-p;
493 				if(n == 0)
494 					n = 1;	/* leading "/" */
495 				q++;
496 			} else {
497 				n = strlen(p);
498 				q = 0;
499 			}
500 			if(n) {
501 				Bputc(b, ANAME);
502 				Bputc(b, D_FILE);
503 				Bputc(b, 1);
504 				Bputc(b, '<');
505 				Bwrite(b, p, n);
506 				Bputc(b, 0);
507 			}
508 			p = q;
509 			if(p == 0 && op) {
510 				p = op;
511 				op = 0;
512 			}
513 		}
514 		pg.lineno = h->line;
515 		pg.to.type = zprog.to.type;
516 		pg.to.offset = h->offset;
517 		if(h->offset)
518 			pg.to.type = D_CONST;
519 
520 		zwrite(b, &pg, 0, 0);
521 	}
522 }
523 
524 void
525 zname(Biobuf *b, char *n, int t, int s)
526 {
527 	char bf[3];
528 
529 	bf[0] = ANAME;
530 	bf[1] = t;	/* type */
531 	bf[2] = s;	/* sym */
532 	Bwrite(b, bf, 3);
533 	Bwrite(b, n, strlen(n)+1);
534 }
535 
536 char*
537 zaddr(char *bp, Adr *a, int s)
538 {
539 	long l;
540 	Ieee e;
541 
542 	bp[0] = a->type;
543 	bp[1] = a->reg;
544 	bp[2] = s;
545 	bp[3] = a->name;
546 	bp += 4;
547 	switch(a->type) {
548 	default:
549 		diag(Z, "unknown type %d in zaddr", a->type);
550 
551 	case D_NONE:
552 	case D_REG:
553 	case D_FREG:
554 	case D_MREG:
555 	case D_FCREG:
556 	case D_LO:
557 	case D_HI:
558 		break;
559 
560 	case D_OREG:
561 	case D_CONST:
562 	case D_BRANCH:
563 		l = a->offset;
564 		bp[0] = l;
565 		bp[1] = l>>8;
566 		bp[2] = l>>16;
567 		bp[3] = l>>24;
568 		bp += 4;
569 		break;
570 
571 	case D_SCONST:
572 		memmove(bp, a->sval, NSNAME);
573 		bp += NSNAME;
574 		break;
575 
576 	case D_FCONST:
577 		ieeedtod(&e, a->dval);
578 		l = e.l;
579 		bp[0] = l;
580 		bp[1] = l>>8;
581 		bp[2] = l>>16;
582 		bp[3] = l>>24;
583 		bp += 4;
584 		l = e.h;
585 		bp[0] = l;
586 		bp[1] = l>>8;
587 		bp[2] = l>>16;
588 		bp[3] = l>>24;
589 		bp += 4;
590 		break;
591 	}
592 	return bp;
593 }
594 
595 void
596 ieeedtod(Ieee *ieee, double native)
597 {
598 	double fr, ho, f;
599 	int exp;
600 
601 	if(native < 0) {
602 		ieeedtod(ieee, -native);
603 		ieee->h |= 0x80000000L;
604 		return;
605 	}
606 	if(native == 0) {
607 		ieee->l = 0;
608 		ieee->h = 0;
609 		return;
610 	}
611 	fr = frexp(native, &exp);
612 	f = 2097152L;		/* shouldnt use fp constants here */
613 	fr = modf(fr*f, &ho);
614 	ieee->h = ho;
615 	ieee->h &= 0xfffffL;
616 	ieee->h |= (exp+1022L) << 20;
617 	f = 65536L;
618 	fr = modf(fr*f, &ho);
619 	ieee->l = ho;
620 	ieee->l <<= 16;
621 	ieee->l |= (long)(fr*f);
622 }
623 
624 long
625 align(long i, Type *t, int op)
626 {
627 	long o;
628 	Type *v;
629 	int w;
630 
631 	o = i;
632 	w = 1;
633 	switch(op) {
634 	default:
635 		diag(Z, "unknown align opcode %d", op);
636 		break;
637 
638 	case Asu2:	/* padding at end of a struct */
639 		w = SZ_LONG;
640 		break;
641 
642 	case Ael1:	/* initial allign of struct element */
643 		for(v=t; v->etype==TARRAY; v=v->link)
644 			;
645 		w = ewidth[v->etype];
646 		if(w <= 0 || w >= SZ_LONG)
647 			w = SZ_LONG;
648 		break;
649 
650 	case Ael2:	/* width of a struct element */
651 		o += t->width;
652 		break;
653 
654 	case Aarg0:	/* initial passbyptr argument in arg list */
655 		if(typesuv[t->etype]) {
656 			o = align(o, types[TIND], Aarg1);
657 			o = align(o, types[TIND], Aarg2);
658 		}
659 		break;
660 
661 	case Aarg1:	/* initial allign of parameter */
662 		w = ewidth[t->etype];
663 		if(w <= 0 || w >= SZ_LONG) {
664 			w = SZ_LONG;
665 			break;
666 		}
667 		o += SZ_LONG - w;	/* big endian adjustment */
668 		w = 1;
669 		break;
670 
671 	case Aarg2:	/* width of a parameter */
672 		o += t->width;
673 		w = SZ_LONG;
674 		break;
675 
676 	case Aaut3:	/* total allign of automatic */
677 		o = align(o, t, Ael1);
678 		o = align(o, t, Ael2);
679 		break;
680 	}
681 	o = round(o, w);
682 	if(debug['A'])
683 		print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
684 	return o;
685 }
686 
687 long
688 maxround(long max, long v)
689 {
690 	v += SZ_LONG-1;
691 	if(v > max)
692 		max = round(v, SZ_LONG);
693 	return max;
694 }
695