xref: /plan9-contrib/sys/src/cmd/kl/asm.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include	"l.h"
2 
3 #define	LPUT(c)\
4 	{\
5 		cbp[0] = (c)>>24;\
6 		cbp[1] = (c)>>16;\
7 		cbp[2] = (c)>>8;\
8 		cbp[3] = (c);\
9 		cbp += 4;\
10 		cbc -= 4;\
11 		if(cbc <= 0)\
12 			cflush();\
13 	}
14 
15 #define	CPUT(c)\
16 	{\
17 		cbp[0] = (c);\
18 		cbp++;\
19 		cbc--;\
20 		if(cbc <= 0)\
21 			cflush();\
22 	}
23 
24 long
25 entryvalue(void)
26 {
27 	char *a;
28 	Sym *s;
29 
30 	a = INITENTRY;
31 	if(*a >= '0' && *a <= '9')
32 		return atolwhex(a);
33 	s = lookup(a, 0);
34 	if(s->type == 0)
35 		return INITTEXT;
36 	if(s->type != STEXT && s->type != SLEAF)
37 		diag("entry not text: %s", s->name);
38 	return s->value;
39 }
40 
41 void
42 asmb(void)
43 {
44 	Prog *p;
45 	long t;
46 	Optab *o;
47 
48 	if(debug['v'])
49 		Bprint(&bso, "%5.2f asm\n", cputime());
50 	Bflush(&bso);
51 	seek(cout, HEADR, 0);
52 	pc = INITTEXT;
53 	for(p = firstp; p != P; p = p->link) {
54 		if(p->as == ATEXT) {
55 			curtext = p;
56 			autosize = p->to.offset + 4;
57 		}
58 		if(p->pc != pc) {
59 			diag("phase error %lux sb %lux\n",
60 				p->pc, pc);
61 			if(!debug['a'])
62 				prasm(curp);
63 			pc = p->pc;
64 		}
65 		curp = p;
66 		o = oplook(p);	/* could probably avoid this call */
67 		if(asmout(p, o, 0)) {
68 			p = p->link;
69 			pc += 4;
70 		}
71 		pc += o->size;
72 	}
73 	if(debug['a'])
74 		Bprint(&bso, "\n");
75 	Bflush(&bso);
76 	cflush();
77 
78 	curtext = P;
79 	switch(HEADTYPE) {
80 	case 0:
81 		seek(cout, HEADR+textsize, 0);
82 		break;
83 	case 1:
84 	case 2:
85 		seek(cout, HEADR+textsize, 0);
86 		break;
87 	}
88 	for(t = 0; t < datsize; t += sizeof(buf)-100) {
89 		if(datsize-t > sizeof(buf)-100)
90 			datblk(t, sizeof(buf)-100);
91 		else
92 			datblk(t, datsize-t);
93 	}
94 
95 	symsize = 0;
96 	lcsize = 0;
97 	if(!debug['s']) {
98 		if(debug['v'])
99 			Bprint(&bso, "%5.2f sym\n", cputime());
100 		Bflush(&bso);
101 		switch(HEADTYPE) {
102 		case 0:
103 			seek(cout, HEADR+textsize+datsize, 0);
104 			break;
105 		case 2:
106 		case 1:
107 			seek(cout, HEADR+textsize+datsize, 0);
108 			break;
109 		}
110 		if(!debug['s'])
111 			asmsym();
112 		if(debug['v'])
113 			Bprint(&bso, "%5.2f sp\n", cputime());
114 		Bflush(&bso);
115 		if(!debug['s'])
116 			asmlc();
117 		if(HEADTYPE == 0)	/* round up file length for boot image */
118 			if((symsize+lcsize) & 1)
119 				CPUT(0);
120 		cflush();
121 	}
122 
123 	seek(cout, 0L, 0);
124 	switch(HEADTYPE) {
125 	case 0:
126 		lput(0x1030107);		/* magic and sections */
127 		lput(textsize);			/* sizes */
128 		lput(datsize);
129 		lput(bsssize);
130 		lput(symsize);			/* nsyms */
131 		lput(entryvalue());		/* va of entry */
132 		lput(0L);
133 		lput(lcsize);
134 		break;
135 	case 1:
136 		break;
137 	case 2:
138 		lput(4*13*13+7);		/* magic */
139 		lput(textsize);			/* sizes */
140 		lput(datsize);
141 		lput(bsssize);
142 		lput(symsize);			/* nsyms */
143 		lput(entryvalue());		/* va of entry */
144 		lput(0L);
145 		lput(lcsize);
146 		break;
147 	}
148 	cflush();
149 }
150 
151 void
152 lput(long l)
153 {
154 
155 	LPUT(l);
156 }
157 
158 void
159 cflush(void)
160 {
161 	int n;
162 
163 	n = sizeof(buf.cbuf) - cbc;
164 	if(n)
165 		write(cout, buf.cbuf, n);
166 	cbp = buf.cbuf;
167 	cbc = sizeof(buf.cbuf);
168 }
169 
170 void
171 asmsym(void)
172 {
173 	Prog *p;
174 	Auto *a;
175 	Sym *s;
176 	int h;
177 
178 	s = lookup("etext", 0);
179 	if(s->type == STEXT)
180 		putsymb(s->name, 'T', s->value, s->version);
181 
182 	for(h=0; h<NHASH; h++)
183 		for(s=hash[h]; s!=S; s=s->link)
184 			switch(s->type) {
185 			case SCONST:
186 				putsymb(s->name, 'D', s->value, s->version);
187 				continue;
188 
189 			case SDATA:
190 				putsymb(s->name, 'D', s->value+INITDAT, s->version);
191 				continue;
192 
193 			case SBSS:
194 				putsymb(s->name, 'B', s->value+INITDAT, s->version);
195 				continue;
196 
197 			case SFILE:
198 				putsymb(s->name, 'f', s->value, s->version);
199 				continue;
200 			}
201 
202 	for(p=textp; p!=P; p=p->cond) {
203 		s = p->from.sym;
204 		if(s->type != STEXT && s->type != SLEAF)
205 			continue;
206 
207 		/* filenames first */
208 		for(a=p->to.autom; a; a=a->link)
209 			if(a->type == D_FILE)
210 				putsymb(a->sym->name, 'z', a->offset, 0);
211 			else
212 			if(a->type == D_FILE1)
213 				putsymb(a->sym->name, 'Z', a->offset, 0);
214 
215 		if(s->type == STEXT)
216 			putsymb(s->name, 'T', s->value, s->version);
217 		else
218 			putsymb(s->name, 'L', s->value, s->version);
219 
220 		/* frame, auto and param after */
221 		putsymb(".frame", 'm', p->to.offset+4, 0);
222 		for(a=p->to.autom; a; a=a->link)
223 			if(a->type == D_AUTO)
224 				putsymb(a->sym->name, 'a', -a->offset, 0);
225 			else
226 			if(a->type == D_PARAM)
227 				putsymb(a->sym->name, 'p', a->offset, 0);
228 	}
229 	if(debug['v'] || debug['n'])
230 		Bprint(&bso, "symsize = %lud\n", symsize);
231 	Bflush(&bso);
232 }
233 
234 void
235 putsymb(char *s, int t, long v, int ver)
236 {
237 	int i, f;
238 
239 	if(t == 'f')
240 		s++;
241 	LPUT(v);
242 	if(ver)
243 		t += 'a' - 'A';
244 	CPUT(t+0x80);			/* 0x80 is variable length */
245 
246 	if(t == 'Z' || t == 'z') {
247 		CPUT(s[0]);
248 		for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
249 			CPUT(s[i]);
250 			CPUT(s[i+1]);
251 		}
252 		CPUT(0);
253 		CPUT(0);
254 		i++;
255 	}
256 	else {
257 		for(i=0; s[i]; i++)
258 			CPUT(s[i]);
259 		CPUT(0);
260 	}
261 	symsize += 4 + 1 + i + 1;
262 
263 	if(debug['n']) {
264 		if(t == 'z' || t == 'Z') {
265 			Bprint(&bso, "%c %.8lux ", t, v);
266 			for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
267 				f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
268 				Bprint(&bso, "/%x", f);
269 			}
270 			Bprint(&bso, "\n");
271 			return;
272 		}
273 		if(ver)
274 			Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
275 		else
276 			Bprint(&bso, "%c %.8lux %s\n", t, v, s);
277 	}
278 }
279 
280 #define	MINLC	4
281 void
282 asmlc(void)
283 {
284 	long oldpc, oldlc;
285 	Prog *p;
286 	long v, s;
287 
288 	oldpc = INITTEXT;
289 	oldlc = 0;
290 	for(p = firstp; p != P; p = p->link) {
291 		if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
292 			if(p->as == ATEXT)
293 				curtext = p;
294 			if(debug['L'])
295 				Bprint(&bso, "%6lux %P\n",
296 					p->pc, p);
297 			continue;
298 		}
299 		if(debug['L'])
300 			Bprint(&bso, "\t\t%6ld", lcsize);
301 		v = (p->pc - oldpc) / MINLC;
302 		while(v) {
303 			s = 127;
304 			if(v < 127)
305 				s = v;
306 			CPUT(s+128);	/* 129-255 +pc */
307 			if(debug['L'])
308 				Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
309 			v -= s;
310 			lcsize++;
311 		}
312 		s = p->line - oldlc;
313 		oldlc = p->line;
314 		oldpc = p->pc + MINLC;
315 		if(s > 64 || s < -64) {
316 			CPUT(0);	/* 0 vv +lc */
317 			CPUT(s>>24);
318 			CPUT(s>>16);
319 			CPUT(s>>8);
320 			CPUT(s);
321 			if(debug['L']) {
322 				if(s > 0)
323 					Bprint(&bso, " lc+%ld(%d,%ld)\n",
324 						s, 0, s);
325 				else
326 					Bprint(&bso, " lc%ld(%d,%ld)\n",
327 						s, 0, s);
328 				Bprint(&bso, "%6lux %P\n",
329 					p->pc, p);
330 			}
331 			lcsize += 5;
332 			continue;
333 		}
334 		if(s > 0) {
335 			CPUT(0+s);	/* 1-64 +lc */
336 			if(debug['L']) {
337 				Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
338 				Bprint(&bso, "%6lux %P\n",
339 					p->pc, p);
340 			}
341 		} else {
342 			CPUT(64-s);	/* 65-128 -lc */
343 			if(debug['L']) {
344 				Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
345 				Bprint(&bso, "%6lux %P\n",
346 					p->pc, p);
347 			}
348 		}
349 		lcsize++;
350 	}
351 	while(lcsize & 1) {
352 		s = 129;
353 		CPUT(s);
354 		lcsize++;
355 	}
356 	if(debug['v'] || debug['L'])
357 		Bprint(&bso, "lcsize = %ld\n", lcsize);
358 	Bflush(&bso);
359 }
360 
361 void
362 datblk(long s, long n)
363 {
364 	Prog *p;
365 	char *cast;
366 	long l, fl, j, d;
367 	int i, c;
368 
369 	memset(buf.dbuf, 0, n+100);
370 	for(p = datap; p != P; p = p->link) {
371 		curp = p;
372 		l = p->from.sym->value + p->from.offset - s;
373 		c = p->reg;
374 		i = 0;
375 		if(l < 0) {
376 			if(l+c <= 0)
377 				continue;
378 			while(l < 0) {
379 				l++;
380 				i++;
381 			}
382 		}
383 		if(l >= n)
384 			continue;
385 		if(p->as != AINIT && p->as != ADYNT) {
386 			for(j=l+(c-i)-1; j>=l; j--)
387 				if(buf.dbuf[j]) {
388 					print("%P\n", p);
389 					diag("multiple initialization\n");
390 					break;
391 				}
392 		}
393 		switch(p->to.type) {
394 		default:
395 			diag("unknown mode in initialization\n%P\n", p);
396 			break;
397 
398 		case D_FCONST:
399 			switch(c) {
400 			default:
401 			case 4:
402 				fl = ieeedtof(&p->to.ieee);
403 				cast = (char*)&fl;
404 				for(; i<c; i++) {
405 					buf.dbuf[l] = cast[fnuxi8[i+4]];
406 					l++;
407 				}
408 				break;
409 			case 8:
410 				cast = (char*)&p->to.ieee;
411 				for(; i<c; i++) {
412 					buf.dbuf[l] = cast[fnuxi8[i]];
413 					l++;
414 				}
415 				break;
416 			}
417 			break;
418 
419 		case D_SCONST:
420 			for(; i<c; i++) {
421 				buf.dbuf[l] = p->to.sval[i];
422 				l++;
423 			}
424 			break;
425 
426 		case D_CONST:
427 			d = p->to.offset;
428 			if(p->to.sym) {
429 				if(p->to.sym->type == STEXT ||
430 				   p->to.sym->type == SLEAF)
431 					d += p->to.sym->value;
432 				if(p->to.sym->type == SDATA)
433 					d += p->to.sym->value + INITDAT;
434 				if(p->to.sym->type == SBSS)
435 					d += p->to.sym->value + INITDAT;
436 			}
437 			cast = (char*)&d;
438 			switch(c) {
439 			default:
440 				diag("bad nuxi %d %d\n%P\n", c, i, curp);
441 				break;
442 			case 1:
443 				for(; i<c; i++) {
444 					buf.dbuf[l] = cast[inuxi1[i]];
445 					l++;
446 				}
447 				break;
448 			case 2:
449 				for(; i<c; i++) {
450 					buf.dbuf[l] = cast[inuxi2[i]];
451 					l++;
452 				}
453 				break;
454 			case 4:
455 				for(; i<c; i++) {
456 					buf.dbuf[l] = cast[inuxi4[i]];
457 					l++;
458 				}
459 				break;
460 			}
461 			break;
462 		}
463 	}
464 	write(cout, buf.dbuf, n);
465 }
466 
467 #define	OP2(x)	(0x80000000|((x)<<19))
468 #define	OP3(x)	(0xc0000000|((x)<<19))
469 #define	OPB(x)	(0x00800000|((x)<<25))
470 #define	OPT(x)	(0x81d02000|((x)<<25))
471 #define	OPF1(x)	(0x81a00000|((x)<<5))
472 #define	OPF2(x)	(0x81a80000|((x)<<5))
473 #define	OPFB(x)	(0x01800000|((x)<<25))
474 
475 #define	OP_RRR(op,r1,r2,r3)\
476 	(0x00000000 | op |\
477 	(((r1)&31L)<<0) |\
478 	(((r2)&31L)<<14) |\
479 	(((r3)&31L)<<25))
480 #define	OP_IRR(op,i,r2,r3)\
481 	(0x00002000L | (op) |\
482 	(((i)&0x1fffL)<<0) |\
483 	(((r2)&31L)<<14) |\
484 	(((r3)&31L)<<25))
485 #define	OP_BRA(op,pc)\
486 	((op) |\
487 	(((pc)&0x3fffff)<<0))
488 
489 int
490 asmout(Prog *p, Optab *o, int aflag)
491 {
492 	long o1, o2, o3, o4, o5, v;
493 	Prog *ct;
494 	int r;
495 
496 	o1 = 0;
497 	o2 = 0;
498 	o3 = 0;
499 	o4 = 0;
500 	o5 = 0;
501 
502 	switch(o->type) {
503 	default:
504 		if(aflag)
505 			return 0;
506 		diag("unknown type %d\n", o->type);
507 		if(!debug['a'])
508 			prasm(p);
509 		break;
510 
511 	case 0:		/* pseudo ops */
512 		if(aflag) {
513 			if(p->link) {
514 				if(p->as == ATEXT) {
515 					ct = curtext;
516 					o2 = autosize;
517 					curtext = p;
518 					autosize = p->to.offset + 4;
519 					o1 = asmout(p->link, oplook(p->link), aflag);
520 					curtext = ct;
521 					autosize = o2;
522 				} else
523 					o1 = asmout(p->link, oplook(p->link), aflag);
524 			}
525 			return o1;
526 		}
527 		break;
528 
529 	case 1:		/* mov r1,r2 ==> OR r1,r0,r2 */
530 		o1 = OP_RRR(opcode(AOR), p->from.reg, REGZERO, p->to.reg);
531 		break;
532 
533 	case 2:		/* mov $c,r ==> add r1,r0,r2 */
534 		r = p->from.reg;
535 		if(r == NREG)
536 			r = o->param;
537 		v = regoff(&p->from);
538 		o1 = OP_IRR(opcode(AADD), v, r, p->to.reg);
539 		break;
540 
541 	case 3:		/* mov soreg, r */
542 		r = p->from.reg;
543 		if(r == NREG)
544 			r = o->param;
545 		v = regoff(&p->from);
546 		if(v == 0 && p->reg != NREG)
547 			o1 = OP_RRR(opcode(p->as), p->reg, r, p->to.reg);
548 		else
549 			o1 = OP_IRR(opcode(p->as), v, r, p->to.reg);
550 		break;
551 
552 	case 4:		/* mov r, soreg */
553 		r = p->to.reg;
554 		if(r == NREG)
555 			r = o->param;
556 		v = regoff(&p->to);
557 		if(v == 0 && p->reg != NREG)
558 			o1 = OP_RRR(opcode(p->as+AEND), p->reg, r, p->from.reg);
559 		else
560 			o1 = OP_IRR(opcode(p->as+AEND), v, r, p->from.reg);
561 		break;
562 
563 	case 5:		/* mov $lcon, reg => sethi, add */
564 		v = regoff(&p->from);
565 		o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff);	/* sethi */
566 		o2 = OP_IRR(opcode(AADD), (v&0x3ff), REGTMP, p->to.reg);
567 		break;
568 
569 	case 6:		/* mov asi, r[+r] */
570 		o1 = OP_RRR(opcode(p->as), p->reg, p->from.reg, p->to.reg);
571 		o1 |= (1<<23) | ((p->from.offset&0xff)<<5);
572 		break;
573 
574 	case 7:		/* mov [+r]r, asi */
575 		o1 = OP_RRR(opcode(p->as+AEND), p->reg, p->to.reg, p->from.reg);
576 		o1 |= (1<<23) | ((p->to.offset&0xff)<<5);
577 		break;
578 
579 	case 8:		/* mov r, preg and mov preg, r */
580 		if(p->to.type == D_PREG) {
581 			r = p->from.reg;
582 			switch(p->to.reg)
583 			{
584 			default:
585 				diag("unknown register P%d", p->to.reg);
586 			case D_Y:
587 				o1 = OP2(48);	/* wry */
588 				break;
589 			case D_PSR:
590 				o1 = OP2(49);	/* wrpsr */
591 				break;
592 			case D_WIM:
593 				o1 = OP2(50);	/* wrwim */
594 				break;
595 			case D_TBR:
596 				o1 = OP2(51);	/* wrtbr */
597 				break;
598 			}
599 			o1 = OP_IRR(o1, 0, r, 0);
600 			break;
601 		}
602 		if(p->from.type == D_PREG) {
603 			r = p->to.reg;
604 			switch(p->from.reg)
605 			{
606 			default:
607 				diag("unknown register P%d", p->to.reg);
608 			case D_Y:
609 				o1 = OP2(40);	/* rdy */
610 				break;
611 			case D_PSR:
612 				o1 = OP2(41);	/* rdpsr */
613 				break;
614 			case D_WIM:
615 				o1 = OP2(42);	/* rdwim */
616 				break;
617 			case D_TBR:
618 				o1 = OP2(43);	/* rdtbr */
619 				break;
620 			}
621 			o1 = OP_RRR(o1, 0, 0, r);
622 			break;
623 		}
624 		break;
625 
626 	case 9:		/* movb r,r */
627 		v = 24;
628 		if(p->as == AMOVH || p->as == AMOVHU)
629 			v = 16;
630 		r = ASRA;
631 		if(p->as == AMOVBU || p->as == AMOVHU)
632 			r = ASRL;
633 		o1 = OP_IRR(opcode(ASLL), v, p->from.reg, p->to.reg);
634 		o2 = OP_IRR(opcode(r), v, p->to.reg, p->to.reg);
635 		break;
636 
637 	case 10:	/* mov $loreg, reg */
638 		r = p->from.reg;
639 		if(r == NREG)
640 			r = o->param;
641 		v = regoff(&p->from);
642 		o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff);	/* sethi */
643 		o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
644 		o3 = OP_IRR(opcode(AADD), (v&0x3ff), REGTMP, p->to.reg);
645 		break;
646 
647 	case 11:	/* mov loreg, r */
648 		r = p->from.reg;
649 		if(r == NREG)
650 			r = o->param;
651 		v = regoff(&p->from);
652 		o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff);	/* sethi */
653 		o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
654 		o3 = OP_IRR(opcode(p->as), (v&0x3ff), REGTMP, p->to.reg);
655 		break;
656 
657 	case 12:	/* mov r, loreg */
658 		r = p->to.reg;
659 		if(r == NREG)
660 			r = o->param;
661 		v = regoff(&p->to);
662 		o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff);	/* sethi */
663 		o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
664 		o3 = OP_IRR(opcode(p->as+AEND), (v&0x3ff), REGTMP, p->from.reg);
665 		break;
666 
667 	case 13:	/* mov $ucon, r */
668 		v = regoff(&p->from);
669 		o1 = 0x1000000 | (p->to.reg<<25) | ((v>>10) & 0x3fffff);	/* sethi */
670 		break;
671 
672 	case 20:	/* op $scon,r */
673 		v = regoff(&p->from);
674 		r = p->reg;
675 		if(r == NREG)
676 			r = p->to.reg;
677 		o1 = OP_IRR(opcode(p->as), v, r, p->to.reg);
678 		break;
679 
680 	case 21:	/* op r1,r2 */
681 		r = p->reg;
682 		if(r == NREG)
683 			r = p->to.reg;
684 		o1 = OP_RRR(opcode(p->as), p->from.reg, r, p->to.reg);
685 		break;
686 
687 	case 22:	/* op $lcon,r */
688 		v = regoff(&p->from);
689 		r = p->reg;
690 		if(r == NREG)
691 			r = p->to.reg;
692 		o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff);	/* sethi */
693 		o2 = OP_IRR(opcode(AADD), (v&0x3ff), REGTMP, REGTMP);
694 		o3 = OP_RRR(opcode(p->as), REGTMP, r, p->to.reg);
695 		break;
696 
697 	case 23:	/* cmp r,r */
698 		o1 = OP_RRR(opcode(ASUBCC), p->to.reg, p->from.reg, REGZERO);
699 		break;
700 
701 	case 24:	/* cmp r,$c */
702 		v = regoff(&p->to);
703 		o1 = OP_IRR(opcode(ASUBCC), v, p->from.reg, REGZERO);
704 		break;
705 
706 	case 25:	/* cmp $c,r BOTCH, fix compiler */
707 		v = regoff(&p->from);
708 		o1 = OP_IRR(opcode(AADD), v, NREG, REGTMP);
709 		o2 = OP_RRR(opcode(ASUBCC), p->to.reg, REGTMP, REGZERO);
710 		break;
711 
712 	case 26:	/* op $ucon,r */
713 		v = regoff(&p->from);
714 		r = p->reg;
715 		if(r == NREG)
716 			r = p->to.reg;
717 		o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff);	/* sethi */
718 		o2 = OP_RRR(opcode(p->as), REGTMP, r, p->to.reg);
719 		break;
720 
721 	case 30:	/* jmp/jmpl soreg */
722 		if(aflag)
723 			return 0;
724 		v = regoff(&p->to);
725 		r = p->reg;
726 		if(r == NREG && p->as == AJMPL)
727 			r = 15;
728 		o1 = OP_IRR(opcode(AJMPL), v, p->to.reg, r);
729 		break;
730 
731 	case 31:	/* ba jmp */
732 		if(aflag)
733 			return 0;
734 		r = p->as;
735 		if(r == AJMP)
736 			r = ABA;
737 		v = 0;
738 		if(p->cond)
739 			v = p->cond->pc - p->pc;
740 		o1 = OP_BRA(opcode(r), v/4);
741 		if(r == ABA && p->link && p->cond && isnop(p->link)) {
742 			o2 = asmout(p->cond, oplook(p->cond), 1);
743 			if(o2) {
744 				o1 += 1;
745 				if(debug['a'])
746 					Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", p->pc, o1, o2, p);
747 				LPUT(o1);
748 				LPUT(o2);
749 				return 1;
750 			}
751 			/* cant set annul here because pc has already been counted */
752 		}
753 		break;
754 
755 	case 32:	/* jmpl lbra */
756 		if(aflag)
757 			return 0;
758 		v = 0;
759 		if(p->cond)
760 			v = p->cond->pc - p->pc;
761 		r = p->reg;
762 		if(r != NREG && r != 15)
763 			diag("cant jmpl other than R15\n");
764 		o1 = 0x40000000 | ((v/4) & 0x3fffffffL);	/* call */
765 		if(p->link && p->cond && isnop(p->link)) {
766 			o2 = asmout(p->cond, oplook(p->cond), 1);
767 			if(o2) {
768 				o1 += 1;
769 				if(debug['a'])
770 					Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", p->pc, o1, o2, p);
771 				LPUT(o1);
772 				LPUT(o2);
773 				return 1;
774 			}
775 		}
776 		break;
777 
778 	case 33:	/* trap r */
779 		if(aflag)
780 			return 0;
781 		o1 = opcode(p->as) | (p->from.reg<<14);
782 		break;
783 
784 	case 34:	/* rett r1,r2 -> jmpl (r1); rett (r2) */
785 		if(aflag)
786 			return 0;
787 		o1 = OP_IRR(opcode(AJMPL), 0, p->from.reg, REGZERO);
788 		o2 = OP_IRR(opcode(ARETT), 0, p->to.reg, REGZERO);
789 		break;
790 
791 	case 40:	/* ldfsr, stfsr, stdq */
792 		if(p->to.type == D_PREG) {
793 			r = p->from.reg;
794 			if(r == NREG)
795 				r = o->param;
796 			v = regoff(&p->from);
797 			if(p->to.reg == D_FSR) {
798 				o1 = OP_IRR(OP3(33), v, r, 0);
799 				break;
800 			}
801 			diag("unknown reg load %d", p->to.reg);
802 		} else {
803 			r = p->to.reg;
804 			if(r == NREG)
805 				r = o->param;
806 			v = regoff(&p->to);
807 			if(p->from.reg == D_FSR) {
808 				o1 = OP_IRR(OP3(37), v, r, 0);
809 				break;
810 			}
811 			if(p->as == AMOVD && p->from.reg == D_FPQ) {
812 				o1 = OP_IRR(OP3(38), v, r, 0);
813 				break;
814 			}
815 			diag("unknown reg store %d", p->from.reg);
816 		}
817 		break;
818 
819 	case 41:	/* ldf,ldd */
820 		r = p->from.reg;
821 		if(r == NREG)
822 			r = o->param;
823 		v = regoff(&p->from);
824 		if(p->as == AFMOVF || p->as == AMOVW) {
825 			o1 = OP_IRR(OP3(32), v, r, p->to.reg);
826 			break;
827 		}
828 		if(p->as == AMOVD || p->as == AFMOVD) {
829 			o1 = OP_IRR(OP3(35), v, r, p->to.reg);
830 			break;
831 		}
832 		diag("only MOVD and MOVW to FREG");
833 		break;
834 
835 	case 42:	/* ldd -> ldf,ldf */
836 		/* note should be ldd with proper allignment */
837 		r = p->from.reg;
838 		if(r == NREG)
839 			r = o->param;
840 		v = regoff(&p->from);
841 		o1 = OP_IRR(OP3(32), v, r, p->to.reg);
842 		o2 = OP_IRR(OP3(32), v+4, r, p->to.reg+1);
843 		break;
844 
845 	case 43:	/* stf */
846 		r = p->to.reg;
847 		if(r == NREG)
848 			r = o->param;
849 		v = regoff(&p->to);
850 		if(p->as == AFMOVF || p->as == AMOVW) {
851 			o1 = OP_IRR(OP3(36), v, r, p->from.reg);
852 			break;
853 		}
854 		if(p->as == AMOVD || p->as == AFMOVD) {
855 			o1 = OP_IRR(OP3(39), v, r, p->from.reg);
856 			break;
857 		}
858 		diag("only MOVD and MOVW from FREG");
859 		break;
860 
861 	case 44:	/* std -> stf,stf */
862 		/* note should be std with proper allignment */
863 		r = p->to.reg;
864 		if(r == NREG)
865 			r = o->param;
866 		v = regoff(&p->to);
867 		o1 = OP_IRR(OP3(36), v, r, p->from.reg);
868 		o2 = OP_IRR(OP3(36), v+4, r, p->from.reg+1);
869 		break;
870 
871 	case 45:	/* ldf lorg */
872 		r = p->from.reg;
873 		if(r == NREG)
874 			r = o->param;
875 		v = regoff(&p->from);
876 		o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff);	/* sethi */
877 		o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
878 		o3 = OP_IRR(OP3(32), v&0x3ff, REGTMP, p->to.reg);
879 		break;
880 
881 	case 46:	/* ldd lorg -> ldf,ldf */
882 		/* note should be ldd with proper allignment */
883 		r = p->from.reg;
884 		if(r == NREG)
885 			r = o->param;
886 		v = regoff(&p->from);
887 		o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff);	/* sethi */
888 		o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
889 		o3 = OP_IRR(OP3(32), (v&0x3ff), REGTMP, p->to.reg);
890 		o4 = OP_IRR(OP3(32), (v&0x3ff)+4, REGTMP, p->to.reg+1);
891 		break;
892 
893 	case 47:	/* stf lorg */
894 		r = p->to.reg;
895 		if(r == NREG)
896 			r = o->param;
897 		v = regoff(&p->to);
898 		o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff);	/* sethi */
899 		o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
900 		o3 = OP_IRR(OP3(36), v&0x3ff, REGTMP, p->from.reg);
901 		break;
902 
903 	case 48:	/* std lorg -> stf,stf */
904 		/* note should be std with proper allignment */
905 		r = p->to.reg;
906 		if(r == NREG)
907 			r = o->param;
908 		v = regoff(&p->to);
909 		o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff);	/* sethi */
910 		o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
911 		o3 = OP_IRR(OP3(36), (v&0x3ff), REGTMP, p->from.reg);
912 		o4 = OP_IRR(OP3(36), (v&0x3ff)+4, REGTMP, p->from.reg+1);
913 		break;
914 
915 	case 49:	/* fmovd -> fmovf,fmovf */
916 		o1 = OP_RRR(opcode(AFMOVF), p->from.reg, 0, p->to.reg);
917 		o2 = OP_RRR(opcode(AFMOVF), p->from.reg+1, 0, p->to.reg+1);
918 		break;
919 
920 	case 50:	/* fcmp */
921 		o1 = OP_RRR(opcode(p->as), p->to.reg, p->from.reg, 0);
922 		break;
923 
924 	case 51:	/* word */
925 		if(aflag)
926 			return 0;
927 		o1 = regoff(&p->from);
928 		break;
929 
930 	case 52:	/* div */
931 		r = p->reg;
932 		if(r == NREG)
933 			r = p->to.reg;
934 		o1 = OP_IRR(opcode(ASRA), 31, r, REGTMP);
935 		o2 = OP_IRR(OP2(48), 0, REGTMP, 0);
936 		o3 = OP_RRR(opcode(ADIV), p->from.reg, r, p->to.reg);
937 		break;
938 
939 	case 53:	/* divl */
940 		r = p->reg;
941 		if(r == NREG)
942 			r = p->to.reg;
943 		o1 = OP_IRR(OP2(48), 0, REGZERO, 0);
944 		o2 = OP_RRR(opcode(ADIVL), p->from.reg, r, p->to.reg);
945 		break;
946 
947 	case 54:	/* mod */
948 		r = p->reg;
949 		if(r == NREG)
950 			r = p->to.reg;
951 		o1 = OP_IRR(opcode(ASRA), 31, r, REGTMP);
952 		o2 = OP_IRR(OP2(48), 0, REGTMP, 0);
953 		o3 = OP_RRR(opcode(ADIV), p->from.reg, r, REGTMP);
954 		o4 = OP_RRR(opcode(AMUL), p->from.reg, REGTMP, REGTMP);
955 		o5 = OP_RRR(opcode(ASUB), REGTMP, r, p->to.reg);
956 		break;
957 
958 	case 55:	/* modl */
959 		r = p->reg;
960 		if(r == NREG)
961 			r = p->to.reg;
962 		o1 = OP_IRR(OP2(48), 0, REGZERO, 0);
963 		o2 = OP_RRR(opcode(ADIVL), p->from.reg, r, REGTMP);
964 		o3 = OP_RRR(opcode(AMUL), p->from.reg, REGTMP, REGTMP);
965 		o4 = OP_RRR(opcode(ASUB), REGTMP, r, p->to.reg);
966 		break;
967 
968 	case 56:	/* b(cc) -- annullable */
969 		if(aflag)
970 			return 0;
971 		r = p->as;
972 		v = 0;
973 		if(p->cond)
974 			v = p->cond->pc - p->pc;
975 		o1 = OP_BRA(opcode(r), v/4);
976 		if(p->link && p->cond && isnop(p->link))
977 		if(!debug['A']) {
978 			o2 = asmout(p->cond, oplook(p->cond), 2);
979 			if(o2) {
980 				o1 |= 1<<29;	/* annul */
981 				o1 += 1;
982 				if(debug['a'])
983 					Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", p->pc, o1, o2, p);
984 				LPUT(o1);
985 				LPUT(o2);
986 				return 1;
987 			}
988 		}
989 		break;
990 	}
991 	if(aflag)
992 		return o1;
993 	v = p->pc;
994 	switch(o->size) {
995 	default:
996 		if(debug['a'])
997 			Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
998 		break;
999 	case 4:
1000 		if(debug['a'])
1001 			Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
1002 		LPUT(o1);
1003 		break;
1004 	case 8:
1005 		if(debug['a'])
1006 			Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
1007 		LPUT(o1);
1008 		LPUT(o2);
1009 		break;
1010 	case 12:
1011 		if(debug['a'])
1012 			Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
1013 		LPUT(o1);
1014 		LPUT(o2);
1015 		LPUT(o3);
1016 		break;
1017 	case 16:
1018 		if(debug['a'])
1019 			Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
1020 				v, o1, o2, o3, o4, p);
1021 		LPUT(o1);
1022 		LPUT(o2);
1023 		LPUT(o3);
1024 		LPUT(o4);
1025 		break;
1026 	case 20:
1027 		if(debug['a'])
1028 			Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
1029 				v, o1, o2, o3, o4, o5, p);
1030 		LPUT(o1);
1031 		LPUT(o2);
1032 		LPUT(o3);
1033 		LPUT(o4);
1034 		LPUT(o5);
1035 		break;
1036 	}
1037 	return 0;
1038 }
1039 
1040 int
1041 isnop(Prog *p)
1042 {
1043 	if(p->as != AORN)
1044 		return 0;
1045 	if(p->reg != REGZERO && p->reg != NREG)
1046 		return 0;
1047 	if(p->from.type != D_REG || p->from.reg != REGZERO)
1048 		return 0;
1049 	if(p->to.type != D_REG || p->to.reg != REGZERO)
1050 		return 0;
1051 	return 1;
1052 }
1053 
1054 long
1055 opcode(int a)
1056 {
1057 	switch(a) {
1058 	case AADD:	return OP2(0);
1059 	case AADDCC:	return OP2(16);
1060 	case AADDX:	return OP2(8);
1061 	case AADDXCC:	return OP2(24);
1062 
1063 	case AMUL:	return OP2(10);
1064 	case ADIV:	return OP2(15);
1065 	case ADIVL:	return OP2(14);
1066 
1067 	case ATADDCC:	return OP2(32);
1068 	case ATADDCCTV:	return OP2(34);
1069 
1070 	case ASUB:	return OP2(4);
1071 	case ASUBCC:	return OP2(20);
1072 	case ASUBX:	return OP2(12);
1073 	case ASUBXCC:	return OP2(28);
1074 
1075 	case ATSUBCC:	return OP2(33);
1076 	case ATSUBCCTV:	return OP2(35);
1077 
1078 	case AMULSCC:	return OP2(36);
1079 	case ASAVE:	return OP2(60);
1080 	case ARESTORE:	return OP2(61);
1081 
1082 	case AAND:	return OP2(1);
1083 	case AANDCC:	return OP2(17);
1084 	case AANDN:	return OP2(5);
1085 	case AANDNCC:	return OP2(21);
1086 
1087 	case AOR:	return OP2(2);
1088 	case AORCC:	return OP2(18);
1089 	case AORN:	return OP2(6);
1090 	case AORNCC:	return OP2(22);
1091 
1092 	case AXOR:	return OP2(3);
1093 	case AXORCC:	return OP2(19);
1094 	case AXNOR:	return OP2(7);
1095 	case AXNORCC:	return OP2(23);
1096 
1097 	case ASLL:	return OP2(37);
1098 	case ASRL:	return OP2(38);
1099 	case ASRA:	return OP2(39);
1100 
1101 	case AJMPL:
1102 	case AJMP:	return OP2(56);
1103 	case ARETT:	return OP2(57);
1104 
1105 	case AMOVBU:	return OP3(1);	/* ldub */
1106 	case AMOVB:	return OP3(9);	/* ldsb */
1107 	case AMOVHU:	return OP3(2);	/* lduh */
1108 	case AMOVH:	return OP3(10);	/* ldsh */
1109 	case AMOVW:	return OP3(0);	/* ld */
1110 	case AMOVD:	return OP3(3);	/* ldd */
1111 
1112 	case AMOVBU+AEND:
1113 	case AMOVB+AEND:return OP3(5);	/* stb */
1114 
1115 	case AMOVHU+AEND:
1116 	case AMOVH+AEND:return OP3(6);	/* sth */
1117 
1118 	case AMOVW+AEND:return OP3(4);	/* st */
1119 
1120 	case AMOVD+AEND:return OP3(7);	/* std */
1121 
1122 	case ASWAP:			/* swap is symmetric */
1123 	case ASWAP+AEND:return OP3(15);
1124 
1125 	case ATAS:	return OP3(13);	/* tas is really ldstub */
1126 
1127 	case ABN:	return OPB(0);
1128 	case ABE:	return OPB(1);
1129 	case ABLE:	return OPB(2);
1130 	case ABL:	return OPB(3);
1131 	case ABLEU:	return OPB(4);
1132 	case ABCS:	return OPB(5);
1133 	case ABNEG:	return OPB(6);
1134 	case ABVS:	return OPB(7);
1135 	case ABA:	return OPB(8);
1136 	case ABNE:	return OPB(9);
1137 	case ABG:	return OPB(10);
1138 	case ABGE:	return OPB(11);
1139 	case ABGU:	return OPB(12);
1140 	case ABCC:	return OPB(13);
1141 	case ABPOS:	return OPB(14);
1142 	case ABVC:	return OPB(15);
1143 
1144 	case AFBA:	return OPFB(8);
1145 	case AFBE:	return OPFB(9);
1146 	case AFBG:	return OPFB(6);
1147 	case AFBGE:	return OPFB(11);
1148 	case AFBL:	return OPFB(4);
1149 	case AFBLE:	return OPFB(13);
1150 	case AFBLG:	return OPFB(2);
1151 	case AFBN:	return OPFB(0);
1152 	case AFBNE:	return OPFB(1);
1153 	case AFBO:	return OPFB(15);
1154 	case AFBU:	return OPFB(7);
1155 	case AFBUE:	return OPFB(10);
1156 	case AFBUG:	return OPFB(5);
1157 	case AFBUGE:	return OPFB(12);
1158 	case AFBUL:	return OPFB(3);
1159 	case AFBULE:	return OPFB(14);
1160 
1161 	case ATN:	return OPT(0);
1162 	case ATE:	return OPT(1);
1163 	case ATLE:	return OPT(2);
1164 	case ATL:	return OPT(3);
1165 	case ATLEU:	return OPT(4);
1166 	case ATCS:	return OPT(5);
1167 	case ATNEG:	return OPT(6);
1168 	case ATVS:	return OPT(7);
1169 	case ATA:	return OPT(8);
1170 	case ATNE:	return OPT(9);
1171 	case ATG:	return OPT(10);
1172 	case ATGE:	return OPT(11);
1173 	case ATGU:	return OPT(12);
1174 	case ATCC:	return OPT(13);
1175 	case ATPOS:	return OPT(14);
1176 	case ATVC:	return OPT(15);
1177 
1178 	case AFADDF:	return OPF1(65);
1179 	case AFADDD:	return OPF1(66);
1180 	case AFADDX:	return OPF1(67);
1181 	case AFSUBF:	return OPF1(69);
1182 	case AFSUBD:	return OPF1(70);
1183 	case AFSUBX:	return OPF1(71);
1184 	case AFMULF:	return OPF1(73);
1185 	case AFMULD:	return OPF1(74);
1186 	case AFMULX:	return OPF1(75);
1187 	case AFDIVF:	return OPF1(77);
1188 	case AFDIVD:	return OPF1(78);
1189 	case AFDIVX:	return OPF1(79);
1190 
1191 	case AFMOVF:	return OPF1(1);
1192 	case AFNEGF:	return OPF1(5);
1193 	case AFABSF:	return OPF1(9);
1194 
1195 	case AFSQRTF:	return OPF1(41);
1196 	case AFSQRTD:	return OPF1(42);
1197 	case AFSQRTX:	return OPF1(43);
1198 
1199 	case AFMOVWF:	return OPF1(196);
1200 	case AFMOVWD:	return OPF1(200);
1201 	case AFMOVWX:	return OPF1(204);
1202 	case AFMOVFW:	return OPF1(209);
1203 	case AFMOVDW:	return OPF1(210);
1204 	case AFMOVXW:	return OPF1(211);
1205 	case AFMOVFD:	return OPF1(201);
1206 	case AFMOVFX:	return OPF1(205);
1207 	case AFMOVDF:	return OPF1(198);
1208 	case AFMOVDX:	return OPF1(206);
1209 	case AFMOVXF:	return OPF1(199);
1210 	case AFMOVXD:	return OPF1(203);
1211 
1212 	case AFCMPF:	return OPF2(81);
1213 	case AFCMPD:	return OPF2(82);
1214 	case AFCMPX:	return OPF2(83);
1215 	case AFCMPEF:	return OPF2(85);
1216 	case AFCMPED:	return OPF2(86);
1217 	case AFCMPEX:	return OPF2(87);
1218 
1219 	case AUNIMP:	return 0;
1220 	}
1221 	diag("bad opcode %A\n", a);
1222 	return 0;
1223 }
1224