xref: /plan9-contrib/sys/src/cmd/4l/span.c (revision f8bc6aaf8056e137bcdfb6117a990ac3eff62cc9)
1 #include	"l.h"
2 
3 void
pagebug(Prog * p)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
span(void)34 span(void)
35 {
36 	Prog *p, *q;
37 	Sym *setext, *s;
38 	Optab *o;
39 	int m, bflag, i;
40 	vlong 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 + 8;
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 + 8;
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 = %llux\n", textsize);
158 	Bflush(&bso);
159 }
160 
161 void
xdefine(char * p,int t,vlong v)162 xdefine(char *p, int t, vlong 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
regoff(Adr * a)174 regoff(Adr *a)
175 {
176 
177 	instoffset = 0;
178 	aclass(a);
179 	return instoffset;
180 }
181 
182 int
isint32(vlong v)183 isint32(vlong v)
184 {
185 	long l;
186 
187 	l = v;
188 	return (vlong)l == v;
189 }
190 
191 int
isuint32(uvlong v)192 isuint32(uvlong v)
193 {
194 	ulong l;
195 
196 	l = v;
197 	return (uvlong)l == v;
198 }
199 
200 int
aclass(Adr * a)201 aclass(Adr *a)
202 {
203 	Sym *s;
204 	int t;
205 
206 	switch(a->type) {
207 	case D_NONE:
208 		return C_NONE;
209 
210 	case D_REG:
211 		return C_REG;
212 
213 	case D_FREG:
214 		return C_FREG;
215 
216 	case D_FCREG:
217 		return C_FCREG;
218 
219 	case D_MREG:
220 		return C_MREG;
221 
222 	case D_OREG:
223 		switch(a->name) {
224 		case D_EXTERN:
225 		case D_STATIC:
226 			if(a->sym == 0 || a->sym->name == 0) {
227 				print("null sym external\n");
228 				print("%D\n", a);
229 				return C_GOK;
230 			}
231 			t = a->sym->type;
232 			if(t == 0 || t == SXREF) {
233 				diag("undefined external: %s in %s",
234 					a->sym->name, TNAME);
235 				a->sym->type = SDATA;
236 			}
237 			instoffset = a->sym->value + a->offset - BIG;
238 			if(instoffset >= -BIG && instoffset < BIG)
239 				return C_SEXT;
240 			return C_LEXT;
241 		case D_AUTO:
242 			instoffset = autosize + a->offset;
243 			if(instoffset >= -BIG && instoffset < BIG)
244 				return C_SAUTO;
245 			return C_LAUTO;
246 
247 		case D_PARAM:
248 			instoffset = autosize + a->offset + 8L;
249 			if(instoffset >= -BIG && instoffset < BIG)
250 				return C_SAUTO;
251 			return C_LAUTO;
252 		case D_NONE:
253 			instoffset = a->offset;
254 			if(instoffset == 0)
255 				return C_ZOREG;
256 			if(instoffset >= -BIG && instoffset < BIG)
257 				return C_SOREG;
258 			return C_LOREG;
259 		}
260 		return C_GOK;
261 
262 	case D_HI:
263 		return C_LO;
264 	case D_LO:
265 		return C_HI;
266 
267 	case D_OCONST:
268 		switch(a->name) {
269 		case D_EXTERN:
270 		case D_STATIC:
271 			s = a->sym;
272 			t = s->type;
273 			if(t == 0 || t == SXREF) {
274 				diag("undefined external: %s in %s",
275 					s->name, TNAME);
276 				s->type = SDATA;
277 			}
278 			instoffset = s->value + a->offset + INITDAT;
279 			if(s->type == STEXT || s->type == SLEAF)
280 				instoffset = s->value + a->offset;
281 			return C_LCON;
282 		}
283 		return C_GOK;
284 
285 	case D_CONST:
286 		switch(a->name) {
287 		case D_NONE:
288 			instoffset = a->offset;
289 		consize:
290 			if(instoffset > 0) {
291 				if(instoffset <= 0x7fff)
292 					return C_SCON;
293 				if(instoffset <= 0xffff)
294 					return C_ANDCON;
295 				if((instoffset & 0xffff) == 0 && isuint32(instoffset))
296 					return C_UCON;
297 				return C_LCON;
298 			}
299 			if(instoffset == 0)
300 				return C_ZCON;
301 			if(instoffset >= -0x8000)
302 				return C_ADDCON;
303 			if((instoffset & 0xffff) == 0 && isint32(instoffset))
304 				return C_UCON;
305 			return C_LCON;
306 
307 		case D_EXTERN:
308 		case D_STATIC:
309 			s = a->sym;
310 			if(s == S)
311 				break;
312 			t = s->type;
313 			switch(t) {
314 			case 0:
315 			case SXREF:
316 				diag("undefined external: %s in %s",
317 					s->name, TNAME);
318 				s->type = SDATA;
319 				break;
320 			case SCONST:
321 				instoffset = s->value + a->offset;
322 				goto consize;
323 			case STEXT:
324 			case SLEAF:
325 				instoffset = s->value + a->offset;
326 				return C_LCON;
327 			}
328 			instoffset = s->value + a->offset - BIG;
329 			if(instoffset >= -BIG && instoffset < BIG && instoffset != 0L)
330 				return C_SECON;
331 			instoffset = s->value + a->offset + INITDAT;
332 			return C_LCON;
333 
334 		case D_AUTO:
335 			instoffset = autosize + a->offset;
336 			if(instoffset >= -BIG && instoffset < BIG)
337 				return C_SACON;
338 			return C_LACON;
339 
340 		case D_PARAM:
341 			instoffset = autosize + a->offset + 8L;
342 			if(instoffset >= -BIG && instoffset < BIG)
343 				return C_SACON;
344 			return C_LACON;
345 		}
346 		return C_GOK;
347 
348 	case D_BRANCH:
349 		return C_SBRA;
350 	}
351 	return C_GOK;
352 }
353 
354 Optab*
oplook(Prog * p)355 oplook(Prog *p)
356 {
357 	int a1, a2, a3, r;
358 	char *c1, *c3;
359 	Optab *o, *e;
360 
361 	a1 = p->optab;
362 	if(a1)
363 		return optab+(a1-1);
364 	a1 = p->from.class;
365 	if(a1 == 0) {
366 		a1 = aclass(&p->from) + 1;
367 		p->from.class = a1;
368 	}
369 	a1--;
370 	a3 = p->to.class;
371 	if(a3 == 0) {
372 		a3 = aclass(&p->to) + 1;
373 		p->to.class = a3;
374 	}
375 	a3--;
376 	a2 = C_NONE;
377 	if(p->reg != NREG)
378 		a2 = C_REG;
379 	r = p->as;
380 	o = oprange[r].start;
381 	if(o == 0) {
382 		a1 = opcross[repop[r]][a1][a2][a3];
383 		if(a1) {
384 			p->optab = a1+1;
385 			return optab+a1;
386 		}
387 		o = oprange[r].stop; /* just generate an error */
388 	}
389 	e = oprange[r].stop;
390 	c1 = xcmp[a1];
391 	c3 = xcmp[a3];
392 	for(; o<e; o++)
393 		if(o->a2 == a2)
394 		if(c1[o->a1])
395 		if(c3[o->a3]) {
396 			p->optab = (o-optab)+1;
397 			return o;
398 		}
399 	diag("illegal combination %A %d %d %d",
400 		p->as, p->from.class-1, a2, a3);
401 	if(!debug['a'])
402 		prasm(p);
403 	o = optab;
404 	p->optab = (o-optab)+1;
405 	return o;
406 }
407 
408 int
cmp(int a,int b)409 cmp(int a, int b)
410 {
411 
412 	if(a == b)
413 		return 1;
414 	switch(a) {
415 	case C_LCON:
416 		if(b == C_ZCON || b == C_SCON || b == C_UCON ||
417 		   b == C_ADDCON || b == C_ANDCON)
418 			return 1;
419 		break;
420 	case C_ADD0CON:
421 		if(b == C_ADDCON)
422 			return 1;
423 	case C_ADDCON:
424 		if(b == C_ZCON || b == C_SCON)
425 			return 1;
426 		break;
427 	case C_AND0CON:
428 		if(b == C_ANDCON)
429 			return 1;
430 	case C_ANDCON:
431 		if(b == C_ZCON || b == C_SCON)
432 			return 1;
433 		break;
434 	case C_UCON:
435 		if(b == C_ZCON)
436 			return 1;
437 		break;
438 	case C_SCON:
439 		if(b == C_ZCON)
440 			return 1;
441 		break;
442 	case C_LACON:
443 		if(b == C_SACON)
444 			return 1;
445 		break;
446 	case C_LBRA:
447 		if(b == C_SBRA)
448 			return 1;
449 		break;
450 	case C_LEXT:
451 		if(b == C_SEXT)
452 			return 1;
453 		break;
454 	case C_LAUTO:
455 		if(b == C_SAUTO)
456 			return 1;
457 		break;
458 	case C_REG:
459 		if(b == C_ZCON)
460 			return 1;
461 		break;
462 	case C_LOREG:
463 		if(b == C_ZOREG || b == C_SOREG)
464 			return 1;
465 		break;
466 	case C_SOREG:
467 		if(b == C_ZOREG)
468 			return 1;
469 		break;
470 	}
471 	return 0;
472 }
473 
474 int
ocmp(const void * a1,const void * a2)475 ocmp(const void *a1, const void *a2)
476 {
477 	Optab *p1, *p2;
478 	int n;
479 
480 	p1 = (Optab*)a1;
481 	p2 = (Optab*)a2;
482 	n = p1->as - p2->as;
483 	if(n)
484 		return n;
485 	n = p1->a1 - p2->a1;
486 	if(n)
487 		return n;
488 	n = p1->a2 - p2->a2;
489 	if(n)
490 		return n;
491 	n = p1->a3 - p2->a3;
492 	if(n)
493 		return n;
494 	return 0;
495 }
496 
497 void
buildop(void)498 buildop(void)
499 {
500 	int i, n, r;
501 
502 	for(i=0; i<32; i++)
503 		for(n=0; n<32; n++)
504 			xcmp[i][n] = cmp(n, i);
505 	for(n=0; optab[n].as != AXXX; n++)
506 		;
507 	qsort(optab, n, sizeof(optab[0]), ocmp);
508 	for(i=0; i<n; i++) {
509 		r = optab[i].as;
510 		oprange[r].start = optab+i;
511 		while(optab[i].as == r)
512 			i++;
513 		oprange[r].stop = optab+i;
514 		i--;
515 
516 		switch(r)
517 		{
518 		default:
519 			diag("unknown op in build: %A", r);
520 			errorexit();
521 		case AABSF:
522 			oprange[AMOVFD] = oprange[r];
523 			oprange[AMOVDF] = oprange[r];
524 			oprange[AMOVWF] = oprange[r];
525 			oprange[AMOVFW] = oprange[r];
526 			oprange[AMOVWD] = oprange[r];
527 			oprange[AMOVDW] = oprange[r];
528 			oprange[ANEGF] = oprange[r];
529 			oprange[ANEGD] = oprange[r];
530 			oprange[AABSD] = oprange[r];
531 			oprange[ATRUNCDW] = oprange[r];
532 			oprange[ATRUNCFW] = oprange[r];
533 			oprange[ATRUNCDV] = oprange[r];
534 			oprange[ATRUNCFV] = oprange[r];
535 			oprange[AMOVDV] = oprange[r];
536 			oprange[AMOVFV] = oprange[r];
537 			oprange[AMOVVD] = oprange[r];
538 			oprange[AMOVVF] = oprange[r];
539 			break;
540 		case AADD:
541 			buildrep(1, AADD);
542 			oprange[ASGT] = oprange[r];
543 			repop[ASGT] = 1;
544 			oprange[ASGTU] = oprange[r];
545 			repop[ASGTU] = 1;
546 			oprange[AADDU] = oprange[r];
547 			repop[AADDU] = 1;
548 			oprange[AADDVU] = oprange[r];
549 			repop[AADDVU] = 1;
550 			oprange[AADDV] = oprange[r];
551 			repop[AADDV] = 1;
552 			break;
553 		case AADDF:
554 			oprange[ADIVF] = oprange[r];
555 			oprange[ADIVD] = oprange[r];
556 			oprange[AMULF] = oprange[r];
557 			oprange[AMULD] = oprange[r];
558 			oprange[ASUBF] = oprange[r];
559 			oprange[ASUBD] = oprange[r];
560 			oprange[AADDD] = oprange[r];
561 			break;
562 		case AAND:
563 			buildrep(2, AAND);
564 			oprange[AXOR] = oprange[r];
565 			repop[AXOR] = 2;
566 			oprange[AOR] = oprange[r];
567 			repop[AOR] = 2;
568 			break;
569 		case ABEQ:
570 			oprange[ABNE] = oprange[r];
571 			break;
572 		case ABLEZ:
573 			oprange[ABGEZ] = oprange[r];
574 			oprange[ABGEZAL] = oprange[r];
575 			oprange[ABLTZ] = oprange[r];
576 			oprange[ABLTZAL] = oprange[r];
577 			oprange[ABGTZ] = oprange[r];
578 			break;
579 		case AMOVB:
580 			buildrep(3, AMOVB);
581 			oprange[AMOVH] = oprange[r];
582 			repop[AMOVH] = 3;
583 			break;
584 		case AMOVBU:
585 			buildrep(4, AMOVBU);
586 			oprange[AMOVHU] = oprange[r];
587 			repop[AMOVHU] = 4;
588 			break;
589 		case AMUL:
590 			oprange[AREM] = oprange[r];
591 			oprange[AREMU] = oprange[r];
592 			oprange[ADIVU] = oprange[r];
593 			oprange[AMULU] = oprange[r];
594 			oprange[ADIV] = oprange[r];
595 			oprange[ADIVV] = oprange[r];
596 			oprange[ADIVVU] = oprange[r];
597 			oprange[AMULV] = oprange[r];
598 			oprange[AMULVU] = oprange[r];
599 			oprange[AREMV] = oprange[r];
600 			oprange[AREMVU] = oprange[r];
601 			break;
602 		case ASLL:
603 			oprange[ASRL] = oprange[r];
604 			oprange[ASRA] = oprange[r];
605 			oprange[ASLLV] = oprange[r];
606 			oprange[ASRAV] = oprange[r];
607 			oprange[ASRLV] = oprange[r];
608 			break;
609 		case ASUB:
610 			oprange[ASUBU] = oprange[r];
611 			oprange[ASUBV] = oprange[r];
612 			oprange[ASUBVU] = oprange[r];
613 			oprange[ANOR] = oprange[r];
614 			break;
615 		case ASYSCALL:
616 			oprange[ATLBP] = oprange[r];
617 			oprange[ATLBR] = oprange[r];
618 			oprange[ATLBWI] = oprange[r];
619 			oprange[ATLBWR] = oprange[r];
620 			break;
621 		case ACMPEQF:
622 			oprange[ACMPGTF] = oprange[r];
623 			oprange[ACMPGTD] = oprange[r];
624 			oprange[ACMPGEF] = oprange[r];
625 			oprange[ACMPGED] = oprange[r];
626 			oprange[ACMPEQD] = oprange[r];
627 			break;
628 		case ABFPT:
629 			oprange[ABFPF] = oprange[r];
630 			break;
631 		case AMOVWL:
632 			oprange[AMOVWR] = oprange[r];
633 			oprange[AMOVVR] = oprange[r];
634 			oprange[AMOVVL] = oprange[r];
635 			break;
636 		case AMOVW:
637 			buildrep(5, AMOVW);
638 			break;
639 		case AMOVD:
640 			buildrep(6, AMOVD);
641 			break;
642 		case AMOVF:
643 			buildrep(7, AMOVF);
644 			break;
645 		case AMOVV:
646 			buildrep(8, AMOVV);
647 			break;
648 		case ABREAK:
649 		case AWORD:
650 		case ARFE:
651 		case AJAL:
652 		case AJMP:
653 		case ATEXT:
654 		case ACASE:
655 		case ABCASE:
656 		case AMOVWU:
657 			break;
658 		}
659 	}
660 }
661 
662 void
buildrep(int x,int as)663 buildrep(int x, int as)
664 {
665 	Opcross *p;
666 	Optab *e, *s, *o;
667 	int a1, a2, a3, n;
668 
669 	if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
670 		diag("assumptions fail in buildrep");
671 		errorexit();
672 	}
673 	repop[as] = x;
674 	p = (opcross + x);
675 	s = oprange[as].start;
676 	e = oprange[as].stop;
677 	for(o=e-1; o>=s; o--) {
678 		n = o-optab;
679 		for(a2=0; a2<2; a2++) {
680 			if(a2) {
681 				if(o->a2 == C_NONE)
682 					continue;
683 			} else
684 				if(o->a2 != C_NONE)
685 					continue;
686 			for(a1=0; a1<32; a1++) {
687 				if(!xcmp[a1][o->a1])
688 					continue;
689 				for(a3=0; a3<32; a3++)
690 					if(xcmp[a3][o->a3])
691 						(*p)[a1][a2][a3] = n;
692 			}
693 		}
694 	}
695 	oprange[as].start = 0;
696 }
697