diff options
Diffstat (limited to 'libinterp/comp-arm.c')
| -rw-r--r-- | libinterp/comp-arm.c | 2260 |
1 files changed, 2260 insertions, 0 deletions
diff --git a/libinterp/comp-arm.c b/libinterp/comp-arm.c new file mode 100644 index 00000000..a793c2c1 --- /dev/null +++ b/libinterp/comp-arm.c @@ -0,0 +1,2260 @@ +#include "lib9.h" +#include "isa.h" +#include "interp.h" +#include "raise.h" + +/* + * to do: + * eliminate litpool? + * eliminate long constants in comi/comd + * bounds checks + * enable and check inline FP code (not much point with fpemu) + */ + +#define RESCHED 1 /* check for interpreter reschedule */ + +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, + + HS = CS, + LO = CC, + + 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, + + Adf = 0, + Muf = 1, + Suf = 2, + Rsf = 3, + Dvf = 4, + Rdf = 5, + Rmf = 8, + + Mvf = 0, + Mnf = 1, + Abs = 2, + Rnd = 3, + + Flt = 0, + Fix = 1, + + Cmf = 4, + Cnf = 5, + + Lea = 100, /* macro memory ops */ + Ldw, + Ldb, + Stw, + Stb, + Ldf, + Stf, + Ldh, + + 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, + MacCASE, + MacCOLR, + MacMCAL, + MacFRAM, + MacMFRA, + MacRELQ, + NMACRO +}; + +#define BITS(B) (1<<B) +#define IMM(O) (O & ((1<<12)-1)) +#define SBIT (1<<20) +#define PBIT (1<<24) +#define UPBIT (1<<23) + +#define LDW(C, Rn, Rd, O) *code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<20)|\ + (Rn<<16)|(Rd<<12)|IMM(O) +#define STW(C, Rn, Rd, O) *code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|\ + (Rn<<16)|(Rd<<12)|IMM(O) +#define LDB(C, Rn, Rd, O) *code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<20)|(1<<22)|\ + (Rn<<16)|(Rd<<12)|IMM(O) +#define STB(C, Rn, Rd, O) *code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<22)|\ + (Rn<<16)|(Rd<<12)|IMM(O) + +#define LDxP(C, Rn, Rd, O, B) *code++ = (C<<28)|(1<<26)|(B<<22)|(1<<23)|(1<<20)|\ + (Rn<<16)|(Rd<<12)|IMM(O) +#define STxP(C, Rn, Rd, O, B) *code++ = (C<<28)|(1<<26)|(B<<22)|(1<<23)|\ + (Rn<<16)|(Rd<<12)|IMM(O) +#define LDRW(C, Rn, Rd, SH, R) *code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<20)|\ + (Rn<<16)|(Rd<<12)|(SH<<4)|R +#define STRW(C, Rn, Rd, SH, R) *code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|\ + (Rn<<16)|(Rd<<12)|(SH<<4)|R +#define LDRB(C, Rn, Rd, SH, R) *code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<20)|(1<<22)|\ + (Rn<<16)|(Rd<<12)|(SH<<4)|R +#define STRB(C, Rn, Rd, SH, R) *code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<22)|\ + (Rn<<16)|(Rd<<12)|(SH<<4)|R + +#define DPI(C, Op, Rn, Rd, RO, O) *code++ = (C<<28)|(1<<25)|(Op<<21)|\ + (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff) +#define DP(C, Op, Rn, Rd, Sh, Ro) *code++ = (C<<28)|(Op<<21)|(Rn<<16)|\ + (Rd<<12)|((Sh)<<4)|Ro +#define CMPI(C, Rn, Rd, RO, O) *code++ = (C<<28)|(1<<25)|(Cmp<<21)|(1<<20)|\ + (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff) +#define CMNI(C, Rn, Rd, RO, O) *code++ = (C<<28)|(1<<25)|(Cmn<<21)|(1<<20)|\ + (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff) +#define CMP(C, Rn, Rd, Sh, Ro) *code++ = (C<<28)|(Cmp<<21)|(Rn<<16)|(1<<20)|\ + (Rd<<12)|((Sh)<<4)|Ro +#define CMN(C, Rn, Rd, Sh, Ro) *code++ = (C<<28)|(Cmn<<21)|(Rn<<16)|(1<<20)|\ + (Rd<<12)|((Sh)<<4)|Ro +#define MUL(C, Rm, Rs, Rd) *code++ = (C<<28)|(Rd<<16)|(Rm<<0)|(Rs<<8)|\ + (9<<4) + +#define LDF(C, Rn, Fd, O) *code++ = (C<<28)|(6<<25)|(1<<24)|(1<<23)|(1<<20)|\ + (Rn<<16)|(1<<15)|(Fd<<12)|(1<<8)|((O)&0xff) +#define STF(C, Rn, Fd, O) *code++ = (C<<28)|(6<<25)|(1<<24)|(1<<23)|\ + (Rn<<16)|(1<<15)|(Fd<<12)|(1<<8)|((O)&0xff) +#define CMF(C, Fn, Fm) *code++ = (C<<28)|(7<<25)|(4<<21)|(1<<20)|(Fn<<16)|\ + (0xF<<12)|(1<<8)|(1<<4)|(Fm) + +#define LDH(C, Rn, Rd, O) *code++ = (C<<28)|(0<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<20)|\ + (Rn<<16)|(Rd<<12)|(((O)&0xf0)<<4)|(0xb<<4)|((O)&0xf) +#define LDRH(C, Rn, Rd, Rm) *code++ = (C<<28)|(0<<25)|(1<<24)|(1<<23)|(1<<20)|\ + (Rn<<16)|(Rd<<12)|(0xb<<4)|Rm + +#define CPDO2(C, Op, Fn, Fd, Fm) *code++ = (C<<28)|(0xE<<24)|(Op<<20)|(Fn<<16)|(Fd<<12)|(1<<8)|(1<<7)|(Fm) +#define CPDO1(C, Op, Fd, Fm) CPDO2((C),(Op),0,(Fd),(Fm))|(1<<15) +#define CPFLT(C, Fn, Rd) *code++ = (C<<28)|(0xE<<24)|(0<<20)|(Fn<<16)|(Rd<<12)|(1<<8)|(9<<4) +#define CPFIX(C, Rd, Fm) *code++ = (C<<28)|(0xE<<24)|(1<<20)|(0<<16)|(Rd<<12)|(1<<8)|(9<<4)|(Fm) + +#define BRAW(C, o) ((C<<28)|(5<<25)|((o) & 0x00ffffff)) +#define BRA(C, o) gen(BRAW((C),(o))) +#define IA(s, o) (ulong)(base+s[o]) +#define BRADIS(C, o) BRA(C, (IA(patch, o)-(ulong)code-8)>>2) +#define BRAMAC(r, o) BRA(r, (IA(macro, o)-(ulong)code-8)>>2) +#define BRANCH(C, o) gen(BRAW(C, ((ulong)(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(C,o) gen(BRAW((C), (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)<BITS(8)) +#define FITS5(v) ((ulong)(v)<BITS(5)) + +/* assumes H==-1 */ +#define CMPH(C, r) CMNI(C, r, 0, 0, 1) +#define NOTNIL(r) (CMPH(AL, (r)), CCALL(EQ, bounds)) + +/* array bounds checking */ +#define BCK(r, rb) (CMP(AL, rb, 0, 0, r), CCALL(LS, bounds)) +#define BCKI(i, rb) (CMPI(AL, rb, 0, 0, i), CCALL(LS, bounds)) + +static ulong* code; +static ulong* base; +static ulong* patch; +static ulong codeoff; +static int pass; +static int puntpc = 1; +static Module* mod; +static uchar* tinit; +static ulong* litpool; +static int nlit; +static ulong macro[NMACRO]; + void (*comvec)(void); +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 void movmem(Inst*); +static void mid(Inst*, int, int); +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 */ + MacRELQ, macrelq, /* reschedule */ +}; + +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; + Prog *p; + + 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; + + if(R.d == H) + error(exModule); + 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 void +urk(char *s) +{ + USED(s); + error(exCompile); //production + //panic("compile failed: urk: %s\n", s); //debugging +} + +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(0)print("BR %d(PC)=%8.8p (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 %lud", disp); + if(0)print("data %8.8p %8.8lux (%8.8p, ins=%8.8lux cpc=%8.8p)\n", code, c->o, c->code, *c->code, c->pc); + *c->code |= (disp&0xfff); + } + *code++ = c->o; + c++; + } + rcon.ptr = 0; +} + +static void +flushchk(void) +{ + if(rcon.ptr >= NCON || rcon.ptr > 0 && (code+codeoff+2-rcon.table[0].pc)*sizeof(*code) >= BITS(12)-256){ // 256 allows for a little delay in calling flushchk + if(0)print("flushed constant table: len %ux disp %ld\n", rcon.ptr, (code+codeoff-rcon.table[0].pc)*sizeof(*code)-8); + flushcon(1); + } +} + +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; + } + u = immrot(o); + if(u) { + DPI(cc, Mov, 0, r, 0, 0) | u; + return; + } + u = o & ~0xffff; + if(u == 0) { + DPI(cc, Mov, 0, r, 0, o); + DPI(cc, Orr, r, r, (24/2), o>>8); + return; + } + } + flushchk(); + 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; + } + bit = immrot(disp); + if(bit) { + DPI(c, Add, rm, r, 0, 0) | bit; + return; + } + ccon(c, disp, RCON, 1); + DP(c, Add, rm, r, 0, RCON); + return; + } + + if(disp < BITS(12) || -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 cc, int inst, ulong disp, int rm, int r) +{ + int bit, wd; + + wd = (disp&03)==0; + bit = 0; + if(wd && disp < BITS(10)) + disp >>= 2; /* direct load */ + else if(wd && -disp < BITS(10)){ + bit = UPBIT; + disp = -disp >> 2; + }else{ + ccon(cc, disp, RCON, 1); + DP(cc, Add, RCON, RCON, 0, rm); + rm = RCON; + disp = 0; + } + switch(inst) { + case Ldf: + LDF(cc, rm, r, disp); + break; + case Stf: + STF(cc, 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(AL, mi, a->ind, RFP, r); + return; + case AMP: + memfl(AL, 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(AL, 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 +schedcheck(Inst *i) +{ + if(RESCHED && i->d.ins <= i){ + mem(Ldw, O(REG, IC), RREG, RA0); + DPI(AL, Sub, RA0, RA0, 0, 1) | SBIT; + mem(Stw, O(REG, IC), RREG, RA0); + /* CMPI(AL, RA0, 0, 0, 1); */ + CALLMAC(LE, MacRELQ); + } +} + +static void +bounds(void) +{ + /* mem(Stw, O(REG,FP), RREG, RFP); */ + error(exBounds); +} + +static void +punt(Inst *i, int m, void (*fn)(void)) +{ + ulong pc; + + if(m & SRCOP) { + if(UXSRC(i->add) == SRC(AIMM)) + literal(i->s.imm, O(REG, s)); + 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) { + pc = patch[i->d.ins-mod->prog]; + literal((ulong)(base+pc), O(REG, d)); + } + + 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: + literal((short)i->reg, O(REG,m)); + break; + case AXINF: + mem(Lea, i->reg, RFP, RA2); + mem(Stw, O(REG, m), RREG, RA2); + break; + case AXINM: + mem(Lea, i->reg, RMP, RA2); + mem(Stw, O(REG, m), RREG, RA2); + break; + } + 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); + memc(NE, Ldw, O(REG, xpc), RREG, RLINK); + CRETURN(NE); /* 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(AL, 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: + if(mi == Lea) + urk("mid/lea"); + con((short)i->reg, r, 1); + 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) +{ + if(RESCHED) + schedcheck(i); + 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(UXSRC(i->add) == SRC(AIMM) && FITS8(-i->s.imm)) { + mid(i, Ldw, RA1); + CMNI(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 if((i->add & ARM) == AXIMM && FITS8(-(short)i->reg)) { + opwld(i, Ldw, RA1); + CMNI(AL, RA1, 0, 0, -(short)i->reg); + } else { + opwld(i, Ldw, RA0); + mid(i, Ldw, RA1); + CMP(AL, RA0, 0, 0, RA1); + } + BRADIS(r, i->d.ins-mod->prog); +} + +static void +cbrab(Inst *i, int r) +{ + if(RESCHED) + schedcheck(i); + 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); +} + +static void +cbral(Inst *i, int jmsw, int jlsw, int mode) +{ + ulong dst, *label; + + if(RESCHED) + schedcheck(i); + opwld(i, Lea, RA1); + mid(i, Lea, RA3); + mem(Ldw, 0, RA1, RA2); + mem(Ldw, 0, RA3, RA0); + CMP(AL, RA2, 0, 0, RA0); + label = nil; + dst = i->d.ins-mod->prog; + 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, RA2, 0, 0, RA0); + BRADIS(jlsw, dst); + if(label != nil) + PATCH(label); +} + +static void +cbraf(Inst *i, int r) +{ + if(RESCHED) + schedcheck(i); + if(0){ + ulong *s=code; + opflld(i, Ldf, FA4); + midfl(i, Ldf, FA2); + CMF(AL, FA4, FA2); + BRADIS(r, i->d.ins-mod->prog); + if(pass){print("%D\n", i); das(s, code-s);} + }else + punt(i, SRCOP|THREOP|DBRAN|NEWPC|WRTPC, optab[i->op]); +} + +static void +comcase(Inst *i, int w) +{ + int l; + WORD *t, *e; + + if(w != 0) { + opwld(i, Ldw, RA1); // v + opwst(i, Lea, RA3); // table + BRAMAC(AL, MacCASE); + } + + 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] = RELPC(patch[t[2]]); + t += 3; + } + t[0] = RELPC(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] = RELPC(patch[t[4]]); + t += 6; + } + t[0] = RELPC(patch[t[0]]); +} + +static void +commframe(Inst *i) +{ + ulong *punt, *mlnil; + + opwld(i, Ldw, RA0); + CMPH(AL, RA0); + mlnil = code; + BRA(EQ, 0); + + if((i->add&ARM) == AXIMM) { + mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame), RA0, RA3); + } else { + mid(i, Ldw, RA1); + DP(AL, Add, RA0, RA1, (3<<3), RA1); // assumes sizeof(Modl) == 8 + mem(Ldw, OA(Modlink, links)+O(Modl, frame), RA1, 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); + CALLMAC(AL, MacFRAM); + opwst(i, Stw, RA2); +} + +static void +commcall(Inst *i) +{ + ulong *mlnil; + + 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, RA3); + CMPH(AL, RA3); + mlnil = code; + BRA(EQ, 0); + if((i->add&ARM) == AXIMM) { + mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RA3, RA0); + } else { + mid(i, Ldw, RA1); + DP(AL, Add, RA3, RA1, (3<<3), RA1); // assumes sizeof(Modl) == 8 + mem(Ldw, OA(Modlink, links)+O(Modl, u.pc), RA1, RA0); + } + PATCH(mlnil); + CALLMAC(AL, MacMCAL); +} + +static void +larith(Inst *i, int op, int opc) +{ + 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); +} + +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); + movloop(i, 1); + PATCH(cp); + return; + } + switch(i->reg){ + case 0: + break; + 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... + 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:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s); +} + +static void +comgoto(Inst *i) +{ + WORD *t, *e; + + opwld(i, Ldw, RA1); + opwst(i, Lea, RA0); + LDRW(AL, RA0, R15, (2<<3), RA1); + flushcon(0); + + if(pass == 0) + return; + + t = (WORD*)(mod->origmp+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, imm; + char buf[64]; +//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); + } + flushchk(); + + 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: + case IMODW: + case IMODB: + case IDIVW: + case IDIVB: + 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 IHEADB: + case IHEADW: + 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 ICASE: + comcase(i, 1); + break; + case IGOTO: + comgoto(i); + break; + case IMOVF: + if(0){ + opflld(i, Ldf, FA2); + opflst(i, Stf, FA2); + break; + } + /* if no hardware, just fall through */ + case IMOVL: + opwld(i, Lea, RA1); + LDW(AL, RA1, RA2, 0); + LDW(AL, RA1, RA3, 4); + opwst(i, Lea, RA1); + STW(AL, RA1, RA2, 0); + STW(AL, RA1, RA3, 4); + break; + break; + case IHEADM: + opwld(i, Ldw, RA1); + NOTNIL(RA1); + DPI(AL, Add, RA1, RA1, 0, OA(List,data)); + movmem(i); + break; +/* + case IHEADW: + opwld(i, Ldw, RA0); + NOTNIL(RA0); + mem(Ldw, OA(List, data), RA0, RA0); + opwst(i, Stw, RA0); + break; +*/ + case IMOVM: + opwld(i, Lea, RA1); + movmem(i); + 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|THREOP, 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); + NOTNIL(RA0); + mem(Ldw, O(List, tail), RA0, RA1); + goto movp; + case IMOVP: + opwld(i, Ldw, RA1); + goto movp; + case IHEADP: + opwld(i, Ldw, RA0); + NOTNIL(RA0); + mem(Ldw, OA(List, data), RA0, RA1); + movp: + CMPH(AL, RA1); + CALLMAC(NE, MacCOLR); // colour if not H + opwst(i, Lea, RA2); + mem(Ldw, 0,RA2, RA0); + mem(Stw, 0,RA2, RA1); + CALLMAC(AL, MacFRP); + break; + case ILENA: + 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: + opwld(i, Ldw, RA1); + con(0, RA0, 1); + CMPH(AL, RA1); + memc(NE, Ldw, O(String,len),RA1, RA0); + CMPI(AL, RA0, 0, 0, 0); + DPI(LT, Rsb, RA0, RA0, 0, 0); + opwst(i, Stw, RA0); + break; + case ILENL: + 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: + 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); + flushcon(0); + break; + case IJMP: + if(RESCHED) + schedcheck(i); + BRADIS(AL, i->d.ins-mod->prog); + 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: + mem(Ldw, O(Frame,t), RFP, RA1); + BRAMAC(AL, MacRET); + break; + case IMULW: + opwld(i, Ldw, RA1); + mid(i, Ldw, RA0); + MUL(AL, RA1, RA0, RA0); + opwst(i, Stw, RA0); + break; + case IMULB: + 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: + mid(i, Ldw, RA1); + if(UXSRC(i->add) == SRC(AIMM) && FITS8(i->s.imm)) + DPI(AL, r, RA1, RA0, 0, i->s.imm); + else if(UXSRC(i->add) == SRC(AIMM) && immrot(i->s.imm)){ + DPI(AL, r, RA1, RA0, 0, 0) | immrot(i->s.imm); + //print("rot: %ux %ux\n", i->s.imm, immrot(i->s.imm)); das(code-1, 1); + } else { + opwld(i, Ldw, RA0); + DP(AL, r, RA1, RA0, 0, RA0); + } + opwst(i, Stw, RA0); + break; + case ISHRW: + r = 2; + shiftw: + 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: + 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: + 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; + case IINDC: + opwld(i, Ldw, RA1); // RA1 = string + NOTNIL(RA1); + 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 + DPI(AL, Add, RA1, RA1, 0, O(String,data)); + CMPI(AL, RA0, 0, 0, 0); + if(bflag) + DPI(LT, Rsb, RA0, RA0, 0, 0); + if(imm){ + LDB(GE, RA1, RA3, i->reg); + LDH(LT, RA1, RA3, (short)i->reg<<1); + if(bflag) + BCKI(i->reg, RA0); + } else { + LDRB(GE, RA1, RA3, 0, RA2); + DP(LT, Mov, 0, RA2, (1<<3), RA2); + LDRH(LT, RA1, RA3, RA2); + if(bflag) + BCK(RA2, RA0); + } + opwst(i, Stw, RA3); + break; + case IINDL: + case IINDF: + case IINDW: + case IINDB: + opwld(i, Ldw, RA0); /* a */ + NOTNIL(RA0); + mem(Ldw, O(Array, data), RA0, RA0); + if(bflag) + mem(Ldw, O(Array, len), RA0, RA2); + 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<<r)) { + if(bflag) + BCKI(i->d.imm, RA2); + DPI(AL, Add, RA0, RA0, 0, (i->d.imm<<r)); + } else { + opwst(i, Ldw, RA1); + if(bflag) + BCK(RA1, RA2); + DP(AL, Add, RA0, RA0, r<<3, RA1); + } + mid(i, Stw, RA0); + break; + case IINDX: + opwld(i, Ldw, RA0); /* a */ + NOTNIL(RA0); + opwst(i, Ldw, RA1); /* i */ + + if(bflag){ + mem(Ldw, O(Array, len), RA0, RA2); + BCK(RA1, RA2); + } + 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: + 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); + opwst(i, Lea, RA2); + DP(AL, Mov, 0, RA0, (0<<3)|(2<<1), RA1); // ASR 32 + STW(AL, RA2, RA0, 0); + STW(AL, RA2, RA1, 4); + 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, CC, EQAND); + break; + case IBGEL: + cbral(i, GT, CS, EQAND); + break; + case ICVTFL: + case ICVTLF: + punt(i, SRCOP|DSTOP, optab[i->op]); + break; + case IDIVF: + r = Dvf; + goto arithf; + case IMULF: + r = Muf; + goto arithf; + case ISUBF: + r = Suf; + goto arithf; + case IADDF: + r = Adf; + arithf: + if(1){ + /* software fp */ + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + break; + } + opflld(i, Ldf, FA2); + midfl(i, Ldf, FA4); + CPDO2(AL, r, FA4, FA4, FA2); + opflst(i, Stf, FA4); + break; + case INEGF: + if(1){ + punt(i, SRCOP|DSTOP, optab[i->op]); + break; + } + opflld(i, Ldf, FA2); + CPDO1(AL, Mnf, FA2, FA2); + opflst(i, Stf, FA2); +//if(pass){print("%D\n", i); das(s, code-s);} + break; + case ICVTWF: + if(1){ + punt(i, SRCOP|DSTOP, optab[i->op]); + break; + } + opwld(i, Ldw, RA2); + CPFLT(AL, FA2, RA2); + opflst(i, Stf, FA2); +//if(pass){print("%D\n", i); das(s, code-s);} + break; + case ICVTFW: + if(1){ + punt(i, SRCOP|DSTOP, optab[i->op]); + break; + } + opflld(i, Ldf, FA2); + CPFIX(AL, RA2, FA2); + opwst(i, Stw, RA2); +//if(pass){print("%D\n", i); das(s, code-s);} + break; + case ISHLL: + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + break; + case ISHRL: + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + 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(10 * sizeof(*code)); + if(comvec == nil) + error(exNomem); + 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) +{ + ulong *cp1, *loop, *inner; +/* + * RA1 = value (input arg), t + * RA2 = count, n + * RA3 = table pointer (input arg) + * RA0 = n/2, n2 + * RCON = pivot element t+n/2*3, l + */ + LDW(AL, RA3, RA2, 0); // count from table + MOV(RA3, RLINK); // initial table pointer + + loop = code; // loop: + CMPI(AL, RA2, 0, 0, 0); + cp1 = code; + BRA(LE, 0); // n <= 0? goto out + + inner = code; + DP(AL, Mov, 0, RA0, (1<<3)|2, RA2); // n2 = n>>1 + DP(AL, Add, RA0, RCON, (1<<3), RA0); // n' = n2+(n2<<1) = 3*n2 + DP(AL, Add, RA3, RCON, (2<<3), RCON); // l = t + n2*3; + + LDW(AL, RCON, RTA, 4); + CMP(AL, RA1, 0, 0, RTA); + DP(LT, Mov, 0, RA2, 0, RA0); // v < l[1]? n=n2 + BRANCH(LT, loop); // v < l[1]? goto loop + + LDW(AL, RCON, RTA, 8); + CMP(AL, RA1, 0, 0, RTA); + LDW(LT, RCON, R15, 12); // v >= l[1] && v < l[2] => found; goto l[3] + + // v >= l[2] (high) + DPI(AL, Add, RCON, RA3, 0, 12); // t = l+3; + DPI(AL, Add, RA0, RTA, 0, 1); + DP(AL, Sub, RA2, RA2, 0, RTA) | SBIT; // n -= n2+1 + BRANCH(GT, inner); // n > 0? goto loop + + PATCH(cp1); // out: + LDW(AL, RLINK, RA2, 0); // initial n + DP(AL, Add, RA2, RA2, (1<<3), RA2); // n = n+(n<<1) = 3*n + DP(AL, Add, RLINK, RLINK, (2<<3), RA2); // t' = &(initial t)[n*3] + LDW(AL, RLINK, R15, 4); // goto (initial t)[n*3+1] +} + +static void +macfrp(void) +{ + /* 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 void +maccolr(void) +{ + /* 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 void +macret(void) +{ + Inst i; + ulong *cp1, *cp2, *cp3, *cp4, *cp5, *linterp; + + 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(Heap,ref)-sizeof(Heap),RA2, RA3); + DPI(AL, Sub, RA3, RA3, 0, 1) | SBIT; + cp5 = code; + BRA(EQ, 0); // --ref(arg) == 0 + mem(Stw, O(Heap,ref)-sizeof(Heap),RA2, RA3); + + mem(Ldw, O(Frame,mr),RFP, RA1); + mem(Stw, O(REG,M),RREG, RA1); + mem(Ldw, O(Modlink,MP),RA1, RMP); + mem(Stw, O(REG,MP),RREG, RMP); + mem(Ldw, O(Modlink,compiled), RA1, RA3); // R.M->compiled + CMPI(AL, RA3, 0, 0, 0); + linterp = code; + BRA(EQ, 0); + + PATCH(cp4); + MOV(R15, R14); // call destroy(t(fp)) + MOV(RA0, R15); + + mem(Stw, O(REG,SP),RREG, RFP); + mem(Ldw, O(Frame,lr),RFP, RA1); + mem(Ldw, O(Frame,fp),RFP, RFP); + mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP + DP(AL, Mov, 0, R15, 0, RA1); // goto lr(Rfp), if compiled + + PATCH(linterp); + MOV(R15, R14); // call destroy(t(fp)) + MOV(RA0, R15); + + mem(Stw, O(REG,SP),RREG, RFP); + mem(Ldw, O(Frame,lr),RFP, RA1); + mem(Ldw, O(Frame,fp),RFP, RFP); + mem(Stw, O(REG,PC),RREG, RA1); // R.PC = fp->lr + mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP + mem(Ldw, O(REG, xpc), RREG, RLINK); + RETURN; // return to xec uncompiled code + + PATCH(cp1); + PATCH(cp2); + PATCH(cp3); + PATCH(cp5); + i.add = AXNON; + punt(&i, TCHECK|NEWPC, optab[IRET]); +} + +static void +macmcal(void) +{ + ulong *lab; + + CMPH(AL, RA0); + memc(NE, Ldw, O(Modlink, prog), RA3, RA1); // RA0 != H + CMPI(NE, RA1, 0, 0, 0); // RA0 != H + lab = code; + BRA(NE, 0); // RA0 != H && m->prog!=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(Heap, ref)-sizeof(Heap), RA3, RA1); + DPI(AL, Add, RA1, RA1, 0, 1); + mem(Stw, O(Heap, ref)-sizeof(Heap), RA3, RA1); + mem(Ldw, O(Modlink, MP), RA3, RMP); // MOVL R.M->mp, RMP + mem(Stw, O(REG, MP), RREG, RMP); // MOVL RA3, R.MP R.MP = ml->m + mem(Ldw, O(Modlink,compiled), RA3, RA1); // M.compiled? + CMPI(AL, RA1, 0, 0, 0); + DP(NE, Mov, 0, R15, 0, RA0); // return to compiled code + mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP + mem(Stw, O(REG,PC),RREG, RA0); // R.PC = RPC + mem(Ldw, O(REG, xpc), RREG, RLINK); + RETURN; // return to xec uncompiled code + flushcon(0); +} + +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); // nsp = R.SP + t->size + mem(Ldw, O(REG, TS), RREG, RA1); + CMP(AL, RA0, 0, 0, RA1); // nsp :: R.TS + lab1 = code; + BRA(CS, 0); // nsp >= R.TS; must expand + + 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); + mem(Stw, O(Frame,mr), RA2, RA0); // MOVL $0, mr(RA2) f->mr + mem(Ldw, O(Type, initialize), RA3, R15); // become t->init(RA2), returning RA2 + + PATCH(lab1); + 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.FP, RFP + 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 +} + +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; +} + +static void +macrelq(void) +{ + mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP + mem(Stw, O(REG,PC),RREG, RLINK); // R.PC = RLINK + mem(Ldw, O(REG, xpc), RREG, RLINK); + 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*); + } + flushchk(); + } + 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*); + } + flushchk(); + } + 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(exNomem); + + 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 > 3) + print("typ= %.8p %4d i %.8p d %.8p asm=%d\n", + t, t->size, t->initialize, t->destroy, n); +} + +extern ulong timer_start(void); +extern ulong timer_ticks(ulong); +extern ulong tmr2ms(ulong); +extern ulong tmr2us(ulong); +extern void timer_delay(); + +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) +{ + Link *l; + Modl *e; + 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; 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 > 3) + print("dis=%5d %5d 386=%5d asm=%.8p: %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("%lud != %d\n", patch[i], n); + urk("phase error"); + } + n += code - s; + if(cflag > 4) { + print("%3d %D\n", i, &m->prog[i]); + das(s, code-s); + } + } + + for(i = 0; i < nelem(mactab); i++) { + s = code; + mactab[i].gen(); + if(macro[mactab[i].idx] != n){ + print("mac phase err: %lud != %d\n", macro[mactab[i].idx], n); + urk("phase error"); + } + n += code - s; + if(cflag > 4) { + print("%s:\n", mactab[i].name); + das(s, code-s); + } + } + s = code; + flushcon(0); + n += code - s; + + for(l = m->ext; l->name; l++) { + l->u.pc = (Inst*)RELPC(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*)RELPC(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*)RELPC(patch[mod->entry-mod->prog]); + free(patch); + free(tinit); + free(tmp); + free(m->prog); + m->prog = (Inst*)base; + m->compiled = 1; + segflush(base, n*sizeof(*base)); + return 1; +bad: + free(patch); + free(tinit); + free(base); + free(tmp); + return 0; +} |
