r = REGRET;
if(typefd[nn->type->etype])
r = FREGRET;
nodreg(n, nn, r);
reg[r]++;
}
void
regalloc(Node *n, Node *tn, Node *o)
{
int i;
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 >= D_AX && i <= D_R15)
goto out;
}
for(i=D_AX; i<=D_R15; i++){
i ^= 7;
if(reg[i] == 0 && !resvreg[i])
goto out;
i ^= 7;
}
diag(tn, "out of fixed registers");
goto err;
case TFLOAT:
case TDOUBLE:
if(o != Z && o->op == OREGISTER) {
i = o->reg;
if(i >= D_X0 && i <= D_X7)
goto out;
}
for(i=D_X0; i<=D_X7; i++)
if(reg[i] == 0 && !resvreg[i])
goto out;
diag(tn, "out of float registers");
goto out;
}
diag(tn, "unknown type in regalloc: %T", tn->type);
err:
i = 0;
out:
if(i)
reg[i]++;
nodreg(n, tn, i);
}
ft = f->type->etype;
tt = t->type->etype;
t64 = tt == TVLONG || tt == TUVLONG || tt == TIND;
if(debug['M'])
print("gop: %O %O[%s],%O[%s]\n", OAS,
f->op, tnames[ft], t->op, tnames[tt]);
if(typefd[ft] && f->op == OCONST) {
/* TO DO: pick up special constants, possibly preloaded */
if(f->fconst == 0.0){
regalloc(&nod, t, t);
gins(AXORPD, &nod, &nod);
gmove(&nod, t);
regfree(&nod);
return;
}
}
/*
* load
*/
if(f->op == ONAME || f->op == OINDREG ||
f->op == OIND || f->op == OINDEX)
switch(ft) {
case TCHAR:
a = AMOVBLSX;
if(t64)
a = AMOVBQSX;
goto ld;
case TUCHAR:
a = AMOVBLZX;
if(t64)
a = AMOVBQZX;
goto ld;
case TSHORT:
a = AMOVWLSX;
if(t64)
a = AMOVWQSX;
goto ld;
case TUSHORT:
a = AMOVWLZX;
if(t64)
a = AMOVWQZX;
goto ld;
case TINT:
case TLONG:
if(typefd[tt]) {
regalloc(&nod, t, t);
if(tt == TDOUBLE)
a = ACVTSL2SD;
else
a = ACVTSL2SS;
gins(a, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
}
a = AMOVL;
if(t64)
a = AMOVLQSX;
goto ld;
case TUINT:
case TULONG:
a = AMOVL;
if(t64)
a = AMOVLQZX; /* could probably use plain MOVL */
goto ld;
case TVLONG:
if(typefd[tt]) {
regalloc(&nod, t, t);
if(tt == TDOUBLE)
a = ACVTSQ2SD;
else
a = ACVTSQ2SS;
gins(a, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
}
case TUVLONG:
case TIND:
a = AMOVQ;
ld:
regalloc(&nod, f, t);
gins(a, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
case TFLOAT:
a = AMOVSS;
goto ld;
case TDOUBLE:
a = AMOVSD;
goto ld;
}
/*
* store
*/
if(t->op == ONAME || t->op == OINDREG ||
t->op == OIND || t->op == OINDEX)
switch(tt) {
case TCHAR:
case TUCHAR:
a = AMOVB; goto st;
case TSHORT:
case TUSHORT:
a = AMOVW; goto st;
case TINT:
case TUINT:
case TLONG:
case TULONG:
a = AMOVL; goto st;
case TVLONG:
case TUVLONG:
case TIND:
a = AMOVQ; goto st;
case TFLOAT:
a = AMOVSS;
goto fst;
case TDOUBLE:
a = AMOVSD;
goto fst;
}
/*
* convert
*/
switch(CASE(ft,tt)) {
default:
/*
* integer to integer
********
a = AGOK; break;
case CASE( TCHAR, TCHAR):
case CASE( TUCHAR, TCHAR):
case CASE( TSHORT, TCHAR):
case CASE( TUSHORT,TCHAR):
case CASE( TINT, TCHAR):
case CASE( TUINT, TCHAR):
case CASE( TLONG, TCHAR):
case CASE( TULONG, TCHAR):
case CASE( TCHAR, TUCHAR):
case CASE( TUCHAR, TUCHAR):
case CASE( TSHORT, TUCHAR):
case CASE( TUSHORT,TUCHAR):
case CASE( TINT, TUCHAR):
case CASE( TUINT, TUCHAR):
case CASE( TLONG, TUCHAR):
case CASE( TULONG, TUCHAR):
case CASE( TSHORT, TSHORT):
case CASE( TUSHORT,TSHORT):
case CASE( TINT, TSHORT):
case CASE( TUINT, TSHORT):
case CASE( TLONG, TSHORT):
case CASE( TULONG, TSHORT):
case CASE( TSHORT, TUSHORT):
case CASE( TUSHORT,TUSHORT):
case CASE( TINT, TUSHORT):
case CASE( TUINT, TUSHORT):
case CASE( TLONG, TUSHORT):
case CASE( TULONG, TUSHORT):
case CASE( TINT, TINT):
case CASE( TUINT, TINT):
case CASE( TLONG, TINT):
case CASE( TULONG, TINT)::
case CASE( TINT, TUINT):
case CASE( TUINT, TUINT):
case CASE( TLONG, TUINT):
case CASE( TULONG, TUINT):
*****/
a = AMOVL;
break;
case CASE( TINT, TIND):
case CASE( TINT, TVLONG):
case CASE( TINT, TUVLONG):
case CASE( TLONG, TIND):
case CASE( TLONG, TVLONG):
case CASE( TLONG, TUVLONG):
a = AMOVLQSX;
if(f->op == OCONST) {
f->vconst &= (uvlong)0xffffffffU;
if(f->vconst & 0x80000000)
f->vconst |= (vlong)0xffffffff << 32;
a = AMOVQ;
}
break;
case CASE( TUINT, TIND):
case CASE( TUINT, TVLONG):
case CASE( TUINT, TUVLONG):
case CASE( TULONG, TVLONG):
case CASE( TULONG, TUVLONG):
case CASE( TULONG, TIND):
a = AMOVLQZX;
if(f->op == OCONST) {
f->vconst &= (uvlong)0xffffffffU;
a = AMOVQ;
}
break;
case CASE( TIND, TCHAR):
case CASE( TIND, TUCHAR):
case CASE( TIND, TSHORT):
case CASE( TIND, TUSHORT):
case CASE( TIND, TINT):
case CASE( TIND, TUINT):
case CASE( TIND, TLONG):
case CASE( TIND, TULONG):
case CASE( TVLONG, TCHAR):
case CASE( TVLONG, TUCHAR):
case CASE( TVLONG, TSHORT):
case CASE( TVLONG, TUSHORT):
case CASE( TVLONG, TINT):
case CASE( TVLONG, TUINT):
case CASE( TVLONG, TLONG):
case CASE( TVLONG, TULONG):
case CASE( TUVLONG, TCHAR):
case CASE( TUVLONG, TUCHAR):
case CASE( TUVLONG, TSHORT):
case CASE( TUVLONG, TUSHORT):
case CASE( TUVLONG, TINT):
case CASE( TUVLONG, TUINT):
case CASE( TUVLONG, TLONG):
case CASE( TUVLONG, TULONG):
a = AMOVQL;
if(f->op == OCONST) {
f->vconst &= 0xffffffffU;
a = AMOVL;
}
break;
case CASE( TIND, TIND):
case CASE( TIND, TVLONG):
case CASE( TIND, TUVLONG):
case CASE( TVLONG, TIND):
case CASE( TVLONG, TVLONG):
case CASE( TVLONG, TUVLONG):
case CASE( TUVLONG, TIND):
case CASE( TUVLONG, TVLONG):
case CASE( TUVLONG, TUVLONG):
a = AMOVQ;
break;
case CASE( TSHORT, TINT):
case CASE( TSHORT, TUINT):
case CASE( TSHORT, TLONG):
case CASE( TSHORT, TULONG):
a = AMOVWLSX;
if(f->op == OCONST) {
f->vconst &= 0xffff;
if(f->vconst & 0x8000)
f->vconst |= 0xffff0000;
a = AMOVL;
}
break;
case CASE( TSHORT, TVLONG):
case CASE( TSHORT, TUVLONG):
case CASE( TSHORT, TIND):
a = AMOVWQSX;
if(f->op == OCONST) {
f->vconst &= 0xffff;
if(f->vconst & 0x8000){
f->vconst |= 0xffff0000;
f->vconst |= (vlong)~0 << 32;
}
a = AMOVL;
}
break;
case CASE( TUSHORT,TINT):
case CASE( TUSHORT,TUINT):
case CASE( TUSHORT,TLONG):
case CASE( TUSHORT,TULONG):
a = AMOVWLZX;
if(f->op == OCONST) {
f->vconst &= 0xffff;
a = AMOVL;
}
break;
case CASE( TUSHORT,TVLONG):
case CASE( TUSHORT,TUVLONG):
case CASE( TUSHORT,TIND):
a = AMOVWQZX;
if(f->op == OCONST) {
f->vconst &= 0xffff;
a = AMOVL; /* MOVL also zero-extends to 64 bits */
}
break;
case CASE( TCHAR, TSHORT):
case CASE( TCHAR, TUSHORT):
case CASE( TCHAR, TINT):
case CASE( TCHAR, TUINT):
case CASE( TCHAR, TLONG):
case CASE( TCHAR, TULONG):
a = AMOVBLSX;
if(f->op == OCONST) {
f->vconst &= 0xff;
if(f->vconst & 0x80)
f->vconst |= 0xffffff00;
a = AMOVL;
}
break;
case CASE( TCHAR, TVLONG):
case CASE( TCHAR, TUVLONG):
case CASE( TCHAR, TIND):
a = AMOVBQSX;
if(f->op == OCONST) {
f->vconst &= 0xff;
if(f->vconst & 0x80){
f->vconst |= 0xffffff00;
f->vconst |= (vlong)~0 << 32;
}
a = AMOVQ;
}
break;
case CASE( TUCHAR, TSHORT):
case CASE( TUCHAR, TUSHORT):
case CASE( TUCHAR, TINT):
case CASE( TUCHAR, TUINT):
case CASE( TUCHAR, TLONG):
case CASE( TUCHAR, TULONG):
a = AMOVBLZX;
if(f->op == OCONST) {
f->vconst &= 0xff;
a = AMOVL;
}
break;
case CASE( TUCHAR, TVLONG):
case CASE( TUCHAR, TUVLONG):
case CASE( TUCHAR, TIND):
a = AMOVBQZX;
if(f->op == OCONST) {
f->vconst &= 0xff;
a = AMOVL; /* zero-extends to 64-bits */
}
break;
/*
* float to fix
*/
case CASE( TFLOAT, TCHAR):
case CASE( TFLOAT, TUCHAR):
case CASE( TFLOAT, TSHORT):
case CASE( TFLOAT, TUSHORT):
case CASE( TFLOAT, TINT):
case CASE( TFLOAT, TUINT):
case CASE( TFLOAT, TLONG):
case CASE( TFLOAT, TULONG):
case CASE( TFLOAT, TVLONG):
case CASE( TFLOAT, TUVLONG):
case CASE( TFLOAT, TIND):
case CASE( TDOUBLE,TCHAR):
case CASE( TDOUBLE,TUCHAR):
case CASE( TDOUBLE,TSHORT):
case CASE( TDOUBLE,TUSHORT):
case CASE( TDOUBLE,TINT):
case CASE( TDOUBLE,TUINT):
case CASE( TDOUBLE,TLONG):
case CASE( TDOUBLE,TULONG):
case CASE( TDOUBLE,TVLONG):
case CASE( TDOUBLE,TUVLONG):
case CASE( TDOUBLE,TIND):
regalloc(&nod, t, Z);
if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){
if(ft == TFLOAT)
a = ACVTTSS2SQ;
else
a = ACVTTSD2SQ;
}else{
if(ft == TFLOAT)
a = ACVTTSS2SL;
else
a = ACVTTSD2SL;
}
gins(a, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
case CASE( TULONG, TDOUBLE):
case CASE( TUINT, TDOUBLE):
case CASE( TULONG, TFLOAT):
case CASE( TUINT, TFLOAT):
a = ACVTSQ2SS;
if(tt == TDOUBLE)
a = ACVTSQ2SD;
regalloc(&nod, f, f);
gins(AMOVLQZX, f, &nod);
regalloc(&nod1, t, t);
gins(a, &nod, &nod1);
gmove(&nod1, t);
regfree(&nod);
regfree(&nod1);
return;
/*
* fix to float
*/
case CASE( TCHAR, TFLOAT):
case CASE( TUCHAR, TFLOAT):
case CASE( TSHORT, TFLOAT):
case CASE( TUSHORT,TFLOAT):
case CASE( TINT, TFLOAT):
case CASE( TLONG, TFLOAT):
case CASE( TVLONG, TFLOAT):
case CASE( TIND, TFLOAT):
case CASE( TCHAR, TDOUBLE):
case CASE( TUCHAR, TDOUBLE):
case CASE( TSHORT, TDOUBLE):
case CASE( TUSHORT,TDOUBLE):
case CASE( TINT, TDOUBLE):
case CASE( TLONG, TDOUBLE):
case CASE( TVLONG, TDOUBLE):
case CASE( TIND, TDOUBLE):
regalloc(&nod, t, t);
if(ewidth[ft] == SZ_VLONG){
if(tt == TFLOAT)
a = ACVTSQ2SS;
else
a = ACVTSQ2SD;
}else{
if(tt == TFLOAT)
a = ACVTSL2SS;
else
a = ACVTSL2SD;
}
gins(a, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
/*
* float to float
*/
case CASE( TFLOAT, TFLOAT):
a = AMOVSS;
break;
case CASE( TDOUBLE,TFLOAT):
a = ACVTSD2SS;
break;
case CASE( TFLOAT, TDOUBLE):
a = ACVTSS2SD;
break;
case CASE( TDOUBLE,TDOUBLE):
a = AMOVSD;
break;
}
if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt]) /* TO DO: check AMOVL */
if(samaddr(f, t))
return;
gins(a, f, t);
}
if(n->left->complex >= FNX)
print("botch in doindex\n");
if(n->right->op == OREGISTER)
o = n->right;
else if(o == Z || o->op != OREGISTER || regused(n, o->reg))
o = Z;
regalloc(&nod, &qregnode, o);
v = constnode.vconst;
cgen(n->right, &nod);
idx.ptr = D_NONE;
if(n->left->op == OCONST)
idx.ptr = D_CONST;
else if(n->left->op == OREGISTER)
idx.ptr = n->left->reg;
else if(n->left->op != OADDR) {
reg[D_BP]++; // cant be used as a base
reg[D_R13]++;
regalloc(&nod1, &qregnode, Z);
cgen(n->left, &nod1);
idx.ptr = nod1.reg;
regfree(&nod1);
reg[D_BP]--;
reg[D_R13]--;
}
idx.reg = nod.reg;
regfree(&nod);
constnode.vconst = v;
}
void
gins(int a, Node *f, Node *t)
{
if(f != Z && f->op == OINDEX)
doindex(f, a == AMOVL || a == ALEAL
|| a == AMOVQ || a == ALEAQ
|| a == AMOVBLSX || a == AMOVBLZX
|| a == AMOVBQSX || a == AMOVBQZX
|| a == AMOVWLSX || a == AMOVWLZX
|| a == AMOVWQSX || a == AMOVWQZX ? t : Z);
if(t != Z && t->op == OINDEX)
doindex(t, Z);
nextpc();
p->as = a;
if(f != Z)
naddr(f, &p->from);
if(t != Z)
naddr(t, &p->to);
if(debug['g'])
print("%P\n", p);
}
void
gopcode(int o, Type *ty, Node *f, Node *t)
{
int a, et;
et = TLONG;
if(ty != T)
et = ty->etype;
if(debug['M']) {
if(f != Z && f->type != T)
print("gop: %O %O[%s],", o, f->op, tnames[et]);
else
print("gop: %O Z,", o);
if(t != Z && t->type != T)
print("%O[%s]\n", t->op, tnames[t->type->etype]);
else
print("Z\n");
}
a = AGOK;
switch(o) {
case OCOM:
a = ANOTL;
if(et == TCHAR || et == TUCHAR)
a = ANOTB;
if(et == TSHORT || et == TUSHORT)
a = ANOTW;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = ANOTQ;
break;
case ONEG:
a = ANEGL;
if(et == TCHAR || et == TUCHAR)
a = ANEGB;
if(et == TSHORT || et == TUSHORT)
a = ANEGW;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = ANEGQ;
break;
case OADDR:
a = ALEAQ;
break;
case OASADD:
case OADD:
a = AADDL;
if(et == TCHAR || et == TUCHAR)
a = AADDB;
if(et == TSHORT || et == TUSHORT)
a = AADDW;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = AADDQ;
if(et == TFLOAT)
a = AADDSS;
if(et == TDOUBLE)
a = AADDSD;
break;
case OASSUB:
case OSUB:
a = ASUBL;
if(et == TCHAR || et == TUCHAR)
a = ASUBB;
if(et == TSHORT || et == TUSHORT)
a = ASUBW;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = ASUBQ;
if(et == TFLOAT)
a = ASUBSS;
if(et == TDOUBLE)
a = ASUBSD;
break;
case OASOR:
case OOR:
a = AORL;
if(et == TCHAR || et == TUCHAR)
a = AORB;
if(et == TSHORT || et == TUSHORT)
a = AORW;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = AORQ;
break;
case OASAND:
case OAND:
a = AANDL;
if(et == TCHAR || et == TUCHAR)
a = AANDB;
if(et == TSHORT || et == TUSHORT)
a = AANDW;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = AANDQ;
break;
case OASXOR:
case OXOR:
a = AXORL;
if(et == TCHAR || et == TUCHAR)
a = AXORB;
if(et == TSHORT || et == TUSHORT)
a = AXORW;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = AXORQ;
break;
case OASLSHR:
case OLSHR:
a = ASHRL;
if(et == TCHAR || et == TUCHAR)
a = ASHRB;
if(et == TSHORT || et == TUSHORT)
a = ASHRW;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = ASHRQ;
break;
case OASASHR:
case OASHR:
a = ASARL;
if(et == TCHAR || et == TUCHAR)
a = ASARB;
if(et == TSHORT || et == TUSHORT)
a = ASARW;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = ASARQ;
break;
case OASASHL:
case OASHL:
a = ASALL;
if(et == TCHAR || et == TUCHAR)
a = ASALB;
if(et == TSHORT || et == TUSHORT)
a = ASALW;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = ASALQ;
break;
case OROL:
a = AROLL;
if(et == TCHAR || et == TUCHAR)
a = AROLB;
if(et == TSHORT || et == TUSHORT)
a = AROLW;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = AROLQ;
break;
case OFUNC:
a = ACALL;
break;
case OASMUL:
case OMUL:
if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
t = Z;
a = AIMULL;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = AIMULQ;
if(et == TFLOAT)
a = AMULSS;
if(et == TDOUBLE)
a = AMULSD;
break;
case OASMOD:
case OMOD:
case OASDIV:
case ODIV:
a = AIDIVL;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = AIDIVQ;
if(et == TFLOAT)
a = ADIVSS;
if(et == TDOUBLE)
a = ADIVSD;
break;
case OASLMUL:
case OLMUL:
a = AMULL;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = AMULQ;
break;
case OASLMOD:
case OLMOD:
case OASLDIV:
case OLDIV:
a = ADIVL;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = ADIVQ;
break;
case OEQ:
case ONE:
case OLT:
case OLE:
case OGE:
case OGT:
case OLO:
case OLS:
case OHS:
case OHI:
a = ACMPL;
if(et == TCHAR || et == TUCHAR)
a = ACMPB;
if(et == TSHORT || et == TUSHORT)
a = ACMPW;
if(et == TVLONG || et == TUVLONG || et == TIND)
a = ACMPQ;
if(et == TFLOAT)
a = AUCOMISS;
if(et == TDOUBLE)
a = AUCOMISD;
gins(a, f, t);
switch(o) {
case OEQ: a = AJEQ; break;
case ONE: a = AJNE; break;
case OLT: a = AJLT; break;
case OLE: a = AJLE; break;
case OGE: a = AJGE; break;
case OGT: a = AJGT; break;
case OLO: a = AJCS; break;
case OLS: a = AJLS; break;
case OHS: a = AJCC; break;
case OHI: a = AJHI; break;
}
gins(a, Z, Z);
return;
}
if(a == AGOK)
diag(Z, "bad in gopcode %O", o);
gins(a, f, t);
}