xref: /plan9-contrib/sys/src/cmd/il/asm.c (revision ce95e1b3727b9cb1c223ffbed69aff21a8ced255)
1 #include	"l.h"
2 
3 long	OFFSET;
4 
5 xlong
entryvalue(void)6 entryvalue(void)
7 {
8 	char *a;
9 	Sym *s;
10 
11 	a = INITENTRY;
12 	if(*a >= '0' && *a <= '9')
13 		return atolwhex(a);
14 	s = lookup(a, 0);
15 	if(s->type == 0)
16 		return INITTEXT;
17 	if(s->type != STEXT && s->type != SLEAF)
18 		diag("entry not text: %s", s->name);
19 	return s->value + INITTEXT;
20 }
21 
22 void
asmb(void)23 asmb(void)
24 {
25 	Prog *p;
26 	long t, etext;
27 	Optab *o;
28 
29 	if(debug['v'])
30 		Bprint(&bso, "%5.2f asm\n", cputime());
31 	Bflush(&bso);
32 	OFFSET = HEADR;
33 	seek(cout, OFFSET, 0);
34 	pc = 0;
35 	for(p = firstp; p != P; p = p->link) {
36 		if(p->as == ATEXT) {
37 			/* align on word boundary */
38 			if(!debug['c'] && (pc & 2) != 0){
39 				nopalign.pc = pc;
40 				pc += asmout(&nopalign, oplook(&nopalign), 0);
41 			}
42 			curtext = p;
43 			autosize = p->to.offset + ptrsize;
44 		}
45 		if(p->pc != pc) {
46 			diag("phase error %lux sb %lux",
47 				p->pc, pc);
48 			if(!debug['a'])
49 				prasm(curp);
50 			pc = p->pc;
51 		}
52 		curp = p;
53 		o = oplook(p);	/* could probably avoid this call */
54 		pc += asmout(p, o, 0);
55 	}
56 	if(debug['a'])
57 		Bprint(&bso, "\n");
58 	Bflush(&bso);
59 	cflush();
60 
61 	etext = textsize;
62 	for(t = pc; t < etext; t += sizeof(buf)-100) {
63 		if(etext-t > sizeof(buf)-100)
64 			datblk(t, sizeof(buf)-100, 1);
65 		else
66 			datblk(t, etext-t, 1);
67 	}
68 
69 	Bflush(&bso);
70 	cflush();
71 
72 	curtext = P;
73 	switch(HEADTYPE) {
74 	case 0:
75 	case 4:
76 		OFFSET = rnd(HEADR+textsize, 4096);
77 		seek(cout, OFFSET, 0);
78 		break;
79 	case 1:
80 	case 2:
81 	case 3:
82 	case 5:
83 	case 6:
84 		OFFSET = HEADR+textsize;
85 		seek(cout, OFFSET, 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, 0);
91 		else
92 			datblk(t, datsize-t, 0);
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 		case 4:
104 			OFFSET = rnd(HEADR+textsize, 4096)+datsize;
105 			seek(cout, OFFSET, 0);
106 			break;
107 		case 3:
108 		case 2:
109 		case 1:
110 		case 5:
111 		case 6:
112 			OFFSET = HEADR+textsize+datsize;
113 			seek(cout, OFFSET, 0);
114 			break;
115 		}
116 		if(!debug['s'])
117 			asmsym();
118 		if(debug['v'])
119 			Bprint(&bso, "%5.2f pc\n", cputime());
120 		Bflush(&bso);
121 		if(!debug['s'])
122 			asmlc();
123 		cflush();
124 	}
125 
126 	if(debug['v'])
127 		Bprint(&bso, "%5.2f header\n", cputime());
128 	Bflush(&bso);
129 	OFFSET = 0;
130 	seek(cout, OFFSET, 0);
131 	switch(HEADTYPE) {
132 	case 1:
133 		break;
134 	case 2:
135 		/* XXX expanded header needed? */
136 		t = thechar == 'j' ? 30 : 29;
137 		lput(((((4*t)+0)*t)+7));	/* magic */
138 		lput(textsize);			/* sizes */
139 		lput(datsize);
140 		lput(bsssize);
141 		lput(symsize);			/* nsyms */
142 		lput(entryvalue());		/* va of entry */
143 		lput(0L);
144 		lput(lcsize);
145 		break;
146 	case 5:
147 		if(thechar == 'j')
148 			elf64(243, ELFDATA2LSB, 0, nil);		/* 243 is RISCV */
149 		else
150 			elf32(243, ELFDATA2LSB, 0, nil);
151 	}
152 	cflush();
153 }
154 
155 void
strnput(char * s,int n)156 strnput(char *s, int n)
157 {
158 	for(; *s; s++){
159 		cput(*s);
160 		n--;
161 	}
162 	for(; n > 0; n--)
163 		cput(0);
164 }
165 
166 void
cput(int c)167 cput(int c)
168 {
169 	cbp[0] = c;
170 	cbp++;
171 	cbc--;
172 	if(cbc <= 0)
173 		cflush();
174 }
175 
176 void
wput(long l)177 wput(long l)
178 {
179 
180 	cbp[0] = l>>8;
181 	cbp[1] = l;
182 	cbp += 2;
183 	cbc -= 2;
184 	if(cbc <= 0)
185 		cflush();
186 }
187 
188 void
wputl(long l)189 wputl(long l)
190 {
191 
192 	cbp[0] = l;
193 	cbp[1] = l>>8;
194 	cbp += 2;
195 	cbc -= 2;
196 	if(cbc <= 0)
197 		cflush();
198 }
199 
200 void
lput(long l)201 lput(long l)
202 {
203 
204 	cbp[0] = l>>24;
205 	cbp[1] = l>>16;
206 	cbp[2] = l>>8;
207 	cbp[3] = l;
208 	cbp += 4;
209 	cbc -= 4;
210 	if(cbc <= 0)
211 		cflush();
212 }
213 
214 void
lputl(long l)215 lputl(long l)
216 {
217 
218 	cbp[3] = l>>24;
219 	cbp[2] = l>>16;
220 	cbp[1] = l>>8;
221 	cbp[0] = l;
222 	cbp += 4;
223 	cbc -= 4;
224 	if(cbc <= 0)
225 		cflush();
226 }
227 
228 void
llput(vlong v)229 llput(vlong v)
230 {
231 	lput(v>>32);
232 	lput(v);
233 }
234 
235 void
llputl(vlong v)236 llputl(vlong v)
237 {
238 	lputl(v);
239 	lputl(v>>32);
240 }
241 
242 void
cflush(void)243 cflush(void)
244 {
245 	int n;
246 
247 	n = sizeof(buf.cbuf) - cbc;
248 	if(n)
249 		write(cout, buf.cbuf, n);
250 	cbp = buf.cbuf;
251 	cbc = sizeof(buf.cbuf);
252 }
253 
254 void
nopstat(char * f,Count * c)255 nopstat(char *f, Count *c)
256 {
257 	if(c->outof)
258 	Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f,
259 		c->outof - c->count, c->outof,
260 		(double)(c->outof - c->count)/c->outof);
261 }
262 
263 void
asmsym(void)264 asmsym(void)
265 {
266 	Prog *p;
267 	Auto *a;
268 	Sym *s;
269 	int h;
270 
271 	s = lookup("etext", 0);
272 	if(s->type == STEXT)
273 		putsymb(s->name, 'T', s->value+INITTEXT, s->version);
274 
275 	for(h=0; h<NHASH; h++)
276 		for(s=hash[h]; s!=S; s=s->link)
277 			switch(s->type) {
278 			case SCONST:
279 				putsymb(s->name, 'D', s->value, s->version);
280 				continue;
281 
282 			case SSTRING:
283 				putsymb(s->name, 'T', s->value, s->version);
284 				continue;
285 
286 			case SDATA:
287 				putsymb(s->name, 'D', s->value+INITDAT, s->version);
288 				continue;
289 
290 			case SBSS:
291 				putsymb(s->name, 'B', s->value+INITDAT, s->version);
292 				continue;
293 
294 			case SFILE:
295 				putsymb(s->name, 'f', s->value, s->version);
296 				continue;
297 			}
298 
299 	for(p=textp; p!=P; p=p->cond) {
300 		s = p->from.sym;
301 		if(s->type != STEXT && s->type != SLEAF)
302 			continue;
303 
304 		/* filenames first */
305 		for(a=p->to.autom; a; a=a->link)
306 			if(a->type == D_FILE)
307 				putsymb(a->asym->name, 'z', a->aoffset, 0);
308 			else
309 			if(a->type == D_FILE1)
310 				putsymb(a->asym->name, 'Z', a->aoffset, 0);
311 
312 		if(s->type == STEXT)
313 			putsymb(s->name, 'T', s->value+INITTEXT, s->version);
314 		else
315 			putsymb(s->name, 'L', s->value+INITTEXT, s->version);
316 
317 		/* frame, auto and param after */
318 		putsymb(".frame", 'm', p->to.offset+ptrsize, 0);
319 		for(a=p->to.autom; a; a=a->link)
320 			if(a->type == D_AUTO)
321 				putsymb(a->asym->name, 'a', -a->aoffset, 0);
322 			else
323 			if(a->type == D_PARAM)
324 				putsymb(a->asym->name, 'p', a->aoffset, 0);
325 	}
326 	if(debug['v'] || debug['n'])
327 		Bprint(&bso, "symsize = %lud\n", symsize);
328 	Bflush(&bso);
329 }
330 
331 void
putsymb(char * s,int t,vlong v,int ver)332 putsymb(char *s, int t, vlong v, int ver)
333 {
334 	int i, f, l;
335 
336 	if(t == 'f')
337 		s++;
338 	if(thechar == 'j'){
339 		l = 8;
340 		llput(v);
341 	}else{
342 		l = 4;
343 		lput(v);
344 	}
345 	if(ver)
346 		t += 'a' - 'A';
347 	cput(t+0x80);			/* 0x80 is variable length */
348 
349 	if(t == 'Z' || t == 'z') {
350 		cput(s[0]);
351 		for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
352 			cput(s[i]);
353 			cput(s[i+1]);
354 		}
355 		cput(0);
356 		cput(0);
357 		i++;
358 	}
359 	else {
360 		for(i=0; s[i]; i++)
361 			cput(s[i]);
362 		cput(0);
363 	}
364 	symsize += l + 1 + i + 1;
365 
366 	if(debug['n']) {
367 		if(t == 'z' || t == 'Z') {
368 			Bprint(&bso, "%c %.8llux ", t, v);
369 			for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
370 				f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
371 				Bprint(&bso, "/%x", f);
372 			}
373 			Bprint(&bso, "\n");
374 			return;
375 		}
376 		if(ver)
377 			Bprint(&bso, "%c %.8llux %s<%d>\n", t, v, s, ver);
378 		else
379 			Bprint(&bso, "%c %.8llux %s\n", t, v, s);
380 	}
381 }
382 
383 #define	MINLC	2
384 void
asmlc(void)385 asmlc(void)
386 {
387 	long oldpc, oldlc;
388 	Prog *p;
389 	long v, s;
390 
391 	oldpc = 0;
392 	oldlc = 0;
393 	for(p = firstp; p != P; p = p->link) {
394 		if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
395 			if(p->as == ATEXT)
396 				curtext = p;
397 			if(debug['L'])
398 				Bprint(&bso, "%6lux %P\n",
399 					p->pc, p);
400 			continue;
401 		}
402 		if(debug['L'])
403 			Bprint(&bso, "\t\t%6ld", lcsize);
404 		v = (p->pc - oldpc) / MINLC;
405 		while(v) {
406 			s = 127;
407 			if(v < 127)
408 				s = v;
409 			cput(s+128);	/* 129-255 +pc */
410 			if(debug['L'])
411 				Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
412 			v -= s;
413 			lcsize++;
414 		}
415 		s = p->line - oldlc;
416 		oldlc = p->line;
417 		oldpc = p->pc + MINLC;
418 		if(s > 64 || s < -64) {
419 			cput(0);	/* 0 vv +lc */
420 			cput(s>>24);
421 			cput(s>>16);
422 			cput(s>>8);
423 			cput(s);
424 			if(debug['L']) {
425 				if(s > 0)
426 					Bprint(&bso, " lc+%ld(%d,%ld)\n",
427 						s, 0, s);
428 				else
429 					Bprint(&bso, " lc%ld(%d,%ld)\n",
430 						s, 0, s);
431 				Bprint(&bso, "%6lux %P\n",
432 					p->pc, p);
433 			}
434 			lcsize += 5;
435 			continue;
436 		}
437 		if(s > 0) {
438 			cput(0+s);	/* 1-64 +lc */
439 			if(debug['L']) {
440 				Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
441 				Bprint(&bso, "%6lux %P\n",
442 					p->pc, p);
443 			}
444 		} else {
445 			cput(64-s);	/* 65-128 -lc */
446 			if(debug['L']) {
447 				Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
448 				Bprint(&bso, "%6lux %P\n",
449 					p->pc, p);
450 			}
451 		}
452 		lcsize++;
453 	}
454 	while(lcsize & 1) {
455 		s = 129;
456 		cput(s);
457 		lcsize++;
458 	}
459 	if(debug['v'] || debug['L'])
460 		Bprint(&bso, "lcsize = %ld\n", lcsize);
461 	Bflush(&bso);
462 }
463 
464 void
datblk(long s,long n,int str)465 datblk(long s, long n, int str)
466 {
467 	Prog *p;
468 	char *cast;
469 	vlong d;
470 	long l, fl, j;
471 	int i, c;
472 
473 	memset(buf.dbuf, 0, n+100);
474 	for(p = datap; p != P; p = p->link) {
475 		curp = p;
476 		if(str != (p->from.sym->type == SSTRING))
477 			continue;
478 		l = p->from.sym->value + p->from.offset - s;
479 		c = p->reg;
480 		i = 0;
481 		if(l < 0) {
482 			if(l+c <= 0)
483 				continue;
484 			while(l < 0) {
485 				l++;
486 				i++;
487 			}
488 		}
489 		if(l >= n)
490 			continue;
491 		if(p->as != AINIT && p->as != ADYNT) {
492 			for(j=l+(c-i)-1; j>=l; j--)
493 				if(buf.dbuf[j]) {
494 					print("%P\n", p);
495 					diag("multiple initialization");
496 					break;
497 				}
498 		}
499 		switch(p->to.type) {
500 		default:
501 			diag("unknown mode in initialization\n%P", p);
502 			break;
503 
504 		case D_FCONST:
505 			switch(c) {
506 			default:
507 			case 4:
508 				fl = ieeedtof(p->to.ieee);
509 				cast = (char*)&fl;
510 				for(; i<c; i++) {
511 					buf.dbuf[l] = cast[fnuxi8[i]];
512 					l++;
513 				}
514 				break;
515 			case 8:
516 				cast = (char*)p->to.ieee;
517 				for(; i<c; i++) {
518 					buf.dbuf[l] = cast[fnuxi8[i]];
519 					l++;
520 				}
521 				break;
522 			}
523 			break;
524 
525 		case D_SCONST:
526 			for(; i<c; i++) {
527 				buf.dbuf[l] = p->to.sval[i];
528 				l++;
529 			}
530 			break;
531 
532 		case D_VCONST:
533 			d = *p->to.vval;
534 			goto dconst;
535 
536 		case D_CONST:
537 			d = p->to.offset;
538 		dconst:
539 			if(p->to.sym) {
540 				switch(p->to.sym->type) {
541 				case STEXT:
542 				case SLEAF:
543 				case SSTRING:
544 					d += (p->to.sym->value + INITTEXT);
545 					break;
546 				case SDATA:
547 				case SBSS:
548 					d += (p->to.sym->value + INITDAT);
549 					break;
550 				}
551 			}
552 			cast = (char*)&d;
553 			switch(c) {
554 			default:
555 				diag("bad nuxi %d %d\n%P", c, i, curp);
556 				break;
557 			case 1:
558 				for(; i<c; i++) {
559 					buf.dbuf[l] = cast[inuxi1[i]];
560 					l++;
561 				}
562 				break;
563 			case 2:
564 				for(; i<c; i++) {
565 					buf.dbuf[l] = cast[inuxi2[i]];
566 					l++;
567 				}
568 				break;
569 			case 4:
570 				for(; i<c; i++) {
571 					buf.dbuf[l] = cast[inuxi4[i]];
572 					l++;
573 				}
574 				break;
575 			case 8:
576 				for(; i<c; i++) {
577 					buf.dbuf[l] = cast[inuxi8[i]];
578 					l++;
579 				}
580 				break;
581 			}
582 			break;
583 		}
584 		if(debug['d'] && i == c) {
585 			Bprint(&bso, "%.8llux", l+s+INITDAT-c);
586 			for(j = -c; j<0; j++)
587 				Bprint(&bso, " %.2ux", ((uchar*)buf.dbuf)[l + j]);
588 			Bprint(&bso, "\t%P\n", curp);
589 		}
590 	}
591 	write(cout, buf.dbuf, n);
592 }
593 
594 #define R(r) ((r)&0x1F)
595 #define OPX	(0x3 | o->op<<2)
596 #define OPF (OPX | o->func3<<12)
597 #define OP_R(rs1,rs2,rd)\
598 	(OPF | rd<<7 | R(rs1)<<15 | R(rs2)<<20 | o->param<<25)
599 #define OP_RF(rs1,rs2,rd,rm)\
600 	(OPX | rm<<12 | rd<<7 | R(rs1)<<15 | R(rs2)<<20 | o->param<<25)
601 #define OP_RO(rs1,rs2,rd)\
602 	(0x3 | OOP<<2 | o->func3<<12 | rd<<7 | R(rs1)<<15 | R(rs2)<<20)
603 #define OP_ADD(rs1,rs2,rd)\
604 	(0x3 | OOP<<2 | rd<<7 | R(rs1)<<15 | R(rs2)<<20)
605 #define OP_I(rs1,rd,imm)\
606 	(OPF | rd<<7 | R(rs1)<<15 | (imm)<<20)
607 #define OP_FI(func3,rs1,rd,imm)\
608 	(OPX | func3<<12 | rd<<7 | R(rs1)<<15 | (imm)<<20)
609 #define OP_S(rs1,rs2,imm)\
610 	(OPF | (imm&0x1F)<<7 | R(rs1)<<15 | R(rs2)<<20 | (imm>>5)<<25)
611 #define OP_B(rs1,rs2,imm)\
612 	(OPF | R(rs1)<<15 | R(rs2)<<20 | (imm&0x800)>>4 | (imm&0x1E)<<7 | \
613 	 (imm&0x7E0)<<20 | (imm&0x1000)<<19)
614 #define OP_U(rd,imm)\
615 	(0x3 | OLUI<<2 | rd<<7 | (imm&0xFFFFF000))
616 #define OP_UP(rd,imm)\
617 	(0x3 | OAUIPC<<2 | rd<<7 | (imm&0xFFFFF000))
618 #define OP_J(rd,imm)\
619 	(OPX | rd<<7 | (imm&0xff000) | (imm&0x800)<<9 | (imm&0x7FE)<<20 | (imm&0x100000)<<11)
620 
621 /*
622  * aflag: 0 - assemble to object file
623  *        1 - return assembled instruction
624  *        2 - first pass, return length of assembled instruction
625  *        3 - later pass, return length of assembled instruction
626  */
627 int
asmout(Prog * p,Optab * o,int aflag)628 asmout(Prog *p, Optab *o, int aflag)
629 {
630 	vlong vv;
631 	long o1, o2, o3, v;
632 	int r;
633 
634 	o1 = 0;
635 	o2 = 0;
636 	o3 = 0;
637 	r = p->reg;
638 	if(r == NREG) switch(p->as){
639 		case AMOVF:
640 		case AMOVD:
641 			if(p->from.type == D_FREG && p->to.type == D_FREG)
642 				r = p->from.reg;
643 			break;
644 		case AMOV:
645 		case AJMP:
646 			r = REGZERO;
647 			break;
648 		case AJAL:
649 			r = REGLINK;
650 			break;
651 		default:
652 			r = p->to.reg;
653 			break;
654 	}
655 	if(!debug['c'] && o->ctype){
656 		o1 = asmcompressed(p, o, r, aflag == 2);
657 		if(o1 != 0){
658 			switch(aflag){
659 			case 1:
660 				return o1;
661 			case 2:
662 			case 3:
663 				return 2;
664 			}
665 			if(debug['a']){
666 				v = p->pc + INITTEXT;
667 				Bprint(&bso, " %.8lux: %.4lux    \t%P\n", v, o1, p);
668 			}
669 			wputl(o1);
670 			return 2;
671 		}
672 	}
673 	if(aflag >= 2)
674 		return o->size;
675 	switch(o->type) {
676 	default:
677 		diag("unknown type %d", o->type);
678 		if(!debug['a'])
679 			prasm(p);
680 		break;
681 
682 	case 0:		/* add S,[R,]D */
683 		o1 = OP_R(r, p->from.reg, p->to.reg);
684 		break;
685 
686 	case 1:		/* slli $I,[R,]D */
687 		v = p->from.offset & 0x3F;
688 		v |= (o->param<<5);
689 		o1 = OP_I(r, p->to.reg, v);
690 		break;
691 
692 	case 2:		/* addi $I,[R,]D */
693 		v = p->from.offset;
694 		if(v < -BIG || v >= BIG)
695 			diag("imm out of range\n%P", p);
696 		o1 = OP_I(r, p->to.reg, v);
697 		break;
698 
699 	case 3:		/* beq S,[R,]L */
700 		if(r == NREG)
701 			r = REGZERO;
702 		if(p->cond == P)
703 			v = 0;
704 		else
705 			v = (p->cond->pc - pc);
706 		if(v < -0x1000 || v >= 0x1000)
707 			diag("branch out of range\n%P", p);
708 		o1 = OP_B(r, p->from.reg, v);
709 		break;
710 
711 	case 4:		/* jal	[D,]L */
712 		if(p->cond == P)
713 			v = 0;
714 		else
715 			v = (p->cond->pc - pc);
716 		if(v < -0x100000 || v >= 0x100000)
717 			diag("jump out of range\n%P", p);
718 		o1 = OP_J(r, v);
719 		break;
720 
721 	case 5:		/* jalr [D,]I(S) */
722 		v = regoff(&p->to);
723 		if(v < -BIG || v >= BIG)
724 			diag("imm out of range\n%P", p);
725 		o1 = OP_I(classreg(&p->to), r, v);
726 		break;
727 
728 	case 6:		/* sb	R,I(S) */
729 		v = regoff(&p->to);
730 		r = classreg(&p->to);
731 		if(v < -BIG || v >= BIG)
732 			diag("imm out of range\n%P", p);
733 		o1 = OP_S(r, p->from.reg, v);
734 		break;
735 
736 	case 7:		/* lb	I(S),D */
737 		v = regoff(&p->from);
738 		r = classreg(&p->from);
739 		if(v < -BIG || v >= BIG)
740 			diag("imm out of range\n%P", p);
741 		o1 = OP_I(r, p->to.reg, v);
742 		break;
743 
744 	case 8:		/* lui	I,D */
745 		v = p->from.offset;
746 		o1 = OP_U(p->to.reg, v);
747 		break;
748 
749 	case 9:		/* lui	I1,D; addi I0,D */
750 		v = regoff(&p->from);
751 		if(thechar == 'j' && v >= 0x7ffff800){
752 			/* awkward edge case */
753 			o1 = OP_U(p->to.reg, -v);
754 			v &= 0xFFF;
755 			o2 = OP_FI(4, p->to.reg, p->to.reg, v);	/* xori */
756 			break;
757 		}
758 		if(v & 0x800)
759 			v += 0x1000;
760 		o1 = OP_U(p->to.reg, v);
761 		v &= 0xFFF;
762 		o2 = OP_I(p->to.reg, p->to.reg, v);
763 		break;
764 
765 	case 10:	/* sign extend */
766 		if(p->as == AMOVBU) {
767 			o1 = OP_I(p->from.reg, p->to.reg, o->param);
768 			break;
769 		}
770 		v = o->param;
771 		if(thechar == 'j')
772 			v += 32;
773 		o1 = OP_FI(1, p->from.reg, p->to.reg, v & 0x3F);	/* slli */
774 		o2 = OP_I(p->to.reg, p->to.reg, v);	/* srli or srai */
775 		break;
776 
777 	case 11:		/* addi $I,R,D */
778 		v = regoff(&p->from);
779 		if(v < -BIG || v >= BIG)
780 			diag("imm out of range\n%P", p);
781 		o1 = OP_I(classreg(&p->from), p->to.reg, v);
782 		break;
783 
784 	case 12:		/* mov r,lext => lui/auipc I1,T; sb r,I0(T) */
785 		v = regoff(&p->to);
786 		if(thechar == 'j'){
787 			vv = v + INITDAT + BIG - INITTEXT - pc;
788 			v = (long)vv;
789 			if(v != vv || (v&~0x7FF) == 0x7FFFF800)
790 				diag("address out of range\n%P", p);
791 		}else
792 			v += INITDAT + BIG;
793 		if(v & 0x800)
794 			v += 0x1000;
795 		o1 = thechar == 'j' ? OP_UP(REGTMP, v) : OP_U(REGTMP, v);
796 		v &= 0xFFF;
797 		o2 = OP_S(REGTMP, p->from.reg, v);
798 		break;
799 
800 	case 13:		/* mov lext, r => lui/auipc I1,T; lb r,I0(T) */
801 		v = regoff(&p->from);
802 		if(thechar == 'j'){
803 			vv = v + INITDAT + BIG - INITTEXT - pc;
804 			v = (long)vv;
805 			if(v != vv || (v&~0x7FF) == 0x7FFFF800)
806 				diag("address out of range\n%P", p);
807 		}else
808 				v += INITDAT + BIG;
809 		if(v & 0x800)
810 			v += 0x1000;
811 		o1 = thechar == 'j' ? OP_UP(REGTMP, v) : OP_U(REGTMP, v);
812 		v &= 0xFFF;
813 		o2 = OP_I(REGTMP, p->to.reg, v);
814 		break;
815 
816 	case 14:		/* op $lcon,[r,]d => lui L1,T; addi $L0,T,T; op T,r,d */
817 		v = regoff(&p->from);
818 		if(p->as == AMOVW || p->as == AMOV)
819 			r = classreg(&p->from);
820 		if(thechar == 'j' && v >= 0x7ffff800){
821 			/* awkward edge case */
822 			o1 = OP_U(p->to.reg, -v);
823 			v &= 0xFFF;
824 			o2 = OP_FI(4, p->to.reg, p->to.reg, v);	/* xori */
825 		}else{
826 			if(v & 0x800)
827 				v += 0x1000;
828 			o1 = OP_U(REGTMP, v);
829 			v &= 0xFFF;
830 			o2 = OP_FI(0, REGTMP, REGTMP, v);	/* addi */
831 		}
832 		o3 = OP_RO(r, REGTMP, p->to.reg);
833 		break;
834 
835 	case 15:		/* mov r,L(s) => lui L1,T; add s,T,T; sb r,L0(T) */
836 		v = regoff(&p->to);
837 		r = classreg(&p->to);
838 		if(v & 0x800)
839 			v += 0x1000;
840 		o1 = OP_U(REGTMP, v);
841 		v &= 0xFFF;
842 		o2 = OP_ADD(r, REGTMP, REGTMP);
843 		o3 = OP_S(REGTMP, p->from.reg, v);
844 		break;
845 
846 	case 16:		/* mov L(s),r => lui L1,T; add s,T,T; lb r,L0(T) */
847 		v = regoff(&p->from);
848 		r = classreg(&p->from);
849 		if(v & 0x800)
850 			v += 0x1000;
851 		o1 = OP_U(REGTMP, v);
852 		v &= 0xFFF;
853 		o2 = OP_ADD(r, REGTMP, REGTMP);
854 		o3 = OP_I(REGTMP, p->to.reg, v);
855 		break;
856 
857 	case 17:	/* fcvt S,D */
858 		v = 7;	/* dynamic rounding mode */
859 		if(o->a3 == C_REG)	/* convert to int? */
860 			v = 1;	/* round towards zero */
861 		o1 = OP_RF(p->from.reg, o->func3, p->to.reg, v);
862 		break;
863 
864 	case 18:	/* lui L1, T; jal [r,]L0(T) */
865 		if(p->cond == P)
866 			v = 0;
867 		else
868 			v = p->cond->pc;
869 		if(thechar == 'j'){
870 			vv = v + INITTEXT;
871 			v = (long)vv;
872 			if(v != vv || (v&~0x7FF) == 0x7FFFF800)
873 				diag("branch out of range\n%P", p);
874 		}else
875 			v += INITTEXT;
876 		if(v & 0x800)
877 			v += 0x1000;
878 		o1 = thechar == 'j' ? OP_UP(REGTMP, v) : OP_U(REGTMP, v);
879 		v &= 0xFFF;
880 		o2 = OP_I(REGTMP, r, v);
881 		break;
882 
883 	case 19:	/* addiw $0, rs, rd */
884 		v = 0;
885 		o1 = OP_I(p->from.reg, p->to.reg, v);
886 		break;
887 
888 	case 20:	/* lui/auipc I1,D; addi I0; D */
889 		if(thechar == 'j'){
890 			vv = regoff(&p->from) + instoffx - (pc + INITTEXT);
891 			v = (long)vv;
892 			if(v != vv || (v&~0x7FF) == 0x7FFFF800)
893 				diag("address %llux out of range\n%P", regoff(&p->from) + instoffx, p);
894 		}else{
895 			v = regoff(&p->from) + instoffx;
896 		}
897 		if(v & 0x800)
898 			v += 0x1000;
899 		o1 = thechar == 'j' ? OP_UP(p->to.reg, v) : OP_U(p->to.reg, v);
900 		v &= 0xFFF;
901 		o2 = OP_I(p->to.reg, p->to.reg, v);
902 		break;
903 
904 	case 21:	/* lui I,D; s[lr]ai N,D */
905 		vv = *p->from.vval;
906 		v = vconshift(vv);
907 		if(v < 0)
908 			diag("64 bit constant error:\n%P", p);
909 		if(v < 12)
910 			vv <<= 12 - v;
911 		else
912 			vv >>= v - 12;
913 		o1 = OP_U(p->to.reg, (long)vv);
914 		if (v > 12)
915 			o2 = OP_FI(1, p->to.reg, p->to.reg, v - 12);	/* slli */
916 		else
917 			o2 = OP_I(p->to.reg, p->to.reg, 12 - v);	/* srai */
918 		break;
919 
920 	case 22:	/* CSRRx C, rs, rd */
921 		v = p->from.offset & 0xFFF;
922 		o1 = OP_I(p->reg, p->to.reg, v);
923 		break;
924 
925 	case 24:		/* SYS */
926 		v = p->to.offset & 0xFFF;
927 		o1 = OP_I(0, 0, v);
928 		break;
929 
930 	case 25:		/* word $x */
931 		o1 = regoff(&p->to);
932 		break;
933 
934 	case 26:		/* pseudo ops */
935 		break;
936 	}
937 	if(aflag)
938 		return o1;
939 	v = p->pc + INITTEXT;
940 	switch(o->size) {
941 	default:
942 		if(debug['a'])
943 			Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
944 		break;
945 	case 4:
946 		if(debug['a'])
947 			Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
948 		lputl(o1);
949 		break;
950 	case 8:
951 		if(debug['a'])
952 			Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
953 		lputl(o1);
954 		lputl(o2);
955 		break;
956 	case 12:
957 		if(debug['a'])
958 			Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
959 		lputl(o1);
960 		lputl(o2);
961 		lputl(o3);
962 		break;
963 	}
964 	return o->size;
965 }
966 
967