xref: /inferno-os/utils/il/span.c (revision 871e0f01ca6cdef953c81d1a5018d90fbd01838a)
1 #include	"l.h"
2 
3 void
4 span(void)
5 {
6 	Prog *p, *q;
7 	Sym *setext, *s;
8 	Optab *o;
9 	int m, bflag, i, spass;
10 	long c, otxt, v;
11 
12 	if(debug['v'])
13 		Bprint(&bso, "%5.2f span\n", cputime());
14 	Bflush(&bso);
15 
16 	bflag = 0;
17 	c = 0;
18 	otxt = c;
19 	for(p = firstp; p != P; p = p->link) {
20 		if(p->as == ATEXT)
21 			c = (c + 3) & ~3;
22 		p->pc = c;
23 		o = oplook(p);
24 		m = o->size;
25 		if(!debug['c']){
26 			if(o->ctype && asmout(p, o, 2) == 2){
27 				bflag = 1;
28 				p->mark |= COMPR;
29 				m = 2;
30 			}
31 		}
32 		if(m == 0) {
33 			if(p->as == ATEXT) {
34 				curtext = p;
35 				autosize = p->to.offset + ptrsize;
36 				if(p->from.sym != S)
37 					p->from.sym->value = c;
38 				/* need passes to resolve branches */
39 				if(c-otxt >= 0x1000)
40 					bflag = 1;
41 				otxt = c;
42 				continue;
43 			}
44 			diag("zero-width instruction\n%P", p);
45 			continue;
46 		}
47 		c += m;
48 	}
49 
50 	/*
51 	 * Multi-pass expansion of span dependent instructions
52 	 *   Bcond JAL C.Bcond C.JAL C.JMP
53 	 */
54 	spass = 0;
55 	while(bflag) {
56 		if(debug['v'])
57 			Bprint(&bso, "%5.2f span1\n", cputime());
58 		bflag = 0;
59 		spass ^= SPASS;
60 		c = 0;
61 		for(p = firstp; p != P; p = p->link) {
62 			o = oplook(p);
63 			m = o->size;
64 			if(p->mark&COMPR)
65 				m = 2;
66 			if((o->type == 3 || o->type == 4) && p->cond) {
67 				if((p->cond->mark&SPASS) == spass)
68 					p->pc = c;
69 				if(m == 2){
70 					/*
71 					 * If instruction was compressed, check again in case
72 					 * branch range is now too large.
73 					 */
74 					m = asmout(p, o, 3);
75 					if(m != 2){
76 						p->mark &= ~COMPR;
77 						bflag = 1;
78 					}
79 				}
80 				otxt = p->cond->pc - p->pc;
81 				if(otxt < 0)
82 					otxt = -otxt;
83 				if(o->type == 3){
84 					/*
85 					 * If Bcond branch range exceeds 4K, replace it by the
86 					 * logically negated branch around a JMP.
87 					*/
88 					if(otxt >= 0x1000) {
89 						q = prg();
90 						q->link = p->link;
91 						q->line = p->line;
92 						q->as = AJMP;
93 						q->to.type = D_BRANCH;
94 						q->cond = p->cond;
95 						p->link = q;
96 						p->as = relinv(p->as);
97 						p->cond = q->link;
98 						p->optab = 0;
99 						o = oplook(p);
100 						q->mark = spass ^ SPASS;
101 						m = asmout(p, o, 2);
102 						if(m == 2)
103 							p->mark |= COMPR;
104 						q->pc = p->pc + m;
105 						bflag = 1;
106 					}
107 				}else{
108 					/*
109 					 * If JAL branch range exceeds 1M, change address class
110 					 * and recalculate instruction length.
111 					 */
112 					if(otxt >= 0x100000) {
113 						p->to.class = C_LBRA + 1;
114 						p->optab = 0;
115 						o = oplook(p);
116 						m = asmout(p, o, 3);
117 						p->mark &= ~COMPR;
118 					}
119 				}
120 			}
121 			if(p->as == ATEXT)
122 				c = (c + 3) & ~3;
123 			p->pc = c;
124 			p->mark ^= SPASS;
125 			if(m == 0) {
126 				if(p->as == ATEXT) {
127 					curtext = p;
128 					autosize = p->to.offset + ptrsize;
129 					if(p->from.sym != S)
130 						p->from.sym->value = c;
131 					continue;
132 				}
133 				diag("zero-width instruction\n%P", p);
134 				continue;
135 			}
136 			c += m;
137 		}
138 	}
139 
140 	if(debug['t']) {
141 		/*
142 		 * add strings to text segment
143 		 */
144 		c = rnd(c, 8);
145 		for(i=0; i<NHASH; i++)
146 		for(s = hash[i]; s != S; s = s->link) {
147 			if(s->type != SSTRING)
148 				continue;
149 			v = s->value;
150 			while(v & 3)
151 				v++;
152 			s->value = c;
153 			c += v;
154 		}
155 	}
156 
157 	c = rnd(c, 8);
158 
159 	setext = lookup("etext", 0);
160 	if(setext != S) {
161 		setext->value = c;
162 		textsize = c;
163 	}
164 	if(INITRND)
165 		INITDAT = rnd(INITTEXT + c, INITRND);
166 	if(debug['v'])
167 		Bprint(&bso, "tsize = %lux\n", textsize);
168 	Bflush(&bso);
169 }
170 
171 void
172 xdefine(char *p, int t, long v)
173 {
174 	Sym *s;
175 
176 	s = lookup(p, 0);
177 	if(s->type == 0 || s->type == SXREF) {
178 		s->type = t;
179 		s->value = v;
180 	}
181 }
182 
183 long
184 regoff(Adr *a)
185 {
186 
187 	instoffset = 0;
188 	a->class = aclass(a) + 1;
189 	return instoffset;
190 }
191 
192 int
193 classreg(Adr *a)
194 {
195 	if(a->reg == NREG) {
196 		switch(a->class - 1) {
197 		case C_SEXT:
198 		case C_SECON:
199 		case C_LECON:
200 			return REGSB;
201 		case C_SAUTO:
202 		case C_LAUTO:
203 		case C_SACON:
204 		case C_LACON:
205 			return REGSP;
206 		}
207 	}
208 	return a->reg;
209 }
210 
211 int
212 aclass(Adr *a)
213 {
214 	Sym *s;
215 	int t;
216 
217 	switch(a->type) {
218 	case D_NONE:
219 		return C_NONE;
220 
221 	case D_REG:
222 		return C_REG;
223 
224 	case D_CTLREG:
225 		return C_CTLREG;
226 
227 	case D_FREG:
228 		return C_FREG;
229 
230 	case D_OREG:
231 		switch(a->name) {
232 		case D_EXTERN:
233 		case D_STATIC:
234 			if(a->sym == 0 || a->sym->name == 0) {
235 				print("null sym external\n");
236 				print("%D\n", a);
237 				return C_GOK;
238 			}
239 			t = a->sym->type;
240 			if(t == 0 || t == SXREF) {
241 				diag("undefined external: %s in %s",
242 					a->sym->name, TNAME);
243 				a->sym->type = SDATA;
244 			}
245 			instoffset = a->sym->value + a->offset - BIG;
246 			if(instoffset >= -BIG && instoffset < BIG)
247 				return C_SEXT;
248 			return C_LEXT;
249 		case D_AUTO:
250 			instoffset = autosize + a->offset;
251 			if(instoffset >= -BIG && instoffset < BIG)
252 				return C_SAUTO;
253 			return C_LAUTO;
254 
255 		case D_PARAM:
256 			instoffset = autosize + a->offset + ptrsize;
257 			if(instoffset >= -BIG && instoffset < BIG)
258 				return C_SAUTO;
259 			return C_LAUTO;
260 		case D_NONE:
261 			instoffset = a->offset;
262 			if(instoffset == 0)
263 				return C_ZOREG;
264 			if(instoffset >= -BIG && instoffset < BIG)
265 				return C_SOREG;
266 			return C_LOREG;
267 		}
268 		return C_GOK;
269 
270 	case D_FCONST:
271 		return C_FCON;
272 
273 	case D_VCONST:
274 		return C_VCON;
275 
276 	case D_CONST:
277 		switch(a->name) {
278 
279 		case D_NONE:
280 			instoffset = a->offset;
281 			if(a->reg != NREG && a->reg != REGZERO){
282 				if(instoffset >= -BIG && instoffset < BIG)
283 					return C_SRCON;
284 				return C_LRCON;
285 			}
286 		consize:
287 			if(instoffset == 0)
288 				return C_ZCON;
289 			if(instoffset >= -0x800 && instoffset <= 0x7ff)
290 				return C_SCON;
291 			if((instoffset & 0xfff) == 0)
292 				return C_UCON;
293 			return C_LCON;
294 
295 		case D_EXTERN:
296 		case D_STATIC:
297 			instoffx = 0;
298 			s = a->sym;
299 			if(s == S)
300 				break;
301 			t = s->type;
302 			switch(t) {
303 			case 0:
304 			case SXREF:
305 				diag("undefined external: %s in %s",
306 					s->name, TNAME);
307 				s->type = SDATA;
308 				break;
309 			case SCONST:
310 				instoffset = s->value + a->offset;
311 				goto consize;
312 			case STEXT:
313 			case SLEAF:
314 			case SSTRING:
315 				instoffset = s->value + a->offset;
316 				instoffx = INITTEXT;
317 				return C_LECON;
318 			}
319 			instoffset = s->value + a->offset - BIG;
320 			if(instoffset >= -BIG && instoffset < BIG && instoffset != 0L)
321 				return C_SECON;
322 			instoffset = s->value + a->offset;
323 			instoffx = INITDAT;
324 			return C_LECON;
325 
326 		case D_AUTO:
327 			instoffset = autosize + a->offset;
328 			if(instoffset >= -BIG && instoffset < BIG)
329 				return C_SACON;
330 			return C_LACON;
331 
332 		case D_PARAM:
333 			instoffset = autosize + a->offset + ptrsize;
334 			if(instoffset >= -BIG && instoffset < BIG)
335 				return C_SACON;
336 			return C_LACON;
337 		}
338 		return C_GOK;
339 
340 	case D_BRANCH:
341 		return C_SBRA;
342 	}
343 	return C_GOK;
344 }
345 
346 Optab*
347 oplook(Prog *p)
348 {
349 	int a1, a2, a3, r;
350 	char *c1, *c3;
351 	Optab *o, *e;
352 
353 	a1 = p->optab;
354 	if(a1)
355 		return optab+(a1-1);
356 	a1 = p->from.class;
357 	if(a1 == 0) {
358 		a1 = aclass(&p->from) + 1;
359 		p->from.class = a1;
360 	}
361 	a1--;
362 	a3 = p->to.class;
363 	if(a3 == 0) {
364 		a3 = aclass(&p->to) + 1;
365 		p->to.class = a3;
366 	}
367 	a3--;
368 	a2 = C_NONE;
369 	if(p->reg != NREG)
370 		a2 = C_REG;
371 	r = p->as;
372 	o = oprange[r].start;
373 	if(o == 0) {
374 		a1 = opcross[repop[r]][a1][a3];
375 		if(a1) {
376 			p->optab = a1+1;
377 			return optab+a1;
378 		}
379 		o = oprange[r].stop; /* just generate an error */
380 		a1 = p->from.class - 1;
381 	}
382 	e = oprange[r].stop;
383 
384 	c1 = xcmp[a1];
385 	c3 = xcmp[a3];
386 	for(; o<e; o++)
387 		if(c1[o->a1])
388 		if(c3[o->a3]) {
389 			p->optab = (o-optab)+1;
390 			return o;
391 		}
392 	diag("illegal combination %A %d %d %d",
393 		p->as, a1, a2, a3);
394 	if(!debug['a'])
395 		prasm(p);
396 	o = optab;
397 	p->optab = (o-optab)+1;
398 	return o;
399 }
400 
401 int
402 cmp(int a, int b)
403 {
404 
405 	if(a == b)
406 		return 1;
407 	switch(a) {
408 	case C_LCON:
409 		if(b == C_ZCON || b == C_SCON || b == C_UCON)
410 			return 1;
411 		break;
412 	case C_UCON:
413 		if(b == C_ZCON)
414 			return 1;
415 		break;
416 	case C_SCON:
417 		if(b == C_ZCON)
418 			return 1;
419 		break;
420 	case C_LACON:
421 		if(b == C_SACON)
422 			return 1;
423 		break;
424 	case C_LRCON:
425 		if(b == C_SRCON)
426 			return 1;
427 		break;
428 	case C_LBRA:
429 		if(b == C_SBRA)
430 			return 1;
431 		break;
432 	case C_LEXT:
433 		if(b == C_SEXT)
434 			return 1;
435 		break;
436 	case C_LAUTO:
437 		if(b == C_SAUTO)
438 			return 1;
439 		break;
440 	case C_ZREG:
441 		if(b == C_REG || b == C_ZCON)
442 			return 1;
443 		break;
444 	case C_LOREG:
445 		if(b == C_ZOREG || b == C_SOREG || b == C_SAUTO || b == C_LAUTO)
446 			return 1;
447 		break;
448 	case C_SOREG:
449 		if(b == C_ZOREG || b == C_SAUTO || b == C_SEXT)
450 			return 1;
451 		break;
452 	}
453 	return 0;
454 }
455 
456 int
457 ocmp(void *a1, void *a2)
458 {
459 	Optab *p1, *p2;
460 	int n;
461 
462 	p1 = (Optab*)a1;
463 	p2 = (Optab*)a2;
464 	n = p1->as - p2->as;
465 	if(n)
466 		return n;
467 	n = p1->a1 - p2->a1;
468 	if(n)
469 		return n;
470 	n = p1->a3 - p2->a3;
471 	if(n)
472 		return n;
473 	return 0;
474 }
475 
476 void
477 buildop(void)
478 {
479 	int i, n, r;
480 
481 	for(i=0; i<32; i++)
482 		for(n=0; n<32; n++)
483 			xcmp[i][n] = cmp(n, i);
484 	for(n=0; optab[n].as != AXXX; n++)
485 		;
486 	qsort(optab, n, sizeof(optab[0]), ocmp);
487 	for(i=0; i<n; i++) {
488 		r = optab[i].as;
489 		oprange[r].start = optab+i;
490 		while(optab[i].as == r)
491 			i++;
492 		oprange[r].stop = optab+i;
493 		i--;
494 	}
495 
496 	buildrep(1, AMOVW);
497 }
498 
499 void
500 buildrep(int x, int as)
501 {
502 	Opcross *p;
503 	Optab *e, *s, *o;
504 	int a1, a3, n;
505 
506 	if(C_GOK >= 32 || x >= nelem(opcross)) {
507 		diag("assumptions fail in buildrep");
508 		errorexit();
509 	}
510 	repop[as] = x;
511 	p = (opcross + x);
512 	s = oprange[as].start;
513 	e = oprange[as].stop;
514 	for(o=e-1; o>=s; o--) {
515 		n = o-optab;
516 		for(a1=0; a1<32; a1++) {
517 			if(!xcmp[a1][o->a1])
518 				continue;
519 			for(a3=0; a3<32; a3++)
520 				if(xcmp[a3][o->a3])
521 					(*p)[a1][a3] = n;
522 		}
523 	}
524 	oprange[as].start = 0;
525 }
526