2009-03-30 20:15:07 -06:00
|
|
|
// 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"
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static void cgen_dcl(Node *n);
|
|
|
|
static void cgen_proc(Node *n, int proc);
|
2011-06-17 13:25:05 -06:00
|
|
|
static void checkgoto(Node*, Node*);
|
|
|
|
|
|
|
|
static Label *labellist;
|
|
|
|
static Label *lastlabel;
|
2010-06-14 12:24:51 -06:00
|
|
|
|
2009-03-30 20:15:07 -06:00
|
|
|
Node*
|
|
|
|
sysfunc(char *name)
|
|
|
|
{
|
|
|
|
Node *n;
|
|
|
|
|
2010-01-22 18:06:20 -07:00
|
|
|
n = newname(pkglookup(name, runtimepkg));
|
2009-03-30 20:15:07 -06:00
|
|
|
n->class = PFUNC;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
allocparams(void)
|
|
|
|
{
|
2009-08-04 23:59:23 -06:00
|
|
|
NodeList *l;
|
2009-03-30 20:15:07 -06:00
|
|
|
Node *n;
|
|
|
|
uint32 w;
|
2009-08-07 13:50:26 -06:00
|
|
|
Sym *s;
|
2009-09-14 19:38:30 -06:00
|
|
|
int lno;
|
2009-08-07 13:50:26 -06:00
|
|
|
|
|
|
|
if(stksize < 0)
|
|
|
|
fatal("allocparams not during code generation");
|
2009-03-30 20:15:07 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* allocate (set xoffset) the stack
|
|
|
|
* slots for all automatics.
|
|
|
|
* allocated starting at -w down.
|
|
|
|
*/
|
2009-09-14 19:38:30 -06:00
|
|
|
lno = lineno;
|
2009-08-07 13:50:26 -06:00
|
|
|
for(l=curfn->dcl; l; l=l->next) {
|
2009-08-04 23:59:23 -06:00
|
|
|
n = l->n;
|
2009-08-07 13:50:26 -06:00
|
|
|
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;
|
|
|
|
}
|
2009-08-04 23:59:23 -06:00
|
|
|
if(n->op != ONAME || n->class != PAUTO)
|
2009-03-30 20:15:07 -06:00
|
|
|
continue;
|
2011-06-09 16:02:34 -06:00
|
|
|
if (n->xoffset != BADWIDTH)
|
|
|
|
continue;
|
2009-08-05 01:42:44 -06:00
|
|
|
if(n->type == T)
|
|
|
|
continue;
|
2009-03-30 20:15:07 -06:00
|
|
|
dowidth(n->type);
|
|
|
|
w = n->type->width;
|
2009-12-03 13:46:34 -07:00
|
|
|
if(w >= MAXWIDTH)
|
2009-08-07 13:50:26 -06:00
|
|
|
fatal("bad width");
|
2009-03-30 20:15:07 -06:00
|
|
|
stksize += w;
|
2010-12-13 09:57:41 -07:00
|
|
|
stksize = rnd(stksize, n->type->align);
|
2011-05-25 08:18:49 -06:00
|
|
|
if(thechar == '5')
|
|
|
|
stksize = rnd(stksize, widthptr);
|
2009-03-30 20:15:07 -06:00
|
|
|
n->xoffset = -stksize;
|
|
|
|
}
|
2009-09-14 19:38:30 -06:00
|
|
|
lineno = lno;
|
2009-03-30 20:15:07 -06:00
|
|
|
}
|
|
|
|
|
2011-03-15 12:05:37 -06:00
|
|
|
void
|
|
|
|
clearlabels(void)
|
|
|
|
{
|
|
|
|
Label *l;
|
|
|
|
|
|
|
|
for(l=labellist; l!=L; l=l->link)
|
|
|
|
l->sym->label = L;
|
|
|
|
|
|
|
|
labellist = L;
|
|
|
|
lastlabel = L;
|
|
|
|
}
|
|
|
|
|
2011-06-17 13:25:05 -06:00
|
|
|
static Label*
|
|
|
|
newlab(Node *n)
|
2009-03-30 20:15:07 -06:00
|
|
|
{
|
2011-03-15 12:05:37 -06:00
|
|
|
Sym *s;
|
2011-06-17 13:25:05 -06:00
|
|
|
Label *lab;
|
2011-03-15 12:05:37 -06:00
|
|
|
|
2011-06-17 13:25:05 -06:00
|
|
|
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;
|
2009-03-30 20:15:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
checklabels(void)
|
|
|
|
{
|
2011-06-17 13:25:05 -06:00
|
|
|
Label *lab;
|
|
|
|
NodeList *l;
|
2009-03-30 20:15:07 -06:00
|
|
|
|
2011-06-17 13:25:05 -06:00
|
|
|
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;
|
2009-03-30 20:15:07 -06:00
|
|
|
}
|
2011-06-17 13:25:05 -06:00
|
|
|
if(lab->gotopc != P)
|
|
|
|
fatal("label %S never resolved", lab->sym);
|
|
|
|
for(l=lab->use; l; l=l->next)
|
|
|
|
checkgoto(l->n, lab->def);
|
2009-03-30 20:15:07 -06:00
|
|
|
}
|
2011-06-17 13:25:05 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2011-03-15 12:05:37 -06:00
|
|
|
}
|
2011-06-17 13:25:05 -06:00
|
|
|
|
|
|
|
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;
|
2011-03-15 12:05:37 -06:00
|
|
|
}
|
2011-06-17 13:25:05 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2009-03-30 20:15:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* compile statements
|
|
|
|
*/
|
2009-07-17 02:00:44 -06:00
|
|
|
void
|
|
|
|
genlist(NodeList *l)
|
|
|
|
{
|
|
|
|
for(; l; l=l->next)
|
|
|
|
gen(l->n);
|
|
|
|
}
|
|
|
|
|
2009-03-30 20:15:07 -06:00
|
|
|
void
|
|
|
|
gen(Node *n)
|
|
|
|
{
|
|
|
|
int32 lno;
|
|
|
|
Prog *scontin, *sbreak;
|
|
|
|
Prog *p1, *p2, *p3;
|
|
|
|
Label *lab;
|
2010-09-11 22:06:45 -06:00
|
|
|
int32 wasregalloc;
|
2009-03-30 20:15:07 -06:00
|
|
|
|
|
|
|
lno = setlineno(n);
|
2010-09-11 22:06:45 -06:00
|
|
|
wasregalloc = anyregalloc();
|
2009-03-30 20:15:07 -06:00
|
|
|
|
|
|
|
if(n == N)
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
p3 = pc; // save pc for loop labels
|
|
|
|
if(n->ninit)
|
2009-07-17 02:00:44 -06:00
|
|
|
genlist(n->ninit);
|
2009-03-30 20:15:07 -06:00
|
|
|
|
|
|
|
setlineno(n);
|
|
|
|
|
|
|
|
switch(n->op) {
|
|
|
|
default:
|
|
|
|
fatal("gen: unknown op %N", n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCASE:
|
|
|
|
case OFALL:
|
|
|
|
case OXCASE:
|
|
|
|
case OXFALL:
|
2009-08-07 13:50:26 -06:00
|
|
|
case ODCLCONST:
|
|
|
|
case ODCLFUNC:
|
|
|
|
case ODCLTYPE:
|
2009-07-29 15:49:01 -06:00
|
|
|
break;
|
|
|
|
|
2009-03-30 20:15:07 -06:00
|
|
|
case OEMPTY:
|
|
|
|
break;
|
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
case OBLOCK:
|
|
|
|
genlist(n->list);
|
|
|
|
break;
|
|
|
|
|
2009-03-30 20:15:07 -06:00
|
|
|
case OLABEL:
|
2011-06-17 13:25:05 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2009-03-30 20:15:07 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OGOTO:
|
2011-06-17 13:25:05 -06:00
|
|
|
// 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);
|
2009-03-30 20:15:07 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OBREAK:
|
|
|
|
if(n->left != N) {
|
2011-03-15 12:05:37 -06:00
|
|
|
lab = n->left->sym->label;
|
|
|
|
if(lab == L) {
|
2009-03-30 20:15:07 -06:00
|
|
|
yyerror("break label not defined: %S", n->left->sym);
|
2011-03-15 12:05:37 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
lab->used = 1;
|
|
|
|
if(lab->breakpc == P) {
|
|
|
|
yyerror("invalid break label %S", n->left->sym);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
gjmp(lab->breakpc);
|
2009-03-30 20:15:07 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(breakpc == P) {
|
|
|
|
yyerror("break is not in a loop");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
gjmp(breakpc);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCONTINUE:
|
|
|
|
if(n->left != N) {
|
2011-03-15 12:05:37 -06:00
|
|
|
lab = n->left->sym->label;
|
|
|
|
if(lab == L) {
|
2009-07-29 15:49:01 -06:00
|
|
|
yyerror("continue label not defined: %S", n->left->sym);
|
2011-03-15 12:05:37 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
lab->used = 1;
|
|
|
|
if(lab->continpc == P) {
|
|
|
|
yyerror("invalid continue label %S", n->left->sym);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
gjmp(lab->continpc);
|
2009-03-30 20:15:07 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(continpc == P) {
|
2009-07-29 15:49:01 -06:00
|
|
|
yyerror("continue is not in a loop");
|
2009-03-30 20:15:07 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
gjmp(continpc);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OFOR:
|
|
|
|
sbreak = breakpc;
|
2009-08-04 17:53:06 -06:00
|
|
|
p1 = gjmp(P); // goto test
|
2009-03-30 20:15:07 -06:00
|
|
|
breakpc = gjmp(P); // break: goto done
|
|
|
|
scontin = continpc;
|
|
|
|
continpc = pc;
|
|
|
|
|
2009-07-29 15:49:01 -06:00
|
|
|
// define break and continue labels
|
2011-06-17 13:25:05 -06:00
|
|
|
if((lab = stmtlabel(n)) != L) {
|
2009-07-29 15:49:01 -06:00
|
|
|
lab->breakpc = breakpc;
|
|
|
|
lab->continpc = continpc;
|
2011-06-17 13:25:05 -06:00
|
|
|
}
|
2009-03-30 20:15:07 -06:00
|
|
|
gen(n->nincr); // contin: incr
|
|
|
|
patch(p1, pc); // test:
|
|
|
|
bgen(n->ntest, 0, breakpc); // if(!test) goto break
|
2009-07-17 02:00:44 -06:00
|
|
|
genlist(n->nbody); // body
|
2009-03-30 20:15:07 -06:00
|
|
|
gjmp(continpc);
|
|
|
|
patch(breakpc, pc); // done:
|
|
|
|
continpc = scontin;
|
|
|
|
breakpc = sbreak;
|
2011-03-15 12:05:37 -06:00
|
|
|
if(lab) {
|
|
|
|
lab->breakpc = P;
|
|
|
|
lab->continpc = P;
|
|
|
|
}
|
2009-03-30 20:15:07 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OIF:
|
|
|
|
p1 = gjmp(P); // goto test
|
|
|
|
p2 = gjmp(P); // p2: goto else
|
|
|
|
patch(p1, pc); // test:
|
2009-08-04 17:53:06 -06:00
|
|
|
bgen(n->ntest, 0, p2); // if(!test) goto p2
|
2009-07-17 02:00:44 -06:00
|
|
|
genlist(n->nbody); // then
|
2009-03-30 20:15:07 -06:00
|
|
|
p3 = gjmp(P); // goto done
|
|
|
|
patch(p2, pc); // else:
|
2009-07-17 02:00:44 -06:00
|
|
|
genlist(n->nelse); // else
|
2009-03-30 20:15:07 -06:00
|
|
|
patch(p3, pc); // done:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OSWITCH:
|
|
|
|
sbreak = breakpc;
|
2009-08-04 17:53:06 -06:00
|
|
|
p1 = gjmp(P); // goto test
|
2009-03-30 20:15:07 -06:00
|
|
|
breakpc = gjmp(P); // break: goto done
|
|
|
|
|
|
|
|
// define break label
|
2011-06-17 13:25:05 -06:00
|
|
|
if((lab = stmtlabel(n)) != L)
|
2009-07-29 15:49:01 -06:00
|
|
|
lab->breakpc = breakpc;
|
2009-03-30 20:15:07 -06:00
|
|
|
|
|
|
|
patch(p1, pc); // test:
|
2009-07-17 02:00:44 -06:00
|
|
|
genlist(n->nbody); // switch(test) body
|
2009-03-30 20:15:07 -06:00
|
|
|
patch(breakpc, pc); // done:
|
|
|
|
breakpc = sbreak;
|
2011-03-15 12:05:37 -06:00
|
|
|
if(lab != L)
|
|
|
|
lab->breakpc = P;
|
2009-03-30 20:15:07 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OSELECT:
|
|
|
|
sbreak = breakpc;
|
2009-08-04 17:53:06 -06:00
|
|
|
p1 = gjmp(P); // goto test
|
2009-03-30 20:15:07 -06:00
|
|
|
breakpc = gjmp(P); // break: goto done
|
|
|
|
|
|
|
|
// define break label
|
2011-06-17 13:25:05 -06:00
|
|
|
if((lab = stmtlabel(n)) != L)
|
2009-07-29 15:49:01 -06:00
|
|
|
lab->breakpc = breakpc;
|
2009-03-30 20:15:07 -06:00
|
|
|
|
|
|
|
patch(p1, pc); // test:
|
2009-07-17 02:00:44 -06:00
|
|
|
genlist(n->nbody); // select() body
|
2009-03-30 20:15:07 -06:00
|
|
|
patch(breakpc, pc); // done:
|
|
|
|
breakpc = sbreak;
|
2011-03-15 12:05:37 -06:00
|
|
|
if(lab != L)
|
|
|
|
lab->breakpc = P;
|
2009-03-30 20:15:07 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OASOP:
|
|
|
|
cgen_asop(n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ODCL:
|
|
|
|
cgen_dcl(n->left);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OAS:
|
2009-09-05 21:32:24 -06:00
|
|
|
if(gen_as_init(n))
|
|
|
|
break;
|
2009-03-30 20:15:07 -06:00
|
|
|
cgen_as(n->left, n->right);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCALLMETH:
|
|
|
|
cgen_callmeth(n, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCALLINTER:
|
|
|
|
cgen_callinter(n, N, 0);
|
|
|
|
break;
|
|
|
|
|
2009-07-30 17:53:08 -06:00
|
|
|
case OCALLFUNC:
|
2009-03-30 20:15:07 -06:00
|
|
|
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:
|
2010-09-11 22:06:45 -06:00
|
|
|
if(anyregalloc() != wasregalloc) {
|
|
|
|
dump("node", n);
|
|
|
|
fatal("registers left allocated");
|
|
|
|
}
|
|
|
|
|
2009-03-30 20:15:07 -06:00
|
|
|
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");
|
|
|
|
|
2009-07-30 17:53:08 -06:00
|
|
|
n->op = OCALLFUNC;
|
2009-03-30 20:15:07 -06:00
|
|
|
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;
|
|
|
|
|
2009-07-30 17:53:08 -06:00
|
|
|
case OCALLFUNC:
|
2009-03-30 20:15:07 -06:00
|
|
|
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.
|
|
|
|
*/
|
2010-06-14 12:24:51 -06:00
|
|
|
static void
|
2009-03-30 20:15:07 -06:00
|
|
|
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;
|
2010-02-01 17:22:16 -07:00
|
|
|
if(n->alloc == nil)
|
|
|
|
n->alloc = callnew(n->type);
|
2009-03-30 20:15:07 -06:00
|
|
|
cgen_as(n->heapaddr, n->alloc);
|
|
|
|
}
|
|
|
|
|
2009-09-09 00:16:19 -06:00
|
|
|
/*
|
|
|
|
* generate discard of value
|
|
|
|
*/
|
2010-06-14 12:24:51 -06:00
|
|
|
static void
|
2009-09-09 00:16:19 -06:00
|
|
|
cgen_discard(Node *nr)
|
|
|
|
{
|
|
|
|
Node tmp;
|
|
|
|
|
|
|
|
if(nr == N)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch(nr->op) {
|
|
|
|
case ONAME:
|
2010-12-13 14:51:19 -07:00
|
|
|
if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
|
2009-09-21 16:45:55 -06:00
|
|
|
gused(nr);
|
2009-09-09 00:16:19 -06:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-30 20:15:07 -06:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
2009-09-09 00:16:19 -06:00
|
|
|
if(isblank(nl)) {
|
|
|
|
cgen_discard(nr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-03-30 20:15:07 -06:00
|
|
|
iszer = 0;
|
|
|
|
if(nr == N || isnil(nr)) {
|
2009-05-04 22:48:46 -06:00
|
|
|
// externals and heaps should already be clear
|
2009-05-05 18:33:51 -06:00
|
|
|
if(nr == N) {
|
|
|
|
if(nl->class == PEXTERN)
|
|
|
|
return;
|
|
|
|
if(nl->class & PHEAP)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-03-30 20:15:07 -06:00
|
|
|
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;
|
|
|
|
|
2010-03-02 19:32:11 -07:00
|
|
|
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;
|
2009-03-30 20:15:07 -06:00
|
|
|
}
|
|
|
|
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:
|
|
|
|
;
|
|
|
|
}
|
2009-08-07 13:50:26 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
2011-06-09 16:02:34 -06:00
|
|
|
tempname(Node *nn, Type *t)
|
2009-08-07 13:50:26 -06:00
|
|
|
{
|
2011-06-09 16:02:34 -06:00
|
|
|
Node *n;
|
2009-08-07 13:50:26 -06:00
|
|
|
Sym *s;
|
|
|
|
uint32 w;
|
|
|
|
|
|
|
|
if(stksize < 0)
|
|
|
|
fatal("tempname not during code generation");
|
|
|
|
|
2011-06-09 16:02:34 -06:00
|
|
|
if (curfn == N)
|
|
|
|
fatal("no curfn for tempname");
|
|
|
|
|
2009-08-07 13:50:26 -06:00
|
|
|
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);
|
2011-06-09 16:02:34 -06:00
|
|
|
n = nod(ONAME, N, N);
|
2009-08-07 13:50:26 -06:00
|
|
|
n->sym = s;
|
|
|
|
n->type = t;
|
|
|
|
n->class = PAUTO;
|
|
|
|
n->addable = 1;
|
|
|
|
n->ullman = 1;
|
|
|
|
n->noescape = 1;
|
2011-06-09 16:02:34 -06:00
|
|
|
n->curfn = curfn;
|
|
|
|
curfn->dcl = list(curfn->dcl, n);
|
2009-08-07 13:50:26 -06:00
|
|
|
|
|
|
|
dowidth(t);
|
|
|
|
w = t->width;
|
|
|
|
stksize += w;
|
2010-12-13 09:57:41 -07:00
|
|
|
stksize = rnd(stksize, t->align);
|
2011-05-25 08:18:49 -06:00
|
|
|
if(thechar == '5')
|
|
|
|
stksize = rnd(stksize, widthptr);
|
2009-08-07 13:50:26 -06:00
|
|
|
n->xoffset = -stksize;
|
2011-06-09 16:02:34 -06:00
|
|
|
|
|
|
|
// print("\ttmpname (%d): %N\n", stksize, n);
|
|
|
|
|
|
|
|
*nn = *n;
|
2009-08-07 13:50:26 -06:00
|
|
|
}
|