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