1
0
mirror of https://github.com/golang/go synced 2024-11-26 17:56:55 -07:00

move portable code generation (basic statements) to gc.

R=ken
OCL=26929
CL=26929
This commit is contained in:
Russ Cox 2009-03-30 19:15:07 -07:00
parent 79b55e226a
commit bac922c6e1
9 changed files with 656 additions and 599 deletions

View File

@ -30,7 +30,5 @@ betypeinit(void)
zprog.from.scale = 0; zprog.from.scale = 0;
zprog.to = zprog.from; zprog.to = zprog.from;
symstringo = lookup(".stringo"); // strings
listinit(); listinit();
} }

View File

@ -8,17 +8,6 @@
#include "gg.h" #include "gg.h"
#include "opt.h" #include "opt.h"
static Node*
sysfunc(char *name)
{
Node *n;
n = newname(pkglookup(name, "sys"));
n->class = PFUNC;
return n;
}
void void
compile(Node *fn) compile(Node *fn)
{ {
@ -29,16 +18,13 @@ compile(Node *fn)
Type *t; Type *t;
Iter save; Iter save;
if(newproc == N) if(newproc == N) {
newproc = sysfunc("newproc"); newproc = sysfunc("newproc");
if(deferproc == N)
deferproc = sysfunc("deferproc"); deferproc = sysfunc("deferproc");
if(deferreturn == N)
deferreturn = sysfunc("deferreturn"); deferreturn = sysfunc("deferreturn");
if(throwindex == N)
throwindex = sysfunc("throwindex"); throwindex = sysfunc("throwindex");
if(throwreturn == N)
throwreturn = sysfunc("throwreturn"); throwreturn = sysfunc("throwreturn");
}
if(fn->nbody == N) if(fn->nbody == N)
return; return;
@ -110,297 +96,6 @@ ret:
lineno = lno; lineno = lno;
} }
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;
}
/*
* 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);
gbranch(AJMP, T);
break;
case OBREAK:
if(n->left != N) {
for(lab=labellist; lab!=L; lab=lab->link) {
if(lab->breakpc != P) {
patch(gbranch(AJMP, T), 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;
}
patch(gbranch(AJMP, T), breakpc);
break;
case OCONTINUE:
if(n->left != N) {
for(lab=labellist; lab!=L; lab=lab->link) {
if(lab->continpc != P) {
patch(gbranch(AJMP, T), 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;
}
patch(gbranch(AJMP, T), continpc);
break;
case OFOR:
sbreak = breakpc;
p1 = gbranch(AJMP, T); // goto test
breakpc = gbranch(AJMP, T); // 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
patch(gbranch(AJMP, T), continpc); // goto contin
patch(breakpc, pc); // done:
continpc = scontin;
breakpc = sbreak;
break;
case OIF:
p1 = gbranch(AJMP, T); // goto test
p2 = gbranch(AJMP, T); // 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 = gbranch(AJMP, T); // goto done
patch(p2, pc); // else:
gen(n->nelse); // else
patch(p3, pc); // done:
break;
case OSWITCH:
sbreak = breakpc;
p1 = gbranch(AJMP, T); // goto test
breakpc = gbranch(AJMP, T); // 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 = gbranch(AJMP, T); // goto test
breakpc = gbranch(AJMP, T); // 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;
}
/*
* compute total size of f's in/out arguments.
*/
int
argsize(Type *t)
{
Iter save;
Type *fp;
int w, x;
w = 0;
fp = structfirst(&save, getoutarg(t));
while(fp != T) {
x = fp->width + fp->type->width;
if(x > w)
w = x;
fp = structnext(&save);
}
fp = funcfirst(&save, t);
while(fp != T) {
x = fp->width + fp->type->width;
if(x > w)
w = x;
fp = funcnext(&save);
}
w = (w+7) & ~7;
return w;
}
/* /*
* generate: * generate:
* call f * call f
@ -494,33 +189,6 @@ cgen_callinter(Node *n, Node *res, int proc)
setmaxarg(n->left->type); setmaxarg(n->left->type);
} }
/*
* 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 function call; * generate function call;
* proc=0 normal call * proc=0 normal call
@ -577,31 +245,6 @@ ret:
; ;
} }
/*
* 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;
}
}
/* /*
* call to n has already been generated. * call to n has already been generated.
* generate: * generate:
@ -807,152 +450,6 @@ ret:
; ;
} }
/*
* 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, n1;
Type *tl;
uint32 w, c, q;
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)) {
/* clear a fat object */
if(debug['g'])
dump("\nclearfat", nl);
w = nl->type->width;
c = w % 8; // bytes
q = w / 8; // quads
gconreg(AMOVQ, 0, D_AX);
nodreg(&n1, types[tptr], D_DI);
agen(nl, &n1);
if(q >= 4) {
gconreg(AMOVQ, q, D_CX);
gins(AREP, N, N); // repeat
gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
} else
while(q > 0) {
gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
q--;
}
if(c >= 4) {
gconreg(AMOVQ, c, D_CX);
gins(AREP, N, N); // repeat
gins(ASTOSB, N, N); // STOB AL,*(DI)+
} else
while(c > 0) {
gins(ASTOSB, N, N); // STOB AL,*(DI)+
c--;
}
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)
gins(ANOP, nl, N); // used
ret:
;
}
int int
samereg(Node *a, Node *b) samereg(Node *a, Node *b)
{ {
@ -1156,61 +653,40 @@ cgen_bmul(int op, Node *nl, Node *nr, Node *res)
} }
void void
checklabels(void) clearfat(Node *nl)
{ {
Label *l, *m; uint32 w, c, q;
Sym *s; Node n1;
// // print the label list /* clear a fat object */
// for(l=labellist; l!=L; l=l->link) { if(debug['g'])
// print("lab %O %S\n", l->op, l->sym); dump("\nclearfat", nl);
// }
for(l=labellist; l!=L; l=l->link) { w = nl->type->width;
switch(l->op) { c = w % 8; // bytes
case OFOR: q = w / 8; // quads
case OLABEL:
// these are definitions - gconreg(AMOVQ, 0, D_AX);
s = l->sym; nodreg(&n1, types[tptr], D_DI);
for(m=labellist; m!=L; m=m->link) { agen(nl, &n1);
if(m->sym != s)
continue; if(q >= 4) {
switch(m->op) { gconreg(AMOVQ, q, D_CX);
case OFOR: gins(AREP, N, N); // repeat
case OLABEL: gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
// these are definitions - } else
// look for redefinitions while(q > 0) {
if(l != m) gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
yyerror("label %S redefined", s); q--;
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 if(c >= 4) {
for(l=labellist; l!=L; l=l->link) gconreg(AMOVQ, c, D_CX);
if(l->op == OGOTO && l->sym != S) gins(AREP, N, N); // repeat
yyerror("label %S not defined", l->sym); gins(ASTOSB, N, N); // STOB AL,*(DI)+
} else
while(c > 0) {
gins(ASTOSB, N, N); // STOB AL,*(DI)+
c--;
} }
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;
} }

View File

@ -13,7 +13,6 @@
#define EXTERN extern #define EXTERN extern
#endif #endif
typedef struct Prog Prog;
typedef struct Addr Addr; typedef struct Addr Addr;
struct Addr struct Addr
@ -41,7 +40,6 @@ struct Prog
Prog* link; // next instruction in this func Prog* link; // next instruction in this func
void* reg; // pointer to containing Reg struct void* reg; // pointer to containing Reg struct
}; };
#define P ((Prog*)0)
typedef struct Plist Plist; typedef struct Plist Plist;
struct Plist struct Plist
@ -53,22 +51,6 @@ struct Plist
Plist* link; Plist* link;
}; };
typedef struct Label Label;
struct Label
{
uchar op; // OGOTO/OLABEL
Sym* sym;
Prog* label; // pointer to code
Prog* breakpc; // pointer to code
Prog* continpc; // pointer to code
Label* link;
};
#define L ((Label*)0)
EXTERN Prog* continpc;
EXTERN Prog* breakpc;
EXTERN Prog* pc;
EXTERN Prog* firstpc;
EXTERN Plist* plist; EXTERN Plist* plist;
EXTERN Plist* plast; EXTERN Plist* plast;
EXTERN Biobuf* bout; EXTERN Biobuf* bout;
@ -79,8 +61,6 @@ EXTERN String emptystring;
extern char* anames[]; extern char* anames[];
EXTERN Hist* hist; EXTERN Hist* hist;
EXTERN Prog zprog; EXTERN Prog zprog;
EXTERN Label* labellist;
EXTERN Label* findlab(Sym*);
EXTERN Node* curfn; EXTERN Node* curfn;
EXTERN Node* newproc; EXTERN Node* newproc;
EXTERN Node* deferproc; EXTERN Node* deferproc;
@ -96,9 +76,6 @@ void proglist(void);
void gen(Node*); void gen(Node*);
Node* lookdot(Node*, Node*, int); Node* lookdot(Node*, Node*, int);
void cgen_as(Node*, Node*); void cgen_as(Node*, Node*);
void cgen_asop(Node*);
void cgen_ret(Node*);
void cgen_call(Node*, int);
void cgen_callmeth(Node*, int); void cgen_callmeth(Node*, int);
void cgen_callinter(Node*, Node*, int); void cgen_callinter(Node*, Node*, int);
void cgen_proc(Node*, int); void cgen_proc(Node*, int);
@ -116,7 +93,6 @@ void ginscall(Node*, int);
/* /*
* cgen * cgen
*/ */
void cgen(Node*, Node*);
void agen(Node*, Node*); void agen(Node*, Node*);
void igen(Node*, Node*, Node*); void igen(Node*, Node*, Node*);
vlong fieldoffset(Type*, Node*); vlong fieldoffset(Type*, Node*);
@ -134,7 +110,6 @@ void cgen_aret(Node*, Node*);
void clearp(Prog*); void clearp(Prog*);
void proglist(void); void proglist(void);
Prog* gbranch(int, Type*); Prog* gbranch(int, Type*);
void patch(Prog*, Prog*);
Prog* prog(int); Prog* prog(int);
void gaddoffset(Node*); void gaddoffset(Node*);
void gconv(int, int); void gconv(int, int);

