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.c790
1 files changed, 0 insertions, 790 deletions
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
deleted file mode 100644
index cb66921ba..000000000
--- a/src/cmd/gc/gen.c
+++ /dev/null
@@ -1,790 +0,0 @@
-// 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"
-
-static void cgen_dcl(Node *n);
-static void cgen_proc(Node *n, int proc);
-static void checkgoto(Node*, Node*);
-
-static Label *labellist;
-static Label *lastlabel;
-
-Node*
-sysfunc(char *name)
-{
- Node *n;
-
- n = newname(pkglookup(name, runtimepkg));
- n->class = PFUNC;
- return n;
-}
-
-void
-allocparams(void)
-{
- NodeList *l;
- Node *n;
- uint32 w;
- Sym *s;
- int lno;
-
- if(stksize < 0)
- fatal("allocparams not during code generation");
-
- /*
- * allocate (set xoffset) the stack
- * slots for all automatics.
- * allocated starting at -w down.
- */
- lno = lineno;
- for(l=curfn->dcl; l; l=l->next) {
- n = l->n;
- if(n->op == ONAME && n->class == PHEAP-1) {
- // heap address variable; finish the job
- // started in addrescapes.
- s = n->sym;
- tempname(n, n->type);
- n->sym = s;
- }
- if(n->op != ONAME || n->class != PAUTO)
- continue;
- if (n->xoffset != BADWIDTH)
- continue;
- if(n->type == T)
- continue;
- dowidth(n->type);
- w = n->type->width;
- if(w >= MAXWIDTH)
- fatal("bad width");
- stksize += w;
- stksize = rnd(stksize, n->type->align);
- if(thechar == '5')
- stksize = rnd(stksize, widthptr);
- n->xoffset = -stksize;
- }
- lineno = lno;
-}
-
-void
-clearlabels(void)
-{
- Label *l;
-
- for(l=labellist; l!=L; l=l->link)
- l->sym->label = L;
-
- labellist = L;
- lastlabel = L;
-}
-
-static Label*
-newlab(Node *n)
-{
- Sym *s;
- Label *lab;
-
- s = n->left->sym;
- if((lab = s->label) == L) {
- lab = mal(sizeof(*lab));
- if(lastlabel == nil)
- labellist = lab;
- else
- lastlabel->link = lab;
- lastlabel = lab;
- lab->sym = s;
- s->label = lab;
- }
-
- if(n->op == OLABEL) {
- if(lab->def != N)
- yyerror("label %S already defined at %L", s, lab->def->lineno);
- else
- lab->def = n;
- } else
- lab->use = list(lab->use, n);
-
- return lab;
-}
-
-void
-checklabels(void)
-{
- Label *lab;
- NodeList *l;
-
- for(lab=labellist; lab!=L; lab=lab->link) {
- if(lab->def == N) {
- for(l=lab->use; l; l=l->next)
- yyerrorl(l->n->lineno, "label %S not defined", lab->sym);
- continue;
- }
- if(lab->use == nil && !lab->used) {
- yyerrorl(lab->def->lineno, "label %S defined and not used", lab->sym);
- continue;
- }
- if(lab->gotopc != P)
- fatal("label %S never resolved", lab->sym);
- for(l=lab->use; l; l=l->next)
- checkgoto(l->n, lab->def);
- }
-}
-
-static void
-checkgoto(Node *from, Node *to)
-{
- int nf, nt;
- Sym *block, *dcl, *fs, *ts;
- int lno;
-
- if(from->sym == to->sym)
- return;
-
- nf = 0;
- for(fs=from->sym; fs; fs=fs->link)
- nf++;
- nt = 0;
- for(fs=to->sym; fs; fs=fs->link)
- nt++;
- fs = from->sym;
- for(; nf > nt; nf--)
- fs = fs->link;
- if(fs != to->sym) {
- lno = lineno;
- setlineno(from);
-
- // decide what to complain about.
- // prefer to complain about 'into block' over declarations,
- // so scan backward to find most recent block or else dcl.
- block = S;
- dcl = S;
- ts = to->sym;
- for(; nt > nf; nt--) {
- if(ts->pkg == nil)
- block = ts;
- else
- dcl = ts;
- ts = ts->link;
- }
- while(ts != fs) {
- if(ts->pkg == nil)
- block = ts;
- else
- dcl = ts;
- ts = ts->link;
- fs = fs->link;
- }
-
- if(block)
- yyerror("goto %S jumps into block starting at %L", from->left->sym, block->lastlineno);
- else
- yyerror("goto %S jumps over declaration of %S at %L", from->left->sym, dcl, dcl->lastlineno);
- lineno = lno;
- }
-}
-
-static Label*
-stmtlabel(Node *n)
-{
- Label *lab;
-
- if(n->sym != S)
- if((lab = n->sym->label) != L)
- if(lab->def != N)
- if(lab->def->right == n)
- return lab;
- return L;
-}
-
-/*
- * compile statements
- */
-void
-genlist(NodeList *l)
-{
- for(; l; l=l->next)
- gen(l->n);
-}
-
-void
-gen(Node *n)
-{
- int32 lno;
- Prog *scontin, *sbreak;
- Prog *p1, *p2, *p3;
- Label *lab;
- int32 wasregalloc;
-
- lno = setlineno(n);
- wasregalloc = anyregalloc();
-
- if(n == N)
- goto ret;
-
- p3 = pc; // save pc for loop labels
- if(n->ninit)
- genlist(n->ninit);
-
- setlineno(n);
-
- switch(n->op) {
- default:
- fatal("gen: unknown op %N", n);
- break;
-
- case OCASE:
- case OFALL:
- case OXCASE:
- case OXFALL:
- case ODCLCONST:
- case ODCLFUNC:
- case ODCLTYPE:
- break;
-
- case OEMPTY:
- break;
-
- case OBLOCK:
- genlist(n->list);
- break;
-
- case OLABEL:
- lab = newlab(n);
-
- // if there are pending gotos, resolve them all to the current pc.
- for(p1=lab->gotopc; p1; p1=p2) {
- p2 = unpatch(p1);
- patch(p1, pc);
- }
- lab->gotopc = P;
- if(lab->labelpc == P)
- lab->labelpc = pc;
-
- if(n->right) {
- switch(n->right->op) {
- case OFOR:
- case OSWITCH:
- case OSELECT:
- // so stmtlabel can find the label
- n->right->sym = lab->sym;
- }
- }
- break;
-
- case OGOTO:
- // if label is defined, emit jump to it.
- // otherwise save list of pending gotos in lab->gotopc.
- // the list is linked through the normal jump target field
- // to avoid a second list. (the jumps are actually still
- // valid code, since they're just going to another goto
- // to the same label. we'll unwind it when we learn the pc
- // of the label in the OLABEL case above.)
- lab = newlab(n);
- if(lab->labelpc != P)
- gjmp(lab->labelpc);
- else
- lab->gotopc = gjmp(lab->gotopc);
- break;
-
- case OBREAK:
- if(n->left != N) {
- lab = n->left->sym->label;
- if(lab == L) {
- yyerror("break label not defined: %S", n->left->sym);
- break;
- }
- lab->used = 1;
- if(lab->breakpc == P) {
- yyerror("invalid break label %S", n->left->sym);
- break;
- }
- gjmp(lab->breakpc);
- break;
- }
- if(breakpc == P) {
- yyerror("break is not in a loop");
- break;
- }
- gjmp(breakpc);
- break;
-
- case OCONTINUE:
- if(n->left != N) {
- lab = n->left->sym->label;
- if(lab == L) {
- yyerror("continue label not defined: %S", n->left->sym);
- break;
- }
- lab->used = 1;
- if(lab->continpc == P) {
- yyerror("invalid continue label %S", n->left->sym);
- break;
- }
- gjmp(lab->continpc);
- break;
- }
- if(continpc == P) {
- yyerror("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 continue labels
- if((lab = stmtlabel(n)) != L) {
- lab->breakpc = breakpc;
- lab->continpc = continpc;
- }
- gen(n->nincr); // contin: incr
- patch(p1, pc); // test:
- bgen(n->ntest, 0, breakpc); // if(!test) goto break
- genlist(n->nbody); // body
- gjmp(continpc);
- patch(breakpc, pc); // done:
- continpc = scontin;
- breakpc = sbreak;
- if(lab) {
- lab->breakpc = P;
- lab->continpc = P;
- }
- break;
-
- case OIF:
- p1 = gjmp(P); // goto test
- p2 = gjmp(P); // p2: goto else
- patch(p1, pc); // test:
- bgen(n->ntest, 0, p2); // if(!test) goto p2
- genlist(n->nbody); // then
- p3 = gjmp(P); // goto done
- patch(p2, pc); // else:
- genlist(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
- if((lab = stmtlabel(n)) != L)
- lab->breakpc = breakpc;
-
- patch(p1, pc); // test:
- genlist(n->nbody); // switch(test) body
- patch(breakpc, pc); // done:
- breakpc = sbreak;
- if(lab != L)
- lab->breakpc = P;
- break;
-
- case OSELECT:
- sbreak = breakpc;
- p1 = gjmp(P); // goto test
- breakpc = gjmp(P); // break: goto done
-
- // define break label
- if((lab = stmtlabel(n)) != L)
- lab->breakpc = breakpc;
-
- patch(p1, pc); // test:
- genlist(n->nbody); // select() body
- patch(breakpc, pc); // done:
- breakpc = sbreak;
- if(lab != L)
- lab->breakpc = P;
- break;
-
- case OASOP:
- cgen_asop(n);
- break;
-
- case ODCL:
- cgen_dcl(n->left);
- break;
-
- case OAS:
- if(gen_as_init(n))
- break;
- cgen_as(n->left, n->right);
- break;
-
- case OCALLMETH:
- cgen_callmeth(n, 0);
- break;
-
- case OCALLINTER:
- cgen_callinter(n, N, 0);
- break;
-
- case OCALLFUNC:
- 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:
- if(anyregalloc() != wasregalloc) {
- dump("node", n);
- fatal("registers left allocated");
- }
-
- 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 = OCALLFUNC;
- 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 OCALLFUNC:
- 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.
- */
-static 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;
- if(n->alloc == nil)
- n->alloc = callnew(n->type);
- cgen_as(n->heapaddr, n->alloc);
-}
-
-/*
- * generate discard of value
- */
-static void
-cgen_discard(Node *nr)
-{
- Node tmp;
-
- if(nr == N)
- return;
-
- switch(nr->op) {
- case ONAME:
- if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
- gused(nr);
- break;
-
- // unary
- case OADD:
- case OAND:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLSH:
- case OLT:
- case OMOD:
- case OMUL:
- case ONE:
- case OOR:
- case ORSH:
- case OSUB:
- case OXOR:
- cgen_discard(nr->left);
- cgen_discard(nr->right);
- break;
-
- // binary
- case OCAP:
- case OCOM:
- case OLEN:
- case OMINUS:
- case ONOT:
- case OPLUS:
- cgen_discard(nr->left);
- break;
-
- // special enough to just evaluate
- default:
- tempname(&tmp, nr->type);
- cgen_as(&tmp, nr);
- gused(&tmp);
- }
-}
-
-/*
- * 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);
- }
-
- if(isblank(nl)) {
- cgen_discard(nr);
- return;
- }
-
- iszer = 0;
- if(nr == N || isnil(nr)) {
- // externals and heaps should already be clear
- if(nr == N) {
- if(nl->class == PEXTERN)
- return;
- if(nl->class & PHEAP)
- 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:
- 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;
-
- case TCOMPLEX64:
- case TCOMPLEX128:
- nr->val.u.cval = mal(sizeof(*nr->val.u.cval));
- mpmovecflt(&nr->val.u.cval->real, 0.0);
- mpmovecflt(&nr->val.u.cval->imag, 0.0);
- 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:
- ;
-}
-
-/*
- * gather series of offsets
- * >=0 is direct addressed field
- * <0 is pointer to next field (+1)
- */
-int
-dotoffset(Node *n, int *oary, Node **nn)
-{
- int i;
-
- switch(n->op) {
- case ODOT:
- if(n->xoffset == BADWIDTH) {
- dump("bad width in dotoffset", n);
- fatal("bad width in dotoffset");
- }
- i = dotoffset(n->left, oary, nn);
- if(i > 0) {
- if(oary[i-1] >= 0)
- oary[i-1] += n->xoffset;
- else
- oary[i-1] -= n->xoffset;
- break;
- }
- if(i < 10)
- oary[i++] = n->xoffset;
- break;
-
- case ODOTPTR:
- if(n->xoffset == BADWIDTH) {
- dump("bad width in dotoffset", n);
- fatal("bad width in dotoffset");
- }
- i = dotoffset(n->left, oary, nn);
- if(i < 10)
- oary[i++] = -(n->xoffset+1);
- break;
-
- default:
- *nn = n;
- return 0;
- }
- if(i >= 10)
- *nn = N;
- return i;
-}
-
-/*
- * make a new off the books
- */
-void
-tempname(Node *nn, Type *t)
-{
- Node *n;
- Sym *s;
- uint32 w;
-
- if(stksize < 0)
- fatal("tempname not during code generation");
-
- if (curfn == N)
- fatal("no curfn for tempname");
-
- if(t == T) {
- yyerror("tempname called with nil type");
- t = types[TINT32];
- }
-
- // give each tmp a different name so that there
- // a chance to registerizer them
- snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
- statuniqgen++;
- s = lookup(namebuf);
- n = nod(ONAME, N, N);
- n->sym = s;
- n->type = t;
- n->class = PAUTO;
- n->addable = 1;
- n->ullman = 1;
- n->noescape = 1;
- n->curfn = curfn;
- curfn->dcl = list(curfn->dcl, n);
-
- dowidth(t);
- w = t->width;
- stksize += w;
- stksize = rnd(stksize, t->align);
- if(thechar == '5')
- stksize = rnd(stksize, widthptr);
- n->xoffset = -stksize;
-
- // print("\ttmpname (%d): %N\n", stksize, n);
-
- *nn = *n;
-}