ref: a2ad59b340bf3339dbba105310002474b98d0184
dir: /sys/src/cmd/zl/asm.c/
#include "l.h" long OFFSET; #define PADDR(a) ((a) & ~0xfffffffff0000000ull) #define VPUT(v) VLEPUT(v) #define VLEPUT(c)\ {\ cbp[0] = (c);\ cbp[1] = (c)>>8;\ cbp[2] = (c)>>16;\ cbp[3] = (c)>>24;\ cbp[4] = (c)>>32;\ cbp[5] = (c)>>40;\ cbp[6] = (c)>>48;\ cbp[7] = (c)>>56;\ cbp += 8;\ cbc -= 8;\ if(cbc <= 0)\ cflush();\ } #define VBEPUT(c)\ {\ cbp[0] = (c)>>56;\ cbp[1] = (c)>>48;\ cbp[2] = (c)>>40;\ cbp[3] = (c)>>32;\ cbp[4] = (c)>>24;\ cbp[5] = (c)>>16;\ cbp[6] = (c)>>8;\ cbp[7] = (c);\ cbp += 8;\ cbc -= 8;\ if(cbc <= 0)\ cflush();\ } #define LPUT(l) LLEPUT(l) #define LLEPUT(c)\ {\ cbp[0] = (c);\ cbp[1] = (c)>>8;\ cbp[2] = (c)>>16;\ cbp[3] = (c)>>24;\ cbp += 4;\ cbc -= 4;\ if(cbc <= 0)\ cflush();\ } #define LBEPUT(c)\ {\ cbp[0] = (c)>>24;\ cbp[1] = (c)>>16;\ cbp[2] = (c)>>8;\ cbp[3] = (c);\ cbp += 4;\ cbc -= 4;\ if(cbc <= 0)\ cflush();\ } #define HPUT(h) HLEPUT(h) #define HLEPUT(c)\ {\ cbp[0] = (c);\ cbp[1] = (c)>>8;\ cbp += 2;\ cbc -= 2;\ if(cbc <= 0)\ cflush();\ } #define HBEPUT(c)\ {\ cbp[0] = (c)>>8;\ cbp[1] = (c);\ cbp += 2;\ cbc -= 2;\ if(cbc <= 0)\ cflush();\ } #define CPUT(c)\ {\ cbp[0] = (c);\ cbp++;\ cbc--;\ if(cbc <= 0)\ cflush();\ } void cput(long l) { CPUT(l); } void objput(long l) /* emit long in byte order appropriate to object machine */ { LPUT(l); } void objhput(short s) { HPUT(s); } void wput(long l) { cbp[0] = l>>8; cbp[1] = l; cbp += 2; cbc -= 2; if(cbc <= 0) cflush(); } void wputl(long l) { cbp[0] = l; cbp[1] = l>>8; cbp += 2; cbc -= 2; if(cbc <= 0) cflush(); } void lput(long l) /* emit long in big-endian byte order */ { LBEPUT(l); } void lputl(long l) /* emit long in big-endian byte order */ { LLEPUT(l); } void llput(vlong v) { lput(v>>32); lput(v); } void llputl(vlong v) { lputl(v); lputl(v>>32); } vlong entryvalue(void) { char *a; Sym *s; a = INITENTRY; if(*a >= '0' && *a <= '9') return atolwhex(a); s = lookup(a, 0); if(s->type == 0) return INITTEXT; if(s->type != STEXT && s->type != SLEAF) diag("entry not text: %s", s->name); return s->value; } void asmb(void) { Prog *p; long magic; vlong vl, t, etext; Optab *o; if(debug['v']) Bprint(&bso, "%5.2f asm\n", cputime()); Bflush(&bso); OFFSET = HEADR; seek(cout, OFFSET, 0); pc = INITTEXT; for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) { curtext = p; autosize = p->to.offset + 8; } if(p->pc != pc) { diag("phase error %llux sb %llux", p->pc, pc); if(!debug['a']) prasm(curp); pc = p->pc; } curp = p; o = oplook(p); /* could probably avoid this call */ if(asmout(p, o, 0)) { p = p->link; pc += 4; } pc += o->size; } if(debug['a']) Bprint(&bso, "\n"); Bflush(&bso); cflush(); etext = INITTEXT + textsize; for(t = pc; t < etext; t += sizeof(buf)-100) { if(etext-t > sizeof(buf)-100) datblk(t, sizeof(buf)-100, 1); else datblk(t, etext-t, 1); } Bflush(&bso); cflush(); curtext = P; switch(HEADTYPE) { case 0: case 2: OFFSET = HEADR+textsize; seek(cout, OFFSET, 0); break; case 6: /* no header, padded */ OFFSET = rnd(HEADR+textsize, INITRND); seek(cout, OFFSET, 0); break; } for(t = 0; t < datsize; t += sizeof(buf)-100) { if(datsize-t > sizeof(buf)-100) datblk(t, sizeof(buf)-100, 0); else datblk(t, datsize-t, 0); } symsize = 0; lcsize = 0; if(!debug['s']) { if(debug['v']) Bprint(&bso, "%5.2f sym\n", cputime()); Bflush(&bso); switch(HEADTYPE) { case 0: debug['s'] = 1; break; case 2: OFFSET = HEADR+textsize+datsize; seek(cout, OFFSET, 0); break; case 6: /* no header, padded */ OFFSET += rnd(datsize, INITRND); seek(cout, OFFSET, 0); break; } if(!debug['s']) asmsym(); if(debug['v']) Bprint(&bso, "%5.2f pc\n", cputime()); Bflush(&bso); if(!debug['s']) asmlc(); cflush(); } if(debug['v']) Bprint(&bso, "%5.2f header\n", cputime()); Bflush(&bso); OFFSET = 0; seek(cout, OFFSET, 0); switch(HEADTYPE) { case 0: /* no header */ case 6: /* no header, padded */ break; case 2: magic = 4*29*29+7; magic |= 0x00008000; lput(magic); /* magic */ lput(textsize); /* sizes */ lput(datsize); lput(bsssize); lput(symsize); /* nsyms */ vl = entryvalue(); lput(PADDR(vl)); /* va of entry */ lput(0L); lput(lcsize); llput(vl); /* va of entry */ break; } cflush(); } void strnput(char *s, int n) { for(; *s; s++){ CPUT(*s); n--; } for(; n > 0; n--) CPUT(0); } void cflush(void) { int n; n = sizeof(buf.cbuf) - cbc; if(n) write(cout, buf.cbuf, n); cbp = buf.cbuf; cbc = sizeof(buf.cbuf); } void nopstat(char *f, Count *c) { if(c->outof) Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f, c->outof - c->count, c->outof, (double)(c->outof - c->count)/c->outof); } void asmsym(void) { Prog *p; Auto *a; Sym *s; int h; s = lookup("etext", 0); if(s->type == STEXT) putsymb(s->name, 'T', s->value, s->version); for(h=0; h<NHASH; h++) for(s=hash[h]; s!=S; s=s->link) switch(s->type) { case SCONST: putsymb(s->name, 'D', s->value, s->version); continue; case SSTRING: putsymb(s->name, 'T', s->value, s->version); continue; case SDATA: putsymb(s->name, 'D', s->value+INITDAT, s->version); continue; case SBSS: putsymb(s->name, 'B', s->value+INITDAT, s->version); continue; case SFILE: putsymb(s->name, 'f', s->value, s->version); continue; } for(p=textp; p!=P; p=p->cond) { s = p->from.sym; if(s->type != STEXT && s->type != SLEAF) continue; /* filenames first */ for(a=p->to.autom; a; a=a->link) if(a->type == D_FILE) putsymb(a->asym->name, 'z', a->aoffset, 0); else if(a->type == D_FILE1) putsymb(a->asym->name, 'Z', a->aoffset, 0); if(s->type == STEXT) putsymb(s->name, 'T', s->value, s->version); else putsymb(s->name, 'L', s->value, s->version); /* frame, auto and param after */ putsymb(".frame", 'm', p->to.offset+8, 0); for(a=p->to.autom; a; a=a->link) if(a->type == D_AUTO) putsymb(a->asym->name, 'a', -a->aoffset, 0); else if(a->type == D_PARAM) putsymb(a->asym->name, 'p', a->aoffset, 0); } if(debug['v'] || debug['n']) Bprint(&bso, "symsize = %lud\n", symsize); Bflush(&bso); } void putsymb(char *s, int t, vlong v, int ver) { int i, f; long l; if(t == 'f') s++; if(HEADTYPE == 2) { l = v >> 32; LBEPUT(l); } l = v; LBEPUT(l); if(ver) t += 'a' - 'A'; CPUT(t+0x80); /* 0x80 is variable length */ if(t == 'Z' || t == 'z') { CPUT(s[0]); for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) { CPUT(s[i]); CPUT(s[i+1]); } CPUT(0); CPUT(0); i++; } else { for(i=0; s[i]; i++) CPUT(s[i]); CPUT(0); } symsize += 4 + 1 + i + 1; if(HEADTYPE == 2) symsize += 4; if(debug['n']) { if(t == 'z' || t == 'Z') { Bprint(&bso, "%c %.8llux ", t, v); for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) { f = ((s[i]&0xff) << 8) | (s[i+1]&0xff); Bprint(&bso, "/%x", f); } Bprint(&bso, "\n"); return; } if(ver) Bprint(&bso, "%c %.8llux %s<%d>\n", t, v, s, ver); else Bprint(&bso, "%c %.8llux %s\n", t, v, s); } } #define MINLC 4 void asmlc(void) { long oldlc, v, s; vlong oldpc; Prog *p; oldpc = INITTEXT; oldlc = 0; for(p = firstp; p != P; p = p->link) { if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) { if(p->as == ATEXT) curtext = p; if(debug['V']) Bprint(&bso, "%6llux %P\n", p->pc, p); continue; } if(debug['V']) Bprint(&bso, "\t\t%6ld", lcsize); v = (p->pc - oldpc) / MINLC; while(v) { s = 127; if(v < 127) s = v; CPUT(s+128); /* 129-255 +pc */ if(debug['V']) Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128); v -= s; lcsize++; } s = p->line - oldlc; oldlc = p->line; oldpc = p->pc + MINLC; if(s > 64 || s < -64) { CPUT(0); /* 0 vv +lc */ CPUT(s>>24); CPUT(s>>16); CPUT(s>>8); CPUT(s); if(debug['V']) { if(s > 0) Bprint(&bso, " lc+%ld(%d,%ld)\n", s, 0, s); else Bprint(&bso, " lc%ld(%d,%ld)\n", s, 0, s); Bprint(&bso, "%6llux %P\n", p->pc, p); } lcsize += 5; continue; } if(s > 0) { CPUT(0+s); /* 1-64 +lc */ if(debug['V']) { Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s); Bprint(&bso, "%6llux %P\n", p->pc, p); } } else { CPUT(64-s); /* 65-128 -lc */ if(debug['V']) { Bprint(&bso, " lc%ld(%ld)\n", s, 64-s); Bprint(&bso, "%6llux %P\n", p->pc, p); } } lcsize++; } while(lcsize & 1) { s = 129; CPUT(s); lcsize++; } if(debug['v'] || debug['V']) Bprint(&bso, "lcsize = %ld\n", lcsize); Bflush(&bso); } void datblk(long s, long n, int str) { Prog *p; char *cast; long l, fl, j; vlong d; int i, c; memset(buf.dbuf, 0, n+100); for(p = datap; p != P; p = p->link) { curp = p; if(str != (p->from.sym->type == SSTRING)) continue; l = p->from.sym->value + p->from.offset - s; c = p->reg; i = 0; if(l < 0) { if(l+c <= 0) continue; while(l < 0) { l++; i++; } } if(l >= n) continue; if(p->as != AINIT && p->as != ADYNT) { for(j=l+(c-i)-1; j>=l; j--) if(buf.dbuf[j]) { print("%P\n", p); diag("multiple initialization"); break; } } switch(p->to.type) { default: diag("unknown mode in initialization\n%P", p); break; case D_FCONST: switch(c) { default: case 4: fl = ieeedtof(p->to.ieee); cast = (char*)&fl; for(; i<c; i++) { buf.dbuf[l] = cast[fnuxi4[i]]; l++; } break; case 8: cast = (char*)p->to.ieee; for(; i<c; i++) { buf.dbuf[l] = cast[fnuxi8[i]]; l++; } break; } break; case D_SCONST: for(; i<c; i++) { buf.dbuf[l] = p->to.sval[i]; l++; } break; case D_CONST: d = p->to.offset; if(p->to.sym) { switch(p->to.sym->type) { case STEXT: case SLEAF: case SSTRING: d += p->to.sym->value; break; case SDATA: case SBSS: d += p->to.sym->value + INITDAT; break; } } cast = (char*)&d; switch(c) { default: diag("bad nuxi %d %d\n%P", c, i, curp); break; case 1: for(; i<c; i++) { buf.dbuf[l] = cast[inuxi1[i]]; l++; } break; case 2: for(; i<c; i++) { buf.dbuf[l] = cast[inuxi2[i]]; l++; } break; case 4: for(; i<c; i++) { buf.dbuf[l] = cast[inuxi4[i]]; l++; } break; case 8: for(; i<c; i++) { buf.dbuf[l] = cast[inuxi8[i]]; l++; } break; } break; } } write(cout, buf.dbuf, n); } #define OP_RRR(op,r1,r2,r3)\ (op|(((r1)&0x1FL)<<10)|(((r2)&0x1FL)<<5)|(((r3)&0x1FL)<<0)) #define OP_RR(op,r2,r3)\ (op|(((r2)&0x1FL)<<5)|(((r3)&0x1FL)<<0)) #define OP_16IR_5I(op,i,r2)\ (op|(((i)&0xFFFFL)<<10)|(((r2)&0x1FL)<<5)|(((i)>>16)&0x1FL)) #define OP_16IRR(op,i,r2,r3)\ (op|(((i)&0xFFFFL)<<10)|(((r2)&0x1FL)<<5)|(((r3)&0x1FL)<<0)) #define OP_12IRR(op,i,r2,r3)\ (op|(((i)&0xFFFL)<<10)|(((r2)&0x1FL)<<5)|(((r3)&0x1FL)<<0)) #define OP_IR(op,i,r2)\ (op|(((i)&0xFFFFFL)<<5)|(((r2)&0x1FL)<<0)) #define OP_B_BL(op,i)\ (op|(((i)&0xFFFFL)<<10)|(((i)>>16)&0x3FFL)) #define OP(x,y)\ (((x)<<3)|((y)<<0)) #define SP(x,y)\ (((x)<<29)|((y)<<26)) #define OP_TEN(x,y)\ (((x)<<21)|((y)<<10)) int vshift(int); int asmout(Prog *p, Optab *o, int aflag) { long o1, o2, o3, o4, o5; vlong v; Prog *ct; int r, a; o1 = 0; o2 = 0; o3 = 0; o4 = 0; o5 = 0; switch(o->type) { default: diag("unknown type %d", o->type); if(!debug['a']) prasm(p); break; case 0: /* pseudo ops */ if(aflag) { if(p->link) { if(p->as == ATEXT) { ct = curtext; o2 = autosize; curtext = p; autosize = p->to.offset + 8; o1 = asmout(p->link, oplook(p->link), aflag); curtext = ct; autosize = o2; } else o1 = asmout(p->link, oplook(p->link), aflag); } return o1; } break; case 1: /* mov[v] r1,r2 ==> OR r1,r0,r2 */ o1 = OP_RRR(oprrr(AOR), REGZERO, p->from.reg, p->to.reg); break; case 2: /* add/sub r1,[r2],r3 */ r = p->reg; if(r == NREG) r = p->to.reg; o1 = OP_RRR(oprrr(p->as), p->from.reg, r, p->to.reg); break; case 3: /* mov $soreg, r ==> or/add $i,o,r */ v = regoff(&p->from); r = p->from.reg; if(r == NREG) r = o->param; a = AADDVU; if(o->a1 == C_ANDCON) a = AOR; o1 = OP_12IRR(opirr(a), v, r, p->to.reg); break; case 4: /* add $scon,[r1],r2 */ v = regoff(&p->from); r = p->reg; if(r == NREG) r = p->to.reg; o1 = OP_12IRR(opirr(p->as), v, r, p->to.reg); break; case 5: /* syscall */ if(aflag) return 0; o1 = oprrr(p->as); break; case 6: /* beq r1,[r2],sbra */ if(aflag) return 0; v = 0; if(p->cond != P) v = (p->cond->pc - pc) >> 2; if(((v << 16) >> 16) != v) diag("short branch too far: %lld\n%P", v, p); o1 = OP_16IRR(opirr(p->as), v, p->from.reg, p->reg); break; case 7: /* mov r, soreg ==> sw o(r) */ r = p->to.reg; if(r == NREG) r = o->param; v = regoff(&p->to); o1 = OP_12IRR(opirr(p->as), v, r, p->from.reg); break; case 8: /* mov soreg, r ==> lw o(r) */ r = p->from.reg; if(r == NREG) r = o->param; v = regoff(&p->from); o1 = OP_12IRR(opirr(p->as+ALAST), v, r, p->to.reg); break; case 9: /* asl r1,[r2],r3 */ r = p->reg; if(r == NREG) r = p->to.reg; o1 = OP_RRR(oprrr(p->as), r, p->from.reg, p->to.reg); break; case 10: /* add $con,[r1],r2 ==> mov $con,t; add t,[r1],r2 */ v = regoff(&p->from); r = AOR; if(v < 0) r = AADDU; o1 = OP_12IRR(opirr(r), v, 0, REGTMP); r = p->reg; if(r == NREG) r = p->to.reg; o2 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg); break; case 11: /* jmp lbra */ if(aflag) return 0; v = 0; if(p->cond != P) v = (p->cond->pc - pc) >> 2; o1 = OP_B_BL(opirr(p->as), v); break; case 12: /* movbs r,r */ v = 16; if(p->as == AMOVB) v = 24; o1 = OP_16IRR(opirr(ASLL), v, p->from.reg, p->to.reg); o2 = OP_16IRR(opirr(ASRA), v, p->to.reg, p->to.reg); break; case 13: /* movbu r,r */ if(p->as == AMOVBU) o1 = OP_12IRR(opirr(AAND), 0xffL, p->from.reg, p->to.reg); else o1 = (0x33c0<<10) | ((p->from.reg&0x1FL)<<5) | (p->to.reg&0x1FL); break; case 14: /* movwu r,r */ o1 = OP_16IRR(opirr(ASLLV+ALAST), 32, p->from.reg, p->to.reg); o2 = OP_16IRR(opirr(ASRLV+ALAST), 32, p->to.reg, p->to.reg); break; case 16: /* sll $c,[r1],r2 */ v = regoff(&p->from); r = p->reg; if(r == NREG) r = p->to.reg; /* OP_SRR will use only the low 5 bits of the shift value */ if(v >= 32 && vshift(p->as)) o1 = OP_16IRR(opirr(p->as+ALAST), v&0x3FL, r, p->to.reg); else o1 = OP_16IRR(opirr(p->as), v&0x1FL, r, p->to.reg); break; case 18: /* jmp [r1],0(r2) */ if(aflag) return 0; r = p->reg; if(r == NREG) r = o->param; o1 = OP_RRR(oprrr(p->as), 0, p->to.reg, r); break; case 19: /* mov $lcon,r ==> lu+or */ v = regoff(&p->from); o1 = OP_IR(opir(ALU12IW), v>>12, p->to.reg); o2 = OP_12IRR(opirr(AOR), v, p->to.reg, p->to.reg); break; case 23: /* add $lcon,r1,r2 ==> lu+or+add */ v = regoff(&p->from); if(p->to.reg == REGTMP || p->reg == REGTMP) diag("cant synthesize large constant\n%P", p); o1 = OP_IR(opir(ALU12IW), v>>12, REGTMP); o2 = OP_12IRR(opirr(AOR), v, REGTMP, REGTMP); r = p->reg; if(r == NREG) r = p->to.reg; o3 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg); break; case 24: /* mov $ucon,,r ==> lu r */ v = regoff(&p->from); o1 = OP_IR(opir(ALU12IW), v>>12, p->to.reg); break; case 25: /* add/and $ucon,[r1],r2 ==> lu $con,t; add t,[r1],r2 */ v = regoff(&p->from); o1 = OP_IR(opir(ALU12IW), v>>12, REGTMP); r = p->reg; if(r == NREG) r = p->to.reg; o2 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg); break; case 26: /* mov $lsext/auto/oreg,,r2 ==> lu+or+add */ v = regoff(&p->from); if(p->to.reg == REGTMP) diag("cant synthesize large constant\n%P", p); o1 = OP_IR(opir(ALU12IW), v>>12, REGTMP); o2 = OP_12IRR(opirr(AOR), v, REGTMP, REGTMP); r = p->from.reg; if(r == NREG) r = o->param; o3 = OP_RRR(oprrr(AADDVU), REGTMP, r, p->to.reg); break; case 27: /* mov [sl]ext/auto/oreg,fr ==> lwc1 o(r) */ r = p->from.reg; if(r == NREG) r = o->param; v = regoff(&p->from); a = AMOVF+ALAST; if(p->as == AMOVD) a = AMOVD+ALAST; switch(o->size) { case 12: o1 = OP_IR(opir(ALU12IW), (v+1<<11)>>12, REGTMP); o2 = OP_RRR(oprrr(AADDVU), r, REGTMP, REGTMP); o3 = OP_12IRR(opirr(a), v, REGTMP, p->to.reg); break; case 4: o1 = OP_12IRR(opirr(a), v, r, p->to.reg); break; default: diag("bad 27 op size"); } break; case 28: /* mov fr,[sl]ext/auto/oreg ==> swc1 o(r) */ r = p->to.reg; if(r == NREG) r = o->param; v = regoff(&p->to); a = AMOVF; if(p->as == AMOVD) a = AMOVD; switch(o->size) { case 12: if(r == REGTMP) diag("cant synthesize large constant\n%P", p); o1 = OP_IR(opir(ALU12IW), (v+1<<11)>>12, REGTMP); o2 = OP_RRR(oprrr(AADDVU), r, REGTMP, REGTMP); o3 = OP_12IRR(opirr(a), v, REGTMP, p->from.reg); break; case 4: o1 = OP_12IRR(opirr(a), v, r, p->from.reg); break; default: diag("bad 28 op size"); } break; case 30: /* movw r,fr */ a = OP_TEN(8, 1321); /* movgr2fr.w */ o1 = OP_RR(a, p->from.reg, p->to.reg); break; case 31: /* movw fr,r */ a = OP_TEN(8, 1325); /* movfr2gr.s */ o1 = OP_RR(a, p->to.reg, p->from.reg); break; case 32: /* fadd fr1,[fr2],fr3 */ r = p->reg; if(r == NREG) r = p->to.reg; o1 = OP_RRR(oprrr(p->as), p->from.reg, r, p->to.reg); break; case 33: /* fabs fr1,fr3 */ o1 = OP_RRR(oprrr(p->as), 0, p->from.reg, p->to.reg); break; case 34: /* mov $con,fr ==> or/add $i,r,r2 */ v = regoff(&p->from); r = AADDU; if(o->a1 == C_ANDCON) r = AOR; o1 = OP_12IRR(opirr(r), v, 0, REGTMP); o2 = OP_RRR(OP_TEN(8, 1321), REGTMP, 0, p->to.reg); /* movgr2fr.w */ break; case 35: /* mov r,lext/luto/oreg ==> sw o(r) */ v = regoff(&p->to); r = p->to.reg; if(r == NREG) r = o->param; if(r == REGTMP) diag("cant synthesize large constant\n%P", p); o1 = OP_IR(opir(ALU12IW), (v+1<<11)>>12, REGTMP); o2 = OP_RRR(oprrr(AADDVU), r, REGTMP, REGTMP); o3 = OP_12IRR(opirr(p->as), r, REGTMP, p->from.reg); break; case 36: /* mov lext/lauto/lreg,r ==> lw o(r30) */ v = regoff(&p->from); r = p->from.reg; if(r == NREG) r = o->param; if(r == REGTMP) diag("cant synthesize large constant\n%P", p); o1 = OP_IR(opir(ALU12IW), (v+1<<11)>>12, REGTMP); o2 = OP_RRR(oprrr(AADDVU), r, REGTMP, REGTMP); o3 = OP_12IRR(opirr(p->as+ALAST), v, REGTMP, p->to.reg); break; case 40: /* word */ if(aflag) return 0; o1 = regoff(&p->to); break; case 47: /* movv r,fr */ r = OP_TEN(8, 1322); /* movgr2fr.d */ o1 = OP_RR(r, p->from.reg, p->to.reg); break; case 48: /* movv fr,r */ r = OP_TEN(8, 1326); /* movfr2gr.d */ o1 = OP_RR(r, p->from.reg, p->to.reg); break; } if(aflag) return o1; v = p->pc; switch(o->size) { default: if(debug['a']) Bprint(&bso, " %.16llux:\t\t%P\n", v, p); break; case 4: if(debug['a']) Bprint(&bso, " %.16llux: %.8lux\t%P\n", v, o1, p); LPUT(o1); break; case 8: if(debug['a']) Bprint(&bso, " %.16llux: %.8lux %.8lux\t%P\n", v, o1, o2, p); LPUT(o1); LPUT(o2); break; case 12: if(debug['a']) Bprint(&bso, " %.16llux: %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, p); LPUT(o1); LPUT(o2); LPUT(o3); break; case 16: if(debug['a']) Bprint(&bso, " %.16llux: %.8lux %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, o4, p); LPUT(o1); LPUT(o2); LPUT(o3); LPUT(o4); break; case 20: if(debug['a']) Bprint(&bso, " %.16llux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, o4, o5, p); LPUT(o1); LPUT(o2); LPUT(o3); LPUT(o4); LPUT(o5); break; } return 0; } int isnop(Prog *p) { if(p->as != ANOR) return 0; if(p->reg != REGZERO && p->reg != NREG) return 0; if(p->from.type != D_REG || p->from.reg != REGZERO) return 0; if(p->to.type != D_REG || p->to.reg != REGZERO) return 0; return 1; } long oprrr(int a) { switch(a) { case AADD: case AADDU: return 0x20<<15; case ASGT: return 0x24<<15; case ASGTU: return 0x25<<15; case AAND: return 0x29<<15; case AOR: return 0x2a<<15; case AXOR: return 0x2b<<15; case ASUB: case ASUBU: return 0x22<<15; case ANOR: return 0x28<<15; case ASLL: return 0x2e<<15; case ASRL: return 0x2f<<15; case ASRA: return 0x30<<15; case ASLLV: return 0x31<<15; case ASRLV: return 0x32<<15; case ASRAV: return 0x33<<15; case AADDV: case AADDVU: return 0x21<<15; case ASUBV: case ASUBVU: return 0x23<<15; case AREM: return 0x41<<15; case ADIV: return 0x40<<15; case AREMU: return 0x43<<15; case ADIVU: return 0x42<<15; case AMUL: case AMULU: return 0x38<<15; case AREMV: return 0x45<<15; case ADIVV: return 0x44<<15; case AREMVU: return 0x47<<15; case ADIVVU: return 0x46<<15; case AMULV: case AMULVU: return 0x3b<<15; case AJMP: return 0x13<<26; case AJAL: return (0x13<<26)|1; case ABREAK: return 0x54<<15; case ASYSCALL: return 0x56<<15; case ADIVF: return 0x20d<<15; case ADIVD: return 0x20e<<15; case AMULF: return 0x209<<15; case AMULD: return 0x20a<<15; case ASUBF: return 0x205<<15; case ASUBD: return 0x206<<15; case AADDF: return 0x201<<15; case AADDD: return 0x202<<15; case ATRUNCFV: return 0x46a9<<10; case ATRUNCDV: return 0x46aa<<10; case ATRUNCFW: return 0x46a1<<10; case ATRUNCDW: return 0x46a2<<10; case AMOVFV: return 0x46c9<<10; case AMOVDV: return 0x46ca<<10; case AMOVVF: return 0x4746<<10; case AMOVVD: return 0x474a<<10; case AMOVFW: return 0x46c1<<10; case AMOVDW: return 0x46c2<<10; case AMOVWF: return 0x4744<<10; case AMOVDF: return 0x4646<<10; case AMOVWD: return 0x4748<<10; case AMOVFD: return 0x4649<<10; case AABSF: return 0x4501<<10; case AABSD: return 0x4502<<10; case AMOVF: return 0x4525<<10; case AMOVD: return 0x4526<<10; case ANEGF: return 0x4505<<10; case ANEGD: return 0x4506<<10; case ACMPEQF: return (0xc1<<20) | (0x4<<15); case ACMPEQD: return (0xc2<<20) | (0x4<<15); case ACMPGTF: return (0xc1<<20) | (0x3<<15); case ACMPGTD: return (0xc2<<20) | (0x3<<15); case ACMPGEF: return (0xc1<<20) | (0x7<<15); case ACMPGED: return (0xc2<<20) | (0x7<<15); } if(a >= ALAST) diag("bad rrr %A+ALAST", a-ALAST); else diag("bad rrr %A", a); return 0; } long opir(int a) { switch(a){ case ALU12IW: return 0xa<<25; case ALU32ID: return 0xb<<25; } diag("bad ir %d", a); return 0; } long opirr(int a) { switch(a) { case AADD: case AADDU: return 0xa<<22; case ASGT: return 0x8<<22; case ASGTU: return 0x9<<22; case AAND: return 0xd<<22; case AOR: return 0xe<<22; case AXOR: return 0xf<<22; case ASLL: return 0x81<<15; case ASRL: return 0x89<<15; case ASRA: return 0x91<<15; case AADDV: case AADDVU: return 0xb<<22; case AJMP: return 0x14<<26; case AJAL: return 0x15<<26; case ABEQ: return 0x16<<26; case ABEQ+ALAST: return 0x10<<26; /* likely */ case ABNE: return 0x17<<26; case ABNE+ALAST: return 0x11<<26; /* likely */ case ABLEZ: case ABGEZ: return 0x19<<26; case ABLTZ: case ABGTZ: return 0x18<<26; case ABFPT: return (0x12<<26) | (0x1<<8); case ABFPF: return 0x12<<26; case AMOVB: case AMOVBU: return 0xa4<<22; case AMOVH: case AMOVHU: return 0xa5<<22; case AMOVW: return 0xa6<<22; case AMOVV: return 0xa7<<22; case AMOVF: return 0xad<<22; case AMOVD: return 0xaf<<22; case AMOVWL: return 0xbc<<22; case AMOVWR: return 0xbd<<22; case AMOVVL: return 0xbe<<22; case AMOVVR: return 0xbf<<22; case ABREAK: return 0x18<<22; case AMOVWL+ALAST: return 0xb8<<22; case AMOVWR+ALAST: return 0xb9<<22; case AMOVVL+ALAST: return 0xba<<22; case AMOVVR+ALAST: return 0xbb<<22; case AMOVB+ALAST: return 0xa0<<22; case AMOVBU+ALAST: return 0xa8<<22; case AMOVH+ALAST: return 0xa1<<22; case AMOVHU+ALAST: return 0xa9<<22; case AMOVW+ALAST: return 0xa2<<22; case AMOVV+ALAST: return 0xa3<<22; case AMOVF+ALAST: return 0xac<<22; case AMOVD+ALAST: return 0xae<<22; case ASLLV: case ASLLV+ALAST: return 0x41<<16; case ASRLV: case ASRLV+ALAST: return 0x45<<16; case ASRAV: case ASRAV+ALAST: return 0x49<<16; case ALU52ID: return 0xc<<22; } if(a >= ALAST) diag("bad irr %A+ALAST", a-ALAST); else diag("bad irr %A", a); return 0; } int vshift(int a) { switch(a){ case ASLLV: return 1; case ASRLV: return 1; case ASRAV: return 1; } return 0; }