xref: /inferno-os/utils/vl/span.c (revision 1981fff245dfce579ef416fa767eb69d462039e9)
1 #include	"l.h"
2 
3 void
4 pagebug(Prog *p)
5 {
6 	Prog *q;
7 
8 	switch(p->as) {
9 	case ABGEZAL:
10 	case ABLTZAL:
11 	case AJAL:
12 	case ABEQ:
13 	case ABGEZ:
14 	case ABGTZ:
15 	case ABLEZ:
16 	case ABLTZ:
17 	case ABNE:
18 	case ABFPT:
19 	case ABFPF:
20 	case AJMP:
21 		q = prg();
22 		*q = *p;
23 		p->link = q;
24 		p->as = ANOR;
25 		p->optab = 0;
26 		p->from = zprg.from;
27 		p->from.type = D_REG;
28 		p->from.reg = REGZERO;
29 		p->to = p->from;
30 	}
31 }
32 
33 void
34 span(void)
35 {
36 	Prog *p, *q;
37 	Sym *setext, *s;
38 	Optab *o;
39 	int m, bflag, i;
40 	long c, otxt, v;
41 
42 	if(debug['v'])
43 		Bprint(&bso, "%5.2f span\n", cputime());
44 	Bflush(&bso);
45 
46 	bflag = 0;
47 	c = INITTEXT;
48 	otxt = c;
49 	for(p = firstp; p != P; p = p->link) {
50 		/* bug in early 4000 chips delayslot on page boundary */
51 		if((c&(0x1000-1)) == 0xffc)
52 			pagebug(p);
53 		p->pc = c;
54 		o = oplook(p);
55 		m = o->size;
56 		if(m == 0) {
57 			if(p->as == ATEXT) {
58 				curtext = p;
59 				autosize = p->to.offset + 4;
60 				if(p->from.sym != S)
61 					p->from.sym->value = c;
62 				/* need passes to resolve branches */
63 				if(c-otxt >= 1L<<17)
64 					bflag = 1;
65 				otxt = c;
66 				continue;
67 			}
68 			diag("zero-width instruction\n%P", p);
69 			continue;
70 		}
71 		c += m;
72 	}
73 
74 	/*
75 	 * if any procedure is large enough to
76 	 * generate a large SBRA branch, then
77 	 * generate extra passes putting branches
78 	 * around jmps to fix. this is rare.
79 	 */
80 	while(bflag) {
81 		if(debug['v'])
82 			Bprint(&bso, "%5.2f span1\n", cputime());
83 		bflag = 0;
84 		c = INITTEXT;
85 		for(p = firstp; p != P; p = p->link) {
86 			/* bug in early 4000 chips delayslot on page boundary */
87 			if((c&(0x1000-1)) == 0xffc)
88 				pagebug(p);
89 			p->pc = c;
90 			o = oplook(p);
91 			if(o->type == 6 && p->cond) {
92 				otxt = p->cond->pc - c;
93 				if(otxt < 0)
94 					otxt = -otxt;
95 				if(otxt >= (1L<<17) - 10) {
96 					q = prg();
97 					q->link = p->link;
98 					p->link = q;
99 					q->as = AJMP;
100 					q->to.type = D_BRANCH;
101 					q->cond = p->cond;
102 					p->cond = q;
103 					q = prg();
104 					q->link = p->link;
105 					p->link = q;
106 					q->as = AJMP;
107 					q->to.type = D_BRANCH;
108 					q->cond = q->link->link;
109 					addnop(p->link);
110 					addnop(p);
111 					bflag = 1;
112 				}
113 			}
114 			m = o->size;
115 			if(m == 0) {
116 				if(p->as == ATEXT) {
117 					curtext = p;
118 					autosize = p->to.offset + 4;
119 					if(p->from.sym != S)
120 						p->from.sym->value = c;
121 					continue;
122 				}
123 				diag("zero-width instruction\n%P", p);
124 				continue;
125 			}
126 			c += m;
127 		}
128 	}
129 
130 	if(debug['t']) {
131 		/*
132 		 * add strings to text segment
133 		 */
134 		c = rnd(c, 8);
135 		for(i=0; i<NHASH; i++)
136 		for(s = hash[i]; s != S; s = s->link) {
137 			if(s->type != SSTRING)
138 				continue;
139 			v = s->value;
140 			while(v & 3)
141 				v++;
142 			s->value = c;
143 			c += v;
144 		}
145 	}
146 
147 	c = rnd(c, 8);
148 
149 	setext = lookup("etext", 0);
150 	if(setext != S) {
151 		setext->value = c;
152 		textsize = c - INITTEXT;
153 	}
154 	if(INITRND)
155 		INITDAT = rnd(c, INITRND);
156 	if(debug['v'])
157 		Bprint(&bso, "tsize = %lux\n", textsize);
158 	Bflush(&bso);
159 }
160 
161 void
162 xdefine(char *p, int t, long v)
163 {
164 	Sym *s;
165 
166 	s = lookup(p, 0);
167 	if(s->type == 0 || s->type == SXREF) {
168 		s->type = t;
169 		s->value = v;
170 	}
171 }
172 
173 long
174 regoff(Adr *a)
175 {
176 
177 	instoffset = 0;
178 	aclass(a);
179 	return instoffset;
180 }
181 
182 int
183 aclass(Adr *a)
184 {
185 	Sym *s;
186 	int t;
187 
188 	switch(a->type) {
189 	case D_NONE:
190 		return C_NONE;
191 
192 	case D_REG:
193 		return C_REG;
194 
195 	case D_FREG:
196 		return C_FREG;
197 
198 	case D_FCREG:
199 		return C_FCREG;
200 
201 	case D_MREG:
202 		return C_MREG;
203 
204 	case D_OREG:
205 		switch(a->name) {
206 		case D_EXTERN:
207 		case D_STATIC:
208 			if(a->sym == 0 || a->sym->name == 0) {
209 				print("null sym external\n");
210 				print("%D\n", a);
211 				return C_GOK;
212 			}
213 			t = a->sym->type;
214 			if(t == 0 || t == SXREF) {
215 				diag("undefined external: %s in %s",
216 					a->sym->name, TNAME);
217 				a->sym->type = SDATA;
218 			}
219 			instoffset = a->sym->value + a->offset - BIG;
220 			if(instoffset >= -BIG && instoffset < BIG)
221 				return C_SEXT;
222 			return C_LEXT;
223 		case D_AUTO:
224 			instoffset = autosize + a->offset;
225 			if(instoffset >= -BIG && instoffset < BIG)
226 				return C_SAUTO;
227 			return C_LAUTO;
228 
229 		case D_PARAM:
230 			instoffset = autosize + a->offset + 4L;
231 			if(instoffset >= -BIG && instoffset < BIG)
232 				return C_SAUTO;
233 			return C_LAUTO;
234 		case D_NONE:
235 			instoffset = a->offset;
236 			if(instoffset == 0)
237 				return C_ZOREG;
238 			if(instoffset >= -BIG && instoffset < BIG)
239 				return C_SOREG;
240 			return C_LOREG;
241 		}
242 		return C_GOK;
243 
244 	case D_HI:
245 		return C_LO;
246 	case D_LO:
247 		return C_HI;
248 
249 	case D_OCONST:
250 		switch(a->name) {
251 		case D_EXTERN:
252 		case D_STATIC:
253 			s = a->sym;
254 			t = s->type;
255 			if(t == 0 || t == SXREF) {
256 				diag("undefined external: %s in %s",
257 					s->name, TNAME);
258 				s->type = SDATA;
259 			}
260 			instoffset = s->value + a->offset + INITDAT;
261 			if(s->type == STEXT || s->type == SLEAF)
262 				instoffset = s->value + a->offset;
263 			return C_LCON;
264 		}
265 		return C_GOK;
266 
267 	case D_CONST:
268 		switch(a->name) {
269 
270 		case D_NONE:
271 			instoffset = a->offset;
272 		consize:
273 			if(instoffset > 0) {
274 				if(instoffset <= 0x7fff)
275 					return C_SCON;
276 				if(instoffset <= 0xffff)
277 					return C_ANDCON;
278 				if((instoffset & 0xffff) == 0)
279 					return C_UCON;
280 				return C_LCON;
281 			}
282 			if(instoffset == 0)
283 				return C_ZCON;
284 			if(instoffset >= -0x8000)
285 				return C_ADDCON;
286 			if((instoffset & 0xffff) == 0)
287 				return C_UCON;
288 			return C_LCON;
289 
290 		case D_EXTERN:
291 		case D_STATIC:
292 			s = a->sym;
293 			if(s == S)
294 				break;
295 			t = s->type;
296 			switch(t) {
297 			case 0:
298 			case SXREF:
299 				diag("undefined external: %s in %s",
300 					s->name, TNAME);
301 				s->type = SDATA;
302 				break;
303 			case SCONST:
304 				instoffset = s->value + a->offset;
305 				goto consize;
306 			case STEXT:
307 			case SLEAF:
308 			case SSTRING:
309 				instoffset = s->value + a->offset;
310 				return C_LCON;
311 			}
312 			instoffset = s->value + a->offset - BIG;
313 			if(instoffset >= -BIG && instoffset < BIG && instoffset != 0L)
314 				return C_SECON;
315 			instoffset = s->value + a->offset + INITDAT;
316 			return C_LCON;
317 
318 		case D_AUTO:
319 			instoffset = autosize + a->offset;
320 			if(instoffset >= -BIG && instoffset < BIG)
321 				return C_SACON;
322 			return C_LACON;
323 
324 		case D_PARAM:
325 			instoffset = autosize + a->offset + 4L;
326 			if(instoffset >= -BIG && instoffset < BIG)
327 				return C_SACON;
328 			return C_LACON;
329 		}
330 		return C_GOK;
331 
332 	case D_BRANCH:
333 		return C_SBRA;
334 	}
335 	return C_GOK;
336 }
337 
338 Optab*
339 oplook(Prog *p)
340 {
341 	int a1, a2, a3, r;
342 	char *c1, *c3;
343 	Optab *o, *e;
344 
345 	a1 = p->optab;
346 	if(a1)
347 		return optab+(a1-1);
348 	a1 = p->from.class;
349 	if(a1 == 0) {
350 		a1 = aclass(&p->from) + 1;
351 		p->from.class = a1;
352 	}
353 	a1--;
354 	a3 = p->to.class;
355 	if(a3 == 0) {
356 		a3 = aclass(&p->to) + 1;
357 		p->to.class = a3;
358 	}
359 	a3--;
360 	a2 = C_NONE;
361 	if(p->reg != NREG)
362 		a2 = C_REG;
363 	r = p->as;
364 	o = oprange[r].start;
365 	if(o == 0) {
366 		a1 = opcross[repop[r]][a1][a2][a3];
367 		if(a1) {
368 			p->optab = a1+1;
369 			return optab+a1;
370 		}
371 		o = oprange[r].stop; /* just generate an error */
372 	}
373 	e = oprange[r].stop;
374 	c1 = xcmp[a1];
375 	c3 = xcmp[a3];
376 	for(; o<e; o++)
377 		if(o->a2 == a2)
378 		if(c1[o->a1])
379 		if(c3[o->a3]) {
380 			p->optab = (o-optab)+1;
381 			return o;
382 		}
383 	diag("illegal combination %A %d %d %d",
384 		p->as, a1, a2, a3);
385 	if(!debug['a'])
386 		prasm(p);
387 	o = optab;
388 	p->optab = (o-optab)+1;
389 	return o;
390 }
391 
392 int
393 cmp(int a, int b)
394 {
395 
396 	if(a == b)
397 		return 1;
398 	switch(a) {
399 	case C_LCON:
400 		if(b == C_ZCON || b == C_SCON || b == C_UCON ||
401 		   b == C_ADDCON || b == C_ANDCON)
402 			return 1;
403 		break;
404 	case C_ADD0CON:
405 		if(b == C_ADDCON)
406 			return 1;
407 	case C_ADDCON:
408 		if(b == C_ZCON || b == C_SCON)
409 			return 1;
410 		break;
411 	case C_AND0CON:
412 		if(b == C_ANDCON)
413 			return 1;
414 	case C_ANDCON:
415 		if(b == C_ZCON || b == C_SCON)
416 			return 1;
417 		break;
418 	case C_UCON:
419 		if(b == C_ZCON)
420 			return 1;
421 		break;
422 	case C_SCON:
423 		if(b == C_ZCON)
424 			return 1;
425 		break;
426 	case C_LACON:
427 		if(b == C_SACON)
428 			return 1;
429 		break;
430 	case C_LBRA:
431 		if(b == C_SBRA)
432 			return 1;
433 		break;
434 	case C_LEXT:
435 		if(b == C_SEXT)
436 			return 1;
437 		break;
438 	case C_LAUTO:
439 		if(b == C_SAUTO)
440 			return 1;
441 		break;
442 	case C_REG:
443 		if(b == C_ZCON)
444 			return 1;
445 		break;
446 	case C_LOREG:
447 		if(b == C_ZOREG || b == C_SOREG)
448 			return 1;
449 		break;
450 	case C_SOREG:
451 		if(b == C_ZOREG)
452 			return 1;
453 		break;
454 	}
455 	return 0;
456 }
457 
458 int
459 ocmp(void *a1, void *a2)
460 {
461 	Optab *p1, *p2;
462 	int n;
463 
464 	p1 = (Optab*)a1;
465 	p2 = (Optab*)a2;
466 	n = p1->as - p2->as;
467 	if(n)
468 		return n;
469 	n = p1->a1 - p2->a1;
470 	if(n)
471 		return n;
472 	n = p1->a2 - p2->a2;
473 	if(n)
474 		return n;
475 	n = p1->a3 - p2->a3;
476 	if(n)
477 		return n;
478 	return 0;
479 }
480 
481 void
482 buildop(void)
483 {
484 	int i, n, r;
485 
486 	for(i=0; i<32; i++)
487 		for(n=0; n<32; n++)
488 			xcmp[i][n] = cmp(n, i);
489 	for(n=0; optab[n].as != AXXX; n++)
490 		;
491 	qsort(optab, n, sizeof(optab[0]), ocmp);
492 	for(i=0; i<n; i++) {
493 		r = optab[i].as;
494 		oprange[r].start = optab+i;
495 		while(optab[i].as == r)
496 			i++;
497 		oprange[r].stop = optab+i;
498 		i--;
499 
500 		switch(r)
501 		{
502 		default:
503 			diag("unknown op in build: %A", r);
504 			errorexit();
505 		case AABSF:
506 			oprange[AMOVFD] = oprange[r];
507 			oprange[AMOVDF] = oprange[r];
508 			oprange[AMOVWF] = oprange[r];
509 			oprange[AMOVFW] = oprange[r];
510 			oprange[AMOVWD] = oprange[r];
511 			oprange[AMOVDW] = oprange[r];
512 			oprange[ANEGF] = oprange[r];
513 			oprange[ANEGD] = oprange[r];
514 			oprange[AABSD] = oprange[r];
515 			break;
516 		case AADD:
517 			buildrep(1, AADD);
518 			oprange[ASGT] = oprange[r];
519 			repop[ASGT] = 1;
520 			oprange[ASGTU] = oprange[r];
521 			repop[ASGTU] = 1;
522 			oprange[AADDU] = oprange[r];
523 			repop[AADDU] = 1;
524 			oprange[AADDVU] = oprange[r];
525 			repop[AADDVU] = 1;
526 			break;
527 		case AADDF:
528 			oprange[ADIVF] = oprange[r];
529 			oprange[ADIVD] = oprange[r];
530 			oprange[AMULF] = oprange[r];
531 			oprange[AMULD] = oprange[r];
532 			oprange[ASUBF] = oprange[r];
533 			oprange[ASUBD] = oprange[r];
534 			oprange[AADDD] = oprange[r];
535 			break;
536 		case AAND:
537 			buildrep(2, AAND);
538 			oprange[AXOR] = oprange[r];
539 			repop[AXOR] = 2;
540 			oprange[AOR] = oprange[r];
541 			repop[AOR] = 2;
542 			break;
543 		case ABEQ:
544 			oprange[ABNE] = oprange[r];
545 			break;
546 		case ABLEZ:
547 			oprange[ABGEZ] = oprange[r];
548 			oprange[ABGEZAL] = oprange[r];
549 			oprange[ABLTZ] = oprange[r];
550 			oprange[ABLTZAL] = oprange[r];
551 			oprange[ABGTZ] = oprange[r];
552 			break;
553 		case AMOVB:
554 			buildrep(3, AMOVB);
555 			oprange[AMOVH] = oprange[r];
556 			repop[AMOVH] = 3;
557 			break;
558 		case AMOVBU:
559 			buildrep(4, AMOVBU);
560 			oprange[AMOVHU] = oprange[r];
561 			repop[AMOVHU] = 4;
562 			break;
563 		case AMUL:
564 			oprange[AREM] = oprange[r];
565 			oprange[AREMU] = oprange[r];
566 			oprange[ADIVU] = oprange[r];
567 			oprange[AMULU] = oprange[r];
568 			oprange[ADIV] = oprange[r];
569 			oprange[ADIVVU] = oprange[r];
570 			oprange[ADIVV] = oprange[r];
571 			break;
572 		case ASLL:
573 			oprange[ASRL] = oprange[r];
574 			oprange[ASRA] = oprange[r];
575 			oprange[ASLLV] = oprange[r];
576 			oprange[ASRAV] = oprange[r];
577 			oprange[ASRLV] = oprange[r];
578 			break;
579 		case ASUB:
580 			oprange[ASUBU] = oprange[r];
581 			oprange[ANOR] = oprange[r];
582 			break;
583 		case ASYSCALL:
584 			oprange[ATLBP] = oprange[r];
585 			oprange[ATLBR] = oprange[r];
586 			oprange[ATLBWI] = oprange[r];
587 			oprange[ATLBWR] = oprange[r];
588 			break;
589 		case ACMPEQF:
590 			oprange[ACMPGTF] = oprange[r];
591 			oprange[ACMPGTD] = oprange[r];
592 			oprange[ACMPGEF] = oprange[r];
593 			oprange[ACMPGED] = oprange[r];
594 			oprange[ACMPEQD] = oprange[r];
595 			break;
596 		case ABFPT:
597 			oprange[ABFPF] = oprange[r];
598 			break;
599 		case AMOVWL:
600 			oprange[AMOVWR] = oprange[r];
601 			oprange[AMOVVR] = oprange[r];
602 			oprange[AMOVVL] = oprange[r];
603 			break;
604 		case AMOVW:
605 			buildrep(5, AMOVW);
606 			break;
607 		case AMOVD:
608 			buildrep(6, AMOVD);
609 			break;
610 		case AMOVF:
611 			buildrep(7, AMOVF);
612 			break;
613 		case AMOVV:
614 			buildrep(8, AMOVV);
615 			break;
616 		case ABREAK:
617 		case AWORD:
618 		case ARFE:
619 		case AJAL:
620 		case AJMP:
621 		case ATEXT:
622 		case ACASE:
623 		case ABCASE:
624 			break;
625 		}
626 	}
627 }
628 
629 void
630 buildrep(int x, int as)
631 {
632 	Opcross *p;
633 	Optab *e, *s, *o;
634 	int a1, a2, a3, n;
635 
636 	if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
637 		diag("assumptions fail in buildrep");
638 		errorexit();
639 	}
640 	repop[as] = x;
641 	p = (opcross + x);
642 	s = oprange[as].start;
643 	e = oprange[as].stop;
644 	for(o=e-1; o>=s; o--) {
645 		n = o-optab;
646 		for(a2=0; a2<2; a2++) {
647 			if(a2) {
648 				if(o->a2 == C_NONE)
649 					continue;
650 			} else
651 				if(o->a2 != C_NONE)
652 					continue;
653 			for(a1=0; a1<32; a1++) {
654 				if(!xcmp[a1][o->a1])
655 					continue;
656 				for(a3=0; a3<32; a3++)
657 					if(xcmp[a3][o->a3])
658 						(*p)[a1][a2][a3] = n;
659 			}
660 		}
661 	}
662 	oprange[as].start = 0;
663 }
664