xref: /plan9-contrib/sys/src/cmd/6l/pass.c (revision 40d015479ed36701ae6dcfd8814f849fc6285e8d)
1 #include	"l.h"
2 
3 void
dodata(void)4 dodata(void)
5 {
6 	int i;
7 	Sym *s;
8 	Prog *p;
9 	long t, u;
10 
11 	if(debug['v'])
12 		Bprint(&bso, "%5.2f dodata\n", cputime());
13 	Bflush(&bso);
14 	for(p = datap; p != P; p = p->link) {
15 		s = p->from.sym;
16 		if(p->as == ADYNT || p->as == AINIT)
17 			s->value = dtype;
18 		if(s->type == SBSS)
19 			s->type = SDATA;
20 		if(s->type != SDATA)
21 			diag("initialize non-data (%d): %s\n%P",
22 				s->type, s->name, p);
23 		t = p->from.offset + p->width;
24 		if(t > s->value)
25 			diag("initialize bounds (%lld): %s\n%P",
26 				s->value, s->name, p);
27 	}
28 	/* allocate small guys */
29 	datsize = 0;
30 	for(i=0; i<NHASH; i++)
31 	for(s = hash[i]; s != S; s = s->link) {
32 		if(s->type != SDATA)
33 		if(s->type != SBSS)
34 			continue;
35 		t = s->value;
36 		if(t == 0) {
37 			diag("%s: no size", s->name);
38 			t = 1;
39 		}
40 		t = rnd(t, 4);
41 		s->value = t;
42 		if(t > MINSIZ)
43 			continue;
44 		if(t >= 8)
45 			datsize = rnd(datsize, 8);
46 		s->value = datsize;
47 		datsize += t;
48 		s->type = SDATA1;
49 	}
50 
51 	/* allocate the rest of the data */
52 	for(i=0; i<NHASH; i++)
53 	for(s = hash[i]; s != S; s = s->link) {
54 		if(s->type != SDATA) {
55 			if(s->type == SDATA1)
56 				s->type = SDATA;
57 			continue;
58 		}
59 		t = s->value;
60 		if(t >= 8)
61 			datsize = rnd(datsize, 8);
62 		s->value = datsize;
63 		datsize += t;
64 	}
65 	if(datsize)
66 		datsize = rnd(datsize, 8);
67 
68 	if(debug['j']) {
69 		/*
70 		 * pad data with bss that fits up to next
71 		 * 8k boundary, then push data to 8k
72 		 */
73 		u = rnd(datsize, 8192);
74 		u -= datsize;
75 		for(i=0; i<NHASH; i++)
76 		for(s = hash[i]; s != S; s = s->link) {
77 			if(s->type != SBSS)
78 				continue;
79 			t = s->value;
80 			if(t > u)
81 				continue;
82 			u -= t;
83 			s->value = datsize;
84 			s->type = SDATA;
85 			datsize += t;
86 		}
87 		datsize += u;
88 	}
89 
90 	/* now the bss */
91 	bsssize = 0;
92 	for(i=0; i<NHASH; i++)
93 	for(s = hash[i]; s != S; s = s->link) {
94 		if(s->type != SBSS)
95 			continue;
96 		t = s->value;
97 		if(t >= 8)
98 			bsssize = rnd(bsssize, 8);
99 		s->value = bsssize + datsize;
100 		bsssize += t;
101 	}
102 	xdefine("bdata", SDATA, 0L);
103 	xdefine("edata", SBSS, datsize);
104 	xdefine("end", SBSS, bsssize + datsize);
105 	/* etext is defined in span.c */
106 }
107 
108 Prog*
brchain(Prog * p)109 brchain(Prog *p)
110 {
111 	int i;
112 
113 	for(i=0; i<20; i++) {
114 		if(p == P || p->as != AJMP)
115 			return p;
116 		p = p->pcond;
117 	}
118 	return P;
119 }
120 
121 void
follow(void)122 follow(void)
123 {
124 
125 	if(debug['v'])
126 		Bprint(&bso, "%5.2f follow\n", cputime());
127 	Bflush(&bso);
128 	firstp = prg();
129 	lastp = firstp;
130 	xfol(textp);
131 	lastp->link = P;
132 	firstp = firstp->link;
133 }
134 
135 void
xfol(Prog * p)136 xfol(Prog *p)
137 {
138 	Prog *q;
139 	int i;
140 	enum as a;
141 
142 loop:
143 	if(p == P)
144 		return;
145 	if(p->as == ATEXT)
146 		curtext = p;
147 	if(p->as == AJMP)
148 	if((q = p->pcond) != P) {
149 		p->mark = 1;
150 		p = q;
151 		if(p->mark == 0)
152 			goto loop;
153 	}
154 	if(p->mark) {
155 		/* copy up to 4 instructions to avoid branch */
156 		for(i=0,q=p; i<4; i++,q=q->link) {
157 			if(q == P)
158 				break;
159 			if(q == lastp)
160 				break;
161 			a = q->as;
162 			if(a == ANOP || a == ATEXT) {
163 				i--;
164 				continue;
165 			}
166 			switch(a) {
167 			case AJMP:
168 			case ARET:
169 			case AIRETL:
170 			case AIRETQ:
171 			case AIRETW:
172 			case ARETFL:
173 			case ARETFQ:
174 			case ARETFW:
175 
176 			case APUSHL:
177 			case APUSHFL:
178 			case APUSHQ:
179 			case APUSHFQ:
180 			case APUSHW:
181 			case APUSHFW:
182 			case APOPL:
183 			case APOPFL:
184 			case APOPQ:
185 			case APOPFQ:
186 			case APOPW:
187 			case APOPFW:
188 				goto brk;
189 			}
190 			if(q->pcond == P || q->pcond->mark)
191 				continue;
192 			if(a == ACALL || a == ALOOP)
193 				continue;
194 			for(;;) {
195 				if(p->as == ANOP) {
196 					p = p->link;
197 					continue;
198 				}
199 				q = copyp(p);
200 				p = p->link;
201 				q->mark = 1;
202 				lastp->link = q;
203 				lastp = q;
204 				if(q->as != a || q->pcond == P || q->pcond->mark)
205 					continue;
206 
207 				q->as = relinv(q->as);
208 				p = q->pcond;
209 				q->pcond = q->link;
210 				q->link = p;
211 				xfol(q->link);
212 				p = q->link;
213 				if(p->mark)
214 					return;
215 				goto loop;
216 			}
217 		} /* */
218 	brk:;
219 		q = prg();
220 		q->as = AJMP;
221 		q->line = p->line;
222 		q->to.type = D_BRANCH;
223 		q->to.offset = p->pc;
224 		q->pcond = p;
225 		p = q;
226 	}
227 	p->mark = 1;
228 	lastp->link = p;
229 	lastp = p;
230 	a = p->as;
231 	if(a == AJMP || a == ARET || a == AIRETL || a == AIRETQ || a == AIRETW ||
232 	   a == ARETFL || a == ARETFQ || a == ARETFW)
233 		return;
234 	if(a == ATEXT) {
235 		xfol(p->link);
236 		q = p->pcond;
237 		if(q == P || q->mark)
238 			return;
239 		p = q;
240 		goto loop;
241 	}
242 	if(p->pcond != P)
243 	if(a != ACALL) {
244 		q = brchain(p->link);
245 		if(q != P && q->mark)
246 		if(a != ALOOP && a != ATEXT) {
247 			p->as = relinv(a);
248 			p->link = p->pcond;
249 			p->pcond = q;
250 		}
251 		xfol(p->link);
252 		q = brchain(p->pcond);
253 		if(q->mark) {
254 			p->pcond = q;
255 			return;
256 		}
257 		p = q;
258 		goto loop;
259 	}
260 	p = p->link;
261 	goto loop;
262 }
263 
264 int
relinv(int a)265 relinv(int a)
266 {
267 
268 	switch(a) {
269 	case AJEQ:	return AJNE;
270 	case AJNE:	return AJEQ;
271 	case AJLE:	return AJGT;
272 	case AJLS:	return AJHI;
273 	case AJLT:	return AJGE;
274 	case AJMI:	return AJPL;
275 	case AJGE:	return AJLT;
276 	case AJPL:	return AJMI;
277 	case AJGT:	return AJLE;
278 	case AJHI:	return AJLS;
279 	case AJCS:	return AJCC;
280 	case AJCC:	return AJCS;
281 	case AJPS:	return AJPC;
282 	case AJPC:	return AJPS;
283 	case AJOS:	return AJOC;
284 	case AJOC:	return AJOS;
285 	}
286 	diag("unknown relation: %s in %s", anames[a], TNAME);
287 	return a;
288 }
289 
290 void
doinit(void)291 doinit(void)
292 {
293 	Sym *s;
294 	Prog *p;
295 	int x;
296 
297 	for(p = datap; p != P; p = p->link) {
298 		x = p->to.type;
299 		if(x != D_EXTERN && x != D_STATIC)
300 			continue;
301 		s = p->to.sym;
302 		if(s->type == 0 || s->type == SXREF)
303 			diag("undefined %s initializer of %s",
304 				s->name, p->from.sym->name);
305 		p->to.offset += s->value;
306 		p->to.type = D_CONST;
307 		if(s->type == SDATA || s->type == SBSS)
308 			p->to.offset += INITDAT;
309 	}
310 }
311 
312 void
patch(void)313 patch(void)
314 {
315 	long c;
316 	Prog *p, *q;
317 	Sym *s;
318 	long vexit;
319 
320 	if(debug['v'])
321 		Bprint(&bso, "%5.2f mkfwd\n", cputime());
322 	Bflush(&bso);
323 	mkfwd();
324 	if(debug['v'])
325 		Bprint(&bso, "%5.2f patch\n", cputime());
326 	Bflush(&bso);
327 	s = lookup("exit", 0);
328 	vexit = s->value;
329 	for(p = firstp; p != P; p = p->link) {
330 		if(p->as == ATEXT)
331 			curtext = p;
332 		if(p->as == ACALL || p->as == ARET) {
333 			s = p->to.sym;
334 			if(s) {
335 				if(debug['c'])
336 					Bprint(&bso, "%s calls %s\n", TNAME, s->name);
337 				switch(s->type) {
338 				default:
339 					/* diag prints TNAME first */
340 					diag("undefined: %s", s->name);
341 					s->type = STEXT;
342 					s->value = vexit;
343 					break;	/* or fall through to set offset? */
344 				case STEXT:
345 					p->to.offset = s->value;
346 					break;
347 				case SUNDEF:
348 					p->pcond = UP;
349 					p->to.offset = 0;
350 					break;
351 				}
352 				p->to.type = D_BRANCH;
353 			}
354 		}
355 		if(p->to.type != D_BRANCH || p->pcond == UP)
356 			continue;
357 		c = p->to.offset;
358 		for(q = firstp; q != P;) {
359 			if(q->forwd != P)
360 			if(c >= q->forwd->pc) {
361 				q = q->forwd;
362 				continue;
363 			}
364 			if(c == q->pc)
365 				break;
366 			q = q->link;
367 		}
368 		if(q == P) {
369 			diag("branch out of range in %s\n%P", TNAME, p);
370 			p->to.type = D_NONE;
371 		}
372 		p->pcond = q;
373 	}
374 
375 	for(p = firstp; p != P; p = p->link) {
376 		if(p->as == ATEXT)
377 			curtext = p;
378 		p->mark = 0;	/* initialization for follow */
379 		if(p->pcond != P && p->pcond != UP) {
380 			p->pcond = brloop(p->pcond);
381 			if(p->pcond != P)
382 			if(p->to.type == D_BRANCH)
383 				p->to.offset = p->pcond->pc;
384 		}
385 	}
386 }
387 
388 #define	LOG	5
389 void
mkfwd(void)390 mkfwd(void)
391 {
392 	Prog *p;
393 	int i;
394 	long dwn[LOG], cnt[LOG];
395 	Prog *lst[LOG];
396 
397 	for(i=0; i<LOG; i++) {
398 		if(i == 0)
399 			cnt[i] = 1; else
400 			cnt[i] = LOG * cnt[i-1];
401 		dwn[i] = 1;
402 		lst[i] = P;
403 	}
404 	i = 0;
405 	for(p = firstp; p != P; p = p->link) {
406 		if(p->as == ATEXT)
407 			curtext = p;
408 		i--;
409 		if(i < 0)
410 			i = LOG-1;
411 		p->forwd = P;
412 		dwn[i]--;
413 		if(dwn[i] <= 0) {
414 			dwn[i] = cnt[i];
415 			if(lst[i] != P)
416 				lst[i]->forwd = p;
417 			lst[i] = p;
418 		}
419 	}
420 }
421 
422 Prog*
brloop(Prog * p)423 brloop(Prog *p)
424 {
425 	int c;
426 	Prog *q;
427 
428 	c = 0;
429 	for(q = p; q != P; q = q->pcond) {
430 		if(q->as != AJMP)
431 			break;
432 		c++;
433 		if(c >= 5000)
434 			return P;
435 	}
436 	return q;
437 }
438 
439 void
dostkoff(void)440 dostkoff(void)
441 {
442 	Prog *p, *q;
443 	long autoffset, deltasp;
444 	int a, f, curframe, curbecome, maxbecome, pcsize;
445 
446 	curframe = 0;
447 	curbecome = 0;
448 	maxbecome = 0;
449 	curtext = 0;
450 	for(p = firstp; p != P; p = p->link) {
451 
452 		/* find out how much arg space is used in this TEXT */
453 		if(p->to.type == (D_INDIR+D_SP))
454 			if(p->to.offset > curframe)
455 				curframe = p->to.offset;
456 
457 		switch(p->as) {
458 		case ATEXT:
459 			if(curtext && curtext->from.sym) {
460 				curtext->from.sym->frame = curframe;
461 				curtext->from.sym->become = curbecome;
462 				if(curbecome > maxbecome)
463 					maxbecome = curbecome;
464 			}
465 			curframe = 0;
466 			curbecome = 0;
467 
468 			curtext = p;
469 			break;
470 
471 		case ARET:
472 			/* special form of RET is BECOME */
473 			if(p->from.type == D_CONST)
474 				if(p->from.offset > curbecome)
475 					curbecome = p->from.offset;
476 			break;
477 		}
478 	}
479 	if(curtext && curtext->from.sym) {
480 		curtext->from.sym->frame = curframe;
481 		curtext->from.sym->become = curbecome;
482 		if(curbecome > maxbecome)
483 			maxbecome = curbecome;
484 	}
485 
486 	if(debug['b'])
487 		print("max become = %d\n", maxbecome);
488 	xdefine("ALEFbecome", STEXT, maxbecome);
489 
490 	curtext = 0;
491 	for(p = firstp; p != P; p = p->link) {
492 		switch(p->as) {
493 		case ATEXT:
494 			curtext = p;
495 			break;
496 		case ACALL:
497 			if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
498 				f = maxbecome - curtext->from.sym->frame;
499 				if(f <= 0)
500 					break;
501 				/* calling a become or calling a variable */
502 				if(p->to.sym == S || p->to.sym->become) {
503 					curtext->to.offset += f;
504 					if(debug['b']) {
505 						curp = p;
506 						print("%D calling %D increase %d\n",
507 							&curtext->from, &p->to, f);
508 					}
509 				}
510 			}
511 			break;
512 		}
513 	}
514 
515 	autoffset = 0;
516 	deltasp = 0;
517 	for(p = firstp; p != P; p = p->link) {
518 		if(p->as == ATEXT) {
519 			curtext = p;
520 			autoffset = p->to.offset;
521 			if(autoffset < 0)
522 				autoffset = 0;
523 			if(autoffset) {
524 				p = appendp(p);
525 				p->as = AADJSP;
526 				p->from.type = D_CONST;
527 				p->from.offset = autoffset;
528 			}
529 			deltasp = autoffset;
530 		}
531 		pcsize = p->mode/8;
532 		a = p->from.type;
533 		if(a == D_AUTO)
534 			p->from.offset += deltasp;
535 		if(a == D_PARAM)
536 			p->from.offset += deltasp + pcsize;
537 		a = p->to.type;
538 		if(a == D_AUTO)
539 			p->to.offset += deltasp;
540 		if(a == D_PARAM)
541 			p->to.offset += deltasp + pcsize;
542 
543 		switch(p->as) {
544 		default:
545 			continue;
546 		case APUSHL:
547 		case APUSHFL:
548 			deltasp += 4;
549 			continue;
550 		case APUSHQ:
551 		case APUSHFQ:
552 			deltasp += 8;
553 			continue;
554 		case APUSHW:
555 		case APUSHFW:
556 			deltasp += 2;
557 			continue;
558 		case APOPL:
559 		case APOPFL:
560 			deltasp -= 4;
561 			continue;
562 		case APOPQ:
563 		case APOPFQ:
564 			deltasp -= 8;
565 			continue;
566 		case APOPW:
567 		case APOPFW:
568 			deltasp -= 2;
569 			continue;
570 		case ARET:
571 			break;
572 		}
573 
574 		if(autoffset != deltasp)
575 			diag("unbalanced PUSH/POP");
576 		if(p->from.type == D_CONST)
577 			goto become;
578 
579 		if(autoffset) {
580 			q = p;
581 			p = appendp(p);
582 			p->as = ARET;
583 
584 			q->as = AADJSP;
585 			q->from.type = D_CONST;
586 			q->from.offset = -autoffset;
587 		}
588 		continue;
589 
590 	become:
591 		q = p;
592 		p = appendp(p);
593 		p->as = AJMP;
594 		p->to = q->to;
595 		p->pcond = q->pcond;
596 
597 		q->as = AADJSP;
598 		q->from = zprg.from;
599 		q->from.type = D_CONST;
600 		q->from.offset = -autoffset;
601 		q->to = zprg.to;
602 		continue;
603 	}
604 }
605 
606 vlong
atolwhex(char * s)607 atolwhex(char *s)
608 {
609 	vlong n;
610 	int f;
611 
612 	n = 0;
613 	f = 0;
614 	while(*s == ' ' || *s == '\t')
615 		s++;
616 	if(*s == '-' || *s == '+') {
617 		if(*s++ == '-')
618 			f = 1;
619 		while(*s == ' ' || *s == '\t')
620 			s++;
621 	}
622 	if(s[0]=='0' && s[1]){
623 		if(s[1]=='x' || s[1]=='X'){
624 			s += 2;
625 			for(;;){
626 				if(*s >= '0' && *s <= '9')
627 					n = n*16 + *s++ - '0';
628 				else if(*s >= 'a' && *s <= 'f')
629 					n = n*16 + *s++ - 'a' + 10;
630 				else if(*s >= 'A' && *s <= 'F')
631 					n = n*16 + *s++ - 'A' + 10;
632 				else
633 					break;
634 			}
635 		} else
636 			while(*s >= '0' && *s <= '7')
637 				n = n*8 + *s++ - '0';
638 	} else
639 		while(*s >= '0' && *s <= '9')
640 			n = n*10 + *s++ - '0';
641 	if(f)
642 		n = -n;
643 	return n;
644 }
645 
646 void
undef(void)647 undef(void)
648 {
649 	int i;
650 	Sym *s;
651 
652 	for(i=0; i<NHASH; i++)
653 	for(s = hash[i]; s != S; s = s->link)
654 		if(s->type == SXREF)
655 			diag("%s: not defined", s->name);
656 }
657 
658 void
import(void)659 import(void)
660 {
661 	int i;
662 	Sym *s;
663 
664 	for(i = 0; i < NHASH; i++)
665 		for(s = hash[i]; s != S; s = s->link)
666 			if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
667 				if(s->value != 0)
668 					diag("value != 0 on SXREF");
669 				undefsym(s);
670 				if(debug['X'])
671 					Bprint(&bso, "IMPORT: %s sig=%lux v=%lld\n", s->name, s->sig, s->value);
672 				if(debug['S'])
673 					s->sig = 0;
674 			}
675 }
676 
677 void
ckoff(Sym * s,long v)678 ckoff(Sym *s, long v)
679 {
680 	if(v < 0 || v >= 1<<Roffset)
681 		diag("relocation offset %ld for %s out of range", v, s->name);
682 }
683 
684 static Prog*
newdata(Sym * s,int o,int w,int t)685 newdata(Sym *s, int o, int w, int t)
686 {
687 	Prog *p;
688 
689 	p = prg();
690 	if(edatap == P)
691 		datap = p;
692 	else
693 		edatap->link = p;
694 	edatap = p;
695 	p->as = ADATA;
696 	p->width = w;
697 	p->from.scale = w;
698 	p->from.type = t;
699 	p->from.sym = s;
700 	p->from.offset = o;
701 	p->to.type = D_CONST;
702 	return p;
703 }
704 
705 void
export(void)706 export(void)
707 {
708 	int i, j, n, off, nb, sv, ne;
709 	Sym *s, *et, *str, **esyms;
710 	Prog *p;
711 	char buf[NSNAME], *t;
712 
713 	n = 0;
714 	for(i = 0; i < NHASH; i++)
715 		for(s = hash[i]; s != S; s = s->link)
716 			if(s->type != SXREF && s->type != SUNDEF && (nexports == 0 && s->sig != 0 || s->subtype == SEXPORT || allexport))
717 				n++;
718 	esyms = malloc(n*sizeof(Sym*));
719 	ne = n;
720 	n = 0;
721 	for(i = 0; i < NHASH; i++)
722 		for(s = hash[i]; s != S; s = s->link)
723 			if(s->type != SXREF && s->type != SUNDEF && (nexports == 0 && s->sig != 0 || s->subtype == SEXPORT || allexport))
724 				esyms[n++] = s;
725 	for(i = 0; i < ne-1; i++)
726 		for(j = i+1; j < ne; j++)
727 			if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
728 				s = esyms[i];
729 				esyms[i] = esyms[j];
730 				esyms[j] = s;
731 			}
732 
733 	nb = 0;
734 	off = 0;
735 	et = lookup(EXPTAB, 0);
736 	if(et->type != 0 && et->type != SXREF)
737 		diag("%s already defined", EXPTAB);
738 	et->type = SDATA;
739 	str = lookup(".string", 0);
740 	if(str->type == 0)
741 		str->type = SDATA;
742 	sv = str->value;
743 	for(i = 0; i < ne; i++){
744 		s = esyms[i];
745 		if(debug['S'])
746 			s->sig = 0;
747 		/* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
748 
749 		/* signature */
750 		p = newdata(et, off, sizeof(long), D_EXTERN);
751 		off += sizeof(long);
752 		p->to.offset = s->sig;
753 
754 		/* address */
755 		p = newdata(et, off, sizeof(long), D_EXTERN);
756 		off += sizeof(long);
757 		p->to.type = D_ADDR;
758 		p->to.index = D_EXTERN;
759 		p->to.sym = s;
760 
761 		/* string */
762 		t = s->name;
763 		n = strlen(t)+1;
764 		for(;;){
765 			buf[nb++] = *t;
766 			sv++;
767 			if(nb >= NSNAME){
768 				p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
769 				p->to.type = D_SCONST;
770 				memmove(p->to.scon, buf, NSNAME);
771 				nb = 0;
772 			}
773 			if(*t++ == 0)
774 				break;
775 		}
776 
777 		/* name */
778 		p = newdata(et, off, sizeof(long), D_EXTERN);
779 		off += sizeof(long);
780 		p->to.type = D_ADDR;
781 		p->to.index = D_STATIC;
782 		p->to.sym = str;
783 		p->to.offset = sv-n;
784 	}
785 
786 	if(nb > 0){
787 		p = newdata(str, sv-nb, nb, D_STATIC);
788 		p->to.type = D_SCONST;
789 		memmove(p->to.scon, buf, nb);
790 	}
791 
792 	for(i = 0; i < 3; i++){
793 		newdata(et, off, sizeof(long), D_EXTERN);
794 		off += sizeof(long);
795 	}
796 	et->value = off;
797 	if(sv == 0)
798 		sv = 1;
799 	str->value = sv;
800 	exports = ne;
801 	free(esyms);
802 }
803