summaryrefslogtreecommitdiff
path: root/appl/cmd/limbo/com.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/limbo/com.b')
-rw-r--r--appl/cmd/limbo/com.b1387
1 files changed, 1387 insertions, 0 deletions
diff --git a/appl/cmd/limbo/com.b b/appl/cmd/limbo/com.b
new file mode 100644
index 00000000..bc977d0a
--- /dev/null
+++ b/appl/cmd/limbo/com.b
@@ -0,0 +1,1387 @@
+# 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();
+ in := genrawop(src, IRET, nil, nil, nil);
+ popblock();
+ reach(decl.pc);
+ if(in.reach != byte 0 && decl.ty.tof != tnone)
+ 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;
+}
+
+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 || c.nlab != 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)
+ 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;
+}