diff options
Diffstat (limited to 'src/cmd/gc/gen.c')
-rw-r--r-- | src/cmd/gc/gen.c | 505 |
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: + ; +} |