xref: /plan9/sys/src/cmd/8l/span.c (revision 282e677fa45fb578cdb8bc2c412ac084c367776e)
1 #include	"l.h"
2 
3 void
4 span(void)
5 {
6 	Prog *p, *q;
7 	long v, c, idat;
8 	int m, n, again;
9 
10 	xdefine("etext", STEXT, 0L);
11 	idat = INITDAT;
12 	for(p = firstp; p != P; p = p->link) {
13 		if(p->as == ATEXT)
14 			curtext = p;
15 		n = 0;
16 		if(p->to.type == D_BRANCH)
17 			if(p->pcond == P)
18 				p->pcond = p;
19 		if((q = p->pcond) != P)
20 			if(q->back != 2)
21 				n = 1;
22 		p->back = n;
23 		if(p->as == AADJSP) {
24 			p->to.type = D_SP;
25 			v = -p->from.offset;
26 			p->from.offset = v;
27 			p->as = AADDL;
28 			if(v < 0) {
29 				p->as = ASUBL;
30 				v = -v;
31 				p->from.offset = v;
32 			}
33 			if(v == 0)
34 				p->as = ANOP;
35 		}
36 	}
37 	n = 0;
38 
39 start:
40 	if(debug['v'])
41 		Bprint(&bso, "%5.2f span\n", cputime());
42 	Bflush(&bso);
43 	c = INITTEXT;
44 	for(p = firstp; p != P; p = p->link) {
45 		if(p->as == ATEXT)
46 			curtext = p;
47 		if(p->to.type == D_BRANCH)
48 			if(p->back)
49 				p->pc = c;
50 		asmins(p);
51 		p->pc = c;
52 		m = andptr-and;
53 		p->mark = m;
54 		c += m;
55 	}
56 
57 loop:
58 	n++;
59 	if(debug['v'])
60 		Bprint(&bso, "%5.2f span %d\n", cputime(), n);
61 	Bflush(&bso);
62 	if(n > 50) {
63 		print("span must be looping\n");
64 		errorexit();
65 	}
66 	again = 0;
67 	c = INITTEXT;
68 	for(p = firstp; p != P; p = p->link) {
69 		if(p->as == ATEXT)
70 			curtext = p;
71 		if(p->to.type == D_BRANCH) {
72 			if(p->back)
73 				p->pc = c;
74 			asmins(p);
75 			m = andptr-and;
76 			if(m != p->mark) {
77 				p->mark = m;
78 				again++;
79 			}
80 		}
81 		p->pc = c;
82 		c += p->mark;
83 	}
84 	if(again) {
85 		textsize = c;
86 		goto loop;
87 	}
88 	if(INITRND) {
89 		INITDAT = rnd(c, INITRND);
90 		if(INITDAT != idat) {
91 			idat = INITDAT;
92 			goto start;
93 		}
94 	}
95 	xdefine("etext", STEXT, c);
96 	if(debug['v'])
97 		Bprint(&bso, "etext = %lux\n", c);
98 	Bflush(&bso);
99 	for(p = textp; p != P; p = p->pcond)
100 		p->from.sym->value = p->pc;
101 	textsize = c - INITTEXT;
102 }
103 
104 void
105 xdefine(char *p, int t, long v)
106 {
107 	Sym *s;
108 
109 	s = lookup(p, 0);
110 	if(s->type == 0 || s->type == SXREF) {
111 		s->type = t;
112 		s->value = v;
113 	}
114 	if(s->type == STEXT && s->value == 0)
115 		s->value = v;
116 }
117 
118 void
119 putsymb(char *s, int t, long v, int ver)
120 {
121 	int i, f;
122 
123 	if(t == 'f')
124 		s++;
125 	lput(v);
126 	if(ver)
127 		t += 'a' - 'A';
128 	cput(t+0x80);			/* 0x80 is variable length */
129 
130 	if(t == 'Z' || t == 'z') {
131 		cput(s[0]);
132 		for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
133 			cput(s[i]);
134 			cput(s[i+1]);
135 		}
136 		cput(0);
137 		cput(0);
138 		i++;
139 	}
140 	else {
141 		for(i=0; s[i]; i++)
142 			cput(s[i]);
143 		cput(0);
144 	}
145 	symsize += 4 + 1 + i + 1;
146 
147 	if(debug['n']) {
148 		if(t == 'z' || t == 'Z') {
149 			Bprint(&bso, "%c %.8lux ", t, v);
150 			for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
151 				f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
152 				Bprint(&bso, "/%x", f);
153 			}
154 			Bprint(&bso, "\n");
155 			return;
156 		}
157 		if(ver)
158 			Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
159 		else
160 			Bprint(&bso, "%c %.8lux %s\n", t, v, s);
161 	}
162 }
163 
164 void
165 asmsym(void)
166 {
167 	Prog *p;
168 	Auto *a;
169 	Sym *s;
170 	int h;
171 	Relocsym *rs;
172 	Reloc *r;
173 
174 	for(rs = relocs; rs != nil; rs = rs->link) {
175 		if(rs->s != nil)
176 			putsymb(rs->s->name, 'U', 0, 0);
177 		for(r = rs->reloc; r != nil; r = r->link)
178 			putsymb("", r->type, r->pc-INITTEXT, 0);
179 	}
180 
181 	s = lookup("etext", 0);
182 	if(s->type == STEXT)
183 		putsymb(s->name, 'T', s->value, s->version);
184 
185 	for(h=0; h<NHASH; h++)
186 		for(s=hash[h]; s!=S; s=s->link)
187 			switch(s->type) {
188 			case SCONST:
189 				putsymb(s->name, 'D', s->value, s->version);
190 				continue;
191 
192 			case SDATA:
193 				putsymb(s->name, 'D', s->value+INITDAT, s->version);
194 				continue;
195 
196 			case SBSS:
197 				putsymb(s->name, 'B', s->value+INITDAT, s->version);
198 				continue;
199 
200 			case SFILE:
201 				putsymb(s->name, 'f', s->value, s->version);
202 				continue;
203 			}
204 
205 	for(p=textp; p!=P; p=p->pcond) {
206 		s = p->from.sym;
207 		if(s->type != STEXT)
208 			continue;
209 
210 		/* filenames first */
211 		for(a=p->to.autom; a; a=a->link)
212 			if(a->type == D_FILE)
213 				putsymb(a->asym->name, 'z', a->aoffset, 0);
214 			else
215 			if(a->type == D_FILE1)
216 				putsymb(a->asym->name, 'Z', a->aoffset, 0);
217 
218 		putsymb(s->name, 'T', s->value, s->version);
219 
220 		/* frame, auto and param after */
221 		putsymb(".frame", 'm', p->to.offset+4, 0);
222 
223 		for(a=p->to.autom; a; a=a->link)
224 			if(a->type == D_AUTO)
225 				putsymb(a->asym->name, 'a', -a->aoffset, 0);
226 			else
227 			if(a->type == D_PARAM)
228 				putsymb(a->asym->name, 'p', a->aoffset, 0);
229 	}
230 	if(debug['v'] || debug['n'])
231 		Bprint(&bso, "symsize = %lud\n", symsize);
232 	Bflush(&bso);
233 }
234 
235 void
236 asmlc(void)
237 {
238 	long oldpc, oldlc;
239 	Prog *p;
240 	long v, s;
241 
242 	oldpc = INITTEXT;
243 	oldlc = 0;
244 	for(p = firstp; p != P; p = p->link) {
245 		if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
246 			if(p->as == ATEXT)
247 				curtext = p;
248 			if(debug['L'])
249 				Bprint(&bso, "%6lux %P\n",
250 					p->pc, p);
251 			continue;
252 		}
253 		if(debug['L'])
254 			Bprint(&bso, "\t\t%6ld", lcsize);
255 		v = (p->pc - oldpc) / MINLC;
256 		while(v) {
257 			s = 127;
258 			if(v < 127)
259 				s = v;
260 			cput(s+128);	/* 129-255 +pc */
261 			if(debug['L'])
262 				Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
263 			v -= s;
264 			lcsize++;
265 		}
266 		s = p->line - oldlc;
267 		oldlc = p->line;
268 		oldpc = p->pc + MINLC;
269 		if(s > 64 || s < -64) {
270 			cput(0);	/* 0 vv +lc */
271 			cput(s>>24);
272 			cput(s>>16);
273 			cput(s>>8);
274 			cput(s);
275 			if(debug['L']) {
276 				if(s > 0)
277 					Bprint(&bso, " lc+%ld(%d,%ld)\n",
278 						s, 0, s);
279 				else
280 					Bprint(&bso, " lc%ld(%d,%ld)\n",
281 						s, 0, s);
282 				Bprint(&bso, "%6lux %P\n",
283 					p->pc, p);
284 			}
285 			lcsize += 5;
286 			continue;
287 		}
288 		if(s > 0) {
289 			cput(0+s);	/* 1-64 +lc */
290 			if(debug['L']) {
291 				Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
292 				Bprint(&bso, "%6lux %P\n",
293 					p->pc, p);
294 			}
295 		} else {
296 			cput(64-s);	/* 65-128 -lc */
297 			if(debug['L']) {
298 				Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
299 				Bprint(&bso, "%6lux %P\n",
300 					p->pc, p);
301 			}
302 		}
303 		lcsize++;
304 	}
305 	while(lcsize & 1) {
306 		s = 129;
307 		cput(s);
308 		lcsize++;
309 	}
310 	if(debug['v'] || debug['L'])
311 		Bprint(&bso, "lcsize = %ld\n", lcsize);
312 	Bflush(&bso);
313 }
314 
315 int
316 oclass(Adr *a)
317 {
318 	long v;
319 
320 	if(a->type >= D_INDIR || a->index != D_NONE) {
321 		if(a->index != D_NONE && a->scale == 0) {
322 			if(a->type == D_ADDR) {
323 				switch(a->index) {
324 				case D_EXTERN:
325 				case D_STATIC:
326 					return Yi32;
327 				case D_AUTO:
328 				case D_PARAM:
329 					return Yiauto;
330 				}
331 				return Yxxx;
332 			}
333 			return Ycol;
334 		}
335 		return Ym;
336 	}
337 	switch(a->type)
338 	{
339 	case D_AL:
340 		return Yal;
341 
342 	case D_AX:
343 		return Yax;
344 
345 	case D_CL:
346 	case D_DL:
347 	case D_BL:
348 	case D_AH:
349 	case D_CH:
350 	case D_DH:
351 	case D_BH:
352 		return Yrb;
353 
354 	case D_CX:
355 		return Ycx;
356 
357 	case D_DX:
358 	case D_BX:
359 		return Yrx;
360 
361 	case D_SP:
362 	case D_BP:
363 	case D_SI:
364 	case D_DI:
365 		return Yrl;
366 
367 	case D_F0+0:
368 		return	Yf0;
369 
370 	case D_F0+1:
371 	case D_F0+2:
372 	case D_F0+3:
373 	case D_F0+4:
374 	case D_F0+5:
375 	case D_F0+6:
376 	case D_F0+7:
377 		return	Yrf;
378 
379 	case D_NONE:
380 		return Ynone;
381 
382 	case D_CS:	return	Ycs;
383 	case D_SS:	return	Yss;
384 	case D_DS:	return	Yds;
385 	case D_ES:	return	Yes;
386 	case D_FS:	return	Yfs;
387 	case D_GS:	return	Ygs;
388 
389 	case D_GDTR:	return	Ygdtr;
390 	case D_IDTR:	return	Yidtr;
391 	case D_LDTR:	return	Yldtr;
392 	case D_MSW:	return	Ymsw;
393 	case D_TASK:	return	Ytask;
394 
395 	case D_CR+0:	return	Ycr0;
396 	case D_CR+1:	return	Ycr1;
397 	case D_CR+2:	return	Ycr2;
398 	case D_CR+3:	return	Ycr3;
399 	case D_CR+4:	return	Ycr4;
400 	case D_CR+5:	return	Ycr5;
401 	case D_CR+6:	return	Ycr6;
402 	case D_CR+7:	return	Ycr7;
403 
404 	case D_DR+0:	return	Ydr0;
405 	case D_DR+1:	return	Ydr1;
406 	case D_DR+2:	return	Ydr2;
407 	case D_DR+3:	return	Ydr3;
408 	case D_DR+4:	return	Ydr4;
409 	case D_DR+5:	return	Ydr5;
410 	case D_DR+6:	return	Ydr6;
411 	case D_DR+7:	return	Ydr7;
412 
413 	case D_TR+0:	return	Ytr0;
414 	case D_TR+1:	return	Ytr1;
415 	case D_TR+2:	return	Ytr2;
416 	case D_TR+3:	return	Ytr3;
417 	case D_TR+4:	return	Ytr4;
418 	case D_TR+5:	return	Ytr5;
419 	case D_TR+6:	return	Ytr6;
420 	case D_TR+7:	return	Ytr7;
421 
422 	case D_EXTERN:
423 	case D_STATIC:
424 	case D_AUTO:
425 	case D_PARAM:
426 		return Ym;
427 
428 	case D_CONST:
429 	case D_ADDR:
430 		if(a->sym == S) {
431 			v = a->offset;
432 			if(v == 0)
433 				return Yi0;
434 			if(v == 1)
435 				return Yi1;
436 			if(v >= -128 && v <= 127)
437 				return Yi8;
438 		}
439 		return Yi32;
440 
441 	case D_BRANCH:
442 		return Ybr;
443 	}
444 	return Yxxx;
445 }
446 
447 void
448 asmidx(Adr *a, int base)
449 {
450 	int i;
451 
452 	switch(a->index) {
453 	default:
454 		goto bad;
455 
456 	case D_NONE:
457 		i = 4 << 3;
458 		goto bas;
459 
460 	case D_AX:
461 	case D_CX:
462 	case D_DX:
463 	case D_BX:
464 	case D_BP:
465 	case D_SI:
466 	case D_DI:
467 		i = reg[a->index] << 3;
468 		break;
469 	}
470 	switch(a->scale) {
471 	default:
472 		goto bad;
473 	case 1:
474 		break;
475 	case 2:
476 		i |= (1<<6);
477 		break;
478 	case 4:
479 		i |= (2<<6);
480 		break;
481 	case 8:
482 		i |= (3<<6);
483 		break;
484 	}
485 bas:
486 	switch(base) {
487 	default:
488 		goto bad;
489 	case D_NONE:	/* must be mod=00 */
490 		i |= 5;
491 		break;
492 	case D_AX:
493 	case D_CX:
494 	case D_DX:
495 	case D_BX:
496 	case D_SP:
497 	case D_SI:
498 	case D_DI:
499 		i |= reg[base];
500 		break;
501 	}
502 	*andptr++ = i;
503 	return;
504 bad:
505 	diag("asmidx: bad address %D", a);
506 	*andptr++ = 0;
507 	return;
508 }
509 
510 static Relocsym *
511 genrelocsym(Sym *s, Relocsym**l)
512 {
513 	Relocsym *r;
514 
515 	*l = r = malloc(sizeof(Relocsym));
516 	r->s = s;
517 	r->reloc = nil;
518 	r->link = nil;
519 	return r;
520 }
521 
522 static void
523 genreloc(Sym *s, long pc, int type)
524 {
525 	Reloc *r;
526 	Relocsym *rs, **l;
527 
528 	if(relocs == nil)
529 		genrelocsym(nil, &relocs);
530 	l = &relocs;
531 	for(rs = *l; rs != nil; rs = *l) {
532 		l = &rs->link;
533 		if(rs->s == s)
534 			break;
535 	}
536 	if(rs == nil)
537 		rs = genrelocsym(s, l);
538 	r = malloc(sizeof(Reloc));
539 	r->type = type;
540 	r->pc = pc;
541 	r->link = rs->reloc;
542 	rs->reloc = r;
543 }
544 
545 void
546 wreloc(Sym *s, long pc)
547 {
548 	switch(s->type) {
549 	case SCONST:
550 		break;
551 	case SUNDEF:
552 		genreloc(s, pc, 'R');
553 		break;
554 	default:
555 		genreloc(nil, pc, 'R');
556 		break;
557 	}
558 }
559 
560 static void
561 put4(long v)
562 {
563 	if(reloca) {
564 		if(curp != P)
565 			wreloc(reloca->sym, curp->pc + andptr - &and[0]);
566 		reloca = nil;
567 	}
568 	andptr[0] = v;
569 	andptr[1] = v>>8;
570 	andptr[2] = v>>16;
571 	andptr[3] = v>>24;
572 	andptr += 4;
573 }
574 
575 long
576 vaddr(Adr *a)
577 {
578 	int t;
579 	long v;
580 	Sym *s;
581 
582 	t = a->type;
583 	v = a->offset;
584 	if(t == D_ADDR)
585 		t = a->index;
586 	switch(t) {
587 	case D_STATIC:
588 	case D_EXTERN:
589 		s = a->sym;
590 		if(s != nil) {
591 			if(reloc)
592 				reloca = a;
593 			switch(s->type) {
594 			case SUNDEF:
595 				break;
596 			case STEXT:
597 			case SCONST:
598 				v += s->value;
599 				break;
600 			default:
601 				v += INITDAT + s->value;
602 			}
603 		}
604 	}
605 	return v;
606 }
607 
608 void
609 asmand(Adr *a, int r)
610 {
611 	long v;
612 	int t;
613 	Adr aa;
614 
615 	v = a->offset;
616 	t = a->type;
617 	if(a->index != D_NONE) {
618 		if(t >= D_INDIR) {
619 			t -= D_INDIR;
620 			if(t == D_NONE) {
621 				*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
622 				asmidx(a, t);
623 				put4(v);
624 				return;
625 			}
626 			if(v == 0) {
627 				*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
628 				asmidx(a, t);
629 				return;
630 			}
631 			if(v >= -128 && v < 128) {
632 				*andptr++ = (1 << 6) | (4 << 0) | (r << 3);
633 				asmidx(a, t);
634 				*andptr++ = v;
635 				return;
636 			}
637 			*andptr++ = (2 << 6) | (4 << 0) | (r << 3);
638 			asmidx(a, t);
639 			put4(v);
640 			return;
641 		}
642 		switch(t) {
643 		default:
644 			goto bad;
645 		case D_STATIC:
646 		case D_EXTERN:
647 			aa.type = D_NONE+D_INDIR;
648 			break;
649 		case D_AUTO:
650 		case D_PARAM:
651 			aa.type = D_SP+D_INDIR;
652 			break;
653 		}
654 		aa.offset = vaddr(a);
655 		aa.index = a->index;
656 		aa.scale = a->scale;
657 		asmand(&aa, r);
658 		return;
659 	}
660 	if(t >= D_AL && t <= D_F0+7) {
661 		if(v)
662 			goto bad;
663 		*andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
664 		return;
665 	}
666 	if(t >= D_INDIR) {
667 		t -= D_INDIR;
668 		if(t == D_NONE) {
669 			*andptr++ = (0 << 6) | (5 << 0) | (r << 3);
670 			put4(v);
671 			return;
672 		}
673 		if(t == D_SP) {
674 			if(v == 0) {
675 				*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
676 				asmidx(a, D_SP);
677 				return;
678 			}
679 			if(v >= -128 && v < 128) {
680 				*andptr++ = (1 << 6) | (4 << 0) | (r << 3);
681 				asmidx(a, D_SP);
682 				*andptr++ = v;
683 				return;
684 			}
685 			*andptr++ = (2 << 6) | (4 << 0) | (r << 3);
686 			asmidx(a, D_SP);
687 			put4(v);
688 			return;
689 		}
690 		if(t >= D_AX && t <= D_DI) {
691 			if(v == 0 && t != D_BP) {
692 				*andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
693 				return;
694 			}
695 			if(v >= -128 && v < 128) {
696 				andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
697 				andptr[1] = v;
698 				andptr += 2;
699 				return;
700 			}
701 			*andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
702 			put4(v);
703 			return;
704 		}
705 		goto bad;
706 	}
707 	switch(a->type) {
708 	default:
709 		goto bad;
710 	case D_STATIC:
711 	case D_EXTERN:
712 		aa.type = D_NONE+D_INDIR;
713 		break;
714 	case D_AUTO:
715 	case D_PARAM:
716 		aa.type = D_SP+D_INDIR;
717 		break;
718 	}
719 	aa.index = D_NONE;
720 	aa.scale = 1;
721 	aa.offset = vaddr(a);
722 	asmand(&aa, r);
723 	return;
724 bad:
725 	diag("asmand: bad address %D", a);
726 	return;
727 }
728 
729 #define	E	0xff
730 uchar	ymovtab[] =
731 {
732 /* push */
733 	APUSHL,	Ycs,	Ynone,	0,	0x0e,E,0,0,
734 	APUSHL,	Yss,	Ynone,	0,	0x16,E,0,0,
735 	APUSHL,	Yds,	Ynone,	0,	0x1e,E,0,0,
736 	APUSHL,	Yes,	Ynone,	0,	0x06,E,0,0,
737 	APUSHL,	Yfs,	Ynone,	0,	0x0f,0xa0,E,0,
738 	APUSHL,	Ygs,	Ynone,	0,	0x0f,0xa8,E,0,
739 
740 	APUSHW,	Ycs,	Ynone,	0,	Pe,0x0e,E,0,
741 	APUSHW,	Yss,	Ynone,	0,	Pe,0x16,E,0,
742 	APUSHW,	Yds,	Ynone,	0,	Pe,0x1e,E,0,
743 	APUSHW,	Yes,	Ynone,	0,	Pe,0x06,E,0,
744 	APUSHW,	Yfs,	Ynone,	0,	Pe,0x0f,0xa0,E,
745 	APUSHW,	Ygs,	Ynone,	0,	Pe,0x0f,0xa8,E,
746 
747 /* pop */
748 	APOPL,	Ynone,	Yds,	0,	0x1f,E,0,0,
749 	APOPL,	Ynone,	Yes,	0,	0x07,E,0,0,
750 	APOPL,	Ynone,	Yss,	0,	0x17,E,0,0,
751 	APOPL,	Ynone,	Yfs,	0,	0x0f,0xa1,E,0,
752 	APOPL,	Ynone,	Ygs,	0,	0x0f,0xa9,E,0,
753 
754 	APOPW,	Ynone,	Yds,	0,	Pe,0x1f,E,0,
755 	APOPW,	Ynone,	Yes,	0,	Pe,0x07,E,0,
756 	APOPW,	Ynone,	Yss,	0,	Pe,0x17,E,0,
757 	APOPW,	Ynone,	Yfs,	0,	Pe,0x0f,0xa1,E,
758 	APOPW,	Ynone,	Ygs,	0,	Pe,0x0f,0xa9,E,
759 
760 /* mov seg */
761 	AMOVW,	Yes,	Yml,	1,	0x8c,0,0,0,
762 	AMOVW,	Ycs,	Yml,	1,	0x8c,1,0,0,
763 	AMOVW,	Yss,	Yml,	1,	0x8c,2,0,0,
764 	AMOVW,	Yds,	Yml,	1,	0x8c,3,0,0,
765 	AMOVW,	Yfs,	Yml,	1,	0x8c,4,0,0,
766 	AMOVW,	Ygs,	Yml,	1,	0x8c,5,0,0,
767 
768 	AMOVW,	Yml,	Yes,	2,	0x8e,0,0,0,
769 	AMOVW,	Yml,	Ycs,	2,	0x8e,1,0,0,
770 	AMOVW,	Yml,	Yss,	2,	0x8e,2,0,0,
771 	AMOVW,	Yml,	Yds,	2,	0x8e,3,0,0,
772 	AMOVW,	Yml,	Yfs,	2,	0x8e,4,0,0,
773 	AMOVW,	Yml,	Ygs,	2,	0x8e,5,0,0,
774 
775 /* mov cr */
776 	AMOVL,	Ycr0,	Yml,	3,	0x0f,0x20,0,0,
777 	AMOVL,	Ycr2,	Yml,	3,	0x0f,0x20,2,0,
778 	AMOVL,	Ycr3,	Yml,	3,	0x0f,0x20,3,0,
779 	AMOVL,	Ycr4,	Yml,	3,	0x0f,0x20,4,0,
780 
781 	AMOVL,	Yml,	Ycr0,	4,	0x0f,0x22,0,0,
782 	AMOVL,	Yml,	Ycr2,	4,	0x0f,0x22,2,0,
783 	AMOVL,	Yml,	Ycr3,	4,	0x0f,0x22,3,0,
784 	AMOVL,	Yml,	Ycr4,	4,	0x0f,0x22,4,0,
785 
786 /* mov dr */
787 	AMOVL,	Ydr0,	Yml,	3,	0x0f,0x21,0,0,
788 	AMOVL,	Ydr6,	Yml,	3,	0x0f,0x21,6,0,
789 	AMOVL,	Ydr7,	Yml,	3,	0x0f,0x21,7,0,
790 
791 	AMOVL,	Yml,	Ydr0,	4,	0x0f,0x23,0,0,
792 	AMOVL,	Yml,	Ydr6,	4,	0x0f,0x23,6,0,
793 	AMOVL,	Yml,	Ydr7,	4,	0x0f,0x23,7,0,
794 
795 /* mov tr */
796 	AMOVL,	Ytr6,	Yml,	3,	0x0f,0x24,6,0,
797 	AMOVL,	Ytr7,	Yml,	3,	0x0f,0x24,7,0,
798 
799 	AMOVL,	Yml,	Ytr6,	4,	0x0f,0x26,6,E,
800 	AMOVL,	Yml,	Ytr7,	4,	0x0f,0x26,7,E,
801 
802 /* lgdt, sgdt, lidt, sidt */
803 	AMOVL,	Ym,	Ygdtr,	4,	0x0f,0x01,2,0,
804 	AMOVL,	Ygdtr,	Ym,	3,	0x0f,0x01,0,0,
805 	AMOVL,	Ym,	Yidtr,	4,	0x0f,0x01,3,0,
806 	AMOVL,	Yidtr,	Ym,	3,	0x0f,0x01,1,0,
807 
808 /* lldt, sldt */
809 	AMOVW,	Yml,	Yldtr,	4,	0x0f,0x00,2,0,
810 	AMOVW,	Yldtr,	Yml,	3,	0x0f,0x00,0,0,
811 
812 /* lmsw, smsw */
813 	AMOVW,	Yml,	Ymsw,	4,	0x0f,0x01,6,0,
814 	AMOVW,	Ymsw,	Yml,	3,	0x0f,0x01,4,0,
815 
816 /* ltr, str */
817 	AMOVW,	Yml,	Ytask,	4,	0x0f,0x00,3,0,
818 	AMOVW,	Ytask,	Yml,	3,	0x0f,0x00,1,0,
819 
820 /* load full pointer */
821 	AMOVL,	Yml,	Ycol,	5,	0,0,0,0,
822 	AMOVW,	Yml,	Ycol,	5,	Pe,0,0,0,
823 
824 /* double shift */
825 	ASHLL,	Ycol,	Yml,	6,	0xa4,0xa5,0,0,
826 	ASHRL,	Ycol,	Yml,	6,	0xac,0xad,0,0,
827 
828 /* extra imul */
829 	AIMULL,	Yml,	Yrl,	7,	Pm,0xaf,0,0,
830 	0
831 };
832 
833 int
834 isax(Adr *a)
835 {
836 
837 	switch(a->type) {
838 	case D_AX:
839 	case D_AL:
840 	case D_AH:
841 	case D_INDIR+D_AX:
842 		return 1;
843 	}
844 	if(a->index == D_AX)
845 		return 1;
846 	return 0;
847 }
848 
849 void
850 subreg(Prog *p, int from, int to)
851 {
852 
853 	if(debug['Q'])
854 		print("\n%P	s/%R/%R/\n", p, from, to);
855 
856 	if(p->from.type == from)
857 		p->from.type = to;
858 	if(p->to.type == from)
859 		p->to.type = to;
860 
861 	if(p->from.index == from)
862 		p->from.index = to;
863 	if(p->to.index == from)
864 		p->to.index = to;
865 
866 	from += D_INDIR;
867 	if(p->from.type == from)
868 		p->from.type = to+D_INDIR;
869 	if(p->to.type == from)
870 		p->to.type = to+D_INDIR;
871 
872 	if(debug['Q'])
873 		print("%P\n", p);
874 }
875 
876 void
877 doasm(Prog *p)
878 {
879 	Optab *o;
880 	Prog *q, pp;
881 	uchar *t;
882 	int z, op, ft, tt;
883 	long v;
884 
885 	o = &optab[p->as];
886 	ft = oclass(&p->from) * Ymax;
887 	tt = oclass(&p->to) * Ymax;
888 	t = o->ytab;
889 	if(t == 0) {
890 		diag("asmins: noproto %P", p);
891 		return;
892 	}
893 	for(z=0; *t; z+=t[3],t+=4)
894 		if(ycover[ft+t[0]])
895 		if(ycover[tt+t[1]])
896 			goto found;
897 	goto domov;
898 
899 found:
900 	switch(o->prefix) {
901 	case Pq:	/* 16 bit escape and opcode escape */
902 		*andptr++ = Pe;
903 		*andptr++ = Pm;
904 		break;
905 
906 	case Pm:	/* opcode escape */
907 		*andptr++ = Pm;
908 		break;
909 
910 	case Pe:	/* 16 bit escape */
911 		*andptr++ = Pe;
912 		break;
913 
914 	case Pb:	/* botch */
915 		break;
916 	}
917 	v = vaddr(&p->from);
918 	op = o->op[z];
919 	switch(t[2]) {
920 	default:
921 		diag("asmins: unknown z %d %P", t[2], p);
922 		return;
923 
924 	case Zpseudo:
925 		break;
926 
927 	case Zlit:
928 		for(; op = o->op[z]; z++)
929 			*andptr++ = op;
930 		break;
931 
932 	case Zm_r:
933 		*andptr++ = op;
934 		asmand(&p->from, reg[p->to.type]);
935 		break;
936 
937 	case Zaut_r:
938 		*andptr++ = 0x8d;	/* leal */
939 		if(p->from.type != D_ADDR)
940 			diag("asmins: Zaut sb type ADDR");
941 		p->from.type = p->from.index;
942 		p->from.index = D_NONE;
943 		asmand(&p->from, reg[p->to.type]);
944 		p->from.index = p->from.type;
945 		p->from.type = D_ADDR;
946 		break;
947 
948 	case Zm_o:
949 		*andptr++ = op;
950 		asmand(&p->from, o->op[z+1]);
951 		break;
952 
953 	case Zr_m:
954 		*andptr++ = op;
955 		asmand(&p->to, reg[p->from.type]);
956 		break;
957 
958 	case Zo_m:
959 		*andptr++ = op;
960 		asmand(&p->to, o->op[z+1]);
961 		break;
962 
963 	case Zm_ibo:
964 		v = vaddr(&p->to);
965 		*andptr++ = op;
966 		asmand(&p->from, o->op[z+1]);
967 		*andptr++ = v;
968 		break;
969 
970 	case Zibo_m:
971 		*andptr++ = op;
972 		asmand(&p->to, o->op[z+1]);
973 		*andptr++ = v;
974 		break;
975 
976 	case Z_ib:
977 		v = vaddr(&p->to);
978 	case Zib_:
979 		*andptr++ = op;
980 		*andptr++ = v;
981 		break;
982 
983 	case Zib_rp:
984 		*andptr++ = op + reg[p->to.type];
985 		*andptr++ = v;
986 		break;
987 
988 	case Zil_rp:
989 		*andptr++ = op + reg[p->to.type];
990 		if(o->prefix == Pe) {
991 			*andptr++ = v;
992 			*andptr++ = v>>8;
993 		}
994 		else
995 			put4(v);
996 		break;
997 
998 	case Zib_rr:
999 		*andptr++ = op;
1000 		asmand(&p->to, reg[p->to.type]);
1001 		*andptr++ = v;
1002 		break;
1003 
1004 	case Z_il:
1005 		v = vaddr(&p->to);
1006 	case Zil_:
1007 		*andptr++ = op;
1008 		if(o->prefix == Pe) {
1009 			*andptr++ = v;
1010 			*andptr++ = v>>8;
1011 		}
1012 		else
1013 			put4(v);
1014 		break;
1015 
1016 	case Zm_ilo:
1017 		v = vaddr(&p->to);
1018 		*andptr++ = op;
1019 		asmand(&p->from, o->op[z+1]);
1020 		if(o->prefix == Pe) {
1021 			*andptr++ = v;
1022 			*andptr++ = v>>8;
1023 		}
1024 		else
1025 			put4(v);
1026 		break;
1027 
1028 	case Zilo_m:
1029 		*andptr++ = op;
1030 		asmand(&p->to, o->op[z+1]);
1031 		if(o->prefix == Pe) {
1032 			*andptr++ = v;
1033 			*andptr++ = v>>8;
1034 		}
1035 		else
1036 			put4(v);
1037 		break;
1038 
1039 	case Zil_rr:
1040 		*andptr++ = op;
1041 		asmand(&p->to, reg[p->to.type]);
1042 		if(o->prefix == Pe) {
1043 			*andptr++ = v;
1044 			*andptr++ = v>>8;
1045 		}
1046 		else
1047 			put4(v);
1048 		break;
1049 
1050 	case Z_rp:
1051 		*andptr++ = op + reg[p->to.type];
1052 		break;
1053 
1054 	case Zrp_:
1055 		*andptr++ = op + reg[p->from.type];
1056 		break;
1057 
1058 	case Zclr:
1059 		*andptr++ = op;
1060 		asmand(&p->to, reg[p->to.type]);
1061 		break;
1062 
1063 	case Zbr:
1064 		q = p->pcond;
1065 		if(q) {
1066 			v = q->pc - p->pc - 2;
1067 			if(v >= -128 && v <= 127) {
1068 				*andptr++ = op;
1069 				*andptr++ = v;
1070 			} else {
1071 				v -= 6-2;
1072 				*andptr++ = 0x0f;
1073 				*andptr++ = o->op[z+1];
1074 				*andptr++ = v;
1075 				*andptr++ = v>>8;
1076 				*andptr++ = v>>16;
1077 				*andptr++ = v>>24;
1078 			}
1079 		}
1080 		break;
1081 
1082 	case Zcall:
1083 		q = p->pcond;
1084 		if(q) {
1085 			v = q->pc - p->pc - 5;
1086 			if(reloc && curp != P) {
1087 				switch(p->to.sym->type) {
1088 				case SUNDEF:
1089 					v = 0;
1090 					genreloc(p->to.sym, p->pc, 'P');
1091 					break;
1092 				case SCONST:
1093 					diag("Zcall: %P", curp);
1094 					break;
1095 				}
1096 			}
1097 			*andptr++ = op;
1098 			*andptr++ = v;
1099 			*andptr++ = v>>8;
1100 			*andptr++ = v>>16;
1101 			*andptr++ = v>>24;
1102 		}
1103 		break;
1104 
1105 	case Zjmp:
1106 		q = p->pcond;
1107 		if(q) {
1108 			v = q->pc - p->pc - 2;
1109 			if(v >= -128 && v <= 127) {
1110 				*andptr++ = op;
1111 				*andptr++ = v;
1112 			} else {
1113 				v -= 5-2;
1114 				*andptr++ = o->op[z+1];
1115 				*andptr++ = v;
1116 				*andptr++ = v>>8;
1117 				*andptr++ = v>>16;
1118 				*andptr++ = v>>24;
1119 			}
1120 		}
1121 		break;
1122 
1123 	case Zloop:
1124 		q = p->pcond;
1125 		if(q) {
1126 			v = q->pc - p->pc - 2;
1127 			if(v < -128 && v > 127)
1128 				diag("loop too far: %P", p);
1129 			*andptr++ = op;
1130 			*andptr++ = v;
1131 		}
1132 		break;
1133 
1134 	case Zbyte:
1135 		*andptr++ = v;
1136 		if(op > 1) {
1137 			*andptr++ = v>>8;
1138 			if(op > 2) {
1139 				*andptr++ = v>>16;
1140 				*andptr++ = v>>24;
1141 			}
1142 		}
1143 		break;
1144 
1145 	case Zmov:
1146 		goto domov;
1147 	}
1148 	return;
1149 
1150 domov:
1151 	for(t=ymovtab; *t; t+=8)
1152 		if(p->as == t[0])
1153 		if(ycover[ft+t[1]])
1154 		if(ycover[tt+t[2]])
1155 			goto mfound;
1156 bad:
1157 	/*
1158 	 * here, the assembly has failed.
1159 	 * if its a byte instruction that has
1160 	 * unaddressable registers, try to
1161 	 * exchange registers and reissue the
1162 	 * instruction with the operands renamed.
1163 	 */
1164 	pp = *p;
1165 	z = p->from.type;
1166 	if(z >= D_BP && z <= D_DI) {
1167 		if(isax(&p->to)) {
1168 			*andptr++ = 0x87;			/* xchg lhs,bx */
1169 			asmand(&p->from, reg[D_BX]);
1170 			subreg(&pp, z, D_BX);
1171 			doasm(&pp);
1172 			*andptr++ = 0x87;			/* xchg lhs,bx */
1173 			asmand(&p->from, reg[D_BX]);
1174 		} else {
1175 			*andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
1176 			subreg(&pp, z, D_AX);
1177 			doasm(&pp);
1178 			*andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
1179 		}
1180 		return;
1181 	}
1182 	z = p->to.type;
1183 	if(z >= D_BP && z <= D_DI) {
1184 		if(isax(&p->from)) {
1185 			*andptr++ = 0x87;			/* xchg rhs,bx */
1186 			asmand(&p->to, reg[D_BX]);
1187 			subreg(&pp, z, D_BX);
1188 			doasm(&pp);
1189 			*andptr++ = 0x87;			/* xchg rhs,bx */
1190 			asmand(&p->to, reg[D_BX]);
1191 		} else {
1192 			*andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
1193 			subreg(&pp, z, D_AX);
1194 			doasm(&pp);
1195 			*andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
1196 		}
1197 		return;
1198 	}
1199 	diag("doasm: notfound t2=%lux from=%lux to=%lux %P", t[2], p->from.type, p->to.type, p);
1200 	return;
1201 
1202 mfound:
1203 	switch(t[3]) {
1204 	default:
1205 		diag("asmins: unknown mov %d %P", t[3], p);
1206 		break;
1207 
1208 	case 0:	/* lit */
1209 		for(z=4; t[z]!=E; z++)
1210 			*andptr++ = t[z];
1211 		break;
1212 
1213 	case 1:	/* r,m */
1214 		*andptr++ = t[4];
1215 		asmand(&p->to, t[5]);
1216 		break;
1217 
1218 	case 2:	/* m,r */
1219 		*andptr++ = t[4];
1220 		asmand(&p->from, t[5]);
1221 		break;
1222 
1223 	case 3:	/* r,m - 2op */
1224 		*andptr++ = t[4];
1225 		*andptr++ = t[5];
1226 		asmand(&p->to, t[6]);
1227 		break;
1228 
1229 	case 4:	/* m,r - 2op */
1230 		*andptr++ = t[4];
1231 		*andptr++ = t[5];
1232 		asmand(&p->from, t[6]);
1233 		break;
1234 
1235 	case 5:	/* load full pointer, trash heap */
1236 		if(t[4])
1237 			*andptr++ = t[4];
1238 		switch(p->to.index) {
1239 		default:
1240 			goto bad;
1241 		case D_DS:
1242 			*andptr++ = 0xc5;
1243 			break;
1244 		case D_SS:
1245 			*andptr++ = 0x0f;
1246 			*andptr++ = 0xb2;
1247 			break;
1248 		case D_ES:
1249 			*andptr++ = 0xc4;
1250 			break;
1251 		case D_FS:
1252 			*andptr++ = 0x0f;
1253 			*andptr++ = 0xb4;
1254 			break;
1255 		case D_GS:
1256 			*andptr++ = 0x0f;
1257 			*andptr++ = 0xb5;
1258 			break;
1259 		}
1260 		asmand(&p->from, reg[p->to.type]);
1261 		break;
1262 
1263 	case 6:	/* double shift */
1264 		z = p->from.type;
1265 		switch(z) {
1266 		default:
1267 			goto bad;
1268 		case D_CONST:
1269 			*andptr++ = 0x0f;
1270 			*andptr++ = t[4];
1271 			asmand(&p->to, reg[p->from.index]);
1272 			*andptr++ = p->from.offset;
1273 			break;
1274 		case D_CL:
1275 		case D_CX:
1276 			*andptr++ = 0x0f;
1277 			*andptr++ = t[5];
1278 			asmand(&p->to, reg[p->from.index]);
1279 			break;
1280 		}
1281 		break;
1282 
1283 	case 7: /* imul rm,r */
1284 		*andptr++ = t[4];
1285 		*andptr++ = t[5];
1286 		asmand(&p->from, reg[p->to.type]);
1287 		break;
1288 	}
1289 }
1290 
1291 void
1292 asmins(Prog *p)
1293 {
1294 
1295 	andptr = and;
1296 	doasm(p);
1297 }
1298