ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /limbo/com.c/
#include "limbo.h"
static Inst **breaks;
static Inst **conts;
static Decl **labels;
static Node **bcscps;
static int labdep;
static Inst nocont;
static int scp;
static Node *scps[MaxScope];
static int trcom(Node*, Node*, int);
static void
pushscp(Node *n)
{
if (scp >= MaxScope)
fatal("scope too deep");
scps[scp++] = n;
}
static void
popscp(void)
{
scp--;
}
static Node *
curscp(void)
{
if (scp == 0)
return nil;
return scps[scp-1];
}
static void
zeroscopes(Node *stop)
{
int i;
Node *cs;
for (i = scp-1; i >= 0; i--) {
cs = scps[i];
if (cs == stop)
break;
zcom(cs->left, nil);
}
}
static void
zeroallscopes(Node *n, Node **nn)
{
if(n == nil)
return;
for(; n != nil; n = n->right){
switch(n->op){
case Oscope:
zeroallscopes(n->right, nn);
zcom(n->left, nn);
return;
case Olabel:
case Odo:
zeroallscopes(n->right, nn);
return;
case Oif:
case Ofor:
zeroallscopes(n->right->left, nn);
zeroallscopes(n->right->right, nn);
return;
case Oalt:
case Ocase:
case Opick:
case Oexcept:
for(n = n->right; n != nil; n = n->right)
zeroallscopes(n->left->right, nn);
return;
case Oseq:
zeroallscopes(n->left, nn);
break;
case Oexstmt:
zeroallscopes(n->left, nn);
zeroallscopes(n->right, nn);
return;
default:
return;
}
}
}
static Except *excs;
static void
installexc(Node *en, Inst *p1, Inst *p2, Node *zn)
{
int i, ne;
Except *e;
Case *c;
Label *lab;
e = allocmem(sizeof(Except));
e->p1 = p1;
e->p2 = p2;
e->c = en->ty->cse;
e->d = en->left->decl;
e->zn = zn;
e->desc = nil;
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;
}
static int
inlist(Decl *d, Decl *dd)
{
for( ; dd != nil; dd = dd->next)
if(d == dd)
return 1;
return 0;
}
static void
excdesc(void)
{
ulong o, maxo;
Except *e;
Node *n;
Decl *d, *dd, *nd;
for(e = excs; e != nil; e = e->next){
if(e->zn != nil){
/* set up a decl list for gendesc */
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;
}
}
}
static Except*
reve(Except *e)
{
Except *l, *n;
l = nil;
for( ; e != nil; e = n){
n = e->next;
e->next = l;
l = e;
}
return l;
}
static int
ckinline0(Node *n, Decl *d)
{
Decl *dd;
if(n == nil)
return 1;
if(n->op == Oname){
dd = n->decl;
if(d == dd)
return 0;
if(dd->caninline == 1)
return ckinline0(dd->init->right, d);
return 1;
}
return ckinline0(n->left, d) && ckinline0(n->right, d);
}
static void
ckinline(Decl *d)
{
d->caninline = ckinline0(d->init->right, d);
}
void
modcom(Decl *entry)
{
Decl *globals, *m, *nils, *d, *ldts;
long ninst, ndata, ndesc, nlink, offset, ldtoff;
int ok, i, hints;
Dlist *dl;
if(errors)
return;
if(emitcode || emitstub || emittab != nil){
emit(curscope());
popscope();
return;
}
/*
* scom introduces global variables for case statements
* and unaddressable constants, so it must be done before
* popping the global scope
*/
nlabel = 0;
maxstack = MaxTemp;
genstart();
for(i = 0; i < nfns; i++)
if(fns[i]->caninline == 1)
ckinline(fns[i]);
ok = 0;
for(i = 0; i < nfns; i++){
d = fns[i];
if(debug['v']) print("fncom: %s %d %p\n", d->sym->name, d->refs, d);
if(d->refs > 1 && !(d->caninline == 1 && local(d) && d->iface == nil)){
fns[ok++] = d;
fncom(d);
}
}
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 = nil;
if(LDT)
globals = resolveldts(globals, &ldts);
offset = idoffsets(globals, 0, IBY2WD);
if(LDT)
ldtoff = idindices(ldts); /* ldtoff = 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);
maxstack *= 10;
if(fixss != 0)
maxstack = fixss;
if(debug['s'])
print("%ld instructions\n%ld data elements\n%ld type descriptors\n%ld functions exported\n%ld stack size\n",
ninst, ndata, ndesc, nlink, maxstack);
excs = reve(excs);
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();
}
if(bsym != nil){
sblmod(impdecl);
sblfiles();
sblinst(firstinst, ninst);
sblty(adts, nadts);
sblfn(fns, nfns);
sblvar(globals);
}
firstinst = nil;
lastinst = nil;
excs = nil;
}
void
fncom(Decl *decl)
{
Src src;
Node *n;
Decl *loc, *last;
Inst *in;
int valued;
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 = allocmem(maxlabdep * sizeof breaks[0]);
conts = allocmem(maxlabdep * sizeof conts[0]);
labels = allocmem(maxlabdep * sizeof labels[0]);
bcscps = allocmem(maxlabdep * sizeof bcscps[0]);
n = decl->init;
if(decl->caninline == 1)
decl->init = dupn(0, nil, n);
else
decl->init = n->left;
src = n->right->src;
src.start.line = src.stop.line;
src.start.pos = src.stop.pos - 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;
in = genrawop(&src, valued? IRAISE: IRET, nil, nil, nil);
popblock();
reach(decl->pc);
if(valued && in->reach)
error(src.start, "no return at end of function %D", decl);
/* decl->endpc = lastinst; */
if(labdep != 0)
fatal("unbalanced label stack");
free(breaks);
free(conts);
free(labels);
free(bcscps);
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
*/
void
scom(Node *n)
{
Inst *p, *pp, *p1, *p2, *p3;
Node tret, *left, *zn;
for(; n != nil; n = n->right){
switch(n->op){
case Ocondecl:
case Otypedecl:
case Ovardecl:
case Oimport:
case Oexdecl:
return;
case Ovardecli:
break;
case Oscope:
pushscp(n);
scom(n->right);
popscp();
zcom(n->left, nil);
return;
case Olabel:
scom(n->right);
return;
case Oif:
pushblock();
left = simplify(n->left);
if(left->op == Oconst && left->ty == tint){
if(left->val != 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;
case Ofor:
n->left = left = simplify(n->left);
if(left->op == Oconst && left->ty == tint){
if(left->val == 0)
return;
left->op = Onothing;
left->ty = tnone;
left->decl = nil;
}
pp = nextinst();
pushblock();
/* 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;
case 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->val != 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;
case Oalt:
case Ocase:
case Opick:
case Oexcept:
/* need push/pop blocks for alt guards */
pushblock();
if(labdep >= maxlabdep)
fatal("label stack overflow");
breaks[labdep] = nil;
conts[labdep] = &nocont;
labels[labdep] = n->decl;
bcscps[labdep] = curscp();
labdep++;
switch(n->op){
case Oalt:
altcom(n);
break;
case Ocase:
case Opick:
casecom(n);
break;
case Oexcept:
excom(n);
break;
}
labdep--;
patch(breaks[labdep], nextinst());
popblock();
return;
case Obreak:
pushblock();
bccom(n, breaks);
popblock();
break;
case Ocont:
pushblock();
bccom(n, conts);
popblock();
break;
case 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);
break;
case 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(&tret, n->left), n->left);
tfreenow();
}
genrawop(&n->src, IRET, nil, nil, nil);
popblock();
return;
case Oexit:
pushblock();
genrawop(&n->src, IEXIT, nil, nil, nil);
popblock();
return;
case Onothing:
return;
case Ofunc:
fatal("Ofunc");
return;
case 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 = nil;
zeroallscopes(n->left, &zn);
scom(n->right);
patch(p3, nextinst());
installexc(n->right, p1, p2, zn);
patch(pp, p);
popblock();
return;
default:
pushblock();
n = simplify(n);
sumark(n);
ecom(&n->src, nil, n);
tfreenow();
popblock();
return;
}
}
}
/*
* compile a break, continue
*/
void
bccom(Node *n, Inst **bs)
{
Sym *s;
Inst *p;
int i, ok;
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){
nerror(n, "no appropriate target for %V", n);
return;
}
zeroscopes(bcscps[ok]);
p = genrawop(&n->src, IJMP, nil, nil, nil);
p->branch = bs[ok];
bs[ok] = p;
}
static int
dogoto(Case *c)
{
int i, j, k, n, r, q, v;
Label *l, *nl;
Src *src;
l = c->labs;
n = c->nlab;
if(n == 0)
return 0;
r = l[n-1].stop->val - l[0].start->val+1;
if(r >= 3 && r <= 3*n){
if(r != n){
/* remove ranges, fill in gaps */
c->nlab = r;
nl = c->labs = allocmem(r*sizeof(*nl));
k = 0;
v = l[0].start->val-1;
for(i = 0; i < n; i++){
/* p = l[i].start->val; */
q = l[i].stop->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, 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;
}
static void
fillrange(Case *c, Node *nn, Inst *in)
{
int i, j, n, p, q;
Label *l;
l = c->labs;
n = c->nlab;
p = nn->left->val;
q = nn->right->val;
for(i = 0; i < n; i++)
if(l[i].start->val == p)
break;
if(i == n)
fatal("fillrange fails");
for(j = p; j <= q; j++)
l[i++].inst = in;
}
static int
nconstqual(Node *s1)
{
Node *s2;
int n;
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;
}
void
casecom(Node *cn)
{
Src *src;
Case *c;
Decl *d;
Type *ctype;
Inst *j, *jmps, *wild, *k, *j1, *j2;
Node *n, *p, *left, tmp, nto, tmpc;
Label *labs;
char buf[32];
int i, nlab, op, needwild, igoto;
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);
j1 = j2 = nil;
/*
* generate global which has case labels
*/
if(igoto){
seprint(buf, buf+sizeof(buf), ".g%d", nlabel++);
cn->ty->kind = Tgoto;
}
else
seprint(buf, buf+sizeof(buf), ".c%d", nlabel++);
d = mkids(&cn->src, enter(buf, 0), cn->ty, nil);
d->init = mkdeclname(&cn->src, d);
nto.addable = Rmreg;
nto.left = nil;
nto.right = nil;
nto.op = Oname;
nto.ty = d->ty;
nto.decl = d;
tmp.decl = tmpc.decl = nil;
left = cn->left;
left = simplify(left);
cn->left = left;
sumark(left);
if(debug['c'])
print("case %n\n", 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 = eacom(left, &tmp, nil);
tfreenow();
}
}
labs = c->labs;
nlab = c->nlab;
if(igoto){
if(labs[0].start->val != 0){
talloc(&tmpc, 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, 0)), nil);
j2 = genrawop(&left->src, IBGTW, left, sumark(mkconst(&left->src, labs[nlab-1].start->val-labs[0].start->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 %n\n", p->left);
switch(p->left->op){
case Oconst:
labs[findlab(ctype, p->left, labs, nlab)].inst = j;
break;
case Orange:
labs[findlab(ctype, p->left->left, labs, nlab)].inst = j;
if(igoto)
fillrange(c, p->left, j);
break;
case Owild:
if(needwild)
wild = j;
/*
else
nwarn(p->left, "default case redundant");
*/
break;
}
}
if(debug['c'])
print("case body for %V: %n\n", n->left->left, 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);
}
void
altcom(Node *nalt)
{
Src altsrc;
Case *c;
Decl *d;
Type *talt;
Node *n, *p, *left, tab, slot, off, add, which, nto, adr;
Node **comm, *op, *tmps;
Inst *j, *tj, *jmps, *me, *wild;
Label *labs;
char buf[32];
int i, is, ir, nlab, nsnd, altop, isptr;
Inst *pp;
talt = nalt->ty;
c = talt->cse;
nlab = c->nlab;
nsnd = c->nsnd;
comm = allocmem(nlab * sizeof *comm);
labs = allocmem(nlab * sizeof *labs);
tmps = allocmem(nlab * sizeof *tmps);
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++;
}
}
talloc(&which, tint, nil);
talloc(&tab, talt, nil);
/*
* build the node for the address of each channel,
* the values to send, and the storage fro values received
*/
off = znode;
off.op = Oconst;
off.ty = tint;
off.addable = Rconst;
adr = znode;
adr.op = Oadr;
adr.left = &tab;
adr.ty = tint;
add = znode;
add.op = Oadd;
add.left = &adr;
add.right = &off;
add.ty = tint;
slot = znode;
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.val = is;
is += 2*IBY2WD;
}else{
off.val = 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.val += IBY2WD;
tmps[i].decl = nil;
p->left = rewritecomm(p->left, comm[i], &tmps[i], &slot);
i++;
}
}
/*
* stuff the number of send & receive channels into the table
*/
altsrc = nalt->src;
altsrc.stop.pos += 3;
off.val = 0;
genmove(&altsrc, Mas, tint, sumark(mkconst(&altsrc, nsnd)), &slot);
off.val += IBY2WD;
genmove(&altsrc, Mas, tint, sumark(mkconst(&altsrc, nlab-nsnd)), &slot);
off.val += IBY2WD;
altop = IALT;
if(c->wild != nil)
altop = INBALT;
pp = genrawop(&altsrc, altop, &tab, nil, &which);
pp->m.offset = talt->size; /* for optimizer */
seprint(buf, buf+sizeof(buf), ".g%d", nlabel++);
d = mkids(&nalt->src, enter(buf, 0), mktype(&nalt->src.start, &nalt->src.stop, Tgoto, nil, nil), nil);
d->ty->cse = c;
d->init = mkdeclname(&nalt->src, d);
nto.addable = Rmreg;
nto.left = nil;
nto.right = nil;
nto.op = Oname;
nto.decl = d;
nto.ty = d->ty;
me = nextinst();
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 %n\n", 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 %n\n", n->left->right);
scom(n->left);
j = genrawop(&lastinst->src, IJMP, nil, nil, nil);
j->branch = jmps;
jmps = j;
}
patch(jmps, nextinst());
free(comm);
c->iwild = wild;
usetype(d->ty);
installids(Dglobal, d);
}
void
excom(Node *en)
{
Src *src;
Decl *ed;
Type *qt;
Case *c;
Inst *j, *jmps, *wild, *k;
Node *n, *p;
Label *labs;
int nlab;
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 = nil;
j = nextinst();
for(p = n->left->left; p != nil; p = p->right){
switch(p->left->op){
case Oconst:
labs[findlab(texception, p->left, labs, nlab)].inst = j;
break;
case Owild:
wild = j;
break;
}
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
*/
Node*
rewritecomm(Node *n, Node *comm, Node *tmp, Node *slot)
{
Node *adr;
Inst *p;
if(n == nil)
return nil;
adr = nil;
if(n == comm){
if(comm->op == Osnd && sumark(n->right)->addable < Rcant)
adr = n->right;
else{
adr = talloc(tmp, 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;
}
n->left = rewritecomm(n->left, comm, tmp, slot);
n->right = rewritecomm(n->right, comm, tmp, slot);
return n;
}
/*
* merge together two sorted lists, yielding a sorted list
*/
static Decl*
declmerge(Decl *e, Decl *f)
{
Decl rock, *d;
int es, fs, v;
d = &rock;
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)
v = -strcmp(e->sym->name, f->sym->name);
if(v >= 0){
d->next = e;
d = e;
e = e->next;
while(e != nil && e->nid == 0){
d = e;
e = e->next;
}
}else{
d->next = f;
d = f;
f = f->next;
while(f != nil && f->nid == 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
*/
static Decl*
recdeclsort(Decl *d, int n)
{
Decl *r, *dd;
int i, m;
if(n <= 1)
return d;
m = n / 2 - 1;
dd = d;
for(i = 0; i < m; i++){
dd = dd->next;
while(dd->nid == 0)
dd = dd->next;
}
r = dd->next;
while(r->nid == 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
*/
Decl*
declsort(Decl *d)
{
Decl *dd;
int n;
n = 0;
for(dd = d; dd != nil; dd = dd->next)
if(dd->nid > 0)
n++;
return recdeclsort(d, n);
}
Src nilsrc;
/* Do we finally
* (a) pick off pointers as in the code below
* (b) generate a block move from zeroed memory as in tfree() in gen.b in limbo version
* (c) add a new block zero instruction to dis
* (d) reorganize the locals/temps in a frame
*/
void
zcom1(Node *n, Node **nn)
{
Type *ty;
Decl *d;
Node *e, *dn;
Src src;
ty = n->ty;
if (!tmustzero(ty))
return;
if (n->op == Oname && n->decl->refs == 0)
return;
if (nn) {
if(n->op != Oname)
nerror(n, "fatal: bad op in zcom1 map");
n->right = *nn;
*nn = n;
return;
}
if (debug['Z'])
print("zcom1 : %n\n", n);
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)) {
if (d->next != nil)
dn = dupn(0, nil, n);
else
dn = 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 %n\n", e);
*/
pushblock();
e = simplify(e);
sumark(e);
ecom(&e->src, nil, e);
popblock();
n->src = src;
}
}
void
zcom0(Decl *id, Node **nn)
{
Node *e;
e = mkname(&nilsrc, id->sym);
e->decl = id;
e->ty = id->ty;
zcom1(e, nn);
}
/* end of scope */
void
zcom(Node *n, Node **nn)
{
Decl *ids, *last;
Node *r, *nt;
for ( ; n != nil; n = r) {
r = n->right;
n->right = nil;
switch (n->op) {
case Ovardecl :
last = n->left->decl;
for (ids = n->decl; ids != last->next; ids = ids->next)
zcom0(ids, nn);
break;
case Oname :
if (n->decl != nildecl)
zcom1(dupn(0, nil, n), nn);
break;
case Otuple :
for (nt = n->left; nt != nil; nt = nt->right)
zcom(nt->left, nn);
break;
default :
fatal("bad node in zcom()");
break;
}
n->right = r;
}
}
static int
ret(Node *n, int nilret)
{
if(n == nil)
return nilret;
if(n->op == Oseq)
n = n->left;
return n->op == Oret && n->left == nil;
}
/*
* tail-recursive call
*/
static int
trcom(Node *e, Node *ne, int nilret)
{
Decl *d, *id;
Node *as, *a, *f, *n;
Inst *p;
if(1)
return 0; /* TO DO: should we enable this? */
if(e->op != Ocall || e->left->op != Oname)
return 0;
d = e->left->decl;
if(d != curfn || 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(mkn(0, nil, nil), id->ty, nil);
f->flags |= TEMP;
}
else
f = mkdeclname(&as->src, id);
n = mkbin(Oas, f, a);
n->ty = id->ty;
scom(n);
if(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(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;
}