ref: b7af62b250e5dff30320a181ca9d53ab5a7c276d
dir: /limbo/ecom.c/
#include "limbo.h" static Node* putinline(Node*); static void fpcall(Src*, int, Node*, Node*); void optabinit(void) { int i; for(i = 0; setisbyteinst[i] >= 0; i++) isbyteinst[setisbyteinst[i]] = 1; for(i = 0; setisused[i] >= 0; i++) isused[setisused[i]] = 1; for(i = 0; setsideeffect[i] >= 0; i++) sideeffect[setsideeffect[i]] = 1; opind[Tbyte] = 1; opind[Tint] = 2; opind[Tbig] = 3; opind[Treal] = 4; opind[Tstring] = 5; opind[Tfix] = 6; opcommute[Oeq] = Oeq; opcommute[Oneq] = Oneq; opcommute[Olt] = Ogt; opcommute[Ogt] = Olt; opcommute[Ogeq] = Oleq; opcommute[Oleq] = Ogeq; opcommute[Oadd] = Oadd; opcommute[Omul] = Omul; opcommute[Oxor] = Oxor; opcommute[Oor] = Oor; opcommute[Oand] = Oand; oprelinvert[Oeq] = Oneq; oprelinvert[Oneq] = Oeq; oprelinvert[Olt] = Ogeq; oprelinvert[Ogt] = Oleq; oprelinvert[Ogeq] = Olt; oprelinvert[Oleq] = Ogt; isrelop[Oeq] = 1; isrelop[Oneq] = 1; isrelop[Olt] = 1; isrelop[Oleq] = 1; isrelop[Ogt] = 1; isrelop[Ogeq] = 1; isrelop[Oandand] = 1; isrelop[Ooror] = 1; isrelop[Onot] = 1; precasttab[Tstring][Tbyte] = tint; precasttab[Tbyte][Tstring] = tint; precasttab[Treal][Tbyte] = tint; precasttab[Tbyte][Treal] = tint; precasttab[Tbig][Tbyte] = tint; precasttab[Tbyte][Tbig] = tint; precasttab[Tfix][Tbyte] = tint; precasttab[Tbyte][Tfix] = tint; precasttab[Tbig][Tfix] = treal; precasttab[Tfix][Tbig] = treal; precasttab[Tstring][Tfix] = treal; precasttab[Tfix][Tstring] = treal; casttab[Tint][Tint] = IMOVW; casttab[Tbig][Tbig] = IMOVL; casttab[Treal][Treal] = IMOVF; casttab[Tbyte][Tbyte] = IMOVB; casttab[Tstring][Tstring] = IMOVP; casttab[Tfix][Tfix] = ICVTXX; /* never same type */ casttab[Tint][Tbyte] = ICVTWB; casttab[Tint][Treal] = ICVTWF; casttab[Tint][Tstring] = ICVTWC; casttab[Tint][Tfix] = ICVTXX; casttab[Tbyte][Tint] = ICVTBW; casttab[Treal][Tint] = ICVTFW; casttab[Tstring][Tint] = ICVTCW; casttab[Tfix][Tint] = ICVTXX; casttab[Tint][Tbig] = ICVTWL; casttab[Treal][Tbig] = ICVTFL; casttab[Tstring][Tbig] = ICVTCL; casttab[Tbig][Tint] = ICVTLW; casttab[Tbig][Treal] = ICVTLF; casttab[Tbig][Tstring] = ICVTLC; casttab[Treal][Tstring] = ICVTFC; casttab[Tstring][Treal] = ICVTCF; casttab[Treal][Tfix] = ICVTFX; casttab[Tfix][Treal] = ICVTXF; casttab[Tstring][Tarray] = ICVTCA; casttab[Tarray][Tstring] = ICVTAC; /* * placeholders; fixed in precasttab */ casttab[Tbyte][Tstring] = 0xff; casttab[Tstring][Tbyte] = 0xff; casttab[Tbyte][Treal] = 0xff; casttab[Treal][Tbyte] = 0xff; casttab[Tbyte][Tbig] = 0xff; casttab[Tbig][Tbyte] = 0xff; casttab[Tfix][Tbyte] = 0xff; casttab[Tbyte][Tfix] = 0xff; casttab[Tfix][Tbig] = 0xff; casttab[Tbig][Tfix] = 0xff; casttab[Tfix][Tstring] = 0xff; casttab[Tstring][Tfix] = 0xff; } /* * global variable and constant initialization checking */ int vcom(Decl *ids) { Decl *v; int ok; ok = 1; for(v = ids; v != nil; v = v->next) ok &= varcom(v); for(v = ids; v != nil; v = v->next) v->init = simplify(v->init); return ok; } Node* simplify(Node *n) { if(n == nil) return nil; if(debug['F']) print("simplify %n\n", n); n = efold(rewrite(n)); if(debug['F']) print("simplified %n\n", n); return n; } static int isfix(Node *n) { if(n->ty->kind == Tint || n->ty->kind == Tfix){ if(n->op == Ocast) return n->left->ty->kind == Tint || n->left->ty->kind == Tfix; return 1; } return 0; } /* * rewrite an expression to make it easiser to compile, * or give the correct results */ Node* rewrite(Node *n) { Long v; Type *t; Decl *d; Node *nn, *left, *right; if(n == nil) return nil; left = n->left; right = n->right; /* * rewrites */ switch(n->op){ case Oname: d = n->decl; if(d->importid != nil){ left = mkbin(Omdot, dupn(1, &n->src, d->eimport), mkdeclname(&n->src, d->importid)); left->ty = n->ty; return rewrite(left); } if((t = n->ty)->kind == Texception){ if(t->cons) fatal("cons in rewrite Oname"); n = mkbin(Oadd, n, mkconst(&n->src, 2*IBY2WD)); n = mkunary(Oind, n); n->ty = t; n->left->ty = n->left->left->ty = tint; return rewrite(n); } break; case Odas: n->op = Oas; return rewrite(n); case Oneg: n->left = rewrite(left); if(n->ty == treal) break; left = n->left; n->right = left; n->left = mkconst(&n->src, 0); n->left->ty = n->ty; n->op = Osub; break; case Ocomp: v = 0; v = ~v; n->right = mkconst(&n->src, v); n->right->ty = n->ty; n->left = rewrite(left); n->op = Oxor; break; case Oinc: case Odec: case Opreinc: case Opredec: n->left = rewrite(left); switch(n->ty->kind){ case Treal: n->right = mkrconst(&n->src, 1.0); break; case Tint: case Tbig: case Tbyte: case Tfix: n->right = mkconst(&n->src, 1); n->right->ty = n->ty; break; default: fatal("can't rewrite inc/dec %n", n); break; } if(n->op == Opreinc) n->op = Oaddas; else if(n->op == Opredec) n->op = Osubas; break; case Oslice: if(right->left->op == Onothing) right->left = mkconst(&right->left->src, 0); n->left = rewrite(left); n->right = rewrite(right); break; case Oindex: n->op = Oindx; n->left = rewrite(left); n->right = rewrite(right); n = mkunary(Oind, n); n->ty = n->left->ty; n->left->ty = tint; break; case Oload: n->right = mkn(Oname, nil, nil); n->right->src = n->left->src; n->right->decl = n->ty->tof->decl; n->right->ty = n->ty; n->left = rewrite(left); break; case Ocast: if(left->ty->kind == Texception){ n = rewrite(left); break; } n->op = Ocast; t = precasttab[left->ty->kind][n->ty->kind]; if(t != nil){ n->left = mkunary(Ocast, left); n->left->ty = t; return rewrite(n); } n->left = rewrite(left); break; case Oraise: if(left->ty == tstring) {} else if(!left->ty->cons) break; else if(left->op != Ocall || left->left->ty->kind == Tfn){ left = mkunary(Ocall, left); left->ty = left->left->ty; } n->left = rewrite(left); break; case Ocall: t = left->ty; if(t->kind == Tref) t = t->tof; if(t->kind == Tfn){ if(debug['U']) print("call %n\n", left); if(left->ty->kind == Tref){ /* call by function reference */ n->left = mkunary(Oind, left); n->left->ty = t; return rewrite(n); } d = nil; if(left->op == Oname) d = left->decl; else if(left->op == Omdot && left->right->op == Odot) d = left->right->right->decl; else if(left->op == Omdot || left->op == Odot) d = left->right->decl; else if(left->op != Oind) fatal("cannot deal with call %n in rewrite", n); if(ispoly(d)) addfnptrs(d, 0); n->left = rewrite(left); if(right != nil) n->right = rewrite(right); if(d != nil && d->caninline == 1) n = simplify(putinline(n)); break; } switch(n->ty->kind){ case Tref: n = mkunary(Oref, n); n->ty = n->left->ty; n->left->ty = n->left->ty->tof; n->left->left->ty = n->left->ty; return rewrite(n); case Tadt: n->op = Otuple; n->right = nil; if(n->ty->tags != nil){ n->left = nn = mkunary(Oseq, mkconst(&n->src, left->right->decl->tag)); if(right != nil){ nn->right = right; nn->src.stop = right->src.stop; } n->ty = left->right->decl->ty->tof; }else n->left = right; return rewrite(n); case Tadtpick: n->op = Otuple; n->right = nil; n->left = nn = mkunary(Oseq, mkconst(&n->src, left->right->decl->tag)); if(right != nil){ nn->right = right; nn->src.stop = right->src.stop; } n->ty = left->right->decl->ty->tof; return rewrite(n); case Texception: if(!n->ty->cons) return n->left; if(left->op == Omdot){ left->right->ty = left->ty; left = left->right; } n->op = Otuple; n->right = nil; n->left = nn = mkunary(Oseq, left->decl->init); nn->right = mkunary(Oseq, mkconst(&n->src, 0)); nn->right->right = right; n->ty = mkexbasetype(n->ty); n = mkunary(Oref, n); n->ty = internaltype(mktype(&n->src.start, &n->src.stop, Tref, t, nil)); return rewrite(n); default: fatal("can't deal with %n in rewrite/Ocall", n); break; } break; case Omdot: /* * what about side effects from left? */ d = right->decl; switch(d->store){ case Dfn: n->left = rewrite(left); if(right->op == Odot){ n->right = dupn(1, &left->src, right->right); n->right->ty = d->ty; } break; case Dconst: case Dtag: case Dtype: /* handled by fold */ return n; case Dglobal: right->op = Oconst; right->val = d->offset; right->ty = tint; n->left = left = mkunary(Oind, left); left->ty = tint; n->op = Oadd; n = mkunary(Oind, n); n->ty = n->left->ty; n->left->ty = tint; n->left = rewrite(n->left); return n; case Darg: return n; default: fatal("can't deal with %n in rewrite/Omdot", n); break; } break; case Odot: /* * what about side effects from left? */ d = right->decl; switch(d->store){ case Dfn: if(right->left != nil){ n = mkbin(Omdot, dupn(1, &left->src, right->left), right); right->left = nil; n->ty = d->ty; return rewrite(n); } if(left->ty->kind == Tpoly){ n = mkbin(Omdot, mkdeclname(&left->src, d->link), mkdeclname(&left->src, d->link->next)); n->ty = d->ty; return rewrite(n); } n->op = Oname; n->decl = d; n->right = nil; n->left = nil; return n; case Dconst: case Dtag: case Dtype: /* handled by fold */ return n; } if(istuple(left)) return n; /* handled by fold */ right->op = Oconst; right->val = d->offset; right->ty = tint; if(left->ty->kind != Tref){ n->left = mkunary(Oadr, left); n->left->ty = tint; } n->op = Oadd; n = mkunary(Oind, n); n->ty = n->left->ty; n->left->ty = tint; n->left = rewrite(n->left); return n; case Oadr: left = rewrite(left); n->left = left; if(left->op == Oind) return left->left; break; case Otagof: if(n->decl == nil){ n->op = Oind; return rewrite(n); } return n; case Omul: case Odiv: left = n->left = rewrite(left); right = n->right = rewrite(right); if(n->ty->kind == Tfix && isfix(left) && isfix(right)){ if(left->op == Ocast && tequal(left->ty, n->ty)) n->left = left->left; if(right->op == Ocast && tequal(right->ty, n->ty)) n->right = right->left; } break; case Oself: if(newfnptr) return n; if(selfdecl == nil){ d = selfdecl = mkids(&n->src, enter(strdup(".self"), 5), tany, nil); installids(Dglobal, d); d->refs++; } nn = mkn(Oload, nil, nil); nn->src = n->src; nn->left = mksconst(&n->src, enterstring(strdup("$self"), 5)); nn->ty = impdecl->ty; usetype(nn->ty); usetype(nn->ty->tof); nn = rewrite(nn); nn->op = Oself; return nn; case Ofnptr: if(n->flags == 0){ /* module */ if(left == nil) left = mkn(Oself, nil, nil); return rewrite(left); } right->flags = n->flags; n = right; d = n->decl; if(n->flags == FNPTR2){ if(left != nil && left->op != Oname) fatal("not Oname for addiface"); if(left == nil){ addiface(nil, d); if(newfnptr) n->flags |= FNPTRN; } else addiface(left->decl, d); /* is this necessary ? */ n->ty = tint; return n; } if(n->flags == FNPTRA){ n = mkdeclname(&n->src, d->link); n->ty = tany; return n; } if(n->flags == (FNPTRA|FNPTR2)){ n = mkdeclname(&n->src, d->link->next); n->ty = tint; return n; } break; case Ochan: if(left == nil) left = n->left = mkconst(&n->src, 0); n->left = rewrite(left); break; default: n->left = rewrite(left); n->right = rewrite(right); break; } return n; } /* * label a node with sethi-ullman numbers and addressablity * genaddr interprets addable to generate operands, * so a change here mandates a change there. * * addressable: * const Rconst $value may also be Roff or Rdesc or Rnoff * Asmall(local) Rreg value(FP) * Asmall(global) Rmreg value(MP) * ind(Rareg) Rreg value(FP) * ind(Ramreg) Rmreg value(MP) * ind(Rreg) Radr *value(FP) * ind(Rmreg) Rmadr *value(MP) * ind(Raadr) Radr value(value(FP)) * ind(Ramadr) Rmadr value(value(MP)) * * almost addressable: * adr(Rreg) Rareg * adr(Rmreg) Ramreg * add(const, Rareg) Rareg * add(const, Ramreg) Ramreg * add(const, Rreg) Raadr * add(const, Rmreg) Ramadr * add(const, Raadr) Raadr * add(const, Ramadr) Ramadr * adr(Radr) Raadr * adr(Rmadr) Ramadr * * strangely addressable: * fn Rpc * mdot(module,exp) Rmpc */ Node* sumark(Node *n) { Node *left, *right; long v; if(n == nil) return nil; n->temps = 0; n->addable = Rcant; left = n->left; right = n->right; if(left != nil){ sumark(left); n->temps = left->temps; } if(right != nil){ sumark(right); if(right->temps == n->temps) n->temps++; else if(right->temps > n->temps) n->temps = right->temps; } switch(n->op){ case Oadr: switch(left->addable){ case Rreg: n->addable = Rareg; break; case Rmreg: n->addable = Ramreg; break; case Radr: n->addable = Raadr; break; case Rmadr: n->addable = Ramadr; break; } break; case Oind: switch(left->addable){ case Rreg: n->addable = Radr; break; case Rmreg: n->addable = Rmadr; break; case Rareg: n->addable = Rreg; break; case Ramreg: n->addable = Rmreg; break; case Raadr: n->addable = Radr; break; case Ramadr: n->addable = Rmadr; break; } break; case Oname: switch(n->decl->store){ case Darg: case Dlocal: n->addable = Rreg; break; case Dglobal: n->addable = Rmreg; if(LDT && n->decl->ty->kind == Tiface) n->addable = Rldt; break; case Dtype: /* * check for inferface to load */ if(n->decl->ty->kind == Tmodule) n->addable = Rmreg; break; case Dfn: if(n->flags & FNPTR){ if(n->flags == FNPTR2) n->addable = Roff; else if(n->flags == (FNPTR2|FNPTRN)) n->addable = Rnoff; } else n->addable = Rpc; break; default: fatal("cannot deal with %K in Oname in %n", n->decl, n); break; } break; case Omdot: n->addable = Rmpc; break; case Oconst: switch(n->ty->kind){ case Tint: case Tfix: v = n->val; if(v < 0 && ((v >> 29) & 0x7) != 7 || v > 0 && (v >> 29) != 0){ n->decl = globalconst(n); n->addable = Rmreg; }else n->addable = Rconst; break; case Tbig: n->decl = globalBconst(n); n->addable = Rmreg; break; case Tbyte: n->decl = globalbconst(n); n->addable = Rmreg; break; case Treal: n->decl = globalfconst(n); n->addable = Rmreg; break; case Tstring: n->decl = globalsconst(n); n->addable = Rmreg; break; default: fatal("cannot %T const in sumark", n->ty); break; } break; case Oadd: if(right->addable == Rconst){ switch(left->addable){ case Rareg: n->addable = Rareg; break; case Ramreg: n->addable = Ramreg; break; case Rreg: case Raadr: n->addable = Raadr; break; case Rmreg: case Ramadr: n->addable = Ramadr; break; } } break; } if(n->addable < Rcant) n->temps = 0; else if(n->temps == 0) n->temps = 1; return n; } Node* mktn(Type *t) { Node *n; n = mkn(Oname, nil, nil); usedesc(mktdesc(t)); n->ty = t; n->decl = t->decl; if(n->decl == nil) fatal("mktn t %T nil decl", t); n->addable = Rdesc; return n; } /* does a tuple of the form (a, b, ...) form a contiguous block * of memory on the stack when offsets are assigned later * - only when (a, b, ...) := rhs and none of the names nil * can we guarantee this */ static int tupblk0(Node *n, Decl **dd) { Decl *d; int nid; switch(n->op){ case Otuple: for(n = n->left; n != nil; n = n->right) if(!tupblk0(n->left, dd)) return 0; return 1; case Oname: if(n->decl == nildecl) return 0; d = *dd; if(d != nil && d->next != n->decl) return 0; nid = n->decl->nid; if(d == nil && nid == 1) return 0; if(d != nil && nid != 0) return 0; *dd = n->decl; return 1; } return 0; } /* could force locals to be next to each other * - need to shuffle locals list * - later */ static Node* tupblk(Node *n) { Decl *d; if(n->op != Otuple) return nil; d = nil; if(!tupblk0(n, &d)) return nil; while(n->op == Otuple) n = n->left->left; if(n->op != Oname || n->decl->nid == 1) fatal("bad tupblk"); return n; } /* for cprof */ #define esrc(src, osrc, nto) (src != nil && nto != nil ? src : osrc) /* * compile an expression with an implicit assignment * note: you are not allowed to use to->src * * need to think carefully about the types used in moves * it particular, it would be nice to gen movp rather than movc sometimes. */ Node* ecom(Src *src, Node *nto, Node *n) { Node *left, *right, *tn; Node tl, tr, tto, ttn; Type *t, *tt; Inst *p, *pp; int op; if(debug['e']){ print("ecom: %n\n", n); if(nto != nil) print("ecom to: %n\n", nto); } if(n->addable < Rcant){ /* * think carefully about the type used here */ if(nto != nil) genmove(src, Mas, n->ty, n, nto); return nto; } tl.decl = nil; tr.decl = nil; tto.decl = nil; ttn.decl = nil; left = n->left; right = n->right; op = n->op; switch(op){ default: case Oadr: fatal("can't %n in ecom", n); return nto; case Oif: p = bcom(left, 1, nil); ecom(&right->left->src, nto, right->left); if(right->right != nil){ pp = p; p = genrawop(&right->left->src, IJMP, nil, nil, nil); patch(pp, nextinst()); ecom(&right->right->src, nto, right->right); } patch(p, nextinst()); break; case Ocomma: tn = left->left; ecom(&left->src, nil, left); ecom(&right->src, nto, right); tfree(tn); break; case Oname: if(n->addable == Rpc){ if(nto != nil) genmove(src, Mas, n->ty, n, nto); return nto; } fatal("can't %n in ecom", n); break; case Onothing: break; case Oused: if(nto != nil) fatal("superfluous used %n to %n", left, nto); talloc(&tto, left->ty, nil); ecom(&left->src, &tto, left); tfree(&tto); break; case Oas: if(right->ty == tany) right->ty = n->ty; if(left->op == Oname && left->decl->ty == tany){ if(nto == nil) nto = talloc(&tto, right->ty, nil); left = nto; nto = nil; } if(left->op == Oinds){ indsascom(src, nto, n); tfree(&tto); break; } if(left->op == Oslice){ slicelcom(src, nto, n); tfree(&tto); break; } if(left->op == Otuple){ if(!tupsaliased(right, left)){ if((tn = tupblk(left)) != nil){ tn->ty = n->ty; ecom(&n->right->src, tn, right); if(nto != nil) genmove(src, Mas, n->ty, tn, nto); tfree(&tto); break; } if((tn = tupblk(right)) != nil){ tn->ty = n->ty; tuplcom(tn, left); if(nto != nil) genmove(src, Mas, n->ty, tn, nto); tfree(&tto); break; } if(nto == nil && right->op == Otuple && left->ty->kind != Tadtpick){ tuplrcom(right, left); tfree(&tto); break; } } if(right->addable >= Ralways || right->op != Oname || tupaliased(right, left)){ talloc(&tr, n->ty, nil); ecom(&n->right->src, &tr, right); right = &tr; } tuplcom(right, n->left); if(nto != nil) genmove(src, Mas, n->ty, right, nto); tfree(&tr); tfree(&tto); break; } /* * check for left/right aliasing and build right into temporary */ if(right->op == Otuple){ if(!tupsaliased(left, right) && (tn = tupblk(right)) != nil){ tn->ty = n->ty; right = tn; } else if(left->op != Oname || tupaliased(left, right)) right = ecom(&right->src, talloc(&tr, right->ty, nil), right); } /* * think carefully about types here */ if(left->addable >= Rcant) left = eacom(left, &tl, nto); ecom(&n->src, left, right); if(nto != nil) genmove(src, Mas, nto->ty, left, nto); tfree(&tl); tfree(&tr); tfree(&tto); break; case Ochan: if(left && left->addable >= Rcant) left = eacom(left, &tl, nto); genchan(src, left, n->ty->tof, nto); tfree(&tl); break; case Oinds: if(right->addable < Ralways){ if(left->addable >= Rcant) left = eacom(left, &tl, nil); }else if(left->temps <= right->temps){ right = ecom(&right->src, talloc(&tr, right->ty, nil), right); if(left->addable >= Rcant) left = eacom(left, &tl, nil); }else{ left = eacom(left, &tl, nil); right = ecom(&right->src, talloc(&tr, right->ty, nil), right); } genop(&n->src, op, left, right, nto); tfree(&tl); tfree(&tr); break; case Osnd: if(right->addable < Rcant){ if(left->addable >= Rcant) left = eacom(left, &tl, nto); }else if(left->temps < right->temps){ right = eacom(right, &tr, nto); if(left->addable >= Rcant) left = eacom(left, &tl, nil); }else{ left = eacom(left, &tl, nto); right = eacom(right, &tr, nil); } p = genrawop(&n->src, ISEND, right, nil, left); p->m.offset = n->ty->size; /* for optimizer */ if(nto != nil) genmove(src, Mas, right->ty, right, nto); tfree(&tl); tfree(&tr); break; case Orcv: if(nto == nil){ ecom(&n->src, talloc(&tto, n->ty, nil), n); tfree(&tto); return nil; } if(left->addable >= Rcant) left = eacom(left, &tl, nto); if(left->ty->kind == Tchan){ p = genrawop(src, IRECV, left, nil, nto); p->m.offset = n->ty->size; /* for optimizer */ }else{ recvacom(src, nto, n); } tfree(&tl); break; case Ocons: /* * another temp which can go with analysis */ if(left->addable >= Rcant) left = eacom(left, &tl, nil); if(!sameaddr(right, nto)){ ecom(&right->src, talloc(&tto, n->ty, nto), right); genmove(src, Mcons, left->ty, left, &tto); if(!sameaddr(&tto, nto)) genmove(src, Mas, nto->ty, &tto, nto); }else genmove(src, Mcons, left->ty, left, nto); tfree(&tl); tfree(&tto); break; case Ohd: if(left->addable >= Rcant) left = eacom(left, &tl, nto); genmove(src, Mhd, nto->ty, left, nto); tfree(&tl); break; case Otl: if(left->addable >= Rcant) left = eacom(left, &tl, nto); genmove(src, Mtl, left->ty, left, nto); tfree(&tl); break; case Otuple: if((tn = tupblk(n)) != nil){ tn->ty = n->ty; genmove(src, Mas, n->ty, tn, nto); break; } tupcom(nto, n); break; case Oadd: case Osub: case Omul: case Odiv: case Omod: case Oand: case Oor: case Oxor: case Olsh: case Orsh: case Oexp: /* * check for 2 operand forms */ if(sameaddr(nto, left)){ if(right->addable >= Rcant) right = eacom(right, &tr, nto); genop(src, op, right, nil, nto); tfree(&tr); break; } if(opcommute[op] && sameaddr(nto, right) && n->ty != tstring){ if(left->addable >= Rcant) left = eacom(left, &tl, nto); genop(src, opcommute[op], left, nil, nto); tfree(&tl); break; } if(right->addable < left->addable && opcommute[op] && n->ty != tstring){ op = opcommute[op]; left = right; right = n->left; } if(left->addable < Ralways){ if(right->addable >= Rcant) right = eacom(right, &tr, nto); }else if(right->temps <= left->temps){ left = ecom(&left->src, talloc(&tl, left->ty, nto), left); if(right->addable >= Rcant) right = eacom(right, &tr, nil); }else{ right = eacom(right, &tr, nto); left = ecom(&left->src, talloc(&tl, left->ty, nil), left); } /* * check for 2 operand forms */ if(sameaddr(nto, left)) genop(src, op, right, nil, nto); else if(opcommute[op] && sameaddr(nto, right) && n->ty != tstring) genop(src, opcommute[op], left, nil, nto); else genop(src, op, right, left, nto); tfree(&tl); tfree(&tr); break; case Oaddas: case Osubas: case Omulas: case Odivas: case Omodas: case Oexpas: case Oandas: case Ooras: case Oxoras: case Olshas: case Orshas: if(left->op == Oinds){ indsascom(src, nto, n); break; } if(right->addable < Rcant){ if(left->addable >= Rcant) left = eacom(left, &tl, nto); }else if(left->temps < right->temps){ right = eacom(right, &tr, nto); if(left->addable >= Rcant) left = eacom(left, &tl, nil); }else{ left = eacom(left, &tl, nto); right = eacom(right, &tr, nil); } genop(&n->src, op, right, nil, left); if(nto != nil) genmove(src, Mas, left->ty, left, nto); tfree(&tl); tfree(&tr); break; case Olen: if(left->addable >= Rcant) left = eacom(left, &tl, nto); op = -1; t = left->ty; if(t == tstring) op = ILENC; else if(t->kind == Tarray) op = ILENA; else if(t->kind == Tlist) op = ILENL; else fatal("can't len %n", n); genrawop(src, op, left, nil, nto); tfree(&tl); break; case Oneg: if(left->addable >= Rcant) left = eacom(left, &tl, nto); genop(&n->src, op, left, nil, nto); tfree(&tl); break; case Oinc: case Odec: if(left->op == Oinds){ indsascom(src, nto, n); break; } if(left->addable >= Rcant) left = eacom(left, &tl, nil); if(nto != nil) genmove(src, Mas, left->ty, left, nto); if(right->addable >= Rcant) fatal("inc/dec amount not addressable: %n", n); genop(&n->src, op, right, nil, left); tfree(&tl); break; case Ospawn: if(left->left->op == Oind) fpcall(&n->src, op, left, nto); else callcom(&n->src, op, left, nto); break; case Oraise: if(left->addable >= Rcant) left = eacom(left, &tl, nil); genrawop(&n->src, IRAISE, left, nil, nil); tfree(&tl); break; case Ocall: if(left->op == Oind) fpcall(esrc(src, &n->src, nto), op, n, nto); else callcom(esrc(src, &n->src, nto), op, n, nto); break; case Oref: t = left->ty; if(left->op == Oname && left->decl->store == Dfn || left->op == Omdot && left->right->op == Oname && left->right->decl->store == Dfn){ /* create a function reference */ Decl *d; Node *mod, *ind; d = left->decl; if(left->op == Omdot){ d = left->right->decl; mod = left->left; } else if(d->eimport != nil) mod = d->eimport; else{ mod = rewrite(mkn(Oself, nil, nil)); addiface(nil, d); } sumark(mod); talloc(&tto, n->ty, nto); genrawop(src, INEW, mktn(usetype(tfnptr)), nil, &tto); tr.src = *src; tr.op = Oind; tr.left = &tto; tr.right = nil; tr.ty = tany; sumark(&tr); ecom(src, &tr, mod); ind = mkunary(Oind, mkbin(Oadd, dupn(0, src, &tto), mkconst(src, IBY2WD))); ind->ty = ind->left->ty = ind->left->right->ty = tint; tr.op = Oas; tr.left = ind; tr.right = mkdeclname(src, d); tr.ty = tr.right->ty = tint; sumark(&tr); tr.right->addable = mod->op == Oself && newfnptr ? Rnoff : Roff; ecom(src, nil, &tr); if(!sameaddr(&tto, nto)) genmove(src, Mas, n->ty, &tto, nto); tfree(&tto); break; } if(left->op == Oname && left->decl->store == Dtype){ genrawop(src, INEW, mktn(t), nil, nto); break; } if(t->kind == Tadt && t->tags != nil){ pickdupcom(src, nto, left); break; } tt = t; if(left->op == Oconst && left->decl->store == Dtag) t = left->decl->ty->tof; /* * could eliminate temp if to does not occur * in tuple initializer */ talloc(&tto, n->ty, nto); genrawop(src, INEW, mktn(t), nil, &tto); tr.op = Oind; tr.left = &tto; tr.right = nil; tr.ty = tt; sumark(&tr); ecom(src, &tr, left); if(!sameaddr(&tto, nto)) genmove(src, Mas, n->ty, &tto, nto); tfree(&tto); break; case Oload: if(left->addable >= Rcant) left = eacom(left, &tl, nto); talloc(&tr, tint, nil); if(LDT) genrawop(src, ILOAD, left, right, nto); else{ genrawop(src, ILEA, right, nil, &tr); genrawop(src, ILOAD, left, &tr, nto); } tfree(&tl); tfree(&tr); break; case Ocast: if(left->addable >= Rcant) left = eacom(left, &tl, nto); t = left->ty; if(t->kind == Tfix || n->ty->kind == Tfix){ op = casttab[t->kind][n->ty->kind]; if(op == ICVTXX) genfixcastop(src, op, left, nto); else{ tn = sumark(mkrconst(src, scale2(t, n->ty))); genrawop(src, op, left, tn, nto); } } else genrawop(src, casttab[t->kind][n->ty->kind], left, nil, nto); tfree(&tl); break; case Oarray: if(left->addable >= Rcant) left = eacom(left, &tl, nto); genrawop(esrc(src, &left->src, nto), arrayz ? INEWAZ : INEWA, left, mktn(n->ty->tof), nto); if(right != nil) arraycom(nto, right); tfree(&tl); break; case Oslice: tn = right->right; right = right->left; /* * make the left node of the slice directly addressable * therefore, if it's len is taken (via tn), * left's tree won't be rewritten */ if(left->addable >= Rcant) left = eacom(left, &tl, nil); if(tn->op == Onothing){ tn = mkn(Olen, left, nil); tn->src = *src; tn->ty = tint; sumark(tn); } if(tn->addable < Ralways){ if(right->addable >= Rcant) right = eacom(right, &tr, nil); }else if(right->temps <= tn->temps){ tn = ecom(&tn->src, talloc(&ttn, tn->ty, nil), tn); if(right->addable >= Rcant) right = eacom(right, &tr, nil); }else{ right = eacom(right, &tr, nil); tn = ecom(&tn->src, talloc(&ttn, tn->ty, nil), tn); } op = ISLICEA; if(nto->ty == tstring) op = ISLICEC; /* * overwrite the destination last, * since it might be used in computing the slice bounds */ if(!sameaddr(left, nto)) ecom(&left->src, nto, left); genrawop(src, op, right, tn, nto); tfree(&tl); tfree(&tr); tfree(&ttn); break; case Oindx: if(right->addable < Rcant){ if(left->addable >= Rcant) left = eacom(left, &tl, nto); }else if(left->temps < right->temps){ right = eacom(right, &tr, nto); if(left->addable >= Rcant) left = eacom(left, &tl, nil); }else{ left = eacom(left, &tl, nto); right = eacom(right, &tr, nil); } if(nto->addable >= Ralways) nto = ecom(src, talloc(&tto, nto->ty, nil), nto); op = IINDX; switch(left->ty->tof->size){ case IBY2LG: op = IINDL; if(left->ty->tof == treal) op = IINDF; break; case IBY2WD: op = IINDW; break; case 1: op = IINDB; break; } genrawop(src, op, left, nto, right); // array[] of {....} [index] frees array too early (before index value used) // function(...) [index] frees array too early (before index value used) if(tl.decl != nil) tfreelater(&tl); else tfree(&tl); tfree(&tr); tfree(&tto); break; case Oind: n = eacom(n, &tl, nto); genmove(src, Mas, n->ty, n, nto); tfree(&tl); break; case Onot: case Oandand: case Ooror: case Oeq: case Oneq: case Olt: case Oleq: case Ogt: case Ogeq: p = bcom(n, 1, nil); genmove(src, Mas, tint, sumark(mkconst(src, 1)), nto); pp = genrawop(src, IJMP, nil, nil, nil); patch(p, nextinst()); genmove(src, Mas, tint, sumark(mkconst(src, 0)), nto); patch(pp, nextinst()); break; case Oself: if(newfnptr){ if(nto != nil) genrawop(src, ISELF, nil, nil, nto); break; } tn = sumark(mkdeclname(src, selfdecl)); p = genbra(src, Oneq, tn, sumark(mkdeclname(src, nildecl))); n->op = Oload; ecom(src, tn, n); patch(p, nextinst()); genmove(src, Mas, n->ty, tn, nto); break; } return nto; } /* * compile exp n to yield an addressable expression * use reg to build a temporary; if t is a temp, it is usable * if dangle leaves the address dangling, generate into a temporary * this should only happen with arrays * * note that 0adr's are strange as they are only used * for calculating the addresses of fields within adt's. * therefore an Oind is the parent or grandparent of the Oadr, * and we pick off all of the cases where Oadr's argument is not * addressable by looking from the Oind. */ Node* eacom(Node *n, Node *reg, Node *t) { Node *left, *tn; if(n->op == Ocomma){ tn = n->left->left; ecom(&n->left->src, nil, n->left); n = eacom(n->right, reg, t); tfree(tn); return n; } if(debug['e'] || debug['E']) print("eacom: %n\n", n); left = n->left; if(n->op != Oind){ ecom(&n->src, talloc(reg, n->ty, t), n); reg->src = n->src; return reg; } if(left->op == Oadd && left->right->op == Oconst){ if(left->left->op == Oadr){ left->left->left = eacom(left->left->left, reg, t); sumark(n); if(n->addable >= Rcant) fatal("eacom can't make node addressable: %n", n); return n; } talloc(reg, left->left->ty, t); ecom(&left->left->src, reg, left->left); left->left->decl = reg->decl; left->left->addable = Rreg; left->left = reg; left->addable = Raadr; n->addable = Radr; }else if(left->op == Oadr){ talloc(reg, left->left->ty, t); ecom(&left->left->src, reg, left->left); /* * sleaze: treat the temp as the type of the field, not the enclosing structure */ reg->ty = n->ty; reg->src = n->src; return reg; }else{ talloc(reg, left->ty, t); ecom(&left->src, reg, left); n->left = reg; n->addable = Radr; } return n; } /* * compile an assignment to an array slice */ Node* slicelcom(Src *src, Node *nto, Node *n) { Node *left, *right, *v; Node tl, tr, tv, tu; tl.decl = nil; tr.decl = nil; tv.decl = nil; tu.decl = nil; left = n->left->left; right = n->left->right->left; v = n->right; if(right->addable < Ralways){ if(left->addable >= Rcant) left = eacom(left, &tl, nto); }else if(left->temps <= right->temps){ right = ecom(&right->src, talloc(&tr, right->ty, nto), right); if(left->addable >= Rcant) left = eacom(left, &tl, nil); }else{ left = eacom(left, &tl, nil); /* dangle on right and v */ right = ecom(&right->src, talloc(&tr, right->ty, nil), right); } switch(n->op){ case Oas: if(v->addable >= Rcant) v = eacom(v, &tv, nil); break; } genrawop(&n->src, ISLICELA, v, right, left); if(nto != nil) genmove(src, Mas, n->ty, left, nto); tfree(&tl); tfree(&tv); tfree(&tr); tfree(&tu); return nto; } /* * compile an assignment to a string location */ Node* indsascom(Src *src, Node *nto, Node *n) { Node *left, *right, *u, *v; Node tl, tr, tv, tu; tl.decl = nil; tr.decl = nil; tv.decl = nil; tu.decl = nil; left = n->left->left; right = n->left->right; v = n->right; if(right->addable < Ralways){ if(left->addable >= Rcant) left = eacom(left, &tl, nto); }else if(left->temps <= right->temps){ right = ecom(&right->src, talloc(&tr, right->ty, nto), right); if(left->addable >= Rcant) left = eacom(left, &tl, nil); }else{ left = eacom(left, &tl, nil); /* dangle on right and v */ right = ecom(&right->src, talloc(&tr, right->ty, nil), right); } switch(n->op){ case Oas: if(v->addable >= Rcant) v = eacom(v, &tv, nil); break; case Oinc: case Odec: if(v->addable >= Rcant) fatal("inc/dec amount not addable"); u = talloc(&tu, tint, nil); genop(&n->left->src, Oinds, left, right, u); if(nto != nil) genmove(src, Mas, n->ty, u, nto); nto = nil; genop(&n->src, n->op, v, nil, u); v = u; break; case Oaddas: case Osubas: case Omulas: case Odivas: case Omodas: case Oexpas: case Oandas: case Ooras: case Oxoras: case Olshas: case Orshas: if(v->addable >= Rcant) v = eacom(v, &tv, nil); u = talloc(&tu, tint, nil); genop(&n->left->src, Oinds, left, right, u); genop(&n->src, n->op, v, nil, u); v = u; break; } genrawop(&n->src, IINSC, v, right, left); tfree(&tl); tfree(&tv); tfree(&tr); tfree(&tu); if(nto != nil) genmove(src, Mas, n->ty, v, nto); return nto; } void callcom(Src *src, int op, Node *n, Node *ret) { Node frame, tadd, toff, pass, *a, *mod, *ind, *nfn, *args, tmod, tind, *tn; Inst *in,*p; Decl *d, *callee; long off; int iop; args = n->right; nfn = n->left; switch(nfn->op){ case Odot: callee = nfn->right->decl; nfn->addable = Rpc; break; case Omdot: callee = nfn->right->decl; break; case Oname: callee = nfn->decl; break; default: callee = nil; fatal("bad call op in callcom"); } if(nfn->addable != Rpc && nfn->addable != Rmpc) fatal("can't gen call addresses"); if(nfn->ty->tof != tnone && ret == nil){ ecom(src, talloc(&tmod, nfn->ty->tof, nil), n); tfree(&tmod); return; } if(ispoly(callee)) addfnptrs(callee, 0); if(nfn->ty->varargs){ nfn->decl = dupdecl(nfn->right->decl); nfn->decl->desc = gendesc(nfn->right->decl, idoffsets(nfn->ty->ids, MaxTemp, MaxAlign), nfn->ty->ids); } talloc(&frame, tint, nil); mod = nfn->left; ind = nfn->right; tmod.decl = tind.decl = nil; if(nfn->addable == Rmpc){ if(mod->addable >= Rcant) mod = eacom(mod, &tmod, nil); /* dangle always */ if(ind->op != Oname && ind->addable >= Ralways){ talloc(&tind, ind->ty, nil); ecom(&ind->src, &tind, ind); ind = &tind; } else if(ind->decl != nil && ind->decl->store != Darg) ind->addable = Roff; } /* * stop nested uncalled frames * otherwise exception handling very complicated */ for(a = args; a != nil; a = a->right){ if(hascall(a->left)){ tn = mkn(0, nil, nil); talloc(tn, a->left->ty, nil); ecom(&a->left->src, tn, a->left); a->left = tn; tn->flags |= TEMP; } } /* * allocate the frame */ if(nfn->addable == Rmpc && !nfn->ty->varargs){ genrawop(src, IMFRAME, mod, ind, &frame); }else if(nfn->op == Odot){ genrawop(src, IFRAME, nfn->left, nil, &frame); }else{ in = genrawop(src, IFRAME, nil, nil, &frame); in->sm = Adesc; in->s.decl = nfn->decl; } /* * build a fake node for the argument area */ toff = znode; tadd = znode; pass = znode; toff.op = Oconst; toff.addable = Rconst; toff.ty = tint; tadd.op = Oadd; tadd.addable = Raadr; tadd.left = &frame; tadd.right = &toff; tadd.ty = tint; pass.op = Oind; pass.addable = Radr; pass.left = &tadd; /* * compile all the args */ d = nfn->ty->ids; off = 0; for(a = args; a != nil; a = a->right){ off = d->offset; toff.val = off; if(d->ty->kind == Tpoly) pass.ty = a->left->ty; else pass.ty = d->ty; ecom(&a->left->src, &pass, a->left); d = d->next; if(a->left->flags & TEMP) tfree(a->left); } if(off > maxstack) maxstack = off; /* * pass return value */ if(ret != nil){ toff.val = REGRET*IBY2WD; pass.ty = nfn->ty->tof; p = genrawop(src, ILEA, ret, nil, &pass); p->m.offset = ret->ty->size; /* for optimizer */ } /* * call it */ if(nfn->addable == Rmpc){ iop = IMCALL; if(op == Ospawn) iop = IMSPAWN; genrawop(src, iop, &frame, ind, mod); tfree(&tmod); tfree(&tind); }else if(nfn->op == Odot){ iop = ICALL; if(op == Ospawn) iop = ISPAWN; genrawop(src, iop, &frame, nil, nfn->right); }else{ iop = ICALL; if(op == Ospawn) iop = ISPAWN; in = genrawop(src, iop, &frame, nil, nil); in->d.decl = nfn->decl; in->dm = Apc; } tfree(&frame); } /* * initialization code for arrays * a must be addressable (< Rcant) */ void arraycom(Node *a, Node *elems) { Node tindex, fake, tmp, ri, *e, *n, *q, *body, *wild; Inst *top, *out; /* Case *c; */ if(debug['A']) print("arraycom: %n %n\n", a, elems); /* c = elems->ty->cse; */ /* don't use c->wild in case we've been inlined */ wild = nil; for(e = elems; e != nil; e = e->right) for(q = e->left->left; q != nil; q = q->right) if(q->left->op == Owild) wild = e->left; if(wild != nil) arraydefault(a, wild->right); tindex = znode; fake = znode; talloc(&tmp, tint, nil); tindex.op = Oindx; tindex.addable = Rcant; tindex.left = a; tindex.right = nil; tindex.ty = tint; fake.op = Oind; fake.addable = Radr; fake.left = &tmp; fake.ty = a->ty->tof; for(e = elems; e != nil; e = e->right){ /* * just duplicate the initializer for Oor */ for(q = e->left->left; q != nil; q = q->right){ if(q->left->op == Owild) continue; body = e->left->right; if(q->right != nil) body = dupn(0, &nosrc, body); top = nil; out = nil; ri.decl = nil; if(q->left->op == Orange){ /* * for(i := q.left.left; i <= q.left.right; i++) */ talloc(&ri, tint, nil); ri.src = q->left->src; ecom(&q->left->src, &ri, q->left->left); /* i <= q.left.right; */ n = mkn(Oleq, &ri, q->left->right); n->src = q->left->src; n->ty = tint; top = nextinst(); out = bcom(n, 1, nil); tindex.right = &ri; }else{ tindex.right = q->left; } tindex.addable = Rcant; tindex.src = q->left->src; ecom(&tindex.src, &tmp, &tindex); ecom(&body->src, &fake, body); if(q->left->op == Orange){ /* i++ */ n = mkbin(Oinc, &ri, sumark(mkconst(&ri.src, 1))); n->ty = tint; n->addable = Rcant; ecom(&n->src, nil, n); /* jump to test */ patch(genrawop(&q->left->src, IJMP, nil, nil, nil), top); patch(out, nextinst()); tfree(&ri); } } } tfree(&tmp); } /* * default initialization code for arrays. * compiles to * n = len a; * while(n){ * n--; * a[n] = elem; * } */ void arraydefault(Node *a, Node *elem) { Inst *out, *top; Node n, e, *t; if(debug['A']) print("arraydefault: %n %n\n", a, elem); t = mkn(Olen, a, nil); t->src = elem->src; t->ty = tint; t->addable = Rcant; talloc(&n, tint, nil); n.src = elem->src; ecom(&t->src, &n, t); top = nextinst(); out = bcom(&n, 1, nil); t = mkbin(Odec, &n, sumark(mkconst(&elem->src, 1))); t->ty = tint; t->addable = Rcant; ecom(&t->src, nil, t); e.decl = nil; if(elem->addable >= Rcant) elem = eacom(elem, &e, nil); t = mkn(Oindx, a, &n); t->src = elem->src; t = mkbin(Oas, mkunary(Oind, t), elem); t->ty = elem->ty; t->left->ty = elem->ty; t->left->left->ty = tint; sumark(t); ecom(&t->src, nil, t); patch(genrawop(&t->src, IJMP, nil, nil, nil), top); tfree(&n); tfree(&e); patch(out, nextinst()); } void tupcom(Node *nto, Node *n) { Node tadr, tadd, toff, fake, *e; Decl *d; if(debug['Y']) print("tupcom %n\nto %n\n", n, nto); /* * build a fake node for the tuple */ toff = znode; tadd = znode; fake = znode; tadr = znode; toff.op = Oconst; toff.ty = tint; tadr.op = Oadr; tadr.left = nto; tadr.ty = tint; tadd.op = Oadd; tadd.left = &tadr; tadd.right = &toff; tadd.ty = tint; fake.op = Oind; fake.left = &tadd; sumark(&fake); if(fake.addable >= Rcant) fatal("tupcom: bad value exp %n", &fake); /* * compile all the exps */ d = n->ty->ids; for(e = n->left; e != nil; e = e->right){ toff.val = d->offset; fake.ty = d->ty; ecom(&e->left->src, &fake, e->left); d = d->next; } } void tuplcom(Node *n, Node *nto) { Node tadr, tadd, toff, fake, tas, *e, *as; Decl *d; if(debug['Y']) print("tuplcom %n\nto %n\n", n, nto); /* * build a fake node for the tuple */ toff = znode; tadd = znode; fake = znode; tadr = znode; toff.op = Oconst; toff.ty = tint; tadr.op = Oadr; tadr.left = n; tadr.ty = tint; tadd.op = Oadd; tadd.left = &tadr; tadd.right = &toff; tadd.ty = tint; fake.op = Oind; fake.left = &tadd; sumark(&fake); if(fake.addable >= Rcant) fatal("tuplcom: bad value exp for %n", &fake); /* * compile all the exps */ d = nto->ty->ids; if(nto->ty->kind == Tadtpick) d = nto->ty->tof->ids->next; for(e = nto->left; e != nil; e = e->right){ as = e->left; if(as->op != Oname || as->decl != nildecl){ toff.val = d->offset; fake.ty = d->ty; fake.src = as->src; if(as->addable < Rcant) genmove(&as->src, Mas, d->ty, &fake, as); else{ tas.op = Oas; tas.ty = d->ty; tas.src = as->src; tas.left = as; tas.right = &fake; tas.addable = Rcant; ecom(&tas.src, nil, &tas); } } d = d->next; } } void tuplrcom(Node *n, Node *nto) { Node *s, *d, tas; Decl *de; de = nto->ty->ids; for(s = n->left, d = nto->left; s != nil && d != nil; s = s->right, d = d->right){ if(d->left->op != Oname || d->left->decl != nildecl){ tas.op = Oas; tas.ty = de->ty; tas.src = s->left->src; tas.left = d->left; tas.right = s->left; sumark(&tas); ecom(&tas.src, nil, &tas); } de = de->next; } if(s != nil || d != nil) fatal("tuplrcom"); } /* * boolean compiler * fall through when condition == true */ Inst* bcom(Node *n, int iftrue, Inst *b) { Inst *bb; Node tl, tr, *t, *left, *right, *tn; int op; if(n->op == Ocomma){ tn = n->left->left; ecom(&n->left->src, nil, n->left); bb = bcom(n->right, iftrue, b); tfree(tn); return bb; } if(debug['b']) print("bcom %n %d\n", n, iftrue); left = n->left; right = n->right; op = n->op; switch(op){ case Onothing: return b; case Onot: return bcom(n->left, !iftrue, b); case Oandand: if(!iftrue) return oror(n, iftrue, b); return andand(n, iftrue, b); case Ooror: if(!iftrue) return andand(n, iftrue, b); return oror(n, iftrue, b); case Ogt: case Ogeq: case Oneq: case Oeq: case Olt: case Oleq: break; default: if(n->ty->kind == Tint){ right = mkconst(&n->src, 0); right->addable = Rconst; left = n; op = Oneq; break; } fatal("can't bcom %n", n); return b; } if(iftrue) op = oprelinvert[op]; if(left->addable < right->addable){ t = left; left = right; right = t; op = opcommute[op]; } tl.decl = nil; tr.decl = nil; if(right->addable < Ralways){ if(left->addable >= Rcant) left = eacom(left, &tl, nil); }else if(left->temps <= right->temps){ right = ecom(&right->src, talloc(&tr, right->ty, nil), right); if(left->addable >= Rcant) left = eacom(left, &tl, nil); }else{ left = eacom(left, &tl, nil); right = ecom(&right->src, talloc(&tr, right->ty, nil), right); } bb = genbra(&n->src, op, left, right); bb->branch = b; tfree(&tl); tfree(&tr); return bb; } Inst* andand(Node *n, int iftrue, Inst *b) { if(debug['b']) print("andand %n\n", n); b = bcom(n->left, iftrue, b); b = bcom(n->right, iftrue, b); return b; } Inst* oror(Node *n, int iftrue, Inst *b) { Inst *bb; if(debug['b']) print("oror %n\n", n); bb = bcom(n->left, !iftrue, nil); b = bcom(n->right, iftrue, b); patch(bb, nextinst()); return b; } /* * generate code for a recva expression * this is just a hacked up small alt */ void recvacom(Src *src, Node *nto, Node *n) { Label *labs; Case *c; Node which, tab, off, add, adr, slot, *left; Type *talt; Inst *p; left = n->left; labs = allocmem(1 * sizeof *labs); labs[0].isptr = left->addable >= Rcant; c = allocmem(sizeof *c); c->nlab = 1; c->labs = labs; talt = mktalt(c); 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); /* * gen the channel * this sleaze is lying to the garbage collector */ off.val = 2*IBY2WD; if(left->addable < Rcant) genmove(src, Mas, tint, left, &slot); else{ slot.ty = left->ty; ecom(src, &slot, left); slot.ty = nil; } /* * gen the value */ off.val += IBY2WD; p = genrawop(&left->src, ILEA, nto, nil, &slot); p->m.offset = nto->ty->size; /* for optimizer */ /* * number of senders and receivers */ off.val = 0; genmove(src, Mas, tint, sumark(mkconst(src, 0)), &slot); off.val += IBY2WD; genmove(src, Mas, tint, sumark(mkconst(src, 1)), &slot); off.val += IBY2WD; p = genrawop(src, IALT, &tab, nil, &which); p->m.offset = talt->size; /* for optimizer */ tfree(&which); tfree(&tab); } /* * generate code to duplicate an adt with pick fields * this is just a hacked up small pick * n is Oind(exp) */ void pickdupcom(Src *src, Node *nto, Node *n) { Node *start, *stop, *node, *orig, *dest, tmp, clab; Case *c; Inst *j, *jmps, *wild; Label *labs; Decl *d, *tg, *stg; Type *t; int i, nlab; char buf[32]; if(n->op != Oind) fatal("pickdupcom not Oind: %n" ,n); t = n->ty; nlab = t->decl->tag; /* * generate global which has case labels */ seprint(buf, buf+sizeof(buf), ".c%d", nlabel++); d = mkids(src, enter(buf, 0), mktype(&src->start, &src->stop, Tcase, nil, nil), nil); d->init = mkdeclname(src, d); clab.addable = Rmreg; clab.left = nil; clab.right = nil; clab.op = Oname; clab.ty = d->ty; clab.decl = d; /* * generate a temp to hold the real value * then generate a case on the tag */ orig = n->left; talloc(&tmp, orig->ty, nil); ecom(src, &tmp, orig); orig = mkunary(Oind, &tmp); orig->ty = tint; sumark(orig); dest = mkunary(Oind, nto); dest->ty = nto->ty->tof; sumark(dest); genrawop(src, ICASE, orig, nil, &clab); labs = allocmem(nlab * sizeof *labs); i = 0; jmps = nil; for(tg = t->tags; tg != nil; tg = tg->next){ stg = tg; for(; tg->next != nil; tg = tg->next) if(stg->ty != tg->next->ty) break; start = sumark(simplify(mkdeclname(src, stg))); stop = start; node = start; if(stg != tg){ stop = sumark(simplify(mkdeclname(src, tg))); node = mkbin(Orange, start, stop); } labs[i].start = start; labs[i].stop = stop; labs[i].node = node; labs[i++].inst = nextinst(); genrawop(src, INEW, mktn(tg->ty->tof), nil, nto); genmove(src, Mas, tg->ty->tof, orig, dest); j = genrawop(src, IJMP, nil, nil, nil); j->branch = jmps; jmps = j; } /* * this should really be a runtime error */ wild = genrawop(src, IJMP, nil, nil, nil); patch(wild, wild); patch(jmps, nextinst()); tfree(&tmp); if(i > nlab) fatal("overflowed label tab for pickdupcom"); c = allocmem(sizeof *c); c->nlab = i; c->nsnd = 0; c->labs = labs; c->iwild = wild; d->ty->cse = c; usetype(d->ty); installids(Dglobal, d); } /* * see if name n occurs anywhere in e */ int tupaliased(Node *n, Node *e) { for(;;){ if(e == nil) return 0; if(e->op == Oname && e->decl == n->decl) return 1; if(tupaliased(n, e->left)) return 1; e = e->right; } } /* * see if any name in n occurs anywere in e */ int tupsaliased(Node *n, Node *e) { for(;;){ if(n == nil) return 0; if(n->op == Oname && tupaliased(n, e)) return 1; if(tupsaliased(n->left, e)) return 1; n = n->right; } } /* * put unaddressable constants in the global data area */ Decl* globalconst(Node *n) { Decl *d; Sym *s; char buf[32]; seprint(buf, buf+sizeof(buf), ".i.%.8lux", (long)n->val); s = enter(buf, 0); d = s->decl; if(d == nil){ d = mkids(&n->src, s, tint, nil); installids(Dglobal, d); d->init = n; d->refs++; } return d; } Decl* globalBconst(Node *n) { Decl *d; Sym *s; char buf[32]; seprint(buf, buf+sizeof(buf), ".B.%.8lux.%8lux", (long)(n->val>>32), (long)n->val); s = enter(buf, 0); d = s->decl; if(d == nil){ d = mkids(&n->src, s, tbig, nil); installids(Dglobal, d); d->init = n; d->refs++; } return d; } Decl* globalbconst(Node *n) { Decl *d; Sym *s; char buf[32]; seprint(buf, buf+sizeof(buf), ".b.%.2lux", (long)n->val & 0xff); s = enter(buf, 0); d = s->decl; if(d == nil){ d = mkids(&n->src, s, tbyte, nil); installids(Dglobal, d); d->init = n; d->refs++; } return d; } Decl* globalfconst(Node *n) { Decl *d; Sym *s; char buf[32]; ulong dv[2]; dtocanon(n->rval, dv); seprint(buf, buf+sizeof(buf), ".f.%.8lux.%8lux", dv[0], dv[1]); s = enter(buf, 0); d = s->decl; if(d == nil){ d = mkids(&n->src, s, treal, nil); installids(Dglobal, d); d->init = n; d->refs++; } return d; } Decl* globalsconst(Node *n) { Decl *d; Sym *s; s = n->decl->sym; d = s->decl; if(d == nil){ d = mkids(&n->src, s, tstring, nil); installids(Dglobal, d); d->init = n; } d->refs++; return d; } static Node* subst(Decl *d, Node *e, Node *n) { if(n == nil) return nil; if(n->op == Oname){ if(d == n->decl){ n = dupn(0, nil, e); n->ty = d->ty; } return n; } n->left = subst(d, e, n->left); n->right = subst(d, e, n->right); return n; } static Node* putinline(Node *n) { Node *e, *tn; Type *t; Decl *d; if(debug['z']) print("inline1: %n\n", n); if(n->left->op == Oname) d = n->left->decl; else d = n->left->right->decl; e = d->init; t = e->ty; e = dupn(1, &n->src, e->right->left->left); for(d = t->ids, n = n->right; d != nil && n != nil; d = d->next, n = n->right){ if(hasside(n->left, 0) && occurs(d, e) != 1){ tn = talloc(mkn(0, nil, nil), d->ty, nil); e = mkbin(Ocomma, mkbin(Oas, tn, n->left), subst(d, tn, e)); e->ty = e->right->ty; e->left->ty = d->ty; } else e = subst(d, n->left, e); } if(d != nil || n != nil) fatal("bad arg match in putinline()"); if(debug['z']) print("inline2: %n\n", e); return e; } static void fpcall(Src *src, int op, Node *n, Node *ret) { Node tp, *e, *mod, *ind; tp.decl = nil; e = n->left->left; if(e->addable >= Rcant) e = eacom(e, &tp, nil); mod = mkunary(Oind, e); ind = mkunary(Oind, mkbin(Oadd, dupn(0, src, e), mkconst(src, IBY2WD))); n->left = mkbin(Omdot, mod, ind); n->left->ty = e->ty->tof; mod->ty = ind->ty = ind->left->ty = ind->left->right->ty = tint; sumark(n); callcom(src, op, n, ret); tfree(&tp); }