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;
}
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);
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);
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);
}
/* invent a "zero" for the rhs */
+ iszer = 1;
nr = &nc;
memset(nr, 0, sizeof(*nr));
switch(tl->etype) {
return;
cgen(nr, nl);
+ if(iszer && nl->addable)
+ gins(ANOP, nl, N); // used
+
ret:
;
case TPTR32:
a = AMOVL;
if(t64)
- a = AMOVLQZX; /* could probably use plain MOVL */
+ a = AMOVLQZX;
goto ld;
case TINT64:
if(isfloat[tt]) {
/*
* integer to integer
********
- 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, 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(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(TINT64, TUINT):
- case CASE(TINT64, TUINT32):
- case CASE(TUINT64, TUINT32):
+ * 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, 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(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(TINT64, TUINT):
+ * case CASE(TINT64, TUINT32):
+ * case CASE(TUINT64, TUINT32):
*****/
a = AMOVL;
break;
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):
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;
uint32 b[BITS];
};
-
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;
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;
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
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
#include "gg.h"
#include "opt.h"
+
static int
needc(Prog *p)
{
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;
r2->link = r1;
r2->prog = p;
+ p->reg = r2;
+
r2->p1 = r;
r->s1 = r2;
r2->s1 = r1;
}
}
- 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;
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)
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;
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*
#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)
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)
{
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
/*
* 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:
}
if(firstr == R)
return;
-//dumpit("pass1", firstr);
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass1", firstr);
/*
* pass 2
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;
r1->p2 = r;
}
}
-//dumpit("pass2", firstr);
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass2", firstr);
/*
* pass 2.5
r->active = 0;
change = 0;
loopit(firstr, nr);
-//dumpit("pass2.5", firstr);
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass2.5", firstr);
/*
* pass 3
if(change)
goto loop1;
-//dumpit("pass3", firstr);
+ if(debug['R'] && debug['v'])
+ dumpit("pass3", firstr);
/*
* pass 4
if(change)
goto loop2;
-//dumpit("pass4", firstr);
+ if(debug['R'] && debug['v'])
+ dumpit("pass4", firstr);
/*
* pass 5
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)
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++)
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++;
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();
}
* 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));
+ }
}
/*
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) {
p1->as = AMOVSS;
break;
case TFLOAT64:
- p1->as = AMOVSS;
+ p1->as = AMOVSD;
break;
case TINT:
case TUINT:
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
* 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:
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:
v->etype = et;
if(debug['R'])
print("bit=%2d et=%2d %D\n", i, et, a);
+ ostats.nvar++;
out:
bit = blsh(i);
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];
}
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]) |
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;
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)
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)
a->sym = 0;
a->offset = 0;
a->type = rn;
+
+ ostats.ncvtreg++;
}
int32
int
BtoR(int32 b)
{
-
- b &= 0xffffL;
+ b &= 0x3fffL; // no R14 or R15
if(b == 0)
return 0;
return bitno(b) + D_AX;
return bitno(b) - 16 + FREGMIN;
}
-static void
+void
dumpit(char *str, Reg *r0)
{
Reg *r, *r1;
static Sym* symlist[10];
-static int
+int
noreturn(Prog *p)
{
Sym *s;
if(symlist[0] == S) {
symlist[0] = pkglookup("throwindex", "sys");
+ symlist[1] = pkglookup("panicl", "sys");
}
s = p->to.sym;
OEQ, ONE, OLT, OLE, OGE, OGT,
OADD, OSUB, OOR, OXOR,
OMUL, ODIV, OMOD, OLSH, ORSH, OAND,
+ OINC, ODEC, // placeholders - not used
OFUNC,
OLABEL,
OBREAK,
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: