xref: /inferno-os/utils/qc/swt.c (revision d3641b487cf5cdc46e9b537d30eb37736e5c7b1a)
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 gextern(Sym *s, Node *a, long o, long w)
244 {
245 	if(a->op == OCONST && typev[a->type->etype]) {
246 		if(align(0, types[TCHAR], Aarg1))	/* isbigendian */
247 			gpseudo(ADATA, s, nod32const(a->vconst>>32));
248 		else
249 			gpseudo(ADATA, s, nod32const(a->vconst));
250 		p->from.offset += o;
251 		p->reg = 4;
252 		if(align(0, types[TCHAR], Aarg1))	/* isbigendian */
253 			gpseudo(ADATA, s, nod32const(a->vconst));
254 		else
255 			gpseudo(ADATA, s, nod32const(a->vconst>>32));
256 		p->from.offset += o + 4;
257 		p->reg = 4;
258 		return;
259 	}
260 	gpseudo(ADATA, s, a);
261 	p->from.offset += o;
262 	p->reg = w;
263 	if(p->to.type == D_OREG)
264 		p->to.type = D_CONST;
265 }
266 
267 void	zname(Biobuf*, Sym*, int);
268 char*	zaddr(char*, Adr*, int);
269 void	zwrite(Biobuf*, Prog*, int, int);
270 void	outhist(Biobuf*);
271 
272 void
273 outcode(void)
274 {
275 	struct { Sym *sym; short type; } h[NSYM];
276 	Prog *p;
277 	Sym *s;
278 	int sf, st, t, sym;
279 
280 	if(debug['S']) {
281 		for(p = firstp; p != P; p = p->link)
282 			if(p->as != ADATA && p->as != AGLOBL)
283 				pc--;
284 		for(p = firstp; p != P; p = p->link) {
285 			print("%P\n", p);
286 			if(p->as != ADATA && p->as != AGLOBL)
287 				pc++;
288 		}
289 	}
290 	outhist(&outbuf);
291 	for(sym=0; sym<NSYM; sym++) {
292 		h[sym].sym = S;
293 		h[sym].type = 0;
294 	}
295 	sym = 1;
296 	for(p = firstp; p != P; p = p->link) {
297 	jackpot:
298 		sf = 0;
299 		s = p->from.sym;
300 		while(s != S) {
301 			sf = s->sym;
302 			if(sf < 0 || sf >= NSYM)
303 				sf = 0;
304 			t = p->from.name;
305 			if(h[sf].type == t)
306 			if(h[sf].sym == s)
307 				break;
308 			s->sym = sym;
309 			zname(&outbuf, s, t);
310 			h[sym].sym = s;
311 			h[sym].type = t;
312 			sf = sym;
313 			sym++;
314 			if(sym >= NSYM)
315 				sym = 1;
316 			break;
317 		}
318 		st = 0;
319 		s = p->to.sym;
320 		while(s != S) {
321 			st = s->sym;
322 			if(st < 0 || st >= NSYM)
323 				st = 0;
324 			t = p->to.name;
325 			if(h[st].type == t)
326 			if(h[st].sym == s)
327 				break;
328 			s->sym = sym;
329 			zname(&outbuf, s, t);
330 			h[sym].sym = s;
331 			h[sym].type = t;
332 			st = sym;
333 			sym++;
334 			if(sym >= NSYM)
335 				sym = 1;
336 			if(st == sf)
337 				goto jackpot;
338 			break;
339 		}
340 		zwrite(&outbuf, p, sf, st);
341 	}
342 	firstp = P;
343 	lastp = P;
344 }
345 
346 void
347 zwrite(Biobuf *b, Prog *p, int sf, int st)
348 {
349 	char bf[100], *bp;
350 	long l;
351 
352 	bf[0] = p->as;
353 	bf[1] = p->as>>8;
354 	bf[2] = p->reg;
355 	if(p->from3.type != D_NONE)
356 		bf[2] |= 0x40;
357 	l = p->lineno;
358 	bf[3] = l;
359 	bf[4] = l>>8;
360 	bf[5] = l>>16;
361 	bf[6] = l>>24;
362 	bp = zaddr(bf+7, &p->from, sf);
363 	if(bf[2] & 0x40)
364 		bp = zaddr(bp, &p->from3, 0);
365 	bp = zaddr(bp, &p->to, st);
366 	Bwrite(b, bf, bp-bf);
367 }
368 
369 void
370 outhist(Biobuf *b)
371 {
372 	Hist *h;
373 	char *p, *q, *op, c;
374 	Prog pg;
375 	int n;
376 
377 	pg = zprog;
378 	pg.as = AHISTORY;
379 	c = pathchar();
380 	for(h = hist; h != H; h = h->link) {
381 		p = h->name;
382 		op = 0;
383 		/* on windows skip drive specifier in pathname */
384 		if(systemtype(Windows) && p && p[1] == ':'){
385 			p += 2;
386 			c = *p;
387 		}
388 		if(p && p[0] != c && h->offset == 0 && pathname){
389 			/* on windows skip drive specifier in pathname */
390 			if(systemtype(Windows) && pathname[1] == ':') {
391 				op = p;
392 				p = pathname+2;
393 				c = *p;
394 			} else if(pathname[0] == c){
395 				op = p;
396 				p = pathname;
397 			}
398 		}
399 		while(p) {
400 			q = utfrune(p, c);
401 			if(q) {
402 				n = q-p;
403 				if(n == 0){
404 					n = 1;	/* leading "/" */
405 					*p = '/';	/* don't emit "\" on windows */
406 				}
407 				q++;
408 			} else {
409 				n = strlen(p);
410 				q = 0;
411 			}
412 			if(n) {
413 				Bputc(b, ANAME);
414 				Bputc(b, ANAME>>8);
415 				Bputc(b, D_FILE);
416 				Bputc(b, 1);
417 				Bputc(b, '<');
418 				Bwrite(b, p, n);
419 				Bputc(b, 0);
420 			}
421 			p = q;
422 			if(p == 0 && op) {
423 				p = op;
424 				op = 0;
425 			}
426 		}
427 		pg.lineno = h->line;
428 		pg.to.type = zprog.to.type;
429 		pg.to.offset = h->offset;
430 		if(h->offset)
431 			pg.to.type = D_CONST;
432 
433 		zwrite(b, &pg, 0, 0);
434 	}
435 }
436 
437 void
438 zname(Biobuf *b, Sym *s, int t)
439 {
440 	char *n, bf[8];
441 	ulong sig;
442 
443 	n = s->name;
444 	if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
445 		sig = sign(s);
446 		bf[0] = ASIGNAME;
447 		bf[1] = ASIGNAME>>8;
448 		bf[2] = sig;
449 		bf[3] = sig>>8;
450 		bf[4] = sig>>16;
451 		bf[5] = sig>>24;
452 		bf[6] = t;
453 		bf[7] = s->sym;
454 		Bwrite(b, bf, 8);
455 		s->sig = SIGDONE;
456 	}
457 	else{
458 		bf[0] = ANAME;
459 		bf[1] = ANAME>>8;
460 		bf[2] = t;	/* type */
461 		bf[3] = s->sym;	/* sym */
462 		Bwrite(b, bf, 4);
463 	}
464 	Bwrite(b, n, strlen(n)+1);
465 }
466 
467 char*
468 zaddr(char *bp, Adr *a, int s)
469 {
470 	long l;
471 	Ieee e;
472 
473 	bp[0] = a->type;
474 	bp[1] = a->reg;
475 	bp[2] = s;
476 	bp[3] = a->name;
477 	bp += 4;
478 	switch(a->type) {
479 	default:
480 		diag(Z, "unknown type %d in zaddr", a->type);
481 
482 	case D_NONE:
483 	case D_REG:
484 	case D_FREG:
485 	case D_CREG:
486 		break;
487 
488 	case D_OREG:
489 	case D_CONST:
490 	case D_BRANCH:
491 		l = a->offset;
492 		bp[0] = l;
493 		bp[1] = l>>8;
494 		bp[2] = l>>16;
495 		bp[3] = l>>24;
496 		bp += 4;
497 		break;
498 
499 	case D_SCONST:
500 		memmove(bp, a->sval, NSNAME);
501 		bp += NSNAME;
502 		break;
503 
504 	case D_FCONST:
505 		ieeedtod(&e, a->dval);
506 		l = e.l;
507 		bp[0] = l;
508 		bp[1] = l>>8;
509 		bp[2] = l>>16;
510 		bp[3] = l>>24;
511 		bp += 4;
512 		l = e.h;
513 		bp[0] = l;
514 		bp[1] = l>>8;
515 		bp[2] = l>>16;
516 		bp[3] = l>>24;
517 		bp += 4;
518 		break;
519 	}
520 	return bp;
521 }
522 
523 static int
524 doubled(Type *t)
525 {
526 	Type *v;
527 
528 	if(debug['4'])
529 		return 0;
530 	if(t->nbits != 0)
531 		return 0;
532 	switch(t->etype){
533 	case TDOUBLE:
534 		return 1;
535 
536 	case TARRAY:
537 		for(v=t; v->etype==TARRAY; v=v->link)
538 			;
539 		return v->etype == TDOUBLE;
540 
541 	case TSTRUCT:
542 	case TUNION:
543 		for(v = t->link; v != T; v = v->down)
544 			if(doubled(v))
545 				return 1;
546 		break;
547 	}
548 	return 0;
549 }
550 
551 long
552 align(long i, Type *t, int op)
553 {
554 	long o;
555 	Type *v;
556 	int w, pc;
557 
558 	o = i;
559 	w = 1;
560 	pc = 0;
561 	switch(op) {
562 	default:
563 		diag(Z, "unknown align opcode %d", op);
564 		break;
565 
566 	case Asu2:	/* padding at end of a struct */
567 		w = doubled(t)? SZ_DOUBLE: SZ_LONG;
568 		if(packflg)
569 			w = packflg;
570 		break;
571 
572 	case Ael1:	/* initial align of struct element (also automatic) */
573 		for(v=t; v->etype==TARRAY; v=v->link)
574 			;
575 		w = ewidth[v->etype];
576 		if(w <= 0 || w >= SZ_LONG){
577 			if(doubled(v)){
578 				w = SZ_DOUBLE;
579 				doubleflag = 1;
580 			}else
581 				w = SZ_LONG;
582 		}
583 		if(packflg)
584 			w = packflg;
585 		break;
586 
587 	case Ael2:	/* width of a struct element */
588 		o += t->width;
589 		break;
590 
591 	case Aarg0:	/* initial passbyptr argument in arg list */
592 		if(typesuv[t->etype]) {
593 			o = align(o, types[TIND], Aarg1);
594 			o = align(o, types[TIND], Aarg2);
595 		}
596 		break;
597 
598 	case Aarg1:	/* initial align of parameter */
599 		w = ewidth[t->etype];
600 		if(w <= 0 || w >= SZ_LONG) {
601 			if(doubled(t)){
602 				w = SZ_DOUBLE;
603 				pc = SZ_LONG;		/* alignment must account for pc */
604 				hasdoubled = 1;
605 			}else
606 				w = SZ_LONG;
607 			break;
608 		}
609 		o += SZ_LONG - w;	/* big endian adjustment */
610 		w = 1;
611 		break;
612 
613 	case Aarg2:	/* width of a parameter */
614 		o += t->width;
615 		w = SZ_LONG;
616 		if(doubled(t)){
617 			pc = SZ_LONG;
618 			hasdoubled = 1;
619 		}
620 		break;
621 
622 	case Aaut3:	/* total align of automatic */
623 		doubleflag = 0;
624 		o = align(o, t, Ael1);
625 		o = align(o, t, Ael2);
626 		hasdoubled |= doubleflag;
627 		break;
628 	}
629 	o = round(o+pc, w)-pc;
630 	if(debug['A'])
631 		print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
632 	return o;
633 }
634 
635 long
636 maxround(long max, long v)
637 {
638 	int w;
639 
640 	w = SZ_LONG;
641 	if((debug['8'] || hasdoubled) && !debug['4'])
642 		w = SZ_DOUBLE;
643 	v = round(v, w);
644 	if(v > max)
645 		return v;
646 	return max;
647 }
648