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