summaryrefslogtreecommitdiff
path: root/libinterp/comp-power.c
diff options
context:
space:
mode:
Diffstat (limited to 'libinterp/comp-power.c')
-rw-r--r--libinterp/comp-power.c2257
1 files changed, 2257 insertions, 0 deletions
diff --git a/libinterp/comp-power.c b/libinterp/comp-power.c
new file mode 100644
index 00000000..25cc9f5b
--- /dev/null
+++ b/libinterp/comp-power.c
@@ -0,0 +1,2257 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+/*
+ * Copyright © 1997 C H Forsyth (forsyth@terzarima.net)
+ */
+
+#define ROMABLE 0 /* costs something to zero patch vectors */
+#define RESCHED 1 /* check for interpreter reschedule */
+
+#define PATCH(ptr) *ptr |= ((ulong)code-(ulong)ptr) & 0xfffc
+
+#define T(r) *((void**)(R.r))
+
+#define XO(o,xo) (((o)<<26)|((xo)<<1))
+
+/* botch: ARRR, AIRR, LRRR, etc have dest first (will fix soon) */
+
+#define OPARRR(o,d,a,b) ((o)|((d)<<21)|((a)<<16)|((b)<<11))
+#define ARRR(o,d,a,b) gen((o)|((d)<<21)|((a)<<16)|((b)<<11))
+#define AIRR(o,d,a,v) gen((o)|((d)<<21)|((a)<<16)|((v)&0xFFFF))
+#define IRR(o,v,a,d) AIRR((o),(d),(a),(v))
+#define RRR(o,b,a,d) ARRR((o),(d),(a),(b))
+#define LRRR(o,a,s,b) ARRR((o),(s),(a),(b))
+#define LIRR(o,a,s,v) AIRR((o),(s),(a),(v))
+#define Bx(li,aa) gen((18<<26)|((li)&0x3FFFFFC)|((aa)<<1))
+#define RLW(op,a,s,sh,mb,me) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((sh)&31L)<<11)|\
+ (((mb)&31L)<<6)|(((me)&31L)<<1))
+#define MFSPR(s, d) gen(XO(31,339) | ((d)<<21) | ((s)<<11))
+#define MTSPR(s, d) gen(XO(31,467) | ((s)<<21) | ((d)<<11));
+
+#define SLWI(d,a,n) gen(slw((d),(a),(n),0))
+#define LRET() gen(Oblr)
+
+#define SETR0() if(macjit){ AIRR(Oaddi, Rzero, 0, 0); } /* set R0 to 0 */
+
+/* assumes H can be formed from signed halfword */
+#define CMPH(r) AIRR(Ocmpi, Rcrf0, (r), (ulong)H);
+#define NOTNIL(r) (CMPH((r)), CCALL(EQ, bounds))
+
+enum
+{
+ Rzero = 0, /* zero by design, not definition (P9/Inferno) */
+
+ Rsp = 1,
+ Rsb = 2,
+ Rarg = 3,
+
+ Ro1 = 8,
+ Ro2 = 9,
+ Ro3 = 10,
+ Ri = 11,
+ Rj = 12,
+
+ Rmp = 13,
+ Rfp = 14,
+ Rreg = 15,
+ Rta = 16, /* unused */
+ Rpic = 17, /* address for computed goto, for move to CTR or LR */
+
+ Rcon = 26, /* constant builder; temporary */
+ /* 27, 28, 29, 30 are potentially external registers (P9/Inferno) */
+ Rlink = 31, /* holds copies of LR; linker temp */
+
+ Rfret = 0,
+ Rf1 = 4,
+ Rf2 = 6,
+ Rfcvi = 27, /* floating conversion constant (P9/Inferno) */
+ Rfzero = 28, /* 0.0 (P9/Inferno) */
+ Rfhalf = 29, /* 0.5 (P9/Inferno) */
+
+ Rlr = 8<<5, /* SPR(LR) */
+ Rctr = 9<<5, /* SPR(CTR) */
+
+ Rcrf0 = 0, /* condition code field 0 */
+ Rcrf1 = 1<<2, /* condition code field 1 */
+
+ Rcrbrel = 31, /* condition code bit set to force relinquish */
+
+ Olwz = XO(32, 0),
+ Olwzu = XO(33, 0),
+ Olwzx = XO(31, 23),
+ Olbz = XO(34, 0),
+ Olbzu = XO(35, 0),
+ Olbzx = XO(31, 87),
+ Olfd = XO(50, 0),
+ Olhz = XO(40, 0),
+ Olhzx = XO(31, 279),
+ Ostw = XO(36, 0),
+ Ostwu = XO(37, 0),
+ Ostwx = XO(31, 151),
+ Ostb = XO(38, 0),
+ Ostbu = XO(39, 0),
+ Ostbx = XO(31, 215),
+ Osth = XO(44,0),
+ Osthx = XO(31, 407),
+ Ostfd = XO(54, 0),
+ Ostfdu = XO(55, 0),
+
+ Oaddc = XO(31,10),
+ Oadde = XO(31, 138),
+ Oaddi = XO(14, 0), /* simm */
+ Oaddic_ = XO(13, 0),
+ Oaddis = XO(15, 0),
+ Ocrxor = XO(19, 193),
+ Ofadd = XO(63, 21),
+ Ofcmpo = XO(63, 32),
+ Ofctiwz = XO(63, 15),
+ Ofsub = XO(63, 20),
+ Ofmr = XO(63, 72),
+ Ofmul = XO(63, 25),
+ Ofdiv = XO(63, 18),
+ Ofneg = XO(63, 40),
+ Oori = XO(24,0), /* uimm */
+ Ooris = XO(25,0), /* uimm */
+ Odivw = XO(31, 491),
+ Odivwu = XO(31, 459),
+ Omulhw = XO(31, 75),
+ Omulhwu = XO(31, 11),
+ Omulli = XO(7, 0),
+ Omullw = XO(31, 235),
+ Osubf = XO(31, 40),
+ Osubfc = XO(31,8),
+ Osubfe = XO(31,136),
+ Osubfic = XO(8, 0),
+ Oadd = XO(31, 266),
+ Oand = XO(31, 28),
+ Oneg = XO(31, 104),
+ Oor = XO(31, 444),
+ Oxor = XO(31, 316),
+
+ Ocmpi = XO(11, 0),
+ Ocmp = XO(31, 0),
+ Ocmpl = XO(31, 32),
+ Ocmpli = XO(10,0),
+
+ Orlwinm = XO(21, 0),
+ Oslw = XO(31, 24),
+ Osraw = XO(31,792),
+ Osrawi = XO(31,824),
+ Osrw = XO(31,536),
+
+ Cnone = OPARRR(0,20,0,0), /* unconditional */
+ Ceq = OPARRR(0,12,2,0),
+ Cle = OPARRR(0,4,1,0),
+ Clt = OPARRR(0,12,0,0),
+ Cdnz = OPARRR(0,16,0,0),
+ Cgt = OPARRR(0,12,1,0),
+ Cne = OPARRR(0,4,2,0),
+ Cge = OPARRR(0,4,0,0),
+ Cle1 = OPARRR(0,4,5,0), /* Cle on CR1 */
+ Crelq = OPARRR(0,12,Rcrbrel,0), /* relinquish */
+ Cnrelq = OPARRR(0,4,Rcrbrel,0), /* not relinquish */
+ Cpredict = OPARRR(0,1,0,0), /* reverse prediction */
+ Lk = 1,
+ Aa = 2,
+
+ Obeq = OPARRR(16<<26,12,2,0),
+ Obge = OPARRR(16<<26,4,0,0),
+ Obgt = OPARRR(16<<26,12,1,0),
+ Oble = OPARRR(16<<26,4,1,0),
+ Oblt = OPARRR(16<<26,12,0,0),
+ Obne = OPARRR(16<<26,4,2,0),
+
+ Ob = XO(18, 0),
+ Obc = XO(16, 0),
+ Obcctr = XO(19,528),
+ Obcctrl = Obcctr | Lk,
+ Obctr = Obcctr | Cnone,
+ Obctrl = Obctr | Lk,
+ Obclr = XO(19, 16),
+ Oblr = Obclr | Cnone,
+ Oblrl = Oblr | Lk,
+
+ Olea = 100, // pseudo op
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2), /* update R.PC */
+ TCHECK = (1<<3), /* check R.t for continue/ret */
+ NEWPC = (1<<4), /* goto R.PC */
+ DBRAN = (1<<5), /* dest is branch */
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR,
+ EQAND,
+
+ MacRET = 0,
+ MacFRP,
+ MacCASE,
+ MacFRAM,
+ MacCOLR,
+ MacMCAL,
+ MacMFRA,
+ MacCVTFW,
+ MacRELQ,
+ MacEND,
+ NMACRO
+};
+
+ void (*comvec)(void);
+ int macjit;
+extern long das(ulong*);
+static ulong* code;
+static ulong* base;
+static ulong* patch;
+static int pass;
+static Module* mod;
+static ulong* tinit;
+static ulong* litpool;
+static int nlit;
+static ulong macro[NMACRO];
+static void ldbigc(long, int);
+static void rdestroy(void);
+static void macret(void);
+static void macfrp(void);
+static void maccase(void);
+static void maccvtfw(void);
+static void macfram(void);
+static void maccolr(void);
+static void macend(void);
+static void macmcal(void);
+static void macmfra(void);
+static void macrelq(void);
+static void movmem(Inst*);
+
+struct
+{
+ int o;
+ void (*f)(void);
+} macinit[] =
+{
+ MacFRP, macfrp, /* decrement and free pointer */
+ MacRET, macret, /* return instruction */
+ MacCASE, maccase, /* case instruction */
+ MacCOLR, maccolr, /* increment and color pointer */
+ MacFRAM, macfram, /* frame instruction */
+ MacMCAL, macmcal, /* mcall bottom half */
+ MacMFRA, macmfra, /* punt mframe because t->initialize==0 */
+ MacCVTFW, maccvtfw,
+ MacRELQ, macrelq, /* reschedule */
+ MacEND, macend,
+ 0
+};
+
+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;
+
+ 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;
+}
+
+void
+urk(char *s)
+{
+ print("compile failed: %s\n", s); // debugging
+ error(exCompile); // production
+}
+
+static void
+gen(ulong o)
+{
+ *code++ = o;
+}
+
+static void
+br(ulong op, ulong disp)
+{
+ *code++ = op | (disp & 0xfffc);
+}
+
+static void
+mfspr(int d, int s)
+{
+ MFSPR(s, d);
+}
+
+static void
+mtspr(int d, int s)
+{
+ MTSPR(s, d);
+}
+
+static ulong
+slw(int d, int s, int v, int rshift)
+{
+ int m0, m1;
+
+ if(v < 0 || v > 32)
+ urk("slw v");
+ if(v < 0)
+ v = 0;
+ else if(v > 32)
+ v = 32;
+ if(rshift) { /* shift right */
+ m0 = v;
+ m1 = 31;
+ v = 32-v;
+ } else {
+ m0 = 0;
+ m1 = 31-v;
+ }
+ return RLW(Orlwinm, d, s, v, m0, m1);
+}
+
+static void
+jr(int reg)
+{
+ mtspr(Rctr, reg); /* code would be faster if this were loaded well before branch */
+ gen(Obctr);
+}
+
+static void
+jrl(int reg)
+{
+ mtspr(Rctr, reg);
+ gen(Obctrl);
+}
+
+static void
+jrc(int op, int reg)
+{
+ mtspr(Rctr, reg);
+ gen(Obcctr | op);
+}
+
+static long
+brdisp(ulong *dest)
+{
+ ulong d, top;
+
+ d = (ulong)dest - (ulong)code;
+ if(!ROMABLE)
+ return d & 0x3fffffc;
+ top = d>>25;
+ if(top == 0 || top == 0x7F){
+ /* fits in 26-bit signed displacement */
+ return d & 0x3fffffc;
+ }
+ return -1;
+}
+
+static void
+jmp(ulong *dest)
+{
+ long d;
+
+ if((d = brdisp(dest)) < 0){
+ ldbigc((ulong)dest, Rpic); /* Rpic & Rctr must be free */
+ jr(Rpic);
+ } else
+ gen(Ob | d);
+}
+
+static void
+jmpl(ulong *dest)
+{
+ long d;
+
+ if((d = brdisp(dest)) < 0){
+ ldbigc((ulong)dest, Rpic); /* Rpic must be free */
+ jrl(Rpic);
+ } else
+ gen(Ob | d | Lk);
+}
+
+static void
+jmpc(int op, ulong *dest)
+{
+ ldbigc((ulong)dest, Rpic);
+ jrc(op, Rpic);
+}
+
+static int
+bigc(long c)
+{
+ if(c >= -0x8000 && c <= 0x7FFF)
+ return 0;
+ return 1;
+}
+
+static void
+ldbigc(long c, int reg)
+{
+ AIRR(Oaddis, reg,Rzero,c>>16);
+ LIRR(Oori, reg,reg,c);
+}
+
+static void
+ldc(long c, int reg)
+{
+ if(!bigc(c))
+ AIRR(Oaddi, reg, Rzero, c);
+ else if((ulong)c <= 0xFFFF)
+ LIRR(Oori, reg, Rzero, c);
+ else if((c&0xFFFF) == 0)
+ LIRR(Ooris, reg, Rzero, c>>16);
+ else {
+ AIRR(Oaddis, reg,Rzero,c>>16);
+ LIRR(Oori, reg,reg,c);
+ }
+}
+
+static void
+mem(int inst, long disp, int rm, int r)
+{
+ if(bigc(disp)) {
+ ldc(disp, Rcon);
+ switch(inst){
+ default: urk("mem op"); break;
+ case Olea: inst = Oadd; break;
+ case Olwz: inst = Olwzx; break;
+ case Olbz: inst = Olbzx; break;
+ case Olhz: inst = Olhzx; break;
+ case Ostw: inst = Ostwx; break;
+ case Ostb: inst = Ostbx; break;
+ case Osth: inst = Osthx; break;
+ }
+ ARRR(inst, r, Rcon, rm);
+ } else {
+ if(inst == Olea)
+ inst = Oaddi;
+ AIRR(inst, r, rm,disp);
+ }
+}
+
+static void
+opx(int mode, Adr *a, int op, int reg)
+{
+ ulong c;
+ int r, rx, lea;
+
+ lea = 0;
+ if(op == Olea){
+ lea = 1;
+ op = Oaddi;
+ }
+ switch(mode) {
+ case AFP:
+ c = a->ind;
+ if(bigc(c))
+ urk("bigc op1b 1");
+ AIRR(op, reg, Rfp,c);
+ break;
+ case AMP:
+ c = a->ind;
+ if(bigc(c))
+ urk("bigc op1b 2");
+ AIRR(op, reg, Rmp,c);
+ break;
+ case AIMM:
+ if(lea) {
+ if(a->imm != 0) {
+ ldc(a->imm, reg);
+ AIRR(Ostw, reg, Rreg,O(REG,st));
+ } else
+ AIRR(Ostw, Rzero, Rreg,O(REG,st));
+ AIRR(Oaddi, reg, Rreg,O(REG,st));
+ } else
+ ldc(a->imm, reg);
+ return;
+ case AIND|AFP:
+ r = Rfp;
+ goto offset;
+ case AIND|AMP:
+ r = Rmp;
+ offset:
+ c = a->i.s;
+ rx = Ri;
+ if(lea || op == Olwz)
+ rx = reg;
+ AIRR(Olwz, rx, r,a->i.f);
+ if(!lea || c != 0)
+ AIRR(op, reg, rx,c);
+ break;
+ }
+}
+
+static void
+opwld(Inst *i, int op, int reg)
+{
+ opx(USRC(i->add), &i->s, op, reg);
+}
+
+static void
+opwst(Inst *i, int op, int reg)
+{
+ opx(UDST(i->add), &i->d, op, reg);
+}
+
+static void
+op2(Inst *i, int op, int reg)
+{
+ int lea;
+
+ lea = 0;
+ if(op == Olea){
+ op = Oaddi;
+ lea = 1;
+ }
+ switch(i->add & ARM) {
+ case AXNON:
+ if(lea)
+ op = Olea;
+ opwst(i, op, reg);
+ return;
+ case AXIMM:
+ if(lea)
+ urk("op2/lea");
+ ldc((short)i->reg, reg);
+ return;
+ case AXINF:
+ IRR(op, i->reg,Rfp, reg);
+ break;
+ case AXINM:
+ IRR(op, i->reg,Rmp, reg);
+ break;
+ }
+}
+
+static void
+op12(Inst *i, int b1flag, int b2flag)
+{
+ int o1, o2;
+
+ o1 = Olwz;
+ if(b1flag)
+ o1 = Olbz;
+ o2 = Olwz;
+ if(b2flag)
+ o2 = Olbz;
+ if((i->add & ARM) == AXIMM) {
+ opwld(i, o1, Ro1);
+ op2(i, o2, Ro2);
+ } else {
+ op2(i, o2, Ro2);
+ opwld(i, o1, Ro1);
+ }
+}
+
+static void
+op13(Inst *i, int o1, int o2)
+{
+ opwld(i, o1, Ro1);
+ opwst(i, o2, Ro1);
+}
+
+static ulong
+branch(Inst *i)
+{
+ ulong rel;
+
+ if(base == 0)
+ return 0;
+ rel = (ulong)(base+patch[i->d.ins - mod->prog]);
+ rel -= (ulong)code;
+ if(rel & 3 || (long)rel <= -(1<<16) || (long)rel >= 1<<16)
+ urk("branch off");
+ return rel & 0xfffc;
+}
+
+static void
+schedcheck(Inst *i)
+{
+ ulong *cp;
+
+ if(i != nil && i->d.ins != nil && i->d.ins > i)
+ return; /* only backwards jumps can loop: needn't check forward ones */
+ cp = code;
+ gen(Obc | Cnrelq | Cpredict);
+ jmpl(base+macro[MacRELQ]);
+ PATCH(cp);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ ldbigc((ulong)litpool, Ro1);
+ IRR(Ostw, roff, Rreg, Ro1);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+static void
+bounds(void)
+{
+ /* mem(Ostw, 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, Olea, Ro1);
+ mem(Ostw, O(REG, s), Rreg, Ro1);
+ }
+ }
+ if(m & DSTOP) {
+ opwst(i, Olea, Ro3);
+ IRR(Ostw, O(REG,d),Rreg, Ro3);
+ }
+ if(m & WRTPC) {
+ pc = patch[i-mod->prog+1];
+ ldbigc((ulong)(base+pc), Ro1);
+ IRR(Ostw, O(REG,PC),Rreg, Ro1);
+ }
+ 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) {
+ IRR(Olwz, O(REG,d),Rreg, Ro2);
+ IRR(Ostw, O(REG,m),Rreg, Ro2);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG,m));
+ break;
+ case AXINF:
+ mem(Olea, i->reg, Rfp, Ro2);
+ mem(Ostw, O(REG, m), Rreg, Ro2);
+ break;
+ case AXINM:
+ mem(Olea, i->reg, Rmp, Ro2);
+ mem(Ostw, O(REG, m), Rreg, Ro2);
+ break;
+ }
+ IRR(Ostw, O(REG,FP),Rreg, Rfp);
+
+ jmpl((ulong*)fn);
+
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ if(m & TCHECK) {
+ IRR(Olwz, O(REG,t),Rreg, Ro1);
+ IRR(Olwz, O(REG,xpc),Rreg, Ro2);
+ IRR(Ocmpi, 0, Ro1, Rcrf0);
+ mtspr(Rctr, Ro2);
+ gen(Obcctr | Cne);
+ }
+ IRR(Olwz, O(REG,FP),Rreg, Rfp);
+ IRR(Olwz, O(REG,MP),Rreg, Rmp);
+
+ if(m & NEWPC) {
+ IRR(Olwz, O(REG,PC),Rreg, Ro1);
+ jr(Ro1);
+ }
+}
+
+static void
+comgoto(Inst *i)
+{
+ WORD *t, *e;
+
+ opwld(i, Olwz, Ro2);
+ opwst(i, Olea, Ro3);
+ SLWI(Ro2, Ro2, 2);
+ ARRR(Olwzx, Ro1, Ro3,Ro2);
+ jr(Ro1);
+
+ if(pass == 0)
+ return;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = (ulong)(base + patch[t[0]]);
+ t++;
+ }
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Olwz, Ro1); // v
+ opwst(i, Olea, Ro3); // table
+ jmp(base+macro[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] = (ulong)(base + patch[t[2]]);
+ t += 3;
+ }
+ t[0] = (ulong)(base + patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = (ulong)base + patch[t[4]];
+ t += 6;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+ ulong *cp1, *cp2;
+
+ opwld(i, Olwz, Ri); // must use Ri for MacFRAM
+ CMPH(Ri);
+ cp1 = code;
+ br(Obeq, 0);
+
+ if((i->add&ARM) == AXIMM) {
+ mem(Olwz, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame), Ri, Ri);
+ } else {
+ op2(i, Olwz, Ro2);
+ SLWI(Ro2, Ro2, 3); // assumes sizeof(Modl) == 8
+ ARRR(Oadd, Ri, Ro2, Ro2);
+ mem(Olwz, OA(Modlink, links)+O(Modl, frame), Ri, Ri);
+ }
+
+ AIRR(Olwz, Ro2, Ri,O(Type,initialize));
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ cp2 = code;
+ br(Obne, 0);
+
+ opwst(i, Olea, Rj);
+
+ PATCH(cp1);
+ ldbigc((ulong)(base+patch[i-mod->prog+1]), Rpic);
+ mtspr(Rlr, Rpic);
+ jmp(base+macro[MacMFRA]);
+
+ PATCH(cp2);
+ jmpl(base+macro[MacFRAM]);
+ opwst(i, Ostw, Ro1);
+}
+
+static void
+commcall(Inst *i)
+{
+ opwld(i, Olwz, Ro1); // f in Ro1
+ AIRR(Olwz, Ro3, Rreg,O(REG,M));
+ AIRR(Ostw, Rfp, Ro1,O(Frame,fp)); // f->fp = R.FP
+ AIRR(Ostw, Ro3, Ro1,O(Frame,mr)); // f->mr = R.M
+ opwst(i, Olwz, Ri);
+ if((i->add&ARM) == AXIMM) {
+ mem(Olwz, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), Ri, Rj); // ml->entry in Rj
+ } else {
+ op2(i, Olwz, Rj);
+ SLWI(Rj, Rj, 3); // assumes sizeof(Modl) == 8
+ ARRR(Oadd, Ri, Rj, Rj);
+ mem(Olwz, OA(Modlink, links)+O(Modl, u.pc), Rj, Rj);
+ }
+ jmpl(base+macro[MacMCAL]);
+}
+
+static int
+swapbraop(int b)
+{
+ switch(b) {
+ case Obge:
+ return Oble;
+ case Oble:
+ return Obge;
+ case Obgt:
+ return Oblt;
+ case Oblt:
+ return Obgt;
+ }
+ return b;
+}
+
+static void
+cbra(Inst *i, int op)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(UXSRC(i->add) == SRC(AIMM) && !bigc(i->s.imm)) {
+ op2(i, Olwz, Ro1);
+ AIRR(Ocmpi, Rcrf0, Ro1, i->s.imm);
+ op = swapbraop(op);
+ } else if((i->add & ARM) == AXIMM) {
+ opwld(i, Olwz, Ro1);
+ AIRR(Ocmpi, Rcrf0, Ro1, i->reg);
+ } else {
+ op12(i, 0, 0);
+ ARRR(Ocmp, Rcrf0, Ro1, Ro2);
+ }
+ br(op, branch(i));
+}
+
+static void
+cbrab(Inst *i, int op)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ op2(i, Olbz, Ro1);
+ AIRR(Ocmpi, Rcrf0, Ro1, i->s.imm&0xFF);
+ op = swapbraop(op);
+ } else if((i->add & ARM) == AXIMM) {
+ opwld(i, Olbz, Ro1);
+ AIRR(Ocmpi, Rcrf0, Ro1, i->reg&0xFF); // mask i->reg?
+ } else {
+ op12(i, 1, 1);
+ ARRR(Ocmp, Rcrf0, Ro1, Ro2);
+ }
+ br(op, branch(i));
+}
+
+static void
+cbraf(Inst *i, int op)
+{
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Olfd, Rf1);
+ op2(i, Olfd, Rf2);
+ ARRR(Ofcmpo, Rcrf0, Rf1, Rf2);
+ br(op, branch(i));
+}
+
+static void
+cbral(Inst *i, int cms, int cls, int mode)
+{
+ ulong *cp;
+
+ if(RESCHED)
+ schedcheck(i);
+ cp = nil;
+ opwld(i, Olea, Ri);
+ op2(i, Olea, Rj);
+ IRR(Olwz, 0,Ri, Ro1);
+ IRR(Olwz, 0,Rj, Ro2);
+ ARRR(Ocmp, Rcrf0, Ro1, Ro2);
+ switch(mode) {
+ case ANDAND:
+ cp = code;
+ br(cms, 0);
+ break;
+ case OROR:
+ br(cms, branch(i));
+ break;
+ case EQAND:
+ br(cms, branch(i));
+ cp = code;
+ br(Obne, 0);
+ break;
+ }
+ IRR(Olwz, 4,Ri, Ro1);
+ IRR(Olwz, 4,Rj, Ro2);
+ ARRR(Ocmpl, Rcrf0, Ro1, Ro2);
+ br(cls, branch(i));
+ if(cp)
+ PATCH(cp);
+}
+
+static void
+shrl(Inst *i)
+{
+// int c;
+
+// if(USRC(i->add) != AIMM) {
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ return;
+// }
+/*
+ c = i->s.imm;
+ op2(i, Olea, Ro3);
+ IRR(Olwz, 0,Ro3, Ro1);
+ if(c >= 32) {
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ SRR(Osra, 31, Ro1, Ro2);
+ IRR(Ostw, 0,Ro3, Ro2);
+ if(c >= 64) {
+ IRR(Ostw, 4,Ro3, Ro2);
+ return;
+ }
+ if(c > 32)
+ SRR(Osra, c-32, Ro1, Ro1);
+ IRR(Ostw, 4,Ro3, Ro1);
+ return;
+ }
+ IRR(Olwz, 4,Ro3, Ro2);
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ if(c != 0) {
+ SRR(Osll, 32-c, Ro1, Ri);
+ SRR(Osra, c, Ro1, Ro1);
+ SRR(Osrl, c, Ro2, Ro2);
+ RRR(Oor, Ri, Ro2, Ro2);
+ }
+ IRR(Ostw, 4,Ro3, Ro2);
+ IRR(Ostw, 0,Ro3, Ro1);
+*/
+}
+
+static void
+shll(Inst *i)
+{
+// int c;
+
+// if(USRC(i->add) != AIMM) {
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ return;
+// }
+/*
+ c = i->s.imm;
+ if(c >= 64) {
+ opwst(i, Olea, Ro3);
+ IRR(Ostw, 0,Ro3, Rzero);
+ IRR(Ostw, 4,Ro3, Rzero);
+ return;
+ }
+ op2(i, Olea, Ro3);
+ if(c >= 32) {
+ IRR(Olwz, 4,Ro3, Ro1);
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ IRR(Ostw, 4,Ro3, Rzero);
+ if(c > 32)
+ SRR(Osll, c-32, Ro1, Ro1);
+ IRR(Ostw, 0,Ro3, Ro1);
+ return;
+ }
+ IRR(Olwz, 4,Ro3, Ro2);
+ IRR(Olwz, 0,Ro3, Ro1);
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ if(c != 0) {
+ SRR(Osrl, 32-c, Ro2, Ri);
+ SRR(Osll, c, Ro2, Ro2);
+ SRR(Osll, c, Ro1, Ro1);
+ RRR(Oor, Ri, Ro1, Ro1);
+ }
+ IRR(Ostw, 4,Ro3, Ro2);
+ IRR(Ostw, 0,Ro3, Ro1);
+*/
+}
+
+static void
+compdbg(void)
+{
+ print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comp(Inst *i)
+{
+ int o, q, b;
+ ulong *cp, *cp1;
+ char buf[64];
+
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ punt(&xx, SRCOP, compdbg);
+ }
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case IMNEWZ:
+ case ILSRW:
+ case ILSRL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ 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 IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTCL:
+ case ICVTLC:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTFL:
+ case ICVTLF:
+ 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 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 ICVTWB:
+ op13(i, Olwz, Ostb);
+ break;
+ case ICVTBW:
+ op13(i, Olbz, Ostw);
+ break;
+ case IMOVB:
+ if(USRC(i->add) == AIMM && i->s.imm == 0) {
+ opwst(i, Ostb, Rzero);
+ break;
+ }
+ op13(i, Olbz, Ostb);
+ break;
+ case IMOVW:
+ if(USRC(i->add) == AIMM && i->s.imm == 0) {
+ opwst(i, Ostw, Rzero);
+ break;
+ }
+ op13(i, Olwz, Ostw);
+ break;
+ case ICVTLW:
+ opwld(i, Olea, Ro1);
+ AIRR(Olwz, Ro2, Ro1,4);
+ opwst(i, Ostw, Ro2);
+ break;
+ case ICVTWL:
+ opwld(i, Olwz, Ro1);
+ opwst(i, Olea, Ro2);
+ LRRR(Osrawi, Ro3, Ro1, 31);
+ AIRR(Ostw, Ro1, Ro2,4);
+ AIRR(Ostw, Ro3, Ro2,0);
+ break;
+ case IHEADM:
+ opwld(i, Olwz, Ro1);
+ AIRR(Oaddi, Ro1, Ro1,OA(List,data));
+ movmem(i);
+ break;
+ case IMOVM:
+ opwld(i, Olea, Ro1);
+ movmem(i);
+ break;
+ case IRET:
+ jmp(base+macro[MacRET]);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ ldc((ulong)mod->type[i->s.imm], Ri);
+ jmpl(base+macro[MacFRAM]);
+ opwst(i, Ostw, Ro1);
+ break;
+ case ILEA:
+ op13(i, Olea, Ostw);
+ break;
+ case IHEADW:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olwz, Ro1, Ro1,OA(List,data));
+ opwst(i, Ostw, Ro1);
+ break;
+ case IHEADF:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olfd, Rf1, Ro1,OA(List,data));
+ opwst(i, Ostfd, Rf1);
+ break;
+ case IHEADB:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olbz, Ro1, Ro1,OA(List,data));
+ opwst(i, Ostb, Ro1);
+ break;
+ case ITAIL:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olwz, Ro1, Ro1,O(List,tail));
+ goto movp;
+ case IMOVP:
+ opwld(i, Olwz, Ro1);
+ goto movp;
+ case IHEADP:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olwz, Ro1, Ro1,OA(List,data));
+ movp:
+ CMPH(Ro1);
+ cp = code;
+ br(Obeq, 0);
+ jmpl(base+macro[MacCOLR]);
+ PATCH(cp);
+ opwst(i, Olea, Ro3);
+ AIRR(Olwz, Ri, Ro3,0);
+ AIRR(Ostw, Ro1, Ro3,0);
+ jmpl(base+macro[MacFRP]);
+ break;
+ case ILENA:
+ opwld(i, Olwz, Ri);
+ ldc(0, Ro1);
+ CMPH(Ri);
+ cp = code;
+ br(Obeq, 0);
+ AIRR(Olwz, Ro1, Ri,O(Array,len));
+ PATCH(cp);
+ opwst(i, Ostw, Ro1);
+ break;
+ case ILENC:
+ opwld(i, Olwz, Ri);
+ ldc(0, Ro1);
+ CMPH(Ri);
+ cp = code;
+ br(Obeq, 0);
+ AIRR(Olwz, Ro1, Ri,O(String,len));
+ AIRR(Ocmpi, Rcrf0, Ro1, 0);
+ br(Obge, 2*4); // BGE 2(PC); skip
+ ARRR(Oneg, Ro1, Ro1, 0);
+ PATCH(cp);
+ opwst(i, Ostw, Ro1);
+ break;
+ case ILENL:
+ opwld(i, Olwz, Ro1);
+ ldc(0, Ro3);
+ CMPH(Ro1);
+ cp = code;
+ br(Obeq, 0);
+
+ cp1 = code;
+ AIRR(Olwz, Ro1, Ro1,O(List,tail));
+ AIRR(Oaddi, Ro3, Ro3, 1);
+ CMPH(Ro1);
+ br(Obne, ((ulong)cp1-(ulong)code));
+
+ PATCH(cp);
+ opwst(i, Ostw, Ro3);
+ break;
+ case IMOVL:
+ opwld(i, Olea, Ro1);
+ AIRR(Olwz, Ro2, Ro1,0);
+ AIRR(Olwz, Ro3, Ro1,4);
+ opwst(i, Olea, Ro1);
+ AIRR(Ostw, Ro2, Ro1,0);
+ AIRR(Ostw, Ro3, Ro1,4);
+ break;
+ case IMOVF:
+ opwld(i, Olfd, Rf1);
+ opwst(i, Ostfd, Rf1);
+ break;
+ case ICVTFW:
+ if(!macjit){
+ opwld(i, Olfd, Rf1);
+ jmpl(base+macro[MacCVTFW]);
+ opwst(i, Ostw, Ro1);
+ break;
+ }
+ case ICVTWF:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEGF:
+ opwld(i, Olfd, Rf1);
+ ARRR(Ofneg, Rf2, 0, Rf1);
+ opwst(i, Ostfd, Rf2);
+ break;
+ case IXORL:
+ case IORL:
+ case IANDL:
+ case IADDL:
+ case ISUBL:
+ opwld(i, Olea, Ro1);
+ op2(i, Olea, Ro3);
+
+ AIRR(Olwz, Rj, Ro1,4); /* ls */
+ AIRR(Olwz, Ro2, Ro3,4);
+ AIRR(Olwz, Ri, Ro1,0); /* ms */
+ AIRR(Olwz, Ro1, Ro3,0);
+
+ switch(i->op) {
+ case IXORL:
+ o = Oxor;
+ goto l1;
+ case IORL:
+ o = Oor;
+ goto l1;
+ case IANDL:
+ o = Oand;
+ l1:
+ LRRR(o, Ro1, Ri, Ro1);
+ LRRR(o, Ro2, Rj, Ro2);
+ break;
+ case IADDL:
+ RRR(Oaddc, Rj,Ro2, Ro2);
+ RRR(Oadde, Ri,Ro1, Ro1);
+ break;
+ case ISUBL:
+ RRR(Osubfc, Ro2,Rj, Ro2);
+ RRR(Osubfe, Ro1,Ri, Ro1);
+ break;
+ }
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ IRR(Ostw, 0,Ro3, Ro1);
+ IRR(Ostw, 4,Ro3, Ro2);
+ break;
+ case ISHLL:
+ shll(i);
+ break;
+ case ISHRL:
+ shrl(i);
+ break;
+ case IADDF: o = Ofadd; goto f1;
+ case ISUBF: o = Ofsub; goto f1;
+ case IMULF: o = Ofmul; goto f1;
+ case IDIVF: o = Ofdiv; goto f1;
+ f1:
+ opwld(i, Olfd, Rf1);
+ op2(i, Olfd, Rf2);
+ if(o == Ofmul)
+ gen(o | (Rf2<<21) | (Rf2<<16) | (Rf1<<6)); /* odd one out: op D,A,-,C */
+ else
+ ARRR(o, Rf2, Rf2, Rf1);
+ opwst(i, Ostfd, Rf2);
+ break;
+
+ case IBEQF:
+ cbraf(i, Obeq);
+ break;
+ case IBGEF:
+ cbraf(i, Obge);
+ case IBGTF:
+ cbraf(i, Obgt);
+ break;
+ case IBLEF:
+ cbraf(i, Oble);
+ break;
+ case IBLTF:
+ cbraf(i, Oblt);
+ break;
+ case IBNEF:
+ cbraf(i, Obne);
+ break;
+
+ case IBLTB:
+ cbrab(i, Oblt);
+ break;
+ case IBLEB:
+ cbrab(i, Oble);
+ break;
+ case IBGTB:
+ cbrab(i, Obgt);
+ break;
+ case IBGEB:
+ cbrab(i, Obge);
+ break;
+ case IBEQB:
+ cbrab(i, Obeq);
+ break;
+ case IBNEB:
+ cbrab(i, Obne);
+ break;
+
+ case IBLTW:
+ cbra(i, Oblt);
+ break;
+ case IBLEW:
+ cbra(i, Oble);
+ break;
+ case IBGTW:
+ cbra(i, Obgt);
+ break;
+ case IBGEW:
+ cbra(i, Obge);
+ break;
+ case IBEQW:
+ cbra(i, Obeq);
+ break;
+ case IBNEW:
+ cbra(i, Obne);
+ break;
+
+ case IBEQL:
+ cbral(i, Obne, Obeq, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Obne, Obne, OROR);
+ break;
+ case IBLTL:
+ cbral(i, Oblt, Oblt, EQAND);
+ break;
+ case IBLEL:
+ cbral(i, Oblt, Oble, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, Obgt, Obgt, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, Obgt, Obge, EQAND);
+ break;
+
+ case ISUBB:
+ case IADDB:
+ case IANDB:
+ case IORB:
+ case IXORB:
+ case IMODB:
+ case IDIVB:
+ case IMULB:
+ b = 1;
+ op12(i, b, b);
+ goto s2;
+ case ISHLB:
+ case ISHRB:
+ b = 1;
+ op12(i, 0, b);
+ goto s2;
+ case ISUBW:
+ case IADDW:
+ case IANDW:
+ case IORW:
+ case IXORW:
+ case ISHLW:
+ case ISHRW:
+ case IMODW:
+ case IDIVW:
+ case IMULW:
+ b = 0;
+ op12(i, b, b);
+ s2:
+ q = 0;
+ switch(i->op) {
+ case ISUBB:
+ case ISUBW: o = Osubf; q = Osubfic;
+ // TO DO: if immediate operand, should use opcode q
+ USED(q);
+ ARRR(o, Ro3, Ro1, Ro2);
+ break;
+ case IADDB:
+ case IADDW: o = Oadd; q = Oaddi; goto c1;
+ case IMULB:
+ case IMULW: o = Omullw; q = Omulli; goto c1;
+ case IDIVB:
+ case IDIVW: o = Odivw; goto c1;
+ c1:
+ // TO DO: if immediate operand, should use opcode q
+ USED(q);
+ ARRR(o, Ro3, Ro2, Ro1);
+ break;
+ case IANDB:
+ case IANDW: o = Oand; goto c2;
+ case IORB:
+ case IORW: o = Oor; goto c2;
+ case IXORB:
+ case IXORW: o = Oxor; goto c2;
+ case ISHLB:
+ case ISHLW: o = Oslw; goto c2;
+ case ISHRB:
+ case ISHRW: o = Osraw; goto c2;
+ c2:
+ LRRR(o, Ro3,Ro2,Ro1);
+ break;
+ case IMODB:
+ case IMODW:
+ ARRR(Odivw, Ro3, Ro2, Ro1);
+ ARRR(Omullw, Ro3, Ro3, Ro1);
+ ARRR(Osubf, Ro3, Ro3, Ro2);
+ break;
+ }
+ opwst(i, b? Ostb: Ostw, Ro3);
+ break;
+ case ICALL:
+ opwld(i, Olwz, Ro1); /* f = T(s) */
+ ldbigc((ulong)(base+patch[i-mod->prog+1]), Ro2); /* R.pc */
+ AIRR(Ostw, Rfp, Ro1,O(Frame,fp)); /* f->fp = R.fp */
+ AIRR(Ostw, Ro2, Ro1,O(Frame,lr)); /* f->lr = R.pc */
+ AIRR(Oaddi, Rfp, Ro1, 0); /* R.fp = (uchar*)f */
+ jmp(base+patch[i->d.ins - mod->prog]);
+ break;
+ case IJMP:
+ if(RESCHED)
+ schedcheck(i);
+ jmp(base+patch[i->d.ins - mod->prog]);
+ break;
+ case IGOTO:
+ comgoto(i);
+ break;
+ case IINDC:
+ opwld(i, Olwz, Ro1); // Ro1 = string
+ if((i->add&ARM) != AXIMM)
+ op2(i, Olwz, Ro2); // Ro2 = i
+ AIRR(Olwz, Ri, Ro1,O(String,len)); // len<0 => index Runes, otherwise bytes
+ AIRR(Oaddi, Ro1, Ro1,O(String,data));
+ AIRR(Ocmpi, Rcrf0, Ri, 0);
+ if(bflag){
+ br(Obge, 2*4);
+ ARRR(Oneg, Ri, Ri, 0);
+ if((i->add&ARM) != AXIMM)
+ ARRR(Ocmpl, Rcrf1, Ri, Ro2); /* CMPU len, i */
+ else
+ AIRR(Ocmpli, Rcrf1, Ri, i->reg); /* CMPU len, i */
+ jmpc(Cle1, (ulong*)bounds);
+ }
+ cp = code;
+ br(Obge, 0);
+ if((i->add&ARM) != AXIMM){
+ SLWI(Ro2, Ro2, 1);
+ ARRR(Olhzx, Ro3, Ro1, Ro2);
+ } else
+ mem(Olhz, (short)i->reg<<1, Ro1, Ro3);
+ gen(Ob | (2*4)); // skip
+ PATCH(cp);
+ if((i->add&ARM) != AXIMM)
+ ARRR(Olbzx, Ro3, Ro1, Ro2);
+ else
+ AIRR(Olbz, Ro3, Ro1,i->reg);
+ opwst(i, Ostw, Ro3);
+ break;
+ case IINDX:
+ case IINDB:
+ case IINDF:
+ case IINDW:
+ case IINDL:
+ opwld(i, Olwz, Ro1); /* Ro1 = a */
+ opwst(i, Olwz, Ro3); /* Ro3 = i */
+ if(bflag){
+ AIRR(Olwz, Ro2, Ro1, O(Array, len)); /* Ro2 = a->len */
+ ARRR(Ocmpl, Rcrf0, Ro3, Ro2); /* CMPU i, len */
+ jmpc(Cge, (ulong*)bounds);
+ }
+ // TO DO: check a != H
+ AIRR(Olwz, Ro2, Ro1,O(Array,data)); /* Ro2 = a->data */
+ switch(i->op) {
+ case IINDX:
+ AIRR(Olwz, Ri, Ro1,O(Array,t)); // Ri = a->t
+ AIRR(Olwz, Ro1, Ri,O(Type,size)); // Ro1 = a->t->size
+ ARRR(Omullw, Ro3, Ro3, Ro1); // Ro3 = i*size
+ break;
+ case IINDL:
+ case IINDF:
+ SLWI(Ro3, Ro3, 3); /* Ro3 = i*8 */
+ break;
+ case IINDW:
+ SLWI(Ro3, Ro3, 2); /* Ro3 = i*4 */
+ break;
+ case IINDB:
+ /* no further work */
+ break;
+ }
+ ARRR(Oadd, Ro2, Ro2, Ro3); /* Ro2 = i*size + data */
+ op2(i, Ostw, Ro2);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ 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;
+ }
+}
+
+enum {
+ PREFLEN = 20, /* max instruction words in comvec */
+};
+
+static void
+preamble(void)
+{
+ ulong *s;
+
+ if(comvec != nil)
+ return;
+ s = code = malloc(PREFLEN*sizeof(*code));
+ if(s == nil)
+ error(exNomem);
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,xpc));
+ AIRR(Olwz, Ri, Rreg,O(REG,PC));
+ mtspr(Rctr, Ri);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ gen(Obctr);
+ if(code >= (ulong*)(s + PREFLEN))
+ urk("preamble");
+ comvec = (void*)s;
+ segflush(s, PREFLEN*sizeof(*s));
+ if(cflag > 3) {
+ print("comvec\n");
+ while(s < code)
+ s += das(s);
+ }
+}
+
+static void
+macfrp(void)
+{
+ CMPH(Ri);
+ gen(Obclr | Ceq); // arg == $H? => return
+
+ AIRR(Olwz, Ro2, Ri,O(Heap,ref)-sizeof(Heap));
+ AIRR(Oaddic_, Rj, Ro2, -1); // ref(arg)-- and test
+ AIRR(Ostw, Rj, Ri,O(Heap,ref)-sizeof(Heap));
+ gen(Obclr | Cne); // ref(arg) nonzero? => return
+
+ AIRR(Ostw, Ro2, Ri,O(Heap,ref)-sizeof(Heap)); // restore ref count of 1 for destroy
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,st));
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP));
+ AIRR(Ostw, Ri, Rreg,O(REG,s));
+
+ jmpl((ulong*)rdestroy); // CALL destroy
+
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ AIRR(Olwz, Rlink, Rreg,O(REG,st));
+ mtspr(Rlr, Rlink);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ LRET();
+}
+
+static void
+macret(void)
+{
+ ulong *cp1, *cp2, *cp3, *cp4, *cp5, *linterp;
+ Inst i;
+
+ AIRR(Olwz, Ro1, Rfp,O(Frame,t));
+ AIRR(Ocmpi, Rcrf0, Ro1, 0);
+ cp1 = code;
+ br(Obeq, 0); // t(Rfp) == 0
+
+ AIRR(Olwz, Rpic, Ro1,O(Type,destroy));
+ AIRR(Ocmpi, Rcrf0, Rpic, 0);
+ cp2 = code;
+ br(Obeq, 0); // destroy(t(fp)) == 0
+
+ AIRR(Olwz, Ro2, Rfp,O(Frame,fp));
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ cp3 = code;
+ br(Obeq, 0); // fp(Rfp) == 0
+
+ AIRR(Olwz, Ro3, Rfp,O(Frame,mr));
+ AIRR(Ocmpi, Rcrf0, Ro3, 0);
+ cp4 = code;
+ br(Obeq, 0); // mr(Rfp) == 0
+
+ AIRR(Olwz, Ro2, Rreg,O(REG,M));
+ AIRR(Olwz, Ro3, Ro2,O(Heap,ref)-sizeof(Heap));
+ AIRR(Oaddic_, Ro3, Ro3, -1); // --ref(arg), set cc
+ cp5 = code;
+ br(Obeq, 0); // --ref(arg) == 0?
+ AIRR(Ostw, Ro3, Ro2,O(Heap,ref)-sizeof(Heap));
+
+ AIRR(Olwz, Ro1, Rfp,O(Frame,mr));
+ AIRR(Ostw, Ro1, Rreg,O(REG,M));
+ AIRR(Olwz, Rmp, Ro1,O(Modlink,MP));
+ AIRR(Ostw, Rmp, Rreg,O(REG,MP));
+ AIRR(Olwz, Ro3, Ro1,O(Modlink,compiled)); // R.M->compiled?
+ AIRR(Ocmpi, Rcrf0, Ro3, 0);
+ linterp = code;
+ br(Obeq, 0);
+
+ PATCH(cp4);
+ jrl(Rpic); // call destroy(t(fp))
+ AIRR(Ostw, Rfp, Rreg,O(REG,SP));
+ AIRR(Olwz, Ro1, Rfp,O(Frame,lr));
+ AIRR(Olwz, Rfp, Rfp,O(Frame,fp));
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP)); // R.FP = Rfp
+ jr(Ro1); // goto lr(Rfp)
+
+ PATCH(linterp);
+ jrl(Rpic); // call destroy(t(fp))
+ AIRR(Ostw, Rfp, Rreg,O(REG,SP));
+ AIRR(Olwz, Ro1, Rfp,O(Frame,lr));
+ AIRR(Olwz, Rfp, Rfp,O(Frame,fp));
+ AIRR(Ostw, Ro1, Rreg,O(REG,PC)); // R.PC = fp->lr
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP)); // R.FP = Rfp
+ AIRR(Olwz, Rpic, Rreg,O(REG,xpc));
+ mtspr(Rlr, Rpic);
+ gen(Oblr); // return to xec uncompiled code
+
+ PATCH(cp1);
+ PATCH(cp2);
+ PATCH(cp3);
+ PATCH(cp5);
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccase(void)
+{
+ 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;
+ br(Oble, 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;
+ br(Oblt, 0); // v < l[1]? goto low
+
+ IRR(Olwz, 8,Rj, Rpic);
+ ARRR(Ocmp, Rcrf0, Ro1, Rpic);
+ cp3 = code;
+ br(Obge, 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);
+}
+
+static void
+macmcal(void)
+{
+ ulong *cp;
+
+ AIRR(Olwz, Ro2, Ri,O(Modlink,prog));
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Ro1,O(Frame,lr)); // f->lr = return
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ AIRR(Oaddi, Rfp, Ro1, 0); // R.FP = f
+ cp = code;
+ br(Obne, 0); // CMPL ml->m->prog != 0
+
+ AIRR(Ostw, Rlink, Rreg,O(REG,st));
+ AIRR(Ostw, Ro1, Rreg,O(REG,FP));
+ AIRR(Ostw, Rj, Rreg,O(REG,dt));
+ jmpl((ulong*)rmcall); // CALL rmcall
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ AIRR(Olwz, Rlink, Rreg,O(REG,st));
+ mtspr(Rlr, Rlink);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ gen(Oblr); // RET
+
+ PATCH(cp);
+ AIRR(Olwz, Ro2, Ri,O(Heap,ref)-sizeof(Heap));
+ AIRR(Ostw, Ri, Rreg,O(REG,M));
+ AIRR(Oaddi, Ro2, Ro2, 1);
+ AIRR(Olwz, Rmp, Ri,O(Modlink,MP));
+ AIRR(Ostw, Ro2, Ri,O(Heap,ref)-sizeof(Heap));
+ AIRR(Ostw, Rmp, Rreg,O(REG,MP));
+ AIRR(Olwz, Ro2, Ri,O(Modlink,compiled));
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ mtspr(Rctr, Rj);
+ gen(Obcctr | Cne); // return to compiled code
+
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP)); // R.FP = Rfp
+ AIRR(Ostw, Rj, Rreg,O(REG,PC)); // R.PC = Rj
+ AIRR(Olwz, Rpic, Rreg,O(REG,xpc));
+ mtspr(Rlr, Rpic);
+ gen(Oblr); // return to xec uncompiled code
+}
+
+static void
+macmfra(void)
+{
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,st));
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP));
+ AIRR(Ostw, Ri, Rreg,O(REG,s));
+ AIRR(Ostw, Rj, Rreg,O(REG,d));
+ jmpl((ulong*)rmfram);
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ AIRR(Olwz, Rlink, Rreg,O(REG,st));
+ mtspr(Rlr, Rlink);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ gen(Oblr);
+}
+
+static void
+macfram(void)
+{
+ ulong *cp;
+
+ /*
+ * Ri has t
+ */
+ AIRR(Olwz, Ro2, Ri,O(Type,size)); // MOVW t->size, Ro3
+ AIRR(Olwz, Ro1, Rreg,O(REG,SP)); // MOVW R.SP, Ro1 (=(Frame*)R.SP)
+ AIRR(Olwz, Ro3, Rreg,O(REG,TS)); // MOVW R.TS, tmp
+ ARRR(Oadd, Ro2, Ro2, Ro1); // ADD Ro1, t->size, nsp
+ ARRR(Ocmpl, Rcrf0, Ro2, Ro3); // CMPU nsp,tmp (nsp >= R.TS?)
+ cp = code;
+ br(Obge, 0); // BGE expand
+
+ AIRR(Olwz, Rj, Ri,O(Type,initialize));
+ mtspr(Rctr, Rj);
+ AIRR(Ostw, Ro2, Rreg,O(REG,SP)); // R.SP = nsp
+ AIRR(Ostw, Rzero, Ro1,O(Frame,mr)); // Ro1->mr = nil
+ AIRR(Ostw, Ri, Ro1,O(Frame,t)); // Ro1->t = t
+ gen(Obctr); // become t->init(Ro1), returning Ro1
+
+ PATCH(cp); // expand:
+ AIRR(Ostw, Ri, Rreg,O(REG,s)); // MOVL t, R.s
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,st)); // MOVL Rlink, R.st
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP)); // MOVL RFP, R.FP
+ jmpl((ulong*)extend); // CALL extend
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ AIRR(Olwz, Rlink, Rreg,O(REG,st)); // reload registers
+ mtspr(Rlr, Rlink);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ AIRR(Olwz, Ro1, Rreg,O(REG,s)); // return R.s set by extend
+ LRET(); // RET
+}
+
+static void
+movloop(int ldu, int stu, int adj)
+{
+ ulong *cp;
+
+ AIRR(Oaddi, Ro1, Ro1, -adj); // adjust for update ld/st
+ AIRR(Oaddi, Ro3, Ro3, -adj);
+ mtspr(Rctr, Ro2);
+
+ cp = code; // l0:
+ AIRR(ldu, Ri, Ro1,adj);
+ AIRR(stu, Ri, Ro3,adj);
+ br(Obc | Cdnz, ((ulong)cp-(ulong)code)); // DBNZ l0
+}
+
+static void
+movmem(Inst *i)
+{
+ ulong *cp;
+
+ // source address already in Ro1
+ if((i->add&ARM) != AXIMM){
+ op2(i, Olwz, Ro2);
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ cp = code;
+ br(Oble, 0);
+ opwst(i, Olea, Ro3);
+ movloop(Olbzu, Ostbu, 1);
+ PATCH(cp);
+ return;
+ }
+ switch(i->reg){
+ case 4:
+ AIRR(Olwz, Ro2, Ro1,0);
+ opwst(i, Ostw, Ro2);
+ break;
+ case 8:
+ AIRR(Olwz, Ro2, Ro1,0);
+ opwst(i, Olea, Ro3);
+ AIRR(Olwz, Ro1, Ro1,4);
+ AIRR(Ostw, Ro2, Ro3,0);
+ AIRR(Ostw, Ro1, Ro3,4);
+ break;
+ default:
+ // could use lwsi/stwsi loop...
+ opwst(i, Olea, Ro3);
+ if((i->reg&3) == 0) {
+ ldc(i->reg>>2, Ro2);
+ movloop(Olwzu, Ostwu, 4);
+ } else {
+ ldc(i->reg, Ro2);
+ movloop(Olbzu, Ostbu, 1);
+ }
+ break;
+ }
+}
+
+static void
+maccolr(void)
+{
+ ldbigc((ulong)&mutator, Ri);
+ AIRR(Olwz, Ri, Ri,0);
+ AIRR(Olwz, Ro3, Ro1,O(Heap,color)-sizeof(Heap)); // h->color
+
+ AIRR(Olwz, Ro2, Ro1,O(Heap,ref)-sizeof(Heap)); // h->ref
+
+ ARRR(Ocmp, Rcrf0, Ri, Ro3);
+ AIRR(Oaddi, Ro2, Ro2, 1); // h->ref++
+ AIRR(Ostw, Ro2, Ro1,O(Heap,ref)-sizeof(Heap));
+ gen(Obclr | Ceq); // return if h->color == mutator
+
+ ldc(propagator, Ro3);
+ AIRR(Ostw, Ro3, Ro1,O(Heap,color)-sizeof(Heap)); // h->color = propagator
+ ldc((ulong)&nprop, Ro3);
+ AIRR(Ostw, Ro1, Ro3,0); // nprop = !0
+ LRET();
+}
+
+static void
+maccvtfw(void)
+{
+ ulong *cp;
+
+ ARRR(Ofcmpo, Rcrf0, Rf1, Rfzero);
+ ARRR(Ofneg, Rf2, 0, Rfhalf);
+ cp = code;
+ br(Oblt, 0);
+ ARRR(Ofmr, Rf2, 0, Rfhalf);
+ PATCH(cp);
+ ARRR(Ofadd, Rf1, Rf1, Rf2); //x<0? x-.5: x+.5
+ ARRR(Ofctiwz, Rf2, 0, Rf1);
+ /* avoid using Ostfdu for now, since software emulation will run on same stack */
+ if(0){
+ AIRR(Ostfdu, Rf2, Rsp,-8); // MOVDU Rf2, -8(R1) (store in temp)
+ }else{
+ AIRR(Oaddi, Rsp, Rsp, -8); // SUB $8, R1
+ AIRR(Ostfd, Rf2, Rsp,0); // MOVD Rf2, 0(R1) (store in temp)
+ }
+ AIRR(Olwz, Ro1, Rsp,4); // MOVW 4(R1), Ro1
+ AIRR(Oaddi, Rsp, Rsp, 8); // ADD $8, R1
+ LRET();
+}
+
+static void
+macrelq(void)
+{
+ ARRR(Ocrxor, Rcrbrel, Rcrbrel, Rcrbrel); /* clear the relinquish condition */
+ mfspr(Rlink, Rlr);
+ IRR(Ostw, O(REG,FP),Rreg, Rfp);
+ IRR(Ostw, O(REG,PC),Rreg, Rlink);
+ IRR(Olwz, O(REG,xpc),Rreg, Ro2);
+ jr(Ro2);
+}
+
+static void
+macend(void)
+{
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,dt));
+ 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(Olwz, j, Rfp, Ri);
+ jmpl(base+macro[MacFRP]);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ AIRR(Olwz, Rlink, Rreg,O(REG,dt));
+ mtspr(Rlr, Rlink);
+ gen(Oblr);
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ ldc((ulong)H, Ri);
+ 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(Ostw, j, Ro1, Ri);
+ j += sizeof(WORD*);
+ }
+ }
+ LRET();
+}
+
+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= %.8lux %4d i %.8lux d %.8lux asm=%d\n",
+ (ulong)t, t->size, (ulong)t->initialize, (ulong)t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ Link *l;
+ Modl *e;
+ int i, n;
+ ulong *s, *tmp;
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), ROMABLE);
+ 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++) {
+ code = tmp;
+ comp(&m->prog[i]);
+ if(code >= &tmp[4096]) {
+ print("%3d %D\n", i, &m->prog[i]);
+ urk("tmp ovflo");
+ }
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i=0; macinit[i].f; i++) {
+ code = tmp;
+ (*macinit[i].f)();
+ macro[macinit[i].o] = n;
+ n += code - tmp;
+ }
+
+ base = mallocz((n+nlit)*sizeof(*base), 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 3)
+ print("dis=%5d %5d ppc=%5d asm=%.8lux lit=%d: %s\n",
+ size, size*sizeof(Inst), n, (ulong)base, nlit, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = base+n;
+ code = base;
+ n = 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]);
+ urk("phase error");
+ }
+ n += code - s;
+ if(cflag > 3) {
+ print("%3d %D\n", i, &m->prog[i]);
+ while(s < code)
+ s += das(s);
+ }/**/
+ }
+
+ for(i=0; macinit[i].f; i++) {
+ if(macro[macinit[i].o] != n) {
+ print("macinit %d\n", macinit[i].o);
+ urk("phase error");
+ }
+ s = code;
+ (*macinit[i].f)();
+ n += code - s;
+ if(cflag > 3) {
+ print("macinit %d\n", macinit[i].o);
+ while(s < code)
+ s += das(s);
+ }/**/
+ }
+
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)(base+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*)(base+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*)(base+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;
+}