ref: d1540c7f666e3c5d636b48c956b444205b50502d
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;
}