#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, /* C's SB */ R13 = 13, /* C's SP */ R14 = 14, /* Link Register */ R15 = 15, /* PC */ RLINK = 14, RFP = R9, /* Frame Pointer */ RMP = R8, /* Module Pointer */ RTA = R7, /* Intermediate address for double indirect */ RCON = R6, /* Constant builder */ RREG = R5, /* Pointer to REG */ RA3 = R4, /* gpr 3 */ RA2 = R3, /* gpr 2 2+3 = L */ RA1 = R2, /* gpr 1 */ RA0 = R1, /* gpr 0 0+1 = L */ 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, Ldf, Stf, NCON = (0xFFC-8)/4, 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-8)>>2) #define CALL(o) gen(BRAW(AL, ((ulong)o-(ulong)code-8)>>2)|(1<<24)) #define CCALL(C,o) gen(BRAW(C, ((ulong)o-(ulong)code-8)>>2)|(1<<24)) #define CALLMAC(o) gen(BRAW(r, (IA(macro, o)-(ulong)code-8)>>2)|(1<<24)) #define RELPC(pc) (ulong)(base+pc) #define RETURN DPI(AL, Add, RLINK, R15, 0, 0) #define CRETURN(C) DPI(C, Add, RLINK, R15, 0, 0) #define PATCH(ptr) *ptr |= (((ulong)code-(ulong)ptr-8)>>2) & 0x00ffffff #define MOV(src, dst) DP(AL, Mov, 0, dst, 0, src) #define FITS8(v) ((ulong)(v)initialize==0 */ }; typedef struct Const Const; struct Const { ulong o; ulong* code; ulong* pc; }; 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(char *s) { panic("compile failed: urk: %s\n", s); } static void gen(ulong w) { *code++ = w; } static long immrot(ulong v) { int i; for(i=0; i<16; i++) { if((v & ~0xff) == 0) return (i<<8) | v | (1<<25); v = (v<<2) | (v>>30); } return 0; } static long immaddr(long v) { if(v >= 0 && v <= 0xfff) return (v & 0xfff) | (1<<24) | /* pre indexing */ (1<<23); /* pre indexing, up */ if(v >= -0xfff && v < 0) return (-v & 0xfff) | (1<<24); /* pre indexing */ return 0; } static void flushcon(int genbr) { int i; Const *c; ulong disp; if(rcon.ptr == 0) return; if(genbr){ if(pass)print("BR %d(PC)=%8.8ux (len=%d)\n", (rcon.ptr*4+4-8)>>2, code+rcon.ptr+1, rcon.ptr); BRA(AL, (rcon.ptr*4+4-8)>>2); } c = &rcon.table[0]; for(i = 0; i < rcon.ptr; i++) { if(pass){ disp = (code - c->code) * sizeof(*code) - 8; if(disp >= BITS(12)) print("INVALID constant range %d", disp); if(0)print("data %8.8ux %8.8ux (%8.8ux, ins=%8.8ux cpc=%8.8ux)\n", code, c->o, c->code, *c->code, c->pc); *c->code |= (disp&0xfff); } *code++ = c->o; c++; } rcon.ptr = 0; } static void ccon(int cc, ulong o, int r, int opt) { ulong u; Const *c; if(opt != 0) { u = o & ~0xff; if(u == 0) { DPI(cc, Mov, 0, r, 0, o); return; } if(u == ~0xff) { DPI(cc, Mvn, 0, r, 0, ~o); return; } } if(rcon.ptr >= NCON || rcon.ptr > 0 && (code+codeoff+2-rcon.table[0].pc)*sizeof(*code) >= BITS(12)-128){ if(0)print("flushed constant table: len %ux disp %d\n", rcon.ptr, (code+codeoff-rcon.table[0].pc)*sizeof(*code)-8); flushcon(1); } c = &rcon.table[rcon.ptr++]; c->o = o; c->code = code; c->pc = code+codeoff; LDW(cc, R15, r, 0); } static void memc(int c, int inst, ulong disp, int rm, int r) { int bit; if(inst == Lea) { if(disp < BITS(8)) { DPI(c, Add, rm, r, 0, disp); return; } if(-disp < BITS(8)) { DPI(c, Sub, rm, r, 0, -disp); return; } ccon(c, disp, RCON, 1); DP(c, Add, rm, r, 0, RCON); return; } if(disp < BITS(12) || 0 && -disp < BITS(12)) { /* Direct load */ if(disp < BITS(12)) bit = 0; else { disp = -disp; bit = UPBIT; } switch(inst) { case Ldw: LDW(c, rm, r, disp); break; case Ldb: LDB(c, rm, r, disp); break; case Stw: STW(c, rm, r, disp); break; case Stb: STB(c, rm, r, disp); break; } if(bit) code[-1] ^= bit; return; } ccon(c, disp, RCON, 1); switch(inst) { case Ldw: LDRW(c, rm, r, 0, RCON); break; case Ldb: LDRB(c, rm, r, 0, RCON); break; case Stw: STRW(c, rm, r, 0, RCON); break; case Stb: STRB(c, rm, r, 0, RCON); break; } } static void con(ulong o, int r, int opt) { ccon(AL, o, r, opt); } static void mem(int inst, ulong disp, int rm, int r) { memc(AL, inst, disp, rm, r); } static void opx(int mode, Adr *a, int mi, int r, int li) { int ir, rta; switch(mode) { default: urk("opx"); case AFP: mem(mi, a->ind, RFP, r); return; case AMP: mem(mi, a->ind, RMP, r); return; case AIMM: con(a->imm, r, 1); if(mi == Lea) { /* could be simpler if con generates reachable literal */ mem(Stw, li, RREG, r); mem(Lea, li, RREG, r); } return; case AIND|AFP: ir = RFP; break; case AIND|AMP: ir = RMP; break; } rta = RTA; if(mi == Lea) rta = r; mem(Ldw, a->i.f, ir, rta); mem(mi, a->i.s, rta, r); } static void opwld(Inst *i, int op, int reg) { opx(USRC(i->add), &i->s, op, reg, O(REG, st)); } static void opwst(Inst *i, int op, int reg) { opx(UDST(i->add), &i->d, op, reg, O(REG, dt)); } static void memfl(int inst, ulong disp, int rm, int r) { int bit; bit = 0; if(disp < BITS(8)) ; /* direct load */ else if(-disp < BITS(8)){ bit = UPBIT; disp = -disp; }else{ con(disp, RCON, 1); DP(AL, Add, RCON, RCON, 0, rm); rm = RCON; disp = 0; } switch(inst) { case Ldf: LDF(AL, rm, r, disp); break; case Stf: STF(AL, rm, r, disp); break; } if(bit) code[-1] ^= bit; } static void opfl(Adr *a, int am, int mi, int r) { int ir; switch(am) { default: urk("opfl"); case AFP: memfl(mi, a->ind, RFP, r); return; case AMP: memfl(mi, a->ind, RMP, r); return; case AIND|AFP: ir = RFP; break; case AIND|AMP: ir = RMP; break; } mem(Ldw, a->i.f, ir, RTA); memfl(mi, a->i.s, RTA, r); } 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 literal(ulong imm, int roff) { nlit++; con((ulong)litpool, RTA, 0); mem(Stw, roff, RREG, RTA); if(pass == 0) return; *litpool = imm; litpool++; } static void punt(Inst *i, int m, void (*fn)(void)) { ulong pc; if(m & SRCOP) { 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[i->d.ins-mod->prog]; else pc = patch[i->d.ins-mod->prog+1]; literal((ulong)(base+pc), O(REG, d)); } if((i->add&ARM) == AXNON) { if(m & THREOP) { mem(Ldw, O(REG, d), RREG, RA0); mem(Stw, O(REG, m), RREG, RA0); } } else { mid(i, Lea, RA2); mem(Stw, O(REG,m),RREG, RA2); } mem(Stw, O(REG, FP), RREG, RFP); CALL(fn); con((ulong)&R, RREG, 1); if(m & TCHECK) { mem(Ldw, O(REG, t), RREG, RA0); CMPI(AL, RA0, 0, 0, 0); LDW(NE, RREG, RLINK, O(REG, xpc)); DPI(NE, Add, RLINK, R15, 0, 0); /* if(R.t) goto(R.xpc) */ } mem(Ldw, O(REG, FP), RREG, RFP); mem(Ldw, O(REG, MP), RREG, RMP); if(m & NEWPC){ mem(Ldw, O(REG, PC), RREG, R15); flushcon(0); } } 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); // BUG return; case AXINF: ir = RFP; break; case AXINM: ir = RMP; break; } memfl(mi, i->reg, ir, r); } 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); if(mi == Lea){ mem(Stw, O(REG,t), RREG, r); mem(Lea, O(REG,t), RREG, r); } return; case AXINF: ir = RFP; break; case AXINM: ir = RMP; break; } mem(mi, i->reg, ir, r); } static int swapbraop(int b) { switch(b) { case GE: return LE; case LE: return GE; case GT: return LT; case LT: return GT; } return b; } static void cbra(Inst *i, int r) { punt(i, SRCOP|THREOP|DBRAN|NEWPC|WRTPC, optab[i->op]); return; if(UXSRC(i->add) == SRC(AIMM) && FITS8(i->s.imm)) { mid(i, Ldw, RA1); CMPI(AL, RA1, 0, 0, i->s.imm); r = swapbraop(r); } else if((i->add & ARM) == AXIMM && FITS8(i->reg)) { opwld(i, Ldw, RA1); CMPI(AL, RA1, 0, 0, i->reg); } else { opwld(i, Ldw, RA0); mid(i, Ldw, RA1); CMP(AL, RA0, 0, 0, RA1); } BRADIS(r, i->d.ins-mod->prog+1); } static void cbrab(Inst *i, int r) { punt(i, SRCOP|THREOP|DBRAN|NEWPC|WRTPC, optab[i->op]); return; if(UXSRC(i->add) == SRC(AIMM)) { mid(i, Ldb, RA1); CMPI(AL, RA1, 0, 0, i->s.imm&0xFF); r = swapbraop(r); } else if((i->add & ARM) == AXIMM) { opwld(i, Ldb, RA1); CMPI(AL, RA1, 0, 0, i->reg&0xFF); } else { opwld(i, Ldb, RA0); mid(i, Ldb, RA1); CMP(AL, RA0, 0, 0, RA1); } BRADIS(r, i->d.ins-mod->prog+1); } static void cbral(Inst *i, int jmsw, int jlsw, int mode) { ulong dst, *label; punt(i, SRCOP|THREOP|DBRAN|NEWPC|WRTPC, optab[i->op]); return; opwld(i, Lea, RA1); mid(i, Lea, RA3); mem(Ldw, 0, RA1, RA2); mem(Ldw, 0, RA3, RA0); CMP(AL, 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); CMP(AL, RA0, 0, 0, RA2); BRADIS(jlsw, dst); if(label != nil) PATCH(label); } static void cbraf(Inst *i, int r) { USED(r); punt(i, SRCOP|THREOP|DBRAN|NEWPC|WRTPC, optab[i->op]); /* opflld(i, Ldf, FA4); midfl(i, Ldf, FA2); FMF2(Fcmp, FA2, FA4, 0); BRADIS(r, i->d.ins-mod->prog+1); */ } 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); CMPH(AL, RA0); 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); CMPI(AL, 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]), 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); mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RA0, RA0); CALL(base+macro[MacMCAL]); } static void larith(Inst *i, int op, int opc) { ulong *s=code; opwld(i, Lea, RA0); mid(i, Lea, RA3); mem(Ldw, 4, RA0, RA1); // ls (big endian `big' even in little endian mode) mem(Ldw, 4, RA3, RA2); DP(AL, op, RA2, RA2, 0, RA1) | SBIT; // ls: RA2 = RA2 op RA1 mem(Ldw, 0, RA0, RA1); mem(Ldw, 0, RA3, RA0); DP(AL, opc, RA0, RA0, 0, RA1); // ms: RA0 = RA0 opc RA1 if((i->add&ARM) != AXNON) opwst(i, Lea, RA3); mem(Stw, 0, RA3, RA0); mem(Stw, 4, RA3, RA2); print("%D\n", i); das(s,code-s); } static void movloop(Inst *i, int s) { int b; b = (s==1); opwst(i, Lea, RA2); LDxP(AL, RA1, RA0, s, b); STxP(AL, RA2, RA0, s, b); DPI(AL, Sub, RA3, RA3, 0, 1) | SBIT; BRA(NE, (-3*4-8)>>2); } static void movmem(Inst *i) { ulong *cp; // source address already in RA1 if((i->add&ARM) != AXIMM){ mid(i, Ldw, RA3); CMPI(AL, RA3, 0, 0, 0); cp = code; BRA(LE, 0); opwst(i, Lea, RA2); movloop(i, 1); PATCH(cp); return; } switch(i->reg){ case 4: LDW(AL, RA1, RA2, 0); opwst(i, Stw, RA2); break; case 8: LDW(AL, RA1, RA2, 0); opwst(i, Lea, RA3); LDW(AL, RA1, RA1, 4); STW(AL, RA3, RA2, 0); STW(AL, RA3, RA1, 4); break; default: // could use ldm/stm loop... opwst(i, Lea, RA2); if((i->reg&3) == 0) { con(i->reg>>2, RA3, 1); movloop(i, 4); } else { con(i->reg, RA3, 1); movloop(i, 1); } break; } } 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 commgoto(Inst *i) { WORD *t, *e; if(0){ opwld(i, Ldw, RA1); opwst(i, Lea, RA0); LDRW(AL, RA0, R15, (2<<3), RA1); flushcon(0); } if(pass == 0) return; t = (WORD*)(mod->mp+i->d.ind); e = t + t[-1]; t[-1] = 0; while(t < e) { t[0] = RELPC(patch[t[0]]); t++; } } static void comp(Inst *i) { int r; char buf[ERRLEN]; ulong *s = code; 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; flushcon(1); } switch(i->op) { default: snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i); error(buf); break; case IMCALL: punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]); break; 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: 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 IDIVW: 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 IHEADB: case IHEADW: case IHEADL: case IINDC: 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: punt(i, SRCOP|DSTOP, optab[i->op]); break; commframe(i); break; case ICASE: comcase(i, 0); punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]); break; break; case IGOTO: commgoto(i); punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]); break; break; case IMOVL: punt(i, SRCOP|DSTOP, optab[i->op]); break; opflld(i, Ldw, RA0); opflst(i, Stw, RA0); break; case IHEADM: punt(i, SRCOP|DSTOP, optab[i->op]); break; opwld(i, Lea, RA1); DPI(AL, Add, RA1, RA1, 0, OA(List,data)); movmem(i); break; case IMOVM: punt(i, SRCOP|DSTOP, optab[i->op]); break; opwld(i, Lea, RA1); movmem(i); break; case IFRAME: if(1 || 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: punt(i, SRCOP|DSTOP, optab[i->op]); break; opwld(i, Ldb, RA0); opwst(i, Stw, RA0); break; case ICVTWB: punt(i, SRCOP|DSTOP, optab[i->op]); break; opwld(i, Ldw, RA0); opwst(i, Stb, RA0); break; case ILEA: punt(i, SRCOP|DSTOP, optab[i->op]); break; opwld(i, Lea, RA0); opwst(i, Stw, RA0); break; case IMOVW: punt(i, SRCOP|DSTOP, optab[i->op]); break; opwld(i, Ldw, RA0); opwst(i, Stw, RA0); break; case IMOVB: punt(i, SRCOP|DSTOP, optab[i->op]); break; opwld(i, Ldb, RA0); opwst(i, Stb, RA0); break; case ITAIL: punt(i, SRCOP|DSTOP, optab[i->op]); break; opwld(i, Ldw, RA0); mem(Ldw, O(List, tail), RA0, RA1); goto movp; case IMOVP: punt(i, SRCOP|DSTOP, optab[i->op]); break; opwld(i, Ldw, RA1); goto movp; case IHEADP: punt(i, SRCOP|DSTOP, optab[i->op]); break; opwld(i, Ldw, RA1); mem(Ldw, OA(List, data), RA1, RA1); movp: CMPH(AL, RA1); CCALL(NE, base+macro[MacCOLR]); // colour if not H opwst(i, Ldw, RA0); // BUG: could do better opwst(i, Stw, RA1); CALL(base+macro[MacFRP]); break; case ILENA: punt(i, SRCOP|DSTOP, optab[i->op]); break; opwld(i, Ldw, RA1); con(0, RA0, 1); CMPH(AL, RA1); LDW(NE, RA1, RA0, O(Array,len)); opwst(i, Stw, RA0); break; case ILENC: punt(i, SRCOP|DSTOP, optab[i->op]); break; break; case ILENL: punt(i, SRCOP|DSTOP, optab[i->op]); break; con(0, RA0, 1); opwld(i, Ldw, RA1); CMPH(AL, RA1); LDW(NE, RA1, RA1, O(List, tail)); DPI(NE, Add, RA0, RA0, 0, 1); BRA(NE, (-4*3-8)>>2); opwst(i, Stw, RA0); break; case ICALL: punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]); break; 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); MOV(RA0, RFP); BRADIS(AL, i->d.ins-mod->prog+1); flushcon(0); break; case IJMP: punt(i, DBRAN|NEWPC, optab[i->op]); break; BRADIS(AL, i->d.ins-mod->prog+1); flushcon(0); break; case IBEQW: cbra(i, EQ); break; case IBNEW: cbra(i, NE); break; case IBLTW: cbra(i, LT); break; case IBLEW: cbra(i, LE); break; case IBGTW: cbra(i, GT); break; case IBGEW: cbra(i, GE); break; case IBEQB: cbrab(i, EQ); break; case IBNEB: cbrab(i, NE); break; case IBLTB: cbrab(i, LT); break; case IBLEB: cbrab(i, LE); break; case IBGTB: cbrab(i, GT); break; case IBGEB: cbrab(i, GE); break; case IBEQF: cbraf(i, EQ); break; case IBNEF: cbraf(i, NE); break; case IBLTF: cbraf(i, LT); break; case IBLEF: cbraf(i, LE); break; case IBGTF: cbraf(i, GT); break; case IBGEF: cbraf(i, GE); break; case IRET: punt(i, NEWPC, optab[i->op]); break; mem(Ldw, O(Frame,t), RFP, RA1); BRAMAC(AL, MacRET); break; case IMULW: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; opwld(i, Ldw, RA1); mid(i, Ldw, RA0); MUL(AL, RA1, RA0, RA0); opwst(i, Stw, RA0); break; case IMULB: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; opwld(i, Ldb, RA1); mid(i, Ldb, RA0); MUL(AL, RA1, RA0, RA0); opwst(i, Stb, RA0); 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 IADDW: r = Add; arithw: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; mid(i, Ldw, RA1); if(UXSRC(i->add) == SRC(AIMM) && FITS8(i->s.imm)) 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 ISHRW: r = 2; shiftw: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; mid(i, Ldw, RA1); if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm)) DP(AL, Mov, 0, RA0, ((i->s.imm&0x3F)<<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 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: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; mid(i, Ldb, RA1); if(UXSRC(i->add) == SRC(AIMM)) DPI(AL, r, RA1, RA0, 0, i->s.imm); else { 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) && FITS5(i->s.imm)) DP(AL, Mov, 0, RA0, ((i->s.imm&0x3F)<<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; #ifdef YYY case IINDC: opwld(i, Ldw, RA1); // RA1 = string imm = 1; if((i->add&ARM) != AXIMM || !FITS8((short)i->reg<<1)){ mid(i, Ldw, RA2); // RA2 = i imm = 0; } mem(Ldw, O(String,len),RA1, RA0); // len<0 => index Runes, otherwise bytes // BUG: check !((ulong)i >= abs(a->len)) AIRR(Oaddi, RA1, RA1,O(String,data)); AIRR(Ocmpi, Rcrf0, RA0, 0); cp = code; BRA(GE, 0); if(!imm){ SLWI(RA2, RA2, 1); ARRR(Olhzx, RA3, RA1, RA2); // ARM: use Ldh (RA2<<1)[RA1] } else mem(Ldw, (short)i->reg<<1, RA1, RA3); /* shifts to adjust halfword */ gen(Ob | (2*4)); // skip PATCH(cp); if(!imm) ARRR(Ldb, RA3, RA1, RA2); else AIRR(Ldb, RA3, RA1,i->reg); opwst(i, Ostw, RA3); break; #endif case IINDL: case IINDF: case IINDW: case IINDB: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; opwld(i, Ldw, RA0); /* a */ mem(Ldw, O(Array, data), RA0, RA0); r = 0; switch(i->op) { case IINDL: case IINDF: r = 3; break; case IINDW: r = 2; break; } if(UXDST(i->add) == DST(AIMM) && FITS8(i->d.imm<d.imm<op]); break; opwld(i, Ldw, RA0); /* a */ opwst(i, Ldw, RA1); /* i */ mem(Ldw, O(Array, t), RA0, RA2); mem(Ldw, O(Array, data), RA0, RA0); mem(Ldw, O(Type, size), RA2, RA2); MUL(AL, RA2, RA1, RA1); DP(AL, Add, RA1, RA0, 0, RA0); mid(i, Stw, RA0); break; case IADDL: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; larith(i, Add, Adc); break; case ISUBL: punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; larith(i, Sub, Sbc); break; case IORL: //punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; larith(i, Orr, Orr); break; case IANDL: //punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; larith(i, And, And); break; case IXORL: //punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); break; larith(i, Eor, Eor); break; case ICVTWL: punt(i, SRCOP|DSTOP, optab[i->op]); break; opwld(i, Ldw, RA1); DPI(AL, Mov, 0, RA0, (31<<3)|(2<<1), RA1); opflst(i, Stw, RA0); break; case ICVTLW: punt(i, SRCOP|DSTOP, optab[i->op]); break; 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, Ldf, FA2); opflst(i, Stf, FA2); break; case IDIVF: r = Fdiv; goto arithf; case IMULF: r = Fmul; goto arithf; case ISUBF: r = Fsub; goto arithf; case IADDF: r = Fadd; arithf: opflld(i, Ldf, FA2); midfl(i, Ldf, FA4); FMF1(r, FA2, FA4, FA4); opflst(i, Stf, FA4); break; case INEGF: opflld(i, Ldf, FA2); FMF1(Fneg, FA2, 0, FA2); opflst(i, Stf, FA2); break; case ICVTFL: // >= Sparc 8 // opflld(i, Ldf, FA2); // FMF1(OfDtoQ, FA2, 0, FA2); // opflst(i, Stf, FA2); punt(i, SRCOP|DSTOP, optab[i->op]); break; case ICVTLF: // >= Sparc 8 // opflld(i, Ldf, FA2); // FMF1(OfQtoD, FA2, 0, FA2); // opflst(i, Stf, FA2); punt(i, SRCOP|DSTOP, optab[i->op]); break; case ICVTWF: opwld(i, Ldw, 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) { if(comvec) return; comvec = malloc(10 * sizeof(*code)); code = (ulong*)comvec; con((ulong)&R, RREG, 0); 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); pass++; flushcon(0); pass--; segflush(comvec, 10 * sizeof(*code)); } static void maccase(void) { #ifdef YYY ulong *cp1, *cp2, *cp3, *loop; /* * Ro1 = value (input arg), t * Ro2 = count, n * Ro3 = table pointer (input arg) * Ri = n/2, n2 * Rj = pivot element t+n/2*3, l */ IRR(Olwz, 0,Ro3, Ro2); // count IRR(Oaddi, 0,Ro3, Rlink); // initial table pointer loop = code; // loop: AIRR(Ocmpi, Rcrf0, Ro2, 0); cp1 = code; BRA(LE, 0); // n <= 0? goto out LRRR(Osrawi, Ri, Ro2, 1); // n2 = n>>1 SLWI(Rj, Ri, 1); ARRR(Oadd, Rj, Rj, Ri); SLWI(Rj, Rj, 2); ARRR(Oadd, Rj, Rj, Ro3); // l = t + n2*3; AIRR(Olwz, Rpic, Rj,4); ARRR(Ocmp, Rcrf0, Ro1, Rpic); cp2 = code; BRA(LT, 0); // v < l[1]? goto low mem(Ldw, 8,Rj, Rpic); ARRR(Ocmp, Rcrf0, Ro1, Rpic); cp3 = code; BRA(GE, 0); // v >= l[2]? goto high IRR(Olwz, 12,Rj, Ro3); // found jr(Ro3); PATCH(cp2); // low: IRR(Oaddi, 0, Ri, Ro2); // n = n2 jmp(loop); PATCH(cp3); // high: IRR(Oaddi, 12, Rj, Ro3); // t = l+3; IRR(Oaddi, 1, Ri, Rpic); RRR(Osubf, Ro2, Rpic, Ro2); // n -= n2 + 1 jmp(loop); PATCH(cp1); // out: IRR(Olwz, 0,Rlink, Ro2); // initial n SLWI(Ro3, Ro2, 1); RRR(Oadd, Ro3, Ro2, Ro2); SLWI(Ro2, Ro2, 2); RRR(Oadd, Ro2, Rlink, Rlink); IRR(Olwz, 4,Rlink, Ro3); // (initial t)[n*3+1] jr(Ro3); #endif } static void macfrp(void) { ulong *s=code; /* destroy the pointer in RA0 */ CMPH(AL, RA0); CRETURN(EQ); // arg == H? => return mem(Ldw, O(Heap, ref)-sizeof(Heap), RA0, RA2); DPI(AL, Sub, RA2, RA2, 0, 1) | SBIT; memc(NE, Stw, O(Heap, ref)-sizeof(Heap), RA0, RA2); CRETURN(NE); // --h->ref != 0 => return mem(Stw, O(REG, FP), RREG, RFP); mem(Stw, O(REG, st), RREG, RLINK); mem(Stw, O(REG, s), RREG, RA0); CALL(rdestroy); 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; flushcon(0); //{static int fix; if(pass&&fix++==0){print("FRP:\n"); das(s, code-s);delay(240000);}} } static void maccolr(void) { ulong *s=code; /* 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); // h->ref++ con((ulong)&mutator, RA2, 1); mem(Ldw, O(Heap, color)-sizeof(Heap), RA1, RA0); mem(Ldw, 0, RA2, RA2); CMP(AL, RA0, 0, 0, RA2); CRETURN(EQ); // return if h->color == mutator con(propagator, RA2, 1); mem(Stw, O(Heap, color)-sizeof(Heap), RA1, RA2); // h->color = propagator con((ulong)&nprop, RA2, 1); mem(Stw, 0, RA2, RA2); // nprop = !0 RETURN; flushcon(0); //{static int fix; if(pass&&fix++==0){print("COLR:\n"); das(s, code-s);delay(240000);}} } static void macret(void) { Inst i; ulong *cp1, *cp2, *cp3, *cp4, *cp5; CMPI(AL, RA1, 0, 0, 0); cp1 = code; BRA(EQ, 0); // t(Rfp) == 0 mem(Ldw, O(Type,destroy),RA1, RA0); CMPI(AL, RA0, 0, 0, 0); cp2 = code; BRA(EQ, 0); // destroy(t(fp)) == 0 mem(Ldw, O(Frame,fp),RFP, RA2); CMPI(AL, RA2, 0, 0, 0); cp3 = code; BRA(EQ, 0); // fp(Rfp) == 0 mem(Ldw, O(Frame,mr),RFP, RA3); CMPI(AL, 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); DP(AL, Sub, RA3, RA3, 0, 1) | SBIT; 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); DP(AL, Mov, 0, R14, R15, 0); // call destroy(t(fp)) DP(AL, Mov, 0, RA0, R15, 0); 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) PATCH(cp1); PATCH(cp2); PATCH(cp3); PATCH(cp5); i.add = AXNON; punt(&i, NEWPC, optab[IRET]); } static void macmcal(void) { ulong *lab; mem(Ldw, O(Module, prog), RA3, RA1); CMPI(AL, RA1, 0, 0, 0); lab = code; BRA(NE, 0); mem(Stw, O(REG, st), RREG, RLINK); mem(Stw, O(REG, FP), RREG, RA2); mem(Stw, O(REG, dt), RREG, RA0); CALL(rmcall); // CALL rmcall 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); CMP(AL, RA1, 0, 0, RA0); lab1 = code; BRA(LT, 0); // BUG: could reorder code for common case mem(Stw, O(REG, s), RREG, RA3); mem(Stw, O(REG, st), RREG, RLINK); mem(Stw, O(REG, FP), RREG, RFP); // MOVL RFP, R.FP CALL(extend); // CALL extend 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 con(0, RA0, 1); // BUG? check this reg free mem(Stw, REGMOD*4, RA2, RA0); // 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 mem(Stw, O(REG, FP), RREG, RFP); CALL(rmfram); // CALL rmfram 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; flushcon(0); } 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; flushcon(0); } 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(4096*sizeof(ulong)); if(tinit == nil || patch == nil || tmp == nil) goto bad; preamble(); mod = m; n = 0; pass = 0; nlit = 0; for(i = 0; i < size; i++) { codeoff = n; code = tmp; comp(&m->prog[i]); patch[i] = n; n += code - tmp; } for(i = 0; 0 && i < nelem(mactab); i++) { codeoff = n; code = tmp; mactab[i].gen(); macro[mactab[i].idx] = n; n += code - tmp; } code = tmp; flushcon(0); n += code - tmp; base = mallocz((n+nlit)*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++; nlit = 0; litpool = base+n; code = base; n = 0; codeoff = 0; for(i = 0; i < size; i++) { s = code; comp(&m->prog[i]); if(patch[i] != n) { print("%3d %D\n", i, &m->prog[i]); print("%d != %d\n", patch[i], n); urk("phase error"); } n += code - s; if(cflag > 2) { print("%3d %D\n", i, &m->prog[i]); das(s, code-s); } } for(i = 0; 0 && i < nelem(mactab); i++) { s = code; mactab[i].gen(); n += code - s; if(cflag > 2) { print("%s:\n", mactab[i].name); das(s, code-s); } } s = code; flushcon(0); n += code - s; 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(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; }