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 TVLONG:
case TUVLONG:
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 && resvreg[j] == 0) {
i = j;
goto out;
}
j++;
}
diag(tn, "out of fixed registers");
goto err;
case TFLOAT:
case TDOUBLE:
if(o != Z && o->op == OREGISTER) {
i = o->reg;
if(i >= NREG && i < NREG+NFREG)
goto out;
}
j = lasti + NREG;
for(i=NREG; i<NREG+NFREG; i++) {
if(j >= NREG+NFREG)
j = NREG;
if(reg[j] == 0) {
i = j;
goto out;
}
j++;
}
diag(tn, "out of float registers");
goto err;
}
diag(tn, "unknown type in regalloc: %T", tn->type);
err:
nodreg(n, tn, 0);
return;
out:
reg[i]++;
lasti++;
if(lasti >= 5)
lasti = 0;
nodreg(n, tn, i);
}
/*
* 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(ewidth[ft] == 4){
if(typeu[ft])
a = AMOVWU;
else
a = AMOVW;
}else
a = AMOV;
break;
case TINT:
a = AMOVW;
break;
case TUINT:
a = AMOVWU;
break;
case TFLOAT:
a = AFMOVS;
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(ewidth[tt] == 4)
a = AMOVW;
else
a = AMOV;
break;
case TINT:
a = AMOVW;
break;
case TUINT:
a = AMOVWU;
break;
case TUCHAR:
a = AMOVBU;
break;
case TCHAR:
a = AMOVB;
break;
case TUSHORT:
a = AMOVHU;
break;
case TSHORT:
a = AMOVH;
break;
case TFLOAT:
a = AFMOVS;
break;
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 TFLOAT:
switch(tt) {
case TDOUBLE:
a = AFMOVD;
if(ft == TFLOAT)
a = AFCVTSD;
break;
case TFLOAT:
a = AFMOVS;
if(ft == TDOUBLE)
a = AFCVTDS;
break;
case TCHAR:
case TSHORT:
case TINT:
case TLONG:
a = AFCVTZSDW;
if(ft == TFLOAT)
a = AFCVTZSSW;
break;
case TUCHAR:
case TUSHORT:
case TUINT:
case TULONG:
a = AFCVTZUDW;
if(ft == TFLOAT)
a = AFCVTZUSW;
break;
case TVLONG:
a = AFCVTZSD;
if(ft == TFLOAT)
a = AFCVTZSS;
break;
case TUVLONG:
case TIND:
a = AFCVTZUD;
if(ft == TFLOAT)
a = AFCVTZUS;
break;
}
break;
case TUINT:
case TULONG:
case TINT:
case TLONG:
switch(tt) {
case TDOUBLE:
if(ft == TUINT || ft == TULONG)
gins(AUCVTFWD, f, t);
else
gins(ASCVTFWD, f, t);
return;
case TFLOAT:
if(ft == TUINT || ft == TULONG)
gins(AUCVTFWS, f, t);
else
gins(ASCVTFWS, f, t);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
if(typeu[tt])
a = AMOVWU;
else
a = AMOVW;
break;
case TVLONG:
case TUVLONG:
case TIND:
if(typeu[ft])
a = AMOVWU;
else
a = (f->op == OREGISTER) ? ASXTW : AMOVW;
break;
}
break;
case TVLONG:
case TUVLONG:
case TIND:
switch(tt) {
case TDOUBLE:
if(ft == TVLONG)
gins(ASCVTFD, f, t);
else
gins(AUCVTFD, f, t);
return;
case TFLOAT:
if(ft == TVLONG)
gins(ASCVTFS, f, t);
else
gins(AUCVTFS, f, t);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOVWU;
break;
case TVLONG:
case TUVLONG:
case TIND:
a = AMOV;
break;
}
break;
case TSHORT:
switch(tt) {
case TDOUBLE:
regalloc(&nod, f, Z);
gins(AMOVH, f, &nod);
gins(ASCVTFWD, &nod, t);
regfree(&nod);
return;
case TFLOAT:
regalloc(&nod, f, Z);
gins(AMOVH, f, &nod);
gins(ASCVTFWS, &nod, t);
regfree(&nod);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TVLONG:
case TUVLONG:
case TIND:
a = AMOVH;
break;
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOV;
break;
}
break;
case TUSHORT:
switch(tt) {
case TDOUBLE:
regalloc(&nod, f, Z);
gins(AMOVHU, f, &nod);
gins(AUCVTFWD, &nod, t);
regfree(&nod);
return;
case TFLOAT:
regalloc(&nod, f, Z);
gins(AMOVHU, f, &nod);
gins(AUCVTFWS, &nod, t);
regfree(&nod);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TVLONG:
case TUVLONG:
case TIND:
a = AMOVHU;
break;
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOV;
break;
}
break;
case TCHAR:
switch(tt) {
case TDOUBLE:
regalloc(&nod, f, Z);
gins(AMOVB, f, &nod);
gins(ASCVTFWD, &nod, t);
regfree(&nod);
return;
case TFLOAT:
regalloc(&nod, f, Z);
gins(AMOVB, f, &nod);
gins(ASCVTFWS, &nod, t);
regfree(&nod);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
case TSHORT:
case TUSHORT:
case TVLONG:
case TUVLONG:
a = AMOVB;
break;
case TCHAR:
case TUCHAR:
a = AMOV;
break;
}
break;
case TUCHAR:
switch(tt) {
case TDOUBLE:
regalloc(&nod, f, Z);
gins(AMOVBU, f, &nod);
gins(AUCVTFWD, &nod, t);
regfree(&nod);
return;
case TFLOAT:
regalloc(&nod, f, Z);
gins(AMOVBU, f, &nod);
gins(AUCVTFWS, &nod, t);
regfree(&nod);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
case TSHORT:
case TUSHORT:
case TVLONG:
case TUVLONG:
a = AMOVBU;
break;
case TCHAR:
case TUCHAR:
a = AMOV;
break;
}
break;
}
if(a == AGOK)
diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
if(a == AMOV || (a == AMOVW || a == AMOVWU) && ewidth[ft] == ewidth[tt] || a == AFMOVS || a == AFMOVD)
if(samaddr(f, t))
return;
gins(a, f, t);
}
void
gmover(Node *f, Node *t)
{
int ft, tt, a;
ft = f->type->etype;
tt = t->type->etype;
a = AGOK;
if(typechlp[ft] && typechlp[tt] && ewidth[ft] >= ewidth[tt]){
switch(tt){
case TSHORT:
a = AMOVH;
break;
case TUSHORT:
a = AMOVHU;
break;
case TCHAR:
a = AMOVB;
break;
case TUCHAR:
a = AMOVBU;
break;
case TINT:
a = AMOVW;
break;
case TUINT:
a = AMOVWU;
break;
}
}
if(a == AGOK)
gmove(f, t);
else
gins(a, f, t);
}
if(n->op == OCONST) {
if(!typefd[n->type->etype]) {
vv = n->vconst;
if(vv >= (vlong)(-32766) && vv < (vlong)32766)
return 1;
/*
* should be specialised for constant values which will
* fit in different instructionsl; for now, let 5l
* sort it out
*/
return 1;
}
}
return 0;
}
static int
isaddcon(vlong v)
{
/* uimm12 or uimm24? */
if(v < 0)
return 0;
if((v & 0xFFF) == 0)
v >>= 12;
return v <= 0xFFF;
}
int
sval(vlong v)
{
return isaddcon(v) || isaddcon(-v);
}
int
usableoffset(Node *n, vlong o, Node *v)
{
int s;
if(v != nil){
if(v->op != OCONST || typefd[v->type->etype])
return 0;
o += v->vconst;
}
s = n->type->width;
if(s > 16)
s = 16;
if((o % s) != 0)
return 0;
return o >= -256 && o < 4096*s;
}