xref: /inferno-os/utils/ql/pass.c (revision ecc9caba0e344ed50c05ee8156b2734f4d76e463)
1 #include	"l.h"
2 
3 void
4 dodata(void)
5 {
6 	int i, t;
7 	Sym *s;
8 	Prog *p, *p1;
9 	long orig, orig1, v;
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 		v = p->from.offset + p->reg;
24 		if(v > s->value)
25 			diag("initialize bounds (%ld): %s\n%P",
26 				s->value, s->name, p);
27 	}
28 
29 	/*
30 	 * pass 1
31 	 *	assign 'small' variables to data segment
32 	 *	(rational is that data segment is more easily
33 	 *	 addressed through offset on REGSB)
34 	 */
35 	orig = 0;
36 	for(i=0; i<NHASH; i++)
37 	for(s = hash[i]; s != S; s = s->link) {
38 		t = s->type;
39 		if(t != SDATA && t != SBSS)
40 			continue;
41 		v = s->value;
42 		if(v == 0) {
43 			diag("%s: no size", s->name);
44 			v = 1;
45 		}
46 		while(v & 3)
47 			v++;
48 		s->value = v;
49 		if(v > MINSIZ)
50 			continue;
51 		if(v >= 8)
52 			while(orig & 7)
53 				orig++;
54 		s->value = orig;
55 		orig += v;
56 		s->type = SDATA1;
57 	}
58 	orig1 = orig;
59 
60 	/*
61 	 * pass 2
62 	 *	assign 'data' variables to data segment
63 	 */
64 	for(i=0; i<NHASH; i++)
65 	for(s = hash[i]; s != S; s = s->link) {
66 		t = s->type;
67 		if(t != SDATA) {
68 			if(t == SDATA1)
69 				s->type = SDATA;
70 			continue;
71 		}
72 		v = s->value;
73 		if(v >= 8)
74 			while(orig & 7)
75 				orig++;
76 		s->value = orig;
77 		orig += v;
78 		s->type = SDATA1;
79 	}
80 
81 	while(orig & 7)
82 		orig++;
83 	datsize = orig;
84 
85 	/*
86 	 * pass 3
87 	 *	everything else to bss segment
88 	 */
89 	for(i=0; i<NHASH; i++)
90 	for(s = hash[i]; s != S; s = s->link) {
91 		if(s->type != SBSS)
92 			continue;
93 		v = s->value;
94 		if(v >= 8)
95 			while(orig & 7)
96 				orig++;
97 		s->value = orig;
98 		orig += v;
99 	}
100 	while(orig & 7)
101 		orig++;
102 	bsssize = orig-datsize;
103 
104 	/*
105 	 * pass 4
106 	 *	add literals to all large values.
107 	 *	at this time:
108 	 *		small data is allocated DATA
109 	 *		large data is allocated DATA1
110 	 *		large bss is allocated BSS
111 	 *	the new literals are loaded between
112 	 *	small data and large data.
113 	 */
114 	orig = 0;
115 	for(p = firstp; p != P; p = p->link) {
116 		if(p->as != AMOVW)
117 			continue;
118 		if(p->from.type != D_CONST)
119 			continue;
120 		if(s = p->from.sym) {
121 			t = s->type;
122 			if(t != SDATA && t != SDATA1 && t != SBSS)
123 				continue;
124 			t = p->from.name;
125 			if(t != D_EXTERN && t != D_STATIC)
126 				continue;
127 			v = s->value + p->from.offset;
128 			if(v >= 0 && v <= 0xffff)
129 				continue;
130 			if(!strcmp(s->name, "setSB"))
131 				continue;
132 			/* size should be 19 max */
133 			if(strlen(s->name) >= 10)	/* has loader address */
134 				sprint(literal, "$%p.%lux", s, p->from.offset);
135 			else
136 				sprint(literal, "$%s.%d.%lux", s->name, s->version, p->from.offset);
137 		} else {
138 			if(p->from.name != D_NONE)
139 				continue;
140 			if(p->from.reg != NREG)
141 				continue;
142 			v = p->from.offset;
143 			if(v >= -0x7fff-1 && v <= 0x7fff)
144 				continue;
145 			if(!(v & 0xffff))
146 				continue;
147 			if(v)
148 				continue;	/* quicker to build it than load it */
149 			/* size should be 9 max */
150 			sprint(literal, "$%lux", v);
151 		}
152 		s = lookup(literal, 0);
153 		if(s->type == 0) {
154 			s->type = SDATA;
155 			s->value = orig1+orig;
156 			orig += 4;
157 			p1 = prg();
158 			p1->as = ADATA;
159 			p1->line = p->line;
160 			p1->from.type = D_OREG;
161 			p1->from.sym = s;
162 			p1->from.name = D_EXTERN;
163 			p1->reg = 4;
164 			p1->to = p->from;
165 			p1->link = datap;
166 			datap = p1;
167 		}
168 		if(s->type != SDATA)
169 			diag("literal not data: %s", s->name);
170 		p->from.type = D_OREG;
171 		p->from.sym = s;
172 		p->from.name = D_EXTERN;
173 		p->from.offset = 0;
174 		continue;
175 	}
176 	while(orig & 7)
177 		orig++;
178 	/*
179 	 * pass 5
180 	 *	re-adjust offsets
181 	 */
182 	for(i=0; i<NHASH; i++)
183 	for(s = hash[i]; s != S; s = s->link) {
184 		t = s->type;
185 		if(t == SBSS) {
186 			s->value += orig;
187 			continue;
188 		}
189 		if(t == SDATA1) {
190 			s->type = SDATA;
191 			s->value += orig;
192 			continue;
193 		}
194 	}
195 	datsize += orig;
196 	xdefine("setSB", SDATA, 0L+BIG);
197 	xdefine("bdata", SDATA, 0L);
198 	xdefine("edata", SDATA, datsize);
199 	xdefine("end", SBSS, datsize+bsssize);
200 	xdefine("etext", STEXT, 0L);
201 }
202 
203 void
204 undef(void)
205 {
206 	int i;
207 	Sym *s;
208 
209 	for(i=0; i<NHASH; i++)
210 	for(s = hash[i]; s != S; s = s->link)
211 		if(s->type == SXREF)
212 			diag("%s: not defined", s->name);
213 }
214 
215 int
216 relinv(int a)
217 {
218 
219 	switch(a) {
220 	case ABEQ:	return ABNE;
221 	case ABNE:	return ABEQ;
222 
223 	case ABGE:	return ABLT;
224 	case ABLT:	return ABGE;
225 
226 	case ABGT:	return ABLE;
227 	case ABLE:	return ABGT;
228 
229 	case ABVC:	return ABVS;
230 	case ABVS:	return ABVC;
231 	}
232 	return 0;
233 }
234 
235 void
236 follow(void)
237 {
238 
239 	if(debug['v'])
240 		Bprint(&bso, "%5.2f follow\n", cputime());
241 	Bflush(&bso);
242 
243 	firstp = prg();
244 	lastp = firstp;
245 
246 	xfol(textp);
247 
248 	firstp = firstp->link;
249 	lastp->link = P;
250 }
251 
252 void
253 xfol(Prog *p)
254 {
255 	Prog *q, *r;
256 	int a, b, i;
257 
258 loop:
259 	if(p == P)
260 		return;
261 	a = p->as;
262 	if(a == ATEXT)
263 		curtext = p;
264 	if(a == ABR) {
265 		q = p->cond;
266 		if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){
267 			p->mark |= FOLL;
268 			lastp->link = p;
269 			lastp = p;
270 			p = p->link;
271 			xfol(p);
272 			p = q;
273 			if(p && !(p->mark & FOLL))
274 				goto loop;
275 			return;
276 		}
277 		if(q != P) {
278 			p->mark |= FOLL;
279 			p = q;
280 			if(!(p->mark & FOLL))
281 				goto loop;
282 		}
283 	}
284 	if(p->mark & FOLL) {
285 		for(i=0,q=p; i<4; i++,q=q->link) {
286 			if(q == lastp || (q->mark&NOSCHED))
287 				break;
288 			b = 0;		/* set */
289 			a = q->as;
290 			if(a == ANOP) {
291 				i--;
292 				continue;
293 			}
294 			if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI)
295 				goto copy;
296 			if(!q->cond || (q->cond->mark&FOLL))
297 				continue;
298 			b = relinv(a);
299 			if(!b)
300 				continue;
301 		copy:
302 			for(;;) {
303 				r = prg();
304 				*r = *p;
305 				if(!(r->mark&FOLL))
306 					print("cant happen 1\n");
307 				r->mark |= FOLL;
308 				if(p != q) {
309 					p = p->link;
310 					lastp->link = r;
311 					lastp = r;
312 					continue;
313 				}
314 				lastp->link = r;
315 				lastp = r;
316 				if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI)
317 					return;
318 				r->as = b;
319 				r->cond = p->link;
320 				r->link = p->cond;
321 				if(!(r->link->mark&FOLL))
322 					xfol(r->link);
323 				if(!(r->cond->mark&FOLL))
324 					print("cant happen 2\n");
325 				return;
326 			}
327 		}
328 
329 		a = ABR;
330 		q = prg();
331 		q->as = a;
332 		q->line = p->line;
333 		q->to.type = D_BRANCH;
334 		q->to.offset = p->pc;
335 		q->cond = p;
336 		p = q;
337 	}
338 	p->mark |= FOLL;
339 	lastp->link = p;
340 	lastp = p;
341 	if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI){
342 		if(p->mark & NOSCHED){
343 			p = p->link;
344 			goto loop;
345 		}
346 		return;
347 	}
348 	if(p->cond != P)
349 	if(a != ABL && p->link != P) {
350 		xfol(p->link);
351 		p = p->cond;
352 		if(p == P || (p->mark&FOLL))
353 			return;
354 		goto loop;
355 	}
356 	p = p->link;
357 	goto loop;
358 }
359 
360 void
361 patch(void)
362 {
363 	long c, vexit;
364 	Prog *p, *q;
365 	Sym *s;
366 	int a;
367 
368 	if(debug['v'])
369 		Bprint(&bso, "%5.2f patch\n", cputime());
370 	Bflush(&bso);
371 	mkfwd();
372 	s = lookup("exit", 0);
373 	vexit = s->value;
374 	for(p = firstp; p != P; p = p->link) {
375 		a = p->as;
376 		if(a == ATEXT)
377 			curtext = p;
378 		if((a == ABL || a == ARETURN) && p->to.sym != S) {
379 			s = p->to.sym;
380 			if(s->type != STEXT && s->type != SUNDEF) {
381 				diag("undefined: %s\n%P", s->name, p);
382 				s->type = STEXT;
383 				s->value = vexit;
384 			}
385 			if(s->type == SUNDEF){
386 				p->to.offset = 0;
387 				p->cond = UP;
388 			}
389 			else
390 				p->to.offset = s->value;
391 			p->to.type = D_BRANCH;
392 		}
393 		if(p->to.type != D_BRANCH || p->cond == UP)
394 			continue;
395 		c = p->to.offset;
396 		for(q = firstp; q != P;) {
397 			if(q->forwd != P)
398 			if(c >= q->forwd->pc) {
399 				q = q->forwd;
400 				continue;
401 			}
402 			if(c == q->pc)
403 				break;
404 			q = q->link;
405 		}
406 		if(q == P) {
407 			diag("branch out of range %ld\n%P", c, p);
408 			p->to.type = D_NONE;
409 		}
410 		p->cond = q;
411 	}
412 
413 	for(p = firstp; p != P; p = p->link) {
414 		if(p->as == ATEXT)
415 			curtext = p;
416 		p->mark = 0;	/* initialization for follow */
417 		if(p->cond != P && p->cond != UP) {
418 			p->cond = brloop(p->cond);
419 			if(p->cond != P)
420 			if(p->to.type == D_BRANCH)
421 				p->to.offset = p->cond->pc;
422 		}
423 	}
424 }
425 
426 #define	LOG	5
427 void
428 mkfwd(void)
429 {
430 	Prog *p;
431 	long dwn[LOG], cnt[LOG], i;
432 	Prog *lst[LOG];
433 
434 	for(i=0; i<LOG; i++) {
435 		if(i == 0)
436 			cnt[i] = 1; else
437 			cnt[i] = LOG * cnt[i-1];
438 		dwn[i] = 1;
439 		lst[i] = P;
440 	}
441 	i = 0;
442 	for(p = firstp; p != P; p = p->link) {
443 		if(p->as == ATEXT)
444 			curtext = p;
445 		i--;
446 		if(i < 0)
447 			i = LOG-1;
448 		p->forwd = P;
449 		dwn[i]--;
450 		if(dwn[i] <= 0) {
451 			dwn[i] = cnt[i];
452 			if(lst[i] != P)
453 				lst[i]->forwd = p;
454 			lst[i] = p;
455 		}
456 	}
457 }
458 
459 Prog*
460 brloop(Prog *p)
461 {
462 	Prog *q;
463 	int c;
464 
465 	for(c=0; p!=P;) {
466 		if(p->as != ABR || (p->mark&NOSCHED))
467 			return p;
468 		q = p->cond;
469 		if(q <= p) {
470 			c++;
471 			if(q == p || c > 5000)
472 				break;
473 		}
474 		p = q;
475 	}
476 	return P;
477 }
478 
479 long
480 atolwhex(char *s)
481 {
482 	long n;
483 	int f;
484 
485 	n = 0;
486 	f = 0;
487 	while(*s == ' ' || *s == '\t')
488 		s++;
489 	if(*s == '-' || *s == '+') {
490 		if(*s++ == '-')
491 			f = 1;
492 		while(*s == ' ' || *s == '\t')
493 			s++;
494 	}
495 	if(s[0]=='0' && s[1]){
496 		if(s[1]=='x' || s[1]=='X'){
497 			s += 2;
498 			for(;;){
499 				if(*s >= '0' && *s <= '9')
500 					n = n*16 + *s++ - '0';
501 				else if(*s >= 'a' && *s <= 'f')
502 					n = n*16 + *s++ - 'a' + 10;
503 				else if(*s >= 'A' && *s <= 'F')
504 					n = n*16 + *s++ - 'A' + 10;
505 				else
506 					break;
507 			}
508 		} else
509 			while(*s >= '0' && *s <= '7')
510 				n = n*8 + *s++ - '0';
511 	} else
512 		while(*s >= '0' && *s <= '9')
513 			n = n*10 + *s++ - '0';
514 	if(f)
515 		n = -n;
516 	return n;
517 }
518 
519 long
520 rnd(long v, long r)
521 {
522 	long c;
523 
524 	if(r <= 0)
525 		return v;
526 	v += r - 1;
527 	c = v % r;
528 	if(c < 0)
529 		c += r;
530 	v -= c;
531 	return v;
532 }
533 
534 void
535 import(void)
536 {
537 	int i;
538 	Sym *s;
539 
540 	for(i = 0; i < NHASH; i++)
541 		for(s = hash[i]; s != S; s = s->link)
542 			if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
543 				undefsym(s);
544 				Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value);
545 			}
546 }
547 
548 void
549 ckoff(Sym *s, long v)
550 {
551 	if(v < 0 || v >= 1<<Roffset)
552 		diag("relocation offset %ld for %s out of range", v, s->name);
553 }
554 
555 static Prog*
556 newdata(Sym *s, int o, int w, int t)
557 {
558 	Prog *p;
559 
560 	p = prg();
561 	p->link = datap;
562 	datap = p;
563 	p->as = ADATA;
564 	p->reg = w;
565 	p->from.type = D_OREG;
566 	p->from.name = t;
567 	p->from.sym = s;
568 	p->from.offset = o;
569 	p->to.type = D_CONST;
570 	p->to.name = D_NONE;
571 	return p;
572 }
573 
574 void
575 export(void)
576 {
577 	int i, j, n, off, nb, sv, ne;
578 	Sym *s, *et, *str, **esyms;
579 	Prog *p;
580 	char buf[NSNAME], *t;
581 
582 	n = 0;
583 	for(i = 0; i < NHASH; i++)
584 		for(s = hash[i]; s != S; s = s->link)
585 			if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
586 				n++;
587 	esyms = malloc(n*sizeof(Sym*));
588 	ne = n;
589 	n = 0;
590 	for(i = 0; i < NHASH; i++)
591 		for(s = hash[i]; s != S; s = s->link)
592 			if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
593 				esyms[n++] = s;
594 	for(i = 0; i < ne-1; i++)
595 		for(j = i+1; j < ne; j++)
596 			if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
597 				s = esyms[i];
598 				esyms[i] = esyms[j];
599 				esyms[j] = s;
600 			}
601 
602 	nb = 0;
603 	off = 0;
604 	et = lookup(EXPTAB, 0);
605 	if(et->type != 0 && et->type != SXREF)
606 		diag("%s already defined", EXPTAB);
607 	et->type = SDATA;
608 	str = lookup(".string", 0);
609 	if(str->type == 0)
610 		str->type = SDATA;
611 	sv = str->value;
612 	for(i = 0; i < ne; i++){
613 		s = esyms[i];
614 		Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type);
615 
616 		/* signature */
617 		p = newdata(et, off, sizeof(long), D_EXTERN);
618 		off += sizeof(long);
619 		p->to.offset = s->sig;
620 
621 		/* address */
622 		p = newdata(et, off, sizeof(long), D_EXTERN);
623 		off += sizeof(long);
624 		p->to.name = D_EXTERN;
625 		p->to.sym = s;
626 
627 		/* string */
628 		t = s->name;
629 		n = strlen(t)+1;
630 		for(;;){
631 			buf[nb++] = *t;
632 			sv++;
633 			if(nb >= NSNAME){
634 				p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
635 				p->to.type = D_SCONST;
636 				memmove(p->to.sval, buf, NSNAME);
637 				nb = 0;
638 			}
639 			if(*t++ == 0)
640 				break;
641 		}
642 
643 		/* name */
644 		p = newdata(et, off, sizeof(long), D_EXTERN);
645 		off += sizeof(long);
646 		p->to.name = D_STATIC;
647 		p->to.sym = str;
648 		p->to.offset = sv-n;
649 	}
650 
651 	if(nb > 0){
652 		p = newdata(str, sv-nb, nb, D_STATIC);
653 		p->to.type = D_SCONST;
654 		memmove(p->to.sval, buf, nb);
655 	}
656 
657 	for(i = 0; i < 3; i++){
658 		newdata(et, off, sizeof(long), D_EXTERN);
659 		off += sizeof(long);
660 	}
661 	et->value = off;
662 	if(sv == 0)
663 		sv = 1;
664 	str->value = sv;
665 	exports = ne;
666 	free(esyms);
667 }
668