diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /libinterp/comp-68020.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'libinterp/comp-68020.c')
| -rw-r--r-- | libinterp/comp-68020.c | 2074 |
1 files changed, 2074 insertions, 0 deletions
diff --git a/libinterp/comp-68020.c b/libinterp/comp-68020.c new file mode 100644 index 00000000..0c5e9b7c --- /dev/null +++ b/libinterp/comp-68020.c @@ -0,0 +1,2074 @@ +#include "lib9.h" +#include "isa.h" +#include "interp.h" +#include "raise.h" + +enum +{ + RAX = 0, + RCX = 1, /* Be careful with RCX, smashed in bra() */ + RTA = 2, + RTMP = 3, + RFP = 4, + RMP = 5, + R7 = 7, + + DTMP = 0, + DTMP1 = 1, + DTMP2 = 2, + DTMP3 = 3, + + Oadd = 0xD000, + OaddaR = 0xD1E8, /* ADDA (d16,Rr), Rr */ + Oaddi = 0x0600, + OaddRD = 0xD0A8, + OaslbD = 0xE120, + OaslwD = 0xE1A0, + OasrbD = 0xE020, + OasrwD = 0xE0A0, + Oand = 0xC000, + Oandi = 0x0200, + Obra = 0x6000, + Obsr = 0x6100, + OclrwD = 0x4280, + OcmpiwR = 0x0CA8, /* cmpi.l offset(Rrm), imm.long */ + OcmpwR = 0xB1E8, /* cmpa $offset(Rrm), Rr */ + OcmpbD = 0xB028, /* cmp.b $offset(Rrm), Dr */ + OcmpwD = 0xB0A8, /* cmp.l $offset(Rx), Dr */ + OcmpwDD = 0xB080, /* cmp.l Dr, Dx */ + Odbeq = 0x57C8, + OdecrwRind = 0x53A8, /* SUBQ.L $0x1, offset(Rr) */ + Odivs = 0x81C0, + Oeor = 0xB000, + Oeori = 0x0A00, + OexgRR = 0xC148, /* exg Rx, Ry */ + Oextw = 0x4880, /* EXT.W Dx extend byte to 16-bit */ + Oextbw = 0x49C0, /* EXTB.L Dx extend byte to 32-bit */ + OincrwR = 0x5288, /* ADDQ.L $0x1, Rr */ + OincrwRind = 0x52A8, /* ADDQ.L $0x1, offset(Rr) */ + Ojhi = 0x6200, /* BHI */ + Ojhs = 0x6400, /* BCC(HS) */ + Ojlo = 0x6500, /* BCS(LO) */ + Ojls = 0x6300, /* BLS */ + Ojeq = 0x6700, /* BEQ */ + Ojge = 0x6C00, /* BGE */ + Ojgt = 0x6E00, /* BGT */ + Ojle = 0x6F00, /* BLE */ + Ojlt = 0x6D00, /* BLT */ + Ojne = 0x6600, /* BNE */ + OjmpRind= 0x4ED0, /* jmp (Rn) */ + OjmpRindoffs= 0x4EE8, /* jmp $offs(Rn) */ + OjsrRind= 0x4E90, + OldbD = 0x1028, /* $offset(Rrm).b -> Dr */ + OldbR = 0x1058, /* $offset(Rrm).b -> Rr */ + OldwD = 0x2028, /* $offset(Rrm) -> Dr */ + OldwR = 0x2068, /* $offset(Rrm) -> Rr */ + OleaR = 0x41E8, /* addr($offset(Rrm) -> Rr */ + OlslD = 0xE388, + Olsl2D = 0xE588, + OlsrD = 0xE288, + OlslbD = 0xE128, + OlslwD = 0xE1A8, + OlsrbD = 0xE028, + OlsrwD = 0xE0A8, + OmovelitwR= 0x207C, /* move $xx, Rr */ + OmovelitwD= 0x203C, /* move $xx, Dr */ + Omoveal = 0x2040, + OmovwR = 0x217C, /* imm.long -> $offset(Rrm) */ + OmovwRR = 0x2048, /* movea.l Rr, Rx */ + OmovwRD = 0x2008, /* move.l Rr, Dx */ + Omuls = 0xC1C0, + OnegwD = 0x4480, + Oor = 0x8000, + Oori = 0x0000, + OpopwR = 0x205F, /* MOVEA.L (A7)+, Rr */ + OpushwR = 0x2F08, /* MOVE.L Rr, -(A7) */ + Opushil = 0x2F3C, /* MOVE.L imm., -(A7) */ + OroxlD = 0xE390, + OroxrD = 0xE290, + Orts = 0x4E75, + OstbD = 0x1140, /* Dr.b -> $offset(Rrm) !!!!! ostbR does NOT exist */ + OstwD = 0x2140, /* Dr -> $offset(Rrm) */ + OstwR = 0x2148, /* Rr -> $offset(Rrm) */ + Osub = 0x9000, + Osubi = 0x0400, + OaddqwR = 0x5088, + Oswap = 0x4840, + OtstbD = 0x4A00, /* tst.b Dr */ + OtstwR = 0x4AA8, /* tst.l $offset(Rx) */ + Oill = 0x4afc, /* illegal instruction trap */ + Onop = 0x4E71, + SRCOP = (1<<0), + DSTOP = (1<<1), + WRTPC = (1<<2), + TCHECK = (1<<3), + NEWPC = (1<<4), + DBRAN = (1<<5), + THREOP = (1<<6), + + ANDAND = 1, + OROR = 2, + EQAND = 3, + + MacFRP = 0, + MacRET = 1, + MacCASE = 2, + MacCOLR = 3, + MacMCAL = 4, + MacFRAM = 5, + MacMFRA = 6, + NMACRO +}; + +static uchar* code; +static uchar* base; +static ulong* patch; +static int pass; +static Module* mod; +static uchar* tinit; +static ulong* litpool; +static int nlit; +static void macfrp(void); +static void macret(void); +static void maccase(void); +static void maccolr(void); +static void macmcal(void); +static void macfram(void); +static void macmfra(void); +static ulong macro[NMACRO]; + void (*comvec)(void); +extern void das(uchar*, int); + +extern void _mull(void); +extern void _divsl(void); + +#define T(r) *((void**)(R.r)) + +struct +{ + int idx; + void (*gen)(void); +} mactab[] = +{ + MacFRP, macfrp, /* decrement and free pointer */ + MacRET, macret, /* return instruction */ + MacCASE, maccase, /* case instruction */ + MacCOLR, maccolr, /* increment and color pointer */ + MacMCAL, macmcal, /* mcall bottom half */ + MacFRAM, macfram, /* frame instruction */ + MacMFRA, macmfra, /* punt mframe because t->initialize==0 */ +}; + +static void +rdestroy(void) +{ + destroy(R.s); +} + +static void +rmcall(void) +{ + Prog *p; + Frame *f; + + f = (Frame*)R.FP; + if(f == H) + error(exModule); + + f->mr = nil; + ((void(*)(Frame*))R.dt)(f); + R.SP = (uchar*)f; + R.FP = f->fp; + if(f->t == nil) + unextend(f); + else + freeptrs(f, f->t); + p = currun(); + if(p->kill != nil) + error(p->kill); +} + +static void +rmfram(void) +{ + Type *t; + Frame *f; + uchar *nsp; + + t = (Type*)R.s; + nsp = R.SP + t->size; + if(nsp >= R.TS) { + R.s = t; + extend(); + T(d) = R.s; + return; + } + f = (Frame*)R.SP; + R.SP = nsp; + f->t = t; + f->mr = nil; + initmem(t, f); + T(d) = f; +} + +static int +bc(int o) +{ + if(o < 127 && o > -128) + return 1; + return 0; +} + +static int +wc(int o) +{ + if(o < 65535 && o > -65536) + return 1; + return 0; +} + +static void +urk(void) +{ + error(exCompile); +} + +static void +gen2(uchar o1, uchar o2) +{ + code[0] = o1; + code[1] = o2; + code += 2; +} + +static void +genw(ulong o) +{ + code[0] = (o>>8)&0xFF; + code[1] = o&0xFF; + code += 2; +} + +static void +genl(ulong o) +{ + *(ulong*)code = o; + code += 4; +} + +static void +modrm(int inst, ulong disp, int rm, int r) +{ + switch (inst) { + case OstwD: + case OstwR: + case OstbD: + if (!disp) { + inst&=0xfe3f; + inst|=0x0080; + } + genw(inst | (rm<<9) | r); + if (disp) + genw(disp); + break; + case Oadd|0x28|(0x6<<6): + case Oadd|0x28|(0x4<<6): + case Osub|0x28|(0x6<<6): + case Osub|0x28|(0x4<<6): + case Oor|0x28|(0x6<<6): + case Oor|0x28|(0x4<<6): + case Oand|0x28|(0x6<<6): + case Oand|0x28|(0x4<<6): + case Oeor|0x28|(0x6<<6): + case Oeor|0x28|(0x4<<6): + case Oaddi|0x28|(0x2<<6): + case Oori|0x28|(0x2<<6): + case Oandi|0x28|(0x2<<6): + case Oeori|0x28|(0x2<<6): + case Osubi|0x28|(0x2<<6): + case Oaddi|0x28: + case Oori|0x28: + case Oandi|0x28: + case Oeori|0x28: + case Osubi|0x28: + case OldbD: + case OldwD: + case OldwR: + case OldbR: + case OleaR: + case OaddRD: + case OcmpwR: + case OcmpwD: + case OcmpbD: + case OdecrwRind: + case OincrwRind: + case OtstwR: + if (!disp) { + inst&=0xffc7; + inst|=0x0010; + } + genw(inst | (r<<9) | rm); + if (disp) + genw(disp); + break; + default: + print("modrm: urk on opcode 0x%ux\n",inst); + urk(); + } +} + +static void +conR(ulong o, int r) +{ + if(o == 0) { + genw(0x91C8|(r<<9)|r); /* SUBA Rr, Rr */ + return; + } + genw(Omoveal|(r<<9)|0x7C); /* MOVEA.L $o,Rr */ + genl(o); +} + +static void +conD(ulong o, int r) +{ + if(o == 0) { + genw(OclrwD|r); /* CLR.L Dr */ + return; + } + genw(OmovelitwD|(r<<9)); /* MOVEA.L $o,Dr */ + genl(o); +} + +static void +opwld(Inst *i, int mi, int r) +{ + int ir, rta; + switch(UXSRC(i->add)) { + default: + print("%D\n", i); + urk(); + case SRC(AFP): + modrm(mi, i->s.ind, RFP, r); + return; + case SRC(AMP): + modrm(mi, i->s.ind, RMP, r); + return; + case SRC(AIMM): + conR(i->s.imm, r); + return; + case SRC(AIND|AFP): + ir = RFP; + break; + case SRC(AIND|AMP): + ir = RMP; + break; + } + rta = RTA; + if(mi == OleaR) + rta = r; + modrm(OldwR, i->s.i.f, ir, rta); + modrm(mi, i->s.i.s, rta, r); +} + +static void +opwldD(Inst *i, int mi, int r) +{ + int ir, rta; + switch(UXSRC(i->add)) { + default: + print("%D\n", i); + urk(); + case SRC(AFP): + modrm(mi, i->s.ind, RFP, r); + return; + case SRC(AMP): + modrm(mi, i->s.ind, RMP, r); + return; + case SRC(AIMM): + conD(i->s.imm, r); + return; + case SRC(AIND|AFP): + ir = RFP; + break; + case SRC(AIND|AMP): + ir = RMP; + break; + } + rta = RTA; + modrm(OldwR, i->s.i.f, ir, rta); + modrm(mi, i->s.i.s, rta, r); +} + +static int +opwst(Inst *i, int mi, int r) +{ + int ir, rta; + + switch(UXDST(i->add)) { + default: + print("%D\n", i); + urk(); + case DST(AIMM): + conR(i->d.imm, r); + return 0; + case DST(AFP): + modrm(mi, i->d.ind, RFP, r); + return i->d.ind; + case DST(AMP): + modrm(mi, i->d.ind, RMP, r); + return i->d.ind; + case DST(AIND|AFP): + ir = RFP; + break; + case DST(AIND|AMP): + ir = RMP; + break; + } + rta = RTA; + if(mi == OleaR) + rta = r; + modrm(OldwR, i->d.i.f, ir, rta); + modrm(mi, i->d.i.s, rta, r); + return i->d.i.s; +} + +static void +opwstD(Inst *i, int mi, int r) +{ + int ir, rta; + + switch(UXDST(i->add)) { + default: + print("%D\n", i); + urk(); + case DST(AIMM): + conD(i->d.imm, r); + return; + case DST(AFP): + modrm(mi, i->d.ind, RFP, r); + return; + case DST(AMP): + modrm(mi, i->d.ind, RMP, r); + return; + case DST(AIND|AFP): + ir = RFP; + break; + case DST(AIND|AMP): + ir = RMP; + break; + } + rta = RTA; + if(mi == OleaR) + rta = r; + modrm(OldwR, i->d.i.f, ir, rta); + modrm(mi, i->d.i.s, rta, r); +} + +static int +swapbraop(int b) +{ + switch(b) { + case Ojge: + return Ojlt; + case Ojle: + return Ojgt; + case Ojgt: + return Ojle; + case Ojlt: + return Ojge; + case Ojhi: + return Ojls; + case Ojlo: + return Ojhs; + case Ojhs: + return Ojlo; + case Ojls: + return Ojhi; + case Ojeq: + return Ojne; + case Ojne: + return Ojeq; + } + return b; +} + +static void +bra(ulong dst, int op) +{ + ulong ddst; + switch (op) { + case Obsr: + genw(OmovelitwR|(RCX<<9)); + genl(dst); + genw(OjsrRind|RCX); + break; + case Obra: +dojmp: + ddst=dst-((ulong)code+2); + if (bc(ddst)) { + genw(Obra|(uchar)ddst); + genw(Onop); + genw(Onop); + genw(Onop); + } else if (wc(ddst)) { + genw(Obra); + genw(ddst); + genw(Onop); + genw(Onop); + } else { + genw(OmovelitwR|(RCX<<9)); + genl(dst); + genw(OjmpRind|RCX); + } + break; + case Ojhi: + case Ojhs: + case Ojlo: + case Ojls: + case Ojeq: + case Ojge: + case Ojgt: + case Ojle: + case Ojlt: + case Ojne: + genw(swapbraop(op)|0x8); + goto dojmp; + default: + print("bra: urk op opcode 0x%ux\n",op); + urk(); + break; + } +} + +static void +rbra(ulong dst, int op) +{ + dst += (ulong)base; + bra(dst,op); +} + +static void +literal(ulong imm, int roff) +{ + nlit++; + genw(OmovelitwR|(RAX<<9)); + genl((ulong)litpool); + modrm(OstwR, roff, RTMP, RAX); + + if(pass == 0) + return; + + *litpool = imm; + litpool++; +} + + +static void +punt(Inst *i, int m, void (*fn)(void)) +{ + ulong pc; + conR((ulong)&R, RTMP); + + if(m & SRCOP) { + if(UXSRC(i->add) == SRC(AIMM)) { + literal(i->s.imm, O(REG, s)); + } + else { + opwld(i, OleaR, RAX); + modrm(OstwR, O(REG, s), RTMP, RAX); + } + } + + if(m & DSTOP) { + if(UXDST(i->add) == DST(AIMM)) { + literal(i->d.imm, O(REG, d)); + } else { + opwst(i, OleaR, RAX); + modrm(OstwR, O(REG, d), RTMP, RAX); + } + } + if(m & WRTPC) { + genw(OmovwR|(RTMP<<9)); + pc = patch[i-mod->prog+1]; + genl((ulong)base + pc); + genw(O(REG, PC)); + } + if(m & DBRAN) { + pc = patch[(Inst*)i->d.imm-mod->prog]; + + literal((ulong)base+pc, O(REG, d)); + } + + switch(i->add&ARM) { + case AXNON: + if(m & THREOP) { + modrm(OldwR, O(REG, d), RTMP, RAX); + modrm(OstwR, O(REG, m), RTMP, RAX); + } + break; + case AXIMM: + literal((short)i->reg, O(REG, m)); + break; + case AXINF: + modrm(OleaR, i->reg, RFP, RAX); + modrm(OstwR, O(REG, m), RTMP, RAX); + break; + case AXINM: + modrm(OleaR, i->reg, RMP, RAX); + modrm(OstwR, O(REG, m), RTMP, RAX); + break; + } + modrm(OstwR, O(REG, FP), RTMP, RFP); + + bra((ulong)fn, Obsr); + + conR((ulong)&R, RTMP); + if(m & TCHECK) { + genw(Orts); + } + + modrm(OldwR, O(REG, FP), RTMP, RFP); + modrm(OldwR, O(REG, MP), RTMP, RMP); + + if(m & NEWPC) { + modrm(OldwR, O(REG, PC), RTMP, RAX); + genw(OjmpRind|RAX); + } +} + +static void +mid(Inst *i, int mi, int r) +{ + int ir; + switch(i->add&ARM) { + default: + opwst(i, mi, r); + return; + case AXIMM: + conR((short)i->reg, r); + return; + case AXINF: + ir = RFP; + break; + case AXINM: + ir = RMP; + break; + } + modrm(mi, i->reg, ir, r); +} + +static void +midD(Inst *i, int mi, int r) +{ + int ir; + switch(i->add&ARM) { + default: + opwstD(i, mi, r); + return; + case AXIMM: + conD((short)i->reg, r); + return; + case AXINF: + ir = RFP; + break; + case AXINM: + ir = RMP; + break; + } + modrm(mi, i->reg, ir, r); +} + +static void +arithimms(Inst *i, int opcode, int opmode) +{ + uchar off[3]; + int hasoff; + if(i->add&ARM) { + midD(i,(opmode)?OldwD:OldbD,DTMP); + if (((opcode==Oaddi)||(opcode==Osubi))&&(i->s.imm>0)&&(i->s.imm<=8)) + genw(0x5000|((opcode==Osubi)?0x100:0)|(((opmode)?0x2:0x0)<<6)|(((uchar)i->s.imm)<<9)|DTMP); + else { + genw(opcode|DTMP|(((opmode)?0x2:0)<<6)); + if (opmode) + genl(i->s.imm); + else + genw(i->s.imm); + } + opwstD(i, (opmode)?OstwD:OstbD, DTMP); + return; + } + if (hasoff=opwst(i, opcode|0x28|(((opmode)?0x2:0)<<6), 0)) { + code-=2; + off[0]=code[0]; off[1]=code[1]; + } + if (((opcode==Oaddi)||(opcode==Osubi))&&(i->s.imm>0)&&(i->s.imm<=8)) { + code-=2; + off[2]=code[1]; + genw(0x5000|((opcode==Osubi)?0x100:0)|(((opmode)?0x2:0x0)<<6)|(((uchar)i->s.imm)<<9)|((hasoff)?0x28:0x10)|(off[2]&0x7)); + } + else { + if (opmode) + genl(i->s.imm); + else + genw(i->s.imm); + } + if (hasoff) + gen2(off[0],off[1]); +} + +static void +arith(Inst *i, int opcode, int opmode) +{ + opwldD(i, (opmode)?OldwD:OldbD, DTMP1); + if(i->add&ARM) { + midD(i,(opmode)?OldwD:OldbD,DTMP); + genw(opcode|(DTMP<<9)|DTMP1|(((opmode)?0x2:0)<<6)); + opwstD(i, (opmode)?OstwD:OstbD, DTMP); + return; + } + opwst(i, opcode|0x28|(((opmode)?0x6:0x4)<<6), DTMP1); +} + +static void +oldarithsub(Inst *i, int opmode) +{ + opwldD(i, (opmode)?OldwD:OldbD, DTMP1); + if(i->add&ARM) + midD(i,(opmode)?OldwD:OldbD,DTMP); + else + opwstD(i, (opmode)?OldwD:OldbD, DTMP); + genw(Osub|(DTMP<<9)|DTMP1|(((opmode)?0x2:0)<<6)); + opwstD(i, (opmode)?OstwD:OstbD, DTMP); +} + +static void +shift(Inst *i, int ld, int st, int op) +{ + midD(i, ld, DTMP); + opwldD(i, OldwD, DTMP1); + genw(op|(DTMP1<<9)|DTMP); + opwstD(i, st, DTMP); +} + +static void +cmpl(int r, ulong v) +{ + genw(0xB1FC|(r<<9)); + genl(v); +} + +static int +swapforcbra(int jmp) { + switch(jmp) { + case Ojge: + return Ojle; + case Ojle: + return Ojge; + case Ojgt: + return Ojlt; + case Ojlt: + return Ojgt; + case Ojhi: + return Ojlo; + case Ojlo: + return Ojhi; + case Ojhs: + return Ojls; + case Ojls: + return Ojhs; + default: + return jmp; + } + +} +static void +cbra(Inst *i, int jmp) +{ + midD(i, OldwD, DTMP); + if (UXSRC(i->add)==SRC(AIMM)) { + genw(0xB0BC|DTMP); + genl(i->s.imm); + } + else + opwldD(i,OcmpwD,DTMP); + rbra(patch[i->d.ins-mod->prog], swapforcbra(jmp)); +} + +static void +cbral(Inst *i, int jmsw, int jlsw, int mode) +{ + ulong dst; + uchar *label; + opwld(i, OleaR, RTMP); + mid(i, OleaR, RTA); + modrm(OldwR, 4, RTMP, RAX); + modrm(OcmpwR, 4, RTA, RAX); + label = 0; + dst = patch[i->d.ins-mod->prog]; + switch(mode) { + case ANDAND: + genw(jmsw); + label = code-1; + break; + case OROR: + rbra(dst, jmsw); + break; + case EQAND: + rbra(dst, jmsw); + genw(Ojne); + label = code-1; + break; + } + modrm(OldwR, 0, RTMP, RAX); + modrm(OcmpwR, 0, RTA, RAX); + rbra(dst, jlsw); + if(label != nil) + *label = code-label-1; +} + +static void +cbrab(Inst *i, int jmp) +{ + if(UXSRC(i->add) == SRC(AIMM)) + urk(); + + midD(i, OldbD, DTMP); + opwldD(i,OcmpbD,DTMP); + rbra(patch[i->d.ins-mod->prog], swapforcbra(jmp)); +} + +static void +comcase(Inst *i, int w) +{ + int l; + WORD *t, *e; + + USED (w); + + t = (WORD*)(mod->origmp+i->d.ind+4); + l = t[-1]; + + /* have to take care not to relocate the same table twice - + * the limbo compiler can duplicate a case instruction + * during its folding phase + */ + + if(pass == 0) { + if(l >= 0) + t[-1] = -l-1; /* Mark it not done */ + return; + } + if(l >= 0) /* Check pass 2 done */ + return; + t[-1] = -l-1; /* Set real count */ + e = t + t[-1]*3; + while(t < e) { + t[2] = (ulong)base + patch[t[2]]; + t += 3; + } + t[0] = (ulong)base + patch[t[0]]; +} + +static void +comcasel(Inst *i) +{ + int l; + WORD *t, *e; + + t = (WORD*)(mod->origmp+i->d.ind+8); + l = t[-2]; + if(pass == 0) { + if(l >= 0) + t[-2] = -l-1; /* Mark it not done */ + return; + } + if(l >= 0) /* Check pass 2 done */ + return; + t[-2] = -l-1; /* Set real count */ + e = t + t[-2]*6; + while(t < e) { + t[4] = (ulong)base + patch[t[4]]; + t += 6; + } + t[0] = (ulong)base + patch[t[0]]; +} + +static void +commframe(Inst *i) +{ + int o; + uchar *punt, *mlnil; + + opwld(i, OldwR, RAX); + cmpl(RAX, (ulong)H); + genw(Ojeq); + mlnil = code - 1; + o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame); + modrm(OldwR, o, RAX, RTA); + modrm(OtstwR,O(Type, initialize),RTA,0); + genw(Ojne); + punt = code - 1; + genw(OexgRR|RAX|(RTA<<9)); + opwst(i, OleaR, RTA); + *mlnil = code-mlnil-1; + rbra(macro[MacMFRA], Obsr); + rbra(patch[i-mod->prog+1], Obra); + + *punt = code-punt-1; + rbra(macro[MacFRAM], Obsr); + opwst(i, OstwR, RAX); +} + +static void +commcall(Inst *i) +{ + conR((ulong)&R, RTMP); // MOVL $R, RTMP + opwld(i, OldwR, RTA); + genw(OmovwR|(RTA<<9)); // MOVL $.+1, lr(RTA) f->lr = R.PC + genl((ulong)base+patch[i-mod->prog+1]); + genw(O(Frame, lr)); + modrm(OstwR, O(Frame, fp), RTA, RFP); // MOVL RFP, fp(RTA) f->fp = R.FP + modrm(OldwD, O(REG, M), RTMP, DTMP); // MOVL R.M, DTMP + modrm(OstwD, O(Frame, mr), RTA, DTMP); // MOVL RTA, mr(RTA) f->mr = R.M + opwst(i, OldwR, RAX); // MOVL ml, RAX + modrm(OldwD, O(Modlink, m), RAX, DTMP); // MOVL ml->m, DTMP + modrm(OldwR, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RAX, RAX); + rbra(macro[MacMCAL], Obsr); +} + +static void +laritha(Inst *i, int opc) +{ + if((i->add&ARM) != AXNON) { + mid(i, OleaR, RTMP); + opwst(i, OleaR, RTA); + genw(0x20D8|(RTA<<9)|RTMP); // MOVL (RTMP)+, (RTA)+ + genw(0x20D8|(RTA<<9)|RTMP); // MOVL (RTMP)+, (RTA)+ + } + else { + mid(i, OleaR, RTA); + genw(0x5088|RTA); // ADDQ.l #8, RTA + } + + opwld(i, OleaR, RTMP); + genw(0x5088|RTMP); // ADDQ.l #8, RTMP + + genw(0x44FC); // MOVE imm16, CCR + genw(0); + genw(opc|RTMP|(RTA<<9)); // ADDX (-RTMP), (-RTA) + genw(opc|RTMP|(RTA<<9)); // ADDX (-RTMP), (-RTA) +} + +static void +larith(Inst *i, int op) +{ + if((i->add&ARM) != AXNON) { + mid(i, OleaR, RTMP); + opwst(i, OleaR, RTA); + genw(0x20D8|RTMP|(RTA<<9)); // MOVL (RTMP)+, (RTA)+ + genw(0x2090|RTMP|(RTA<<9)); // MOVL (RTMP), (RTA) + genw(0x5988|RTA); // SUBQ.l #4, RTA + } + else + mid(i, OleaR, RTA); + + + opwld(i, OleaR, RTMP); + genw(0x2018|RTMP|(DTMP<<9)); // MOVL (RTMP+), DTMP + genw(op|RTA|(DTMP<<9)); // ORL DTMP, (RTA+) + genw(0x2010|(DTMP<<9)|RTMP); // MOVL (RTMP) DTMP + genw((op&0xFFF7)|RTA|(DTMP<<9)); // ORL DTMP, (RTA) +} + +static void +shll(Inst *i) +{ + uchar *label; + + opwldD(i, OldwD, DTMP); // The number of shifts -> DTMP + mid(i, OleaR, RTA); // LEA source, RTA + genw(0x2018|(DTMP1<<9)|RTA); // move (RTA+), DTMP1 + genw(0x2010|(DTMP2<<9)|RTA); // move (RTA), DTMP2 + + genw(Obra); + label=code-1; + + genw(OlslD|DTMP2); + genw(OroxlD|DTMP1); + *label=code-label-1; + genw(Odbeq); + genw(label-code+1); + + opwst(i, OleaR, RTA); + genw(0x2080|(RTA<<9)|DTMP2); // move DTMP2, (RTA) + genw(0x2100|(RTA<<9)|DTMP1); // move DTMP1, (-RTA) +} + +static void +shrl(Inst *i) +{ + uchar *label; + + opwldD(i, OldwD, DTMP); // The number of shifts -> DTMP + mid(i, OleaR, RTA); // LEA source, RTA + genw(0x2018|(DTMP1<<9)|RTA); // move (RTA+), DTMP1 + genw(0x2010|(DTMP2<<9)|RTA); // move (RTA), DTMP2 + + genw(Obra); + label=code-1; + + genw(OlsrD|DTMP2); + genw(OroxrD|DTMP1); + *label=code-label-1; + genw(Odbeq); + genw(label-code+1); + + opwst(i, OleaR, RTA); + genw(0x2080|(RTA<<9)|DTMP2); // move DTMP2, (RTA) + genw(0x2100|(RTA<<9)|DTMP1); // move DTMP1, (-RTA) +} + +static int myic; + +static +void +compdbg(void) +{ + print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s); +} + +static void +comp(Inst *i) +{ + int r; + WORD *t, *e; + char buf[64]; + + if(0) { + Inst xx; + xx.add = AXIMM|SRC(AIMM); + xx.s.imm = (ulong)code; + xx.reg = i-mod->prog; + punt(&xx, SRCOP, compdbg); + } + + switch(i->op) { + default: + snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i); + error(buf); + break; + case IMCALL: + if((i->add&ARM) == AXIMM) + commcall(i); + else + punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]); + break; + case ISEND: + case IRECV: + case IALT: + punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]); + break; + case ISPAWN: + punt(i, SRCOP|DBRAN, optab[i->op]); + break; + case IBNEC: + case IBEQC: + case IBLTC: + case IBLEC: + case IBGTC: + case IBGEC: + punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]); + break; + case ICASEC: + comcase(i, 0); + punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]); + break; + case ICASEL: + comcasel(i); + punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]); + break; + case IADDC: + case IMULL: + case IDIVL: + case IMODL: + case ILOAD: + case IMSPAWN: + case ISLICEA: + case ISLICELA: + case ISLICEC: + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + break; + case INEWA: + case INEW: + case ICONSB: + case ICONSW: + case ICONSF: + case ICONSM: + case ICONSMP: + case ICONSP: + case IMOVMP: + case IHEADMP: + case IINSC: + case ICVTAC: + case ICVTCW: + case ICVTWC: + case ICVTLC: + case ICVTCL: + case ICVTFC: + case ICVTCF: + case ICVTCA: + case INBALT: + punt(i, SRCOP|DSTOP, optab[i->op]); + break; + case INEWCM: + case INEWCMP: + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + break; + case IMFRAME: + if((i->add&ARM) == AXIMM) + commframe(i); + else + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + break; + case INEWCB: + case INEWCW: + case INEWCF: + case INEWCP: + case INEWCL: + punt(i, DSTOP|THREOP, optab[i->op]); + break; + case IEXIT: + punt(i, 0, optab[i->op]); + break; + case ICVTBW: + genw(OclrwD| DTMP); + opwldD(i, OldbD, DTMP); + opwstD(i, OstwD, DTMP); + break; + case ICVTWB: + opwldD(i, OldwD, DTMP); + opwstD(i, OstbD, DTMP); + break; + case ICVTFW: + case ICVTWF: + case ICVTLF: + case ICVTFL: + punt(i, SRCOP|DSTOP, optab[i->op]); + break; + case IHEADM: + case IMOVM: + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + break; + case IRET: + rbra(macro[MacRET], Obra); + break; + case IFRAME: + if(UXSRC(i->add) != SRC(AIMM)) { + punt(i, SRCOP|DSTOP, optab[i->op]); + break; + } + tinit[i->s.imm] = 1; + conR((ulong)mod->type[i->s.imm], RTA); + rbra(macro[MacFRAM], Obsr); + opwst(i, OstwR, RAX); + break; + case ILEA: + if(UXSRC(i->add) == SRC(AIMM)) { + genw(Obra|4); + genl(i->s.imm); + conR((ulong)(code-4), RAX); + } + else + opwld(i, OleaR, RAX); + opwst(i, OstwR, RAX); + break; + case IHEADW: + opwld(i, OldwR, RAX); + modrm(OldwR, OA(List, data), RAX, RAX); + opwst(i, OstwR, RAX); + break; + case IHEADF: + punt(i, SRCOP|DSTOP, optab[i->op]); + break; + case IHEADB: + opwld(i, OldwR, RAX); + modrm(OldbD, OA(List, data), RAX, DTMP); + opwstD(i, OstbD, DTMP); + break; + case ITAIL: + opwld(i, OldwR, RAX); + modrm(OldwR, O(List, tail), RAX, RTMP); + goto movp; + case IMOVP: + case IHEADP: + opwld(i, OldwR, RTMP); + if(i->op == IHEADP) + modrm(OldwR, OA(List, data), RTMP, RTMP); + movp: + {uchar *label; + cmpl(RTMP, (ulong)H); + genw(Ojeq); + label=code-1; + rbra(macro[MacCOLR], Obsr); + *label=code-label-1; + opwst(i, OldwR, RAX); + opwst(i, OstwR, RTMP); + rbra(macro[MacFRP], Obsr); + } + break; + case ILENA: + opwld(i, OldwR, RTMP); + conR(0, RAX); + cmpl(RTMP, (ulong)H); + genw(Ojeq|0x2); + modrm(OldwR, O(Array, len), RTMP, RAX); + opwst(i, OstwR, RAX); + break; + case ILENC: + {uchar *label; + opwld(i, OldwR, RTMP); + conD(0, DTMP); + cmpl(RTMP, (ulong)H); + genw(Ojeq); + label=code-1; + modrm(OldwD, O(String, len), RTMP, DTMP); + genw(0x4A80|RAX); // TSTL DTMP + genw(Ojge|0x02); + genw(OnegwD|DTMP); + *label=code-label-1; + opwstD(i, OstwD, DTMP); + } + break; + case ILENL: + {uchar *label,*l2; + conR(0, RAX); + opwld(i, OldwR, RTMP); + l2=code-1; + cmpl(RTMP, (ulong)H); + genw(Ojeq); + label=code-1; + modrm(OldwR, O(List, tail), RTMP, RTMP); + genw(OincrwR|RAX); + genw(Obra|(uchar)(l2-code-1)); + *label=code-label-1; + opwst(i, OstwR, RAX); + } + break; + case IBEQF: + case IBNEF: + case IBLEF: + case IBLTF: + case IBGEF: + case IBGTF: + punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]); + break; + case IBEQW: + cbra(i, Ojeq); + break; + case IBLEW: + cbra(i, Ojle); + break; + case IBNEW: + cbra(i, Ojne); + break; + case IBGTW: + cbra(i, Ojgt); + break; + case IBLTW: + cbra(i, Ojlt); + break; + case IBGEW: + cbra(i, Ojge); + break; + case IBEQB: + cbrab(i, Ojeq); + break; + case IBLEB: + cbrab(i, Ojls); + break; + case IBNEB: + cbrab(i, Ojne); + break; + case IBGTB: + cbrab(i, Ojhi); + break; + case IBLTB: + cbrab(i, Ojlo); + break; + case IBGEB: + cbrab(i, Ojhs); + break; + case ISUBW: + if (UXSRC(i->add)==SRC(AIMM)) + arithimms(i,Osubi,1); + else + arith(i, Osub, 1); + break; + case ISUBB: + if (UXSRC(i->add)==SRC(AIMM)) + arithimms(i,Osubi,1); + else + arith(i, Osub, 0); + break; + case ISUBF: + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + break; + case IADDW: + if (UXSRC(i->add)==SRC(AIMM)) + arithimms(i,Oaddi,1); + else + arith(i, Oadd, 1); + break; + case IADDB: + if (UXSRC(i->add)==SRC(AIMM)) + arithimms(i,Oaddi,0); + else + arith(i, Oadd, 0); + break; + case IADDF: + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + break; + case IORW: + if (UXSRC(i->add)==SRC(AIMM)) + arithimms(i,Oori,1); + else + arith(i, Oor, 1); + break; + case IORB: + if (UXSRC(i->add)==SRC(AIMM)) + arithimms(i,Oori,0); + else + arith(i, Oor, 0); + break; + case IANDW: + arith(i, Oand, 1); + break; + case IANDB: + arith(i, Oand, 0); + break; + case IXORW: + if (UXSRC(i->add)==SRC(AIMM)) + arithimms(i,Oeori,1); + else + arith(i, Oeor, 1); + break; + case IXORB: + if (UXSRC(i->add)==SRC(AIMM)) + arithimms(i,Oeori,0); + else + arith(i, Oeor, 0); + break; + case ISHLW: + shift(i, OldwD, OstwD, OaslwD); + break; + case ISHLB: + shift(i, OldbD, OstbD, OaslbD); + break; + case ISHRW: + shift(i, OldwD, OstwD, OasrwD); + break; + case ISHRB: + shift(i, OldbD, OstbD, OasrbD); + break; + case IMOVF: + case INEGF: + punt(i, SRCOP|DSTOP, optab[i->op]); + break; + case IMOVB: + opwldD(i, OldbD, DTMP); + opwstD(i, OstbD, DTMP); + break; + case IMOVW: + opwldD(i, OldwD, DTMP); + opwstD(i, OstwD, DTMP); + break; + case ICVTLW: + case ICVTWL: + punt(i, SRCOP|DSTOP, optab[i->op]); + break; + case ICALL: + opwld(i, OldwR, RAX); + genw(OmovwR|(RAX<<9)); // MOVL $.+1, lr(AX) + genl((ulong)base+patch[i-mod->prog+1]); + genw(O(Frame, lr)); + modrm(OstwR, O(Frame, fp), RAX, RFP); // MOVL RFP, fp(AX) + genw(OmovwRR|(RFP<<9)|RAX); // MOVL AX,RFP + /* no break */ + case IJMP: + rbra(patch[i->d.ins-mod->prog], Obra); + break; + case IGOTO: + opwst(i, OleaR, RTMP); + opwldD(i, OldwD, DTMP); + genw(OlslwD|DTMP); + genw(Oadd|(RTMP<<9)|(7<<6)|DTMP); + genw(OjmpRind|RTMP); + + if(pass == 0) + break; + + t = (WORD*)(mod->origmp+i->d.ind); + e = t + t[-1]; + t[-1] = 0; + while(t < e) { + t[0] = (ulong)base + patch[t[0]]; + t++; + } + break; + case IMULF: + case IDIVF: + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + break; + case IMODW: + case IDIVW: + case IMULW: + opwld(i, OldwR, RAX); + genw(OpushwR|RAX); + mid(i, OldwR, RAX); + genw(OpushwR|RAX); + switch(i->op) { + case IMULW: + bra((ulong)_mull,Obsr); + genw(OaddqwR|(4<<9)|R7); + genw(OpopwR|(RAX<<9)); + break; + case IMODW: + bra((ulong)_divsl,Obsr); + genw(OaddqwR|(4<<9)|R7); + genw(OpopwR|(RAX<<9)); + break; + case IDIVW: + bra((ulong)_divsl,Obsr); + genw(OpopwR|(RAX<<9)); + genw(OaddqwR|(4<<9)|R7); + break; + } + opwst(i, OstwR, RAX); + break; + case IMODB: + case IDIVB: + case IMULB: + midD(i, OldbD, DTMP); + genw(Oextw|DTMP); + opwldD(i, OldbD, DTMP2); + if (i->op == IMULB) + if(i->op == IMULB) { + genw(Oextw|DTMP2); + genw(Omuls|(DTMP<<9)|DTMP2); + } + else { + genw(Oextbw|DTMP2); + genw(Odivs|(DTMP<<9)|DTMP2); + } + if (i->op == IMODB) + genw(Oswap|DTMP); + opwstD(i, OstbD, DTMP); + break; + case IINDX: + opwld(i, OldwR, RTMP); // MOVW xx(s), RTMP + modrm(OldwR, O(Array, t), RTMP, RAX); // MOVW t(RTMP), AX + modrm(OldwD, O(Type, size), RAX, DTMP1); // MOVW size(AX), DTMP1 + opwstD(i, OldwD, DTMP2); // MOVW indx, DTMP2 + genl(0x70204283); // loop to MULW DTMP1, DTMP2, DTMP3 + genl(0xe2996402); + genl(0xd682e38a); + genl(0x57c8fff6); + + modrm(OldwR, O(Array, data), RTMP, RTMP); + genw(Oadd|(DTMP3<<9)|0x0088|RTMP); // ADDL data(RTMP), DTMP3 + r = RMP; + if((i->add&ARM) == AXINF) + r = RFP; + modrm(OstwD, i->reg, r, DTMP3); + break; + case IINDB: + r = 0; + goto idx; + case IINDF: + punt(i, SRCOP|THREOP|DSTOP, optab[i->op]); + break; + case IINDL: + r = 3; + goto idx; + case IINDW: + r = 2; + idx: + opwld(i, OldwR, RAX); + opwstD(i, OldwD, DTMP); + modrm(OldwR, O(Array, data), RAX, RTMP); + + if (r) + genw(0xE188|(r<<9)|DTMP); + genw(Oadd|(RTMP<<9)|(7<<6)|DTMP); /* lea (AX)(DTMP*r) */ + + r = RMP; + if((i->add&ARM) == AXINF) + r = RFP; + modrm(OstwR, i->reg, r, RTMP); + break; + case IINDC: + { uchar *label; + opwld(i, OldwR, RAX); // string + midD(i, OldwD, DTMP); // index + modrm(OtstwR,O(String, len),RAX,0); + modrm(OleaR, O(String, data), RAX, RAX); + genw(Ojge); // Ascii only, jump + label=code-1; + + genw(OnegwD|DTMP); + genw(Olsl2D|DTMP); // << 2; index is times 4 bytes + genw(Oadd|(RAX<<9)|0x01C0|DTMP); + modrm(OldwD, 0, RAX, DTMP); + genw(Obra|0x4); + *label=code-label-1; + genw(Oadd|(RAX<<9)|0x01C0|DTMP); + modrm(OldbD, 0, RAX, DTMP); + + opwst(i, OstwD, DTMP); + } + break; + case ICASE: + comcase(i, 1); + punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]); + break; + case IMOVL: + opwld(i, OleaR, RTA); + opwst(i, OleaR, RTMP); + genw(0x20D8|(RTMP<<9)|RTA); // MOVE.l (RTA+), (RTMP+) + genw(0x2090|(RTMP<<9)|RTA); // MOVE.l (RTA), (RTMP) + break; + case IADDL: + laritha(i, 0xD188); // ADDX.l (-R0), (-R0) + break; + case ISUBL: + laritha(i, 0x9188); // SUBX.l (-R0), (-R0) + break; + case IORL: + larith(i, 0x8198); // OR.l D0, (R0+) + break; + case IANDL: + larith(i, 0xC198); // AND.l D0, (R0+) + break; + case IXORL: + larith(i, 0xB198); // EOR.l D0, (R0+) + break; + case IBEQL: + cbral(i, Ojne, Ojeq, ANDAND); + break; + case IBNEL: + cbral(i, Ojne, Ojne, OROR); + break; + case IBLEL: + cbral(i, Ojlt, Ojls, EQAND); + break; + case IBGTL: + cbral(i, Ojgt, Ojhi, EQAND); + break; + case IBLTL: + cbral(i, Ojlt, Ojlo, EQAND); + break; + case IBGEL: + cbral(i, Ojgt, Ojhs, EQAND); + break; + case ISHLL: + shll(i); + break; + case ISHRL: + shrl(i); + break; + case IRAISE: + punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]); + break; + case IMULX: + case IDIVX: + case ICVTXX: + case IMULX0: + case IDIVX0: + case ICVTXX0: + case IMULX1: + case IDIVX1: + case ICVTXX1: + case ICVTFX: + case ICVTXF: + case IEXPW: + case IEXPL: + case IEXPF: + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + break; + case ISELF: + punt(i, DSTOP, optab[i->op]); + break; + } +} + +static void +preamble(void) +{ + uchar *s; + if(comvec) + return; + + comvec = malloc(32); + if(comvec == nil) + error(exNomem); + code = (uchar*)comvec; + s = code; + + conR((ulong)&R, RAX); + modrm(OldwR, O(REG, FP), RAX, RFP); + modrm(OldwR, O(REG, MP), RAX, RMP); + modrm(OldwR, O(REG, PC), RAX, RAX); + genw(OjmpRind|RAX); + + segflush(comvec, 32); + + if(cflag > 2) { + print("preamble\n"); + das(s, code-s); + } +} + +static void +maccase(void) +{ + /* Not used yet, done with punt() */ +} + +static void +macfrp(void) +{ + uchar *label,*s; + s=code; + cmpl(RAX, (ulong)H); // CMPL AX, $H + genw(Ojne|0x2); // JNE .+2 + genw(Orts); // RET + genw(OcmpiwR|(RAX<<9)); + genl(0x01); // CMP AX.ref, $1 + genw(O(Heap, ref)-sizeof(Heap)); + genw(Ojeq); // JEQ + label=code-1; + modrm(OdecrwRind, O(Heap, ref)-sizeof(Heap), RAX, 0); // DEC AX.ref + genw(Orts); // RET + *label=code-label-1; + + conR((ulong)&R, RTMP); // MOV $R, RTMP + modrm(OstwR, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP + modrm(OstwR, O(REG, s), RTMP, RAX); // MOVL RAX, R.s + // CALL rdestroy + bra((ulong)rdestroy, Obsr); + conR((ulong)&R, RTMP); // MOVL $R, RTMP + modrm(OldwR, O(REG, FP), RTMP, RFP); // MOVL R.FP, RFP + modrm(OldwR, O(REG, MP), RTMP, RMP); // MOVL R.MP, RMP + genw(Orts); + if(pass&&(cflag > 2)) { + print("macfrp\n"); + das(s, code-s); + } +} + +static void +macret(void) +{ + Inst i; + uchar *s; + static ulong lpunt, lnomr, lfrmr,linterp; + + s = code; + + lpunt -= 2; + lnomr -= 2; + lfrmr -= 2; + linterp -= 2; + + modrm(OldwR, O(Frame, t), RFP, RAX); // MOVL t(FP), RAX + genw(OmovwRD|(DTMP<<9)|RAX); + genw(0x4A80|DTMP); // TSTL DTMP + genw(Ojeq|(uchar)(lpunt-(code-s))); // JEQ lpunt + modrm(OldwR, O(Type, destroy), RAX, RAX); // MOVL destroy(RAX), RAX + genw(OmovwRD|(DTMP<<9)|RAX); + genw(0x4A80|DTMP); // TSTL DTMP + genw(Ojeq|(uchar)(lpunt-(code-s))); // JEQ lpunt + modrm(OtstwR, O(Frame, fp), RFP, 0); // TSTL fp(RFP) + genw(Ojeq|(uchar)(lpunt-(code-s))); // JEQ lpunt + modrm(OtstwR, O(Frame, mr), RFP, 0); // TSTL mr(RFP) + genw(Ojeq|(uchar)(lnomr-(code-s))); // JEQ lnomr + conR((ulong)&R, RTMP); // MOVL $R, RTMP + modrm(OldwR, O(REG, M), RTMP, RTA); // MOVL R.M, RTA + modrm(OdecrwRind, O(Module, ref), RTA, 0); // DECL ref(RTA) + genw(Ojne|(uchar)(lfrmr-(code-s))); // JNE lfrmr + modrm(OincrwRind, O(Module, ref), RTA, 0); // INCL ref(RTA) + genw(Obra|(uchar)(lpunt-(code-s))); // JMP lpunt + lfrmr = code - s; + modrm(OldwR, O(Frame, mr), RFP, RTA); // MOVL mr(RFP), RTA + modrm(OstwR, O(REG, M), RTMP, RTA); // MOVL RTA, R.M + modrm(OldwR, O(Modlink, MP), RTA, RMP); // MOVL mp(RTA), RMP + modrm(OstwR, O(REG, MP), RTMP, RMP); // MOVL RMP, R.MP + + modrm(OtstwR, O(Modlink, compiled), RTA, 0); // CMPL $0, M.compiled + genw(Ojeq|(uchar)(linterp-(code-s))); + + lnomr = code - s; + genw(OjsrRind|RAX); // CALL* AX + conR((ulong)&R, RTMP); // MOVL $R, RTMP + modrm(OstwR, O(REG, SP), RTMP, RFP); // MOVL RFP, R.SP + modrm(OldwR, O(Frame, lr), RFP, RAX); // MOVL lr(RFP), RAX + modrm(OldwR, O(Frame, fp), RFP, RFP); // MOVL fp(RFP), RFP + modrm(OstwR, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP + genw(OjmpRind|RAX); // JMP*L AX + + linterp = code - s; + genw(OjsrRind|RAX); // CALL* AX + conR((ulong)&R, RTMP); // MOVL $R, RTMP + modrm(OstwR, O(REG, SP), RTMP, RFP); // MOVL RFP, R.SP + modrm(OldwR, O(Frame, lr), RFP, RAX); // MOVL lr(RFP), RAX + modrm(OstwR, O(REG, PC), RTMP, RAX); // MOVL RAX, R.PC + modrm(OldwR, O(Frame, fp), RFP, RFP); // MOVL fp(RFP), RFP + modrm(OstwR, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP + + genw(Orts); + lpunt = code - s; // label: + i.add = AXNON; + punt(&i, NEWPC, optab[IRET]); + if(pass&&(cflag > 2)) { + print("macret\n"); + das(s, code-s); + } +} + +static void +maccolr(void) +{ + uchar *s; + s=code; + modrm(OincrwRind, O(Heap, ref)-sizeof(Heap), RTMP, 0); // INCL ref(RTMP) + genw(0x2079|(RAX<<9)); // MOVL (mutator), RAX + genl((ulong)&mutator); + modrm(OcmpwR, O(Heap, color)-sizeof(Heap), RTMP, RAX); // CMPL color(RTMP), RAX + genw(Ojne|0x02); + genw(Orts); + conR(propagator, RAX); // MOVL $propagator,RAX + modrm(OstwR, O(Heap, color)-sizeof(Heap), RTMP, RAX); // MOVL RAX, color(RTMP) + genw(0x23C8|RAX); // can be any !0 value + genl((ulong)&nprop); // MOVL RAX, (nprop) + genw(Orts); + if(pass&&(cflag > 2)) { + print("maccolr\n"); + das(s, code-s); + } +} + +static void +macmcal(void) +{ + uchar *s,*label,*interp; + s=code; + + genw(0x2040|(RCX<<9)|DTMP); + modrm(OtstwR,O(Module, prog),RCX,0); // TSTL ml->m->prog + + genw(Ojne); // JNE patch + label = code-1; + modrm(OstwR, O(REG, FP), RTMP, RTA); + modrm(OstwR, O(REG, dt), RTMP, RAX); + // CALL rmcall + bra((ulong)rmcall, Obsr); + + conR((ulong)&R, RTMP); // MOVL $R, RTMP + modrm(OldwR, O(REG, FP), RTMP, RFP); + modrm(OldwR, O(REG, MP), RTMP, RMP); + genw(Orts); // RET + *label = code-label-1; // patch: + genw(0x2048|(RFP<<9)|RTA); // MOVL RTA, RFP R.FP = f + modrm(OstwR, O(REG, M), RTMP, RCX); // MOVL RCX, R.M + modrm(OincrwRind, O(Module, ref), RCX, 0); // INC.L R.M->ref + modrm(OldwR, O(Modlink, MP), RCX, RMP); // MOVL R.M->mp, RMP + modrm(OstwR, O(REG, MP), RTMP, RMP); // MOVL RCX, R.MP R.MP = ml->m + modrm(OtstwR, O(Module, compiled), RCX, 0);// CMPL $0, M.compiled + + genw(OpopwR|(RCX<<9)); // balance call + genw(Ojeq); // JEQ interp + interp=code-1; + genw(OjmpRind|RAX); // JMP*L AX + *interp= code-interp-1; + modrm(OstwR, O(REG, FP), RTMP, RFP); // MOVL FP, R.FP + modrm(OstwR, O(REG, PC), RTMP, RAX); // MOVL PC, R.PC + genw(Orts); + if(pass&&(cflag > 2)) { + print("macmcal\n"); + das(s, code-s); + } +} + +static void +macfram(void) +{ + uchar *label,*s; + s=code; + conR((ulong)&R, RTMP); // MOVL $R, RTMP + modrm(OldwD, O(REG, SP), RTMP, DTMP); // MOVL R.SP, DTMP + modrm(OaddRD, O(Type, size), RTA, DTMP);// ADDL size(RTA), DTMP + modrm(OcmpwD, O(REG, TS), RTMP, DTMP); // CMPL DTMP, R.TS + genw(Ojlt); // JLT .+(patch) + label = code-1; + + modrm(OstwR, O(REG, s), RTMP, RTA); + modrm(OstwR, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP + // BSR extend + bra((ulong)extend, Obsr); + conR((ulong)&R, RTMP); + modrm(OldwR, O(REG, FP), RTMP, RFP); // MOVL R.MP, RMP + modrm(OldwR, O(REG, MP), RTMP, RMP); // MOVL R.FP, RFP + modrm(OldwR, O(REG, s), RTMP, RAX); // MOVL R.s, *R.d + genw(Orts); // RET + *label = code-label-1; + modrm(OldwR, O(REG, SP), RTMP, RAX); // MOVL R.SP, RAX + modrm(OstwD, O(REG, SP), RTMP, DTMP); // MOVL DTMP, R.SP + + modrm(OstwR, O(Frame, t), RAX, RTA); // MOVL RTA, t(RAX) f->t = t + genw(OmovwR|(RAX<<9)); // MOVL $0, mr(RAX) f->mr + genl(0); + genw(REGMOD*4); + + modrm(OldwR, O(Type, initialize), RTA, RTA); + genw(OjmpRind|RTA); // JMP*L RTA + genw(Orts); // RET + if(pass&&(cflag > 2)) { + print("macfram\n"); + das(s, code-s); + } +} + +static void +macmfra(void) +{ + uchar *s; + s=code; + conR((ulong)&R, RTMP); // MOVL $R, RTMP + modrm(OstwR, O(REG, FP), RTMP, RFP); + modrm(OstwR, O(REG, s), RTMP, RAX); // Save type + modrm(OstwR, O(REG, d), RTMP, RTA); // Save destination + // CALL rmfram + bra((ulong)rmfram, Obsr); + conR((ulong)&R, RTMP); // MOVL $R, RTMP + modrm(OldwR, O(REG, FP), RTMP, RFP); + modrm(OldwR, O(REG, MP), RTMP, RMP); + genw(Orts); // RET + if(pass&&(cflag > 2)) { + print("macmfra\n"); + das(s, code-s); + } +} + +void +comd(Type *t) +{ + int i, j, m, c; + + for(i = 0; i < t->np; i++) { + c = t->map[i]; + j = i<<5; + for(m = 0x80; m != 0; m >>= 1) { + if(c & m) { + modrm(OldwR, j, RFP, RAX); + rbra(macro[MacFRP], Obsr); + } + j += sizeof(WORD*); + } + } + genw(Orts); +} + +void +comi(Type *t) +{ + int i, j, m, c; + + conD((ulong)H, DTMP); + for(i = 0; i < t->np; i++) { + c = t->map[i]; + j = i<<5; + for(m = 0x80; m != 0; m >>= 1) { + if(c & m) + modrm(OstwD, j, RAX, DTMP); + j += sizeof(WORD*); + } + } + genw(Orts); +} + +void +typecom(Type *t) +{ + int n; + uchar *tmp; + tmp=malloc(4096); + + if(tmp == nil) + error(exNomem); + if(t == nil || t->initialize != 0) + return; + + code = tmp; + comi(t); + n = code - tmp; + code = tmp; + comd(t); + n += code - tmp; + + code = mallocz(n, 0); + if(code == nil) + return; + + t->initialize = code; + comi(t); + t->destroy = code; + comd(t); + + segflush(t->initialize, n); + + if(cflag > 1) { + print("typ= %.8p %4d i %.8p d %.8p asm=%d\n", + t, t->size, t->initialize, t->destroy, n); + if (cflag > 2) + das(t->destroy, code-(uchar*)t->destroy); + } + free(tmp); +} + +static void +patchex(Module *m, ulong *p) +{ + Handler *h; + Except *e; + + if((h = m->htab) == nil) + return; + for( ; h->etab != nil; h++){ + h->pc1 = p[h->pc1]; + h->pc2 = p[h->pc2]; + for(e = h->etab; e->s != nil; e++) + e->pc = p[e->pc]; + if(e->pc != -1) + e->pc = p[e->pc]; + } +} + +int +compile(Module *m, int size, Modlink *ml) +{ + ulong v; + Link *l; + Modl *e; + int i, n; + uchar *s, *tmp; + base = nil; + + tmp=malloc(4096); + patch = mallocz(size*sizeof(*patch), 0); + tinit = malloc(m->ntype*sizeof(*tinit)); + if(tinit == nil || patch == nil || tmp == nil) + goto bad; + + preamble(); + + mod = m; + n = 0; + pass = 0; + nlit = 0; + + for(i = 0; i < size; i++) { + code = tmp; + comp(&m->prog[i]); + if(code >= &tmp[4096]) { + print("tmp ovlo\n%3d %D\n", i, &m->prog[i]); + urk(); + } + patch[i] = n; + n += code - tmp; + } + + for(i = 0; i < nelem(mactab); i++) { + code = tmp; + (*mactab[i].gen)(); + macro[mactab[i].idx] = n; + n += code - tmp; + } + + nlit *= sizeof(ulong); + base = mallocz(n + nlit, 0); + if(base == nil) + goto bad; + + if(cflag > 1) + print("dis=%5d %5d 386=%5d asm=%.8p lit=%d: %s\n", + size, size*sizeof(Inst), n, base, nlit, m->name); + + pass++; + nlit = 0; + litpool = (ulong*)(base+n); + code = base; + n = 0; + for(i = 0; i < size; i++) { + s = code; + comp(&m->prog[i]); + if(patch[i] != n) { + print("phase error\n%3d %D\n", i, &m->prog[i]); + urk(); + } + n += code - s; + if(cflag > 1) { + print("%d: %D\n", i,&m->prog[i]); + das(s, code-s); + } + } + + for(i = 0; i < nelem(mactab); i++) { + if(macro[mactab[i].idx] != n) { + print("phase error\nmactab %d\n", mactab[i].idx); + urk(); + } + s = code; + (*mactab[i].gen)(); + n += code-s; + if(cflag > 1) { + print("mactab %d\n", mactab[i].idx); + das(s, code-s); + } + } + + v = (ulong)base; + for(l = m->ext; l->name; l++) { +//print("### link: %lux ",l->u.pc-m->prog); + l->u.pc = (Inst*)(v+patch[l->u.pc-m->prog]); +//print("%lux\n",l->u.pc); + typecom(l->frame); + } + if(ml != nil) { + e = &ml->links[0]; + for(i = 0; i < ml->nlinks; i++) { + e->u.pc = (Inst*)(v+patch[e->u.pc-m->prog]); + typecom(e->frame); + e++; + } + } + for(i = 0; i < m->ntype; i++) { + if(tinit[i] != 0) + typecom(m->type[i]); + } + patchex(m, patch); + m->entry = (Inst*)(v+patch[mod->entry-mod->prog]); + free(patch); + free(tinit); + free(tmp); + free(m->prog); + m->prog = (Inst*)base; + m->compiled = 1; + segflush(base, n*sizeof(*base)); + return 1; +bad: + free(tmp); + free(patch); + free(tinit); + free(base); + return 0; +} |
