summaryrefslogtreecommitdiff
path: root/src/cmd/gc/gen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/gen.c')
-rw-r--r--src/cmd/gc/gen.c505
1 files changed, 505 insertions, 0 deletions
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
new file mode 100644
index 000000000..410c1a519
--- /dev/null
+++ b/src/cmd/gc/gen.c
@@ -0,0 +1,505 @@
+// 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.
+
+/*
+ * portable half of code generator.
+ * mainly statements and control flow.
+ */
+
+#include "go.h"
+
+Node*
+sysfunc(char *name)
+{
+ Node *n;
+
+ n = newname(pkglookup(name, "sys"));
+ n->class = PFUNC;
+ return n;
+}
+
+void
+allocparams(void)
+{
+ Dcl *d;
+ Node *n;
+ uint32 w;
+
+ /*
+ * allocate (set xoffset) the stack
+ * slots for all automatics.
+ * allocated starting at -w down.
+ */
+ for(d=autodcl; d!=D; d=d->forw) {
+ if(d->op != ONAME)
+ continue;
+
+ n = d->dnode;
+ if(n->class != PAUTO)
+ continue;
+
+ dowidth(n->type);
+ w = n->type->width;
+ if(n->class & PHEAP)
+ w = widthptr;
+ stksize += w;
+ stksize = rnd(stksize, w);
+
+ n->xoffset = -stksize;
+ }
+}
+
+void
+newlab(int op, Sym *s)
+{
+ Label *lab;
+
+ lab = mal(sizeof(*lab));
+ lab->link = labellist;
+ labellist = lab;
+
+ lab->sym = s;
+ lab->op = op;
+ lab->label = pc;
+}
+
+void
+checklabels(void)
+{
+ Label *l, *m;
+ Sym *s;
+
+// // print the label list
+// for(l=labellist; l!=L; l=l->link) {
+// print("lab %O %S\n", l->op, l->sym);
+// }
+
+ for(l=labellist; l!=L; l=l->link) {
+ switch(l->op) {
+ case OFOR:
+ case OLABEL:
+ // these are definitions -
+ s = l->sym;
+ for(m=labellist; m!=L; m=m->link) {
+ if(m->sym != s)
+ continue;
+ switch(m->op) {
+ case OFOR:
+ case OLABEL:
+ // these are definitions -
+ // look for redefinitions
+ if(l != m)
+ yyerror("label %S redefined", s);
+ break;
+ case OGOTO:
+ // these are references -
+ // patch to definition
+ patch(m->label, l->label);
+ m->sym = S; // mark done
+ break;
+ }
+ }
+ }
+ }
+
+ // diagnostic for all undefined references
+ for(l=labellist; l!=L; l=l->link)
+ if(l->op == OGOTO && l->sym != S)
+ yyerror("label %S not defined", l->sym);
+}
+
+Label*
+findlab(Sym *s)
+{
+ Label *l;
+
+ for(l=labellist; l!=L; l=l->link) {
+ if(l->sym != s)
+ continue;
+ if(l->op != OFOR)
+ continue;
+ return l;
+ }
+ return L;
+}
+
+/*
+ * compile statements
+ */
+void
+gen(Node *n)
+{
+ int32 lno;
+ Prog *scontin, *sbreak;
+ Prog *p1, *p2, *p3;
+ Label *lab;
+
+ lno = setlineno(n);
+
+loop:
+ if(n == N)
+ goto ret;
+
+ p3 = pc; // save pc for loop labels
+ if(n->ninit)
+ gen(n->ninit);
+
+ setlineno(n);
+
+ switch(n->op) {
+ default:
+ fatal("gen: unknown op %N", n);
+ break;
+
+ case OLIST:
+ gen(n->left);
+ n = n->right;
+ goto loop;
+
+ case OCASE:
+ case OFALL:
+ case OXCASE:
+ case OXFALL:
+ case OEMPTY:
+ break;
+
+ case OLABEL:
+ newlab(OLABEL, n->left->sym);
+ break;
+
+ case OGOTO:
+ newlab(OGOTO, n->left->sym);
+ gjmp(P);
+ break;
+
+ case OBREAK:
+ if(n->left != N) {
+ for(lab=labellist; lab!=L; lab=lab->link) {
+ if(lab->breakpc != P) {
+ gjmp(lab->breakpc);
+ break;
+ }
+ }
+ if(lab == L)
+ yyerror("break label not defined: %S", n->left->sym);
+ break;
+ }
+ if(breakpc == P) {
+ yyerror("break is not in a loop");
+ break;
+ }
+ gjmp(breakpc);
+ break;
+
+ case OCONTINUE:
+ if(n->left != N) {
+ for(lab=labellist; lab!=L; lab=lab->link) {
+ if(lab->continpc != P) {
+ gjmp(lab->continpc);
+ break;
+ }
+ }
+ if(lab == L)
+ yyerror("break label not defined: %S", n->left->sym);
+ break;
+ }
+
+ if(continpc == P) {
+ yyerror("gen: continue is not in a loop");
+ break;
+ }
+ gjmp(continpc);
+ break;
+
+ case OFOR:
+ sbreak = breakpc;
+ p1 = gjmp(P); // goto test
+ breakpc = gjmp(P); // break: goto done
+ scontin = continpc;
+ continpc = pc;
+
+ // define break and cotinue labels
+ for(lab=labellist; lab!=L; lab=lab->link) {
+ if(lab->label != p3)
+ break;
+ if(lab->op == OLABEL) {
+ lab->breakpc = breakpc;
+ lab->continpc = continpc;
+ }
+ }
+
+ gen(n->nincr); // contin: incr
+ patch(p1, pc); // test:
+ if(n->ntest != N)
+ if(n->ntest->ninit != N)
+ gen(n->ntest->ninit);
+ bgen(n->ntest, 0, breakpc); // if(!test) goto break
+ gen(n->nbody); // body
+ gjmp(continpc);
+ patch(breakpc, pc); // done:
+ continpc = scontin;
+ breakpc = sbreak;
+ break;
+
+ case OIF:
+ p1 = gjmp(P); // goto test
+ p2 = gjmp(P); // p2: goto else
+ patch(p1, pc); // test:
+ if(n->ntest != N)
+ if(n->ntest->ninit != N)
+ gen(n->ntest->ninit);
+ bgen(n->ntest, 0, p2); // if(!test) goto p2
+ gen(n->nbody); // then
+ p3 = gjmp(P); // goto done
+ patch(p2, pc); // else:
+ gen(n->nelse); // else
+ patch(p3, pc); // done:
+ break;
+
+ case OSWITCH:
+ sbreak = breakpc;
+ p1 = gjmp(P); // goto test
+ breakpc = gjmp(P); // break: goto done
+
+ // define break label
+ for(lab=labellist; lab!=L; lab=lab->link) {
+ if(lab->label != p3)
+ break;
+ if(lab->op == OLABEL) {
+ lab->breakpc = breakpc;
+ }
+ }
+
+ patch(p1, pc); // test:
+ gen(n->nbody); // switch(test) body
+ patch(breakpc, pc); // done:
+ breakpc = sbreak;
+ break;
+
+ case OSELECT:
+ sbreak = breakpc;
+ p1 = gjmp(P); // goto test
+ breakpc = gjmp(P); // break: goto done
+
+ // define break label
+ for(lab=labellist; lab!=L; lab=lab->link) {
+ if(lab->label != p3)
+ break;
+ if(lab->op == OLABEL) {
+ lab->breakpc = breakpc;
+ }
+ }
+
+ patch(p1, pc); // test:
+ gen(n->nbody); // select() body
+ patch(breakpc, pc); // done:
+ breakpc = sbreak;
+ break;
+
+ case OASOP:
+ cgen_asop(n);
+ break;
+
+ case ODCL:
+ cgen_dcl(n->left);
+ break;
+
+ case OAS:
+ cgen_as(n->left, n->right);
+ break;
+
+ case OCALLMETH:
+ cgen_callmeth(n, 0);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n, N, 0);
+ break;
+
+ case OCALL:
+ cgen_call(n, 0);
+ break;
+
+ case OPROC:
+ cgen_proc(n, 1);
+ break;
+
+ case ODEFER:
+ cgen_proc(n, 2);
+ break;
+
+ case ORETURN:
+ cgen_ret(n);
+ break;
+ }
+
+ret:
+ lineno = lno;
+}
+
+/*
+ * generate call to non-interface method
+ * proc=0 normal call
+ * proc=1 goroutine run in new proc
+ * proc=2 defer call save away stack
+ */
+void
+cgen_callmeth(Node *n, int proc)
+{
+ Node *l;
+
+ // generate a rewrite for method call
+ // (p.f)(...) goes to (f)(p,...)
+
+ l = n->left;
+ if(l->op != ODOTMETH)
+ fatal("cgen_callmeth: not dotmethod: %N");
+
+ n->op = OCALL;
+ n->left = n->left->right;
+ n->left->type = l->type;
+
+ if(n->left->op == ONAME)
+ n->left->class = PFUNC;
+ cgen_call(n, proc);
+}
+
+/*
+ * generate code to start new proc running call n.
+ */
+void
+cgen_proc(Node *n, int proc)
+{
+ switch(n->left->op) {
+ default:
+ fatal("cgen_proc: unknown call %O", n->left->op);
+
+ case OCALLMETH:
+ cgen_callmeth(n->left, proc);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n->left, N, proc);
+ break;
+
+ case OCALL:
+ cgen_call(n->left, proc);
+ break;
+ }
+
+}
+
+/*
+ * generate declaration.
+ * nothing to do for on-stack automatics,
+ * but might have to allocate heap copy
+ * for escaped variables.
+ */
+void
+cgen_dcl(Node *n)
+{
+ if(debug['g'])
+ dump("\ncgen-dcl", n);
+ if(n->op != ONAME) {
+ dump("cgen_dcl", n);
+ fatal("cgen_dcl");
+ }
+ if(!(n->class & PHEAP))
+ return;
+ cgen_as(n->heapaddr, n->alloc);
+}
+
+/*
+ * generate assignment:
+ * nl = nr
+ * nr == N means zero nl.
+ */
+void
+cgen_as(Node *nl, Node *nr)
+{
+ Node nc;
+ Type *tl;
+ int iszer;
+
+ if(nl == N)
+ return;
+
+ if(debug['g']) {
+ dump("cgen_as", nl);
+ dump("cgen_as = ", nr);
+ }
+
+ iszer = 0;
+ if(nr == N || isnil(nr)) {
+ if(nl->op == OLIST) {
+ cgen_as(nl->left, nr);
+ cgen_as(nl->right, nr);
+ return;
+ }
+ tl = nl->type;
+ if(tl == T)
+ return;
+ if(isfat(tl)) {
+ clearfat(nl);
+ goto ret;
+ }
+
+ /* invent a "zero" for the rhs */
+ iszer = 1;
+ nr = &nc;
+ memset(nr, 0, sizeof(*nr));
+ switch(simtype[tl->etype]) {
+ default:
+ fatal("cgen_as: tl %T", tl);
+ break;
+
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ nr->val.u.xval = mal(sizeof(*nr->val.u.xval));
+ mpmovecfix(nr->val.u.xval, 0);
+ nr->val.ctype = CTINT;
+ break;
+
+ case TFLOAT32:
+ case TFLOAT64:
+ case TFLOAT80:
+ nr->val.u.fval = mal(sizeof(*nr->val.u.fval));
+ mpmovecflt(nr->val.u.fval, 0.0);
+ nr->val.ctype = CTFLT;
+ break;
+
+ case TBOOL:
+ nr->val.u.bval = 0;
+ nr->val.ctype = CTBOOL;
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ nr->val.ctype = CTNIL;
+ break;
+
+ }
+ nr->op = OLITERAL;
+ nr->type = tl;
+ nr->addable = 1;
+ ullmancalc(nr);
+ }
+
+ tl = nl->type;
+ if(tl == T)
+ return;
+
+ cgen(nr, nl);
+ if(iszer && nl->addable)
+ gused(nl);
+
+ret:
+ ;
+}