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 TIND:
if(o != Z && o->op == OREGISTER) {
i = o->reg;
if(i >= D_AX && i <= D_DI)
goto out;
}
for(i=D_AX; i<=D_DI; i++)
if(reg[i] == 0)
goto out;
diag(tn, "out of fixed registers");
goto err;
ft = f->type->etype;
tt = t->type->etype;
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) {
if(f->fconst == 0)
gins(AFLDZ, Z, Z);
else
if(f->fconst == 1)
gins(AFLD1, Z, Z);
else
gins(AFMOVD, f, &fregnode0);
gmove(&fregnode0, t);
return;
}
/*
* load
*/
if(f->op == ONAME || f->op == OINDREG ||
f->op == OIND || f->op == OINDEX)
switch(ft) {
case TCHAR:
a = AMOVBLSX;
goto ld;
case TUCHAR:
a = AMOVBLZX;
goto ld;
case TSHORT:
if(typefd[tt]) {
gins(AFMOVW, f, &fregnode0);
gmove(&fregnode0, t);
return;
}
a = AMOVWLSX;
goto ld;
case TUSHORT:
a = AMOVWLZX;
goto ld;
case TINT:
case TLONG:
if(typefd[tt]) {
gins(AFMOVL, f, &fregnode0);
gmove(&fregnode0, t);
return;
}
case TUINT:
case TULONG:
case TIND:
a = AMOVL;
ld:
regalloc(&nod, f, t);
gins(a, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
case TFLOAT:
gins(AFMOVF, f, t);
return;
case TDOUBLE:
gins(AFMOVD, f, t);
return;
}
/*
* 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:
case TIND:
a = AMOVL; goto st;
case TFLOAT:
gins(AFMOVFP, f, t);
return;
case TDOUBLE:
gins(AFMOVDP, f, t);
return;
}
/*
* 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( TIND, 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( TIND, 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( TIND, 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( TIND, TUSHORT):
case CASE( TINT, TINT):
case CASE( TUINT, TINT):
case CASE( TLONG, TINT):
case CASE( TULONG, TINT):
case CASE( TIND, TINT):
case CASE( TINT, TUINT):
case CASE( TUINT, TUINT):
case CASE( TLONG, TUINT):
case CASE( TULONG, TUINT):
case CASE( TIND, TUINT):
case CASE( TINT, TLONG):
case CASE( TUINT, TLONG):
case CASE( TLONG, TLONG):
case CASE( TULONG, TLONG):
case CASE( TIND, TLONG):
case CASE( TINT, TULONG):
case CASE( TUINT, TULONG):
case CASE( TLONG, TULONG):
case CASE( TULONG, TULONG):
case CASE( TIND, TULONG):
case CASE( TINT, TIND):
case CASE( TUINT, TIND):
case CASE( TLONG, TIND):
case CASE( TULONG, TIND):
case CASE( TIND, TIND):
*****/
a = AMOVL;
break;
case CASE( TSHORT, TINT):
case CASE( TSHORT, TUINT):
case CASE( TSHORT, TLONG):
case CASE( TSHORT, TULONG):
case CASE( TSHORT, TIND):
a = AMOVWLSX;
if(f->op == OCONST) {
f->vconst &= 0xffff;
if(f->vconst & 0x8000)
f->vconst |= 0xffff0000;
a = AMOVL;
}
break;
case CASE( TUSHORT,TINT):
case CASE( TUSHORT,TUINT):
case CASE( TUSHORT,TLONG):
case CASE( TUSHORT,TULONG):
case CASE( TUSHORT,TIND):
a = AMOVWLZX;
if(f->op == OCONST) {
f->vconst &= 0xffff;
a = AMOVL;
}
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):
case CASE( TCHAR, TIND):
a = AMOVBLSX;
if(f->op == OCONST) {
f->vconst &= 0xff;
if(f->vconst & 0x80)
f->vconst |= 0xffffff00;
a = AMOVL;
}
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):
case CASE( TUCHAR, TIND):
a = AMOVBLZX;
if(f->op == OCONST) {
f->vconst &= 0xff;
a = AMOVL;
}
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, TLONG):
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,TLONG):
case CASE( TDOUBLE,TIND):
if(fproundflg) {
regsalloc(&nod, ®node);
gins(AFMOVLP, f, &nod);
gmove(&nod, t);
return;
}
regsalloc(&nod, ®node);
regsalloc(&nod1, ®node);
gins(AFSTCW, Z, &nod1);
nod1.xoffset += 2;
gins(AMOVW, nodconst(0xf7f), &nod1);
gins(AFLDCW, &nod1, Z);
gins(AFMOVLP, f, &nod);
nod1.xoffset -= 2;
gins(AFLDCW, &nod1, Z);
gmove(&nod, t);
return;
/*
* float to ulong
*/
case CASE( TDOUBLE, TULONG):
case CASE( TFLOAT, TULONG):
case CASE( TDOUBLE, TUINT):
case CASE( TFLOAT, TUINT):
regsalloc(&nod, ®node);
gmove(f, &fregnode0);
gins(AFADDD, nodfconst(-2147483648.), &fregnode0);
gins(AFMOVLP, f, &nod);
gins(ASUBL, nodconst(-2147483648), &nod);
gmove(&nod, t);
return;
/*
* ulong to float
*/
case CASE( TULONG, TDOUBLE):
case CASE( TULONG, TFLOAT):
case CASE( TUINT, TDOUBLE):
case CASE( TUINT, TFLOAT):
regalloc(&nod, f, f);
gmove(f, &nod);
regsalloc(&nod1, ®node);
gmove(&nod, &nod1);
gins(AFMOVL, &nod1, &fregnode0);
gins(ACMPL, &nod, nodconst(0));
gins(AJGE, Z, Z);
p1 = p;
gins(AFADDD, nodfconst(4294967296.), &fregnode0);
patch(p1, pc);
regfree(&nod);
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( 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( TIND, TDOUBLE):
regsalloc(&nod, ®node);
gmove(f, &nod);
gins(AFMOVL, &nod, &fregnode0);
return;
/*
* float to float
*/
case CASE( TFLOAT, TFLOAT):
case CASE( TDOUBLE,TFLOAT):
case CASE( TFLOAT, TDOUBLE):
case CASE( TDOUBLE,TDOUBLE):
a = AFMOVD; break;
}
if(a == AMOVL || a == AFMOVD)
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, ®node, 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)
// else if(n->left->op == OREGISTER && typeil[n->left->type->etype])
idx.ptr = n->left->reg;
else if(n->left->op != OADDR) {
reg[D_BP]++; // cant be used as a base
regalloc(&nod1, ®node, Z);
cgen(n->left, &nod1);
idx.ptr = nod1.reg;
regfree(&nod1);
reg[D_BP]--;
}
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 == AMOVBLSX || a == AMOVBLZX
|| a == AMOVWLSX || a == AMOVWLZX ? 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
fgopcode(int o, Node *f, Node *t, int pop, int rev)
{
int a, et;
Node nod;
et = TLONG;
if(f != Z && f->type != T)
et = f->type->etype;
if(!typefd[et]) {
diag(f, "fop: integer %O", o);
return;
}
if(debug['M']) {
if(t != Z && t->type != T)
print("gop: %O %O-%s Z\n", o, f->op, tnames[et]);
else
print("gop: %O %O-%s %O-%s\n", o,
f->op, tnames[et], t->op, tnames[t->type->etype]);
}
a = AGOK;
switch(o) {
case OASADD:
case OADD:
if(et == TFLOAT)
a = AFADDF;
else
if(et == TDOUBLE) {
a = AFADDD;
if(pop)
a = AFADDDP;
}
break;
case OASSUB:
case OSUB:
if(et == TFLOAT) {
a = AFSUBF;
if(rev)
a = AFSUBRF;
} else
if(et == TDOUBLE) {
a = AFSUBD;
if(pop)
a = AFSUBDP;
if(rev) {
a = AFSUBRD;
if(pop)
a = AFSUBRDP;
}
}
break;
case OASMUL:
case OMUL:
if(et == TFLOAT)
a = AFMULF;
else
if(et == TDOUBLE) {
a = AFMULD;
if(pop)
a = AFMULDP;
}
break;
case OASMOD:
case OMOD:
case OASDIV:
case ODIV:
if(et == TFLOAT) {
a = AFDIVF;
if(rev)
a = AFDIVRF;
} else
if(et == TDOUBLE) {
a = AFDIVD;
if(pop)
a = AFDIVDP;
if(rev) {
a = AFDIVRD;
if(pop)
a = AFDIVRDP;
}
}
break;
case OEQ:
case ONE:
case OLT:
case OLE:
case OGE:
case OGT:
pop += rev;
if(et == TFLOAT) {
a = AFCOMF;
if(pop) {
a = AFCOMFP;
if(pop > 1)
a = AGOK;
}
} else
if(et == TDOUBLE) {
a = AFCOMF;
if(pop) {
a = AFCOMDP;
if(pop > 1)
a = AFCOMDPP;
}
}
gins(a, f, t);
regalloc(&nod, ®node, Z);
if(nod.reg != D_AX) {
regfree(&nod);
nod.reg = D_AX;
gins(APUSHL, &nod, Z);
gins(AWAIT, Z, Z);
gins(AFSTSW, Z, &nod);
gins(ASAHF, Z, Z);
gins(APOPL, Z, &nod);
} else {
gins(AWAIT, Z, Z);
gins(AFSTSW, Z, &nod);
gins(ASAHF, Z, Z);
regfree(&nod);
}
switch(o) {
case OEQ: a = AJEQ; break;
case ONE: a = AJNE; break;
case OLT: a = AJCS; break;
case OLE: a = AJLS; break;
case OGE: a = AJCC; break;
case OGT: a = AJHI; break;
}
gins(a, Z, Z);
return;
}
if(a == AGOK)
diag(Z, "bad in gopcode %O", o);
gins(a, f, t);
}
void
gopcode(int o, Type *ty, Node *f, Node *t)
{
int a, et;
et = TLONG;
if(ty != T)
et = ty->etype;
if(typefd[et] && o != OADDR && o != OFUNC) {
diag(f, "gop: float %O", o);
return;
}
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;
break;
case ONEG:
a = ANEGL;
if(et == TCHAR || et == TUCHAR)
a = ANEGB;
if(et == TSHORT || et == TUSHORT)
a = ANEGW;
break;
case OADDR:
a = ALEAL;
break;
case OASADD:
case OADD:
a = AADDL;
if(et == TCHAR || et == TUCHAR)
a = AADDB;
if(et == TSHORT || et == TUSHORT)
a = AADDW;
break;
case OASSUB:
case OSUB:
a = ASUBL;
if(et == TCHAR || et == TUCHAR)
a = ASUBB;
if(et == TSHORT || et == TUSHORT)
a = ASUBW;
break;
case OASOR:
case OOR:
a = AORL;
if(et == TCHAR || et == TUCHAR)
a = AORB;
if(et == TSHORT || et == TUSHORT)
a = AORW;
break;
case OASAND:
case OAND:
a = AANDL;
if(et == TCHAR || et == TUCHAR)
a = AANDB;
if(et == TSHORT || et == TUSHORT)
a = AANDW;
break;
case OASXOR:
case OXOR:
a = AXORL;
if(et == TCHAR || et == TUCHAR)
a = AXORB;
if(et == TSHORT || et == TUSHORT)
a = AXORW;
break;
case OASLSHR:
case OLSHR:
a = ASHRL;
if(et == TCHAR || et == TUCHAR)
a = ASHRB;
if(et == TSHORT || et == TUSHORT)
a = ASHRW;
break;
case OASASHR:
case OASHR:
a = ASARL;
if(et == TCHAR || et == TUCHAR)
a = ASARB;
if(et == TSHORT || et == TUSHORT)
a = ASARW;
break;
case OASASHL:
case OASHL:
a = ASALL;
if(et == TCHAR || et == TUCHAR)
a = ASALB;
if(et == TSHORT || et == TUSHORT)
a = ASALW;
break;
case OROL:
a = AROLL;
if(et == TCHAR || et == TUCHAR)
a = AROLB;
if(et == TSHORT || et == TUSHORT)
a = AROLW;
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;
break;
case OASMOD:
case OMOD:
case OASDIV:
case ODIV:
a = AIDIVL;
break;
case OASLMUL:
case OLMUL:
a = AMULL;
break;
case OASLMOD:
case OLMOD:
case OASLDIV:
case OLDIV:
a = ADIVL;
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;
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);
}