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