From 37da2899f40661e3e9631e497da8dc59b971cbd0 Mon Sep 17 00:00:00 2001 From: "Charles.Forsyth" Date: Fri, 22 Dec 2006 17:07:39 +0000 Subject: 20060303a --- libinterp/comp-thumb.c | 2466 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2466 insertions(+) create mode 100644 libinterp/comp-thumb.c (limited to 'libinterp/comp-thumb.c') diff --git a/libinterp/comp-thumb.c b/libinterp/comp-thumb.c new file mode 100644 index 00000000..03aaa20e --- /dev/null +++ b/libinterp/comp-thumb.c @@ -0,0 +1,2466 @@ +#include "lib9.h" +#include "isa.h" +#include "interp.h" +#include "raise.h" + +#define RESCHED 1 /* check for interpreter reschedule */ + +enum +{ + R0 = 0, // why wasn't this used ? + R1 = 1, + R2 = 2, + R3 = 3, + R4 = 4, + R5 = 5, + R6 = 6, + R7 = 7, + R8 = 8, + R9 = 9, + R10 = 10, // unused + R11 = 11, // unused + R12 = 12, /* C's SB */ + R13 = 13, /* C's SP */ + R14 = 14, /* Link Register */ + R15 = 15, /* PC */ + + RSB = R12, + RLINK = R14, + RPC = R15, + + RTMP = R11, /* linker temp */ + RHT = R8, /* high temp */ + RFP = R7, /* Frame Pointer */ + RMP = R6, /* Module Pointer */ + 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 */ + RCON = R0, /* Constant builder */ + + 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, + Lsl = 2, + Lsr = 3, + Asr = 4, + Adc = 5, + Sbc = 6, + Ror = 7, + Tst = 8, + Neg = 9, + Cmp = 10, + Cmn = 11, + Orr = 12, + Mul = 13, + Bic = 14, + Mvn = 15, + + Mov = 16, + Cmpi = 17, + Add = 18, + Sub = 19, + + Cmph = 19, + Movh = 20, + + Lea = 100, /* macro memory ops */ + Ldw, + Ldb, + Stw, + Stb, + + NCON = (0x3fc-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 FIRSTPASS 0 +#define MIDDLEPASS 1 +#define LASTPASS 2 +static int pass; + +static void +OP(int o, int o1, int o2, char *s) +{ + if(o < o1 || o > o2) print("error: bad op %d in %s\n", o, s); +} + +static void +IMM(int i, int i1, int i2, char *s) +{ + if(i < i1 || i > i2) print("error: bad imm %d in %s\n", i, s); +} + +static void +MULT(int o, int m, char *s) +{ + if((o/m)*m != o) print("error: %d not multiple of %d in %s\n", o, m, s); +} + +static void +LOWREG(int r, char *s) +{ + if(r < 0 || r >= 8) print("error: %s: bad low reg %d\n", s, r); +} + +static void +HIGHREG(int r, char *s) +{ + if(r < 8) print("error: %s: bad high reg %d\n", s, r); +} + +static void +CKIRRS(int op, int i, int rm, int rd) +{ + OP(op, Lsl, Asr, "IRRS"); + IMM(i, 0, 31, "IRRS"); + LOWREG(rm, "IRRS rm"); + LOWREG(rd, "IRRS rd"); +} + +static void +CKRRR(int op, int rs, int rm, int rd) +{ + OP(op, Add, Sub, "RRR"); + LOWREG(rs, "RRR rs"); + LOWREG(rm, "RRR rm"); + LOWREG(rd, "RRR rd"); +} + +static void +CKIRR(int op, int i, int rm, int rd) +{ + OP(op, Add, Sub, "IRR"); + IMM(i, 0, 7, "IRR"); + LOWREG(rm, "IRR rm"); + LOWREG(rd, "IRR rd"); +} + +static void +CKIR(int op, int i, int rd) +{ + OP(op, Mov, Sub, "IR"); + IMM(i, 0, 255, "IR"); + LOWREG(rd, "IR rd"); +} + +static void +CKRR(int op, int rs, int rd) +{ + OP(op, And, Mvn, "RR"); + LOWREG(rs, "RR rs"); + LOWREG(rd, "RR rd"); +} + +static void +CKRH(int op, int rs, int rd) +{ + OP(op, Add, Movh, "RH"); + LOWREG(rs, "RH"); + HIGHREG(rd, "RH"); +} + +static void +CKHR(int op, int rs, int rd) +{ + OP(op, Add, Movh, "HR"); + HIGHREG(rs, "HR"); + LOWREG(rd, "HR"); +} + +static void +CKHH(int op, int rs, int rd) +{ + OP(op, Add, Movh, "HH"); + HIGHREG(rs, "HH"); + HIGHREG(rd, "HH"); +} + +static void +CKLS(int rn, int o, int rd, int s, int l) +{ + char buf[16]; + + sprint(buf, "LS %d %d", s, l); + LOWREG(rn, buf); + LOWREG(rd, buf); + MULT(o, s, buf); + IMM(o/s, 0, 31, buf); +} + +static void +CKLSR(int rn, int rm, int rd, int s, int l) +{ + char buf[16]; + + sprint(buf, "LSR %d %d", s, l); + LOWREG(rn, buf); + LOWREG(rm, buf); + LOWREG(rd, buf); +} + +static void +CKLPCR(int o, int rd) +{ + LOWREG(rd, "LPCR"); + if(o&3) + o += 2; + MULT(o, 4, "LPCR"); + IMM(o/4, 0, 255, "LPCR"); +} + +static void +CKB(int o) +{ + if(pass == FIRSTPASS) + return; + MULT(o, 2, "B"); + IMM(o, -2048, 2046, "B"); +} + +static void +CKBCC(int o) +{ + if(pass == FIRSTPASS) + return; + MULT(o, 2, "BCC"); + IMM(o, -256, 254, "BCC"); +} + +static void +CKBL(int o) +{ + if(pass == FIRSTPASS) + return; + MULT(o, 2, "BL"); + IMM(o, -4194304, 4194302, "BL"); +} + +#define DPIRRS(op, i, rm, rd) (CKIRRS(op, i, rm, rd), *code++ = ((op-Lsl)<<11) | (i<<6) | (rm<<3) | rd) +#define DPRRR(op, rs, rm, rd) (CKRRR(op, rs, rm, rd), *code++ = (6<<10) | ((op-Add)<<9) | (rs<<6) | (rm<<3) | rd) +#define DPIRR(op, i, rm, rd) (CKIRR(op, i, rm, rd), *code++ = (7<<10) | ((op-Add)<<9) | (i<<6) | (rm<<3) | rd) +#define DPIR(op, i, rd) (CKIR(op, i, rd), *code++ = (1<<13) | ((op-Mov)<<11) | (rd<<8) | i) +#define DPRR(op, rs, rd) (CKRR(op, rs, rd), *code++ = (1<<14) | (op<<6) | (rs<<3) | rd) + +#define DPRH(op, rs, hd) (CKRH(op, rs, hd), *code++ = (17<<10) | ((op-Add)<<8) | (1<<7) | (rs<<3) | (hd-8)) +#define DPHR(op, hs, rd) (CKHR(op, hs, rd), *code++ = (17<<10) | ((op-Add)<<8) | (1<<6) | ((hs-8)<<3) | rd) +#define DPHH(op, hs, hd) (CKHH(op, hs, hd), *code++ = (17<<10) | ((op-Add)<<8) | (3<<6) | ((hs-8)<<3) | (hd-8)) + +#define LDW(rs, o, rd) (CKLS(rs, o, rd, 4, 1), *code++ = (13<<11)|((o/4)<<6)|(rs<<3)|rd) +#define STW(rs, o, rd) (CKLS(rs, o, rd, 4, 0), *code++ = (12<<11)|((o/4)<<6)|(rs<<3)|rd) +#define LDH(rs, o, rd) (CKLS(rs, o, rd, 2, 0), *code++ = (17<<11)|((o/2)<<6)|(rs<<3)|rd) +#define STH(rs, o, rd) (CKLS(rs, o, rd, 2, 1), *code++ = (16<<11)|((o/2)<<6)|(rs<<3)|rd) +#define LDB(rs, o, rd) (CKLS(rs, o, rd, 1, 1), *code++ = (15<<11)|(o<<6)|(rs<<3)|rd) +#define STB(rs, o, rd) (CKLS(rs, o, rd, 1, 0), *code++ = (14<<11)|(o<<6)|(rs<<3)|rd) +#define LDRW(rs, rm, rd) (CKLSR(rs, rm, rd, 4, 1), *code++ = (44<<9)|(rs<<6)|(rm<<3)|rd) +#define STRW(rs, rm, rd) (CKLSR(rs, rm, rd, 4, 1), *code++ = (40<<9)|(rs<<6)|(rm<<3)|rd) +#define LDRH(rs, rm, rd) (CKLSR(rs, rm, rd, 4, 1), *code++ = (45<<9)|(rs<<6)|(rm<<3)|rd) +#define STRH(rs, rm, rd) (CKLSR(rs, rm, rd, 4, 1), *code++ = (41<<9)|(rs<<6)|(rm<<3)|rd) +#define LDRB(rs, rm, rd) (CKLSR(rs, rm, rd, 4, 1), *code++ = (46<<9)|(rs<<6)|(rm<<3)|rd) +#define STRB(rs, rm, rd) (CKLSR(rs, rm, rd, 4, 1), *code++ = (42<<9)|(rs<<6)|(rm<<3)|rd) + +#define LDWPCREL(o, rd) (CKLPCR(o, rd), *code++ = (9<<11)|(rd<<8)|(o/4)) + +#define CMPI(i, rn) DPIR(Cmpi, i, rn) +#define CMP(rs, rn) DPRR(Cmp, rs, rn) +#define CMPRH(rs, rn) DPRH(Cmph, rs, rn) +#define CMPHR(rs, rn) DPHR(Cmph, rs, rn) +#define CMPHH(rs, rn) DPHH(Cmph, rs, rn) +#define MOV(src, dst) DPIRRS(Lsl, 0, src, dst) +#define MOVRH(s, d) DPRH(Movh, s, d) +#define MOVHR(s, d) DPHR(Movh, s, d) +#define MOVHH(s, d) DPHH(Movh, s, d) +#define MUL(rs, rd) DPRR(Mul, rs, rd) + +#define CODE (code+codeoff) +#define IA(s, o) (ulong)(base+s[o]) +#define RELPC(pc) (ulong)(base+(pc)) + +#define RINV(c) ((c)&1 ? (c)-1 : (c)+1) +#define FPX(fp) (((ulong)(fp))&~1) +#define NOBR 4 + +#define BRAU(o) ((28<<11) | (((o)>>1)&0x7ff)) +#define BRAC(c, o) ((13<<12) | ((c)<<8) | (((o)>>1)&0xff)) +#define BRAL1(o) ((30<<11) | ((o)&0x7ff)) +#define BRAL2(o) ((31<<11) | ((o)&0x7ff)) + +#define CJUMP(c, o) CBRA(RINV(c), o) +#define BRA(o) (CKB((o)-4), gen(BRAU((o)-4))) +#define CBRA(c, o) (CKBCC((o)-4), gen(BRAC(c, (o)-4))) +#define BRADIS(o) branch(IA(patch, o)-(ulong)CODE) +#define CBRADIS(c, o) cbranch(c, IA(patch, o)-(ulong)CODE) +#define BRAMAC(o) branch(IA(macro, o)-(ulong)CODE) +#define RETURN MOVHH(RLINK, RPC) +#define CALL(o) call((ulong)(FPX(o))-(ulong)CODE) +#define CALLMAC(o) call(IA(macro, o)-(ulong)CODE) + +#define PATCH(ptr) (CKB((ulong)code-(ulong)ptr-4), *ptr |= (((ulong)code-(ulong)(ptr)-4)>>1) & 0x7ff) +#define CPATCH(ptr) (CKBCC((ulong)code-(ulong)ptr-4), *ptr |= (((ulong)code-(ulong)(ptr)-4)>>1) & 0xff) +#define BPATCH(ptr) ((ulong)ptr-(ulong)code) + +/* long branches */ +#define DWORD(o) (*code++ = (o)&0xffff, *code++ = ((o)>>16)&0xffff) +#define BRALONG(o) (LDWPCREL(0, RCON), MOVRH(RCON, RPC), DWORD(o+(ulong)code-4)) +#define CALLLONG(o) (MOVHR(RPC, RCON), DPIR(Add, 10, RCON), MOVRH(RCON, RLINK), BRALONG(o)) + +#define PAD() MOVHH(RSB, RSB) + +#define BITS(B) (1<>2) +#define SUBSP(o) *code++ = (11<<12) | (1<<7) | (o>>2) +#define LDSP(o, r) *code++ = (19<<11) | (r<<8) | (o>>2) +#define STSP(o, r) *code++ = (18<<11) | (r<<8) | (o>>2) + +static ushort* code; +static ushort* base; +static ulong* patch; +static ulong codeoff; +static Module* mod; +static uchar* tinit; +static ushort* 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(ushort*, 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; + ushort* code; + ushort* pc; +}; + +typedef struct Con Con; +struct Con +{ + int ptr; + Const table[NCON]; +}; +static Con rcon; + +static void gen(ulong), genc(ulong); + +/* only CBRADIS could be too long by the look of things */ +static void +cbranch(int c, long o) +{ + long off = o-4; + + if(pass == FIRSTPASS || (off >= -256 && off <= 254)) + CBRA(c, o); + else if(off >= -2046 && off <= 2048){ + CBRA(RINV(c), 4); + BRA(o-2); + } + else{ + if(!((int)CODE&2)) + PAD(); + CBRA(RINV(c), 10); + BRALONG(o); + } +} + +/* only BRADIS, BRAMAC could be too long */ +static void +branch(long o) +{ + long off = o-4; + + if(pass == FIRSTPASS || (off >= -2048 && off <= 2046)) + BRA(o); + else{ + if((int)CODE&2) + PAD(); + BRALONG(o); + } +} + +static void +call(long o) +{ + long off = o-4; + + if(pass == FIRSTPASS || (off >= -4194304 && off <= 4194302)) + genc(o); + else{ + if(!((int)CODE&2)) + PAD(); + CALLLONG(o); + } +} + +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 void +genc(ulong o) +{ + o -= 4; + CKBL(o); + *code++ = BRAL1(o>>12); + *code++ = BRAL2(o>>1); +} + +static void +flushcon(int genbr) +{ + int i; + Const *c; + ulong disp; + + if(rcon.ptr == 0) + return; + if(genbr ^ (((int)CODE&2)>>1)) + PAD(); + if(genbr) + BRA(rcon.ptr*4+2); + c = &rcon.table[0]; + for(i = 0; i < rcon.ptr; i++) { + if(pass == LASTPASS){ + disp = (code - c->code) * sizeof(*code) - 4; + if(disp >= BITS(10)) + print("error: INVALID constant range %lud", disp); + CKLPCR(disp, R0); // any reg will do + if(disp & 3) + disp += 2; // ensure M(4) offset + *c->code |= (disp/4); + } + *code++ = (c->o)&0xffff; + *code++ = (c->o >> 16)&0xffff; + 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(10)-256) // 256 allows for a little delay in calling flushchk + flushcon(1); +} + +static void +con(ulong o, int r, int opt) +{ + Const *c; + + LOWREG(r, "con"); + if(opt != 0) { + if(o >= 0 && o <= 255){ + DPIR(Mov, o, r); + return; + } + if(-o >= 0 && -o <= 255){ + DPIR(Mov, -o, r); + DPRR(Neg, r, r); + return; + } + if(o >= 256 && o <= 510){ + DPIR(Mov, 255, r); + DPIR(Add, o-255, r); + return; + } + if(o > 0){ + int n = 0; + ulong m = o; + + while(!(m & 1)){ + n++; + m >>= 1; + } + if(m >= 0 && m <= 255){ + DPIR(Mov, m, r); + DPIRRS(Lsl, n, r, r); + return; + } + } + } + flushchk(); + c = &rcon.table[rcon.ptr++]; + c->o = o; + c->code = code; + c->pc = code+codeoff; + LDWPCREL(0, r); +} + +static void +mem(int inst, ulong disp, int rm, int r) +{ + LOWREG(rm, "mem"); + LOWREG(r, "mem"); + LOWREG(RCON, "mem"); + if(inst == Lea) { + if(rm == r){ + if(disp < BITS(8)){ + DPIR(Add, disp, r); + return; + } + if(-disp < BITS(8)){ + DPIR(Sub, -disp, r); + return; + } + } + else{ + if(disp < BITS(3)){ + DPIRR(Add, disp, rm, r); + return; + } + if(-disp < BITS(3)){ + DPIRR(Sub, -disp, rm, r); + return; + } + } + con(disp, RCON, 1); + DPRRR(Add, RCON, rm, r); + return; + } + + switch(inst) { + case Ldw: + if(disp < BITS(7)){ + LDW(rm, disp, r); + return; + } + break; + case Ldb: + if(disp < BITS(5)){ + LDB(rm, disp, r); + return; + } + break; + case Stw: + if(disp < BITS(7)){ + STW(rm, disp, r); + return; + } + break; + case Stb: + if(disp < BITS(5)){ + STB(rm, disp, r); + return; + } + break; + } + + con(disp, RCON, 1); + switch(inst) { + case Ldw: + LDRW(rm, RCON, r); + break; + case Ldb: + LDRB(rm, RCON, r); + break; + case Stw: + STRW(rm, RCON, r); + break; + case Stb: + STRB(rm, RCON, r); + break; + } +} + +static void +memh(int inst, ulong disp, int rm, int r) +{ + HIGHREG(r, "memh"); + if(inst == Stw || inst == Stb) + MOVHR(r, RCON); + mem(inst, disp, rm, RCON); + if(inst != Stw && inst != Stb) + MOVRH(RCON, 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; + } + if(mi == Lea || mi == Ldb || mi == Ldw) + rta = r; + else if(r == RA3) /* seems safe - have to squeeze reg use */ + rta = RA2; + else + rta = RA3; + 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 +literal(ulong imm, int roff) +{ + nlit++; + + con((ulong)litpool, RCON, 0); + mem(Stw, roff, RREG, RCON); + + if(pass != LASTPASS) + return; + + *litpool++ = imm&0xffff; + *litpool++ = (imm>>16)&0xffff; +} + +static void +schedcheck(Inst *i) +{ + ushort *label; + + if(RESCHED && i->d.ins <= i){ + mem(Ldw, O(REG, IC), RREG, RA0); + DPIR(Sub, 1, RA0); + mem(Stw, O(REG, IC), RREG, RA0); + /* CMPI(1, RA0); */ + label = code; + CBRA(LE, NOBR); + /* CJUMP(LE, NOBR); */ + CALLMAC(MacRELQ); + CPATCH(label); + } +} + +static void +bounds(void) +{ + /* mem(Stw, O(REG,FP), RREG, RFP); */ + error(exBounds); +} + +/* +static void +called(int x) +{ + extern void ttrace(void); + + if(x) + mem(Stw, O(REG, FP), RREG, RFP); + CALL(ttrace); + con((ulong)&R, RREG, 1); + mem(Ldw, O(REG, FP), RREG, RFP); + mem(Ldw, O(REG, MP), RREG, RMP); +} +*/ + +static void +punt(Inst *i, int m, void (*fn)(void)) +{ + ulong pc; + ushort *label; + + 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(0, RA0); + label = code; + CJUMP(NE, NOBR); + memh(Ldw, O(REG, xpc), RREG, RLINK); + RETURN; /* if(R.t) goto(R.xpc) */ + CPATCH(label); + } + mem(Ldw, O(REG, FP), RREG, RFP); + mem(Ldw, O(REG, MP), RREG, RMP); + + if(m & NEWPC){ + memh(Ldw, O(REG, PC), RREG, RPC); + flushcon(0); + } +} + +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(i->s.imm, RA1); + r = swapbraop(r); + } else if((i->add & ARM) == AXIMM && FITS8(i->reg)) { + opwld(i, Ldw, RA1); + CMPI(i->reg, RA1); + } else { + opwld(i, Ldw, RA0); + mid(i, Ldw, RA1); + CMP(RA1, RA0); + } + CBRADIS(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(i->s.imm&0xff, RA1); + r = swapbraop(r); + } else if((i->add & ARM) == AXIMM) { + opwld(i, Ldb, RA1); + CMPI(i->reg&0xff, RA1); + } else { + opwld(i, Ldb, RA0); + mid(i, Ldb, RA1); + CMP(RA1, RA0); + } + CBRADIS(r, i->d.ins-mod->prog); +} + +static void +cbral(Inst *i, int jmsw, int jlsw, int mode) +{ + ulong dst; + ushort *label; + + if(RESCHED) + schedcheck(i); + opwld(i, Lea, RA1); + mid(i, Lea, RA3); + mem(Ldw, 0, RA1, RA2); + mem(Ldw, 0, RA3, RA0); + CMP(RA0, RA2); + label = nil; + dst = i->d.ins-mod->prog; + switch(mode) { + case ANDAND: + label = code; + CBRA(jmsw, NOBR); + break; + case OROR: + CBRADIS(jmsw, dst); + break; + case EQAND: + CBRADIS(jmsw, dst); + label = code; + CBRA(NE, NOBR); + break; + } + mem(Ldw, 4, RA3, RA0); + mem(Ldw, 4, RA1, RA2); + CMP(RA0, RA2); + CBRADIS(jlsw, dst); + if(label != nil) + CPATCH(label); +} + +static void +cbraf(Inst *i, int r) +{ + USED(r); + if(RESCHED) + schedcheck(i); + 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(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 == FIRSTPASS || pass == MIDDLEPASS) { + 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 == FIRSTPASS || pass == MIDDLEPASS) { + 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) +{ + ushort *punt, *mlnil; + + opwld(i, Ldw, RA0); + CMPH(RA0, RA3); + mlnil = code; + CBRA(EQ, NOBR); + + if((i->add&ARM) == AXIMM) { + mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame), RA0, RA3); + } else { + mid(i, Ldw, RA1); + // RA1 = RA0 + (RA1<<3) + DPIRRS(Lsl, 3, RA1, RA1); + DPRRR(Add, RA0, RA1, RA1); // assumes sizeof(Modl) == 8 + mem(Ldw, OA(Modlink, links)+O(Modl, frame), RA1, RA3); + } + + mem(Ldw, O(Type, initialize), RA3, RA1); + CMPI(0, RA1); + punt = code; + CBRA(NE, NOBR); + + opwst(i, Lea, RA0); + + /* Type in RA3, destination in RA0 */ + CPATCH(mlnil); + con(RELPC(patch[i-mod->prog+1]), RA2, 0); + MOVRH(RA2, RLINK); + BRAMAC(MacMFRA); + + /* Type in RA3 */ + CPATCH(punt); + CALLMAC(MacFRAM); + opwst(i, Stw, RA2); +} + +static void +commcall(Inst *i) +{ + ushort *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(RA3, RA0); + mlnil = code; + CBRA(EQ, NOBR); + 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); + DPIRRS(Lsl, 3, RA1, RA1); + DPRRR(Add, RA1, RA3, RA1); // assumes sizeof(Modl) == 8 + mem(Ldw, OA(Modlink, links)+O(Modl, u.pc), RA1, RA0); + } + CPATCH(mlnil); + CALLMAC(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); + if(op == Add || op == Sub) + DPRRR(op, RA1, RA2, RA2); + else + DPRR(op, RA1, RA2); // ls: RA2 = RA2 op RA1 + mem(Ldw, 0, RA0, RA1); + mem(Ldw, 0, RA3, RA0); + DPRR(opc, RA1, RA0); // 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) +{ + ushort *label; + + opwst(i, Lea, RA2); + label = code; + if(s == 1) + LDB(RA1, 0, RA0); + else + LDW(RA1, 0, RA0); + DPIR(Add, s, RA1); + if(s == 1) + STB(RA2, 0, RA0); + else + STW(RA2, 0, RA0); + DPIR(Add, s, RA2); + DPIR(Sub, 1, RA3); + CBRA(NE, BPATCH(label)); +} + +static void +movmem(Inst *i) +{ + ushort *cp; + + // source address already in RA1 + if((i->add&ARM) != AXIMM){ + mid(i, Ldw, RA3); + CMPI(0, RA3); + cp = code; + CBRA(LE, NOBR); + movloop(i, 1); + CPATCH(cp); + return; + } + switch(i->reg){ + case 0: + break; + case 4: + LDW(RA1, 0, RA2); + opwst(i, Stw, RA2); + break; + case 8: + LDW(RA1, 0, RA2); + opwst(i, Lea, RA3); + LDW(RA1, 4, RA1); + STW(RA3, 0, RA2); + STW(RA3, 4, RA1); + 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); + DPIRRS(Lsl, 2, RA1, RA1); + LDRW(RA0, RA1, RA0); + MOVRH(RA0, RPC); + flushcon(0); + + if(pass != LASTPASS) + 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]; + ushort *label, *label1; + + 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 IMODW: + case IMODB: + case IDIVW: + case IDIVB: + SUBSP(8); + mid(i, Ldw, RA0); + MOVRH(RA0, RTMP); + opwld(i, Ldw, RA0); + STSP(4, RA0); // movw RA0, 4(SP) + call // need to save, restore context + MOVHR(RTMP, RA0); + opwst(i, Stw, RA0); + ADDSP(8); +*/ + 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 IHEADF: + 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); + //comcase(i, 0); + //punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]); break; + break; + case IGOTO: + comgoto(i); + //punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]); break; + break; + case IMOVL: + case IMOVF: + opwld(i, Lea, RA1); + LDW(RA1, 0, RA2); + LDW(RA1, 4, RA3); + opwst(i, Lea, RA1); + STW(RA1, 0, RA2); + STW(RA1, 4, RA3); + break; + case IHEADM: + //punt(i, SRCOP|DSTOP, optab[i->op]); break; + opwld(i, Ldw, RA1); + NOTNIL(RA1, RA2); + DPIR(Add, OA(List,data), RA1); + movmem(i); + break; + case IMOVM: + //punt(i, SRCOP|DSTOP, optab[i->op]); break; + 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 IHEADW: + opwld(i, Ldw, RA0); + mem(Ldw, OA(List, data), RA0, RA0); + opwst(i, Stw, RA0); + break; + case IHEADB: + opwld(i, Ldw, RA0); + mem(Ldb, OA(List, data), RA0, RA0); + opwst(i, Stb, RA0); + break; + case IHEADL: + case IHEADF: + opwld(i, Ldw, RA0); + mem(Lea, OA(List, data), RA0, RA0); + LDW(RA0, 0, RA1); + LDW(RA0, 4, RA2); + opwst(i, Lea, RA0); + STW(RA0, 0, RA1); + STW(RA0, 4, RA2); + 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, RA1); + 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, RA1); + mem(Ldw, OA(List, data), RA0, RA1); + movp: + CMPH(RA1, RA2); + label = code; + CJUMP(NE, NOBR); + CALLMAC(MacCOLR); // colour if not H + CPATCH(label); + opwst(i, Lea, RA2); + mem(Ldw, 0, RA2, RA0); + mem(Stw, 0, RA2, RA1); + CALLMAC(MacFRP); + break; + case ILENA: + opwld(i, Ldw, RA1); + con(0, RA0, 1); + CMPH(RA1, RA2); + CJUMP(NE, 4); + LDW(RA1, O(Array,len), RA0); + opwst(i, Stw, RA0); + break; + case ILENC: + opwld(i, Ldw, RA1); + con(0, RA0, 1); + CMPH(RA1, RA2); + label = code; + CJUMP(NE, NOBR); + mem(Ldw, O(String,len),RA1, RA0); + CPATCH(label); + CMPI(0, RA0); + CJUMP(LT, 4); + DPRR(Neg, RA0, RA0); + opwst(i, Stw, RA0); + break; + case ILENL: + con(0, RA0, 1); + opwld(i, Ldw, RA1); + + label = code; + CMPH(RA1, RA2); + label1 = code; + CJUMP(NE, NOBR); + LDW(RA1, O(List, tail), RA1); + DPIR(Add, 1, RA0); + BRA(BPATCH(label)); + CPATCH(label1); + + 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(i->d.ins-mod->prog); + flushcon(0); + break; + case IJMP: + if(RESCHED) + schedcheck(i); + BRADIS(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: + //punt(i, TCHECK|NEWPC, optab[i->op]); break; + mem(Ldw, O(Frame,t), RFP, RA1); + BRAMAC(MacRET); + break; + case IMULW: + opwld(i, Ldw, RA1); + mid(i, Ldw, RA0); + MUL(RA1, RA0); + opwst(i, Stw, RA0); + break; + case IMULB: + opwld(i, Ldb, RA1); + mid(i, Ldb, RA0); + MUL(RA1, 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((r == Add || r == Sub) && UXSRC(i->add) == SRC(AIMM) && FITS3(i->s.imm)){ + DPIRR(r, i->s.imm, RA1, RA0); + opwst(i, Stw, RA0); + } + else { + opwld(i, Ldw, RA0); + if(r == Add || r == Sub){ + DPRRR(r, RA0, RA1, RA0); + opwst(i, Stw, RA0); + } + else{ + DPRR(r, RA0, RA1); + opwst(i, Stw, RA1); + } + } + break; + case ISHRW: + r = Asr; + shiftw: + mid(i, Ldw, RA1); + if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm)){ + DPIRRS(r, i->s.imm, RA1, RA0); + opwst(i, Stw, RA0); + } + else { + opwld(i, Ldw, RA0); + DPRR(r, RA0, RA1); + opwst(i, Stw, RA1); + } + break; + case ISHLW: + r = Lsl; + goto shiftw; + break; + case ILSRW: + r = Lsr; + 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((r == Add || r == Sub) && UXSRC(i->add) == SRC(AIMM) && FITS3(i->s.imm)){ + DPIRR(r, i->s.imm, RA1, RA0); + opwst(i, Stb, RA0); + } + else { + opwld(i, Ldb, RA0); + if(r == Add || r == Sub){ + DPRRR(r, RA0, RA1, RA0); + opwst(i, Stb, RA0); + } + else{ + DPRR(r, RA0, RA1); + opwst(i, Stb, RA1); + } + } + break; + case ISHRB: + r = Asr; + goto shiftb; + case ISHLB: + r = Lsl; + shiftb: + mid(i, Ldb, RA1); + if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm)){ + DPIRRS(r, i->s.imm, RA1, RA0); + opwst(i, Stb, RA0); + } + else { + opwld(i, Ldw, RA0); + DPRR(r, RA0, RA1); + opwst(i, Stb, RA1); + } + break; + case IINDC: + opwld(i, Ldw, RA1); // RA1 = string + NOTNIL(RA1, RA2); + 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)) + DPIR(Add, O(String,data), RA1); + CMPI(0, RA0); + if(imm){ + label = code; + CJUMP(GE, NOBR); + if(i->reg < BITS(5)) + LDB(RA1, i->reg, RA3); + else{ + con(i->reg, RCON, 1); + LDRB(RA1, RCON, RA3); + } + CPATCH(label); + label = code; + CJUMP(LT, NOBR); + if((ushort)((short)i->reg<<1) < BITS(6)) + LDH(RA1, (short)i->reg<<1, RA3); + else{ + con((short)i->reg<<1, RCON, 1); + LDRH(RA1, RCON, RA3); + } + CPATCH(label); + } else { + CJUMP(GE, 4); + LDRB(RA1, RA2, RA3); + CJUMP(LT, 6); + DPIRRS(Lsl, 1, RA2, RA2); + LDRH(RA1, RA2, RA3); + } + opwst(i, Stw, RA3); + break; + case IINDL: + case IINDF: + case IINDW: + case IINDB: + opwld(i, Ldw, RA0); /* a */ + NOTNIL(RA0, RA1); + 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; + // case IMOVF: + // punt(i, SRCOP|DSTOP, optab[i->op]); + // break; + case IDIVF: + goto arithf; + case IMULF: + goto arithf; + case ISUBF: + goto arithf; + case IADDF: + arithf: + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + break; + case INEGF: + punt(i, SRCOP|DSTOP, optab[i->op]); + break; + case ICVTWF: + punt(i, SRCOP|DSTOP, optab[i->op]); + break; + case ICVTFW: + punt(i, SRCOP|DSTOP, optab[i->op]); + 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 = (ushort*)comvec; + + con((ulong)&R, RREG, 0); + memh(Stw, O(REG, xpc), RREG, RLINK); + mem(Ldw, O(REG, FP), RREG, RFP); + mem(Ldw, O(REG, MP), RREG, RMP); + memh(Ldw, O(REG, PC), RREG, RPC); + pass = LASTPASS; + flushcon(0); + pass = FIRSTPASS; + // print("preamble\n"); + // das((ushort*)comvec, code-(ushort*)comvec); + segflush(comvec, 10 * sizeof(*code)); + comvec =(void *)((ulong)comvec | 1); /* T bit */ +} + +static void +maccase(void) +{ + ushort *cp1, *loop, *inner, *label; +/* + * RA1, RHT = value (input arg), t + * RA2 = count, n + * RA3 = table pointer (input arg) + * RA0 = n/2, n2 + * RCON = pivot element t+n/2*3, l + */ + MOVRH(RA1, RHT); + LDW(RA3, 0, RA2); // count from table + MOVRH(RA3, RLINK); // initial table pointer + + loop = code; // loop: + CMPI(0, RA2); + cp1 = code; + CBRA(LE, NOBR); // n <= 0? goto out + + inner = code; + DPIRRS(Lsr, 1, RA2, RA0); + DPIRRS(Lsl, 1, RA0, RCON); + DPRRR(Add, RA0, RCON, RCON); + DPIRRS(Lsl, 2, RCON, RCON); + DPRRR(Add, RA3, RCON, RCON); + + LDW(RCON, 4, RA1); + CMPRH(RA1, RHT); + label = code; + CJUMP(LT, NOBR); + MOV(RA0, RA2); + BRA(BPATCH(loop)); // v < l[1]? goto loop + CPATCH(label); + + LDW(RCON, 8, RA1); + CMPRH(RA1, RHT); + CJUMP(LT, 6); + LDW(RCON, 12, RA1); + MOVRH(RA1, RPC); // v >= l[1] && v < l[2] => found; goto l[3] + + // v >= l[2] (high) + DPIRR(Add, 7, RCON, RA3); + DPIR(Add, 5, RA3); + DPIRR(Add, 1, RA0, RA1); + DPRRR(Sub, RA1, RA2, RA2); + CBRA(GT, BPATCH(inner)); // n > 0? goto loop + + CPATCH(cp1); // out: + MOVHR(RLINK, RA2); + LDW(RA2, 0, RA2); // initial n + DPIRRS(Lsl, 1, RA2, RA0); + DPRRR(Add, RA2, RA0, RA2); + DPIRRS(Lsl, 2, RA2, RA2); + DPRH(Add, RA2, RLINK); + MOVHR(RLINK, RA2); + LDW(RA2, 4, RA1); + MOVRH(RA1, RPC); // goto (initial t)[n*3+1] +} + +static void +macfrp(void) +{ + ushort *label; + + /* destroy the pointer in RA0 */ + CMPH(RA0, RA2); + CJUMP(EQ, 4); + RETURN; // arg == H? => return + + mem(Ldw, O(Heap, ref)-sizeof(Heap), RA0, RA2); + DPIR(Sub, 1, RA2); + label = code; + CJUMP(NE, NOBR); + mem(Stw, O(Heap, ref)-sizeof(Heap), RA0, RA2); + RETURN; // --h->ref != 0 => return + CPATCH(label); + + mem(Stw, O(REG, FP), RREG, RFP); + memh(Stw, O(REG, st), RREG, RLINK); + mem(Stw, O(REG, s), RREG, RA0); + CALL(rdestroy); + con((ulong)&R, RREG, 1); + memh(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); + DPIR(Add, 1, RA0); + 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(RA2, RA0); + CJUMP(EQ, 4); + RETURN; // 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; + ushort *cp1, *cp2, *cp3, *cp4, *cp5, *linterp; + + CMPI(0, RA1); + cp1 = code; + CBRA(EQ, NOBR); // t(Rfp) == 0 + + mem(Ldw, O(Type,destroy),RA1, RA0); + CMPI(0, RA0); + cp2 = code; + CBRA(EQ, NOBR); // destroy(t(fp)) == 0 + + mem(Ldw, O(Frame,fp),RFP, RA2); + CMPI(0, RA2); + cp3 = code; + CBRA(EQ, NOBR); // fp(Rfp) == 0 + + mem(Ldw, O(Frame,mr),RFP, RA3); + CMPI(0, RA3); + cp4 = code; + CBRA(EQ, NOBR); // mr(Rfp) == 0 + + mem(Ldw, O(REG,M),RREG, RA2); + mem(Ldw, O(Heap,ref)-sizeof(Heap),RA2, RA3); + DPIR(Sub, 1, RA3); + cp5 = code; + CBRA(EQ, NOBR); // --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(0, RA3); + linterp = code; + CBRA(EQ, NOBR); + + CPATCH(cp4); + MOVHH(RPC, RLINK); // call destroy(t(fp)) + MOVRH(RA0, RPC); + + 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 + MOVRH(RA1, RPC); + + CPATCH(linterp); + MOVHH(RPC, RLINK); // call destroy(t(fp)) + MOVRH(RA0, RPC); + + 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 + memh(Ldw, O(REG, xpc), RREG, RLINK); + RETURN; // return to xec uncompiled code + + CPATCH(cp1); + CPATCH(cp2); + CPATCH(cp3); + CPATCH(cp5); + i.add = AXNON; + punt(&i, TCHECK|NEWPC, optab[IRET]); +} + +static void +macmcal(void) +{ + ushort *lab, *label; + + CMPH(RA0, RA1); + label = code; + CJUMP(NE, NOBR); + mem(Ldw, O(Modlink, prog), RA3, RA1); // RA0 != H + CMPI(0, RA1); // RA0 != H + lab = code; + CBRA(NE, NOBR); // RA0 != H && m->prog!=0 + CPATCH(label); + + memh(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 + memh(Ldw, O(REG, st), RREG, RLINK); + mem(Ldw, O(REG, FP), RREG, RFP); + mem(Ldw, O(REG, MP), RREG, RMP); + RETURN; + + CPATCH(lab); // patch: + MOV(RA2, RFP); + mem(Stw, O(REG, M), RREG, RA3); // MOVL RA3, R.M + mem(Ldw, O(Heap, ref)-sizeof(Heap), RA3, RA1); + DPIR(Add, 1, RA1); + 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(0, RA1); + CJUMP(NE, 4); + MOVRH(RA0, RPC); + mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP + mem(Stw, O(REG,PC),RREG, RA0); // R.PC = RPC + memh(Ldw, O(REG, xpc), RREG, RLINK); + RETURN; // return to xec uncompiled code + flushcon(0); +} + +static void +macfram(void) +{ + ushort *lab1; + + mem(Ldw, O(REG, SP), RREG, RA0); // MOVL R.SP, RA0 + mem(Ldw, O(Type, size), RA3, RA1); + DPRRR(Add, RA0, RA1, RA0); + mem(Ldw, O(REG, TS), RREG, RA1); + CMP(RA1, RA0); // nsp :: R.TS + lab1 = code; + CBRA(CS, NOBR); // 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 + memh(Ldw, O(Type, initialize), RA3, RPC); // become t->init(RA2), returning RA2 + + CPATCH(lab1); + mem(Stw, O(REG, s), RREG, RA3); + memh(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); + memh(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) +{ + memh(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); + memh(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 + memh(Stw, O(REG,PC),RREG, RLINK); // R.PC = RLINK + memh(Ldw, O(REG, xpc), RREG, RLINK); + RETURN; +} + +void +comd(Type *t) +{ + int i, j, m, c; + + memh(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(); + } + memh(Ldw, O(REG, dt), RREG, RLINK); + RETURN; + flushcon(0); +} + +void +comi(Type *t) +{ + int i, j = 0, m, c, r; + + if(t->np > 4){ + r = RA3; + MOV(RA2, RA3); + } + else + r = RA2; + con((ulong)H, RA0, 1); + for(i = 0; i < t->np; i++) { + c = t->map[i]; + if(j == 128){ + if(t->np <= 4) print("error: bad j in comi\n"); + DPIR(Add, 128, RA3); + j = 0; + } + for(m = 0x80; m != 0; m >>= 1) { + if(c & m) + mem(Stw, j, r, RA0); + j += sizeof(WORD*); + } + flushchk(); + } + RETURN; + flushcon(0); +} + +void +typecom(Type *t) +{ + int n; + ushort *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); + +// print("type\n"); +// das(start, code-start); + + if(cflag > 1) + print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n", + t, t->size, t->initialize, t->destroy, n); +} + +static void +patchex(Module *m, ulong *p) +{ + Handler *h; + Except *e; + + if((h = m->htab) == nil) + return; + for( ; h->etab != nil; h++){ + h->pc1 = p[h->pc1]; + h->pc2 = p[h->pc2]; + for(e = h->etab; e->s != nil; e++) + e->pc = p[e->pc]; + if(e->pc != -1) + e->pc = p[e->pc]; + } +} + +int +compile(Module *m, int size, Modlink *ml) +{ + Link *l; + Modl *e; + int i, n; + ushort *s, *tmp; + int again, lastc = 0, lastn = 0; + + base = nil; + patch = mallocz(size*sizeof(*patch), 0); + tinit = malloc(m->ntype*sizeof(*tinit)); + tmp = malloc(4096*sizeof(ulong)); + base = tmp; + if(tinit == nil || patch == nil || tmp == nil) + goto bad; + + preamble(); + + mod = m; + pass = FIRSTPASS; + + do{ + again = 0; + n = 0; + nlit = 0; + + for(i = 0; i < size; i++) { + codeoff = n; + code = tmp; + comp(&m->prog[i]); + if(patch[i] != n) + again = 1; + patch[i] = n; + n += code - tmp; + } + + for(i = 0; i < nelem(mactab); i++) { + codeoff = n; + code = tmp; + mactab[i].gen(); + if(macro[mactab[i].idx] != n) + again = 1; + macro[mactab[i].idx] = n; + n += code - tmp; + } + code = tmp; + flushcon(0); + n += code - tmp; + if(code-tmp != lastc || n != lastn) + again = 1; + lastc = code-tmp; + lastn = n; + + if(pass == FIRSTPASS) + pass = MIDDLEPASS; + + }while(again); + + 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 = LASTPASS; + 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("error: %lud != %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; i < nelem(mactab); i++) { + s = code; + mactab[i].gen(); + if(macro[mactab[i].idx] != n){ + print("error: mac phase err: %lud != %d\n", macro[mactab[i].idx], n); + urk("phase error"); + } + 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->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)); +// print("comvec at %lux\n", (ulong)comvec); +// print("base at %lux-%lux\n", (ulong)base, (ulong)base+2*n); +// print("entry %lux prog %lux\n", (ulong)m->entry, (ulong)m->prog); + return 1; +bad: + free(patch); + free(tinit); + free(base); + free(tmp); + return 0; +} -- cgit v1.2.3