summaryrefslogtreecommitdiff
path: root/src/old/c/gen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/old/c/gen.c')
-rw-r--r--src/old/c/gen.c1186
1 files changed, 1186 insertions, 0 deletions
diff --git a/src/old/c/gen.c b/src/old/c/gen.c
new file mode 100644
index 000000000..dc9e55038
--- /dev/null
+++ b/src/old/c/gen.c
@@ -0,0 +1,1186 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+#undef EXTERN
+#define EXTERN
+#include "gen.h"
+
+static Node* curfn;
+
+void
+compile(Node *fn)
+{
+ Plist *pl;
+
+ if(fn->nbody == N)
+ return;
+ if(nerrors != 0) {
+ walk(fn);
+ return;
+ }
+
+ if(debug['w'])
+ dump("--- pre walk ---", fn->nbody);
+ walk(fn);
+ if(nerrors != 0)
+ return;
+ if(debug['w'])
+ dump("--- post walk ---", fn->nbody);
+
+ curfn = fn;
+
+ continpc = P;
+ breakpc = P;
+
+ pc = mal(sizeof(*pc));
+ firstpc = pc;
+ pc->op = PEND;
+ pc->addr.type = ANONE;
+ pc->loc = 1;
+ inarggen();
+ gen(curfn->nbody);
+
+ if(curfn->type->outtuple != 0)
+ gopcodet(PPANIC, N, N);
+
+ if(debug['p'])
+ proglist();
+
+ pl = mal(sizeof(*pl));
+ pl->name = curfn->nname;
+ pl->locals = autodcl;
+ pl->firstpc = firstpc;
+
+ if(plist == nil)
+ plist = pl;
+ else
+ plast->link = pl;
+ plast = pl;
+
+ if(debug['f'])
+ frame(0);
+}
+
+/*
+ * compile statements
+ */
+void
+gen(Node *n)
+{
+ long lno;
+ Prog *scontin, *sbreak;
+ Prog *p1, *p2, *p3;
+ Sym *s;
+
+ lno = dynlineno;
+
+loop:
+ if(n == N)
+ goto ret;
+ dynlineno = n->lineno; // for diagnostics
+
+ switch(n->op) {
+ default:
+ dump("gen: unknown op", n);
+ break;
+
+ case OLIST:
+ gen(n->left);
+ n = n->right;
+ goto loop;
+
+ case OPANIC:
+ case OPRINT:
+ genprint(n->left);
+ if(n->op == OPANIC)
+ gopcodet(PPANIC, N, N);
+ break;
+
+ case OCASE:
+ case OFALL:
+ case OXCASE:
+ case OXFALL:
+ case OEMPTY:
+ break;
+
+ case OLABEL:
+ // before declaration, s->label points at
+ // a link list of PXGOTO instructions.
+ // after declaration, s->label points
+ // at a PGOTO to .+1
+
+ s = n->left->sym;
+ p1 = (Prog*)s->label;
+
+ if(p1 != P) {
+ if(p1->op == PGOTO) {
+ yyerror("label redeclared: %S", s);
+ break;
+ }
+ while(p1 != P) {
+ if(p1->op != PGOTOX)
+ fatal("bad label pointer: %S", s);
+ p2 = p1->addr.branch;
+ p1->addr.branch = pc;
+ p1->op = PGOTO;
+ p1 = p2;
+ }
+ }
+
+ s->label = pc;
+ p1 = gbranch(PGOTO, N);
+ patch(p1, pc);
+ break;
+
+ case OGOTO:
+ s = n->left->sym;
+ p1 = (Prog*)s->label;
+ if(p1 != P && p1->op == PGOTO) {
+ // already declared
+ p2 = gbranch(PGOTO, N);
+ patch(p2, p1->addr.branch);
+ break;
+ }
+
+ // not declaraed yet
+ p2 = gbranch(PGOTOX, N);
+ p2->addr.node = n; // info for diagnostic if never declared
+ patch(p2, p1);
+ s->label = p2;
+ break;
+
+ case OBREAK:
+ if(breakpc == P) {
+ yyerror("gen: break is not in a loop");
+ break;
+ }
+ patch(gbranch(PGOTO, N), breakpc);
+ break;
+
+ case OCONTINUE:
+ if(continpc == P) {
+ yyerror("gen: continue is not in a loop");
+ break;
+ }
+ patch(gbranch(PGOTO, N), continpc);
+ break;
+
+ case OFOR:
+ gen(n->ninit); // init
+ p1 = gbranch(PGOTO, N); // goto test
+ sbreak = breakpc;
+ breakpc = gbranch(PGOTO, N); // break: goto done
+ scontin = continpc;
+ continpc = pc;
+ gen(n->nincr); // contin: incr
+ patch(p1, pc); // test:
+ bgen(n->ntest, 0, breakpc); // if(!test) goto break
+ gen(n->nbody); // body
+ patch(gbranch(PGOTO, N), continpc); // goto contin
+ patch(breakpc, pc); // done:
+ continpc = scontin;
+ breakpc = sbreak;
+ break;
+
+ case OIF:
+ gen(n->ninit); // init
+ p1 = gbranch(PGOTO, N); // goto test
+ p2 = gbranch(PGOTO, N); // p2: goto else
+ patch(p1, pc); // test:
+ bgen(n->ntest, 0, p2); // if(!test) goto p2
+ gen(n->nbody); // then
+ p3 = gbranch(PGOTO, N); // goto done
+ patch(p2, pc); // else:
+ gen(n->nelse); // else
+ patch(p3, pc); // done:
+ break;
+
+ case OSWITCH:
+ gen(n->ninit); // init
+ p1 = gbranch(PGOTO, N); // goto test
+ sbreak = breakpc;
+ breakpc = gbranch(PGOTO, N); // break: goto done
+ patch(p1, pc); // test:
+ swgen(n); // switch(test) body
+ patch(breakpc, pc); // done:
+ breakpc = sbreak;
+ break;
+
+ case OASOP:
+ cgen_asop(n->left, n->right, n->kaka);
+ break;
+
+ case OAS:
+ cgen_as(n->left, n->right, n->op, n->kaka);
+ break;
+
+ case OCALL:
+ case OCALLPTR:
+ case OCALLMETH:
+ case OCALLINTER:
+ cgen_call(n, 1);
+ break;
+
+ case ORETURN:
+ cgen_ret(n);
+ break;
+ }
+
+ret:
+ dynlineno = lno;
+}
+
+/*
+ * compile expression to (unnamed) reg
+ */
+void
+cgen(Node *n)
+{
+ long lno;
+ Node *nl, *nr, *r;
+ int a;
+ Prog *p1, *p2, *p3;
+
+ if(n == N)
+ return;
+
+ lno = dynlineno;
+ if(n->op != ONAME)
+ dynlineno = n->lineno; // for diagnostics
+
+ nl = n->left;
+ nr = n->right;
+
+ if(nr != N && nr->ullman >= UINF && nl != N && nl->ullman >= UINF) {
+ cgen(nr);
+ r = tempname(n->type);
+ gopcodet(PSTORE, n->type, r);
+ nr = r;
+ }
+
+ switch(n->op) {
+ default:
+ yyerror("cgen: unknown op %O", n->op);
+ break;
+
+ case ONAME:
+ case OLITERAL:
+ gopcodet(PLOAD, n->type, n);
+ break;
+
+ case ONEW:
+ gopcodet(PNEW, n->type, n);
+ break;
+
+ // these call bgen to get a bool value
+ case OOROR:
+ case OANDAND:
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case ONOT:
+ p1 = gbranch(PGOTO, N);
+ p2 = gopcodet(PLOAD, n->type, booltrue);
+ p3 = gbranch(PGOTO, N);
+ patch(p1, pc);
+ bgen(n, 1, p2);
+ p2 = gopcodet(PLOAD, n->type, boolfalse);
+ patch(p3, pc);
+ goto ret;
+
+ case OPLUS:
+ cgen(nl);
+ goto ret;
+
+ // unary
+ case OMINUS:
+ case OCOM:
+ a = optopop(n->op);
+ goto uop;
+
+ // symmetric binary
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OADD:
+ case OMUL:
+ a = optopop(n->op);
+ goto sbop;
+
+ // asymmetric binary
+ case OMOD:
+ case OSUB:
+ case ODIV:
+ case OLSH:
+ case ORSH:
+ case OCAT:
+ a = optopop(n->op);
+ goto abop;
+
+ case OCONV:
+ if(isbytearray(nl->type)) {
+ if(nl->type->etype == TPTR)
+ cgen(nl);
+ else
+ agen(nl);
+ gopcode(PCONV, PTNIL, nod(OCONV, n->type, nl->type));
+ break;
+ }
+
+ cgen(nl);
+ gopcode(PCONV, PTNIL, nod(OCONV, n->type, nl->type));
+ break;
+
+ case OINDEXPTRSTR:
+ nl = n->left;
+ nr = n->right;
+ if(nl->addable) {
+ cgen(nr);
+ cgen(nl);
+ gopcode(PLOADI, PTADDR, N);
+ gopcodet(PINDEXZ, nr->type, N);
+ break;
+ }
+fatal("xxx");
+ break;
+
+ case OINDEXSTR:
+ nl = n->left;
+ nr = n->right;
+ if(nl->addable) {
+ cgen(nr);
+ gopcodet(PINDEXZ, nr->type, nl);
+ break;
+ }
+ cgen(nl);
+ r = tempname(nl->type);
+ gopcodet(PSTORE, nl->type, r);
+ cgen(nr);
+ gopcodet(PINDEXZ, nr->type, r);
+ break;
+
+ case OSLICESTR:
+ case OSLICEPTRSTR:
+ nl = n->left; // name
+ nr = n->right;
+
+ r = nr->right; // index2
+ if(!r->addable) {
+ cgen(r);
+ r = tempname(r->type);
+ gopcodet(PSTORE, r->type, r);
+ }
+
+ // string into PTADDR
+ if(!nl->addable) {
+ cgen(nl);
+ gconv(PTADDR, nl->type->etype);
+ } else
+ gopcode(PLOAD, PTADDR, nl);
+
+ if(n->op == OSLICEPTRSTR)
+ gopcode(PLOADI, PTADDR, N);
+
+ // offset in int reg
+ cgen(nr->left);
+
+ // index 2 addressed
+ gopcodet(PSLICE, r->type, r);
+ break;
+
+ case OINDEXPTR:
+ case OINDEX:
+ case ODOT:
+ case ODOTPTR:
+ case OIND:
+ agen(n);
+ gopcodet(PLOADI, n->type, N);
+ break;
+
+ case OLEN:
+ cgen(nl);
+ gopcodet(PLEN, nl->type, nl);
+ break;
+
+ case ODOTMETH:
+ case ODOTINTER:
+ cgen(n->left);
+ break;
+
+ case OADDR:
+ agen(nl);
+ gconv(PTPTR, PTADDR);
+ break;
+
+ case OCALL:
+ case OCALLPTR:
+ case OCALLMETH:
+ case OCALLINTER:
+ cgen_call(n, 0);
+ cgen_callret(n, N);
+ break;
+ }
+ goto ret;
+
+sbop: // symmetric
+ if(nl->ullman < nr->ullman) {
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+abop: // asymmetric
+ if(nr->addable) {
+ cgen(nl);
+ gopcodet(a, n->type, nr);
+ goto ret;
+ }
+
+ cgen(nr);
+ r = tempname(n->type);
+ gopcodet(PSTORE, n->type, r);
+ cgen(nl);
+ gopcodet(a, n->type, r);
+ goto ret;
+
+uop: // unary
+ cgen(nl);
+ gopcodet(a, n->type, N);
+ goto ret;
+
+ret:
+ dynlineno = lno;
+}
+
+/*
+ * compile the address of a value
+ */
+void
+agen(Node *n)
+{
+ Node *nl, *nr;
+ Node *t, *r;
+
+ if(n == N || n->type == N)
+ return;
+ switch(n->op) {
+ default:
+ dump("agen: unknown op", n);
+ break;
+
+ case ONAME:
+ gopcode(PADDR, PTADDR, n);
+ break;
+
+ case OINDEXPTR:
+ nl = n->left;
+ nr = n->right;
+ if(nl->addable) {
+ cgen(nr);
+ gopcode(PLOAD, PTADDR, nl);
+ genindex(n);
+ break;
+ }
+ if(nr->addable) {
+ cgen(nl);
+ gconv(PTADDR, nl->type->etype);
+ cgen(nr);
+ genindex(n);
+ break;
+ }
+ cgen(nr);
+ r = tempname(n->type);
+ gopcodet(PSTORE, n->type, r);
+ cgen(nl);
+ gconv(PTADDR, nl->type->etype);
+ cgen(r);
+ genindex(n);
+ break;
+
+ case OINDEX:
+ nl = n->left;
+ nr = n->right;
+ if(nl->addable) {
+ cgen(nr);
+ agen(nl);
+ genindex(n);
+ break;
+ }
+ if(nr->addable) {
+ agen(nl);
+ cgen(nr);
+ genindex(n);
+ break;
+ }
+ cgen(nr);
+ r = tempname(n->type);
+ gopcodet(PSTORE, n->type, r);
+ agen(nl);
+ cgen(r);
+ genindex(n);
+ break;
+
+ case OIND:
+ nl = n->left;
+ if(nl->addable) {
+ gopcode(PLOAD, PTADDR, nl);
+ break;
+ }
+ cgen(nl);
+ gconv(PTADDR, nl->type->etype);
+ break;
+
+ case ODOT:
+ case ODOTPTR:
+ nl = n->left;
+ nr = n->right;
+ t = nl->type;
+ switch(t->etype) {
+ default:
+ badtype(n->op, n->left->type, n->right->type);
+ break;
+
+ case TPTR:
+ if(nl->op != ONAME) {
+ cgen(nl);
+ gconv(PTADDR, nl->type->etype);
+ } else
+ gopcode(PLOAD, PTADDR, nl);
+ gaddoffset(nr);
+ break;
+
+ case TSTRUCT:
+ agen(nl);
+ gaddoffset(nr);
+ break;
+ }
+ break;
+ }
+}
+
+/*
+ * compile boolean expression
+ * true is branch-true or branch-false
+ * to is where to branch
+ */
+void
+bgen(Node *n, int true, Prog *to)
+{
+ long lno;
+ int et, a;
+ Node *nl, *nr, *r;
+ Prog *p1, *p2;
+
+ if(n == N)
+ n = booltrue;
+
+ lno = dynlineno;
+ if(n->op != ONAME)
+ dynlineno = n->lineno; // for diagnostics
+
+ if(n == N)
+ goto ret;
+ if(n->type == N) {
+ convlit(n, types[TBOOL]);
+ if(n->type == N)
+ goto ret;
+ }
+
+ et = n->type->etype;
+ if(et != TBOOL) {
+ yyerror("cgen: bad type %T for %O", n->type, n->op);
+ patch(gbranch(PERROR, N), to);
+ goto ret;
+ }
+ nl = N;
+ nr = N;
+
+ switch(n->op) {
+ default:
+ cgen(n);
+ gopcodet(PTEST, n->type, N);
+ a = PBTRUE;
+ if(!true)
+ a = PBFALSE;
+ patch(gbranch(a, n->type), to);
+ goto ret;
+
+ case OLITERAL:
+ if(!true == !n->val.vval)
+ patch(gbranch(PGOTO, N), to);
+ goto ret;
+
+ case ONAME:
+ gopcodet(PTEST, n->type, n);
+ a = PBTRUE;
+ if(!true)
+ a = PBFALSE;
+ patch(gbranch(a, n->type), to);
+ goto ret;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ p1 = gbranch(PGOTO, N);
+ p2 = gbranch(PGOTO, N);
+ patch(p1, pc);
+ bgen(n->left, !true, p2);
+ bgen(n->right, !true, p2);
+ p1 = gbranch(PGOTO, N);
+ patch(p1, to);
+ patch(p2, pc);
+ goto ret;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bgen(n->left, true, to);
+ bgen(n->right, true, to);
+ goto ret;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ nr = n->right;
+ if(nr == N || nr->type == N)
+ goto ret;
+
+ case ONOT: // unary
+ nl = n->left;
+ if(nl == N || nl->type == N)
+ goto ret;
+ }
+
+ switch(n->op) {
+
+ case ONOT:
+ bgen(nl, !true, to);
+ goto ret;
+
+ case OEQ: a = PBEQ; goto br;
+ case ONE: a = PBNE; goto br;
+ case OLT: a = PBLT; goto br;
+ case OGT: a = PBGT; goto br;
+ case OLE: a = PBLE; goto br;
+ case OGE: a = PBGE; goto br;
+ br:
+ if(!true)
+ a = brcom(a);
+
+ // make simplest on right
+ if(nl->ullman < nr->ullman) {
+ a = brrev(a);
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+ if(nr->addable) {
+ cgen(nl);
+ gopcodet(PCMP, nr->type, nr);
+ patch(gbranch(a, nr->type), to);
+ break;
+ }
+ cgen(nr);
+ r = tempname(nr->type);
+ gopcodet(PSTORE, nr->type, r);
+ cgen(nl);
+ gopcodet(PCMP, nr->type, r);
+ patch(gbranch(a, nr->type), to);
+ break;
+ }
+ goto ret;
+
+ret:
+ dynlineno = lno;
+}
+
+void
+swgen(Node *n)
+{
+ Node *c1, *c2;
+ Case *s0, *se, *s;
+ Prog *p1, *dflt;
+ long lno;
+ int any;
+ Iter save1, save2;
+
+ lno = dynlineno;
+
+ p1 = gbranch(PGOTO, N);
+ s0 = C;
+ se = C;
+
+ // walk thru the body placing breaks
+ // and labels into the case statements
+
+ any = 0;
+ dflt = P;
+ c1 = listfirst(&save1, &n->nbody);
+ while(c1 != N) {
+ dynlineno = c1->lineno; // for diagnostics
+ if(c1->op != OCASE) {
+ if(s0 == C)
+ yyerror("unreachable statements in a switch");
+ gen(c1);
+
+ any = 1;
+ if(c1->op == OFALL)
+ any = 0;
+ c1 = listnext(&save1);
+ continue;
+ }
+
+ // put in the break between cases
+ if(any) {
+ patch(gbranch(PGOTO, N), breakpc);
+ any = 0;
+ }
+
+ // over case expressions
+ c2 = listfirst(&save2, &c1->left);
+ if(c2 == N)
+ dflt = pc;
+
+ while(c2 != N) {
+
+ s = mal(sizeof(*s));
+ if(s0 == C)
+ s0 = s;
+ else
+ se->slink = s;
+ se = s;
+
+ s->scase = c2; // case expression
+ s->sprog = pc; // where to go
+
+ c2 = listnext(&save2);
+ }
+
+ c1 = listnext(&save1);
+ }
+
+ if(any)
+ patch(gbranch(PGOTO, N), breakpc);
+
+ patch(p1, pc);
+ c1 = tempname(n->ntest->type);
+ cgen(n->ntest);
+ gopcodet(PSTORE, n->ntest->type, c1);
+
+ for(s=s0; s!=C; s=s->slink) {
+ cgen(s->scase);
+ gopcodet(PCMP, n->ntest->type, c1);
+ patch(gbranch(PBEQ, n->ntest->type), s->sprog);
+ }
+ if(dflt != P) {
+ patch(gbranch(PGOTO, N), dflt);
+ goto ret;
+ }
+ patch(gbranch(PGOTO, N), breakpc);
+
+ret:
+ dynlineno = lno;
+}
+
+/*
+ * does this tree use
+ * the pointer register
+ */
+int
+usesptr(Node *n)
+{
+// if(n->addable)
+// return 0;
+ return 1;
+}
+
+void
+cgen_as(Node *nl, Node *nr, int op, int kaka)
+{
+ Node *r;
+
+loop:
+ switch(op) {
+ default:
+ fatal("cgen_as: unknown op %O", op);
+
+ case OAS:
+ if(nr == N && nl->op == OLIST) {
+ kaka = PAS_SINGLE;
+ cgen_as(nl->left, nr, op, kaka);
+ nl = nl->right;
+ goto loop;
+ }
+ switch(kaka) {
+ default:
+ yyerror("cgen_as: unknown param %d %d", kaka, PAS_CALLM);
+ break;
+
+ case PAS_CALLM: // function returning multi values
+ cgen_call(nr, 0);
+ cgen_callret(nr, nl);
+ break;
+
+ case PAS_SINGLE: // single return val used in expr
+ if(nr == N || isnil(nr)) {
+ if(nl->addable) {
+ gopcodet(PSTOREZ, nl->type, nl);
+ break;
+ }
+ agen(nl);
+ gopcodet(PSTOREZI, nl->type, N);
+ break;
+ }
+
+ if(nl->addable) {
+ cgen(nr);
+ genconv(nl, nr);
+ gopcodet(PSTORE, nl->type, nl);
+ break;
+ }
+
+ if(nr->addable && !needconvert(nl->type, nr->type)) {
+ agen(nl);
+ gopcodet(PSTOREI, nr->type, nr);
+ break;
+ }
+ if(!usesptr(nr)) {
+ cgen(nr);
+ genconv(nl, nr);
+ agen(nl);
+ gopcodet(PSTOREI, nr->type, N);
+ break;
+ }
+ agen(nl);
+ r = tempname(ptrto(nl->type));
+ gopcode(PSTORE, PTADDR, r);
+ cgen(nr);
+ genconv(nl, nr);
+ gopcode(PLOAD, PTADDR, r);
+ gopcodet(PSTOREI, nl->type, N);
+ break;
+
+ case PAS_STRUCT: // structure assignment
+ r = ptrto(nr->type);
+ if(!usesptr(nr)) {
+ agen(nr);
+ agen(nl);
+ gopcodet(PLOAD, N, r);
+ gopcodet(PERROR, nr->type, N);
+ break;
+ }
+ r = tempname(r);
+ agen(nr);
+ gopcode(PSTORE, PTADDR, r);
+
+ agen(nl);
+ gopcodet(PERROR, nr->type, r);
+ break;
+ }
+ break;
+ }
+}
+
+void
+cgen_asop(Node *nl, Node *nr, int op)
+{
+ Node *r;
+ int a;
+
+ a = optopop(op);
+ if(nr->addable) {
+ if(nl->addable) {
+ gopcodet(PLOAD, nl->type, nl);
+ gopcodet(a, nr->type, nr);
+ gopcodet(PSTORE, nl->type, nl);
+ return;
+ }
+
+ agen(nl);
+ gopcodet(PLOADI, nl->type, N);
+ gopcodet(a, nr->type, nr);
+ gopcodet(PSTOREI, nl->type, N);
+ return;
+ }
+
+ r = tempname(nr->type);
+ cgen(nr);
+ gopcodet(PSTORE, nr->type, r);
+
+ agen(nl);
+ gopcodet(PLOADI, nl->type, N);
+ gopcodet(a, nr->type, r);
+ gopcodet(PSTOREI, nl->type, N);
+}
+
+void
+inarggen(void)
+{
+ Iter save;
+ Node *arg, *t;
+ int i;
+
+ t = curfn->type;
+
+ arg = structfirst(&save, getthis(t));
+ if(arg != N) {
+ fnparam(t, 0, 0);
+ gopcodet(PSTORE, arg->type, arg->nname);
+ }
+
+ i = 0;
+ arg = structfirst(&save, getinarg(t));
+ while(arg != N) {
+ fnparam(t, 2, i);
+ gopcodet(PLOADI, arg->type, arg->nname);
+
+ arg = structnext(&save);
+ i++;
+ }
+}
+
+void
+cgen_ret(Node *n)
+{
+ Node *arg, *a, *f;
+ Iter save;
+
+ arg = listfirst(&save, &n->left); // expr list
+ a = getoutargx(curfn->type);
+ f = a->type;
+ for(;;) {
+ if(arg == N)
+ break;
+ if(f->etype != TFIELD)
+ fatal("cgen_ret: not field");
+ if(arg->addable && !needconvert(f->type, arg->type)) {
+ gopcode(PLOAD, PTADDR, a->nname);
+ gopcode(PADDO, PTADDR, f->nname);
+ gopcodet(PSTOREI, arg->type, arg);
+ } else {
+ cgen(arg);
+ genconv(f, arg);
+ gopcode(PLOAD, PTADDR, a->nname);
+ gopcode(PADDO, PTADDR, f->nname);
+ gopcodet(PSTOREI, f->type, N);
+ }
+ arg = listnext(&save);
+ f = f->down;
+ }
+ gopcodet(PRETURN, N, N);
+}
+
+void
+cgen_call(Node *n, int toss)
+{
+ Node *t, *at, *ae, *sn;
+ Iter save;
+ int i;
+
+ /*
+ * open a block
+ */
+ gopcodet(PCALL1, N, n->left);
+
+ /*
+ * prepare the input args
+ */
+ t = n->left->type;
+ if(t->etype == TPTR)
+ t = t->type;
+
+ at = *getinarg(t); // parameter struct
+ sn = at->nname; // in arg structure name
+
+ at = at->type; // parameter fields
+ ae = listfirst(&save, &n->right); // expr list
+
+ for(i=0; i<t->intuple; i++) {
+ if(ae == N)
+ fatal("cgen_call: tupleness");
+
+ if(ae->addable && !needconvert(at->type, ae->type)) {
+ gopcode(PADDR, PTADDR, sn);
+ gopcode(PADDO, PTADDR, at->nname);
+ gopcodet(PSTOREI, at->type, ae);
+ } else {
+ cgen(ae);
+ genconv(at, ae);
+ gopcode(PADDR, PTADDR, sn);
+ gopcode(PADDO, PTADDR, at->nname);
+ gopcodet(PSTOREI, at->type, N);
+ }
+ ae = listnext(&save);
+ at = at->down;
+ }
+
+ /*
+ * call the function
+ */
+ switch(n->op) {
+ default:
+ fatal("cgen_call: %O", n->op);
+
+ case OCALL:
+ gopcodet(PCALL2, N, n->left);
+ break;
+
+ case OCALLPTR:
+ cgen(n->left);
+ gopcodet(PCALLI2, N, n->left);
+ break;
+
+ case OCALLMETH:
+ cgen(n->left);
+ gopcodet(PCALLM2, N, n->left);
+ break;
+
+ case OCALLINTER:
+ cgen(n->left);
+ gopcodet(PCALLF2, N, n->left);
+ break;
+ }
+
+ /*
+ * toss the output args
+ */
+ if(toss) {
+ gopcodet(PCALL3, N, n->left);
+ return;
+ }
+}
+
+void
+cgen_callret(Node *n, Node *mas)
+{
+ Node *t, *at, *ae, *sn;
+ Iter save;
+ int i;
+
+ t = n->left->type;
+ if(t->etype == TPTR)
+ t = t->type;
+
+ at = *getoutarg(t); // parameter struct
+ sn = at->nname; // out arg structure name
+ at = at->type; // parameter fields
+
+ // call w single return val to a register
+ if(mas == N) {
+ gopcode(PADDR, PTADDR, sn);
+ gopcode(PADDO, PTADDR, at->nname);
+ gopcodet(PLOADI, at->type, N);
+ gopcodet(PCALL3, N, N);
+ return;
+ }
+
+ // call w multiple values to lval list
+ ae = listfirst(&save, &mas); // expr list
+ for(i=0; i<t->outtuple; i++) {
+ if(ae == N)
+ fatal("cgen_callret: output arguments do not match");
+
+ if(ae->addable) {
+ gopcode(PADDR, PTADDR, sn);
+ gopcode(PADDO, PTADDR, at->nname);
+ gopcodet(PLOADI, at->type, ae);
+ } else {
+ agen(ae);
+ gopcode(PADDR, PTADDR, sn);
+ gopcode(PADDO, PTADDR, at->nname);
+ gopcodet(PLOADI, at->type, N);
+ }
+
+ ae = listnext(&save);
+ at = at->down;
+ }
+
+ gopcodet(PCALL3, N, N);
+}
+
+void
+genprint(Node *n)
+{
+ Node *arg;
+ Iter save;
+
+ arg = listfirst(&save, &n);
+ while(arg != N) {
+ cgen(arg);
+ gopcodet(PPRINT, arg->type, N);
+ arg = listnext(&save);
+ }
+}
+
+int
+needconvert(Node *tl, Node *tr)
+{
+ if(isinter(tl)) {
+ if(isptrto(tr, TSTRUCT))
+ return 1;
+ if(isinter(tr))
+ return 1;
+ return 0;
+ }
+ if(isptrto(tl, TSTRUCT))
+ if(isinter(tr))
+ return 1;
+ return 0;
+}
+
+void
+genconv(Node *l, Node *r)
+{
+ Node *tl, *tr;
+
+ tl = l->type;
+ tr = r->type;
+ if(needconvert(tl, tr))
+ gopcode(PCONV, PTNIL, nod(OCONV, tl, tr));
+}
+
+void
+genindex(Node *n)
+{
+ gopcode(PINDEX, n->right->type->etype, n);
+}
+
+int
+optopop(int op)
+{
+ int a;
+
+ switch(op) {
+ default:
+ fatal("optopop: unknown op %O\n", op);
+
+ case OMINUS: a = PMINUS; break;
+ case OCOM: a = PCOM; break;
+ case OAND: a = PAND; break;
+ case OOR: a = POR; break;
+ case OXOR: a = PXOR; break;
+ case OADD: a = PADD; break;
+ case OMUL: a = PMUL; break;
+ case OMOD: a = PMOD; break;
+ case OSUB: a = PSUB; break;
+ case ODIV: a = PDIV; break;
+ case OLSH: a = PLSH; break;
+ case ORSH: a = PRSH; break;
+ case OCAT: a = PCAT; break;
+ }
+ return a;
+}