/*
* 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 = AMOVF;
break;
case TDOUBLE:
a = AMOVD;
break;
case TCHAR:
a = AMOVB;
break;
case TUCHAR:
a = AMOVBU;
break;
case TSHORT:
a = AMOVH;
break;
case TUSHORT:
a = AMOVHU;
break;
}
if(typev[ft]) {
if(typev[tt]) {
nod1 = *f;
regalloc(&nod, f, t);
if(f->op == OINDREG && f->xoffset == 0 && nod.left->reg < nod.right->reg) {
gmovm(&nod1, nodconst((1<<nod.left->reg)|(1<<nod.right->reg)), 0);
} else {
/* low order first, because its value will be used first */
gins(AMOVW, &nod1, nod.left);
nod1.xoffset += SZ_LONG;
gins(AMOVW, &nod1, nod.right);
}
} else {
/* assumed not float or double */
regalloc(&nod, ®node, t);
gins(AMOVW, f, &nod);
}
} else {
if(typechlp[ft] && typeilp[tt])
regalloc(&nod, t, t);
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 = AMOVBU;
break;
case TCHAR:
a = AMOVB;
break;
case TUSHORT:
a = AMOVHU;
break;
case TSHORT:
a = AMOVH;
break;
case TFLOAT:
a = AMOVF;
break;
case TDOUBLE:
a = AMOVD;
break;
}
if(ft == tt)
regalloc(&nod, t, f);
else
regalloc(&nod, t, Z);
gmove(f, &nod);
if(typev[tt]) {
nod1 = *t;
if(t->op == OINDREG && t->xoffset == 0 && nod.left->reg < nod.right->reg){
gmovm(nodconst((1<<nod.left->reg)|(1<<nod.right->reg)), &nod1, 0);
} else {
gins(a, nod.left, &nod1);
nod1.xoffset += SZ_LONG;
gins(a, nod.right, &nod1);
}
} 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:
case TVLONG:
a = AMOVD;
if(ft == TFLOAT)
a = AMOVFD;
break;
case TFLOAT:
a = AMOVDF;
if(ft == TFLOAT)
a = AMOVF;
break;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
a = AMOVDW;
if(ft == TFLOAT)
a = AMOVFW;
break;
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOVDW;
if(ft == TFLOAT)
a = AMOVFW;
break;
}
break;
case TUINT:
case TULONG:
if(tt == TFLOAT || tt == TDOUBLE) {
// ugly and probably longer than necessary,
// but vfp has a single instruction for this,
// so hopefully it won't last long.
//
// tmp = f
// tmp1 = tmp & 0x80000000
// tmp ^= tmp1
// t = float(int32(tmp))
// if(tmp1)
// t += 2147483648.
//
regalloc(&nod, f, Z);
regalloc(&nod1, f, Z);
gins(AMOVW, f, &nod);
gins(AMOVW, &nod, &nod1);
gins(AAND, nodconst(0x80000000), &nod1);
gins(AEOR, &nod1, &nod);
if(tt == TFLOAT)
gins(AMOVWF, &nod, t);
else
gins(AMOVWD, &nod, t);
gins(ACMP, nodconst(0), Z);
raddr(&nod1, p);
gins(ABEQ, Z, Z);
regfree(&nod);
regfree(&nod1);
p1 = p;
regalloc(&nod, t, Z);
if(tt == TFLOAT) {
gins(AMOVF, nodfconst(2147483648.), &nod);
gins(AADDF, &nod, t);
} else {
gins(AMOVD, nodfconst(2147483648.), &nod);
gins(AADDD, &nod, t);
}
regfree(&nod);
patch(p1, pc);
return;
}
// fall through
case TINT:
case TLONG:
case TIND:
switch(tt) {
case TDOUBLE:
gins(AMOVWD, f, t);
return;
case TFLOAT:
gins(AMOVWF, 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:
regalloc(&nod, f, Z);
gins(AMOVH, f, &nod);
gins(AMOVWD, &nod, t);
regfree(&nod);
return;
case TFLOAT:
regalloc(&nod, f, Z);
gins(AMOVH, f, &nod);
gins(AMOVWF, &nod, t);
regfree(&nod);
return;
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:
regalloc(&nod, f, Z);
gins(AMOVHU, f, &nod);
gins(AMOVWD, &nod, t);
regfree(&nod);
return;
case TFLOAT:
regalloc(&nod, f, Z);
gins(AMOVHU, f, &nod);
gins(AMOVWF, &nod, t);
regfree(&nod);
return;
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:
regalloc(&nod, f, Z);
gins(AMOVB, f, &nod);
gins(AMOVWD, &nod, t);
regfree(&nod);
return;
case TFLOAT:
regalloc(&nod, f, Z);
gins(AMOVB, f, &nod);
gins(AMOVWF, &nod, t);
regfree(&nod);
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:
regalloc(&nod, f, Z);
gins(AMOVBU, f, &nod);
gins(AMOVWD, &nod, t);
regfree(&nod);
return;
case TFLOAT:
regalloc(&nod, f, Z);
gins(AMOVBU, f, &nod);
gins(AMOVWF, &nod, t);
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;
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 == AMOVF || a == AMOVD)
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
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;
}
}
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;
}