xref: /plan9-contrib/sys/src/cmd/6l/span.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include	"l.h"
2 
3 void
4 span(void)
5 {
6 	Prog *p, *q;
7 	long c, idat;
8 	int m, n, again;
9 
10 	xdefine("etext", STEXT, 0L);
11 	idat = INITDAT;
12 	for(p = firstp; p != P; p = p->link) {
13 		if(p->as == ATEXT)
14 			curtext = p;
15 		n = 0;
16 		q = p->cond;
17 		if(q != P)
18 			if(q->back != 2)
19 				n = 1;
20 		p->back = n;
21 	}
22 	n = 0;
23 
24 start:
25 	if(debug['v'])
26 		Bprint(&bso, "%5.2f span\n", cputime());
27 	Bflush(&bso);
28 	c = INITTEXT;
29 	for(p = firstp; p != P; p = p->link) {
30 		if(p->as == ATEXT) {
31 			curtext = p;
32 			autosize = p->to.offset + 4;
33 			if(p->from.sym != S)
34 				p->from.sym->value = c;
35 		}
36 		p->pc = c;
37 		if(p->to.type == D_BRANCH) {
38 			if(p->cond == P)
39 				p->cond = p;
40 		}
41 		asmins(p);
42 		m = (char*)andptr - (char*)and;
43 		p->mark = m;
44 		c += m;
45 	}
46 
47 loop:
48 	n++;
49 	if(debug['v'])
50 		Bprint(&bso, "%5.2f span %d\n", cputime(), n);
51 	Bflush(&bso);
52 	if(n > 60) {
53 		print("span must be looping\n");
54 		errorexit();
55 	}
56 	again = 0;
57 	c = INITTEXT;
58 	for(p = firstp; p != P; p = p->link) {
59 		if(p->as == ATEXT) {
60 			curtext = p;
61 			autosize = p->to.offset + 4;
62 		}
63 		if(p->to.type == D_BRANCH) {
64 			asmins(p);
65 			if(!p->back)
66 				p->pc = c;
67 			m = (char*)andptr - (char*)and;
68 			if(m != p->mark) {
69 				p->mark = m;
70 				again++;
71 			}
72 		}
73 		p->pc = c;
74 		c += p->mark;
75 	}
76 	if(again) {
77 		textsize = c;
78 		goto loop;
79 	}
80 	INITDAT = c;
81 	if(INITRND) {
82 		INITDAT = rnd(c, INITRND);
83 		if(INITDAT != idat) {
84 			idat = INITDAT;
85 			goto start;
86 		}
87 	}
88 	xdefine("etext", STEXT, c);
89 	if(debug['v'])
90 		Bprint(&bso, "etext = %lux\n", c);
91 	Bflush(&bso);
92 	for(p = textp; p != P; p = p->cond)
93 		p->from.sym->value = p->pc;
94 	textsize = c - INITTEXT;
95 }
96 
97 void
98 xdefine(char *p, int t, long v)
99 {
100 	Sym *s;
101 
102 	s = lookup(p, 0);
103 	if(s->type == 0 || s->type == SXREF) {
104 		s->type = t;
105 		s->value = v;
106 	}
107 	if(s->type == STEXT || s->type == SLEAF)
108 		if(s->value == 0)
109 			s->value = v;
110 }
111 
112 void
113 putsymb(char *s, int t, long v, int ver)
114 {
115 	int i, f;
116 
117 	if(t == 'f')
118 		s++;
119 	lput(v);
120 	if(ver)
121 		t += 'a' - 'A';
122 	CPUT(t+0x80);			/* 0x80 is variable length */
123 
124 	if(t == 'Z' || t == 'z') {
125 		CPUT(s[0]);
126 		for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
127 			CPUT(s[i]);
128 			CPUT(s[i+1]);
129 		}
130 		CPUT(0);
131 		CPUT(0);
132 		i++;
133 	}
134 	else {
135 		for(i=0; s[i]; i++)
136 			CPUT(s[i]);
137 		CPUT(0);
138 	}
139 	symsize += 4 + 1 + i + 1;
140 
141 	if(debug['n']) {
142 		if(t == 'z' || t == 'Z') {
143 			Bprint(&bso, "%c %.8lux ", t, v);
144 			for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
145 				f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
146 				Bprint(&bso, "/%x", f);
147 			}
148 			Bprint(&bso, "\n");
149 			return;
150 		}
151 		if(ver)
152 			Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
153 		else
154 			Bprint(&bso, "%c %.8lux %s\n", t, v, s);
155 	}
156 }
157 
158 void
159 asmsym(void)
160 {
161 	Prog *p;
162 	Auto *a;
163 	Sym *s;
164 	int h;
165 
166 	s = lookup("etext", 0);
167 	if(s->type == STEXT)
168 		putsymb(s->name, 'T', s->value, s->version);
169 
170 	for(h=0; h<NHASH; h++)
171 		for(s=hash[h]; s!=S; s=s->link)
172 			switch(s->type) {
173 			case SDATA:
174 				putsymb(s->name, 'D', s->value+INITDAT, s->version);
175 				continue;
176 
177 			case SBSS:
178 				putsymb(s->name, 'B', s->value+INITDAT, s->version);
179 				continue;
180 
181 			case SFILE:
182 				putsymb(s->name, 'f', s->value, s->version);
183 				continue;
184 			}
185 
186 	for(p=textp; p!=P; p=p->cond) {
187 		s = p->from.sym;
188 		if(s->type != STEXT && s->type != SLEAF)
189 			continue;
190 
191 		/* filenames first */
192 		for(a=p->to.autom; a; a=a->link)
193 			if(a->type == D_FILE)
194 				putsymb(a->sym->name, 'z', a->offset, 0);
195 			else
196 			if(a->type == D_FILE1)
197 				putsymb(a->sym->name, 'Z', a->offset, 0);
198 
199 		if(s->type == STEXT)
200 			putsymb(s->name, 'T', s->value, s->version);
201 		else
202 			putsymb(s->name, 'L', s->value, s->version);
203 
204 		/* frame, auto and param after */
205 		putsymb(".frame", 'm', p->to.offset+4, 0);
206 		for(a=p->to.autom; a; a=a->link)
207 			if(a->type == D_AUTO)
208 				putsymb(a->sym->name, 'a', -a->offset, 0);
209 			else
210 			if(a->type == D_PARAM)
211 				putsymb(a->sym->name, 'p', a->offset, 0);
212 	}
213 	if(debug['v'] || debug['n'])
214 		Bprint(&bso, "symsize = %lud\n", symsize);
215 	Bflush(&bso);
216 }
217 
218 void
219 asmlc(void)
220 {
221 	long oldpc, oldlc;
222 	Prog *p;
223 	long v, s;
224 
225 	oldpc = INITTEXT;
226 	oldlc = 0;
227 	for(p = firstp; p != P; p = p->link) {
228 		if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
229 			if(p->as == ATEXT)
230 				curtext = p;
231 			if(debug['L'])
232 				Bprint(&bso, "%6lux %P\n",
233 					p->pc, p);
234 			continue;
235 		}
236 		if(debug['L'])
237 			Bprint(&bso, "\t\t%6ld", lcsize);
238 		v = (p->pc - oldpc) / MINLC;
239 		while(v) {
240 			s = 127;
241 			if(v < 127)
242 				s = v;
243 			CPUT(s+128);	/* 129-255 +pc */
244 			if(debug['L'])
245 				Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
246 			v -= s;
247 			lcsize++;
248 		}
249 		s = p->line - oldlc;
250 		oldlc = p->line;
251 		oldpc = p->pc + MINLC;
252 		if(s > 64 || s < -64) {
253 			CPUT(0);	/* 0 vv +lc */
254 			CPUT(s>>24);
255 			CPUT(s>>16);
256 			CPUT(s>>8);
257 			CPUT(s);
258 			if(debug['L']) {
259 				if(s > 0)
260 					Bprint(&bso, " lc+%ld(%d,%ld)\n",
261 						s, 0, s);
262 				else
263 					Bprint(&bso, " lc%ld(%d,%ld)\n",
264 						s, 0, s);
265 				Bprint(&bso, "%6lux %P\n",
266 					p->pc, p);
267 			}
268 			lcsize += 5;
269 			continue;
270 		}
271 		if(s > 0) {
272 			CPUT(0+s);	/* 1-64 +lc */
273 			if(debug['L']) {
274 				Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
275 				Bprint(&bso, "%6lux %P\n",
276 					p->pc, p);
277 			}
278 		} else {
279 			CPUT(64-s);	/* 65-128 -lc */
280 			if(debug['L']) {
281 				Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
282 				Bprint(&bso, "%6lux %P\n",
283 					p->pc, p);
284 			}
285 		}
286 		lcsize++;
287 	}
288 	while(lcsize & 1) {
289 		s = 129;
290 		CPUT(s);
291 		lcsize++;
292 	}
293 	if(debug['v'] || debug['L'])
294 		Bprint(&bso, "lcsize = %ld\n", lcsize);
295 	Bflush(&bso);
296 }
297 
298 int
299 oclass1(Prog *p)
300 {
301 	int t;
302 
303 	t = p->type;
304 	if(t == D_NONE)
305 		return Ynone;
306 	if(t >= D_R0 && t < D_R0+32)
307 		return Yr;
308 	if(t == D_CONST)
309 		return Yi5;
310 	return Yxxx;
311 }
312 
313 int
314 oclass(Adr *a)
315 {
316 	long v;
317 
318 	if(a->type >= D_INDIR || a->index != D_NONE) {
319 		if(a->index != D_NONE && a->scale == 0) {
320 			if(a->type >= D_ADDR)
321 				return Yi32;
322 			return Ycol;
323 		}
324 		return Ym;
325 	}
326 	switch(a->type)
327 	{
328 	default:
329 		if(a->type >= D_R0 && a->type < D_R0+32)
330 			return Yr;
331 	case D_NONE:
332 		return Ynone;
333 
334 	case D_EXTERN:
335 	case D_STATIC:
336 	case D_AUTO:
337 	case D_PARAM:
338 		return Ym;
339 
340 	case D_CONST:
341 	case D_ADDR:
342 		if(a->sym == S) {
343 			v = a->offset;
344 			if(v >= 0 && v < 32)
345 				return Yi5;
346 		}
347 		return Yi32;
348 
349 	case D_BRANCH:
350 		return Ybr;
351 	}
352 	return Yxxx;
353 }
354 
355 void
356 dob(int o, long dpc)
357 {
358 	long i;
359 
360 	i = (o & 0xff) << 24;
361 	if(dpc >= -(1<<23) || dpc < (1<<23)) {
362 		i |= dpc & 0xfffffc;	/* tandi seems to keep low bits on */
363 		*andptr++ = i;
364 		return;
365 	}
366 	diag("branch 23 too far");
367 }
368 
369 void
370 dorrb(int o, int r, int m, long dpc)
371 {
372 	long i;
373 
374 	i = (o & 0xff) << 24;
375 	i |= (r & 0x1f) << 19;
376 	if(r & 32)
377 		i |= 1<<13;		/* m1 */
378 	i |= (m & 0x1f) << 14;
379 	if(r & 32)
380 		i |= 1<<13;		/* m1 */
381 /* bug?? */
382 	if(dpc >= -((1<<12)) || dpc < ((1<<12))) {
383 		i |= dpc & 0xffc;
384 		*andptr++ = i;
385 		return;
386 	}
387 	diag("branch 12 too far");
388 }
389 
390 void
391 dormem(int o, int r, Adr *a)
392 {
393 	long i, v;
394 	int t, abase, index, scale;
395 
396 
397 	abase = D_NONE;
398 	index = a->index;
399 	scale = a->scale;
400 	v = a->offset;
401 
402 	t = a->type;
403 	if(t >= D_INDIR) {
404 		t -= D_INDIR;
405 		if(t < D_R0 || t >= D_R0+32)
406 			if(t != D_NONE)
407 				diag("dormem 1 %D %d", a, a->type);
408 		abase = t;
409 		goto asm;
410 	}
411 	switch(t) {
412 	default:
413 		diag("dormem 2 %D", a);
414 		break;
415 
416 	case D_STATIC:
417 	case D_EXTERN:
418 		t = a->sym->type;
419 		if(t == 0 || t == SXREF) {
420 			diag("undefined external: %s in %s\n",
421 				a->sym->name, TNAME);
422 			a->sym->type = SDATA;
423 		}
424 		v += a->sym->value;
425 		abase = REGSB;
426 		if(a->sym == symSB) {
427 			v = INITDAT;
428 			abase = D_NONE;
429 		}
430 		break;
431 
432 	case D_PARAM:
433 		v += 4L;
434 
435 	case D_AUTO:
436 		v += autosize;
437 		abase = REGSP;
438 		break;
439 	}
440 
441 asm:
442 	t = 0;
443 	if(v == 0)
444 		t |= Anooffset;
445 	else
446 	if(v < 0 || v >= 4096)
447 		t |= Abigoffset;
448 	if(index != D_NONE) {
449 		t |= Aindex;
450 		switch(scale) {
451 		default:
452 			diag("bad scale %A", a);
453 		case 1:
454 			scale = 0;
455 			break;
456 		case 2:
457 			scale = 1;
458 			break;
459 		case 4:
460 			scale = 2;
461 			break;
462 		case 8:
463 			scale = 3;
464 			break;
465 		case 16:
466 			scale = 4;
467 			break;
468 		}
469 	}
470 	if(abase != D_NONE)
471 		t |= Abase;
472 
473 	i = (o & 0xff) << 24;
474 	i |= (r & 0x1f) << 19;
475 	switch(t) {
476 	default:
477 		diag("dormem mode %lux %D\n", t, a);
478 		break;
479 
480 	case 0:
481 	case Anooffset:
482 		/*
483 		 * mema mode 0
484 		 */
485 		i |= v;
486 		*andptr++ = i;
487 		break;
488 
489 	case Abase:
490 		/*
491 		 * mema mode 1
492 		 */
493 		i |= 1 << 13;
494 		i |= ((abase-D_R0) & 0x1f) << 14;
495 		i |= v;
496 		*andptr++ = i;
497 		break;
498 
499 	case Abase|Anooffset:
500 		/*
501 		 * memb mode 4
502 		 */
503 		i |= 0x4 << 10;
504 		i |= ((abase-D_R0) & 0x1f) << 14;
505 		*andptr++ = i;
506 		break;
507 
508 	case Abase|Aindex|Anooffset:
509 		/*
510 		 * memb mode 7
511 		 */
512 		i |= 0x7 << 10;
513 		i |= ((abase-D_R0) & 0x1f) << 14;
514 		i |= ((index-D_R0) & 0x1f) << 0;
515 		i |= (scale & 0x7) << 7;
516 		*andptr++ = i;
517 		break;
518 
519 	case Abigoffset:
520 		/*
521 		 * memb mode c
522 		 */
523 		i |= 0xc << 10;
524 		*andptr++ = i;
525 		*andptr++ = v;
526 		break;
527 
528 	case Abase|Abigoffset:
529 		/*
530 		 * memb mode d
531 		 */
532 		i |= 0xd << 10;
533 		i |= ((abase-D_R0) & 0x1f) << 14;
534 		*andptr++ = i;
535 		*andptr++ = v;
536 		break;
537 
538 	case Aindex:
539 	case Aindex|Abigoffset:
540 	case Aindex|Anooffset:
541 		/*
542 		 * memb mode e
543 		 */
544 		i |= 0xe << 10;
545 		i |= ((index-D_R0) & 0x1f) << 0;
546 		i |= (scale & 0x7) << 7;
547 		*andptr++ = i;
548 		*andptr++ = v;
549 		break;
550 
551 	case Abase|Aindex:
552 	case Abase|Aindex|Abigoffset:
553 		/*
554 		 * memb mode f
555 		 */
556 		i |= 0xf << 10;
557 		i |= ((abase-D_R0) & 0x1f) << 14;
558 		i |= ((index-D_R0) & 0x1f) << 0;
559 		i |= (scale & 0x7) << 7;
560 		*andptr++ = i;
561 		*andptr++ = v;
562 		break;
563 	}
564 
565 }
566 
567 void
568 dorrr(int op, int src1, int src2, int dst)
569 {
570 	ulong i;
571 
572 	i = (op & 0xfL) << 7;
573 	i |= (op & 0xff0L) << 20;
574 	i |= (src1 & 31) << 0;		/* src1 */
575 	if(src1 & 32)
576 		i |= 1<<11;		/* m1 */
577 	i |= (src2 & 31) << 14;		/* src2 */
578 	if(src2 & 32)
579 		i |= 1<<12;		/* m2 */
580 	i |= (dst & 31) << 19;		/* dst */
581 	*andptr++ = i;
582 }
583 
584 void
585 doir(Adr *a, int dst)
586 {
587 	long c;
588 	int t;
589 
590 	c = a->offset;
591 	if(a->type == D_ADDR) {
592 		switch(a->index) {
593 		default:
594 			diag("type in doir/D_ADDR");
595 			break;
596 		case D_EXTERN:
597 		case D_STATIC:
598 			if(!a->sym)
599 				break;
600 			t = a->sym->type;
601 			if(t == 0 || t == SXREF) {
602 				diag("undefined external: %s in %s\n",
603 					a->sym->name, TNAME);
604 				a->sym->type = SDATA;
605 			}
606 			c += a->sym->value;
607 			if(a->sym == symSB)
608 				c = INITDAT;
609 		}
610 	} else
611 	if(a->type != D_CONST)
612 		diag("type in doir");
613 
614 	if(c >= 0 && c < 4096) {
615 		*andptr++ = (0x8c<<24) | (dst<<19) | (c<<0);	/* mova $c,dst */
616 		return;
617 	}
618 	if(c >= -31 && c < 0) {
619 		dorrr(0x592, 32-c, 32+0, dst);			/* subo $c,$0,dst */
620 		return;
621 	}
622 	for(t=10; t<32-5; t++)
623 		if((c & ~(31<<t)) == 0) {			/* shlo $c1,$c2,dst */
624 			dorrr(0x59c, 32+t, 32+((c>>t)&31), dst);
625 			return;
626 		}
627 	*andptr++ = (0x8c<<24) | (dst<<19) | (0xc<<10);	/* mova $bigc,dst */
628 	*andptr++ = c;
629 }
630 
631 void
632 doasm(Prog *p)
633 {
634 	Optab *o;
635 	uchar *t;
636 	int z, ft, tt, mt;
637 
638 	o = &optab[p->as];
639 	ft = oclass(&p->from) * Ymax;
640 	mt = oclass1(p) * Ymax;
641 	tt = oclass(&p->to) * Ymax;
642 	t = o->ytab;
643 	if(t == 0) {
644 		diag("asmins: noproto %P\n", p);
645 		return;
646 	}
647 	for(z=0; *t; z+=t[4], t+=5)
648 		if(ycover[ft+t[0]])
649 		if(ycover[mt+t[1]])
650 		if(ycover[tt+t[2]])
651 			goto found;
652 
653 	diag("asmins: notfound <%d,%d,%d> %P\n",
654 		ft/Ymax, mt/Ymax, tt/Ymax, p);
655 	return;
656 
657 found:
658 	switch(t[3]) {
659 	default:
660 		diag("asmins: unknown z %d %P\n", t[3], p);
661 		return;
662 
663 	case Zpseudo:
664 		break;
665 
666 	case Zbr:
667 		dob(o->op[z], p->cond->pc - p->pc);
668 		break;
669 
670 	case Zrxr:	/* Yri5, Ynone, Yr5 */
671 		if(ft == Yr*Ymax)
672 			ft = p->from.type - D_R0;
673 		else
674 			ft = p->from.offset | 32;
675 
676 		dorrr(o->op[z], ft, 0, p->to.type-D_R0);
677 		break;
678 
679 	case Zrrx:	/* Yri5, Ynone, Yri5 */
680 		if(ft == Yr*Ymax)
681 			ft = p->from.type - D_R0;
682 		else
683 			ft = p->from.offset | 32;
684 		if(tt == Yr*Ymax)
685 			tt = p->to.type - D_R0;
686 		else
687 			tt = p->to.offset | 32;
688 
689 		dorrr(o->op[z], ft, tt, 0);
690 		break;
691 
692 	case Zirx:	/* Yi32, Ynone, Yri5 */
693 		if(tt == Yr*Ymax)
694 			tt = p->to.type - D_R0;
695 		else
696 			tt = p->to.offset | 32;
697 
698 		doir(&p->from, REGTMP-D_R0);
699 		dorrr(o->op[z], REGTMP-D_R0, tt, 0);
700 		break;
701 
702 	case Zrrr:	/* Yri5, Ynri5, Yr */
703 		if(ft == Yr*Ymax)
704 			ft = p->from.type - D_R0;
705 		else
706 			ft = p->from.offset | 32;
707 
708 		if(mt == Ynone*Ymax)
709 			mt = p->to.type - D_R0;
710 		else
711 		if(mt == Yr*Ymax)
712 			mt = p->type - D_R0;
713 		else
714 			mt = p->offset | 32;
715 
716 		dorrr(o->op[z], ft, mt, p->to.type-D_R0);
717 		break;
718 
719 	case Zir:	/* Yi32, Yr */
720 		doir(&p->from, p->to.type-D_R0);
721 		break;
722 
723 	case Zirr:	/* Yi32, Ynri5, Yr */
724 		if(mt == Ynone*Ymax)
725 			mt = p->to.type - D_R0;
726 		else
727 		if(mt == Yr*Ymax)
728 			mt = p->type - D_R0;
729 		else
730 			mt = p->offset | 32;
731 
732 		doir(&p->from, REGTMP-D_R0);
733 		dorrr(o->op[z], REGTMP-D_R0, mt, p->to.type-D_R0);
734 		break;
735 
736 	case Zmbr:
737 		dormem(o->op[z], REGLINK-D_R0, &p->to);
738 		break;
739 
740 	case Zmr:
741 		dormem(o->op[z], p->to.type-D_R0, &p->from);
742 		break;
743 
744 	case Zrm:
745 		dormem(o->op[z], p->from.type-D_R0, &p->to);
746 		break;
747 
748 	case Zim:
749 		if(p->from.offset != 0) {
750 			doir(&p->from, REGTMP-D_R0);
751 			dormem(o->op[z], REGTMP-D_R0, &p->to);
752 		} else
753 			dormem(o->op[z], REGZERO-D_R0, &p->to);
754 		break;
755 
756 	case Zlong:
757 		*andptr++ = p->from.offset;
758 		break;
759 
760 	case Znone:
761 		dorrr(o->op[z], 0, 0, 0);
762 		break;
763 	}
764 }
765 
766 void
767 asmins(Prog *p)
768 {
769 
770 	andptr = and;
771 	doasm(p);
772 }
773