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:
if(o != Z && o->op == OREGISTER) {
i = o->reg;
if(i >= NREG && i < NREG+NREG)
goto out;
}
j = lasti + NREG;
for(i=NREG; i<NREG+NREG; i++) {
if(j >= NREG+NREG)
j = NREG;
if(reg[j] == 0) {
i = j;
goto out;
}
j++;
}
diag(tn, "out of float registers");
goto err;
case TVLONG:
case TUVLONG:
n->op = OREGPAIR;
n->complex = 0; /* already in registers */
n->addable = 11;
n->type = tn->type;
n->lineno = nearln;
n->left = alloc(sizeof(Node));
n->right = alloc(sizeof(Node));
if(o != Z && o->op == OREGPAIR) {
regalloc(n->left, ®node, o->left);
regalloc(n->right, ®node, o->right);
} else {
regalloc(n->left, ®node, Z);
regalloc(n->right, ®node, Z);
}
n->right->type = types[TULONG];
if(tn->type->etype == TUVLONG)
n->left->type = types[TULONG]; /* TO DO: is this a bad idea? */
return;
}
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;
}
}
if((ft == TVLONG || ft == TUVLONG) && f->op == OCONST && t->op == OREGPAIR) {
if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
gmove(nod32const(f->vconst>>32), t->left);
else
gmove(nod32const(f->vconst), t->left);
if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
gmove(nod32const(f->vconst), t->right);
else
gmove(nod32const(f->vconst>>32), t->right);
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:
a = AMOVW;
break;
case TFLOAT:
a = AFMOVS;
break;
case TDOUBLE:
a = AFMOVD;
break;
case TCHAR:
a = AMOVB;
break;
case TUCHAR:
a = AMOVBZ;
break;
case TSHORT:
a = AMOVH;
break;
case TUSHORT:
a = AMOVHZ;
break;
}
if(typev[ft]) {
if(typev[tt] || typefd[tt]) {
regalloc(&nod, f, t);
/* low order first, because its value will be used first */
f->xoffset += SZ_LONG;
gins(AMOVW, f, nod.right);
f->xoffset -= SZ_LONG;
gins(AMOVW, f, nod.left);
} else {
/* assumed not float or double */
regalloc(&nod, ®node, t);
f->xoffset += SZ_LONG;
gins(AMOVW, f, &nod);
f->xoffset -= SZ_LONG;
}
} else {
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:
a = AMOVW;
break;
case TUCHAR:
a = AMOVBZ;
break;
case TCHAR:
a = AMOVB;
break;
case TUSHORT:
a = AMOVHZ;
break;
case TSHORT:
a = AMOVH;
break;
case TFLOAT:
a = AFMOVS;
break;
case TDOUBLE:
a = AFMOVD;
break;
}
if(R0ISZERO && !typefd[ft] && vconst(f) == 0) {
gins(a, f, t);
if(typev[tt]) {
t->xoffset += SZ_LONG;
gins(a, f, t);
t->xoffset -= SZ_LONG;
}
return;
}
if(ft == tt)
regalloc(&nod, t, f);
else
regalloc(&nod, t, Z);
gmove(f, &nod);
if(typev[tt]) {
t->xoffset += SZ_LONG;
gins(a, nod.right, t);
t->xoffset -= SZ_LONG;
gins(a, nod.left, t);
} else
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 = AFMOVS; /* AFMOVSD */
break;
case TFLOAT:
a = AFRSP;
if(ft == TFLOAT)
a = AFMOVS;
break;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
/* BUG: not right for unsigned long */
floattofix(f, t);
return;
case TVLONG:
case TUVLONG:
diag(f, "unimplemented double->vlong");
return;
}
break;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
switch(tt) {
case TDOUBLE:
case TFLOAT:
fixtofloat(f, t);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
case TSHORT:
switch(tt) {
case TDOUBLE:
case TFLOAT:
fixtofloat(f, t);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
a = AMOVH;
break;
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
case TUSHORT:
switch(tt) {
case TDOUBLE:
case TFLOAT:
fixtofloat(f, t);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
a = AMOVHZ;
break;
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
case TCHAR:
switch(tt) {
case TDOUBLE:
case TFLOAT:
fixtofloat(f, t);
return;
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 TFLOAT:
fixtofloat(f, t);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
case TSHORT:
case TUSHORT:
a = AMOVBZ;
break;
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
case TVLONG:
case TUVLONG:
switch(tt) {
case TVLONG:
case TUVLONG:
a = AMOVW;
break;
}
break;
}
if(a == AGOK)
diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
if(a == AMOVW || a == AFMOVS || a == AFMOVD)
if(samaddr(f, t))
return;
if(typev[ft]) {
if(f->op != OREGPAIR || t->op != OREGPAIR)
diag(Z, "bad vlong in gmove (%O->%O)", f->op, t->op);
gins(a, f->left, t->left);
gins(a, f->right, t->right);
} else
gins(a, f, t);
}
void
gopcode(int o, Node *f1, Node *f2, Node *t)
{
int a, et, uns;
if(o == OAS) {
gmove(f1, t);
return;
}
et = TLONG;
if(f1 != Z && f1->type != T) {
if(f1->op == OCONST && t != Z && t->type != T)
et = t->type->etype;
else
et = f1->type->etype;
}
if((typev[et] || t->type != T && typev[t->type->etype]) && o != OFUNC) {
gopcode64(o, f1, f2, t);
return;
}
uns = 0;
a = AGOK;
switch(o) {
case OASADD:
case OADD:
a = AADD;
if(et == TFLOAT)
a = AFADDS;
else
if(et == TDOUBLE)
a = AFADD;
break;
case OASSUB:
case OSUB:
a = ASUB;
if(et == TFLOAT)
a = AFSUBS;
else
if(et == TDOUBLE)
a = AFSUB;
break;
case OASOR:
case OOR:
a = AOR;
break;
case OASAND:
case OAND:
a = AAND;
if(f1->op == OCONST)
a = AANDCC;
break;
case OASXOR:
case OXOR:
a = AXOR;
break;
case OASLSHR:
case OLSHR:
a = ASRW;
break;
case OASASHR:
case OASHR:
a = ASRAW;
break;
case OASASHL:
case OASHL:
a = ASLW;
break;
case OFUNC:
a = ABL;
break;
case OASLMUL:
case OLMUL:
case OASMUL:
case OMUL:
if(et == TFLOAT) {
a = AFMULS;
break;
} else
if(et == TDOUBLE) {
a = AFMUL;
break;
}
a = AMULLW;
break;
case OASDIV:
case ODIV:
if(et == TFLOAT) {
a = AFDIVS;
break;
} else
if(et == TDOUBLE) {
a = AFDIV;
break;
}
a = ADIVW;
break;
case OASMOD:
case OMOD:
a = AREM;
break;
case OASLMOD:
case OLMOD:
a = AREMU;
break;
case OASLDIV:
case OLDIV:
a = ADIVWU;
break;
case OCOM:
a = ANOR;
break;
case ONEG:
a = ANEG;
if(et == TFLOAT || et == TDOUBLE)
a = AFNEG;
break;
case OEQ:
a = ABEQ;
if(t->op == OCONST && t->vconst >= (1<<15))
goto cmpu;
goto cmp;
case ONE:
a = ABNE;
if(t->op == OCONST && t->vconst >= (1<<15))
goto cmpu;
goto cmp;
case OLT:
a = ABLT;
goto cmp;
case OLE:
a = ABLE;
goto cmp;
case OGE:
a = ABGE;
goto cmp;
case OGT:
a = ABGT;
goto cmp;
case OLO:
a = ABLT;
goto cmpu;
case OLS:
a = ABLE;
goto cmpu;
case OHS:
a = ABGE;
goto cmpu;
case OHI:
a = ABGT;
goto cmpu;
cmpu:
uns = 1;
cmp:
nextpc();
p->as = uns? ACMPU: ACMP;
if(et == TFLOAT)
p->as = AFCMPU;
else
if(et == TDOUBLE)
p->as = AFCMPU;
if(f1 != Z)
naddr(f1, &p->from);
if(t != Z)
naddr(t, &p->to);
if(f1 == Z || t == Z || f2 != Z)
diag(Z, "bad cmp in gopcode %O", o);
if(debug['g'])
print("%P\n", p);
f1 = Z;
f2 = Z;
t = Z;
break;
}
if(a == AGOK)
diag(Z, "bad in gopcode %O", o);
gins3(a, f1, f2, t);
}
static void
gopcode64(int o, Node *f1, Node *f2, Node *t)
{
int a1, a2;
Node nod, nod1, nod2, sh;
ulong m;
Prog *p1;