1
0
mirror of https://github.com/golang/go synced 2024-10-05 00:11:21 -06:00
go/src/cmd/gc/gen.c
Russ Cox 758f2bc556 eliminate the package global name space assumption in object files
5g/6g/8g: add import statements to export metadata, mapping package path to package name.
	recognize "" as the path of the package in export metadata.
	use "" as the path of the package in object symbol names.

5c/6c/8c, 5a/6a/8a: rewrite leading . to "". so that ·Sin means Sin in this package.

5l/6l/8l: rewrite "" in symbol names as object files are read.

gotest: handle new symbol names.

gopack: handle new import lines in export metadata.

Collectively, these changes eliminate the assumption of a global
name space in the object file formats.  Higher level pieces such as
reflect and the computation of type hashes still depend on the
assumption; we're not done yet.

R=ken2, r, ken3
CC=golang-dev
https://golang.org/cl/186263
2010-01-22 17:06:20 -08:00

659 lines
11 KiB
C

// 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, 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->type == T)
continue;
dowidth(n->type);
w = n->type->width;
if(w >= MAXWIDTH)
fatal("bad width");
stksize += w;
stksize = rnd(stksize, w);
n->xoffset = -stksize;
}
lineno = lno;
}
void
newlab(int op, Sym *s, Node *stmt)
{
Label *lab;
lab = mal(sizeof(*lab));
lab->link = labellist;
labellist = lab;
lab->sym = s;
lab->op = op;
lab->label = pc;
lab->stmt = stmt;
}
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 OLABEL:
// these are definitions -
s = l->sym;
for(m=labellist; m!=L; m=m->link) {
if(m->sym != s)
continue;
switch(m->op) {
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);
}
/*
* 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;
lno = setlineno(n);
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:
// insert no-op so that
// L:; for { }
// does not treat L as a label for the loop.
if(labellist && labellist->label == p3)
gused(N);
break;
case OBLOCK:
genlist(n->list);
break;
case OLABEL:
newlab(OLABEL, n->left->sym, n->right);
break;
case OGOTO:
newlab(OGOTO, n->left->sym, N);
gjmp(P);
break;
case OBREAK:
if(n->left != N) {
for(lab=labellist; lab!=L; lab=lab->link) {
if(lab->sym == n->left->sym) {
if(lab->breakpc == P)
yyerror("invalid break label %S", n->left->sym);
gjmp(lab->breakpc);
goto donebreak;
}
}
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);
donebreak:
break;
case OCONTINUE:
if(n->left != N) {
for(lab=labellist; lab!=L; lab=lab->link) {
if(lab->sym == n->left->sym) {
if(lab->continpc == P)
yyerror("invalid continue label %S", n->left->sym);
gjmp(lab->continpc);
goto donecont;
}
}
if(lab == L)
yyerror("continue label not defined: %S", n->left->sym);
break;
}
if(continpc == P) {
yyerror("continue is not in a loop");
break;
}
gjmp(continpc);
donecont:
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 = labellist) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n) {
lab->breakpc = breakpc;
lab->continpc = continpc;
}
gen(n->nincr); // contin: incr
patch(p1, pc); // test:
if(n->ntest != N)
if(n->ntest->ninit != nil)
genlist(n->ntest->ninit);
bgen(n->ntest, 0, breakpc); // if(!test) goto break
genlist(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 != nil)
genlist(n->ntest->ninit);
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 = labellist) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n)
lab->breakpc = breakpc;
patch(p1, pc); // test:
genlist(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
if((lab = labellist) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n)
lab->breakpc = breakpc;
patch(p1, pc); // test:
genlist(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:
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:
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.
*/
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 discard of value
*/
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)
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;
}
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 *n, Type *t)
{
Sym *s;
uint32 w;
if(stksize < 0)
fatal("tempname not during code generation");
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);
memset(n, 0, sizeof(*n));
n->op = ONAME;
n->sym = s;
n->type = t;
n->class = PAUTO;
n->addable = 1;
n->ullman = 1;
n->noescape = 1;
dowidth(t);
w = t->width;
stksize += w;
stksize = rnd(stksize, w);
n->xoffset = -stksize;
}