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