summaryrefslogtreecommitdiff
path: root/libinterp/comp-68020.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /libinterp/comp-68020.c
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libinterp/comp-68020.c')
-rw-r--r--libinterp/comp-68020.c2074
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;
+}