xref: /plan9-contrib/sys/src/cmd/8l/span.c (revision d46c239f8612929b7dbade67d0d071633df3a15d)
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\n", 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\n", 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 	0
829 };
830 
831 int
832 isax(Adr *a)
833 {
834 
835 	switch(a->type) {
836 	case D_AX:
837 	case D_AL:
838 	case D_AH:
839 	case D_INDIR+D_AX:
840 		return 1;
841 	}
842 	if(a->index == D_AX)
843 		return 1;
844 	return 0;
845 }
846 
847 void
848 subreg(Prog *p, int from, int to)
849 {
850 
851 	if(debug['Q'])
852 		print("\n%P	s/%R/%R/\n", p, from, to);
853 
854 	if(p->from.type == from)
855 		p->from.type = to;
856 	if(p->to.type == from)
857 		p->to.type = to;
858 
859 	if(p->from.index == from)
860 		p->from.index = to;
861 	if(p->to.index == from)
862 		p->to.index = to;
863 
864 	from += D_INDIR;
865 	if(p->from.type == from)
866 		p->from.type = to+D_INDIR;
867 	if(p->to.type == from)
868 		p->to.type = to+D_INDIR;
869 
870 	if(debug['Q'])
871 		print("%P\n", p);
872 }
873 
874 void
875 doasm(Prog *p)
876 {
877 	Optab *o;
878 	Prog *q, pp;
879 	uchar *t;
880 	int z, op, ft, tt;
881 	long v;
882 
883 	o = &optab[p->as];
884 	ft = oclass(&p->from) * Ymax;
885 	tt = oclass(&p->to) * Ymax;
886 	t = o->ytab;
887 	if(t == 0) {
888 		diag("asmins: noproto %P\n", p);
889 		return;
890 	}
891 	for(z=0; *t; z+=t[3],t+=4)
892 		if(ycover[ft+t[0]])
893 		if(ycover[tt+t[1]])
894 			goto found;
895 	goto domov;
896 
897 found:
898 	switch(o->prefix) {
899 	case Pq:	/* 16 bit escape and opcode escape */
900 		*andptr++ = Pe;
901 		*andptr++ = Pm;
902 		break;
903 
904 	case Pm:	/* opcode escape */
905 		*andptr++ = Pm;
906 		break;
907 
908 	case Pe:	/* 16 bit escape */
909 		*andptr++ = Pe;
910 		break;
911 
912 	case Pb:	/* botch */
913 		break;
914 	}
915 	v = vaddr(&p->from);
916 	op = o->op[z];
917 	switch(t[2]) {
918 	default:
919 		diag("asmins: unknown z %d %P\n", t[2], p);
920 		return;
921 
922 	case Zpseudo:
923 		break;
924 
925 	case Zlit:
926 		for(; op = o->op[z]; z++)
927 			*andptr++ = op;
928 		break;
929 
930 	case Zm_r:
931 		*andptr++ = op;
932 		asmand(&p->from, reg[p->to.type]);
933 		break;
934 
935 	case Zaut_r:
936 		*andptr++ = 0x8d;	/* leal */
937 		if(p->from.type != D_ADDR)
938 			diag("asmins: Zaut sb type ADDR");
939 		p->from.type = p->from.index;
940 		p->from.index = D_NONE;
941 		asmand(&p->from, reg[p->to.type]);
942 		p->from.index = p->from.type;
943 		p->from.type = D_ADDR;
944 		break;
945 
946 	case Zm_o:
947 		*andptr++ = op;
948 		asmand(&p->from, o->op[z+1]);
949 		break;
950 
951 	case Zr_m:
952 		*andptr++ = op;
953 		asmand(&p->to, reg[p->from.type]);
954 		break;
955 
956 	case Zo_m:
957 		*andptr++ = op;
958 		asmand(&p->to, o->op[z+1]);
959 		break;
960 
961 	case Zm_ibo:
962 		v = vaddr(&p->to);
963 		*andptr++ = op;
964 		asmand(&p->from, o->op[z+1]);
965 		*andptr++ = v;
966 		break;
967 
968 	case Zibo_m:
969 		*andptr++ = op;
970 		asmand(&p->to, o->op[z+1]);
971 		*andptr++ = v;
972 		break;
973 
974 	case Z_ib:
975 		v = vaddr(&p->to);
976 	case Zib_:
977 		*andptr++ = op;
978 		*andptr++ = v;
979 		break;
980 
981 	case Zib_rp:
982 		*andptr++ = op + reg[p->to.type];
983 		*andptr++ = v;
984 		break;
985 
986 	case Zil_rp:
987 		*andptr++ = op + reg[p->to.type];
988 		if(o->prefix == Pe) {
989 			*andptr++ = v;
990 			*andptr++ = v>>8;
991 		}
992 		else
993 			put4(v);
994 		break;
995 
996 	case Zib_rr:
997 		*andptr++ = op;
998 		asmand(&p->to, reg[p->to.type]);
999 		*andptr++ = v;
1000 		break;
1001 
1002 	case Z_il:
1003 		v = vaddr(&p->to);
1004 	case Zil_:
1005 		*andptr++ = op;
1006 		if(o->prefix == Pe) {
1007 			*andptr++ = v;
1008 			*andptr++ = v>>8;
1009 		}
1010 		else
1011 			put4(v);
1012 		break;
1013 
1014 	case Zm_ilo:
1015 		v = vaddr(&p->to);
1016 		*andptr++ = op;
1017 		asmand(&p->from, o->op[z+1]);
1018 		if(o->prefix == Pe) {
1019 			*andptr++ = v;
1020 			*andptr++ = v>>8;
1021 		}
1022 		else
1023 			put4(v);
1024 		break;
1025 
1026 	case Zilo_m:
1027 		*andptr++ = op;
1028 		asmand(&p->to, o->op[z+1]);
1029 		if(o->prefix == Pe) {
1030 			*andptr++ = v;
1031 			*andptr++ = v>>8;
1032 		}
1033 		else
1034 			put4(v);
1035 		break;
1036 
1037 	case Zil_rr:
1038 		*andptr++ = op;
1039 		asmand(&p->to, reg[p->to.type]);
1040 		if(o->prefix == Pe) {
1041 			*andptr++ = v;
1042 			*andptr++ = v>>8;
1043 		}
1044 		else
1045 			put4(v);
1046 		break;
1047 
1048 	case Z_rp:
1049 		*andptr++ = op + reg[p->to.type];
1050 		break;
1051 
1052 	case Zrp_:
1053 		*andptr++ = op + reg[p->from.type];
1054 		break;
1055 
1056 	case Zclr:
1057 		*andptr++ = op;
1058 		asmand(&p->to, reg[p->to.type]);
1059 		break;
1060 
1061 	case Zbr:
1062 		q = p->pcond;
1063 		if(q) {
1064 			v = q->pc - p->pc - 2;
1065 			if(v >= -128 && v <= 127) {
1066 				*andptr++ = op;
1067 				*andptr++ = v;
1068 			} else {
1069 				v -= 6-2;
1070 				*andptr++ = 0x0f;
1071 				*andptr++ = o->op[z+1];
1072 				*andptr++ = v;
1073 				*andptr++ = v>>8;
1074 				*andptr++ = v>>16;
1075 				*andptr++ = v>>24;
1076 			}
1077 		}
1078 		break;
1079 
1080 	case Zcall:
1081 		q = p->pcond;
1082 		if(q) {
1083 			v = q->pc - p->pc - 5;
1084 			if(reloc && curp != P) {
1085 				switch(p->to.sym->type) {
1086 				case SUNDEF:
1087 					v = 0;
1088 					genreloc(p->to.sym, p->pc, 'P');
1089 					break;
1090 				case SCONST:
1091 					diag("Zcall: %P", curp);
1092 					break;
1093 				}
1094 			}
1095 			*andptr++ = op;
1096 			*andptr++ = v;
1097 			*andptr++ = v>>8;
1098 			*andptr++ = v>>16;
1099 			*andptr++ = v>>24;
1100 		}
1101 		break;
1102 
1103 	case Zjmp:
1104 		q = p->pcond;
1105 		if(q) {
1106 			v = q->pc - p->pc - 2;
1107 			if(v >= -128 && v <= 127) {
1108 				*andptr++ = op;
1109 				*andptr++ = v;
1110 			} else {
1111 				v -= 5-2;
1112 				*andptr++ = o->op[z+1];
1113 				*andptr++ = v;
1114 				*andptr++ = v>>8;
1115 				*andptr++ = v>>16;
1116 				*andptr++ = v>>24;
1117 			}
1118 		}
1119 		break;
1120 
1121 	case Zloop:
1122 		q = p->pcond;
1123 		if(q) {
1124 			v = q->pc - p->pc - 2;
1125 			if(v < -128 && v > 127)
1126 				diag("loop too far: %P\n", p);
1127 			*andptr++ = op;
1128 			*andptr++ = v;
1129 		}
1130 		break;
1131 
1132 	case Zbyte:
1133 		*andptr++ = v;
1134 		if(op > 1) {
1135 			*andptr++ = v>>8;
1136 			if(op > 2) {
1137 				*andptr++ = v>>16;
1138 				*andptr++ = v>>24;
1139 			}
1140 		}
1141 		break;
1142 
1143 	case Zmov:
1144 		goto domov;
1145 	}
1146 	return;
1147 
1148 domov:
1149 	for(t=ymovtab; *t; t+=8)
1150 		if(p->as == t[0])
1151 		if(ycover[ft+t[1]])
1152 		if(ycover[tt+t[2]])
1153 			goto mfound;
1154 bad:
1155 	/*
1156 	 * here, the assembly has failed.
1157 	 * if its a byte instruction that has
1158 	 * unaddressable registers, try to
1159 	 * exchange registers and reissue the
1160 	 * instruction with the operands renamed.
1161 	 */
1162 	pp = *p;
1163 	z = p->from.type;
1164 	if(z >= D_BP && z <= D_DI) {
1165 		if(isax(&p->to)) {
1166 			*andptr++ = 0x87;			/* xchg lhs,bx */
1167 			asmand(&p->from, reg[D_BX]);
1168 			subreg(&pp, z, D_BX);
1169 			doasm(&pp);
1170 			*andptr++ = 0x87;			/* xchg lhs,bx */
1171 			asmand(&p->from, reg[D_BX]);
1172 		} else {
1173 			*andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
1174 			subreg(&pp, z, D_AX);
1175 			doasm(&pp);
1176 			*andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
1177 		}
1178 		return;
1179 	}
1180 	z = p->to.type;
1181 	if(z >= D_BP && z <= D_DI) {
1182 		if(isax(&p->from)) {
1183 			*andptr++ = 0x87;			/* xchg rhs,bx */
1184 			asmand(&p->to, reg[D_BX]);
1185 			subreg(&pp, z, D_BX);
1186 			doasm(&pp);
1187 			*andptr++ = 0x87;			/* xchg rhs,bx */
1188 			asmand(&p->to, reg[D_BX]);
1189 		} else {
1190 			*andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
1191 			subreg(&pp, z, D_AX);
1192 			doasm(&pp);
1193 			*andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
1194 		}
1195 		return;
1196 	}
1197 	diag("doasm: notfound t2=%lux from=%lux to=%lux %P\n", t[2], p->from.type, p->to.type, p);
1198 	return;
1199 
1200 mfound:
1201 	switch(t[3]) {
1202 	default:
1203 		diag("asmins: unknown mov %d %P\n", t[3], p);
1204 		break;
1205 
1206 	case 0:	/* lit */
1207 		for(z=4; t[z]!=E; z++)
1208 			*andptr++ = t[z];
1209 		break;
1210 
1211 	case 1:	/* r,m */
1212 		*andptr++ = t[4];
1213 		asmand(&p->to, t[5]);
1214 		break;
1215 
1216 	case 2:	/* m,r */
1217 		*andptr++ = t[4];
1218 		asmand(&p->from, t[5]);
1219 		break;
1220 
1221 	case 3:	/* r,m - 2op */
1222 		*andptr++ = t[4];
1223 		*andptr++ = t[5];
1224 		asmand(&p->to, t[6]);
1225 		break;
1226 
1227 	case 4:	/* m,r - 2op */
1228 		*andptr++ = t[4];
1229 		*andptr++ = t[5];
1230 		asmand(&p->from, t[6]);
1231 		break;
1232 
1233 	case 5:	/* load full pointer, trash heap */
1234 		if(t[4])
1235 			*andptr++ = t[4];
1236 		switch(p->to.index) {
1237 		default:
1238 			goto bad;
1239 		case D_DS:
1240 			*andptr++ = 0xc5;
1241 			break;
1242 		case D_SS:
1243 			*andptr++ = 0x0f;
1244 			*andptr++ = 0xb2;
1245 			break;
1246 		case D_ES:
1247 			*andptr++ = 0xc4;
1248 			break;
1249 		case D_FS:
1250 			*andptr++ = 0x0f;
1251 			*andptr++ = 0xb4;
1252 			break;
1253 		case D_GS:
1254 			*andptr++ = 0x0f;
1255 			*andptr++ = 0xb5;
1256 			break;
1257 		}
1258 		asmand(&p->from, reg[p->to.type]);
1259 		break;
1260 
1261 	case 6:	/* double shift */
1262 		z = p->from.type;
1263 		switch(z) {
1264 		default:
1265 			goto bad;
1266 		case D_CONST:
1267 			*andptr++ = 0x0f;
1268 			*andptr++ = t[4];
1269 			asmand(&p->to, reg[p->from.index]);
1270 			*andptr++ = p->from.offset;
1271 			break;
1272 		case D_CL:
1273 		case D_CX:
1274 			*andptr++ = 0x0f;
1275 			*andptr++ = t[5];
1276 			asmand(&p->to, reg[p->from.index]);
1277 			break;
1278 		}
1279 		break;
1280 	}
1281 }
1282 
1283 void
1284 asmins(Prog *p)
1285 {
1286 
1287 	andptr = and;
1288 	doasm(p);
1289 }
1290