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