summaryrefslogtreecommitdiff
path: root/libinterp/comp-386.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-386.c
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libinterp/comp-386.c')
-rw-r--r--libinterp/comp-386.c1975
1 files changed, 1975 insertions, 0 deletions
diff --git a/libinterp/comp-386.c b/libinterp/comp-386.c
new file mode 100644
index 00000000..4f5d89c4
--- /dev/null
+++ b/libinterp/comp-386.c
@@ -0,0 +1,1975 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define DOT ((ulong)code)
+
+#define RESCHED 1 /* check for interpreter reschedule */
+
+enum
+{
+ RAX = 0,
+ RAH = 4,
+ RCX = 1,
+ RDX = 2,
+ RBX = 3,
+ RSP = 4,
+ RBP = 5,
+ RSI = 6,
+ RDI = 7,
+
+ RFP = RSI,
+ RMP = RDI,
+ RTA = RDX,
+ RTMP = RBX,
+
+ Omovzxb = 0xb6,
+ Omovzxw = 0xb7,
+ Osal = 0xd1,
+ Oaddf = 0xdc,
+ Ocall = 0xe8,
+ Ocallrm = 0xff,
+ Ocdq = 0x99,
+ Ocld = 0xfc,
+ Ocmpb = 0x38,
+ Ocmpw = 0x39,
+ Ocmpi = 0x83,
+ Odecrm = 0xff,
+ Oincr = 0x40,
+ Oincrm = 0xff,
+ Ojccl = 0x83,
+ Ojcsl = 0x82,
+ Ojeqb = 0x74,
+ Ojeql = 0x84,
+ Ojgel = 0x8d,
+ Ojgtl = 0x8f,
+ Ojhil = 0x87,
+ Ojlel = 0x8e,
+ Ojlsl = 0x86,
+ Ojltl = 0x8c,
+ Ojol = 0x80,
+ Ojnol = 0x81,
+ Ojbl = 0x82,
+ Ojael = 0x83,
+ Ojal = 0x87,
+ Ojnel = 0x85,
+ Ojbel = 0x86,
+ Ojneb = 0x75,
+ Ojgtb = 0x7f,
+ Ojgeb = 0x7d,
+ Ojleb = 0x7e,
+ Ojltb = 0x7c,
+ Ojmp = 0xe9,
+ Ojmpb = 0xeb,
+ Ojmprm = 0xff,
+ Oldb = 0x8a,
+ Olds = 0x89,
+ Oldw = 0x8b,
+ Olea = 0x8d,
+ Otestib = 0xf6,
+ Oshld = 0xa5,
+ Oshrd = 0xad,
+ Osar = 0xd3,
+ Osarimm = 0xc1,
+ Omov = 0xc7,
+ Omovf = 0xdd,
+ Omovimm = 0xb8,
+ Omovsb = 0xa4,
+ Orep = 0xf3,
+ Oret = 0xc3,
+ Oshl = 0xd3,
+ Oshr = 0xd1,
+ Ostb = 0x88,
+ Ostw = 0x89,
+ Osubf = 0xdc,
+ Oxchg = 0x87,
+ OxchgAX = 0x90,
+ Oxor = 0x31,
+ Opopl = 0x58,
+ Opushl = 0x50,
+ Opushrm = 0xff,
+ Oneg = 0xf7,
+
+ 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,
+ MacRELQ = 7,
+ 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 void macrelq(void);
+static ulong macro[NMACRO];
+ void (*comvec)(void);
+extern void das(uchar*, int);
+
+#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 */
+ MacRELQ, macrelq, /* reschedule */
+};
+
+static void
+bounds(void)
+{
+ error(exBounds);
+}
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Prog *p;
+ Frame *f;
+
+ if((void*)R.dt == H)
+ error(exModule);
+
+ 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;
+ if(t == H)
+ error(exModule);
+
+ 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 void
+urk(void)
+{
+ error(exCompile);
+}
+
+static void
+genb(uchar o)
+{
+ *code++ = o;
+}
+
+static void
+gen2(uchar o1, uchar o2)
+{
+ code[0] = o1;
+ code[1] = o2;
+ code += 2;
+}
+
+static void
+genw(ulong o)
+{
+ *(ulong*)code = o;
+ code += 4;
+}
+
+static void
+modrm(int inst, ulong disp, int rm, int r)
+{
+ *code++ = inst;
+ if(disp == 0) {
+ *code++ = (0<<6)|(r<<3)|rm;
+ return;
+ }
+ if(bc(disp)) {
+ code[0] = (1<<6)|(r<<3)|rm;
+ code[1] = disp;
+ code += 2;
+ return;
+ }
+ *code++ = (2<<6)|(r<<3)|rm;
+ *(ulong*)code = disp;
+ code += 4;
+}
+
+static void
+con(ulong o, int r)
+{
+ if(o == 0) {
+ gen2(Oxor, (3<<6)|(r<<3)|r);
+ return;
+ }
+ genb(Omovimm+r);
+ genw(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):
+ con(i->s.imm, r);
+ return;
+ case SRC(AIND|AFP):
+ ir = RFP;
+ break;
+ case SRC(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Olea)
+ rta = r;
+ modrm(Oldw, i->s.i.f, ir, rta);
+ modrm(mi, i->s.i.s, rta, r);
+}
+
+static void
+opwst(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXDST(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case DST(AIMM):
+ con(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 == Olea)
+ rta = r;
+ modrm(Oldw, i->d.i.f, ir, rta);
+ modrm(mi, i->d.i.s, rta, r);
+}
+
+static void
+bra(ulong dst, int op)
+{
+ dst -= (DOT+5);
+ genb(op);
+ genw(dst);
+}
+
+static void
+rbra(ulong dst, int op)
+{
+ dst += (ulong)base;
+ dst -= DOT+5;
+ genb(op);
+ genw(dst);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ genb(Omovimm+RAX);
+ genw((ulong)litpool);
+ modrm(Ostw, roff, RTMP, RAX);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+
+ con((ulong)&R, RTMP);
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM))
+ literal(i->s.imm, O(REG, s));
+ else {
+ opwld(i, Olea, RAX);
+ modrm(Ostw, O(REG, s), RTMP, RAX);
+ }
+ }
+
+ if(m & DSTOP) {
+ opwst(i, Olea, 0);
+ modrm(Ostw, O(REG, d), RTMP, RAX);
+ }
+ if(m & WRTPC) {
+ modrm(Omov, O(REG, PC), RTMP, 0);
+ pc = patch[i-mod->prog+1];
+ genw((ulong)base + 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(Oldw, O(REG, d), RTMP, RAX);
+ modrm(Ostw, O(REG, m), RTMP, RAX);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG, m));
+ break;
+ case AXINF:
+ modrm(Olea, i->reg, RFP, RAX);
+ modrm(Ostw, O(REG, m), RTMP, RAX);
+ break;
+ case AXINM:
+ modrm(Olea, i->reg, RMP, RAX);
+ modrm(Ostw, O(REG, m), RTMP, RAX);
+ break;
+ }
+ modrm(Ostw, O(REG, FP), RTMP, RFP);
+
+ bra((ulong)fn, Ocall);
+
+ con((ulong)&R, RTMP);
+ if(m & TCHECK) {
+ modrm(Ocmpi, O(REG, t), RTMP, 7);// CMPL $0, R.t
+ genb(0x00);
+ gen2(Ojeqb, 0x06); // JEQ .+6
+ genb(Opopl+RDI);
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+ }
+
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+
+ if(m & NEWPC) {
+ modrm(Oldw, O(REG, PC), RTMP, RAX);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX);
+ }
+}
+
+static void
+mid(Inst *i, uchar mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opwst(i, mi, r);
+ return;
+ case AXIMM:
+ con((short)i->reg, r);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ modrm(mi, i->reg, ir, r);
+}
+
+static void
+arith(Inst *i, int op2, int rm)
+{
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ if(i->add&ARM) {
+ mid(i, Oldw, RAX);
+ opwld(i, op2|2, 0);
+ opwst(i, Ostw, 0);
+ return;
+ }
+ opwld(i, Oldw, RAX);
+ opwst(i, op2, 0);
+ return;
+ }
+ if(i->add&ARM) {
+ mid(i, Oldw, RAX);
+ if(bc(i->s.imm)) {
+ gen2(0x83, (3<<6)|(rm<<3)|RAX);
+ genb(i->s.imm);
+ }
+ else {
+ gen2(0x81, (3<<6)|(rm<<3)|RAX);
+ genw(i->s.imm);
+ }
+ opwst(i, Ostw, RAX);
+ return;
+ }
+ if(bc(i->s.imm)) {
+ opwst(i, 0x83, rm);
+ genb(i->s.imm);
+ return;
+ }
+ opwst(i, 0x81, rm);
+ genw(i->s.imm);
+}
+
+static void
+arithb(Inst *i, int op2)
+{
+ if(UXSRC(i->add) == SRC(AIMM))
+ urk();
+
+ if(i->add&ARM) {
+ mid(i, Oldb, RAX);
+ opwld(i, op2|2, 0);
+ opwst(i, Ostb, 0);
+ return;
+ }
+ opwld(i, Oldb, RAX);
+ opwst(i, op2, RAX);
+}
+
+static void
+shift(Inst *i, int ld, int st, int op, int r)
+{
+ mid(i, ld, RAX);
+ opwld(i, Oldw, RCX);
+ gen2(op, (3<<6)|(r<<3)|RAX);
+ opwst(i, st, RAX);
+}
+
+static void
+arithf(Inst *i, int op)
+{
+ opwld(i, Omovf, 0);
+ mid(i, 0xdc, op);
+ opwst(i, Omovf, 3);
+}
+
+static void
+cmpl(int r, ulong v)
+{
+ if(bc(v)) {
+ gen2(0x83, (3<<6)|(7<<3)|r);
+ genb(v);
+ return;
+ }
+ gen2(0x81, (3<<6)|(7<<3)|r);
+ genw(v);
+}
+
+static int
+swapbraop(int b)
+{
+ switch(b) {
+ case Ojgel:
+ return Ojlel;
+ case Ojlel:
+ return Ojgel;
+ case Ojgtl:
+ return Ojltl;
+ case Ojltl:
+ return Ojgtl;
+ }
+ return b;
+}
+
+static void
+schedcheck(Inst *i)
+{
+ if(RESCHED && i->d.ins <= i){
+ con((ulong)&R, RTMP);
+ /* sub $1, R.IC */
+ modrm(0x83, O(REG, IC), RTMP, 5);
+ genb(1);
+ gen2(Ojgtb, 5);
+ rbra(macro[MacRELQ], Ocall);
+ }
+}
+
+static void
+cbra(Inst *i, int jmp)
+{
+ if(RESCHED)
+ schedcheck(i);
+ mid(i, Oldw, RAX);
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ cmpl(RAX, i->s.imm);
+ jmp = swapbraop(jmp);
+ }
+ else
+ opwld(i, Ocmpw, RAX);
+ genb(0x0f);
+ rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+ ulong dst;
+ uchar *label;
+
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Olea, RTMP);
+ mid(i, Olea, RTA);
+ modrm(Oldw, 4, RTA, RAX);
+ modrm(Ocmpw, 4, RTMP, RAX);
+ label = 0;
+ dst = patch[i->d.ins-mod->prog];
+ switch(mode) {
+ case ANDAND:
+ gen2(Ojneb, 0);
+ label = code-1;
+ break;
+ case OROR:
+ genb(0x0f);
+ rbra(dst, jmsw);
+ break;
+ case EQAND:
+ genb(0x0f);
+ rbra(dst, jmsw);
+ gen2(Ojneb, 0);
+ label = code-1;
+ break;
+ }
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Ocmpw, 0, RTMP, RAX);
+ genb(0x0f);
+ rbra(dst, jlsw);
+ if(label != nil)
+ *label = code-label-1;
+}
+
+static void
+cbrab(Inst *i, int jmp)
+{
+ if(RESCHED)
+ schedcheck(i);
+ mid(i, Oldb, RAX);
+ if(UXSRC(i->add) == SRC(AIMM))
+ urk();
+
+ opwld(i, Ocmpb, RAX);
+ genb(0x0f);
+ rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+cbraf(Inst *i, int jmp)
+{
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Omovf, 0);
+ mid(i, 0xdc, 3); // FCOMP
+ genb(0x9b); // FWAIT
+ gen2(0xdf, 0xe0); // FSTSW AX
+ genb(0x9e); // SAHF
+
+ genb(0x0f);
+ rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Oldw, RAX); // v
+ genb(Opushl+RSI);
+ opwst(i, Olea, RSI); // table
+ rbra(macro[MacCASE], Ojmp);
+ }
+
+ 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, Oldw, RAX);
+ cmpl(RAX, (ulong)H);
+ gen2(Ojeqb, 0);
+ mlnil = code - 1;
+ if((i->add&ARM) == AXIMM) {
+ o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame);
+ modrm(Oldw, o, RAX, RTA);
+ } else {
+ gen2(Oldw, (3<<6)|(RTMP<<3)|RAX); // MOVL AX, RTMP
+ mid(i, Oldw, RCX); // index
+ gen2(Olea, (0<<6)|(0<<3)|4); // lea (AX)(RCX*8)
+ genb((3<<6)|(RCX<<3)|RAX); // assumes sizeof(Modl) == 8 hence 3
+ o = OA(Modlink, links)+O(Modl, frame);
+ modrm(Oldw, o, RAX, RTA); // frame
+ genb(OxchgAX+RTMP); // get old AX back
+ }
+ modrm(0x83, O(Type, initialize), RTA, 7);
+ genb(0);
+ gen2(Ojneb, 0);
+ punt = code - 1;
+ genb(OxchgAX+RTA);
+ opwst(i, Olea, RTA);
+ *mlnil = code-mlnil-1;
+ rbra(macro[MacMFRA], Ocall);
+ rbra(patch[i-mod->prog+1], Ojmp);
+
+ *punt = code-punt-1;
+ rbra(macro[MacFRAM], Ocall);
+ opwst(i, Ostw, RCX);
+}
+
+static void
+commcall(Inst *i)
+{
+ uchar *mlnil;
+
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ opwld(i, Oldw, RCX);
+ modrm(Omov, O(Frame, lr), RCX, 0); // MOVL $.+1, lr(CX) f->lr = R.PC
+ genw((ulong)base+patch[i-mod->prog+1]);
+ modrm(Ostw, O(Frame, fp), RCX, RFP); // MOVL RFP, fp(CX) f->fp = R.FP
+ modrm(Oldw, O(REG, M), RTMP, RTA); // MOVL R.M, RTA
+ modrm(Ostw, O(Frame, mr), RCX, RTA); // MOVL RTA, mr(CX) f->mr = R.M
+ opwst(i, Oldw, RTA); // MOVL ml, RTA
+ cmpl(RTA, (ulong)H);
+ gen2(Ojeqb, 0);
+ mlnil = code - 1;
+ if((i->add&ARM) == AXIMM)
+ modrm(Oldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RTA, RAX);
+ else {
+ genb(Opushl+RCX);
+ mid(i, Oldw, RCX); // index
+ gen2(Olea, (0<<6)|(0<<3)|4); // lea (RTA)(RCX*8)
+ genb((3<<6)|(RCX<<3)|RTA); // assumes sizeof(Modl) == 8 hence 3
+ modrm(Oldw, OA(Modlink, links)+O(Modl, u.pc), RAX, RAX);
+ genb(Opopl+RCX);
+ }
+ *mlnil = code-mlnil-1;
+ rbra(macro[MacMCAL], Ocall);
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+ opwld(i, Olea, RTMP);
+ mid(i, Olea, RTA);
+ modrm(Oldw, 0, RTA, RAX); // MOVL 0(RTA), AX
+ modrm(op, 0, RTMP, RAX); // ADDL 0(RTMP), AX
+ modrm(Oldw, 4, RTA, RCX); // MOVL 4(RTA), CX
+ modrm(opc, 4, RTMP, RCX); // ADCL 4(RTMP), CX
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, RTA);
+ modrm(Ostw, 0, RTA, RAX);
+ modrm(Ostw, 4, RTA, RCX);
+}
+
+static void
+shll(Inst *i)
+{
+ uchar *label, *label1;
+
+ opwld(i, Oldw, RCX);
+ mid(i, Olea, RTA);
+ gen2(Otestib, (3<<6)|(0<<3)|RCX);
+ genb(0x20);
+ gen2(Ojneb, 0);
+ label = code-1;
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Oldw, 4, RTA, RBX);
+ genb(0x0f);
+ gen2(Oshld, (3<<6)|(RAX<<3)|RBX);
+ gen2(Oshl, (3<<6)|(4<<3)|RAX);
+ gen2(Ojmpb, 0);
+ label1 = code-1;
+ *label = code-label-1;
+ modrm(Oldw, 0, RTA, RBX);
+ con(0, RAX);
+ gen2(Oshl, (3<<6)|(4<<3)|RBX);
+ *label1 = code-label1-1;
+ opwst(i, Olea, RTA);
+ modrm(Ostw, 0, RTA, RAX);
+ modrm(Ostw, 4, RTA, RBX);
+}
+
+static void
+shrl(Inst *i)
+{
+ uchar *label, *label1;
+
+ opwld(i, Oldw, RCX);
+ mid(i, Olea, RTA);
+ gen2(Otestib, (3<<6)|(0<<3)|RCX);
+ genb(0x20);
+ gen2(Ojneb, 0);
+ label = code-1;
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Oldw, 4, RTA, RBX);
+ genb(0x0f);
+ gen2(Oshrd, (3<<6)|(RBX<<3)|RAX);
+ gen2(Osar, (3<<6)|(7<<3)|RBX);
+ gen2(Ojmpb, 0);
+ label1 = code-1;
+ *label = code-label-1;
+ modrm(Oldw, 4, RTA, RBX);
+ gen2(Oldw, (3<<6)|(RAX<<3)|RBX);
+ gen2(Osarimm, (3<<6)|(7<<3)|RBX);
+ genb(0x1f);
+ gen2(Osar, (3<<6)|(7<<3)|RAX);
+ *label1 = code-label1-1;
+ opwst(i, Olea, RTA);
+ modrm(Ostw, 0, RTA, RAX);
+ modrm(Ostw, 4, RTA, RBX);
+}
+
+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 IMNEWZ:
+ case ILSRW:
+ case ILSRL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ case IHEADL:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTLC:
+ case ICVTCL:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTRF:
+ case ICVTFR:
+ case ICVTWS:
+ case ICVTSW:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ 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:
+ opwld(i, Oldb, RAX);
+ genb(0x0f);
+ gen2(0xb6, (3<<6)|(RAX<<3)|RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ICVTWB:
+ opwld(i, Oldw, RAX);
+ opwst(i, Ostb, RAX);
+ break;
+ case ICVTFW:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, Omovf, 0);
+ opwst(i, 0xdb, 3);
+ break;
+ case ICVTWF:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, 0xdb, 0);
+ opwst(i, Omovf, 3);
+ break;
+ case ICVTLF:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, 0xdf, 5);
+ opwst(i, Omovf, 3);
+ break;
+ case ICVTFL:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, Omovf, 0);
+ opwst(i, 0xdf, 7);
+ break;
+ case IHEADM:
+ opwld(i, Oldw, RAX);
+ modrm(Olea, OA(List, data), RAX, RAX);
+ goto movm;
+ case IMOVM:
+ opwld(i, Olea, RAX);
+ movm:
+ opwst(i, Olea, RBX);
+ mid(i, Oldw, RCX);
+ genb(OxchgAX+RSI);
+ gen2(Oxchg, (3<<6)|(RDI<<3)|RBX);
+ genb(Ocld);
+ gen2(Orep, Omovsb);
+ genb(OxchgAX+RSI);
+ gen2(Oxchg, (3<<6)|(RDI<<3)|RBX);
+ break;
+ case IRET:
+ rbra(macro[MacRET], Ojmp);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ con((ulong)mod->type[i->s.imm], RTA);
+ rbra(macro[MacFRAM], Ocall);
+ opwst(i, Ostw, RCX);
+ break;
+ case ILEA:
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ gen2(Ojmpb, 4);
+ genw(i->s.imm);
+ con((ulong)(code-4), RAX);
+ }
+ else
+ opwld(i, Olea, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case IHEADW:
+ opwld(i, Oldw, RAX);
+ modrm(Oldw, OA(List, data), RAX, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case IHEADF:
+ opwld(i, Oldw, RAX);
+ modrm(Omovf, OA(List, data), RAX, 0);
+ opwst(i, Omovf, 3);
+ break;
+ case IHEADB:
+ opwld(i, Oldw, RAX);
+ modrm(Oldb, OA(List, data), RAX, RAX);
+ opwst(i, Ostb, RAX);
+ break;
+ case ITAIL:
+ opwld(i, Oldw, RAX);
+ modrm(Oldw, O(List, tail), RAX, RBX);
+ goto movp;
+ case IMOVP:
+ case IHEADP:
+ opwld(i, Oldw, RBX);
+ if(i->op == IHEADP)
+ modrm(Oldw, OA(List, data), RBX, RBX);
+ movp:
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x05);
+ rbra(macro[MacCOLR], Ocall);
+ opwst(i, Oldw, RAX);
+ opwst(i, Ostw, RBX);
+ rbra(macro[MacFRP], Ocall);
+ break;
+ case ILENA:
+ opwld(i, Oldw, RBX);
+ con(0, RAX);
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x02);
+ modrm(Oldw, O(Array, len), RBX, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ILENC:
+ opwld(i, Oldw, RBX);
+ con(0, RAX);
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x09);
+ modrm(Oldw, O(String, len), RBX, RAX);
+ cmpl(RAX, 0);
+ gen2(Ojgeb, 0x02);
+ gen2(Oneg, (3<<6)|(3<<3)|RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ILENL:
+ con(0, RAX);
+ opwld(i, Oldw, RBX);
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x05);
+ modrm(Oldw, O(List, tail), RBX, RBX);
+ genb(Oincr+RAX);
+ gen2(Ojmpb, 0xf6);
+ opwst(i, Ostw, RAX);
+ break;
+ case IBEQF:
+ cbraf(i, Ojeql);
+ break;
+ case IBNEF:
+ cbraf(i, Ojnel);
+ break;
+ case IBLEF:
+ cbraf(i, Ojlsl);
+ break;
+ case IBLTF:
+ cbraf(i, Ojcsl);
+ break;
+ case IBGEF:
+ cbraf(i, Ojccl);
+ break;
+ case IBGTF:
+ cbraf(i, Ojhil);
+ break;
+ case IBEQW:
+ cbra(i, Ojeql);
+ break;
+ case IBLEW:
+ cbra(i, Ojlel);
+ break;
+ case IBNEW:
+ cbra(i, Ojnel);
+ break;
+ case IBGTW:
+ cbra(i, Ojgtl);
+ break;
+ case IBLTW:
+ cbra(i, Ojltl);
+ break;
+ case IBGEW:
+ cbra(i, Ojgel);
+ break;
+ case IBEQB:
+ cbrab(i, Ojeql);
+ break;
+ case IBLEB:
+ cbrab(i, Ojlsl);
+ break;
+ case IBNEB:
+ cbrab(i, Ojnel);
+ break;
+ case IBGTB:
+ cbrab(i, Ojhil);
+ break;
+ case IBLTB:
+ cbrab(i, Ojbl);
+ break;
+ case IBGEB:
+ cbrab(i, Ojael);
+ break;
+ case ISUBW:
+ arith(i, 0x29, 5);
+ break;
+ case ISUBB:
+ arithb(i, 0x28);
+ break;
+ case ISUBF:
+ arithf(i, 5);
+ break;
+ case IADDW:
+ arith(i, 0x01, 0);
+ break;
+ case IADDB:
+ arithb(i, 0x00);
+ break;
+ case IADDF:
+ arithf(i, 0);
+ break;
+ case IORW:
+ arith(i, 0x09, 1);
+ break;
+ case IORB:
+ arithb(i, 0x08);
+ break;
+ case IANDW:
+ arith(i, 0x21, 4);
+ break;
+ case IANDB:
+ arithb(i, 0x20);
+ break;
+ case IXORW:
+ arith(i, Oxor, 6);
+ break;
+ case IXORB:
+ arithb(i, 0x30);
+ break;
+ case ISHLW:
+ shift(i, Oldw, Ostw, 0xd3, 4);
+ break;
+ case ISHLB:
+ shift(i, Oldb, Ostb, 0xd2, 4);
+ break;
+ case ISHRW:
+ shift(i, Oldw, Ostw, 0xd3, 7);
+ break;
+ case ISHRB:
+ shift(i, Oldb, Ostb, 0xd2, 5);
+ break;
+ case IMOVF:
+ opwld(i, Omovf, 0);
+ opwst(i, Omovf, 3);
+ break;
+ case INEGF:
+ opwld(i, Omovf, 0);
+ genb(0xd9);
+ genb(0xe0);
+ opwst(i, Omovf, 3);
+ break;
+ case IMOVB:
+ opwld(i, Oldb, RAX);
+ opwst(i, Ostb, RAX);
+ break;
+ case IMOVW:
+ case ICVTLW: // Little endian
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ opwst(i, Omov, RAX);
+ genw(i->s.imm);
+ break;
+ }
+ opwld(i, Oldw, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ICVTWL:
+ opwst(i, Olea, RTMP);
+ opwld(i, Oldw, RAX);
+ modrm(Ostw, 0, RTMP, RAX);
+ genb(0x99);
+ modrm(Ostw, 4, RTMP, RDX);
+ break;
+ case ICALL:
+ if(UXDST(i->add) != DST(AIMM))
+ opwst(i, Oldw, RTA);
+ opwld(i, Oldw, RAX);
+ modrm(Omov, O(Frame, lr), RAX, 0); // MOVL $.+1, lr(AX)
+ genw((ulong)base+patch[i-mod->prog+1]);
+ modrm(Ostw, O(Frame, fp), RAX, RFP); // MOVL RFP, fp(AX)
+ gen2(Oldw, (3<<6)|(RFP<<3)|RAX); // MOVL AX,RFP
+ if(UXDST(i->add) != DST(AIMM)){
+ gen2(Ojmprm, (3<<6)|(4<<3)|RTA);
+ break;
+ }
+ /* no break */
+ case IJMP:
+ if(RESCHED)
+ schedcheck(i);
+ rbra(patch[i->d.ins-mod->prog], Ojmp);
+ break;
+ case IMOVPC:
+ opwst(i, Omov, RAX);
+ genw(patch[i->s.imm]+(ulong)base);
+ break;
+ case IGOTO:
+ opwst(i, Olea, RBX);
+ opwld(i, Oldw, RAX);
+ gen2(Ojmprm, (0<<6)|(4<<3)|4);
+ genb((2<<6)|(RAX<<3)|RBX);
+
+ 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:
+ arithf(i, 1);
+ break;
+ case IDIVF:
+ arithf(i, 7);
+ break;
+ case IMODW:
+ case IDIVW:
+ case IMULW:
+ mid(i, Oldw, RAX);
+ opwld(i, Oldw, RTMP);
+ if(i->op == IMULW)
+ gen2(0xf7, (3<<6)|(4<<3)|RTMP);
+ else {
+ genb(Ocdq);
+ gen2(0xf7, (3<<6)|(7<<3)|RTMP); // IDIV AX, RTMP
+ if(i->op == IMODW)
+ genb(0x90+RDX); // XCHG AX, DX
+ }
+ opwst(i, Ostw, RAX);
+ break;
+ case IMODB:
+ case IDIVB:
+ case IMULB:
+ mid(i, Oldb, RAX);
+ opwld(i, Oldb, RTMP);
+ if(i->op == IMULB)
+ gen2(0xf6, (3<<6)|(4<<3)|RTMP);
+ else {
+ genb(Ocdq);
+ gen2(0xf6, (3<<6)|(7<<3)|RTMP); // IDIV AX, RTMP
+ if(i->op == IMODB)
+ genb(0x90+RDX); // XCHG AX, DX
+ }
+ opwst(i, Ostb, RAX);
+ break;
+ case IINDX:
+ opwld(i, Oldw, RTMP); // MOVW xx(s), BX
+
+ if(bflag){
+ opwst(i, Oldw, RAX);
+ modrm(0x3b, O(Array, len), RTMP, RAX); /* CMP index, len */
+ gen2(0x72, 5); /* JB */
+ bra((ulong)bounds, Ocall);
+ modrm(Oldw, O(Array, t), RTMP, RTA);
+ modrm(0xf7, O(Type, size), RTA, 5); /* IMULL AX, xx(t) */
+ }
+ else{
+ modrm(Oldw, O(Array, t), RTMP, RAX); // MOVW t(BX), AX
+ modrm(Oldw, O(Type, size), RAX, RAX); // MOVW size(AX), AX
+ if(UXDST(i->add) == DST(AIMM)) {
+ gen2(0x69, (3<<6)|(RAX<<3)|0);
+ genw(i->d.imm);
+ }
+ else
+ opwst(i, 0xf7, 5); // IMULL AX,xx(d)
+ }
+
+ modrm(0x03, O(Array, data), RBX, RAX); // ADDL data(BX), AX
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ modrm(Ostw, i->reg, r, RAX);
+ break;
+ case IINDB:
+ r = 0;
+ goto idx;
+ case IINDF:
+ case IINDL:
+ r = 3;
+ goto idx;
+ case IINDW:
+ r = 2;
+ idx:
+ opwld(i, Oldw, RAX);
+ opwst(i, Oldw, RTMP);
+ if(bflag){
+ modrm(0x3b, O(Array, len), RAX, RTMP); /* CMP index, len */
+ gen2(0x72, 5); /* JB */
+ bra((ulong)bounds, Ocall);
+ }
+ modrm(Oldw, O(Array, data), RAX, RAX);
+ gen2(Olea, (0<<6)|(0<<3)|4); /* lea (AX)(RTMP*r) */
+ genb((r<<6)|(RTMP<<3)|RAX);
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ modrm(Ostw, i->reg, r, RAX);
+ break;
+ case IINDC:
+ opwld(i, Oldw, RAX); // string
+ mid(i, Oldw, RBX); // index
+ if(bflag){
+ modrm(Oldw, O(String, len), RAX, RTA);
+ cmpl(RTA, 0);
+ gen2(Ojltb, 16);
+ gen2(0x3b, (3<<6)|(RBX<<3)|RTA); /* cmp index, len */
+ gen2(0x72, 5); /* JB */
+ bra((ulong)bounds, Ocall);
+ genb(0x0f);
+ gen2(Omovzxb, (1<<6)|(0<<3)|4);
+ gen2((0<<6)|(RBX<<3)|RAX, O(String, data));
+ gen2(Ojmpb, 11);
+ gen2(Oneg, (3<<6)|(3<<3)|RTA);
+ gen2(0x3b, (3<<6)|(RBX<<3)|RTA); /* cmp index, len */
+ gen2(0x73, 0xee); /* JNB */
+ genb(0x0f);
+ gen2(Omovzxw, (1<<6)|(0<<3)|4);
+ gen2((1<<6)|(RBX<<3)|RAX, O(String, data));
+ opwst(i, Ostw, RAX);
+ break;
+ }
+ modrm(Ocmpi, O(String, len), RAX, 7);
+ genb(0);
+ gen2(Ojltb, 7);
+ genb(0x0f);
+ gen2(Omovzxb, (1<<6)|(0<<3)|4); /* movzbx 12(AX)(RBX*1), RAX */
+ gen2((0<<6)|(RBX<<3)|RAX, O(String, data));
+ gen2(Ojmpb, 5);
+ genb(0x0f);
+ gen2(Omovzxw, (1<<6)|(0<<3)|4); /* movzwx 12(AX)(RBX*4), RAX */
+ gen2((1<<6)|(RBX<<3)|RAX, O(String, data));
+ opwst(i, Ostw, RAX);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ break;
+ case IMOVL:
+ opwld(i, Olea, RTA);
+ opwst(i, Olea, RTMP);
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Ostw, 0, RTMP, RAX);
+ modrm(Oldw, 4, RTA, RAX);
+ modrm(Ostw, 4, RTMP, RAX);
+ break;
+ case IADDL:
+ larith(i, 0x03, 0x13);
+ break;
+ case ISUBL:
+ larith(i, 0x2b, 0x1b);
+ break;
+ case IORL:
+ larith(i, 0x0b, 0x0b);
+ break;
+ case IANDL:
+ larith(i, 0x23, 0x23);
+ break;
+ case IXORL:
+ larith(i, 0x33, 0x33);
+ break;
+ case IBEQL:
+ cbral(i, Ojnel, Ojeql, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Ojnel, Ojnel, OROR);
+ break;
+ case IBLEL:
+ cbral(i, Ojltl, Ojbel, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, Ojgtl, Ojal, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, Ojltl, Ojbl, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, Ojgtl, Ojael, 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)
+{
+ if(comvec)
+ return;
+
+ comvec = malloc(32);
+ if(comvec == nil)
+ error(exNomem);
+ code = (uchar*)comvec;
+
+ genb(Opushl+RBX);
+ genb(Opushl+RCX);
+ genb(Opushl+RDX);
+ genb(Opushl+RSI);
+ genb(Opushl+RDI);
+ con((ulong)&R, RTMP);
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+ modrm(Ojmprm, O(REG, PC), RTMP, 4);
+}
+
+static void
+maccase(void)
+{
+ uchar *loop, *def, *lab1;
+
+ modrm(Oldw, 0, RSI, RDX); // n = t[0]
+ modrm(Olea, 4, RSI, RSI); // t = &t[1]
+ gen2(Oldw, (3<<6)|(RBX<<3)|RDX); // MOVL DX, BX
+ gen2(Oshr, (3<<6)|(4<<3)|RBX); // SHL BX,1
+ gen2(0x01, (3<<6)|(RDX<<3)|RBX); // ADDL DX, BX BX = n*3
+ gen2(Opushrm, (0<<6)|(6<<3)|4);
+ genb((2<<6)|(RBX<<3)|RSI); // PUSHL 0(SI)(BX*4)
+ loop = code;
+ cmpl(RDX, 0);
+ gen2(Ojleb, 0);
+ def = code-1;
+ gen2(Oldw, (3<<6)|(RCX<<3)|RDX); // MOVL DX, CX n2 = n
+ gen2(Oshr, (3<<6)|(5<<3)|RCX); // SHR CX,1 n2 = n2>>1
+ gen2(Oldw, (3<<6)|(RBX<<3)|RCX); // MOVL CX, BX
+ gen2(Oshr, (3<<6)|(4<<3)|RBX); // SHL BX,1
+ gen2(0x01, (3<<6)|(RCX<<3)|RBX); // ADDL CX, BX BX = n2*3
+ gen2(0x3b, (0<<6)|(RAX<<3)|4);
+ genb((2<<6)|(RBX<<3)|RSI); // CMPL AX, 0(SI)(BX*4)
+ gen2(Ojgeb, 0); // JGE lab1
+ lab1 = code-1;
+ gen2(Oldw, (3<<6)|(RDX<<3)|RCX);
+ gen2(Ojmpb, loop-code-2);
+ *lab1 = code-lab1-1; // lab1:
+ gen2(0x3b, (1<<6)|(RAX<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RSI, 4); // CMPL AX, 4(SI)(BX*4)
+ gen2(Ojltb, 0);
+ lab1 = code-1;
+ gen2(Olea, (1<<6)|(RSI<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RSI, 12); // LEA 12(SI)(RBX*4), RSI
+ gen2(0x2b, (3<<6)|(RDX<<3)|RCX); // SUBL CX, DX n -= n2
+ gen2(Odecrm, (3<<6)|(1<<3)|RDX); // DECL DX n -= 1
+ gen2(Ojmpb, loop-code-2);
+ *lab1 = code-lab1-1; // lab1:
+ gen2(Oldw, (1<<6)|(RAX<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RSI, 8); // MOVL 8(SI)(BX*4), AX
+ genb(Opopl+RSI); // ditch default
+ genb(Opopl+RSI);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX); // JMP*L AX
+ *def = code-def-1; // def:
+ genb(Opopl+RAX); // ditch default
+ genb(Opopl+RSI);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX);
+}
+
+static void
+macfrp(void)
+{
+ cmpl(RAX, (ulong)H); // CMPL AX, $H
+ gen2(Ojneb, 0x01); // JNE .+1
+ genb(Oret); // RET
+ modrm(0x83, O(Heap, ref)-sizeof(Heap), RAX, 7);
+ genb(0x01); // CMP AX.ref, $1
+ gen2(Ojeqb, 0x04); // JNE .+4
+ modrm(Odecrm, O(Heap, ref)-sizeof(Heap), RAX, 1);
+ genb(Oret); // DEC AX.ref
+ // RET
+ con((ulong)&R, RTMP); // MOV $R, RTMP
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ modrm(Ostw, O(REG, s), RTMP, RAX); // MOVL RAX, R.s
+ bra((ulong)rdestroy, Ocall); // CALL rdestroy
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, FP), RTMP, RFP); // MOVL R.MP, RMP
+ modrm(Oldw, O(REG, MP), RTMP, RMP); // MOVL R.FP, RFP
+ genb(Oret);
+}
+
+static void
+macret(void)
+{
+ Inst i;
+ uchar *s;
+ static ulong lpunt, lnomr, lfrmr, linterp;
+
+ s = code;
+
+ lpunt -= 2;
+ lnomr -= 2;
+ lfrmr -= 2;
+ linterp -= 2;
+
+ con(0, RBX); // MOVL $0, RBX
+ modrm(Oldw, O(Frame, t), RFP, RAX); // MOVL t(FP), RAX
+ gen2(Ocmpw, (3<<6)|(RAX<<3)|RBX); // CMPL RAX, RBX
+ gen2(Ojeqb, lpunt-(code-s)); // JEQ lpunt
+ modrm(Oldw, O(Type, destroy), RAX, RAX);// MOVL destroy(RAX), RAX
+ gen2(Ocmpw, (3<<6)|(RAX<<3)|RBX); // CMPL RAX, RBX
+ gen2(Ojeqb, lpunt-(code-s)); // JEQ lpunt
+ modrm(Ocmpw, O(Frame, fp), RFP, RBX); // CMPL fp(FP), RBX
+ gen2(Ojeqb, lpunt-(code-s)); // JEQ lpunt
+ modrm(Ocmpw, O(Frame, mr), RFP, RBX); // CMPL mr(FP), RBX
+ gen2(Ojeqb, lnomr-(code-s)); // JEQ lnomr
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, M), RTMP, RTA); // MOVL R.M, RTA
+ modrm(Odecrm, O(Heap, ref)-sizeof(Heap), RTA, 1);
+ gen2(Ojneb, lfrmr-(code-s)); // JNE lfrmr
+ modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RTA, 0);
+ gen2(Ojmpb, lpunt-(code-s)); // JMP lpunt
+ lfrmr = code - s;
+ modrm(Oldw, O(Frame, mr), RFP, RTA); // MOVL mr(FP), RTA
+ modrm(Ostw, O(REG, M), RTMP, RTA); // MOVL RTA, R.M
+ modrm(Oldw, O(Modlink, MP), RTA, RMP); // MOVL MP(RTA), RMP
+ modrm(Ostw, O(REG, MP), RTMP, RMP); // MOVL RMP, R.MP
+ modrm(Ocmpi, O(Modlink, compiled), RTA, 7);// CMPL $0, M.compiled
+ genb(0x00);
+ gen2(Ojeqb, linterp-(code-s)); // JEQ linterp
+ lnomr = code - s;
+ gen2(Ocallrm, (3<<6)|(2<<3)|RAX); // CALL* AX
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Ostw, O(REG, SP), RTMP, RFP); // MOVL RFP, R.SP
+ modrm(Oldw, O(Frame, lr), RFP, RAX); // MOVL lr(RFP), RAX
+ modrm(Oldw, O(Frame, fp), RFP, RFP); // MOVL fp(RFP), RFP
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX); // JMP*L AX
+
+ linterp = code - s; // return to uncompiled code
+ gen2(Ocallrm, (3<<6)|(2<<3)|RAX); // CALL* AX
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Ostw, O(REG, SP), RTMP, RFP); // MOVL RFP, R.SP
+ modrm(Oldw, O(Frame, lr), RFP, RAX); // MOVL lr(RFP), RAX
+ modrm(Ostw, O(REG, PC), RTMP, RAX); // MOVL RAX, R.PC
+ modrm(Oldw, O(Frame, fp), RFP, RFP); // MOVL fp(RFP), RFP
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ genb(Opopl+RDI); // return to uncompiled code
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+ // label:
+ lpunt = code - s;
+
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccolr(void)
+{
+ modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RBX, 0);
+ gen2(Oldw, (0<<6)|(RAX<<3)|5); // INCL ref(BX)
+ genw((ulong)&mutator); // MOVL mutator, RAX
+ modrm(Ocmpw, O(Heap, color)-sizeof(Heap), RBX, RAX);
+ gen2(Ojneb, 0x01); // CMPL color(BX), RAX
+ genb(Oret); // MOVL $propagator,RTMP
+ con(propagator, RAX); // MOVL RTMP, color(BX)
+ modrm(Ostw, O(Heap, color)-sizeof(Heap), RBX, RAX);
+ gen2(Ostw, (0<<6)|(RAX<<3)|5); // can be any !0 value
+ genw((ulong)&nprop); // MOVL RBX, nprop
+ genb(Oret);
+}
+
+static void
+macmcal(void)
+{
+ uchar *label, *mlnil, *interp;
+
+ cmpl(RAX, (ulong)H);
+ gen2(Ojeqb, 0);
+ mlnil = code - 1;
+ modrm(0x83, O(Modlink, prog), RTA, 7); // CMPL $0, ml->prog
+ genb(0x00);
+ gen2(Ojneb, 0); // JNE patch
+ label = code-1;
+ *mlnil = code-mlnil-1;
+ modrm(Ostw, O(REG, FP), RTMP, RCX);
+ modrm(Ostw, O(REG, dt), RTMP, RAX);
+ bra((ulong)rmcall, Ocall); // CALL rmcall
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+ genb(Oret); // RET
+ *label = code-label-1; // patch:
+ gen2(Oldw, (3<<6)|(RFP<<3)|RCX); // MOVL CX, RFP R.FP = f
+ modrm(Ostw, O(REG, M), RTMP, RTA); // MOVL RTA, R.M
+ modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RTA, 0);
+ modrm(Oldw, O(Modlink, MP), RTA, RMP); // MOVL R.M->mp, RMP
+ modrm(Ostw, O(REG, MP), RTMP, RMP); // MOVL RMP, R.MP R.MP = ml->MP
+ modrm(Ocmpi, O(Modlink, compiled), RTA, 7);// CMPL $0, M.compiled
+ genb(0x00);
+ genb(Opopl+RTA); // balance call
+ gen2(Ojeqb, 0); // JEQ interp
+ interp = code-1;
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX); // JMP*L AX
+ *interp = code-interp-1; // interp:
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL FP, R.FP
+ modrm(Ostw, O(REG, PC), RTMP, RAX); // MOVL PC, R.PC
+ genb(Opopl+RDI); // call to uncompiled code
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+}
+
+static void
+macfram(void)
+{
+ uchar *label;
+
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, SP), RTMP, RAX); // MOVL R.SP, AX
+ modrm(0x03, O(Type, size), RTA, RAX); // ADDL size(RCX), RAX
+ modrm(0x3b, O(REG, TS), RTMP, RAX); // CMPL AX, R.TS
+ gen2(0x7c, 0x00); // JL .+(patch)
+ label = code-1;
+
+ modrm(Ostw, O(REG, s), RTMP, RTA);
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ bra((ulong)extend, Ocall); // CALL extend
+ con((ulong)&R, RTMP);
+ modrm(Oldw, O(REG, FP), RTMP, RFP); // MOVL R.MP, RMP
+ modrm(Oldw, O(REG, MP), RTMP, RMP); // MOVL R.FP, RFP
+ modrm(Oldw, O(REG, s), RTMP, RCX); // MOVL R.s, *R.d
+ genb(Oret); // RET
+ *label = code-label-1;
+ modrm(Oldw, O(REG, SP), RTMP, RCX); // MOVL R.SP, CX
+ modrm(Ostw, O(REG, SP), RTMP, RAX); // MOVL AX, R.SP
+
+ modrm(Ostw, O(Frame, t), RCX, RTA); // MOVL RTA, t(CX) f->t = t
+ modrm(Omov, REGMOD*4, RCX, 0); // MOVL $0, mr(CX) f->mr
+ genw(0);
+ modrm(Oldw, O(Type, initialize), RTA, RTA);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RTA); // JMP*L RTA
+ genb(Oret); // RET
+}
+
+static void
+macmfra(void)
+{
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Ostw, O(REG, FP), RTMP, RFP);
+ modrm(Ostw, O(REG, s), RTMP, RAX); // Save type
+ modrm(Ostw, O(REG, d), RTMP, RTA); // Save destination
+ bra((ulong)rmfram, Ocall); // CALL rmfram
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+ genb(Oret); // RET
+}
+
+static void
+macrelq(void)
+{
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL FP, R.FP
+ genb(Opopl+RAX);
+ modrm(Ostw, O(REG, PC), RTMP, RAX); // MOVL PC, R.PC
+ genb(Opopl+RDI);
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+}
+
+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(Oldw, j, RFP, RAX);
+ rbra(macro[MacFRP], Ocall);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ genb(Oret);
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ con((ulong)H, RAX);
+ 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(Ostw, j, RCX, RAX);
+ j += sizeof(WORD*);
+ }
+ }
+ genb(Oret);
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ uchar *tmp;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096*sizeof(uchar), 0);
+ if(tmp == nil)
+ error(exNomem);
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ if(cflag > 3)
+ print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n",
+ (ulong)t, t->size, (ulong)t->initialize, (ulong)t->destroy, n);
+}
+
+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;
+ Modl *e;
+ Link *l;
+ int i, n;
+ uchar *s, *tmp;
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ tmp = mallocz(4096*sizeof(uchar),0);
+ 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]);
+ 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;
+ }
+
+ n = (n+3)&~3;
+
+ nlit *= sizeof(ulong);
+ base = mallocz(n + nlit, 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 3)
+ print("dis=%5d %5d 386=%5d asm=%.8lux lit=%d: %s\n",
+ size, size*sizeof(Inst), n, (ulong)base, nlit, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = (ulong*)(base+n);
+ code = base;
+
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(cflag > 4) {
+ print("%D\n", &m->prog[i]);
+ das(s, code-s);
+ }
+ }
+
+ for(i = 0; i < nelem(mactab); i++)
+ mactab[i].gen();
+
+ v = (ulong)base;
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)(v+patch[l->u.pc-m->prog]);
+ 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;
+ return 1;
+bad:
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(base);
+ return 0;
+}
+