ref: 51bf59e016b43f16ec91943829af30d99a886cc1
dir: /appl/cmd/limbo/com.b/
# back end breaks: array of ref Inst; conts: array of ref Inst; labels: array of ref Decl; bcscps: array of ref Node; labdep: int; nocont: ref Inst; nlabel: int; scp: int; scps:= array[MaxScope] of ref Node; curfn: ref Decl; pushscp(n : ref Node) { if (scp >= MaxScope) fatal("scope too deep"); scps[scp++] = n; } popscp() { scp--; } curscp() : ref Node { if (scp == 0) return nil; return scps[scp-1]; } zeroscopes(stop : ref Node) { i : int; cs : ref Node; for (i = scp-1; i >= 0; i--) { cs = scps[i]; if (cs == stop) break; zcom(cs.left, nil); } } zeroallscopes(n: ref Node, nn: array of ref Node) { if(n == nil) return; for(; n != nil; n = n.right){ case(n.op){ Oscope => zeroallscopes(n.right, nn); zcom(n.left, nn); return; Olabel or Odo => zeroallscopes(n.right, nn); return; Oif or Ofor => zeroallscopes(n.right.left, nn); zeroallscopes(n.right.right, nn); return; Oalt or Ocase or Opick or Oexcept => for(n = n.right; n != nil; n = n.right) zeroallscopes(n.left.right, nn); return; Oseq => zeroallscopes(n.left, nn); break; Oexstmt => zeroallscopes(n.left, nn); zeroallscopes(n.right, nn); return; * => return; } } } excs: ref Except; installexc(en: ref Node, p1: ref Inst, p2: ref Inst, zn: ref Node) { e := ref Except; e.p1 = p1; e.p2 = p2; e.c = en.ty.cse; e.d = en.left.decl; e.zn = zn; e.next = excs; excs = e; ne := 0; c := e.c; for(i := 0; i < c.nlab; i++){ lab := c.labs[i]; if(lab.start.ty.kind == Texception) ne++; } e.ne = ne; } inlist(d: ref Decl, dd: ref Decl): int { for( ; dd != nil; dd = dd.next) if(d == dd) return 1; return 0; } excdesc() { dd, nd: ref Decl; for(e := excs; e != nil; e = e.next){ if(e.zn != nil){ dd = nil; maxo := 0; for(n := e.zn ; n != nil; n = n.right){ d := n.decl; d.locals = d.next; if(!inlist(d, dd)){ d.next = dd; dd = d; o := d.offset+d.ty.size; if(o > maxo) maxo = o; } } e.desc = gendesc(e.d, align(maxo, MaxAlign), dd); for(d := dd; d != nil; d = nd){ nd = d.next; d.next = d.locals; d.locals = nil; } e.zn = nil; } } } reve(e: ref Except): ref Except { l, n: ref Except; l = nil; for( ; e != nil; e = n){ n = e.next; e.next = l; l = e; } return l; } ckinline0(n: ref Node, d: ref Decl): int { dd: ref Decl; if(n == nil) return 1; if(n.op == Oname){ dd = n.decl; if(d == dd) return 0; if(int dd.inline == 1) return ckinline0(dd.init.right, d); return 1; } return ckinline0(n.left, d) && ckinline0(n.right, d); } ckinline(d: ref Decl) { d.inline = byte ckinline0(d.init.right, d); } modcom(entry: ref Decl) { d, m: ref Decl; if(errors) return; if(emitcode != "" || emitstub || emittab != "" || emitsbl != ""){ emit(curscope()); popscope(); return; } # # scom introduces global variables for case statements # and unaddressable constants, so it must be done before # popping the global scope # gent = sys->millisec(); nlabel = 0; maxstack = MaxTemp; nocont = ref Inst; genstart(); for(i := 0; i < nfns; i++) if(int fns[i].inline == 1) ckinline(fns[i]); ok := 0; for(i = 0; i < nfns; i++){ d = fns[i]; if(d.refs > 1 && !(int d.inline == 1 && local(d) && d.iface == nil)){ fns[ok++] = d; fncom(d); } } fns = fns[:ok]; nfns = ok; if(blocks != -1) fatal("blocks not nested correctly"); firstinst = firstinst.next; if(errors) return; globals := popscope(); checkrefs(globals); if(errors) return; globals = vars(globals); moddataref(); nils := popscope(); m = nil; for(d = nils; d != nil; d = d.next){ if(debug['n']) print("nil '%s' ref %d\n", d.sym.name, d.refs); if(d.refs && m == nil) m = dupdecl(d); d.offset = 0; } globals = appdecls(m, globals); globals = namesort(globals); globals = modglobals(impdecls.d, globals); vcom(globals); narrowmods(); ldts: ref Decl; if(LDT) (globals, ldts) = resolveldts(globals); offset := idoffsets(globals, 0, IBY2WD); if(LDT) ldtoff := idindices(ldts); # idoffsets(ldts, 0, IBY2WD); for(d = nils; d != nil; d = d.next){ if(debug['n']) print("nil '%s' ref %d\n", d.sym.name, d.refs); if(d.refs) d.offset = m.offset; } if(debug['g']){ print("globals:\n"); printdecls(globals); } ndata := 0; for(d = globals; d != nil; d = d.next) ndata++; ndesc := resolvedesc(impdecls.d, offset, globals); ninst := resolvepcs(firstinst); modresolve(); if(impdecls.next != nil) for(dl := impdecls; dl != nil; dl = dl.next) resolvemod(dl.d); nlink := resolvemod(impdecl); gent = sys->millisec() - gent; maxstack *= 10; if(fixss != 0) maxstack = fixss; if(debug['s']) print("%d instructions\n%d data elements\n%d type descriptors\n%d functions exported\n%d stack size\n", ninst, ndata, ndesc, nlink, maxstack); excs = reve(excs); writet = sys->millisec(); if(gendis){ discon(XMAGIC); hints := 0; if(mustcompile) hints |= MUSTCOMPILE; if(dontcompile) hints |= DONTCOMPILE; if(LDT) hints |= HASLDT; if(excs != nil) hints |= HASEXCEPT; discon(hints); # runtime hints discon(maxstack); # minimum stack extent size discon(ninst); discon(offset); discon(ndesc); discon(nlink); disentry(entry); disinst(firstinst); disdesc(descriptors); disvar(offset, globals); dismod(impdecl); if(LDT) disldt(ldtoff, ldts); if(excs != nil) disexc(excs); dispath(); }else{ asminst(firstinst); asmentry(entry); asmdesc(descriptors); asmvar(offset, globals); asmmod(impdecl); if(LDT) asmldt(ldtoff, ldts); if(excs != nil) asmexc(excs); asmpath(); } writet = sys->millisec() - writet; symt = sys->millisec(); if(bsym != nil){ sblmod(impdecl); sblfiles(); sblinst(firstinst, ninst); sblty(adts, nadts); sblfn(fns, nfns); sblvar(globals); } symt = sys->millisec() - symt; firstinst = nil; lastinst = nil; excs = nil; } fncom(decl: ref Decl) { curfn = decl; if(ispoly(decl)) addfnptrs(decl, 1); # # pick up the function body and compile it # this code tries to clean up the parse nodes as fast as possible # function is Ofunc(name, body) # decl.pc = nextinst(); tinit(); labdep = 0; scp = 0; breaks = array[maxlabdep] of ref Inst; conts = array[maxlabdep] of ref Inst; labels = array[maxlabdep] of ref Decl; bcscps = array[maxlabdep] of ref Node; n := decl.init; if(int decl.inline == 1) decl.init = dupn(0, nosrc, n); else decl.init = n.left; src := n.right.src; src.start = src.stop - 1; for(n = n.right; n != nil; n = n.right){ if(n.op != Oseq){ if(n.op == Ocall && trcom(n, nil, 1)) break; scom(n); break; } if(n.left.op == Ocall && trcom(n.left, n.right, 1)){ n = n.right; if(n == nil || n.op != Oseq) break; } else scom(n.left); } pushblock(); valued := decl.ty.tof != tnone; if(valued) in := genrawop(src, IRAISE, nil, nil, nil); else in = genrawop(src, IRET, nil, nil, nil); popblock(); reach(decl.pc); if(valued && in.reach != byte 0) error(src.start, "no return at end of function " + dotconv(decl)); # decl.endpc = lastinst; if(labdep != 0) fatal("unbalanced label stack"); breaks = nil; conts = nil; labels = nil; bcscps = nil; loc := declsort(appdecls(vars(decl.locals), tdecls())); decl.offset = idoffsets(loc, decl.offset, MaxAlign); for(last := decl.ty.ids; last != nil && last.next != nil; last = last.next) ; if(last != nil) last.next = loc; else decl.ty.ids = loc; if(debug['f']){ print("fn: %s\n", decl.sym.name); printdecls(decl.ty.ids); } decl.desc = gendesc(decl, decl.offset, decl.ty.ids); decl.locals = loc; excdesc(); if(decl.offset > maxstack) maxstack = decl.offset; if(optims) optim(decl.pc, decl); if(last != nil) last.next = nil; else decl.ty.ids = nil; } # # statement compiler # scom(n: ref Node) { b: int; p, pp: ref Inst; left: ref Node; for(; n != nil; n = n.right){ case n.op{ Ocondecl or Otypedecl or Ovardecl or Oimport or Oexdecl => return; Ovardecli => break; Oscope => pushscp(n); scom(n.right); popscp(); zcom(n.left, nil); return; Olabel => scom(n.right); return; Oif => pushblock(); left = simplify(n.left); if(left.op == Oconst && left.ty == tint){ if(left.c.val != big 0) scom(n.right.left); else scom(n.right.right); popblock(); return; } sumark(left); pushblock(); p = bcom(left, 1, nil); tfreenow(); popblock(); scom(n.right.left); if(n.right.right != nil){ pp = p; p = genrawop(lastinst.src, IJMP, nil, nil, nil); patch(pp, nextinst()); scom(n.right.right); } patch(p, nextinst()); popblock(); return; Ofor => n.left = left = simplify(n.left); if(left.op == Oconst && left.ty == tint){ if(left.c.val == big 0) return; left.op = Onothing; left.ty = tnone; left.decl = nil; } pp = nextinst(); b = pushblock(); sumark(left); p = bcom(left, 1, nil); tfreenow(); popblock(); if(labdep >= maxlabdep) fatal("label stack overflow"); breaks[labdep] = nil; conts[labdep] = nil; labels[labdep] = n.decl; bcscps[labdep] = curscp(); labdep++; scom(n.right.left); labdep--; patch(conts[labdep], nextinst()); if(n.right.right != nil){ pushblock(); scom(n.right.right); popblock(); } repushblock(lastinst.block); # was b patch(genrawop(lastinst.src, IJMP, nil, nil, nil), pp); # for cprof: was left.src popblock(); patch(p, nextinst()); patch(breaks[labdep], nextinst()); return; Odo => pp = nextinst(); if(labdep >= maxlabdep) fatal("label stack overflow"); breaks[labdep] = nil; conts[labdep] = nil; labels[labdep] = n.decl; bcscps[labdep] = curscp(); labdep++; scom(n.right); labdep--; patch(conts[labdep], nextinst()); left = simplify(n.left); if(left.op == Onothing || left.op == Oconst && left.ty == tint){ if(left.op == Onothing || left.c.val != big 0){ pushblock(); p = genrawop(left.src, IJMP, nil, nil, nil); popblock(); }else p = nil; }else{ pushblock(); p = bcom(sumark(left), 0, nil); tfreenow(); popblock(); } patch(p, pp); patch(breaks[labdep], nextinst()); return; Ocase or Opick or Oalt or Oexcept => pushblock(); if(labdep >= maxlabdep) fatal("label stack overflow"); breaks[labdep] = nil; conts[labdep] = nocont; labels[labdep] = n.decl; bcscps[labdep] = curscp(); labdep++; case n.op{ Oalt => altcom(n); Ocase or Opick => casecom(n); Oexcept => excom(n); } labdep--; patch(breaks[labdep], nextinst()); popblock(); return; Obreak => pushblock(); bccom(n, breaks); popblock(); Ocont => pushblock(); bccom(n, conts); popblock(); Oseq => if(n.left.op == Ocall && trcom(n.left, n.right, 0)){ n = n.right; if(n == nil || n.op != Oseq) return; } else scom(n.left); Oret => if(n.left != nil && n.left.op == Ocall && trcom(n.left, nil, 1)) return; pushblock(); if(n.left != nil){ n.left = simplify(n.left); sumark(n.left); ecom(n.left.src, retalloc(ref Node, n.left), n.left); tfreenow(); } genrawop(n.src, IRET, nil, nil, nil); popblock(); return; Oexit => pushblock(); genrawop(n.src, IEXIT, nil, nil, nil); popblock(); return; Onothing => return; Ofunc => fatal("Ofunc"); return; Oexstmt => pushblock(); pp = genrawop(n.right.src, IEXC0, nil, nil, nil); # marker p1 := nextinst(); scom(n.left); p2 := nextinst(); p3 := genrawop(n.right.src, IJMP, nil, nil, nil); p = genrawop(n.right.src, IEXC, nil, nil, nil); # marker p.d.decl = mkdecl(n.src, 0, n.right.ty); zn := array[1] of ref Node; zeroallscopes(n.left, zn); scom(n.right); patch(p3, nextinst()); installexc(n.right, p1, p2, zn[0]); patch(pp, p); popblock(); return; * => pushblock(); n = simplify(n); sumark(n); ecom(n.src, nil, n); tfreenow(); popblock(); return; } } } # # compile a break, continue # bccom(n: ref Node, bs: array of ref Inst) { s: ref Sym; s = nil; if(n.decl != nil) s = n.decl.sym; ok := -1; for(i := 0; i < labdep; i++){ if(bs[i] == nocont) continue; if(s == nil || labels[i] != nil && labels[i].sym == s) ok = i; } if(ok < 0) fatal("didn't find break or continue"); zeroscopes(bcscps[ok]); p := genrawop(n.src, IJMP, nil, nil, nil); p.branch = bs[ok]; bs[ok] = p; } dogoto(c: ref Case): int { i, j, k, n, r, q, v: int; l, nl: array of Label; src: Src; l = c.labs; n = c.nlab; if(n == 0) return 0; r = int l[n-1].stop.c.val - int l[0].start.c.val+1; if(r >= 3 && r <= 3*n){ if(r != n){ # remove ranges, fill in gaps c.nlab = r; nl = c.labs = array[r] of Label; k = 0; v = int l[0].start.c.val-1; for(i = 0; i < n; i++){ # p = int l[i].start.c.val; q = int l[i].stop.c.val; src = l[i].start.src; for(j = v+1; j <= q; j++){ nl[k] = l[i]; nl[k].start = nl[k].stop = mkconst(src, big j); k++; } v = q; } if(k != r) fatal("bad case expansion"); } l = c.labs; for(i = 0; i < r; i++) l[i].inst = nil; return 1; } return 0; } fillrange(c: ref Case, nn: ref Node, in: ref Inst) { i, j, n, p, q: int; l: array of Label; l = c.labs; n = c.nlab; p = int nn.left.c.val; q = int nn.right.c.val; for(i = 0; i < n; i++) if(int l[i].start.c.val == p) break; if(i == n) fatal("fillrange fails"); for(j = p; j <= q; j++) l[i++].inst = in; } nconstqual(s1: ref Node): int { n := 0; for(; s1 != nil; s1 = s1.right){ for(s2 := s1.left.left; s2 != nil; s2 = s2.right) if(s2.left.op == Oconst) n++; } return n; } casecom(cn: ref Node) { d: ref Decl; left, p, tmp, tmpc: ref Node; jmps, wild, j1, j2: ref Inst; c := cn.ty.cse; needwild := cn.op != Opick || nconstqual(cn.right) != cn.left.right.ty.tof.decl.tag; igoto := cn.left.ty == tint && dogoto(c); # # generate global which has case labels # if(igoto){ d = mkids(cn.src, enter(".g"+string nlabel++, 0), cn.ty, nil); cn.ty.kind = Tgoto; } else d = mkids(cn.src, enter(".c"+string nlabel++, 0), cn.ty, nil); d.init = mkdeclname(cn.src, d); nto := ref znode; nto.addable = Rmreg; nto.left = nil; nto.right = nil; nto.op = Oname; nto.ty = d.ty; nto.decl = d; tmp = nil; left = cn.left; left = simplify(left); cn.left = left; sumark(left); if(debug['c']) print("case %s\n", nodeconv(left)); ctype := cn.left.ty; if(left.addable >= Rcant){ if(cn.op == Opick){ ecom(left.src, nil, left); tfreenow(); left = mkunary(Oind, dupn(1, left.src, left.left)); left.ty = tint; sumark(left); ctype = tint; }else{ (left, tmp) = eacom(left, nil); tfreenow(); } } labs := c.labs; nlab := c.nlab; if(igoto){ if(labs[0].start.c.val != big 0){ tmpc = talloc(left.ty, nil); if(left.addable == Radr || left.addable == Rmadr){ genrawop(left.src, IMOVW, left, nil, tmpc); left = tmpc; } genrawop(left.src, ISUBW, sumark(labs[0].start), left, tmpc); left = tmpc; } if(needwild){ j1 = genrawop(left.src, IBLTW, left, sumark(mkconst(left.src, big 0)), nil); j2 = genrawop(left.src, IBGTW, left, sumark(mkconst(left.src, labs[nlab-1].start.c.val-labs[0].start.c.val)), nil); } j := nextinst(); genrawop(left.src, IGOTO, left, nil, nto); j.d.reg = IBY2WD; } else{ op := ICASE; if(ctype == tbig) op = ICASEL; else if(ctype == tstring) op = ICASEC; genrawop(left.src, op, left, nil, nto); } tfree(tmp); tfree(tmpc); jmps = nil; wild = nil; for(n := cn.right; n != nil; n = n.right){ j := nextinst(); for(p = n.left.left; p != nil; p = p.right){ if(debug['c']) print("case qualifier %s\n", nodeconv(p.left)); case p.left.op{ Oconst => labs[findlab(ctype, p.left, labs, nlab)].inst = j; Orange => labs[findlab(ctype, p.left.left, labs, nlab)].inst = j; if(igoto) fillrange(c, p.left, j); Owild => if(needwild) wild = j; # else # nwarn(p.left, "default case redundant"); } } if(debug['c']) print("case body for %s: %s\n", expconv(n.left.left), nodeconv(n.left.right)); k := nextinst(); scom(n.left.right); src := lastinst.src; # if(n.left.right == nil || n.left.right.op == Onothing) if(k == nextinst()) src = n.left.left.src; j = genrawop(src, IJMP, nil, nil, nil); j.branch = jmps; jmps = j; } patch(jmps, nextinst()); if(wild == nil && needwild) wild = nextinst(); if(igoto){ if(needwild){ patch(j1, wild); patch(j2, wild); } for(i := 0; i < nlab; i++) if(labs[i].inst == nil) labs[i].inst = wild; } c.iwild = wild; d.ty.cse = c; usetype(d.ty); installids(Dglobal, d); } altcom(nalt: ref Node) { p, op, left: ref Node; jmps, wild, j: ref Inst = nil; talt := nalt.ty; c := talt.cse; nlab := c.nlab; nsnd := c.nsnd; comm := array[nlab] of ref Node; labs := array[nlab] of Label; tmps := array[nlab] of ref Node; c.labs = labs; # # built the type of the alt channel table # note that we lie to the garbage collector # if we know that another reference exists for the channel # is := 0; ir := nsnd; i := 0; for(n := nalt.left; n != nil; n = n.right){ for(p = n.left.right.left; p != nil; p = p.right){ left = simplify(p.left); p.left = left; if(left.op == Owild) continue; comm[i] = hascomm(left); left = comm[i].left; sumark(left); isptr := left.addable >= Rcant; if(comm[i].op == Osnd) labs[is++].isptr = isptr; else labs[ir++].isptr = isptr; i++; } } which := talloc(tint, nil); tab := talloc(talt, nil); # # build the node for the address of each channel, # the values to send, and the storage fro values received # off := ref znode; adr := ref znode; add := ref znode; slot := ref znode; off.op = Oconst; off.c = ref Const(big 0, 0.0); # jrf - added initialization off.ty = tint; off.addable = Rconst; adr.op = Oadr; adr.left = tab; adr.ty = tint; add.op = Oadd; add.left = adr; add.right = off; add.ty = tint; slot.op = Oind; slot.left = add; sumark(slot); # # compile the sending and receiving channels and values # is = 2*IBY2WD; ir = is + nsnd*2*IBY2WD; i = 0; for(n = nalt.left; n != nil; n = n.right){ for(p = n.left.right.left; p != nil; p = p.right){ if(p.left.op == Owild) continue; # # gen channel # op = comm[i]; if(op.op == Osnd){ off.c.val = big is; is += 2*IBY2WD; }else{ off.c.val = big ir; ir += 2*IBY2WD; } left = op.left; # # this sleaze is lying to the garbage collector # if(left.addable < Rcant) genmove(left.src, Mas, tint, left, slot); else{ slot.ty = left.ty; ecom(left.src, slot, left); tfreenow(); slot.ty = nil; } # # gen value # off.c.val += big IBY2WD; (p.left, tmps[i]) = rewritecomm(p.left, comm[i], slot); i++; } } # # stuff the number of send & receive channels into the table # altsrc := nalt.src; altsrc.stop = (altsrc.stop & ~PosMask) | ((altsrc.stop + 3) & PosMask); off.c.val = big 0; genmove(altsrc, Mas, tint, sumark(mkconst(altsrc, big nsnd)), slot); off.c.val += big IBY2WD; genmove(altsrc, Mas, tint, sumark(mkconst(altsrc, big(nlab-nsnd))), slot); off.c.val += big IBY2WD; altop := IALT; if(c.wild != nil) altop = INBALT; pp := genrawop(altsrc, altop, tab, nil, which); pp.m.offset = talt.size; # for optimizer d := mkids(nalt.src, enter(".g"+string nlabel++, 0), mktype(nalt.src.start, nalt.src.stop, Tgoto, nil, nil), nil); d.ty.cse = c; d.init = mkdeclname(nalt.src, d); nto := ref znode; nto.addable = Rmreg; nto.left = nil; nto.right = nil; nto.op = Oname; nto.decl = d; nto.ty = d.ty; me := genrawop(altsrc, IGOTO, which, nil, nto); me.d.reg = IBY2WD; # skip the number of cases field tfree(tab); tfree(which); # # compile the guard expressions and bodies # i = 0; is = 0; ir = nsnd; jmps = nil; wild = nil; for(n = nalt.left; n != nil; n = n.right){ j = nil; for(p = n.left.right.left; p != nil; p = p.right){ tj := nextinst(); if(p.left.op == Owild){ wild = nextinst(); }else{ if(comm[i].op == Osnd) labs[is++].inst = tj; else{ labs[ir++].inst = tj; tacquire(tmps[i]); } sumark(p.left); if(debug['a']) print("alt guard %s\n", nodeconv(p.left)); ecom(p.left.src, nil, p.left); tfree(tmps[i]); tfreenow(); i++; } if(p.right != nil){ tj = genrawop(lastinst.src, IJMP, nil, nil, nil); tj.branch = j; j = tj; } } patch(j, nextinst()); if(debug['a']) print("alt body %s\n", nodeconv(n.left.right)); scom(n.left); j = genrawop(lastinst.src, IJMP, nil, nil, nil); j.branch = jmps; jmps = j; } patch(jmps, nextinst()); comm = nil; c.iwild = wild; usetype(d.ty); installids(Dglobal, d); } excom(en: ref Node) { ed: ref Decl; p: ref Node; jmps, wild: ref Inst; ed = en.left.decl; ed.ty = rtexception; c := en.ty.cse; labs := c.labs; nlab := c.nlab; jmps = nil; wild = nil; for(n := en.right; n != nil; n = n.right){ qt: ref Type = nil; j := nextinst(); for(p = n.left.left; p != nil; p = p.right){ case p.left.op{ Oconst => labs[findlab(texception, p.left, labs, nlab)].inst = j; Owild => wild = j; } if(qt == nil) qt = p.left.ty; else if(!tequal(qt, p.left.ty)) qt = texception; } if(qt != nil) ed.ty = qt; k := nextinst(); scom(n.left.right); src := lastinst.src; if(k == nextinst()) src = n.left.left.src; j = genrawop(src, IJMP, nil, nil, nil); j.branch = jmps; jmps = j; } ed.ty = rtexception; patch(jmps, nextinst()); c.iwild = wild; } # # rewrite the communication operand # allocate any temps needed for holding value to send or receive # rewritecomm(n, comm, slot: ref Node): (ref Node, ref Node) { adr, tmp: ref Node; if(n == nil) return (nil, nil); adr = nil; if(n == comm){ if(comm.op == Osnd && sumark(n.right).addable < Rcant) adr = n.right; else{ adr = tmp = talloc(n.ty, nil); tmp.src = n.src; if(comm.op == Osnd){ ecom(n.right.src, tmp, n.right); tfreenow(); } else trelease(tmp); } } if(n.right == comm && n.op == Oas && comm.op == Orcv && sumark(n.left).addable < Rcant && (n.left.op != Oname || n.left.decl != nildecl)) adr = n.left; if(adr != nil){ p := genrawop(comm.left.src, ILEA, adr, nil, slot); p.m.offset = adr.ty.size; # for optimizer if(comm.op == Osnd) p.m.reg = 1; # for optimizer return (adr, tmp); } (n.left, tmp) = rewritecomm(n.left, comm, slot); if(tmp == nil) (n.right, tmp) = rewritecomm(n.right, comm, slot); return (n, tmp); } # # merge together two sorted lists, yielding a sorted list # declmerge(e, f: ref Decl): ref Decl { d := rock := ref Decl; while(e != nil && f != nil){ fs := f.ty.size; es := e.ty.size; # v := 0; v := (e.link == nil) - (f.link == nil); if(v == 0 && (es <= IBY2WD || fs <= IBY2WD)) v = fs - es; if(v == 0) v = e.refs - f.refs; if(v == 0) v = fs - es; if(v == 0 && e.sym.name > f.sym.name) v = -1; if(v >= 0){ d.next = e; d = e; e = e.next; while(e != nil && e.nid == byte 0){ d = e; e = e.next; } }else{ d.next = f; d = f; f = f.next; while(f != nil && f.nid == byte 0){ d = f; f = f.next; } } # d = d.next; } if(e != nil) d.next = e; else d.next = f; return rock.next; } # # recursively split lists and remerge them after they are sorted # recdeclsort(d: ref Decl, n: int): ref Decl { if(n <= 1) return d; m := n / 2 - 1; dd := d; for(i := 0; i < m; i++){ dd = dd.next; while(dd.nid == byte 0) dd = dd.next; } r := dd.next; while(r.nid == byte 0){ dd = r; r = r.next; } dd.next = nil; return declmerge(recdeclsort(d, n / 2), recdeclsort(r, (n + 1) / 2)); } # # sort the ids by size and number of references # declsort(d: ref Decl): ref Decl { n := 0; for(dd := d; dd != nil; dd = dd.next) if(dd.nid > byte 0) n++; return recdeclsort(d, n); } nilsrc : Src; zcom1(n : ref Node, nn: array of ref Node) { ty : ref Type; d : ref Decl; e : ref Node; ty = n.ty; if (!tmustzero(ty)) return; if (n.op == Oname && n.decl.refs == 0) return; if (nn != nil) { if(n.op != Oname) error(n.src.start, "fatal: bad op in zcom1 map"); n.right = nn[0]; nn[0] = n; return; } if (ty.kind == Tadtpick) ty = ty.tof; if (ty.kind == Ttuple || ty.kind == Tadt) { for (d = ty.ids; d != nil; d = d.next) { if (tmustzero(d.ty)) { dn := n; if (d.next != nil) dn = dupn(0, nilsrc, n); e = mkbin(Odot, dn, mkname(nilsrc, d.sym)); e.right.decl = d; e.ty = e.right.ty = d.ty; zcom1(e, nn); } } } else { src := n.src; n.src = nilsrc; e = mkbin(Oas, n, mknil(nilsrc)); e.ty = e.right.ty = ty; if (debug['Z']) print("ecom %s\n", nodeconv(e)); pushblock(); e = simplify(e); sumark(e); ecom(e.src, nil, e); popblock(); n.src = src; e = nil; } } zcom0(id : ref Decl, nn: array of ref Node) { e := mkname(nilsrc, id.sym); e.decl = id; e.ty = id.ty; zcom1(e, nn); } zcom(n : ref Node, nn: array of ref Node) { r : ref Node; for ( ; n != nil; n = r) { r = n.right; n.right = nil; case (n.op) { Ovardecl => last := n.left.decl; for (ids := n.decl; ids != last.next; ids = ids.next) zcom0(ids, nn); break; Oname => if (n.decl != nildecl) zcom1(dupn(0, nilsrc, n), nn); break; Otuple => for (nt := n.left; nt != nil; nt = nt.right) zcom(nt.left, nn); break; * => fatal("bad node in zcom()"); break; } n.right = r; } } ret(n: ref Node, nilret: int): int { if(n == nil) return nilret; if(n.op == Oseq) n = n.left; return n.op == Oret && n.left == nil; } trcom(e: ref Node, ne: ref Node, nilret: int): int { d, id: ref Decl; as, a, f, n: ref Node; p: ref Inst; return 0; # TBS if(e.op != Ocall || e.left.op != Oname) return 0; d = e.left.decl; if(d != curfn || int d.handler || ispoly(d)) return 0; if(!ret(ne, nilret)) return 0; pushblock(); id = d.ty.ids; # evaluate args in same order as normal calls for(as = e.right; as != nil; as = as.right){ a = as.left; if(!(a.op == Oname && id == a.decl)){ if(occurs(id, as.right)){ f = talloc(id.ty, nil); f.flags |= byte TEMP; } else f = mkdeclname(as.src, id); n = mkbin(Oas, f, a); n.ty = id.ty; scom(n); if(int f.flags&TEMP) as.left = f; } id = id.next; } id = d.ty.ids; for(as = e.right; as != nil; as = as.right){ a = as.left; if(int a.flags&TEMP){ f = mkdeclname(as.src, id); n = mkbin(Oas, f, a); n.ty = id.ty; scom(n); tfree(a); } id = id.next; } p = genrawop(e.src, IJMP, nil, nil, nil); patch(p, d.pc); popblock(); return 1; }