summaryrefslogtreecommitdiff
path: root/limbo/ecom.c
diff options
context:
space:
mode:
Diffstat (limited to 'limbo/ecom.c')
-rw-r--r--limbo/ecom.c2560
1 files changed, 2560 insertions, 0 deletions
diff --git a/limbo/ecom.c b/limbo/ecom.c
new file mode 100644
index 00000000..e19b51c0
--- /dev/null
+++ b/limbo/ecom.c
@@ -0,0 +1,2560 @@
+#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 true, 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, true, b);
+ tfree(tn);
+ return bb;
+ }
+
+ if(debug['b'])
+ print("bcom %n %d\n", n, true);
+
+ left = n->left;
+ right = n->right;
+ op = n->op;
+
+ switch(op){
+ case Onothing:
+ return b;
+ case Onot:
+ return bcom(n->left, !true, b);
+ case Oandand:
+ if(!true)
+ return oror(n, true, b);
+ return andand(n, true, b);
+ case Ooror:
+ if(!true)
+ return andand(n, true, b);
+ return oror(n, true, 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(true)
+ 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 true, Inst *b)
+{
+ if(debug['b'])
+ print("andand %n\n", n);
+ b = bcom(n->left, true, b);
+ b = bcom(n->right, true, b);
+ return b;
+}
+
+Inst*
+oror(Node *n, int true, Inst *b)
+{
+ Inst *bb;
+
+ if(debug['b'])
+ print("oror %n\n", n);
+ bb = bcom(n->left, !true, nil);
+ b = bcom(n->right, true, 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;
+ }
+ return 0;
+}
+
+/*
+ * 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;
+ }
+ return 0;
+}
+
+/*
+ * 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);
+}