xref: /inferno-os/utils/tl/span.c (revision 50b0dbb170df61467e42c7ea4deb0b5692d15f4c)
1 #include	"l.h"
2 
3 static struct {
4 	ulong	start;
5 	ulong	size;
6 	ulong	extra;
7 } pool;
8 
9 int	checkpool(Prog*, int);
10 int 	flushpool(Prog*, int, int);
11 
12 int
13 isbranch(Prog *p)
14 {
15 	int as = p->as;
16 	return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX;
17 }
18 
19 static int
20 ispad(Prog *p)
21 {
22 	if(p->as != AMOVW)
23 		return 0;
24 	if(p->from.type != D_REG || p->from.reg != REGSB)
25 		return 0;
26 	if(p->to.type != D_REG || p->to.reg != REGSB)
27 		return 0;
28 	return 1;
29 }
30 
31 int
32 fninc(Sym *s)
33 {
34 	if(thumb){
35 		if(s->thumb){
36 			if(s->foreign)
37 				return 8;
38 			else
39 				return 0;
40 		}
41 		else{
42 			if(s->foreign)
43 				return 0;
44 			else
45 				diag("T A !foreign in fninc");
46 		}
47 	}
48 	else{
49 		if(s->thumb){
50 			if(s->foreign)
51 				return 0;
52 			else
53 				diag("A T !foreign in fninc");
54 		}
55 		else{
56 			if(s->foreign)
57 				return 4;
58 			else
59 				return 0;
60 		}
61 	}
62 	return 0;
63 }
64 
65 int
66 fnpinc(Sym *s)
67 {
68 	if(!s->fnptr){	// a simplified case BX O(R) -> BL O(R)
69 		if(!debug['f'])
70 			diag("fnptr == 0 in fnpinc");
71 		if(s->foreign)
72 			diag("bad usage in fnpinc %s %d %d %d", s->name, s->used, s->foreign, s->thumb);
73 		return 0;
74 	}
75 	/* 0, 1, 2, 3 squared */
76 	if(s->thumb)
77 		return s->foreign ? 9 : 1;
78 	else
79 		return s->foreign ? 4 : 0;
80 }
81 
82 static Prog *
83 pad(Prog *p, int pc)
84 {
85 	Prog *q;
86 
87 	q = prg();
88 	q->as = AMOVW;
89 	q->line = p->line;
90 	q->from.type = D_REG;
91 	q->from.reg = REGSB;
92 	q->to.type = D_REG;
93 	q->to.reg = REGSB;
94 	q->pc = pc;
95 	q->link = p->link;
96 	return q;
97 }
98 
99 static int
100 scan(Prog *op, Prog *p, int c)
101 {
102 	Prog *q;
103 
104 	for(q = op->link; q != p; q = q->link){
105 		q->pc = c;
106 		c += oplook(q)->size;
107 		nocache(q);
108 	}
109 	return c;
110 }
111 
112 /* size of a case statement including jump table */
113 static long
114 casesz(Prog *p)
115 {
116 	int jt = 0;
117 	long n = 0;
118 	Optab *o;
119 
120 	for( ; p != P; p = p->link){
121 		if(p->as == ABCASE)
122 			jt = 1;
123 		else if(jt)
124 			break;
125 		o = oplook(p);
126 		n += o->size;
127 	}
128 	return n;
129 }
130 
131 void
132 span(void)
133 {
134 	Prog *p, *op;
135 	Sym *setext, *s;
136 	Optab *o;
137 	int m, bflag, i;
138 	long c, otxt, v;
139 	int lastthumb = -1;
140 
141 	if(debug['v'])
142 		Bprint(&bso, "%5.2f span\n", cputime());
143 	Bflush(&bso);
144 
145 	bflag = 0;
146 	c = INITTEXT;
147 	op = nil;
148 	otxt = c;
149 	for(p = firstp; p != P; op = p, p = p->link) {
150 		setarch(p);
151 		p->pc = c;
152 		o = oplook(p);
153 		m = o->size;
154 		// must check literal pool here in case p generates many instructions
155 		if(blitrl){
156 			if(thumb && isbranch(p))
157 				pool.extra += brextra(p);
158 			if(checkpool(op, p->as == ACASE ? casesz(p) : m))
159 				c = p->pc = scan(op, p, c);
160 		}
161 		if(m == 0) {
162 			if(p->as == ATEXT) {
163 				if(blitrl && lastthumb != -1 && lastthumb != thumb){	// flush literal pool
164 					if(flushpool(op, 0, 1))
165 						c = p->pc = scan(op, p, c);
166 				}
167 				lastthumb = thumb;
168 				curtext = p;
169 				autosize = p->to.offset + 4;
170 				if(p->from.sym != S)
171 					p->from.sym->value = c;
172 				/* need passes to resolve branches */
173 				if(c-otxt >= 1L<<17)
174 					bflag = 1;
175 				otxt = c;
176 				if(thumb && blitrl)
177 					pool.extra += brextra(p);
178 				continue;
179 			}
180 			diag("zero-width instruction\n%P", p);
181 			continue;
182 		}
183 		switch(o->flag & (LFROM|LTO|LPOOL)) {
184 		case LFROM:
185 			addpool(p, &p->from);
186 			break;
187 		case LTO:
188 			addpool(p, &p->to);
189 			break;
190 		case LPOOL:
191 			if ((p->scond&C_SCOND) == 14)
192 				flushpool(p, 0, 0);
193 			break;
194 		}
195 		if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
196 			flushpool(p, 0, 0);
197 		c += m;
198 		if(blitrl && p->link == P){
199 			if(thumb && isbranch(p))
200 				pool.extra += brextra(p);
201 			checkpool(p, 0);
202 		}
203 	}
204 
205 	/*
206 	 * if any procedure is large enough to
207 	 * generate a large SBRA branch, then
208 	 * generate extra passes putting branches
209 	 * around jmps to fix. this is rare.
210 	 */
211 	while(bflag) {
212 		if(debug['v'])
213 			Bprint(&bso, "%5.2f span1\n", cputime());
214 		bflag = 0;
215 		c = INITTEXT;
216 		for(p = firstp; p != P; p = p->link) {
217 			setarch(p);
218 			p->pc = c;
219 			if(thumb && isbranch(p))
220 				nocache(p);
221 			o = oplook(p);
222 /* very larg branches
223 			if(o->type == 6 && p->cond) {
224 				otxt = p->cond->pc - c;
225 				if(otxt < 0)
226 					otxt = -otxt;
227 				if(otxt >= (1L<<17) - 10) {
228 					q = prg();
229 					q->link = p->link;
230 					p->link = q;
231 					q->as = AB;
232 					q->to.type = D_BRANCH;
233 					q->cond = p->cond;
234 					p->cond = q;
235 					q = prg();
236 					q->link = p->link;
237 					p->link = q;
238 					q->as = AB;
239 					q->to.type = D_BRANCH;
240 					q->cond = q->link->link;
241 					bflag = 1;
242 				}
243 			}
244  */
245 			m = o->size;
246 			if(m == 0) {
247 				if(p->as == ATEXT) {
248 					curtext = p;
249 					autosize = p->to.offset + 4;
250 					if(p->from.sym != S)
251 						p->from.sym->value = c;
252 					continue;
253 				}
254 				diag("zero-width instruction\n%P", p);
255 				continue;
256 			}
257 			c += m;
258 		}
259 	}
260 
261 	if(seenthumb){		// branch resolution
262 		int passes = 0;
263 		int lastc = 0;
264 		int again;
265 		Prog *oop;
266 
267 	loop:
268 		passes++;
269 		if(passes > 150){
270 			diag("span looping !");
271 			errorexit();
272 		}
273 		c = INITTEXT;
274 		oop = op = nil;
275 		again = 0;
276 		for(p = firstp; p != P; oop = op, op = p, p = p->link){
277 			setarch(p);
278 			if(p->pc != c)
279 				again = 1;
280 			p->pc = c;
281 			if(thumb && isbranch(p))
282 				nocache(p);
283 			o = oplook(p);
284 			m = o->size;
285 			if(passes == 1 && thumb && isbranch(p)){	// start conservative so unneeded alignment is not added
286 				if(p->as == ABL)
287 					m = 4;
288 				else
289 					m = 2;
290 				p->align = 0;
291 			}
292 			if(p->align){
293 				if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){
294 					if(ispad(op)){
295 						oop->link = p;
296 						op = oop;
297 						c -= 2;
298 						p->pc = c;
299 					}
300 					else{
301 						op->link = pad(op, c);
302 						op = op->link;
303 						c += 2;
304 						p->pc = c;
305 					}
306 					again = 1;
307 				}
308 			}
309 			if(m == 0) {
310 				if(p->as == ATEXT) {
311 					curtext = p;
312 					autosize = p->to.offset + 4;
313 					if(p->from.sym != S)
314 						p->from.sym->value = c;
315 					continue;
316 				}
317 			}
318 			c += m;
319 		}
320 		if(c != lastc || again){
321 			lastc = c;
322 			goto loop;
323 		}
324 	}
325 
326 	if(0 && seenthumb){		// rm redundant padding - obsolete
327 		int d;
328 
329 		op = nil;
330 		d = 0;
331 		for(p = firstp; p != P; op = p, p = p->link){
332 			p->pc -= d;
333 			if(p->as == ATEXT){
334 				if(p->from.sym != S)
335 					p->from.sym->value -= d;
336 // if(p->from.sym != S) print("%s %ux %d %d %d\n", p->from.sym->name ? p->from.sym->name : "?", p->from.sym->value, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr);
337 			}
338 			if(ispad(p) && p->link != P && ispad(p->link)){
339 				op->link = p->link->link;
340 				d += 4;
341 				p = op;
342 			}
343 		}
344 		// print("%d bytes removed (padding)\n", d);
345 		c -= d;
346 	}
347 
348 	if(debug['t']) {
349 		/*
350 		 * add strings to text segment
351 		 */
352 		c = rnd(c, 8);
353 		for(i=0; i<NHASH; i++)
354 		for(s = hash[i]; s != S; s = s->link) {
355 			if(s->type != SSTRING)
356 				continue;
357 			v = s->value;
358 			while(v & 3)
359 				v++;
360 			s->value = c;
361 			c += v;
362 		}
363 	}
364 
365 	c = rnd(c, 8);
366 
367 	setext = lookup("etext", 0);
368 	if(setext != S) {
369 		setext->value = c;
370 		textsize = c - INITTEXT;
371 	}
372 	if(INITRND)
373 		INITDAT = rnd(c, INITRND);
374 	if(debug['v'])
375 		Bprint(&bso, "tsize = %lux\n", textsize);
376 	Bflush(&bso);
377 }
378 
379 /*
380  * when the first reference to the literal pool threatens
381  * to go out of range of a 12-bit PC-relative offset,
382  * drop the pool now, and branch round it.
383  * this happens only in extended basic blocks that exceed 4k.
384  */
385 int
386 checkpool(Prog *p, int sz)
387 {
388 	if(thumb){
389 		if(pool.size >= 0x3fc || (p->pc+sz+pool.extra+2+2)+(pool.size-4)-pool.start-4 >= 0x3fc)
390 			return flushpool(p, 1, 0);
391 		else if(p->link == P)
392 			return flushpool(p, 2, 0);
393 		return 0;
394 	}
395 	if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
396 		return flushpool(p, 1, 0);
397 	else if(p->link == P)
398 		return flushpool(p, 2, 0);
399 	return 0;
400 }
401 
402 int
403 flushpool(Prog *p, int skip, int force)
404 {
405 	Prog *q;
406 
407 	if(blitrl) {
408 		if(skip){
409 			if(0 && skip==1)print("note: flush literal pool at %lux: len=%lud ref=%lux\n", p->pc+4, pool.size, pool.start);
410 			q = prg();
411 			q->as = AB;
412 			q->to.type = D_BRANCH;
413 			q->cond = p->link;
414 			q->link = blitrl;
415 			blitrl = q;
416 		}
417 		else if(!force && (p->pc+pool.size-pool.start < (thumb ? 0x3fc+4-pool.extra : 2048)))
418 			return 0;
419 		elitrl->link = p->link;
420 		p->link = blitrl;
421 		blitrl = 0;	/* BUG: should refer back to values until out-of-range */
422 		elitrl = 0;
423 		pool.size = 0;
424 		pool.start = 0;
425 		pool.extra = 0;
426 		return 1;
427 	}
428 	return 0;
429 }
430 
431 void
432 addpool(Prog *p, Adr *a)
433 {
434 	Prog *q, t;
435 	int c;
436 
437 	if(thumb)
438 		c = thumbaclass(a, p);
439 	else
440 		c = aclass(a);
441 
442 	t = zprg;
443 	t.as = AWORD;
444 
445 	switch(c) {
446 	default:
447 		t.to = *a;
448 		break;
449 
450 	case	C_SROREG:
451 	case C_LOREG:
452 	case C_ROREG:
453 	case C_FOREG:
454 	case C_SOREG:
455 	case C_HOREG:
456 	case C_GOREG:
457 	case C_FAUTO:
458 	case C_SAUTO:
459 	case C_LAUTO:
460 	case C_LACON:
461 	case C_GACON:
462 		t.to.type = D_CONST;
463 		t.to.offset = instoffset;
464 		break;
465 	}
466 
467 	for(q = blitrl; q != P; q = q->link)	/* could hash on t.t0.offset */
468 		if(memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
469 			p->cond = q;
470 			return;
471 		}
472 
473 	q = prg();
474 	*q = t;
475 	q->pc = pool.size;
476 
477 	if(blitrl == P) {
478 		blitrl = q;
479 		pool.start = p->pc;
480 		q->align = 4;
481 	} else
482 		elitrl->link = q;
483 	elitrl = q;
484 	pool.size += 4;
485 
486 	p->cond = q;
487 }
488 
489 void
490 xdefine(char *p, int t, long v)
491 {
492 	Sym *s;
493 
494 	s = lookup(p, 0);
495 	if(s->type == 0 || s->type == SXREF) {
496 		s->type = t;
497 		s->value = v;
498 	}
499 }
500 
501 long
502 regoff(Adr *a)
503 {
504 
505 	instoffset = 0;
506 	aclass(a);
507 	return instoffset;
508 }
509 
510 long
511 immrot(ulong v)
512 {
513 	int i;
514 
515 	for(i=0; i<16; i++) {
516 		if((v & ~0xff) == 0)
517 			return (i<<8) | v | (1<<25);
518 		v = (v<<2) | (v>>30);
519 	}
520 	return 0;
521 }
522 
523 long
524 immaddr(long v)
525 {
526 	if(v >= 0 && v <= 0xfff)
527 		return (v & 0xfff) |
528 			(1<<24) |	/* pre indexing */
529 			(1<<23);	/* pre indexing, up */
530 	if(v >= -0xfff && v < 0)
531 		return (-v & 0xfff) |
532 			(1<<24);	/* pre indexing */
533 	return 0;
534 }
535 
536 int
537 immfloat(long v)
538 {
539 	return (v & 0xC03) == 0;	/* offset will fit in floating-point load/store */
540 }
541 
542 int
543 immhalf(long v)
544 {
545 	if(v >= 0 && v <= 0xff)
546 		return v|
547 			(1<<24)|	/* pre indexing */
548 			(1<<23);	/* pre indexing, up */
549 	if(v >= -0xff && v < 0)
550 		return (-v & 0xff)|
551 			(1<<24);	/* pre indexing */
552 	return 0;
553 }
554 
555 int
556 aclass(Adr *a)
557 {
558 	Sym *s;
559 	int t;
560 
561 	switch(a->type) {
562 	case D_NONE:
563 		return C_NONE;
564 
565 	case D_REG:
566 		return C_REG;
567 
568 	case D_REGREG:
569 		return C_REGREG;
570 
571 	case D_SHIFT:
572 		return C_SHIFT;
573 
574 	case D_FREG:
575 		return C_FREG;
576 
577 	case D_FPCR:
578 		return C_FCR;
579 
580 	case D_OREG:
581 		switch(a->name) {
582 		case D_EXTERN:
583 		case D_STATIC:
584 			if(a->sym == 0 || a->sym->name == 0) {
585 				print("null sym external\n");
586 				print("%D\n", a);
587 				return C_GOK;
588 			}
589 			s = a->sym;
590 			t = s->type;
591 			if(t == 0 || t == SXREF) {
592 				diag("undefined external: %s in %s",
593 					s->name, TNAME);
594 				s->type = SDATA;
595 			}
596 			if(dlm) {
597 				switch(t) {
598 				default:
599 					instoffset = s->value + a->offset + INITDAT;
600 					break;
601 				case SUNDEF:
602 				case STEXT:
603 				case SCONST:
604 				case SLEAF:
605 				case SSTRING:
606 					instoffset = s->value + a->offset;
607 					break;
608 				}
609 				return C_ADDR;
610 			}
611 			instoffset = s->value + a->offset - BIG;
612 			t = immaddr(instoffset);
613 			if(t) {
614 				if(immhalf(instoffset))
615 					return immfloat(t) ? C_HFEXT : C_HEXT;
616 				if(immfloat(t))
617 					return C_FEXT;
618 				return C_SEXT;
619 			}
620 			return C_LEXT;
621 		case D_AUTO:
622 			instoffset = autosize + a->offset;
623 			t = immaddr(instoffset);
624 			if(t){
625 				if(immhalf(instoffset))
626 					return immfloat(t) ? C_HFAUTO : C_HAUTO;
627 				if(immfloat(t))
628 					return C_FAUTO;
629 				return C_SAUTO;
630 			}
631 			return C_LAUTO;
632 
633 		case D_PARAM:
634 			instoffset = autosize + a->offset + 4L;
635 			t = immaddr(instoffset);
636 			if(t){
637 				if(immhalf(instoffset))
638 					return immfloat(t) ? C_HFAUTO : C_HAUTO;
639 				if(immfloat(t))
640 					return C_FAUTO;
641 				return C_SAUTO;
642 			}
643 			return C_LAUTO;
644 		case D_NONE:
645 			instoffset = a->offset;
646 			t = immaddr(instoffset);
647 			if(t) {
648 				if(immhalf(instoffset))		 /* n.b. that it will also satisfy immrot */
649 					return immfloat(t) ? C_HFOREG : C_HOREG;
650 				if(immfloat(t))
651 					return C_FOREG; /* n.b. that it will also satisfy immrot */
652 				t = immrot(instoffset);
653 				if(t)
654 					return C_SROREG;
655 				if(immhalf(instoffset))
656 					return C_HOREG;
657 				return C_SOREG;
658 			}
659 			t = immrot(instoffset);
660 			if(t)
661 				return C_ROREG;
662 			return C_LOREG;
663 		}
664 		return C_GOK;
665 
666 	case D_PSR:
667 		return C_PSR;
668 
669 	case D_OCONST:
670 		switch(a->name) {
671 		case D_EXTERN:
672 		case D_STATIC:
673 			s = a->sym;
674 			t = s->type;
675 			if(t == 0 || t == SXREF) {
676 				diag("undefined external: %s in %s",
677 					s->name, TNAME);
678 				s->type = SDATA;
679 			}
680 			instoffset = s->value + a->offset + INITDAT;
681 			if(s->type == STEXT || s->type == SLEAF || s->type == SUNDEF) {
682 				instoffset = s->value + a->offset;
683 #ifdef CALLEEBX
684 				instoffset += fnpinc(s);
685 #else
686 				if(s->thumb)
687 					instoffset++;	// T bit
688 #endif
689 				return C_LCON;
690 			}
691 			return C_LCON;
692 		}
693 		return C_GOK;
694 
695 	case D_FCONST:
696 		return C_FCON;
697 
698 	case D_CONST:
699 		switch(a->name) {
700 
701 		case D_NONE:
702 			instoffset = a->offset;
703 			if(a->reg != NREG)
704 				goto aconsize;
705 
706 			t = immrot(instoffset);
707 			if(t)
708 				return C_RCON;
709 			t = immrot(~instoffset);
710 			if(t)
711 				return C_NCON;
712 			return C_LCON;
713 
714 		case D_EXTERN:
715 		case D_STATIC:
716 			s = a->sym;
717 			if(s == S)
718 				break;
719 			t = s->type;
720 			switch(t) {
721 			case 0:
722 			case SXREF:
723 				diag("undefined external: %s in %s",
724 					s->name, TNAME);
725 				s->type = SDATA;
726 				break;
727 			case SUNDEF:
728 			case STEXT:
729 			case SSTRING:
730 			case SCONST:
731 			case SLEAF:
732 				instoffset = s->value + a->offset;
733 #ifdef CALLEEBX
734 				instoffset += fnpinc(s);
735 #else
736 				if(s->thumb)
737 					instoffset++;	// T bit
738 #endif
739 				return C_LCON;
740 			}
741 			if(!dlm) {
742 				instoffset = s->value + a->offset - BIG;
743 				t = immrot(instoffset);
744 				if(t && instoffset != 0)
745 					return C_RECON;
746 			}
747 			instoffset = s->value + a->offset + INITDAT;
748 			return C_LCON;
749 
750 		case D_AUTO:
751 			instoffset = autosize + a->offset;
752 			goto aconsize;
753 
754 		case D_PARAM:
755 			instoffset = autosize + a->offset + 4L;
756 		aconsize:
757 			t = immrot(instoffset);
758 			if(t)
759 				return C_RACON;
760 			return C_LACON;
761 		}
762 		return C_GOK;
763 
764 	case D_BRANCH:
765 		return C_SBRA;
766 	}
767 	return C_GOK;
768 }
769 
770 Optab*
771 oplook(Prog *p)
772 {
773 	int a1, a2, a3, r;
774 	char *c1, *c3;
775 	Optab *o, *e;
776 	Optab *otab;
777 	Oprang *orange;
778 
779 	if(thumb){
780 		otab = thumboptab;
781 		orange = thumboprange;
782 	}
783 	else{
784 		otab = optab;
785 		orange = oprange;
786 	}
787 	a1 = p->optab;
788 	if(a1)
789 		return otab+(a1-1);
790 	a1 = p->from.class;
791 	if(a1 == 0) {
792 		if(thumb)
793 			a1 = thumbaclass(&p->from, p) + 1;
794 		else
795 			a1 = aclass(&p->from) + 1;
796 		p->from.class = a1;
797 	}
798 	a1--;
799 	a3 = p->to.class;
800 	if(a3 == 0) {
801 		if(thumb)
802 			a3 = thumbaclass(&p->to, p) + 1;
803 		else
804 			a3 = aclass(&p->to) + 1;
805 		p->to.class = a3;
806 	}
807 	a3--;
808 	a2 = C_NONE;
809 	if(p->reg != NREG)
810 		a2 = C_REG;
811 	r = p->as;
812 	o = orange[r].start;
813 	if(o == 0) {
814 		a1 = opcross[repop[r]][a1][a2][a3];
815 		if(a1) {
816 			p->optab = a1+1;
817 			return otab+a1;
818 		}
819 		o = orange[r].stop; /* just generate an error */
820 	}
821 	if(0) {
822 		print("oplook %A %d %d %d\n",
823 			(int)p->as, a1, a2, a3);
824 		print("		%d %d\n", p->from.type, p->to.type);
825 	}
826 	e = orange[r].stop;
827 	c1 = xcmp[a1];
828 	c3 = xcmp[a3];
829 	for(; o<e; o++)
830 		if(o->a2 == a2)
831 		if(c1[o->a1])
832 		if(c3[o->a3]) {
833 			p->optab = (o-otab)+1;
834 			return o;
835 		}
836 	diag("illegal combination %A %d %d %d",
837 		p->as, a1, a2, a3);
838 	prasm(p);
839 	if(o == 0)
840 		o = otab;
841 	return o;
842 }
843 
844 int
845 cmp(int a, int b)
846 {
847 
848 	if(a == b)
849 		return 1;
850 	switch(a) {
851 	case C_LCON:
852 		if(b == C_RCON || b == C_NCON)
853 			return 1;
854 		break;
855 	case C_LACON:
856 		if(b == C_RACON)
857 			return 1;
858 		break;
859 	case C_LECON:
860 		if(b == C_RECON)
861 			return 1;
862 		break;
863 
864 	case C_HFEXT:
865 		return b == C_HEXT || b == C_FEXT;
866 	case C_FEXT:
867 	case C_HEXT:
868 		return b == C_HFEXT;
869 	case C_SEXT:
870 		return cmp(C_HFEXT, b);
871 	case C_LEXT:
872 		return cmp(C_SEXT, b);
873 
874 	case C_HFAUTO:
875 		return b == C_HAUTO || b == C_FAUTO;
876 	case C_FAUTO:
877 	case C_HAUTO:
878 		return b == C_HFAUTO;
879 	case C_SAUTO:
880 		return cmp(C_HFAUTO, b);
881 	case C_LAUTO:
882 		return cmp(C_SAUTO, b);
883 
884 	case C_HFOREG:
885 		return b == C_HOREG || b == C_FOREG;
886 	case C_FOREG:
887 	case C_HOREG:
888 		return b == C_HFOREG;
889 	case C_SROREG:
890 		return cmp(C_SOREG, b) || cmp(C_ROREG, b);
891 	case C_SOREG:
892 	case C_ROREG:
893 		return b == C_SROREG || cmp(C_HFOREG, b);
894 	case C_LOREG:
895 		return cmp(C_SROREG, b);
896 
897 	case C_LBRA:
898 		if(b == C_SBRA)
899 			return 1;
900 		break;
901 	case C_GBRA:
902 		if(b == C_SBRA || b == C_LBRA)
903 			return 1;
904 
905 	case C_HREG:
906 		return cmp(C_SP, b) || cmp(C_PC, b);
907 
908 	}
909 	return 0;
910 }
911 
912 int
913 ocmp(void *a1, void *a2)
914 {
915 	Optab *p1, *p2;
916 	int n;
917 
918 	p1 = (Optab*)a1;
919 	p2 = (Optab*)a2;
920 	n = p1->as - p2->as;
921 	if(n)
922 		return n;
923 	n = (p2->flag&V4) - (p1->flag&V4);	/* architecture version */
924 	if(n)
925 		return n;
926 	n = p1->a1 - p2->a1;
927 	if(n)
928 		return n;
929 	n = p1->a2 - p2->a2;
930 	if(n)
931 		return n;
932 	n = p1->a3 - p2->a3;
933 	if(n)
934 		return n;
935 	return 0;
936 }
937 
938 void
939 buildop(void)
940 {
941 	int i, n, r;
942 
943 	armv4 = !debug['h'];
944 	for(i=0; i<C_GOK; i++)
945 		for(n=0; n<C_GOK; n++)
946 			xcmp[i][n] = cmp(n, i);
947 	for(n=0; optab[n].as != AXXX; n++)
948 		if((optab[n].flag & V4) && !armv4) {
949 			optab[n].as = AXXX;
950 			break;
951 		}
952 	qsort(optab, n, sizeof(optab[0]), ocmp);
953 	for(i=0; i<n; i++) {
954 		r = optab[i].as;
955 		oprange[r].start = optab+i;
956 		while(optab[i].as == r)
957 			i++;
958 		oprange[r].stop = optab+i;
959 		i--;
960 
961 		switch(r)
962 		{
963 		default:
964 			diag("unknown op in build: %A", r);
965 			errorexit();
966 		case AADD:
967 			oprange[AAND] = oprange[r];
968 			oprange[AEOR] = oprange[r];
969 			oprange[ASUB] = oprange[r];
970 			oprange[ARSB] = oprange[r];
971 			oprange[AADC] = oprange[r];
972 			oprange[ASBC] = oprange[r];
973 			oprange[ARSC] = oprange[r];
974 			oprange[AORR] = oprange[r];
975 			oprange[ABIC] = oprange[r];
976 			break;
977 		case ACMP:
978 			oprange[ATST] = oprange[r];
979 			oprange[ATEQ] = oprange[r];
980 			oprange[ACMN] = oprange[r];
981 			break;
982 		case AMVN:
983 			break;
984 		case ABEQ:
985 			oprange[ABNE] = oprange[r];
986 			oprange[ABCS] = oprange[r];
987 			oprange[ABHS] = oprange[r];
988 			oprange[ABCC] = oprange[r];
989 			oprange[ABLO] = oprange[r];
990 			oprange[ABMI] = oprange[r];
991 			oprange[ABPL] = oprange[r];
992 			oprange[ABVS] = oprange[r];
993 			oprange[ABVC] = oprange[r];
994 			oprange[ABHI] = oprange[r];
995 			oprange[ABLS] = oprange[r];
996 			oprange[ABGE] = oprange[r];
997 			oprange[ABLT] = oprange[r];
998 			oprange[ABGT] = oprange[r];
999 			oprange[ABLE] = oprange[r];
1000 			break;
1001 		case ASLL:
1002 			oprange[ASRL] = oprange[r];
1003 			oprange[ASRA] = oprange[r];
1004 			break;
1005 		case AMUL:
1006 			oprange[AMULU] = oprange[r];
1007 			break;
1008 		case ADIV:
1009 			oprange[AMOD] = oprange[r];
1010 			oprange[AMODU] = oprange[r];
1011 			oprange[ADIVU] = oprange[r];
1012 			break;
1013 		case AMOVW:
1014 		case AMOVB:
1015 		case AMOVBU:
1016 		case AMOVH:
1017 		case AMOVHU:
1018 			break;
1019 		case ASWPW:
1020 			oprange[ASWPBU] = oprange[r];
1021 			break;
1022 		case AB:
1023 		case ABL:
1024 		case ABX:
1025 		case ABXRET:
1026 		case ASWI:
1027 		case AWORD:
1028 		case AMOVM:
1029 		case ARFE:
1030 		case ATEXT:
1031 		case ACASE:
1032 		case ABCASE:
1033 			break;
1034 		case AADDF:
1035 			oprange[AADDD] = oprange[r];
1036 			oprange[ASUBF] = oprange[r];
1037 			oprange[ASUBD] = oprange[r];
1038 			oprange[AMULF] = oprange[r];
1039 			oprange[AMULD] = oprange[r];
1040 			oprange[ADIVF] = oprange[r];
1041 			oprange[ADIVD] = oprange[r];
1042 			oprange[AMOVFD] = oprange[r];
1043 			oprange[AMOVDF] = oprange[r];
1044 			break;
1045 
1046 		case ACMPF:
1047 			oprange[ACMPD] = oprange[r];
1048 			break;
1049 
1050 		case AMOVF:
1051 			oprange[AMOVD] = oprange[r];
1052 			break;
1053 
1054 		case AMOVFW:
1055 			oprange[AMOVWF] = oprange[r];
1056 			oprange[AMOVWD] = oprange[r];
1057 			oprange[AMOVDW] = oprange[r];
1058 			break;
1059 
1060 		case AMULL:
1061 			oprange[AMULA] = oprange[r];
1062 			oprange[AMULAL] = oprange[r];
1063 			oprange[AMULLU] = oprange[r];
1064 			oprange[AMULALU] = oprange[r];
1065 			break;
1066 		}
1067 	}
1068 }
1069 
1070 /*
1071 void
1072 buildrep(int x, int as)
1073 {
1074 	Opcross *p;
1075 	Optab *e, *s, *o;
1076 	int a1, a2, a3, n;
1077 
1078 	if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
1079 		diag("assumptions fail in buildrep");
1080 		errorexit();
1081 	}
1082 	repop[as] = x;
1083 	p = (opcross + x);
1084 	s = oprange[as].start;
1085 	e = oprange[as].stop;
1086 	for(o=e-1; o>=s; o--) {
1087 		n = o-optab;
1088 		for(a2=0; a2<2; a2++) {
1089 			if(a2) {
1090 				if(o->a2 == C_NONE)
1091 					continue;
1092 			} else
1093 				if(o->a2 != C_NONE)
1094 					continue;
1095 			for(a1=0; a1<32; a1++) {
1096 				if(!xcmp[a1][o->a1])
1097 					continue;
1098 				for(a3=0; a3<32; a3++)
1099 					if(xcmp[a3][o->a3])
1100 						(*p)[a1][a2][a3] = n;
1101 			}
1102 		}
1103 	}
1104 	oprange[as].start = 0;
1105 }
1106 */
1107 
1108 enum{
1109 	ABSD = 0,
1110 	ABSU = 1,
1111 	RELD = 2,
1112 	RELU = 3,
1113 };
1114 
1115 int modemap[4] = { 0, 1, -1, 2, };
1116 
1117 typedef struct Reloc Reloc;
1118 
1119 struct Reloc
1120 {
1121 	int n;
1122 	int t;
1123 	uchar *m;
1124 	ulong *a;
1125 };
1126 
1127 Reloc rels;
1128 
1129 static void
1130 grow(Reloc *r)
1131 {
1132 	int t;
1133 	uchar *m, *nm;
1134 	ulong *a, *na;
1135 
1136 	t = r->t;
1137 	r->t += 64;
1138 	m = r->m;
1139 	a = r->a;
1140 	r->m = nm = malloc(r->t*sizeof(uchar));
1141 	r->a = na = malloc(r->t*sizeof(ulong));
1142 	memmove(nm, m, t*sizeof(uchar));
1143 	memmove(na, a, t*sizeof(ulong));
1144 	free(m);
1145 	free(a);
1146 }
1147 
1148 void
1149 dynreloc(Sym *s, long v, int abs)
1150 {
1151 	int i, k, n;
1152 	uchar *m;
1153 	ulong *a;
1154 	Reloc *r;
1155 
1156 	if(v&3)
1157 		diag("bad relocation address");
1158 	v >>= 2;
1159 	if(s != S && s->type == SUNDEF)
1160 		k = abs ? ABSU : RELU;
1161 	else
1162 		k = abs ? ABSD : RELD;
1163 	/* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, a, a, k); */
1164 	k = modemap[k];
1165 	r = &rels;
1166 	n = r->n;
1167 	if(n >= r->t)
1168 		grow(r);
1169 	m = r->m;
1170 	a = r->a;
1171 	for(i = n; i > 0; i--){
1172 		if(v < a[i-1]){	/* happens occasionally for data */
1173 			m[i] = m[i-1];
1174 			a[i] = a[i-1];
1175 		}
1176 		else
1177 			break;
1178 	}
1179 	m[i] = k;
1180 	a[i] = v;
1181 	r->n++;
1182 }
1183 
1184 static int
1185 sput(char *s)
1186 {
1187 	char *p;
1188 
1189 	p = s;
1190 	while(*s)
1191 		cput(*s++);
1192 	cput(0);
1193 	return  s-p+1;
1194 }
1195 
1196 void
1197 asmdyn()
1198 {
1199 	int i, n, t, c;
1200 	Sym *s;
1201 	ulong la, ra, *a;
1202 	vlong off;
1203 	uchar *m;
1204 	Reloc *r;
1205 
1206 	cflush();
1207 	off = seek(cout, 0, 1);
1208 	lput(0);
1209 	t = 0;
1210 	lput(imports);
1211 	t += 4;
1212 	for(i = 0; i < NHASH; i++)
1213 		for(s = hash[i]; s != S; s = s->link)
1214 			if(s->type == SUNDEF){
1215 				lput(s->sig);
1216 				t += 4;
1217 				t += sput(s->name);
1218 			}
1219 
1220 	la = 0;
1221 	r = &rels;
1222 	n = r->n;
1223 	m = r->m;
1224 	a = r->a;
1225 	lput(n);
1226 	t += 4;
1227 	for(i = 0; i < n; i++){
1228 		ra = *a-la;
1229 		if(*a < la)
1230 			diag("bad relocation order");
1231 		if(ra < 256)
1232 			c = 0;
1233 		else if(ra < 65536)
1234 			c = 1;
1235 		else
1236 			c = 2;
1237 		cput((c<<6)|*m++);
1238 		t++;
1239 		if(c == 0){
1240 			cput(ra);
1241 			t++;
1242 		}
1243 		else if(c == 1){
1244 			wput(ra);
1245 			t += 2;
1246 		}
1247 		else{
1248 			lput(ra);
1249 			t += 4;
1250 		}
1251 		la = *a++;
1252 	}
1253 
1254 	cflush();
1255 	seek(cout, off, 0);
1256 	lput(t);
1257 
1258 	if(debug['v']){
1259 		Bprint(&bso, "import table entries = %d\n", imports);
1260 		Bprint(&bso, "export table entries = %d\n", exports);
1261 	}
1262 }
1263