1
0
mirror of https://github.com/golang/go synced 2024-11-12 07:40:23 -07:00

reg and peep

R=r
OCL=19871
CL=19871
This commit is contained in:
Ken Thompson 2008-11-22 17:58:53 -08:00
parent 5169bb44e6
commit e081f25c3e
8 changed files with 306 additions and 130 deletions

View File

@ -176,12 +176,14 @@ cgen(Node *n, Node *res)
gins(optoas(OCMP, types[tptr]), &n1, &n2);
p1 = gbranch(optoas(OEQ, types[tptr]), T);
n1.op = OINDREG;
n1.type = types[TINT32];
gmove(&n1, res);
n2 = n1;
n2.op = OINDREG;
n2.type = types[TINT32];
gmove(&n2, &n1);
patch(p1, pc);
gmove(&n1, res);
regfree(&n1);
break;
}

View File

@ -100,9 +100,8 @@ if(throwreturn == N) {
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
if(debug['N']) {
if(!debug['N'] || debug['R'] || debug['P'])
regopt(ptxt);
}
// fill in argument size
ptxt->to.offset = rnd(curfn->type->argwid, maxround);
@ -918,6 +917,33 @@ cgen_asop(Node *n)
nl = n->left;
nr = n->right;
if(nl->addable && nr->op == OLITERAL)
switch(n->etype) {
case OADD:
if(!isint[nl->type->etype])
goto com;
if(mpgetfix(nr->val.u.xval) != 1)
goto com;
gins(optoas(OINC, nl->type), N, nl);
goto ret;
case OSUB:
if(!isint[nl->type->etype])
goto com;
if(mpgetfix(nr->val.u.xval) != 1)
goto com;
gins(optoas(ODEC, nl->type), N, nl);
goto ret;
com:
case OXOR:
case OAND:
case OOR:
if(!isint[nl->type->etype])
break;
gins(optoas(n->etype, nl->type), nr, nl);
goto ret;
}
if(nr->ullman >= UINF && nl->ullman >= UINF) {
tempname(&n1, nr->type);
cgen(nr, &n1);
@ -960,10 +986,12 @@ cgen_as(Node *nl, Node *nr, int op)
Node nc, n1;
Type *tl;
uint32 w, c;
int iszer;
if(nl == N)
return;
iszer = 0;
if(nr == N || isnil(nr)) {
if(nl->op == OLIST) {
cgen_as(nl->left, nr, op);
@ -1008,6 +1036,7 @@ cgen_as(Node *nl, Node *nr, int op)
}
/* invent a "zero" for the rhs */
iszer = 1;
nr = &nc;
memset(nr, 0, sizeof(*nr));
switch(tl->etype) {
@ -1062,6 +1091,9 @@ cgen_as(Node *nl, Node *nr, int op)
return;
cgen(nr, nl);
if(iszer && nl->addable)
gins(ANOP, nl, N); // used
ret:
;

View File

@ -383,7 +383,7 @@ gmove(Node *f, Node *t)
case TPTR32:
a = AMOVL;
if(t64)
a = AMOVLQZX; /* could probably use plain MOVL */
a = AMOVLQZX;
goto ld;
case TINT64:
if(isfloat[tt]) {
@ -480,50 +480,50 @@ gmove(Node *f, Node *t)
/*
* integer to integer
********
a = AGOK; break;
* a = AGOK; break;
case CASE(TBOOL, TBOOL):
case CASE(TINT8, TBOOL):
case CASE(TUINT8, TBOOL):
case CASE(TINT16, TBOOL):
case CASE(TUINT16, TBOOL):
case CASE(TINT32, TBOOL):
case CASE(TUINT32, TBOOL):
case CASE(TPTR64, TBOOL):
* case CASE(TBOOL, TBOOL):
* case CASE(TINT8, TBOOL):
* case CASE(TUINT8, TBOOL):
* case CASE(TINT16, TBOOL):
* case CASE(TUINT16, TBOOL):
* case CASE(TINT32, TBOOL):
* case CASE(TUINT32, TBOOL):
* case CASE(TPTR64, TBOOL):
case CASE(TBOOL, TINT8):
case CASE(TINT8, TINT8):
case CASE(TUINT8, TINT8):
case CASE(TINT16, TINT8):
case CASE(TUINT16, TINT8):
case CASE(TINT32, TINT8):
case CASE(TUINT32, TINT8):
case CASE(TPTR64, TINT8):
* case CASE(TBOOL, TINT8):
* case CASE(TINT8, TINT8):
* case CASE(TUINT8, TINT8):
* case CASE(TINT16, TINT8):
* case CASE(TUINT16, TINT8):
* case CASE(TINT32, TINT8):
* case CASE(TUINT32, TINT8):
* case CASE(TPTR64, TINT8):
case CASE(TBOOL, TUINT8):
case CASE(TINT8, TUINT8):
case CASE(TUINT8, TUINT8):
case CASE(TINT16, TUINT8):
case CASE(TUINT16, TUINT8):
case CASE(TINT32, TUINT8):
case CASE(TUINT32, TUINT8):
case CASE(TPTR64, TUINT8):
* case CASE(TBOOL, TUINT8):
* case CASE(TINT8, TUINT8):
* case CASE(TUINT8, TUINT8):
* case CASE(TINT16, TUINT8):
* case CASE(TUINT16, TUINT8):
* case CASE(TINT32, TUINT8):
* case CASE(TUINT32, TUINT8):
* case CASE(TPTR64, TUINT8):
case CASE(TINT16, TINT16):
case CASE(TUINT16, TINT16):
case CASE(TINT32, TINT16):
case CASE(TUINT32, TINT16):
case CASE(TPTR64, TINT16):
* case CASE(TINT16, TINT16):
* case CASE(TUINT16, TINT16):
* case CASE(TINT32, TINT16):
* case CASE(TUINT32, TINT16):
* case CASE(TPTR64, TINT16):
case CASE(TINT16, TUINT16):
case CASE(TUINT16, TUINT16):
case CASE(TINT32, TUINT16):
case CASE(TUINT32, TUINT16):
case CASE(TPTR64, TUINT16):
* case CASE(TINT16, TUINT16):
* case CASE(TUINT16, TUINT16):
* case CASE(TINT32, TUINT16):
* case CASE(TUINT32, TUINT16):
* case CASE(TPTR64, TUINT16):
case CASE(TINT64, TUINT):
case CASE(TINT64, TUINT32):
case CASE(TUINT64, TUINT32):
* case CASE(TINT64, TUINT):
* case CASE(TINT64, TUINT32):
* case CASE(TUINT64, TUINT32):
*****/
a = AMOVL;
break;
@ -534,25 +534,21 @@ gmove(Node *f, Node *t)
case CASE(TUINT64, TINT8):
case CASE(TUINT64, TINT16):
case CASE(TUINT64, TINT32):
a = AMOVLQSX; // this looks bad
break;
case CASE(TINT32, TINT64):
case CASE(TINT32, TPTR64):
a = AMOVLQSX;
// if(f->op == OCONST) {
// f->val.vval &= (uvlong)0xffffffffU;
// if(f->val.vval & 0x80000000)
// f->val.vval |= (vlong)0xffffffff << 32;
// a = AMOVQ;
// }
break;
case CASE(TUINT32, TINT64):
case CASE(TUINT32, TUINT64):
case CASE(TUINT32, TPTR64):
a = AMOVL; /* same effect as AMOVLQZX */
// if(f->op == OCONST) {
// f->val.vval &= (uvlong)0xffffffffU;
// a = AMOVQ;
// }
case CASE(TPTR32, TINT64):
case CASE(TPTR32, TUINT64):
case CASE(TPTR32, TPTR64):
a = AMOVLQZX;
break;
case CASE(TPTR64, TINT64):
@ -1239,6 +1235,50 @@ optoas(int op, Type *t)
a = ASUBSD;
break;
case CASE(OINC, TINT8):
case CASE(OINC, TUINT8):
a = AINCB;
break;
case CASE(OINC, TINT16):
case CASE(OINC, TUINT16):
a = AINCW;
break;
case CASE(OINC, TINT32):
case CASE(OINC, TUINT32):
case CASE(OINC, TPTR32):
a = AINCL;
break;
case CASE(OINC, TINT64):
case CASE(OINC, TUINT64):
case CASE(OINC, TPTR64):
a = AINCQ;
break;
case CASE(ODEC, TINT8):
case CASE(ODEC, TUINT8):
a = ADECB;
break;
case CASE(ODEC, TINT16):
case CASE(ODEC, TUINT16):
a = ADECW;
break;
case CASE(ODEC, TINT32):
case CASE(ODEC, TUINT32):
case CASE(ODEC, TPTR32):
a = ADECL;
break;
case CASE(ODEC, TINT64):
case CASE(ODEC, TUINT64):
case CASE(ODEC, TPTR64):
a = ADECQ;
break;
case CASE(OMINUS, TINT8):
case CASE(OMINUS, TUINT8):
a = ANEGB;

View File

@ -60,7 +60,6 @@ struct Bits
uint32 b[BITS];
};
struct Reg
{
@ -75,14 +74,12 @@ struct Reg
Bits regdiff;
Bits act;
int32 regu;
int32 loop; /* could be shorter */
int32 rpo; /* reverse post ordering */
int32 regu; // register used bitmap
int32 rpo; // reverse post ordering
int32 active;
// uint32 magic;
// int32 pc;
// Reg* log5;
uint16 loop; // x5 for every loop
uchar refset; // diagnostic generated
Reg* p1;
Reg* p2;
@ -130,10 +127,9 @@ EXTERN Bits externs;
EXTERN Bits params;
EXTERN Bits consts;
EXTERN Bits addrs;
EXTERN Bits ovar;
EXTERN int change;
EXTERN Bits zbits;
EXTERN uchar typechlpfd[NTYPE]; // botch
EXTERN uchar typev[NTYPE]; // botch
EXTERN int32 maxnr;
EXTERN int32* idom;
@ -150,6 +146,15 @@ int beq(Bits, Bits);
int bset(Bits, uint);
int Qconv(Fmt *fp);
int bitno(int32);
struct
{
int32 ncvtreg;
int32 nspill;
int32 nreload;
int32 ndelmov;
int32 nvar;
int32 naddr;
} ostats;
/*
* reg.c
@ -167,6 +172,8 @@ void paint1(Reg*, int);
uint32 paint2(Reg*, int);
void paint3(Reg*, int, int32, int);
void addreg(Adr*, int);
void dumpit(char *str, Reg *r0);
int noreturn(Prog *p);
/*
* peep.c

View File

@ -31,6 +31,7 @@
#include "gg.h"
#include "opt.h"
static int
needc(Prog *p)
{
@ -67,7 +68,7 @@ rnops(Reg *r)
Reg *r1;
if(r != R)
for(;;){
for(;;) {
p = r->prog;
if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
break;
@ -103,6 +104,8 @@ peep(void)
r2->link = r1;
r2->prog = p;
p->reg = r2;
r2->p1 = r;
r->s1 = r2;
r2->s1 = r1;
@ -119,10 +122,11 @@ peep(void)
}
}
pc = 0; /* speculating it won't kill */
loop1:
if(debug['P'] && debug['v'])
dumpit("loop1", firstr);
t = 0;
for(r=firstr; r!=R; r=r->link) {
p = r->prog;
@ -186,13 +190,15 @@ loop1:
if(p->from.offset == -1){
if(p->as == AADDQ)
p->as = ADECQ;
else if(p->as == AADDL)
else
if(p->as == AADDL)
p->as = ADECL;
else
p->as = ADECW;
p->from = zprog.from;
}
else if(p->from.offset == 1){
else
if(p->from.offset == 1){
if(p->as == AADDQ)
p->as = AINCQ;
else if(p->as == AADDL)
@ -211,16 +217,19 @@ loop1:
if(p->from.offset == -1) {
if(p->as == ASUBQ)
p->as = AINCQ;
else if(p->as == ASUBL)
else
if(p->as == ASUBL)
p->as = AINCL;
else
p->as = AINCW;
p->from = zprog.from;
}
else if(p->from.offset == 1){
else
if(p->from.offset == 1){
if(p->as == ASUBQ)
p->as = ADECQ;
else if(p->as == ASUBL)
else
if(p->as == ASUBL)
p->as = ADECL;
else
p->as = ADECW;
@ -239,9 +248,14 @@ excise(Reg *r)
Prog *p;
p = r->prog;
if(debug['P'] && debug['v'])
print("%P ===delete===\n", p);
p->as = ANOP;
p->from = zprog.from;
p->to = zprog.to;
ostats.ndelmov++;
}
Reg*

View File

@ -34,11 +34,8 @@
#include "opt.h"
#define P2R(p) (Reg*)(p->reg)
#define MAGIC 0xb00fbabe
static int first = 1;
static void dumpit(char *str, Reg *r0);
static int noreturn(Prog *p);
Reg*
rega(void)
@ -70,6 +67,30 @@ rcmp(const void *a1, const void *a2)
return p2->varno - p1->varno;
}
void
setoutvar(void)
{
Type *t;
Node *n;
Addr a;
Iter save;
Bits bit;
int z;
t = structfirst(&save, getoutarg(curfn->type));
while(t != T) {
n = nodarg(t, 1);
a = zprog.from;
naddr(n, &a);
bit = mkvar(R, &a);
for(z=0; z<BITS; z++)
ovar.b[z] |= bit.b[z];
t = structnext(&save);
}
//if(bany(b))
//print("ovars = %Q\n", &ovar);
}
void
regopt(Prog *firstp)
{
@ -93,8 +114,12 @@ regopt(Prog *firstp)
params.b[z] = 0;
consts.b[z] = 0;
addrs.b[z] = 0;
ovar.b[z] = 0;
}
// build list of return variables
setoutvar();
/*
* pass 1
* build aux data structure
@ -221,6 +246,15 @@ regopt(Prog *firstp)
/*
* right side read+write
*/
case AINCB:
case AINCL:
case AINCQ:
case AINCW:
case ADECB:
case ADECL:
case ADECQ:
case ADECW:
case AADDB:
case AADDL:
case AADDQ:
@ -380,7 +414,9 @@ regopt(Prog *firstp)
}
if(firstr == R)
return;
//dumpit("pass1", firstr);
if(debug['R'] && debug['v'])
dumpit("pass1", firstr);
/*
* pass 2
@ -396,7 +432,7 @@ regopt(Prog *firstp)
if(r1 == R)
fatal("rnil %P", p);
if(r1 == r) {
fatal("ref to self %P", p);
//fatal("ref to self %P", p);
continue;
}
r->s2 = r1;
@ -404,7 +440,9 @@ regopt(Prog *firstp)
r1->p2 = r;
}
}
//dumpit("pass2", firstr);
if(debug['R'] && debug['v'])
dumpit("pass2", firstr);
/*
* pass 2.5
@ -414,7 +452,9 @@ regopt(Prog *firstp)
r->active = 0;
change = 0;
loopit(firstr, nr);
//dumpit("pass2.5", firstr);
if(debug['R'] && debug['v'])
dumpit("pass2.5", firstr);
/*
* pass 3
@ -443,7 +483,8 @@ loop11:
if(change)
goto loop1;
//dumpit("pass3", firstr);
if(debug['R'] && debug['v'])
dumpit("pass3", firstr);
/*
* pass 4
@ -458,7 +499,8 @@ loop2:
if(change)
goto loop2;
//dumpit("pass4", firstr);
if(debug['R'] && debug['v'])
dumpit("pass4", firstr);
/*
* pass 5
@ -470,10 +512,11 @@ loop2:
for(z=0; z<BITS; z++)
bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
if(bany(&bit)) {
warn("used and not set: %Q", bit);
if(debug['R'] && !debug['w'])
print("used and not set: %Q\n", bit);
if(bany(&bit) && !r->refset) {
// should never happen - all variables are preset
if(debug['w'])
print("%L: used and not set: %Q\n", r->prog->lineno, bit);
r->refset = 1;
}
}
for(r = firstr; r != R; r = r->link)
@ -484,10 +527,10 @@ loop2:
for(z=0; z<BITS; z++)
bit.b[z] = r->set.b[z] &
~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
if(bany(&bit)) {
warn("set and not used: %Q", bit);
if(debug['R'])
print("set and not used: %Q\n", bit);
if(bany(&bit) && !r->refset) {
if(debug['w'])
print("%L: set and not used: %Q\n", r->prog->lineno, bit);
r->refset = 1;
excise(r);
}
for(z=0; z<BITS; z++)
@ -497,20 +540,15 @@ loop2:
rgp->enter = r;
rgp->varno = i;
change = 0;
if(debug['R'] && debug['v'])
print("\n");
paint1(r, i);
bit.b[i/32] &= ~(1L<<(i%32));
if(change <= 0) {
if(debug['R'])
print("%L$%d: %Q\n",
r->prog->lineno, change, blsh(i));
if(change <= 0)
continue;
}
rgp->cost = change;
nregion++;
if(nregion >= NRGN) {
fatal("too many regions");
if(debug['R'] && debug['v'])
print("too many regions\n");
goto brk;
}
rgp++;
@ -534,11 +572,14 @@ brk:
rgp++;
}
if(debug['R'] && debug['v'])
dumpit("pass6", firstr);
/*
* pass 7
* peep-hole on basic block
*/
if(debug['P']) {
if(!debug['R'] || debug['P']) {
peep();
}
@ -547,14 +588,43 @@ brk:
* free aux structures
*/
for(p=firstp; p!=P; p=p->link) {
while(p->link && p->link->as == ANOP)
while(p->link != P && p->link->as == ANOP)
p->link = p->link->link;
if(p->to.type == D_BRANCH)
while(p->to.branch != P && p->to.branch->as == ANOP)
p->to.branch = p->to.branch->link;
}
if(r1 != R) {
r1->link = freer;
freer = firstr;
}
if(debug['R']) {
if(ostats.ncvtreg ||
ostats.nspill ||
ostats.nreload ||
ostats.ndelmov ||
ostats.nvar ||
ostats.naddr ||
0)
print("\nstats\n");
if(ostats.ncvtreg)
print(" %4ld cvtreg\n", ostats.ncvtreg);
if(ostats.nspill)
print(" %4ld spill\n", ostats.nspill);
if(ostats.nreload)
print(" %4ld reload\n", ostats.nreload);
if(ostats.ndelmov)
print(" %4ld delmov\n", ostats.ndelmov);
if(ostats.nvar)
print(" %4ld delmov\n", ostats.nvar);
if(ostats.naddr)
print(" %4ld delmov\n", ostats.naddr);
memset(&ostats, 0, sizeof(ostats));
}
}
/*
@ -585,7 +655,7 @@ addmove(Reg *r, int bn, int rn, int f)
a->etype = v->etype;
a->type = v->name;
// need to chean this up with wptr and
// need to clean this up with wptr and
// some of the defaults
p1->as = AMOVL;
switch(v->etype) {
@ -611,7 +681,7 @@ addmove(Reg *r, int bn, int rn, int f)
p1->as = AMOVSS;
break;
case TFLOAT64:
p1->as = AMOVSS;
p1->as = AMOVSD;
break;
case TINT:
case TUINT:
@ -631,8 +701,9 @@ addmove(Reg *r, int bn, int rn, int f)
if(v->etype == TUINT16)
p1->as = AMOVW;
}
// if(debug['R'])
print("%P\t.a%P\n", p, p1);
if(debug['R'] && debug['v'])
print("%P ===add=== %P\n", p, p1);
ostats.nspill++;
}
uint32
@ -670,8 +741,10 @@ mkvar(Reg *r, Adr *a)
* mark registers used
*/
t = a->type;
r->regu |= doregbits(t);
r->regu |= doregbits(a->index);
if(r != R) {
r->regu |= doregbits(t);
r->regu |= doregbits(a->index);
}
switch(t) {
default:
@ -682,6 +755,7 @@ mkvar(Reg *r, Adr *a)
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
a->type = t;
ostats.naddr++;
goto none;
case D_EXTERN:
case D_STATIC:
@ -727,6 +801,7 @@ mkvar(Reg *r, Adr *a)
v->etype = et;
if(debug['R'])
print("bit=%2d et=%2d %D\n", i, et, a);
ostats.nvar++;
out:
bit = blsh(i);
@ -738,7 +813,8 @@ out:
params.b[z] |= bit.b[z];
if(v->etype != et) {
/* funny punning */
print("pun %d %d %S\n", v->etype, et, s);
if(debug['R'])
print("pun %d %d %S\n", v->etype, et, s);
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
}
@ -787,9 +863,10 @@ prop(Reg *r, Bits ref, Bits cal)
case ARET:
for(z=0; z<BITS; z++) {
cal.b[z] = externs.b[z];
cal.b[z] = externs.b[z] | ovar.b[z];
ref.b[z] = 0;
}
break;
}
for(z=0; z<BITS; z++) {
ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
@ -1044,9 +1121,6 @@ paint1(Reg *r, int bn)
if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
print("%ld%P\tld %Q $%d\n", r->loop,
r->prog, blsh(bn), change);
}
for(;;) {
r->act.b[z] |= bb;
@ -1054,23 +1128,14 @@ paint1(Reg *r, int bn)
if(r->use1.b[z] & bb) {
change += CREF * r->loop;
if(debug['R'] && debug['v'])
print("%ld%P\tu1 %Q $%d\n", r->loop,
p, blsh(bn), change);
}
if((r->use2.b[z]|r->set.b[z]) & bb) {
change += CREF * r->loop;
if(debug['R'] && debug['v'])
print("%ld%P\tu2 %Q $%d\n", r->loop,
p, blsh(bn), change);
}
if(STORE(r) & r->regdiff.b[z] & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
print("%ld%P\tst %Q $%d\n", r->loop,
p, blsh(bn), change);
}
if(r->refbehind.b[z] & bb)
@ -1226,18 +1291,18 @@ paint3(Reg *r, int bn, int32 rb, int rn)
p = r->prog;
if(r->use1.b[z] & bb) {
if(debug['R'])
if(debug['R'] && debug['v'])
print("%P", p);
addreg(&p->from, rn);
if(debug['R'])
print("\t.c%P\n", p);
if(debug['R'] && debug['v'])
print(" ===change== %P\n", p);
}
if((r->use2.b[z]|r->set.b[z]) & bb) {
if(debug['R'])
if(debug['R'] && debug['v'])
print("%P", p);
addreg(&p->to, rn);
if(debug['R'])
print("\t.c%P\n", p);
if(debug['R'] && debug['v'])
print(" ===change== %P\n", p);
}
if(STORE(r) & r->regdiff.b[z] & bb)
@ -1272,6 +1337,8 @@ addreg(Adr *a, int rn)
a->sym = 0;
a->offset = 0;
a->type = rn;
ostats.ncvtreg++;
}
int32
@ -1286,8 +1353,7 @@ RtoB(int r)
int
BtoR(int32 b)
{
b &= 0xffffL;
b &= 0x3fffL; // no R14 or R15
if(b == 0)
return 0;
return bitno(b) + D_AX;
@ -1317,7 +1383,7 @@ BtoF(int32 b)
return bitno(b) - 16 + FREGMIN;
}
static void
void
dumpit(char *str, Reg *r0)
{
Reg *r, *r1;
@ -1380,7 +1446,7 @@ dumpit(char *str, Reg *r0)
static Sym* symlist[10];
static int
int
noreturn(Prog *p)
{
Sym *s;
@ -1388,6 +1454,7 @@ noreturn(Prog *p)
if(symlist[0] == S) {
symlist[0] = pkglookup("throwindex", "sys");
symlist[1] = pkglookup("panicl", "sys");
}
s = p->to.sym;

View File

@ -284,6 +284,7 @@ enum
OEQ, ONE, OLT, OLE, OGE, OGT,
OADD, OSUB, OOR, OXOR,
OMUL, ODIV, OMOD, OLSH, ORSH, OAND,
OINC, ODEC, // placeholders - not used
OFUNC,
OLABEL,
OBREAK,

View File

@ -1094,7 +1094,20 @@ loop:
goto ret;
nottop:
yyerror("didn't expect %O here", n->op);
switch(top) {
default:
yyerror("didn't expect %O here", n->op);
break;
case Etop:
yyerror("operation %O not allowed in statement context", n->op);
break;
case Elv:
yyerror("operation %O not allowed in assignment context", n->op);
break;
case Erv:
yyerror("operation %O not allowed in expression context", n->op);
break;
}
goto ret;
badt: