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");Lines 1–500 of 1011. Load more
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");