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