#include "lib9.h" #include "isa.h" #include "interp.h" enum { R0 = 0, R1 = 1, R2 = 2, R3 = 3, R4 = 4, R5 = 5, R6 = 6, R7 = 7, R8 = 8, R9 = 9, R10 = 10, R11 = 11, R12 = 12, R13 = 13, R14 = 14, /* Link Register */ R15 = 15, /* PC */ RLINK = 14, RFP = R13, /* Frame Pointer */ RMP = R12, /* Module Pointer */ RTA = R11, /* Intermediate address for double indirect */ RREG = R10, /* Pointer to REG */ RA3 = R9, /* gpr 3 */ RA2 = R8, /* gpr 2 2+3 = L */ RA1 = R7, /* gpr 1 */ RA0 = R6, /* gpr 0 0+1 = L */ RCON = R8, /* Constant builder */ FA2 = 2, /* Floating */ FA3 = 3, FA4 = 4, FA5 = 5, EQ = 0, NE = 1, CS = 2, CC = 3, MI = 4, PL = 5, VS = 6, VC = 7, HI = 8, LS = 9, GE = 10, LT = 11, GT = 12, LE = 13, AL = 14, NV = 15, And = 0, Eor = 1, Sub = 2, Rsb = 3, Add = 4, Adc = 5, Sbc = 6, Rsc = 7, Tst = 8, Teq = 9, Cmp = 10, Cmn = 11, Orr = 12, Mov = 13, Bic = 14, Mvn = 15, Lea = 100, /* macro memory ops */ Ldw, Ldb, Stw, Stb, NCON = 20, 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 }; #define BITS(B) (1<>2) #define BRAMAC(r, o) BRA(r, (IA(macro, o)-(ulong)code)>>2); #define CALL(o) BRA(AL, (ulong*)o-code)|(1<<24) #define CALLMAC(o) BRAMAC(AL,o)|(1<<24) #define RELPC(pc) (ulong)(base+pc) #define RETURN DPI(AL, Add, RLINK, R15, 0, 0) #define PATCH(ptr) *ptr |= (code-ptr) & 0x00ffffff #define MOV(src, dst) DP(AL, Mov, 0, dst, 0, src) extern char Tmodule[]; static ulong* code; static ulong* base; static ulong* patch; static int pass; static int puntpc = 1; static Module* mod; static uchar* tinit; 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(ulong*, int); #define T(r) *((void**)(R.r)) struct { int idx; void (*gen)(void); char* name; } mactab[] = { MacFRP, macfrp, "FRP", /* decrement and free pointer */ MacRET, macret, "RET", /* return instruction */ MacCASE, maccase, "CASE", /* case instruction */ MacCOLR, maccolr, "COLR", /* increment and color pointer */ MacMCAL, macmcal, "MCAL", /* mcall bottom half */ MacFRAM, macfram, "FRAM", /* frame instruction */ MacMFRA, macmfra, "MFRA", /* punt mframe because t->initialize==0 */ }; typedef struct Const Const; struct Const { ulong o; ulong* code; }; typedef struct Con Con; struct Con { int ptr; Const table[NCON]; }; static Con rcon; static void rdestroy(void) { destroy(R.s); } static void rmcall(void) { Frame *f; f = (Frame*)R.FP; if(f == H) error(Tmodule); f->mr = nil; ((void(*)(Frame*))R.dt)(f); R.SP = (uchar*)f; R.FP = f->fp; if(f->t == nil) { unextend(f); return; } freeptrs(f, f->t); if(currun()->kill) error(""); } 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 void urk(void) { error("compile failed"); } static void flushcon(void) { int i; Const *c; ulong disp; c = &rcon.table[0]; for(i = 0; i < rcon.ptr; i++) { disp = (code - c->code) * sizeof(*code); if(disp >= BITS(12)) error("constant range"); *code = c->o; *c->code |= disp; c++; } rcon.ptr = 0; } static void con(ulong o, int r, int opt) { ulong u; Const *c; if(opt != 0) { u = o & ~0xff; if(u == 0) { DPI(AL, Mov, 0, r, 0, o); return; } if(u == ~0xff) { DPI(AL, Mvn, 0, r, 0, ~o); return; } } c = &rcon.table[rcon.ptr++]; if(rcon.ptr >= NCON) error("constant table overflow"); c->o = o; c->code = code; LDW(AL, R15, r, 0); } static void mem(int inst, ulong disp, int rm, int r) { if(inst == Lea) { if(disp < BITS(8)) { DPI(AL, Add, rm, r, 0, disp); return; } con(disp, RCON, 1); DP(AL, Add, rm, r, 0, RCON); return; } if(disp < BITS(12)) { /* Direct load */ switch(inst) { case Ldw: LDW(AL, rm, r, disp); break; case Ldb: LDB(AL, rm, r, disp); break; case Stw: STW(AL, rm, r, disp); break; case Stb: STB(AL, rm, r, disp); break; } return; } con(disp, RCON, 1); switch(inst) { case Ldw: LDRW(AL, rm, r, 0, RCON); break; case Ldb: LDRB(AL, rm, r, 0, RCON); break; case Stw: STRW(AL, rm, r, 0, RCON); break; case Stb: STRB(AL, rm, r, 0, RCON); break; } } 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): mem(mi, i->s.ind, RFP, r); return; case SRC(AMP): mem(mi, i->s.ind, RMP, r); return; case SRC(AIMM): con(i->s.imm, r, 1); if(mi == Lea) { mem(Stw, O(REG, st), RREG, r); con((ulong)&R.st, r, 1); } return; case SRC(AIND|AFP): ir = RFP; break; case SRC(AIND|AMP): ir = RMP; break; } rta = RTA; if(mi == Lea) rta = r; mem(Ldw, i->s.i.f, ir, rta); mem(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, 1); return; case DST(AFP): mem(mi, i->d.ind, RFP, r); return; case DST(AMP): mem(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 == Lea) rta = r; mem(Ldw, i->d.i.f, ir, rta); mem(mi, i->d.i.s, rta, r); } static void opfl(Adr *a, int am, int mi, int r) { int ir; switch(am) { default: urk(); case AFP: mem(mi, a->ind, RFP, r); mem(mi, a->ind+4, RFP, r+1); return; case AMP: mem(mi, a->ind, RMP, r); mem(mi, a->ind+4, RMP, r+1); return; case AIND|AFP: ir = RFP; break; case AIND|AMP: ir = RMP; break; } mem(Ldw, a->i.f, ir, RTA); mem(mi, a->i.s, RTA, r); mem(mi, a->i.s+4, RTA, r+1); } static void opflld(Inst *i, int mi, int r) { opfl(&i->s, USRC(i->add), mi, r); } static void opflst(Inst *i, int mi, int r) { opfl(&i->d, UDST(i->add), mi, r); } static void puntimm(ulong imm, int ot, ulong oo, int opt) { con(imm, RA0, opt); mem(Stw, ot, RREG, RA0); con((ulong)&R + ot, RA0, 1); mem(Stw, oo, RREG, RA0); } static void punt(Inst *i, int m, void (*fn)(void)) { ulong pc; if(m & SRCOP) { if(UXSRC(i->add) == SRC(AIMM)) puntimm(i->s.imm, O(REG, st), O(REG, s), puntpc); else { opwld(i, Lea, RA0); mem(Stw, O(REG, s), RREG, RA0); } } if(m & DSTOP) { opwst(i, Lea, RA0); mem(Stw, O(REG, d), RREG, RA0); } if(m & WRTPC) { con(RELPC(patch[i-mod->prog+1]), RA0, 0); mem(Stw, O(REG, PC), RREG, RA0); } if(m & DBRAN) { if(i->op == ISPAWN) pc = patch[(Inst*)i->d.imm-mod->prog]; else pc = patch[(Inst*)i->d.imm-mod->prog+1]; puntimm(RELPC(pc), O(REG, dt), O(REG, d), 0); } switch(i->add&ARM) { case AXNON: if(m & THREOP) { mem(Ldw, O(REG, d), RREG, RA0); mem(Stw, O(REG, m), RREG, RA0); } break; case AXIMM: puntimm((short)i->reg, O(REG, t), O(REG, m), 1); break; case AXINF: mem(Lea, i->reg, RFP, RA0); mem(Stw, O(REG, m), RREG, RA0); break; case AXINM: mem(Lea, i->reg, RMP, RA0); mem(Stw, O(REG, m), RREG, RA0); break; } CALL(fn); mem(Stw, O(REG, FP), RREG, RFP); con((ulong)&R, RREG, 1); if(m & TCHECK) { mem(Ldw, O(REG, t), RREG, RA0); DPI(AL, Cmp, RA0, 0, 0, 0); BRA(EQ, 1); mem(Ldw, O(REG, xpc), RREG, RLINK); RETURN; } mem(Ldw, O(REG, FP), RREG, RFP); mem(Ldw, O(REG, MP), RREG, RMP); if(m & NEWPC) mem(Ldw, O(REG, PC), RREG, R15); /* ARM Needs offset ?8 */ } static void midfl(Inst *i, int mi, int r) { int ir; switch(i->add&ARM) { default: opflst(i, mi, r); return; case AXIMM: con((short)i->reg, r, 1); return; case AXINF: ir = RFP; break; case AXINM: ir = RMP; break; } mem(mi, i->reg, ir, r); mem(mi, i->reg+4, ir, r+1); } static void mid(Inst *i, int mi, int r) { int ir; switch(i->add&ARM) { default: opwst(i, mi, r); return; case AXIMM: con((short)i->reg, r, 1); return; case AXINF: ir = RFP; break; case AXINM: ir = RMP; break; } mem(mi, i->reg, ir, r); } static void cbral(Inst *i, int jmsw, int jlsw, int mode) { ulong dst, *label; opwld(i, Lea, RA1); mid(i, Lea, RA3); mem(Ldw, 0, RA1, RA2); mem(Ldw, 0, RA3, RA0); DP(AL, Cmp, RA0, 0, 0, RA2); label = nil; dst = i->d.ins-mod->prog+1; switch(mode) { case ANDAND: label = code; BRA(jmsw, 0); break; case OROR: BRADIS(jmsw, dst); break; case EQAND: BRADIS(jmsw, dst); label = code; BRA(NE, 0); break; } mem(Ldw, 4, RA3, RA0); mem(Ldw, 4, RA1, RA2); DP(AL, Cmp, RA0, 0, 0, RA2); BRADIS(jlsw, dst); if(label != nil) PATCH(label); } static void comcase(Inst *i, int w) { int l; WORD *t, *e; if(w != 0) { opwld(i, Ldw, RA0); // v opwst(i, Lea, RCON); // table BRAMAC(AL, MacCASE); } t = (WORD*)(mod->mp+i->d.ind+4); l = t[-1]; if(pass == 0) { if(l > 0) t[-1] = -l; /* Mark it not done */ return; } if(l >= 0) /* Check pass 2 done */ return; t[-1] = -l; /* Set real count */ e = t + t[-1]*3; while(t < e) { t[2] = RELPC(patch[t[2]]); t += 3; } t[0] = RELPC(patch[t[0]]); } static void commframe(Inst *i) { int o; ulong *punt, *mlnil; opwld(i, Ldw, RA0); con(-1, RA1, 1); DP(AL, Cmp, RA0, 0, 0, RA1); mlnil = code; BRA(EQ, 0); o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame); mem(Ldw, o, RA0, RA3); mem(Ldw, O(Type, initialize), RA3, RA1); DPI(AL, Cmp, RA1, 0, 0, 0); punt = code; BRA(NE, 0); opwst(i, Lea, RA0); /* Type in RA3, destination in RA0 */ PATCH(mlnil); con(RELPC(patch[i-mod->prog+1])-8, RLINK, 0); BRAMAC(AL, MacMFRA); /* Type in RA3 */ PATCH(punt); CALL(base+macro[MacFRAM]); opwst(i, Stw, RA2); } static void commcall(Inst *i) { opwld(i, Ldw, RA2); con(RELPC(patch[i-mod->prog+1]), RA0, 0); mem(Stw, O(Frame, lr), RA2, RA0); mem(Stw, O(Frame, fp), RA2, RFP); mem(Ldw, O(REG, M), RREG, RA3); mem(Stw, O(Frame, mr), RA2, RA3); opwst(i, Ldw, RA0); mem(Ldw, O(Modlink, m), RA0, RA3); CALL(base+macro[MacMCAL]); mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RA0, RA0); } static void larith(Inst *i, int op, int opc) { opflld(i, Ldw, RA0); midfl(i, Ldw, RA2); DP(AL, op, RA1, RA1, 0, RA3); DP(AL, opc, RA0, RA0, 0, RA2); opflst(i, Stw, RA0); } static void movloop(Inst *i, int ld, int st) { USED(i, ld, st); error("movloop"); /* int s; s = 1; if(ld == Oldw) s = 4; opwld(i, Olea, RA1); opwst(i, Olea, RA2); mem(ld, 0, RA1, RA0); mem(st, 0, RA2, RA0); FM3I(2, Oadd, s, RA2, RA2); FM3I(2, Oaddcc, -1, RA3, RA3); BRA(Obne, -4); FM3I(2, Oadd, s, RA1, RA1); */ } static void compdbg(void) { print("%s:%d@%.8lux\n", R.M->name, R.t, R.st); } static void shll(Inst *i) { USED(i); error("shll"); /* ulong *lab0, *lab1, *lab2; opwld(i, Oldw, RA2); midfl(i, Oldw, RA0); FM3I(2, Ocmp, RZ, RA2, RZ); lab0 = code; BRA(Obe, 0); FM3I(2, Ocmp, 32, RA2, RZ); lab1 = code; BRA(Obl, 0); NOOP; FM3I(2, Osub, 32, RA2, RA2); FM3(2, Osll, RA2, RA1, RA0); lab2 = code; BRA(Oba, 0); MOV(RZ, RA1); PATCH(lab1); FM3(2, Osll, RA2, RA0, RA0); con(32, RA3, 1); FM3(2, Osub, RA2, RA3, RA3); FM3(2, Osrl, RA3, RA1, RA3); FM3(2, Oor, RA0, RA3, RA0); FM3(2, Osll, RA2, RA1, RA1); PATCH(lab0); PATCH(lab2); opflst(i, Ostw, RA0); */ } static void comp(Inst *i) { int r; WORD *t, *e; char buf[ERRLEN]; if(0) { Inst xx; xx.add = AXIMM|SRC(AIMM); xx.s.imm = (ulong)code; xx.reg = i-mod->prog; puntpc = 0; punt(&xx, SRCOP, compdbg); puntpc = 1; } switch(i->op) { default: snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i); error(buf); break; case IMCALL: commcall(i); 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: punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]); break; comcase(i, 0); punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]); break; case IADDC: case IMULL: case IDIVL: case IMODL: case IMODW: case IMODB: case IMULW: case IDIVW: case IMULB: case IDIVB: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; case ILOAD: case INEWA: case INEW: case ISLICEA: case ISLICELA: case ICONSB: case ICONSW: case ICONSF: case ICONSM: case ICONSMP: case ICONSP: case IMOVMP: case IHEADMP: case IHEADM: case IHEADB: case IHEADW: case IHEADL: case IINDC: case ILENC: case IINSC: case ICVTAC: case ICVTCW: case ICVTWC: case ICVTLC: case ICVTCL: case ICVTFC: case ICVTCF: case IMSPAWN: case ICVTCA: case ISLICEC: case INEWCM: case INEWCMP: case INBALT: punt(i, SRCOP|DSTOP, optab[i->op]); break; case IMFRAME: commframe(i); break; case ICASE: punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]); break; comcase(i, 1); break; case IGOTO: opwld(i, Ldw, RA1); opwst(i, Lea, RA0); LDRW(AL, RA0, R15, (2<<3), RA1); flushcon(); if(pass == 0) break; t = (WORD*)(mod->mp+i->d.ind); e = t + t[-1]; t[-1] = 0; while(t < e) { t[0] = RELPC(patch[t[0]]); /* ARM PC 8 fix? */ t++; } break; case IMOVL: movl: opflld(i, Ldw, RA0); opflst(i, Stw, RA0); break; case IMOVM: punt(i, SRCOP|DSTOP, optab[i->op]); break; if((i->add&ARM) == AXIMM) { if(i->reg == 8) goto movl; if((i->reg&3) == 0) { con(i->reg>>2, RA3, 1); movloop(i, Ldw, Stw); break; } } mid(i, Ldw, RA3); movloop(i, Ldb, Stb); 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], RA3, 1); CALL(base+macro[MacFRAM]); opwst(i, Stw, RA2); break; case INEWCB: case INEWCW: case INEWCF: case INEWCP: case INEWCL: punt(i, DSTOP, optab[i->op]); break; case IEXIT: punt(i, 0, optab[i->op]); break; case ICVTBW: opwld(i, Ldb, RA0); opwst(i, Stw, RA0); break; case ICVTWB: opwld(i, Ldw, RA0); opwst(i, Stb, RA0); break; case ILEA: opwld(i, Lea, RA0); opwst(i, Stw, RA0); break; case IMOVW: opwld(i, Ldw, RA0); opwst(i, Stw, RA0); break; case IMOVB: opwld(i, Ldb, RA0); opwst(i, Stb, RA0); break; case ITAIL: opwld(i, Ldw, RA0); mem(Ldw, O(List, tail), RA0, RA1); goto movp; case IMOVP: case IHEADP: opwld(i, Ldw, RA1); if(i->op == IHEADP) mem(Ldw, OA(List, data), RA1, RA1); movp: con(-1, RA3, 1); DP(AL, Cmp, RA1, 0, 0, RA3); BRA(EQ, 1); CALL(base+macro[MacCOLR]); opwst(i, Ldw, RA0); opwst(i, Stw, RA1); CALL(base+macro[MacFRP]); break; case ILENA: opwld(i, Ldw, RA1); con(-1, RA3, 1); DP(AL, Cmp, RA1, 0, 0, RA3); BRA(EQ, 3); con(0, RA0, 1); mem(Ldw, O(Array, len), RA1, RA0); opwst(i, Stw, RA0); break; case ILENL: con(0, RA0, 1); opwld(i, Ldw, RA1); con(-1, RA3, 1); DP(AL, Cmp, RA1, 0, 0, RA3); BRA(EQ, 5); mem(Ldw, O(List, tail), RA1, RA1); DPI(AL, Add, RA0, RA0, 0, 1); BRA(AL, -4); opwst(i, Stw, RA0); break; case ICALL: opwld(i, Ldw, RA0); con(RELPC(patch[i-mod->prog+1]), RA1, 0); mem(Stw, O(Frame, lr), RA0, RA1); mem(Stw, O(Frame, fp), RA0, RFP); BRADIS(AL, i->d.ins-mod->prog+1); MOV(RA0, RFP); break; case IJMP: BRADIS(AL, i->d.ins-mod->prog+1); flushcon(); break; case IBEQW: r = EQ; braw: opwld(i, Ldw, RA1); mid(i, Ldw, RA0); DP(AL, Cmp, RA0, 0, 0, RA1); BRADIS(r, i->d.ins-mod->prog+1); break; case IBNEW: r = NE; goto braw; case IBLTW: r = LT; goto braw; case IBLEW: r = LE; goto braw; case IBGTW: r = GT; goto braw; case IBGEW: r = GE; goto braw; case IBEQB: r = EQ; brab: opwld(i, Ldb, RA1); mid(i, Ldb, RA0); DP(AL, Cmp, RA0, 0, 0, RA1); BRADIS(r, i->d.ins-mod->prog+1); break; case IBNEB: r = NE; goto brab; case IBLTB: r = LT; goto brab; case IBLEB: r = LE; goto brab; case IBGTB: r = GT; goto brab; case IBGEB: r = GE; goto brab; /* case IBEQF: r = Ofbe; braf: opflld(i, Oldf, FA4); midfl(i, Oldf, FA2); FMF2(OfcmpD, FA2, FA4, 0); NOOP; BRAFDIS(r, i->d.ins-mod->prog+1); NOOP; break; case IBNEF: r = Ofbne; goto braf; case IBLTF: r = Ofbl; goto braf; case IBLEF: r = Ofble; goto braf; case IBGTF: r = Ofbg; goto braf; case IBGEF: r = Ofbge; goto braf; */ case IRET: mem(Ldw, O(Frame,t), RFP, RA1); BRAMAC(AL, MacRET); break; case IORW: r = Orr; goto arithw; case IANDW: r = And; goto arithw; case IXORW: r = Eor; goto arithw; case ISUBW: r = Sub; goto arithw; case ISHRW: r = 2; shiftw: mid(i, Ldw, RA1); if(UXSRC(i->add) == SRC(AIMM)) DPI(AL, Mov, 0, RA0, (i->s.imm<<3)|(r<<1), RA1); else { opwld(i, Ldw, RA0); DP(AL, Mov, 0, RA0, (RA0<<4)|(r<<1)|1, RA1); } opwst(i, Stw, RA0); break; case ISHLW: r = 0; goto shiftw; break; case IADDW: r = Add; arithw: mid(i, Ldw, RA1); if(UXSRC(i->add) == SRC(AIMM) && (ulong)i->s.imm < BITS(8)) DPI(AL, r, RA1, RA0, 0, i->s.imm); else { opwld(i, Ldw, RA0); DP(AL, r, RA1, RA0, 0, RA0); } opwst(i, Stw, RA0); break; case IORB: r = Orr; goto arithb; case IANDB: r = And; goto arithb; case IXORB: r = Eor; goto arithb; case ISUBB: r = Sub; goto arithb; case IADDB: r = Add; arithb: mid(i, Ldb, RA1); opwld(i, Ldb, RA0); DP(AL, r, RA1, RA0, 0, RA0); opwst(i, Stb, RA0); break; case ISHRB: r = 2; goto shiftb; case ISHLB: r = 0; shiftb: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; mid(i, Ldb, RA1); if(UXSRC(i->add) == SRC(AIMM)) DPI(AL, Mov, 0, RA0, (i->s.imm<<3)|(r<<1), RA1); else { opwld(i, Ldw, RA0); DP(AL, Mov, 0, RA0, (RA0<<4)|(r<<1)|1, RA1); } opwst(i, Stb, RA0); break; case IINDL: case IINDF: case IINDW: case IINDB: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; opwld(i, Ldw, RA0); /* a */ r = 0; switch(i->op) { case IINDL: case IINDF: r = 3; break; case IINDW: r = 2; break; } if(UXDST(i->add) == DST(AIMM) && i->d.imm < ?)) { mem(Oldw, O(Array, data), RA0, RA0); FM3I(2, Oadd, (i->d.imm<add&ARM) == AXINF) r = RFP; mem(Ostw, i->reg, r, RA0); break; case IINDX: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; #ifdef YYYY opwld(i, Oldw, RA0); /* a */ /* r = 0; if(UXDST(i->add) == DST(AIMM) && bc(i->d.imm<d.imm<add&ARM) == AXINF) r = RFP; mem(Ostw, i->reg, r, RA0); break; #endif case IADDL: larith(i, Add, Adc); break; case ISUBL: larith(i, Sub, Sbc); break; case IORL: larith(i, Orr, Orr); break; case IANDL: larith(i, And, And); break; case IXORL: larith(i, Eor, Eor); break; case ICVTWL: opwld(i, Ldw, RA1); DPI(AL, Mov, 0, RA0, (31<<3)|(2<<1), RA1); opflst(i, Stw, RA0); break; case ICVTLW: opwld(i, Lea, RA0); mem(Ldw, 4, RA0, RA0); opwst(i, Stw, RA0); break; case IBEQL: cbral(i, NE, EQ, ANDAND); break; case IBNEL: cbral(i, NE, NE, OROR); break; case IBLEL: cbral(i, LT, LS, EQAND); break; case IBGTL: cbral(i, GT, HI, EQAND); break; case IBLTL: cbral(i, LT, CS, EQAND); break; case IBGEL: cbral(i, GT, CC, EQAND); break; case IMOVF: punt(i, SRCOP|DSTOP, optab[i->op]); break; case IDIVF: case IMULF: case ISUBF: case IADDF: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; case INEGF: case ICVTFL: case ICVTLF: case ICVTWF: case ICVTFW: punt(i, SRCOP|DSTOP, optab[i->op]); break; /* case IMOVF: opflld(i, Oldf, FA2); opflst(i, Ostf, FA2); break; case IDIVF: r = OfdivD; goto arithf; case IMULF: r = OfmulD; goto arithf; case ISUBF: r = OfsubD; goto arithf; case IADDF: r = OfaddD; arithf: opflld(i, Oldf, FA2); midfl(i, Oldf, FA4); FMF1(r, FA2, FA4, FA4); opflst(i, Ostf, FA4); break; case INEGF: opflld(i, Oldf, FA2); FMF1(OfnegS, FA2, 0, FA2); opflst(i, Ostf, FA2); break; case ICVTFL: // >= Sparc 8 // opflld(i, Oldf, FA2); // FMF1(OfDtoQ, FA2, 0, FA2); // opflst(i, Ostf, FA2); punt(i, SRCOP|DSTOP, optab[i->op]); break; case ICVTLF: // >= Sparc 8 // opflld(i, Oldf, FA2); // FMF1(OfQtoD, FA2, 0, FA2); // opflst(i, Ostf, FA2); punt(i, SRCOP|DSTOP, optab[i->op]); break; case ICVTWF: opwld(i, Oldf, FA2); FMF1(OfWtoD, FA2, 0, FA2); opflst(i, Ostf, FA2); break; case ICVTFW: opflld(i, Oldf, FA2); FMF1(OfDtoW, FA2, 0, FA2); opwst(i, Ostf, FA2); break; */ case ISHLL: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; shll(i); break; case ISHRL: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; } } static void preamble(void) { ulong *start; if(comvec) return; comvec = malloc(10 * sizeof(*code)); code = (ulong*)comvec; start = code; con((ulong)&R, RREG, 1); mem(Stw, O(REG, xpc), RREG, RLINK); mem(Ldw, O(REG, FP), RREG, RFP); mem(Ldw, O(REG, MP), RREG, RMP); mem(Ldw, O(REG, PC), RREG, R15); flushcon(); segflush(comvec, 10 * sizeof(*code)); if(cflag > 4) { print("comvec:\n"); das(start, code-start); } } static void maccase(void) { error("case"); /* ulong *loop, *def, *lab1; mem(Oldw, 0, RCON, RA3); // n = t[0] FM3I(2, Oadd, 4, RCON, RCON); MOV(RA3, RA1); FM3I(2, Osll, 1, RA1, RA1); FM3(2, Oadd, RA3, RA1, RA1); FM3I(2, Osll, 2, RA1, RA1); FM3(3, Oldw, RCON, RA1, RLINK); loop = code; FM3(2, Ocmp, RZ, RA3, RZ); def = code; BRA(Oble, 0); NOOP; MOV(RA3, RA2); // MOVL DX, CX n2 = n FM3I(2, Osra, 1, RA2, RA2); // SHR CX,1 n2 = n2>>1 MOV(RA2, RA1); FM3I(2, Osll, 1, RA1, RA1); FM3(2, Oadd, RA2, RA1, RA1); FM3I(2, Osll, 2, RA1, RA1); FM3(3, Oldw, RA1, RCON, RTA); // MOV (RA1+RCON), RTA FM3(2, Ocmp, RTA, RA0, RZ); lab1 = code; BRA(Obge, 0); NOOP; MOV(RA2, RA3); // n = n2 BRA(Oba, loop-code+1); NOOP; PATCH(lab1); FM3I(2, Oadd, 4, RA1, RTA); FM3(3, Oldw, RTA, RCON, RTA); // MOV (RA1+RCON), RTA FM3(2, Ocmp, RTA, RA0, RZ); lab1 = code; BRA(Obl, 0); NOOP; FM3I(2, Oadd, 12, RA1, RTA); FM3(2, Oadd, RTA, RCON, RCON); FM3(2, Osub, RA2, RA3, RA3); // SUBL CX, DX n -= n2 FM3I(2, Oadd, -1, RA3, RA3); // DECL DX n -= 1 BRA(Oba, loop-code+1); NOOP; PATCH(lab1); FM3I(2, Oadd, 8, RA1, RTA); FM3(3, Oldw, RTA, RCON, RLINK); PATCH(def); FM3I(2, Ojmpl, 0, RLINK, RZ); NOOP; */ } static void macfrp(void) { ulong *lab1, *lab2; /* destroy the pointer in RA0 */ con(-1, RA3, 1); DP(AL, Cmp, RA0, 0, 0, RA3); lab1 = code; BRA(EQ, 0); mem(Ldw, O(Heap, ref)-sizeof(Heap), RA0, RA2); DP(AL, Add, RA2, RA2, 0, RA3); DPI(AL, Cmp, RA2, 0, 0, 0); lab2 = code; BRA(NE, 0); mem(Stw, O(REG, FP), RREG, RFP); mem(Stw, O(REG, st), RREG, RLINK); CALL(rdestroy); mem(Stw, O(REG, s), RREG, RA0); con((ulong)&R, RREG, 1); mem(Ldw, O(REG, st), RREG, RLINK); mem(Ldw, O(REG, FP), RREG, RFP); mem(Ldw, O(REG, MP), RREG, RMP); RETURN; PATCH(lab2); mem(Stw, O(Heap, ref)-sizeof(Heap), RA0, RA2); PATCH(lab1); RETURN; } static void macret(void) { Inst i; ulong *cp1, *cp2, *cp3, *cp4, *cp5; DPI(AL, Cmp, RA1, 0, 0, 0); cp1 = code; BRA(EQ, 0); // t(Rfp) == 0 mem(Ldw, O(Type,destroy),RA1, RA0); DPI(AL, Cmp, RA0, 0, 0, 0); cp2 = code; BRA(EQ, 0); // destroy(t(fp)) == 0 mem(Ldw, O(Frame,fp),RFP, RA2); DPI(AL, Cmp, RA2, 0, 0, 0); cp3 = code; BRA(EQ, 0); // fp(Rfp) == 0 mem(Ldw, O(Frame,mr),RFP, RA3); DPI(AL, Cmp, RA3, 0, 0, 0); cp4 = code; BRA(EQ, 0); // mr(Rfp) == 0 mem(Ldw, O(REG,M),RREG, RA2); mem(Ldw, O(Module,ref),RA2, RA3); con(-1, RCON, 1); DP(AL, Add, RA3, RA3, 0, RCON); cp5 = code; BRA(EQ, 0); // --ref(arg) == 0 mem(Stw, O(Module,ref),RA2, RA3); mem(Ldw, O(Frame,mr),RFP, RA1); mem(Stw, O(REG,M),RREG, RA1); mem(Ldw, O(Module,mp),RA1, RMP); mem(Stw, O(REG,MP),RREG, RMP); PATCH(cp4); CALLR(RA0); // call destroy(t(fp)) mem(Stw, O(REG,SP),RREG, RFP); mem(Ldw, O(Frame,lr),RFP, RA1); mem(Ldw, O(Frame,fp),RFP, RFP); DP(AL, Mov, 0, R15, 0, RA1); // goto lr(Rfp) flushcon(); PATCH(cp1); PATCH(cp2); PATCH(cp3); PATCH(cp5); i.add = AXNON; punt(&i, NEWPC, optab[IRET]); } static void maccolr(void) { ulong *br; /* color the pointer in RA1 */ mem(Ldw, O(Heap, ref)-sizeof(Heap), RA1, RA0); DPI(AL, Add, RA0, RA0, 0, 1); mem(Stw, O(Heap, ref)-sizeof(Heap), RA1, RA0); con((ulong)&mutator, RA2, 1); mem(Ldw, O(Heap, color)-sizeof(Heap), RA1, RA0); mem(Ldw, 0, RA2, RA2); DP(AL, Cmp, RA0, 0, 0, RA2); br = code; BRA(EQ, 0); con(propagator, RA2, 1); mem(Stw, O(Heap, color)-sizeof(Heap), RA1, RA2); con((ulong)&nprop, RA2, 1); mem(Stw, 0, RA2, RA2); PATCH(br); RETURN; } static void macmcal(void) { ulong *lab; mem(Ldw, O(Module, prog), RA3, RA1); DPI(AL, Cmp, RA1, 0, 0, 0); lab = code; BRA(NE, 0); mem(Stw, O(REG, st), RREG, RLINK); mem(Stw, O(REG, FP), RREG, RA2); CALL(rmcall); // CALL rmcall mem(Stw, O(REG, dt), RREG, RA0); con((ulong)&R, RREG, 1); // MOVL $R, RREG mem(Ldw, O(REG, st), RREG, RLINK); mem(Ldw, O(REG, FP), RREG, RFP); mem(Ldw, O(REG, MP), RREG, RMP); RETURN; PATCH(lab); // patch: DP(AL, Mov, 0, RFP, 0, RA2); mem(Stw, O(REG, M), RREG, RA3); // MOVL RA3, R.M mem(Ldw, O(Module, ref), RA3, RA1); DPI(AL, Add, RA1, RA1, 0, 1); mem(Stw, O(Module, ref), RA3, RA1); mem(Ldw, O(Module, mp), RA3, RMP); // MOVL R.M->mp, RMP mem(Stw, O(REG, MP), RREG, RMP); // MOVL RA3, R.MP R.MP = ml->m DP(AL, Mov, 0, R15, 0, RA0); } static void macfram(void) { ulong *lab1; mem(Ldw, O(REG, SP), RREG, RA0); // MOVL R.SP, RA0 mem(Ldw, O(Type, size), RA3, RA1); DP(AL, ADD, RA0, RA0, 0, RA1); mem(Ldw, O(REG, TS), RREG, RA1); DP(AL, CMP, RA1, 0, 0, RA0); lab1 = code; BRA(LT, 0); mem(Stw, O(REG, s), RREG, RA3); mem(Stw, O(REG, st), RREG, RLINK); CALL(extend); // CALL extend mem(Stw, O(REG, FP), RREG, RFP); // MOVL RFP, R.FP con((ulong)&R, RREG, 1); mem(Ldw, O(REG, st), RREG, RLINK); mem(Ldw, O(REG, FP), RREG, RFP); // MOVL R.MP, RMP mem(Ldw, O(REG, s), RREG, RA2); // MOVL R.s, *R.d mem(Ldw, O(REG, MP), RREG, RMP); // MOVL R.MP, RMP RETURN; // RET PATCH(lab1); mem(Ldw, O(REG, SP), RREG, RA2); // MOVL R.SP, RA2 mem(Stw, O(REG, SP), RREG, RA0); // MOVL RA0, R.SP mem(Stw, O(Frame, t), RA2, RA3); // MOVL RA3, t(RA2) f->t = t mem(Stw, REGMOD*4, RA2, RZ); // MOVL $0, mr(RA2) f->mr mem(Ldw, O(Type, initialize), RA3, R15); } static void macmfra(void) { mem(Stw, O(REG, st), RREG, RLINK); mem(Stw, O(REG, s), RREG, RA3); // Save type mem(Stw, O(REG, d), RREG, RA0); // Save destination CALL(rmfram); // CALL rmfram mem(Stw, O(REG, FP), RREG, RFP); con((ulong)&R, RREG, 1); mem(Ldw, O(REG, st), RREG, RLINK); mem(Ldw, O(REG, FP), RREG, RFP); mem(Ldw, O(REG, MP), RREG, RMP); RETURN; } void comd(Type *t) { int i, j, m, c; mem(Stw, O(REG, dt), RREG, RLINK); for(i = 0; i < t->np; i++) { c = t->map[i]; j = i<<5; for(m = 0x80; m != 0; m >>= 1) { if(c & m) { mem(Ldw, j, RFP, RA0); CALL(base+macro[MacFRP]); } j += sizeof(WORD*); } } mem(Ldw, O(REG, dt), RREG, RLINK); RETURN; } void comi(Type *t) { int i, j, m, c; con((ulong)H, RA0, 1); for(i = 0; i < t->np; i++) { c = t->map[i]; j = i<<5; for(m = 0x80; m != 0; m >>= 1) { if(c & m) mem(Stw, j, RA2, RA0); j += sizeof(WORD*); } } RETURN; } void typecom(Type *t) { int n; ulong *tmp, *start; if(t == nil || t->initialize != 0) return; tmp = mallocz(4096*sizeof(ulong), 0); if(tmp == nil) error("insufficient memory"); code = tmp; comi(t); n = code - tmp; code = tmp; comd(t); n += code - tmp; free(tmp); n *= sizeof(*code); code = mallocz(n, 0); if(code == nil) return; start = code; t->initialize = code; comi(t); t->destroy = code; comd(t); segflush(start, n); if(cflag > 1) print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n", t, t->size, t->initialize, t->destroy, n); } int compile(Module *m, int size) { Link *l; int i, n; ulong *s, *tmp; base = nil; patch = mallocz(size*sizeof(*patch), 0); tinit = malloc(m->ntype*sizeof(*tinit)); tmp = malloc(1024*sizeof(ulong)); if(tinit == nil || patch == nil || tmp == nil) goto bad; preamble(); mod = m; n = 0; pass = 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; } base = mallocz(n*sizeof(*code), 0); if(base == nil) goto bad; if(cflag > 1) print("dis=%5d %5d 386=%5d asm=%.8lux: %s\n", size, size*sizeof(Inst), n, base, m->name); pass++; code = base; for(i = 0; i < size; i++) { s = code; comp(&m->prog[i]); if(cflag > 2) { print("%D\n", &m->prog[i]); das(s, code-s); } } for(i = 0; i < nelem(mactab); i++) { s = code; mactab[i].gen(); if(cflag > 2) { print("%s:\n", mactab[i].name); das(s, code-s); } } if(n != (code - base)) error("compiler phase error"); for(l = m->ext; l; l = l->next) { l->u.pc = (Inst*)RELPC(patch[l->u.pc-m->prog+1]); typecom(l->frame); } for(i = 0; i < m->ntype; i++) { if(tinit[i] != 0) typecom(m->type[i]); } //m->entry = (Inst*)RELPC(patch[mod->entry-mod->prog]); free(patch); free(tinit); free(m->prog); free(tmp); //m->prog = (Inst*)base; //m->compiled = 1; //segflush(base, n*sizeof(*base)); //return 1; bad: free(patch); free(tinit); free(base); free(tmp); return 0; }