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