r = REGRET;
if(typefd[nn->type->etype])
r = FREGRET+NREG;
nodreg(n, nn, r);
reg[r]++;
}
void
regalloc(Node *n, Node *tn, Node *o)
{
int i, j;
static int lasti;
switch(tn->type->etype) {
case TCHAR:
case TUCHAR:
case TSHORT:
case TUSHORT:
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
if(o != Z && o->op == OREGISTER) {
i = o->reg;
if(i > 0 && i < NREG)
goto out;
}
j = lasti + REGRET+1;
for(i=REGRET+1; i<NREG; i++) {
if(j >= NREG)
j = REGRET+1;
if(reg[j] == 0) {
i = j;
goto out;
}
j++;
}
diag(tn, "out of fixed registers");
goto err;
case TFLOAT:
case TDOUBLE:
case TVLONG:
if(o != Z && o->op == OREGISTER) {
i = o->reg;
if(i >= NREG && i < NREG+NREG)
goto out;
}
j = lasti*2 + NREG;
for(i=NREG; i<NREG+NREG; i+=2) {
if(j >= NREG+NREG)
j = NREG;
if(reg[j] == 0) {
i = j;
goto out;
}
j += 2;
}
diag(tn, "out of float registers");
goto err;
}
diag(tn, "unknown type in regalloc: %T", tn->type);
err:
i = 0;
out:
if(i)
reg[i]++;
lasti++;
if(lasti >= 5)
lasti = 0;
nodreg(n, tn, i);
}
if(ft == TDOUBLE && f->op == OCONST) {
d = f->fconst;
if(d == 0.0) {
a = FREGZERO;
goto ffreg;
}
if(d == 0.5) {
a = FREGHALF;
goto ffreg;
}
if(d == 1.0) {
a = FREGONE;
goto ffreg;
}
if(d == 2.0) {
a = FREGTWO;
goto ffreg;
}
if(d == -.5) {
fop(OSUB, FREGHALF, FREGZERO, t);
return;
}
if(d == -1.0) {
fop(OSUB, FREGONE, FREGZERO, t);
return;
}
if(d == -2.0) {
fop(OSUB, FREGTWO, FREGZERO, t);
return;
}
if(d == 1.5) {
fop(OADD, FREGONE, FREGHALF, t);
return;
}
if(d == 2.5) {
fop(OADD, FREGTWO, FREGHALF, t);
return;
}
if(d == 3.0) {
fop(OADD, FREGTWO, FREGONE, t);
return;
}
}
if(ft == TFLOAT && f->op == OCONST) {
d = f->fconst;
if(d == 0) {
a = FREGZERO;
ffreg:
nodreg(&nod, f, NREG+a);
gmove(&nod, t);
return;
}
}
/*
* a load --
* put it into a register then
* worry what to do with it.
*/
if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
switch(ft) {
default:
if(typefd[tt]) {
/* special case can load mem to Freg */
regalloc(&nod, t, t);
gins(AMOVW, f, &nod);
a = AFMOVWD;
if(tt == TFLOAT)
a = AFMOVWF;
gins(a, &nod, &nod);
gmove(&nod, t);
regfree(&nod);
return;
}
a = AMOVW;
break;
case TFLOAT:
a = AFMOVF;
break;
case TDOUBLE:
a = AFMOVD;
break;
case TCHAR:
a = AMOVB;
break;
case TUCHAR:
a = AMOVBU;
break;
case TSHORT:
a = AMOVH;
break;
case TUSHORT:
a = AMOVHU;
break;
}
regalloc(&nod, f, t);
gins(a, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
}
/*
* a store --
* put it into a register then
* store it.
*/
if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
switch(tt) {
default:
if(typefd[ft]) {
/* special case can store mem from Freg */
regalloc(&nod, f, Z);
a = AFMOVDW;
if(ft == TFLOAT)
a = AFMOVFW;
gins(a, f, &nod);
gins(AMOVW, &nod, t);
regfree(&nod);
return;
}
a = AMOVW;
break;
case TUCHAR:
a = AMOVBU;
break;
case TCHAR:
a = AMOVB;
break;
case TUSHORT:
a = AMOVHU;
break;
case TSHORT:
a = AMOVH;
break;
case TFLOAT:
a = AFMOVF;
break;
case TVLONG:
case TDOUBLE:
a = AFMOVD;
break;
}
if(!typefd[ft] && vconst(f) == 0) {
gins(a, f, t);
return;
}
if(ft == tt)
regalloc(&nod, t, f);
else
regalloc(&nod, t, Z);
gmove(f, &nod);
gins(a, &nod, t);
regfree(&nod);
return;
}
/*
* type x type cross table
*/
a = AGOK;
switch(ft) {
case TDOUBLE:
case TVLONG:
case TFLOAT:
switch(tt) {
case TDOUBLE:
case TVLONG:
a = AFMOVD;
if(ft == TFLOAT)
a = AFMOVFD;
break;
case TFLOAT:
a = AFMOVDF;
if(ft == TFLOAT)
a = AFMOVF;
break;
case TLONG:
case TULONG:
case TIND:
case TINT:
case TUINT:
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
regalloc(&nod, f, Z); /* should be type float */
a = AFMOVDW;
if(ft == TFLOAT)
a = AFMOVFW;
gins(a, f, &nod);
gins(AFMOVF, &nod, nodrat);
regfree(&nod);
gins(AMOVW, nodrat, t);
gmove(t, t);
if(nrathole < SZ_LONG)
nrathole = SZ_LONG;
return;
}
break;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
switch(tt) {
case TDOUBLE:
case TVLONG:
case TFLOAT:
goto fxtofl;
case TLONG:
case TULONG:
case TINT:
case TUINT:
case TIND:
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
case TSHORT:
switch(tt) {
case TDOUBLE:
case TVLONG:
case TFLOAT:
goto fxtofl;
case TUINT:
case TINT:
case TULONG:
case TLONG:
case TIND:
a = AMOVH;
break;
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
case TUSHORT:
switch(tt) {
case TDOUBLE:
case TVLONG:
case TFLOAT:
goto fxtofl;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
a = AMOVHU;
break;
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
case TCHAR:
switch(tt) {
case TDOUBLE:
case TVLONG:
case TFLOAT:
goto fxtofl;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
case TSHORT:
case TUSHORT:
a = AMOVB;
break;
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
case TUCHAR:
switch(tt) {
case TDOUBLE:
case TVLONG:
case TFLOAT:
fxtofl:
regalloc(&nod, t, t); /* should be type float */
gins(AMOVW, f, nodrat);
gins(AFMOVF, nodrat, &nod);
a = AFMOVWD;
if(tt == TFLOAT)
a = AFMOVWF;
gins(a, &nod, t);
regfree(&nod);
if(nrathole < SZ_LONG)
nrathole = SZ_LONG;
if(ft == TULONG) {
regalloc(&nod, t, Z);
if(tt == TFLOAT) {
gins(AFCMPF, t, Z);
p->to.type = D_FREG;
p->to.reg = FREGZERO;
gins(AFBGE, Z, Z);
p1 = p;
gins(AFMOVF, nodfconst(4294967296.), &nod);
gins(AFADDF, &nod, t);
} else {
gins(AFCMPD, t, Z);
p->to.type = D_FREG;
p->to.reg = FREGZERO;
gins(AFBGE, Z, Z);
p1 = p;
gins(AFMOVD, nodfconst(4294967296.), &nod);
gins(AFADDD, &nod, t);
}
patch(p1, pc);
regfree(&nod);
}
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
case TSHORT:
case TUSHORT:
a = AMOVBU;
break;
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
}
if(a == AGOK)
diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
if(a == AMOVW || a == AFMOVF || a == AFMOVD)
if(samaddr(f, t))
return;
gins(a, f, t);
}
void
gopcode(int o, Node *f1, Node *f2, Node *t)
{
int a, et;
Adr ta;
et = TLONG;
if(f1 != Z && f1->type != T)
et = f1->type->etype;
a = AGOK;
switch(o) {
case OAS:
gmove(f1, t);
return;
case OASADD:
case OADD:
a = AADD;
if(et == TFLOAT)
a = AFADDF;
else
if(et == TDOUBLE || et == TVLONG)
a = AFADDD;
break;
case OASSUB:
case OSUB:
a = ASUB;
if(et == TFLOAT)
a = AFSUBF;
else
if(et == TDOUBLE || et == TVLONG)
a = AFSUBD;
break;
case OASOR:
case OOR:
a = AOR;
break;
case OASAND:
case OAND:
a = AAND;
break;
case OASXOR:
case OXOR:
a = AXOR;
break;
case OASLSHR:
case OLSHR:
a = ASRL;
break;
case OASASHR:
case OASHR:
a = ASRA;
break;
case OASASHL:
case OASHL:
a = ASLL;
break;
case OFUNC:
a = AJMPL;
break;
case OASLMUL:
case OLMUL:
case OASMUL:
case OMUL:
if(et == TFLOAT) {
a = AFMULF;
break;
} else
if(et == TDOUBLE || et == TVLONG) {
a = AFMULD;
break;
}
a = AMUL;
break;
case OASDIV:
case ODIV:
if(et == TFLOAT) {
a = AFDIVF;
break;
} else
if(et == TDOUBLE || et == TVLONG) {
a = AFDIVD;
break;
}
a = ADIV;
break;
case OASMOD:
case OMOD:
a = AMOD;
break;
case OASLMOD:
case OLMOD:
a = AMODL;
break;
case OASLDIV:
case OLDIV:
a = ADIVL;
break;
case OEQ:
a = ABE;
if(typefd[et])
a = AFBE;
goto cmp;
case ONE:
a = ABNE;
if(typefd[et])
a = AFBLG;
goto cmp;
case OLT:
a = ABL;
if(typefd[et])
a = AFBL;
goto cmp;
case OLE:
a = ABLE;
if(typefd[et])
a = AFBLE;
goto cmp;
case OGE:
a = ABGE;
if(typefd[et])
a = AFBGE;
goto cmp;
case OGT:
a = ABG;
if(typefd[et])
a = AFBG;
goto cmp;