View File

@ -1927,3 +1927,21 @@ no:
sudoclean(); sudoclean();
return 0; return 0;
} }
void
gused(Node *n)
{
gins(ANOP, n, N); // used
}
Prog*
gjmp(Prog *to)
{
Prog *p;
p = gbranch(AJMP, T);
if(to != P)
patch(p, to);
return p;
}

View File

@ -30,6 +30,7 @@ OFILES=\
compat.$O\ compat.$O\
bits.$O\ bits.$O\
align.$O\ align.$O\
gen.$O\
$(LIB): $(OFILES) $(LIB): $(OFILES)
ar rsc $(LIB) $(OFILES) ar rsc $(LIB) $(OFILES)

View File

@ -349,3 +349,35 @@ typeinit(int lex)
Array_cap = rnd(Array_nel+types[TUINT32]->width, types[TUINT32]->width); Array_cap = rnd(Array_nel+types[TUINT32]->width, types[TUINT32]->width);
sizeof_Array = rnd(Array_cap+types[TUINT32]->width, maxround); sizeof_Array = rnd(Array_cap+types[TUINT32]->width, maxround);
} }
/*
* compute total size of f's in/out arguments.
*/
int
argsize(Type *t)
{
Iter save;
Type *fp;
int w, x;
w = 0;
fp = structfirst(&save, getoutarg(t));
while(fp != T) {
x = fp->width + fp->type->width;
if(x > w)
w = x;
fp = structnext(&save);
}
fp = funcfirst(&save, t);
while(fp != T) {
x = fp->width + fp->type->width;
if(x > w)
w = x;
fp = funcnext(&save);
}
w = (w+7) & ~7;
return w;
}

505
src/cmd/gc/gen.c Normal file
View File

@ -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:
;
}

View File

@ -937,26 +937,12 @@ int smallintconst(Node*);
int consttype(Node*); int consttype(Node*);
int isconst(Node*, int); int isconst(Node*, int);
/*
* gen.c/gsubr.c/obj.c
*/
void betypeinit(void);
vlong convvtox(vlong, int);
void compile(Node*);
void proglist(void);
int optopop(int);
void dumpobj(void);
void dowidth(Type*);
void argspace(int32);
Node* nodarg(Type*, int);
Type* deep(Type*);
Type* shallow(Type*);
/* /*
* align.c * align.c
*/ */
uint32 rnd(uint32, uint32); uint32 rnd(uint32, uint32);
void dowidth(Type*); void dowidth(Type*);
int argsize(Type*);
/* /*
* bits.c * bits.c
@ -972,3 +958,66 @@ int bset(Bits, uint);
int Qconv(Fmt *fp); int Qconv(Fmt *fp);
int bitno(int32); int bitno(int32);
/*
* gen.c
*/
typedef struct Prog Prog;
#define P ((Prog*)0)
typedef struct Label Label;
struct Label
{
uchar op; // OGOTO/OLABEL
Sym* sym;
Prog* label; // pointer to code
Prog* breakpc; // pointer to code
Prog* continpc; // pointer to code
Label* link;
};
#define L ((Label*)0)
EXTERN Label* labellist;
EXTERN Label* findlab(Sym*);
EXTERN Prog* continpc;
EXTERN Prog* breakpc;
EXTERN Prog* pc;
EXTERN Prog* firstpc;
void allocparams(void);
void cgen_as(Node *nl, Node *nr);
void cgen_callmeth(Node *n, int proc);
void cgen_dcl(Node *n);
void cgen_proc(Node *n, int proc);
void checklabels(void);
Label* findlab(Sym *s);
void gen(Node *n);
void newlab(int op, Sym *s);
Node* sysfunc(char *name);
/*
* gen.c/gsubr.c/obj.c
*/
void betypeinit(void);
vlong convvtox(vlong, int);
void compile(Node*);
void proglist(void);
int optopop(int);
void dumpobj(void);
void dowidth(Type*);
void argspace(int32);
Node* nodarg(Type*, int);
Type* deep(Type*);
Type* shallow(Type*);
Prog* gjmp(Prog*);
void patch(Prog*, Prog*);
void bgen(Node *n, int true, Prog *to);
void cgen_asop(Node *n);
void cgen_call(Node *n, int proc);
void cgen_callinter(Node *n, Node *res, int proc);
void cgen_ret(Node *n);
int isfat(Type*);
void clearfat(Node *n);
void cgen(Node*, Node*);
void gused(Node*);

View File

@ -66,6 +66,8 @@ main(int argc, char *argv[])
lexinit(); lexinit();
typeinit(LBASETYPE); typeinit(LBASETYPE);
symstringo = lookup(".stringo"); // strings
lineno = 1; lineno = 1;
block = 1; block = 1;
blockgen = 1; blockgen = 1;
@ -336,7 +338,8 @@ cannedimports(char *file, char *cp)
} }
int int
isfrog(int c) { isfrog(int c)
{
// complain about possibly invisible control characters // complain about possibly invisible control characters
if(c < 0) if(c < 0)
return 1; return 1;