summaryrefslogtreecommitdiff
path: root/limbo/gen.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /limbo/gen.c
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'limbo/gen.c')
-rw-r--r--limbo/gen.c1097
1 files changed, 1097 insertions, 0 deletions
diff --git a/limbo/gen.c b/limbo/gen.c
new file mode 100644
index 00000000..feb87d64
--- /dev/null
+++ b/limbo/gen.c
@@ -0,0 +1,1097 @@
+#include "limbo.h"
+
+static int addrmode[Rend] =
+{
+ /* Rreg */ Afp,
+ /* Rmreg */ Amp,
+ /* Roff */ Aoff,
+ /* Rnoff */ Anoff,
+ /* Rdesc */ Adesc,
+ /* Rdescp */ Adesc,
+ /* Rconst */ Aimm,
+ /* Ralways */ Aerr,
+ /* Radr */ Afpind,
+ /* Rmadr */ Ampind,
+ /* Rcant */ Aerr,
+ /* Rpc */ Apc,
+ /* Rmpc */ Aerr,
+ /* Rareg */ Aerr,
+ /* Ramreg */ Aerr,
+ /* Raadr */ Aerr,
+ /* Ramadr */ Aerr,
+ /* Rldt */ Aldt,
+};
+
+static Decl *wtemp;
+static Decl *bigtemp;
+static int ntemp;
+static Node retnode;
+static Inst zinst;
+
+ int *blockstack;
+ int blockdep;
+ int nblocks;
+static int lenblockstack;
+static Node *ntoz;
+
+static Inst* genfixop(Src *src, int op, Node *s, Node *m, Node *d);
+
+void
+genstart(void)
+{
+ Decl *d;
+
+ d = mkdecl(&nosrc, Dlocal, tint);
+ d->sym = enter(".ret", 0);
+ d->offset = IBY2WD * REGRET;
+
+ retnode = znode;
+ retnode.op = Oname;
+ retnode.addable = Rreg;
+ retnode.decl = d;
+ retnode.ty = tint;
+
+ zinst.op = INOP;
+ zinst.sm = Anone;
+ zinst.dm = Anone;
+ zinst.mm = Anone;
+
+ firstinst = allocmem(sizeof *firstinst);
+ *firstinst = zinst;
+ lastinst = firstinst;
+
+ blocks = -1;
+ blockdep = 0;
+ nblocks = 0;
+}
+
+/*
+ * manage nested control flow blocks
+ */
+int
+pushblock(void)
+{
+ if(blockdep >= lenblockstack){
+ lenblockstack = blockdep + 32;
+ blockstack = reallocmem(blockstack, lenblockstack * sizeof *blockstack);
+ }
+ blockstack[blockdep++] = blocks;
+ return blocks = nblocks++;
+}
+
+void
+repushblock(int b)
+{
+ blockstack[blockdep++] = blocks;
+ blocks = b;
+}
+
+void
+popblock(void)
+{
+ blocks = blockstack[blockdep -= 1];
+}
+
+void
+tinit(void)
+{
+ wtemp = nil;
+ bigtemp = nil;
+}
+
+Decl*
+tdecls(void)
+{
+ Decl *d;
+
+ for(d = wtemp; d != nil; d = d->next){
+ if(d->tref != 1)
+ fatal("temporary %s has %d references", d->sym->name, d->tref-1);
+ }
+
+ for(d = bigtemp; d != nil; d = d->next){
+ if(d->tref != 1)
+ fatal("temporary %s has %d references", d->sym->name, d->tref-1);
+ }
+
+ return appdecls(wtemp, bigtemp);
+}
+
+Node*
+talloc(Node *n, Type *t, Node *nok)
+{
+ Decl *d, *ok;
+ Desc *desc;
+ char buf[StrSize];
+
+ ok = nil;
+ if(nok != nil)
+ ok = nok->decl;
+ if(ok == nil || ok->tref == 0 || tattr[ok->ty->kind].big != tattr[t->kind].big || ok->ty->align != t->align)
+ ok = nil;
+ *n = znode;
+ n->op = Oname;
+ n->addable = Rreg;
+ n->ty = t;
+ if(tattr[t->kind].big){
+ desc = mktdesc(t);
+ if(ok != nil && ok->desc == desc){
+ ok->tref++;
+ ok->refs++;
+ n->decl = ok;
+ return n;
+ }
+ for(d = bigtemp; d != nil; d = d->next){
+ if(d->tref == 1 && d->desc == desc && d->ty->align == t->align){
+ d->tref++;
+ d->refs++;
+ n->decl = d;
+ return n;
+ }
+ }
+ d = mkdecl(&nosrc, Dlocal, t);
+ d->desc = desc;
+ d->tref = 2;
+ d->refs = 1;
+ n->decl = d;
+ seprint(buf, buf+sizeof(buf), ".b%d", ntemp++);
+ d->sym = enter(buf, 0);
+ d->next = bigtemp;
+ bigtemp = d;
+ return n;
+ }
+ if(ok != nil
+ && tattr[ok->ty->kind].isptr == tattr[t->kind].isptr
+ && ok->ty->size == t->size){
+ ok->tref++;
+ n->decl = ok;
+ return n;
+ }
+ for(d = wtemp; d != nil; d = d->next){
+ if(d->tref == 1
+ && tattr[d->ty->kind].isptr == tattr[t->kind].isptr
+ && d->ty->size == t->size
+ && d->ty->align == t->align){
+ d->tref++;
+ n->decl = d;
+ return n;
+ }
+ }
+ d = mkdecl(&nosrc, Dlocal, t);
+ d->tref = 2;
+ d->refs = 1;
+ n->decl = d;
+ seprint(buf, buf+sizeof(buf), ".t%d", ntemp++);
+ d->sym = enter(buf, 0);
+ d->next = wtemp;
+ wtemp = d;
+ return n;
+}
+
+void
+tfree(Node *n)
+{
+ if(n == nil || n->decl == nil || n->decl->tref == 0)
+ return;
+ if(n->decl->tref == 1)
+ fatal("double free of temporary %s", n->decl->sym->name);
+ if (--n->decl->tref == 1)
+ zcom1(n, nil);
+}
+
+void
+tfreelater(Node *n)
+{
+ if(n == nil || n->decl == nil || n->decl->tref == 0)
+ return;
+ if(n->decl->tref == 1)
+ fatal("double free of temporary %s", n->decl->sym->name);
+ if(--n->decl->tref == 1){
+ Node *nn = mkn(Oname, nil, nil);
+
+ *nn = *n;
+ nn->left = ntoz;
+ ntoz = nn;
+ n->decl->tref++;
+ }
+}
+
+void
+tfreenow()
+{
+ Node *n, *nn;
+
+ for(n = ntoz; n != nil; n = nn){
+ nn = n->left;
+ n->left = nil;
+ if(n->decl->tref != 2)
+ fatal("bad free of temporary %s", n->decl->sym->name);
+ --n->decl->tref;
+ zcom1(n, nil);
+ }
+ ntoz = nil;
+}
+
+/*
+ * realloc a temporary after it's been freed
+ */
+Node*
+tacquire(Node *n)
+{
+ if(n == nil || n->decl == nil || n->decl->tref == 0)
+ return n;
+/*
+ if(n->decl->tref != 1)
+ fatal("tacquire ref != 1: %d", n->decl->tref);
+*/
+ n->decl->tref++;
+ return n;
+}
+
+void
+trelease(Node *n)
+{
+ if(n == nil || n->decl == nil || n->decl->tref == 0)
+ return;
+ if(n->decl->tref == 1)
+ fatal("double release of temporary %s", n->decl->sym->name);
+ n->decl->tref--;
+}
+
+Inst*
+mkinst(void)
+{
+ Inst *in;
+
+ in = lastinst->next;
+ if(in == nil){
+ in = allocmem(sizeof *in);
+ *in = zinst;
+ lastinst->next = in;
+ }
+ lastinst = in;
+ in->block = blocks;
+ if(blocks < 0)
+ fatal("mkinst no block");
+ return in;
+}
+
+Inst*
+nextinst(void)
+{
+ Inst *in;
+
+ in = lastinst->next;
+ if(in != nil)
+ return in;
+ in = allocmem(sizeof(*in));
+ *in = zinst;
+ lastinst->next = in;
+ return in;
+}
+
+/*
+ * allocate a node for returning
+ */
+Node*
+retalloc(Node *n, Node *nn)
+{
+ if(nn->ty == tnone)
+ return nil;
+ *n = znode;
+ n->op = Oind;
+ n->addable = Radr;
+ n->left = dupn(1, &n->src, &retnode);
+ n->ty = nn->ty;
+ return n;
+}
+
+Inst*
+genrawop(Src *src, int op, Node *s, Node *m, Node *d)
+{
+ Inst *in;
+
+ in = mkinst();
+ in->op = op;
+ in->src = *src;
+if(in->sm != Anone || in->mm != Anone || in->dm != Anone)
+fatal("bogus mkinst in genrawop: %I\n", in);
+ if(s != nil){
+ in->s = genaddr(s);
+ in->sm = addrmode[s->addable];
+ }
+ if(m != nil){
+ in->m = genaddr(m);
+ in->mm = addrmode[m->addable];
+ if(in->mm == Ampind || in->mm == Afpind)
+ fatal("illegal addressing mode in register %n", m);
+ }
+ if(d != nil){
+ in->d = genaddr(d);
+ in->dm = addrmode[d->addable];
+ }
+ return in;
+}
+
+Inst*
+genop(Src *src, int op, Node *s, Node *m, Node *d)
+{
+ Inst *in;
+ int iop;
+
+ iop = disoptab[op][opind[d->ty->kind]];
+ if(iop == 0)
+ fatal("can't deal with op %s on %n %n %n in genop", opname[op], s, m, d);
+ if(iop == IMULX || iop == IDIVX)
+ return genfixop(src, iop, s, m, d);
+ in = mkinst();
+ in->op = iop;
+ in->src = *src;
+ if(s != nil){
+ in->s = genaddr(s);
+ in->sm = addrmode[s->addable];
+ }
+ if(m != nil){
+ in->m = genaddr(m);
+ in->mm = addrmode[m->addable];
+ if(in->mm == Ampind || in->mm == Afpind)
+ fatal("illegal addressing mode in register %n", m);
+ }
+ if(d != nil){
+ in->d = genaddr(d);
+ in->dm = addrmode[d->addable];
+ }
+ return in;
+}
+
+Inst*
+genbra(Src *src, int op, Node *s, Node *m)
+{
+ Type *t;
+ Inst *in;
+ int iop;
+
+ t = s->ty;
+ if(t == tany)
+ t = m->ty;
+ iop = disoptab[op][opind[t->kind]];
+ if(iop == 0)
+ fatal("can't deal with op %s on %n %n in genbra", opname[op], s, m);
+ in = mkinst();
+ in->op = iop;
+ in->src = *src;
+ if(s != nil){
+ in->s = genaddr(s);
+ in->sm = addrmode[s->addable];
+ }
+ if(m != nil){
+ in->m = genaddr(m);
+ in->mm = addrmode[m->addable];
+ if(in->mm == Ampind || in->mm == Afpind)
+ fatal("illegal addressing mode in register %n", m);
+ }
+ return in;
+}
+
+Inst*
+genchan(Src *src, Node *sz, Type *mt, Node *d)
+{
+ Inst *in;
+ Desc *td;
+ Addr reg;
+ int op, regm;
+
+ regm = Anone;
+ reg.decl = nil;
+ reg.reg = 0;
+ reg.offset = 0;
+ op = chantab[mt->kind];
+ if(op == 0)
+ fatal("can't deal with op %d in genchan", mt->kind);
+
+ switch(mt->kind){
+ case Tadt:
+ case Tadtpick:
+ case Ttuple:
+ td = mktdesc(mt);
+ if(td->nmap != 0){
+ op++; /* sleazy */
+ usedesc(td);
+ regm = Adesc;
+ reg.decl = mt->decl;
+ }else{
+ regm = Aimm;
+ reg.offset = mt->size;
+ }
+ break;
+ }
+ in = mkinst();
+ in->op = op;
+ in->src = *src;
+ in->s = reg;
+ in->sm = regm;
+ if(sz != nil){
+ in->m = genaddr(sz);
+ in->mm = addrmode[sz->addable];
+ }
+ if(d != nil){
+ in->d = genaddr(d);
+ in->dm = addrmode[d->addable];
+ }
+ return in;
+}
+
+Inst*
+genmove(Src *src, int how, Type *mt, Node *s, Node *d)
+{
+ Inst *in;
+ Desc *td;
+ Addr reg;
+ int op, regm;
+
+ regm = Anone;
+ reg.decl = nil;
+ reg.reg = 0;
+ reg.offset = 0;
+ op = movetab[how][mt->kind];
+ if(op == 0)
+ fatal("can't deal with op %d on %n %n in genmove", how, s, d);
+
+ switch(mt->kind){
+ case Tadt:
+ case Tadtpick:
+ case Ttuple:
+ case Texception:
+ if(mt->size == 0 && how == Mas)
+ return nil;
+ td = mktdesc(mt);
+ if(td->nmap != 0){
+ op++; /* sleazy */
+ usedesc(td);
+ regm = Adesc;
+ reg.decl = mt->decl;
+ }else{
+ regm = Aimm;
+ reg.offset = mt->size;
+ }
+ break;
+ }
+ in = mkinst();
+ in->op = op;
+ in->src = *src;
+ if(s != nil){
+ in->s = genaddr(s);
+ in->sm = addrmode[s->addable];
+ }
+ in->m = reg;
+ in->mm = regm;
+ if(d != nil){
+ in->d = genaddr(d);
+ in->dm = addrmode[d->addable];
+ }
+ if(s->addable == Rpc)
+ in->op = IMOVPC;
+ return in;
+}
+
+void
+patch(Inst *b, Inst *dst)
+{
+ Inst *n;
+
+ for(; b != nil; b = n){
+ n = b->branch;
+ b->branch = dst;
+ }
+}
+
+long
+getpc(Inst *i)
+{
+ if(i->pc == 0 && i != firstinst && (firstinst->op != INOOP || i != firstinst->next)){
+ do
+ i = i->next;
+ while(i != nil && i->pc == 0);
+ if(i == nil || i->pc == 0)
+ fatal("bad instruction in getpc");
+ }
+ return i->pc;
+}
+
+/*
+ * follow all possible paths from n,
+ * marking reached code, compressing branches, and reclaiming unreached insts
+ */
+void
+reach(Inst *in)
+{
+ Inst *last;
+
+ foldbranch(in);
+ last = in;
+ for(in = in->next; in != nil; in = in->next){
+ if(!in->reach)
+ last->next = in->next;
+ else
+ last = in;
+ }
+ lastinst = last;
+}
+
+/*
+ * follow all possible paths from n,
+ * marking reached code, compressing branches, and eliminating tail recursion
+ */
+void
+foldbranch(Inst *in)
+{
+ Inst *b, *next;
+ Label *lab;
+ int i, n;
+
+ while(in != nil && !in->reach){
+ in->reach = 1;
+ if(in->branch != nil)
+ while(in->branch->op == IJMP){
+ if(in == in->branch || in->branch == in->branch->branch)
+ break;
+ in->branch = in->branch->branch;
+ }
+ switch(in->op){
+ case IGOTO:
+ case ICASE:
+ case ICASEL:
+ case ICASEC:
+ case IEXC:
+ foldbranch(in->d.decl->ty->cse->iwild);
+ lab = in->d.decl->ty->cse->labs;
+ n = in->d.decl->ty->cse->nlab;
+ for(i = 0; i < n; i++)
+ foldbranch(lab[i].inst);
+ if(in->op == IEXC)
+ in->op = INOOP;
+ return;
+ case IEXC0:
+ foldbranch(in->branch);
+ in->op = INOOP;
+ break;
+ case IRET:
+ case IEXIT:
+ case IRAISE:
+ return;
+ case IJMP:
+ b = in->branch;
+ switch(b->op){
+ case ICASE:
+ case ICASEL:
+ case ICASEC:
+ case IRET:
+ case IEXIT:
+ next = in->next;
+ *in = *b;
+ in->next = next;
+ /* b->reach = 1; */ /* why ? */
+ continue;
+ }
+ foldbranch(in->branch);
+ return;
+ default:
+ if(in->branch != nil)
+ foldbranch(in->branch);
+ break;
+ }
+
+ in = in->next;
+ }
+}
+
+/*
+ * convert the addressable node into an operand
+ * see the comment for sumark
+ */
+Addr
+genaddr(Node *n)
+{
+ Addr a;
+
+ a.reg = 0;
+ a.offset = 0;
+ a.decl = nil;
+ if(n == nil)
+ return a;
+ switch(n->addable){
+ case Rreg:
+ if(n->decl != nil)
+ a.decl = n->decl;
+ else
+ a = genaddr(n->left);
+ break;
+ case Rmreg:
+ if(n->decl != nil)
+ a.decl = n->decl;
+ else
+ a = genaddr(n->left);
+ break;
+ case Rdesc:
+ a.decl = n->ty->decl;
+ break;
+ case Roff:
+ case Rnoff:
+ a.decl = n->decl;
+ break;
+ case Rconst:
+ a.offset = n->val;
+ break;
+ case Radr:
+ a = genaddr(n->left);
+ break;
+ case Rmadr:
+ a = genaddr(n->left);
+ break;
+ case Rareg:
+ case Ramreg:
+ a = genaddr(n->left);
+ if(n->op == Oadd)
+ a.reg += n->right->val;
+ break;
+ case Raadr:
+ case Ramadr:
+ a = genaddr(n->left);
+ if(n->op == Oadd)
+ a.offset += n->right->val;
+ break;
+ case Rldt:
+ a.decl = n->decl;
+ break;
+ case Rdescp:
+ case Rpc:
+ a.decl = n->decl;
+ break;
+ default:
+ fatal("can't deal with %n in genaddr", n);
+ break;
+ }
+ return a;
+}
+
+int
+sameaddr(Node *n, Node *m)
+{
+ Addr a, b;
+
+ if(n->addable != m->addable)
+ return 0;
+ a = genaddr(n);
+ b = genaddr(m);
+ return a.offset == b.offset && a.reg == b.reg && a.decl == b.decl;
+}
+
+long
+resolvedesc(Decl *mod, long length, Decl *decls)
+{
+ Desc *g, *d, *last;
+ int descid;
+
+ g = gendesc(mod, length, decls);
+ g->used = 0;
+ last = nil;
+ for(d = descriptors; d != nil; d = d->next){
+ if(!d->used){
+ if(last != nil)
+ last->next = d->next;
+ else
+ descriptors = d->next;
+ continue;
+ }
+ last = d;
+ }
+
+ g->next = descriptors;
+ descriptors = g;
+
+ descid = 0;
+ for(d = descriptors; d != nil; d = d->next)
+ d->id = descid++;
+ if(g->id != 0)
+ fatal("bad global descriptor id");
+
+ return descid;
+}
+
+int
+resolvemod(Decl *m)
+{
+ Decl *id, *d;
+
+ for(id = m->ty->ids; id != nil; id = id->next){
+ switch(id->store){
+ case Dfn:
+ id->iface->pc = id->pc;
+ id->iface->desc = id->desc;
+if(debug['v']) print("R1: %s %p %p %p\n", id->sym->name, id, id->iface, id->pc);
+ break;
+ case Dtype:
+ if(id->ty->kind != Tadt)
+ break;
+ for(d = id->ty->ids; d != nil; d = d->next){
+ if(d->store == Dfn){
+ d->iface->pc = d->pc;
+ d->iface->desc = d->desc;
+if(debug['v']) print("R2: %s %p %p %p\n", d->sym->name, d, d->iface, d->pc);
+ }
+ }
+ break;
+ }
+ }
+ /* for addiface */
+ for(id = m->ty->tof->ids; id != nil; id = id->next){
+ if(id->store == Dfn){
+ if(id->pc == nil)
+ id->pc = id->iface->pc;
+ if(id->desc == nil)
+ id->desc = id->iface->desc;
+if(debug['v']) print("R3: %s %p %p %p\n", id->sym->name, id, id->iface, id->pc);
+ }
+ }
+ return m->ty->tof->decl->init->val;
+}
+
+/*
+ * place the Tiface decs in another list
+ */
+Decl*
+resolveldts(Decl *d, Decl **dd)
+{
+ Decl *d1, *ld1, *d2, *ld2, *n;
+
+ d1 = d2 = nil;
+ ld1 = ld2 = nil;
+ for( ; d != nil; d = n){
+ n = d->next;
+ d->next = nil;
+ if(d->ty->kind == Tiface){
+ if(d2 == nil)
+ d2 = d;
+ else
+ ld2->next = d;
+ ld2 = d;
+ }
+ else{
+ if(d1 == nil)
+ d1 = d;
+ else
+ ld1->next = d;
+ ld1 = d;
+ }
+ }
+ *dd = d2;
+ return d1;
+}
+
+/*
+ * fix up all pc's
+ * finalize all data offsets
+ * fix up instructions with offsets too large
+ */
+long
+resolvepcs(Inst *inst)
+{
+ Decl *d;
+ Inst *in;
+ int op;
+ ulong r, off;
+ long v, pc;
+
+ pc = 0;
+ for(in = inst; in != nil; in = in->next){
+ if(!in->reach || in->op == INOP)
+ fatal("unreachable pc: %I %ld", in, pc);
+ if(in->op == INOOP){
+ in->pc = pc;
+ continue;
+ }
+ d = in->s.decl;
+ if(d != nil){
+ if(in->sm == Adesc){
+ if(d->desc != nil)
+ in->s.offset = d->desc->id;
+ }else
+ in->s.reg += d->offset;
+ }
+ r = in->s.reg;
+ off = in->s.offset;
+ if((in->sm == Afpind || in->sm == Ampind)
+ && (r >= MaxReg || off >= MaxReg))
+ fatal("big offset in %I\n", in);
+
+ d = in->m.decl;
+ if(d != nil){
+ if(in->mm == Adesc){
+ if(d->desc != nil)
+ in->m.offset = d->desc->id;
+ }else
+ in->m.reg += d->offset;
+ }
+ v = 0;
+ switch(in->mm){
+ case Anone:
+ break;
+ case Aimm:
+ case Apc:
+ case Adesc:
+ v = in->m.offset;
+ break;
+ case Aoff:
+ case Anoff:
+ v = in->m.decl->iface->offset;
+ break;
+ case Afp:
+ case Amp:
+ case Aldt:
+ v = in->m.reg;
+ if(v < 0)
+ v = 0x8000;
+ break;
+
+ default:
+ fatal("can't deal with %I's m mode\n", in);
+ break;
+ }
+ if(v > 0x7fff || v < -0x8000){
+ switch(in->op){
+ case IALT:
+ case IINDX:
+warn(in->src.start, "possible bug: temp m too big in %I: %ld %ld %d\n", in, in->m.reg, in->m.reg, MaxReg);
+ rewritedestreg(in, IMOVW, RTemp);
+ break;
+ default:
+ op = IMOVW;
+ if(isbyteinst[in->op])
+ op = IMOVB;
+ in = rewritesrcreg(in, op, RTemp, pc++);
+ break;
+ }
+ }
+
+ d = in->d.decl;
+ if(d != nil){
+ if(in->dm == Apc)
+ in->d.offset = d->pc->pc;
+ else
+ in->d.reg += d->offset;
+ }
+ r = in->d.reg;
+ off = in->d.offset;
+ if((in->dm == Afpind || in->dm == Ampind)
+ && (r >= MaxReg || off >= MaxReg))
+ fatal("big offset in %I\n", in);
+
+ in->pc = pc;
+ pc++;
+ }
+ for(in = inst; in != nil; in = in->next){
+ d = in->s.decl;
+ if(d != nil && in->sm == Apc)
+ in->s.offset = d->pc->pc;
+ d = in->d.decl;
+ if(d != nil && in->dm == Apc)
+ in->d.offset = d->pc->pc;
+ if(in->branch != nil){
+ in->dm = Apc;
+ in->d.offset = in->branch->pc;
+ }
+ }
+ return pc;
+}
+
+/*
+ * fixp up a big register constant uses as a source
+ * ugly: smashes the instruction
+ */
+Inst*
+rewritesrcreg(Inst *in, int op, int treg, int pc)
+{
+ Inst *new;
+ Addr a;
+ int am;
+
+ a = in->m;
+ am = in->mm;
+ in->mm = Afp;
+ in->m.reg = treg;
+ in->m.decl = nil;
+
+ new = allocmem(sizeof(*in));
+ *new = *in;
+
+ *in = zinst;
+ in->src = new->src;
+ in->next = new;
+ in->op = op;
+ in->s = a;
+ in->sm = am;
+ in->dm = Afp;
+ in->d.reg = treg;
+ in->pc = pc;
+ in->reach = 1;
+ in->block = new->block;
+ return new;
+}
+
+/*
+ * fix up a big register constant by moving to the destination
+ * after the instruction completes
+ */
+Inst*
+rewritedestreg(Inst *in, int op, int treg)
+{
+ Inst *n;
+
+ n = allocmem(sizeof(*n));
+ *n = zinst;
+ n->next = in->next;
+ in->next = n;
+ n->src = in->src;
+ n->op = op;
+ n->sm = Afp;
+ n->s.reg = treg;
+ n->d = in->m;
+ n->dm = in->mm;
+ n->reach = 1;
+ n->block = in->block;
+
+ in->mm = Afp;
+ in->m.reg = treg;
+ in->m.decl = nil;
+
+ return n;
+}
+
+int
+instconv(Fmt *f)
+{
+ Inst *in;
+ char buf[512], *p;
+ char *op, *comma;
+
+ in = va_arg(f->args, Inst*);
+ op = nil;
+ if(in->op >= 0 && in->op < MAXDIS)
+ op = instname[in->op];
+ if(op == nil)
+ op = "??";
+ buf[0] = '\0';
+ if(in->op == INOP)
+ return fmtstrcpy(f, "\tnop");
+ p = seprint(buf, buf + sizeof(buf), "\t%s\t", op);
+ comma = "";
+ if(in->sm != Anone){
+ p = addrprint(p, buf + sizeof(buf), in->sm, &in->s);
+ comma = ",";
+ }
+ if(in->mm != Anone){
+ p = seprint(p, buf + sizeof(buf), "%s", comma);
+ p = addrprint(p, buf + sizeof(buf), in->mm, &in->m);
+ comma = ",";
+ }
+ if(in->dm != Anone){
+ p = seprint(p, buf + sizeof(buf), "%s", comma);
+ p = addrprint(p, buf + sizeof(buf), in->dm, &in->d);
+ }
+
+ if(asmsym && in->s.decl != nil && in->sm == Adesc)
+ p = seprint(p, buf+sizeof(buf), " #%D", in->s.decl);
+ if(0 && asmsym && in->m.decl != nil)
+ p = seprint(p, buf+sizeof(buf), " #%D", in->m.decl);
+ if(asmsym && in->d.decl != nil && in->dm == Apc)
+ p = seprint(p, buf+sizeof(buf), " #%D", in->d.decl);
+ if(asmsym)
+ p = seprint(p, buf+sizeof(buf), " #%U", in->src);
+ USED(p);
+ return fmtstrcpy(f, buf);
+}
+
+char*
+addrprint(char *buf, char *end, int am, Addr *a)
+{
+ switch(am){
+ case Anone:
+ return buf;
+ case Aimm:
+ case Apc:
+ case Adesc:
+ return seprint(buf, end, "$%ld", a->offset);
+ case Aoff:
+ return seprint(buf, end, "$%ld", a->decl->iface->offset);
+ case Anoff:
+ return seprint(buf, end, "-$%ld", a->decl->iface->offset);
+ case Afp:
+ return seprint(buf, end, "%ld(fp)", a->reg);
+ case Afpind:
+ return seprint(buf, end, "%ld(%ld(fp))", a->offset, a->reg);
+ case Amp:
+ return seprint(buf, end, "%ld(mp)", a->reg);
+ case Ampind:
+ return seprint(buf, end, "%ld(%ld(mp))", a->offset, a->reg);
+ case Aldt:
+ return seprint(buf, end, "$%ld", a->reg);
+ case Aerr:
+ default:
+ return seprint(buf, end, "%ld(%ld(?%d?))", a->offset, a->reg, am);
+ }
+}
+
+static void
+genstore(Src *src, Node *n, int offset)
+{
+ Decl *de;
+ Node d;
+
+ de = mkdecl(&nosrc, Dlocal, tint);
+ de->sym = nil;
+ de->offset = offset;
+
+ d = znode;
+ d.op = Oname;
+ d.addable = Rreg;
+ d.decl = de;
+ d.ty = tint;
+ genrawop(src, IMOVW, n, nil, &d);
+}
+
+static Inst*
+genfixop(Src *src, int op, Node *s, Node *m, Node *d)
+{
+ int p, a;
+ Node *mm;
+ Inst *i;
+
+ mm = m ? m: d;
+ op = fixop(op, mm->ty, s->ty, d->ty, &p, &a);
+ if(op == IMOVW){ /* just zero d */
+ s = sumark(mkconst(src, 0));
+ return genrawop(src, op, s, nil, d);
+ }
+ if(op != IMULX && op != IDIVX)
+ genstore(src, sumark(mkconst(src, a)), STemp);
+ genstore(src, sumark(mkconst(src, p)), DTemp);
+ i = genrawop(src, op, s, m, d);
+ return i;
+}
+
+Inst*
+genfixcastop(Src *src, int op, Node *s, Node *d)
+{
+ int p, a;
+ Node *m;
+
+ op = fixop(op, s->ty, tint, d->ty, &p, &a);
+ if(op == IMOVW){ /* just zero d */
+ s = sumark(mkconst(src, 0));
+ return genrawop(src, op, s, nil, d);
+ }
+ m = sumark(mkconst(src, p));
+ if(op != ICVTXX)
+ genstore(src, sumark(mkconst(src, a)), STemp);
+ return genrawop(src, op, s, m, d);
+}