summaryrefslogtreecommitdiff
path: root/appl/cmd/limbo/gen.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/limbo/gen.b')
-rw-r--r--appl/cmd/limbo/gen.b1012
1 files changed, 1012 insertions, 0 deletions
diff --git a/appl/cmd/limbo/gen.b b/appl/cmd/limbo/gen.b
new file mode 100644
index 00000000..062980fb
--- /dev/null
+++ b/appl/cmd/limbo/gen.b
@@ -0,0 +1,1012 @@
+ blocks: int; # nesting of blocks while generating code
+ zinst: Inst;
+ firstinst: ref Inst;
+ lastinst: ref Inst;
+
+include "disoptab.m";
+
+addrmode := array[int Rend] of
+{
+ int Rreg => Afp,
+ int Rmreg => Amp,
+ int Roff => Aoff,
+ int Rnoff => Anoff,
+ int Rdesc => Adesc,
+ int Rdescp => Adesc,
+ int Rconst => Aimm,
+ int Radr => Afpind,
+ int Rmadr => Ampind,
+ int Rpc => Apc,
+ int Rldt => Aldt,
+ * => Aerr,
+};
+
+wtemp: ref Decl;
+bigtemp: ref Decl;
+ntemp: int;
+retnode: ref Node;
+nilnode: ref Node;
+
+blockstack: array of int;
+blockdep: int;
+nblocks: int;
+ntoz: ref Node;
+
+#znode: Node;
+
+genstart()
+{
+ d := mkdecl(nosrc, Dlocal, tint);
+ d.sym = enter(".ret", 0);
+ d.offset = IBY2WD * REGRET;
+
+ retnode = ref 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 = ref zinst;
+ lastinst = firstinst;
+
+ nilnode = ref znode;
+ nilnode.op = Oname;
+ nilnode.addable = Rmreg;
+ nilnode.decl = nildecl;
+ nilnode.ty = nildecl.ty;
+
+ blocks = -1;
+ blockdep = 0;
+ nblocks = 0;
+}
+
+#
+# manage nested control flow blocks
+#
+pushblock(): int
+{
+ if(blockdep >= len blockstack){
+ bs := array[blockdep + 32] of int;
+ bs[0:] = blockstack;
+ blockstack = bs;
+ }
+ blockstack[blockdep++] = blocks;
+ return blocks = nblocks++;
+}
+
+repushblock(b: int)
+{
+ blockstack[blockdep++] = blocks;
+ blocks = b;
+}
+
+popblock()
+{
+ blocks = blockstack[blockdep -= 1];
+}
+
+tinit()
+{
+ wtemp = nil;
+ bigtemp = nil;
+}
+
+tdecls(): ref Decl
+{
+ for(d := wtemp; d != nil; d = d.next){
+ if(d.tref != 1)
+ fatal("temporary "+d.sym.name+" has "+string(d.tref-1)+" references");
+ }
+
+ for(d = bigtemp; d != nil; d = d.next){
+ if(d.tref != 1)
+ fatal("temporary "+d.sym.name+" has "+string(d.tref-1)+" references");
+ }
+
+ return appdecls(wtemp, bigtemp);
+}
+
+talloc(t: ref Type, nok: ref Node): ref Node
+{
+ ok, d: ref Decl;
+
+ ok = nil;
+ if(nok != nil)
+ ok = nok.decl;
+ if(ok == nil || ok.tref == 0 || tattr[ok.ty.kind].isbig != tattr[t.kind].isbig || ok.ty.align != t.align)
+ ok = nil;
+ n := ref znode;
+ n.op = Oname;
+ n.addable = Rreg;
+ n.ty = t;
+ if(tattr[t.kind].isbig){
+ 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;
+ d.sym = enter(".b"+string ntemp++, 0);
+ d.next = bigtemp;
+ bigtemp = d;
+ n.decl = 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;
+ d.sym = enter(".t"+string ntemp++, 0);
+ d.next = wtemp;
+ wtemp = d;
+ n.decl = d;
+ return n;
+}
+
+tfree(n: ref Node)
+{
+ if(n == nil || n.decl == nil)
+ return;
+ d := n.decl;
+ if(d.tref == 0)
+ return;
+
+ if(d.tref == 1)
+ fatal("double free of temporary " + d.sym.name);
+ if (--d.tref == 1)
+ zcom1(n, nil);
+
+ #
+ # nil out any pointers so we don't
+ # hang onto references
+ #
+#
+# costs ~7% in instruction count
+# if(d.tref != 1)
+# return;
+# if(!tattr[d.ty.kind].isbig){
+# if(tattr[d.ty.kind].isptr){ # or tmustzero()
+# nilnode.decl.refs++;
+# genmove(lastinst.src, Mas, d.ty, nilnode, n);
+# }
+# }else{
+# if(d.desc.nmap != 0){ # tmustzero() is better
+# zn := ref znode;
+# zn.op = Oname;
+# zn.addable = Rmreg;
+# zn.decl = globalztup(d.ty);
+# zn.ty = d.ty;
+# genmove(lastinst.src, Mas, d.ty, zn, n);
+# }
+# }
+}
+
+tfreelater(n: ref Node)
+{
+ if(n == nil || n.decl == nil)
+ return;
+ d := n.decl;
+ if(d.tref == 0)
+ return;
+
+ if(d.tref == 1)
+ fatal("double free of temporary " + d.sym.name);
+ if (--d.tref == 1){
+ nn := mkn(Oname, nil, nil);
+ *nn = *n;
+ nn.left = ntoz;
+ ntoz = nn;
+ d.tref++;
+ }
+}
+
+tfreenow()
+{
+ nn: ref Node;
+
+ for(n := ntoz; n != nil; n = nn){
+ nn = n.left;
+ n.left = nil;
+ if(n.decl.tref != 2)
+ fatal(sprint("bad free of temporary %s", n.decl.sym.name));
+ --n.decl.tref;
+ zcom1(n, nil);
+ }
+ ntoz = nil;
+}
+
+#
+# realloc a temporary after it's been released
+#
+tacquire(n: ref Node): ref Node
+{
+ if(n == nil || n.decl == nil)
+ return n;
+ d := n.decl;
+ if(d.tref == 0)
+ return n;
+ # if(d.tref != 1)
+ # fatal("tacquire ref != 1: "+string d.tref);
+ d.tref++;
+ return n;
+}
+
+trelease(n: ref Node)
+{
+ if(n == nil || n.decl == nil)
+ return;
+ d := n.decl;
+ if(d.tref == 0)
+ return;
+ if(d.tref == 1)
+ fatal("double release of temporary " + d.sym.name);
+ d.tref--;
+}
+
+mkinst(): ref Inst
+{
+ in := lastinst.next;
+ if(in == nil){
+ in = ref zinst;
+ lastinst.next = in;
+ }
+ lastinst = in;
+ in.block = blocks;
+ if(blocks < 0)
+ fatal("mkinst no block");
+ return in;
+}
+
+nextinst(): ref Inst
+{
+ in := lastinst.next;
+ if(in != nil)
+ return in;
+ in = ref zinst;
+ lastinst.next = in;
+ return in;
+}
+
+#
+# allocate a node for returning
+#
+retalloc(n, nn: ref Node): ref Node
+{
+ if(nn.ty == tnone)
+ return nil;
+ n = ref znode;
+ n.op = Oind;
+ n.addable = Radr;
+ n.left = dupn(1, n.src, retnode);
+ n.ty = nn.ty;
+ return n;
+}
+
+genrawop(src: Src, op: int, s, m, d: ref Node): ref Inst
+{
+ in := mkinst();
+ in.op = op;
+ in.src = src;
+ if(s != nil){
+ in.s = genaddr(s);
+ in.sm = addrmode[int s.addable];
+ }
+ if(m != nil){
+ in.m = genaddr(m);
+ in.mm = addrmode[int m.addable];
+ if(in.mm == Ampind || in.mm == Afpind)
+ fatal("illegal addressing mode in register "+nodeconv(m));
+ }
+ if(d != nil){
+ in.d = genaddr(d);
+ in.dm = addrmode[int d.addable];
+ }
+ return in;
+}
+
+genop(src: Src, op: int, s, m, d: ref Node): ref Inst
+{
+ iop := disoptab[op][opind[d.ty.kind]];
+ if(iop == 0)
+ fatal("can't deal with op "+opconv(op)+" on "+nodeconv(s)+" "+nodeconv(m)+" "+nodeconv(d)+" in genop");
+ 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[int s.addable];
+ }
+ if(m != nil){
+ in.m = genaddr(m);
+ in.mm = addrmode[int m.addable];
+ if(in.mm == Ampind || in.mm == Afpind)
+ fatal("illegal addressing mode in register "+nodeconv(m));
+ }
+ if(d != nil){
+ in.d = genaddr(d);
+ in.dm = addrmode[int d.addable];
+ }
+ return in;
+}
+
+genbra(src: Src, op: int, s, m: ref Node): ref Inst
+{
+ t := s.ty;
+ if(t == tany)
+ t = m.ty;
+ iop := disoptab[op][opind[t.kind]];
+ if(iop == 0)
+ fatal("can't deal with op "+opconv(op)+" on "+nodeconv(s)+" "+nodeconv(m)+" in genbra");
+ in := mkinst();
+ in.op = iop;
+ in.src = src;
+ if(s != nil){
+ in.s = genaddr(s);
+ in.sm = addrmode[int s.addable];
+ }
+ if(m != nil){
+ in.m = genaddr(m);
+ in.mm = addrmode[int m.addable];
+ if(in.mm == Ampind || in.mm == Afpind)
+ fatal("illegal addressing mode in register "+nodeconv(m));
+ }
+ return in;
+}
+
+genchan(src: Src, sz: ref Node, mt: ref Type, d: ref Node): ref Inst
+{
+ reg: Addr;
+
+ regm := Anone;
+ reg.decl = nil;
+ reg.reg = 0;
+ reg.offset = 0;
+ op := chantab[mt.kind];
+ if(op == 0)
+ fatal("can't deal with op "+string mt.kind+" in genchan");
+
+ case mt.kind{
+ Tadt or
+ Tadtpick or
+ 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;
+ }
+ }
+ in := mkinst();
+ in.op = op;
+ in.src = src;
+ in.s = reg;
+ in.sm = regm;
+ if(sz != nil){
+ in.m = genaddr(sz);
+ in.mm = addrmode[int sz.addable];
+ }
+ if(d != nil){
+ in.d = genaddr(d);
+ in.dm = addrmode[int d.addable];
+ }
+ return in;
+}
+
+genmove(src: Src, how: int, mt: ref Type, s, d: ref Node): ref Inst
+{
+ reg: Addr;
+
+ 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 "+string how+" on "+nodeconv(s)+" "+nodeconv(d)+" in genmove");
+
+ case mt.kind{
+ Tadt or
+ Tadtpick or
+ Ttuple or
+ 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;
+ }
+ }
+ in := mkinst();
+ in.op = op;
+ in.src = src;
+ if(s != nil){
+ in.s = genaddr(s);
+ in.sm = addrmode[int s.addable];
+ }
+ in.m = reg;
+ in.mm = regm;
+ if(d != nil){
+ in.d = genaddr(d);
+ in.dm = addrmode[int d.addable];
+ }
+ if(s.addable == Rpc)
+ in.op = IMOVPC;
+ return in;
+}
+
+patch(b, dst: ref Inst)
+{
+ n: ref Inst;
+
+ for(; b != nil; b = n){
+ n = b.branch;
+ b.branch = dst;
+ }
+}
+
+getpc(i: ref Inst): int
+{
+ 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
+#
+reach(in: ref Inst)
+{
+ foldbranch(in);
+ last := in;
+ for(in = in.next; in != nil; in = in.next){
+ if(in.reach == byte 0)
+ last.next = in.next;
+ else
+ last = in;
+ }
+ lastinst = last;
+}
+
+foldbranch(in: ref Inst)
+{
+ while(in != nil && in.reach != byte 1){
+ in.reach = byte 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;
+ }
+ case in.op{
+ IGOTO or
+ ICASE or
+ ICASEL or
+ ICASEC or
+ 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;
+ IEXC0 =>
+ foldbranch(in.branch);
+ in.op = INOOP;
+ break;
+ IRET or
+ IEXIT or
+ IRAISE =>
+ return;
+ IJMP =>
+ b := in.branch;
+ case b.op{
+ ICASE or
+ ICASEL or
+ ICASEC or
+ IRET or
+ IEXIT =>
+ next := in.next;
+ *in = *b;
+ in.next = next;
+ # b.reach = byte 1;
+ continue;
+ }
+ foldbranch(in.branch);
+ return;
+ * =>
+ if(in.branch != nil)
+ foldbranch(in.branch);
+ }
+
+ in = in.next;
+ }
+}
+
+#
+# convert the addressable node into an operand
+# see the comment for sumark
+#
+genaddr(n: ref Node): Addr
+{
+ a: Addr;
+
+ a.reg = 0;
+ a.offset = 0;
+ a.decl = nil;
+ case int n.addable{
+ int Rreg =>
+ if(n.decl != nil)
+ a.decl = n.decl;
+ else
+ a = genaddr(n.left);
+ int Rmreg =>
+ if(n.decl != nil)
+ a.decl = n.decl;
+ else
+ a = genaddr(n.left);
+ int Rdesc =>
+ a.decl = n.ty.decl;
+ int Roff or
+ int Rnoff =>
+ a.decl = n.decl;
+ int Rconst =>
+ a.offset = int n.c.val;
+ int Radr =>
+ a = genaddr(n.left);
+ int Rmadr =>
+ a = genaddr(n.left);
+ int Rareg or
+ int Ramreg =>
+ a = genaddr(n.left);
+ if(n.op == Oadd)
+ a.reg += int n.right.c.val;
+ int Raadr or
+ int Ramadr =>
+ a = genaddr(n.left);
+ if(n.op == Oadd)
+ a.offset += int n.right.c.val;
+ int Rldt =>
+ a.decl = n.decl;
+ int Rdescp or
+ int Rpc =>
+ a.decl = n.decl;
+ * =>
+ fatal("can't deal with "+nodeconv(n)+" in genaddr");
+ }
+ return a;
+}
+
+sameaddr(n, m: ref Node): int
+{
+ 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;
+}
+
+resolvedesc(mod: ref Decl, length: int, id: ref Decl): int
+{
+ last: ref Desc;
+
+ g := gendesc(mod, length, id);
+ 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;
+}
+
+resolvemod(m: ref Decl): int
+{
+ for(id := m.ty.ids; id != nil; id = id.next){
+ case id.store{
+ Dfn =>
+ id.iface.pc = id.pc;
+ id.iface.desc = id.desc;
+ 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;
+ }
+ }
+ }
+ }
+ # 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;
+ }
+ }
+ return int m.ty.tof.decl.init.c.val;
+}
+
+#
+# place the Tiface decs in another list
+#
+resolveldts(d: ref Decl): (ref Decl, ref Decl)
+{
+ d1, ld1, d2, ld2, n: ref Decl;
+
+ 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;
+ }
+ }
+ return (d1, d2);
+}
+
+#
+# fix up all pc's
+# finalize all data offsets
+# fix up instructions with offsets too large
+#
+resolvepcs(inst: ref Inst): int
+{
+ d: ref Decl;
+
+ pc := 0;
+ for(in := inst; in != nil; in = in.next){
+ if(in.reach == byte 0 || in.op == INOP)
+ fatal("unreachable pc: "+instconv(in));
+ 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 "+instconv(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;
+ case int in.mm{
+ int Anone =>
+ break;
+ int Aimm or
+ int Apc or
+ int Adesc =>
+ v = in.m.offset;
+ int Aoff or
+ int Anoff =>
+ v = in.m.decl.iface.offset;
+ int Afp or
+ int Amp or
+ int Aldt =>
+ v = in.m.reg;
+ if(v < 0)
+ v = 16r8000;
+ * =>
+ fatal("can't deal with "+instconv(in)+"'s m mode");
+ }
+ if(v > 16r7fff || v < -16r8000){
+ case in.op{
+ IALT or
+ IINDX =>
+ rewritedestreg(in, IMOVW, RTemp);
+ * =>
+ op := IMOVW;
+ if(isbyteinst[in.op])
+ op = IMOVB;
+ in = rewritesrcreg(in, op, RTemp, pc++);
+ }
+ }
+
+ 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 "+instconv(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
+#
+rewritesrcreg(in: ref Inst, op: int, treg: int, pc: int): ref Inst
+{
+ a := in.m;
+ am := in.mm;
+ in.mm = Afp;
+ in.m.reg = treg;
+ in.m.decl = nil;
+
+ new := ref *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 = byte 1;
+ in.block = new.block;
+ return new;
+}
+
+#
+# fix up a big register constant by moving to the destination
+# after the instruction completes
+#
+rewritedestreg(in: ref Inst, op: int, treg: int): ref Inst
+{
+ n := ref 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 = byte 1;
+ n.block = in.block;
+
+ in.mm = Afp;
+ in.m.reg = treg;
+ in.m.decl = nil;
+
+ return n;
+}
+
+instconv(in: ref Inst): string
+{
+ if(in.op == INOP)
+ return "nop";
+ op := "";
+ if(in.op >= 0 && in.op < 256)
+ op = instname[in.op];
+ if(op == nil)
+ op = "?"+string in.op+"?";
+ s := "\t" + op + "\t";
+ comma := "";
+ if(in.sm != Anone){
+ s += addrconv(in.sm, in.s);
+ comma = ",";
+ }
+ if(in.mm != Anone){
+ s += comma;
+ s += addrconv(in.mm, in.m);
+ comma = ",";
+ }
+ if(in.dm != Anone){
+ s += comma;
+ s += addrconv(in.dm, in.d);
+ }
+
+ if(!asmsym)
+ return s;
+
+ if(in.s.decl != nil && in.sm == Adesc){
+ s += "\t#";
+ s += dotconv(in.s.decl);
+ }
+ if(0 && in.m.decl != nil){
+ s += "\t#";
+ s += dotconv(in.m.decl);
+ }
+ if(in.d.decl != nil && in.dm == Apc){
+ s += "\t#";
+ s += dotconv(in.d.decl);
+ }
+ s += "\t#";
+ s += srcconv(in.src);
+ return s;
+}
+
+addrconv(am: byte, a: Addr): string
+{
+ s := "";
+ case int am{
+ int Anone =>
+ break;
+ int Aimm or
+ int Apc or
+ int Adesc =>
+ s = "$" + string a.offset;
+ int Aoff =>
+ s = "$" + string a.decl.iface.offset;
+ int Anoff =>
+ s = "-$" + string a.decl.iface.offset;
+ int Afp =>
+ s = string a.reg + "(fp)";
+ int Afpind =>
+ s = string a.offset + "(" + string a.reg + "(fp))";
+ int Amp =>
+ s = string a.reg + "(mp)";
+ int Ampind =>
+ s = string a.offset + "(" + string a.reg + "(mp))";
+ int Aldt =>
+ s = "$" + string a.reg;
+ * =>
+ s = string a.offset + "(" + string a.reg + "(?" + string am + "?))";
+ }
+ return s;
+}
+
+genstore(src: Src, n: ref Node, offset: int)
+{
+ de := mkdecl(nosrc, Dlocal, tint);
+ de.sym = nil;
+ de.offset = offset;
+
+ d := ref znode;
+ d.op = Oname;
+ d.addable = Rreg;
+ d.decl = de;
+ d.ty = tint;
+ genrawop(src, IMOVW, n, nil, d);
+}
+
+genfixop(src: Src, op: int, s, m, d: ref Node): ref Inst
+{
+ p, a: int;
+ mm: ref Node;
+
+ if(m == nil)
+ mm = d;
+ else
+ mm = m;
+ (op, p, a) = fixop(op, mm.ty, s.ty, d.ty);
+ if(op == IMOVW){ # just zero d
+ s = sumark(mkconst(src, big 0));
+ return genrawop(src, op, s, nil, d);
+ }
+ if(op != IMULX && op != IDIVX)
+ genstore(src, sumark(mkconst(src, big a)), STemp);
+ genstore(src, sumark(mkconst(src, big p)), DTemp);
+ i := genrawop(src, op, s, m, d);
+ return i;
+}
+
+genfixcastop(src: Src, op: int, s, d: ref Node): ref Inst
+{
+ p, a: int;
+ m: ref Node;
+
+ (op, p, a) = fixop(op, s.ty, tint, d.ty);
+ if(op == IMOVW){ # just zero d
+ s = sumark(mkconst(src, big 0));
+ return genrawop(src, op, s, nil, d);
+ }
+ m = sumark(mkconst(src, big p));
+ if(op != ICVTXX)
+ genstore(src, sumark(mkconst(src, big a)), STemp);
+ return genrawop(src, op, s, m, d);
+}