plan9fox/sys/src/cmd/6c/cgen.c
cinap_lenrek 9de5aac7a2 5c, 6c, 7c, 8c, kc, qc, vc: use explicit gmove(... , nn) in cgen() for result of OAS*, OPREINC, OPOSTINC
The expression value of the assignment operation was
returned implicitely by relying on regalloc() on the
right hand side "nod" borrowing the register from nn.

But this only works if nn is a register.

In case of 6c, it can also be a ONAME from a .safe
rathole returned by regsalloc().

This change adds explicit gmove() calls to assign the
expression value. Note that gmove() checks if source
and destination are the same register so it wont emit
redundant move operations in the common case.

The same is applied also to OPREINC and OPOSTINC operations.
2021-03-13 13:56:40 +01:00

1957 lines
34 KiB
C

#include "gc.h"
/* ,x/^(print|prtree)\(/i/\/\/ */
int castup(Type*, Type*);
void
cgen(Node *n, Node *nn)
{
Node *l, *r, *t;
Prog *p1;
Node nod, nod1, nod2, nod3, nod4;
int o, hardleft;
long v, curs;
vlong c;
if(debug['g']) {
prtree(nn, "cgen lhs");
prtree(n, "cgen");
}
if(n == Z || n->type == T)
return;
if(typesu[n->type->etype]) {
sugen(n, nn, n->type->width);
return;
}
l = n->left;
r = n->right;
o = n->op;
if(n->addable >= INDEXED) {
if(nn == Z) {
switch(o) {
default:
nullwarn(Z, Z);
break;
case OINDEX:
nullwarn(l, r);
break;
}
return;
}
gmove(n, nn);
return;
}
curs = cursafe;
if(l->complex >= FNX)
if(r != Z && r->complex >= FNX)
switch(o) {
default:
if(cond(o) && typesu[l->type->etype])
break;
regret(&nod, r);
cgen(r, &nod);
regsalloc(&nod1, r);
gmove(&nod, &nod1);
regfree(&nod);
nod = *n;
nod.right = &nod1;
cgen(&nod, nn);
return;
case OFUNC:
case OCOMMA:
case OANDAND:
case OOROR:
case OCOND:
case ODOT:
break;
}
hardleft = l->addable < INDEXED || l->complex >= FNX;
switch(o) {
default:
diag(n, "unknown op in cgen: %O", o);
break;
case ONEG:
case OCOM:
if(nn == Z) {
nullwarn(l, Z);
break;
}
regalloc(&nod, l, nn);
cgen(l, &nod);
gopcode(o, n->type, Z, &nod);
gmove(&nod, nn);
regfree(&nod);
break;
case OAS:
if(l->op == OBIT)
goto bitas;
if(!hardleft) {
if(nn != Z || r->addable < INDEXED || hardconst(r)) {
if(r->complex >= FNX && nn == Z)
regret(&nod, r);
else
regalloc(&nod, r, nn);
cgen(r, &nod);
gmove(&nod, l);
if(nn != Z)
gmove(&nod, nn);
regfree(&nod);
} else
gmove(r, l);
break;
}
if(l->complex >= r->complex) {
if(l->op == OINDEX && immconst(r)) {
gmove(r, l);
if(nn != Z)
gmove(r, nn);
break;
}
reglcgen(&nod1, l, Z);
if(r->addable >= INDEXED && !hardconst(r)) {
gmove(r, &nod1);
if(nn != Z)
gmove(r, nn);
regfree(&nod1);
break;
}
regalloc(&nod, r, nn);
cgen(r, &nod);
} else {
regalloc(&nod, r, nn);
cgen(r, &nod);
reglcgen(&nod1, l, Z);
}
gmove(&nod, &nod1);
if(nn != Z)
gmove(&nod, nn);
regfree(&nod);
regfree(&nod1);
break;
bitas:
n = l->left;
regalloc(&nod, r, nn);
if(l->complex >= r->complex) {
reglcgen(&nod1, n, Z);
cgen(r, &nod);
} else {
cgen(r, &nod);
reglcgen(&nod1, n, Z);
}
regalloc(&nod2, n, Z);
gmove(&nod1, &nod2);
bitstore(l, &nod, &nod1, &nod2, nn);
break;
case OBIT:
if(nn == Z) {
nullwarn(l, Z);
break;
}
bitload(n, &nod, Z, Z, nn);
gmove(&nod, nn);
regfree(&nod);
break;
case OROL:
case OLSHR:
case OASHL:
case OASHR:
if(nn == Z) {
nullwarn(l, r);
break;
}
if(r->op == OCONST) {
if(r->vconst == 0) {
cgen(l, nn);
break;
}
regalloc(&nod, l, nn);
cgen(l, &nod);
if(o == OASHL && r->vconst == 1)
gopcode(OADD, n->type, &nod, &nod);
else
gopcode(o, n->type, r, &nod);
gmove(&nod, nn);
regfree(&nod);
break;
}
/*
* get nod to be D_CX
*/
if(nodreg(&nod, nn, D_CX)) {
regsalloc(&nod1, n);
gmove(&nod, &nod1);
cgen(n, &nod); /* probably a bug */
gmove(&nod, nn);
gmove(&nod1, &nod);
break;
}
reg[D_CX]++;
if(nn->op == OREGISTER && nn->reg == D_CX)
regalloc(&nod1, l, Z);
else
regalloc(&nod1, l, nn);
if(r->complex >= l->complex) {
cgen(r, &nod);
cgen(l, &nod1);
} else {
cgen(l, &nod1);
cgen(r, &nod);
}
gopcode(o, n->type, &nod, &nod1);
gmove(&nod1, nn);
regfree(&nod);
regfree(&nod1);
break;
case OADD:
case OSUB:
case OOR:
case OXOR:
case OAND:
if(nn == Z) {
nullwarn(l, r);
break;
}
if(typefd[n->type->etype])
goto fop;
if(r->op == OCONST) {
if(r->vconst == 0 && o != OAND) {
cgen(l, nn);
break;
}
}
if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
&& (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
c = l->right->vconst;
if(c > 0 && c <= 3) {
if(l->left->complex >= r->complex) {
regalloc(&nod, l->left, nn);
cgen(l->left, &nod);
if(r->addable < INDEXED) {
regalloc(&nod1, r, Z);
cgen(r, &nod1);
genmuladd(&nod, &nod, 1 << c, &nod1);
regfree(&nod1);
}
else
genmuladd(&nod, &nod, 1 << c, r);
}
else {
regalloc(&nod, r, nn);
cgen(r, &nod);
regalloc(&nod1, l->left, Z);
cgen(l->left, &nod1);
genmuladd(&nod, &nod1, 1 << c, &nod);
regfree(&nod1);
}
gmove(&nod, nn);
regfree(&nod);
break;
}
}
if(r->addable >= INDEXED && !hardconst(r)) {
regalloc(&nod, l, nn);
cgen(l, &nod);
gopcode(o, n->type, r, &nod);
gmove(&nod, nn);
regfree(&nod);
break;
}
if(l->complex >= r->complex) {
regalloc(&nod, l, nn);
cgen(l, &nod);
regalloc(&nod1, r, Z);
cgen(r, &nod1);
gopcode(o, n->type, &nod1, &nod);
} else {
regalloc(&nod1, r, nn);
cgen(r, &nod1);
regalloc(&nod, l, Z);
cgen(l, &nod);
gopcode(o, n->type, &nod1, &nod);
}
gmove(&nod, nn);
regfree(&nod);
regfree(&nod1);
break;
case OLMOD:
case OMOD:
case OLMUL:
case OLDIV:
case OMUL:
case ODIV:
if(nn == Z) {
nullwarn(l, r);
break;
}
if(typefd[n->type->etype])
goto fop;
if(r->op == OCONST && typechl[n->type->etype]) { /* TO DO */
SET(v);
switch(o) {
case ODIV:
case OMOD:
c = r->vconst;
if(c < 0)
c = -c;
v = log2(c);
if(v < 0)
break;
/* fall thru */
case OMUL:
case OLMUL:
regalloc(&nod, l, nn);
cgen(l, &nod);
switch(o) {
case OMUL:
case OLMUL:
mulgen(n->type, r, &nod);
break;
case ODIV:
sdiv2(r->vconst, v, l, &nod);
break;
case OMOD:
smod2(r->vconst, v, l, &nod);
break;
}
gmove(&nod, nn);
regfree(&nod);
goto done;
case OLDIV:
c = r->vconst;
if((c & 0x80000000) == 0)
break;
regalloc(&nod1, l, Z);
cgen(l, &nod1);
regalloc(&nod, l, nn);
zeroregm(&nod);
gins(ACMPL, &nod1, nodconst(c));
gins(ASBBL, nodconst(-1), &nod);
regfree(&nod1);
gmove(&nod, nn);
regfree(&nod);
goto done;
}
}
if(o == OMUL) {
if(l->addable >= INDEXED) {
t = l;
l = r;
r = t;
}
/* should favour AX */
regalloc(&nod, l, nn);
cgen(l, &nod);
if(r->addable < INDEXED || hardconst(r)) {
regalloc(&nod1, r, Z);
cgen(r, &nod1);
gopcode(OMUL, n->type, &nod1, &nod);
regfree(&nod1);
}else
gopcode(OMUL, n->type, r, &nod); /* addressible */
gmove(&nod, nn);
regfree(&nod);
break;
}
/*
* get nod to be D_AX
* get nod1 to be D_DX
*/
if(nodreg(&nod, nn, D_AX)) {
regsalloc(&nod2, n);
gmove(&nod, &nod2);
v = reg[D_AX];
reg[D_AX] = 0;
if(isreg(l, D_AX)) {
nod3 = *n;
nod3.left = &nod2;
cgen(&nod3, nn);
} else
if(isreg(r, D_AX)) {
nod3 = *n;
nod3.right = &nod2;
cgen(&nod3, nn);
} else
cgen(n, nn);
gmove(&nod2, &nod);
reg[D_AX] = v;
break;
}
if(nodreg(&nod1, nn, D_DX)) {
regsalloc(&nod2, n);
gmove(&nod1, &nod2);
v = reg[D_DX];
reg[D_DX] = 0;
if(isreg(l, D_DX)) {
nod3 = *n;
nod3.left = &nod2;
cgen(&nod3, nn);
} else
if(isreg(r, D_DX)) {
nod3 = *n;
nod3.right = &nod2;
cgen(&nod3, nn);
} else
cgen(n, nn);
gmove(&nod2, &nod1);
reg[D_DX] = v;
break;
}
reg[D_AX]++;
if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) {
reg[D_DX]++;
if(l->addable < INDEXED) {
regalloc(&nod2, l, Z);
cgen(l, &nod2);
l = &nod2;
}
if(o == ODIV)
sdivgen(l, r, &nod, &nod1);
else
udivgen(l, r, &nod, &nod1);
gmove(&nod1, nn);
if(l == &nod2)
regfree(l);
goto freeaxdx;
}
if(l->complex >= r->complex) {
cgen(l, &nod);
reg[D_DX]++;
if(o == ODIV || o == OMOD)
gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
if(o == OLDIV || o == OLMOD)
zeroregm(&nod1);
if(r->addable < INDEXED || r->op == OCONST) {
regalloc(&nod3, r, Z);
cgen(r, &nod3);
gopcode(o, n->type, &nod3, Z);
regfree(&nod3);
} else
gopcode(o, n->type, r, Z);
} else {
regsalloc(&nod3, r);
cgen(r, &nod3);
cgen(l, &nod);
reg[D_DX]++;
if(o == ODIV || o == OMOD)
gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
if(o == OLDIV || o == OLMOD)
zeroregm(&nod1);
gopcode(o, n->type, &nod3, Z);
}
if(o == OMOD || o == OLMOD)
gmove(&nod1, nn);
else
gmove(&nod, nn);
freeaxdx:
regfree(&nod);
regfree(&nod1);
break;
case OASLSHR:
case OASASHL:
case OASASHR:
if(r->op == OCONST)
goto asand;
if(l->op == OBIT)
goto asbitop;
if(typefd[n->type->etype])
goto asand; /* can this happen? */
/*
* get nod to be D_CX
*/
if(nodreg(&nod, nn, D_CX)) {
regsalloc(&nod1, n);
gmove(&nod, &nod1);
cgen(n, &nod);
if(nn != Z)
gmove(&nod, nn);
gmove(&nod1, &nod);
break;
}
reg[D_CX]++;
if(r->complex >= l->complex) {
cgen(r, &nod);
if(hardleft)
reglcgen(&nod1, l, Z);
else
nod1 = *l;
} else {
if(hardleft)
reglcgen(&nod1, l, Z);
else
nod1 = *l;
cgen(r, &nod);
}
gopcode(o, l->type, &nod, &nod1);
regfree(&nod);
if(nn != Z)
gmove(&nod1, nn);
if(hardleft)
regfree(&nod1);
break;
case OASAND:
case OASADD:
case OASSUB:
case OASXOR:
case OASOR:
asand:
if(l->op == OBIT)
goto asbitop;
if(typefd[l->type->etype] || typefd[r->type->etype])
goto asfop;
if(l->complex >= r->complex) {
if(hardleft)
reglcgen(&nod, l, Z);
else
nod = *l;
if(!immconst(r)) {
regalloc(&nod1, r, nn);
cgen(r, &nod1);
gopcode(o, l->type, &nod1, &nod);
regfree(&nod1);
} else
gopcode(o, l->type, r, &nod);
} else {
regalloc(&nod1, r, nn);
cgen(r, &nod1);
if(hardleft)
reglcgen(&nod, l, Z);
else
nod = *l;
gopcode(o, l->type, &nod1, &nod);
regfree(&nod1);
}
if(nn != Z)
gmove(&nod, nn);
if(hardleft)
regfree(&nod);
break;
asfop:
if(l->complex >= r->complex) {
if(hardleft)
reglcgen(&nod, l, Z);
else
nod = *l;
if(r->addable < INDEXED){
regalloc(&nod1, r, nn);
cgen(r, &nod1);
}else
nod1 = *r;
regalloc(&nod2, r, Z);
gmove(&nod, &nod2);
gopcode(o, r->type, &nod1, &nod2);
gmove(&nod2, &nod);
regfree(&nod2);
if(r->addable < INDEXED)
regfree(&nod1);
} else {
regalloc(&nod1, r, nn);
cgen(r, &nod1);
if(hardleft)
reglcgen(&nod, l, Z);
else
nod = *l;
if(o != OASMUL && o != OASADD || !typefd[l->type->etype]) {
regalloc(&nod2, r, Z);
gmove(&nod, &nod2);
gopcode(o, r->type, &nod1, &nod2);
regfree(&nod1);
gmove(&nod2, &nod);
regfree(&nod2);
} else {
gopcode(o, r->type, &nod, &nod1);
gmove(&nod1, &nod);
regfree(&nod1);
}
}
if(nn != Z)
gmove(&nod, nn);
if(hardleft)
regfree(&nod);
break;
case OASLMUL:
case OASLDIV:
case OASLMOD:
case OASMUL:
case OASDIV:
case OASMOD:
if(l->op == OBIT)
goto asbitop;
if(typefd[n->type->etype] || typefd[r->type->etype])
goto asfop;
if(r->op == OCONST && typechl[n->type->etype]) {
SET(v);
switch(o) {
case OASDIV:
case OASMOD:
c = r->vconst;
if(c < 0)
c = -c;
v = log2(c);
if(v < 0)
break;
/* fall thru */
case OASMUL:
case OASLMUL:
if(hardleft)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
regalloc(&nod, l, nn);
cgen(&nod2, &nod);
switch(o) {
case OASMUL:
case OASLMUL:
mulgen(n->type, r, &nod);
break;
case OASDIV:
sdiv2(r->vconst, v, l, &nod);
break;
case OASMOD:
smod2(r->vconst, v, l, &nod);
break;
}
havev:
gmove(&nod, &nod2);
if(nn != Z)
gmove(&nod, nn);
if(hardleft)
regfree(&nod2);
regfree(&nod);
goto done;
case OASLDIV:
c = r->vconst;
if((c & 0x80000000) == 0)
break;
if(hardleft)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
regalloc(&nod1, l, nn);
cgen(&nod2, &nod1);
regalloc(&nod, l, nn);
zeroregm(&nod);
gins(ACMPL, &nod1, nodconst(c));
gins(ASBBL, nodconst(-1), &nod);
regfree(&nod1);
goto havev;
}
}
if(o == OASMUL) {
/* should favour AX */
regalloc(&nod, l, nn);
if(r->complex >= FNX) {
regalloc(&nod1, r, Z);
cgen(r, &nod1);
r = &nod1;
}
if(hardleft)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
cgen(&nod2, &nod);
if(r->addable < INDEXED || hardconst(r)) {
if(r->complex < FNX) {
regalloc(&nod1, r, Z);
cgen(r, &nod1);
}
gopcode(OASMUL, n->type, &nod1, &nod);
regfree(&nod1);
}
else
gopcode(OASMUL, n->type, r, &nod);
if(r == &nod1)
regfree(r);
gmove(&nod, &nod2);
if(nn != Z)
gmove(&nod, nn);
regfree(&nod);
if(hardleft)
regfree(&nod2);
break;
}
/*
* get nod to be D_AX
* get nod1 to be D_DX
*/
if(nodreg(&nod, nn, D_AX)) {
regsalloc(&nod2, n);
gmove(&nod, &nod2);
v = reg[D_AX];
reg[D_AX] = 0;
if(isreg(l, D_AX)) {
nod3 = *n;
nod3.left = &nod2;
cgen(&nod3, nn);
} else
if(isreg(r, D_AX)) {
nod3 = *n;
nod3.right = &nod2;
cgen(&nod3, nn);
} else
cgen(n, nn);
gmove(&nod2, &nod);
reg[D_AX] = v;
break;
}
if(nodreg(&nod1, nn, D_DX)) {
regsalloc(&nod2, n);
gmove(&nod1, &nod2);
v = reg[D_DX];
reg[D_DX] = 0;
if(isreg(l, D_DX)) {
nod3 = *n;
nod3.left = &nod2;
cgen(&nod3, nn);
} else
if(isreg(r, D_DX)) {
nod3 = *n;
nod3.right = &nod2;
cgen(&nod3, nn);
} else
cgen(n, nn);
gmove(&nod2, &nod1);
reg[D_DX] = v;
break;
}
reg[D_AX]++;
reg[D_DX]++;
if(l->complex >= r->complex) {
if(hardleft)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
cgen(&nod2, &nod);
if(r->op == OCONST && typechl[r->type->etype]) {
switch(o) {
case OASDIV:
sdivgen(&nod2, r, &nod, &nod1);
goto divdone;
case OASLDIV:
udivgen(&nod2, r, &nod, &nod1);
divdone:
gmove(&nod1, &nod2);
if(nn != Z)
gmove(&nod1, nn);
goto freelxaxdx;
}
}
if(o == OASDIV || o == OASMOD)
gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
if(o == OASLDIV || o == OASLMOD)
zeroregm(&nod1);
if(r->addable < INDEXED || r->op == OCONST ||
!typeil[r->type->etype]) {
regalloc(&nod3, r, Z);
cgen(r, &nod3);
gopcode(o, l->type, &nod3, Z);
regfree(&nod3);
} else
gopcode(o, n->type, r, Z);
} else {
regalloc(&nod3, r, Z);
cgen(r, &nod3);
if(hardleft)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
cgen(&nod2, &nod);
if(o == OASDIV || o == OASMOD)
gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
if(o == OASLDIV || o == OASLMOD)
zeroregm(&nod1);
gopcode(o, l->type, &nod3, Z);
regfree(&nod3);
}
if(o == OASMOD || o == OASLMOD) {
gmove(&nod1, &nod2);
if(nn != Z)
gmove(&nod1, nn);
} else {
gmove(&nod, &nod2);
if(nn != Z)
gmove(&nod, nn);
}
freelxaxdx:
if(hardleft)
regfree(&nod2);
regfree(&nod);
regfree(&nod1);
break;
fop:
if(l->complex >= r->complex) {
regalloc(&nod, l, nn);
cgen(l, &nod);
if(r->addable < INDEXED) {
regalloc(&nod1, r, Z);
cgen(r, &nod1);
gopcode(o, n->type, &nod1, &nod);
regfree(&nod1);
} else
gopcode(o, n->type, r, &nod);
} else {
/* TO DO: could do better with r->addable >= INDEXED */
regalloc(&nod1, r, nn);
cgen(r, &nod1);
regalloc(&nod, l, Z);
cgen(l, &nod);
gopcode(o, n->type, &nod1, &nod);
regfree(&nod1);
}
gmove(&nod, nn);
regfree(&nod);
break;
asbitop:
regalloc(&nod4, n, nn);
if(l->complex >= r->complex) {
bitload(l, &nod, &nod1, &nod2, &nod4);
regalloc(&nod3, r, Z);
cgen(r, &nod3);
} else {
regalloc(&nod3, r, Z);
cgen(r, &nod3);
bitload(l, &nod, &nod1, &nod2, &nod4);
}
gmove(&nod, &nod4);
{ /* TO DO: check floating point source */
Node onod;
/* incredible grot ... */
onod = nod3;
onod.op = o;
onod.complex = 2;
onod.addable = 0;
onod.type = tfield;
onod.left = &nod4;
onod.right = &nod3;
cgen(&onod, Z);
}
regfree(&nod3);
gmove(&nod4, &nod);
regfree(&nod4);
bitstore(l, &nod, &nod1, &nod2, nn);
break;
case OADDR:
if(nn == Z) {
nullwarn(l, Z);
break;
}
lcgen(l, nn);
break;
case OFUNC:
l = uncomma(l);
if(l->complex >= FNX) {
if(l->op != OIND)
diag(n, "bad function call");
regret(&nod, l->left);
cgen(l->left, &nod);
regsalloc(&nod1, l->left);
gmove(&nod, &nod1);
regfree(&nod);
nod = *n;
nod.left = &nod2;
nod2 = *l;
nod2.left = &nod1;
nod2.complex = 1;
cgen(&nod, nn);
return;
}
o = reg[REGARG];
gargs(r, &nod, &nod1);
if(l->addable < INDEXED) {
reglcgen(&nod, l, nn);
nod.op = OREGISTER;
gopcode(OFUNC, n->type, Z, &nod);
regfree(&nod);
} else
gopcode(OFUNC, n->type, Z, l);
if(REGARG)
if(o != reg[REGARG])
reg[REGARG]--;
if(nn != Z) {
regret(&nod, n);
gmove(&nod, nn);
regfree(&nod);
}
break;
case OIND:
if(nn == Z) {
nullwarn(l, Z);
break;
}
regialloc(&nod, n, nn);
r = l;
while(r->op == OADD)
r = r->right;
if(sconst(r)) {
v = r->vconst;
r->vconst = 0;
cgen(l, &nod);
nod.xoffset += v;
r->vconst = v;
} else
cgen(l, &nod);
regind(&nod, n);
gmove(&nod, nn);
regfree(&nod);
break;
case OEQ:
case ONE:
case OLE:
case OLT:
case OGE:
case OGT:
case OLO:
case OLS:
case OHI:
case OHS:
if(nn == Z) {
nullwarn(l, r);
break;
}
boolgen(n, 1, nn);
break;
case OANDAND:
case OOROR:
boolgen(n, 1, nn);
if(nn == Z)
patch(p, pc);
break;
case ONOT:
if(nn == Z) {
nullwarn(l, Z);
break;
}
boolgen(n, 1, nn);
break;
case OCOMMA:
cgen(l, Z);
cgen(r, nn);
break;
case OCAST:
if(nn == Z) {
cgen(l, Z);
break;
}
/*
* convert from types l->n->nn
*/
if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
/* both null, gen l->nn */
cgen(l, nn);
break;
}
if(ewidth[n->type->etype] < ewidth[l->type->etype]){
if(l->type->etype == TIND && typechlp[n->type->etype])
warn(n, "conversion of pointer to shorter integer");
}else if(0){
if(nocast(n->type, nn->type) || castup(n->type, nn->type)){
if(typefd[l->type->etype] != typefd[nn->type->etype])
regalloc(&nod, l, nn);
else
regalloc(&nod, nn, nn);
cgen(l, &nod);
gmove(&nod, nn);
regfree(&nod);
break;
}
}
regalloc(&nod, l, nn);
cgen(l, &nod);
regalloc(&nod1, n, &nod);
gmove(&nod, &nod1);
gmove(&nod1, nn);
regfree(&nod1);
regfree(&nod);
break;
case ODOT:
sugen(l, nodrat, l->type->width);
if(nn == Z)
break;
warn(n, "non-interruptable temporary");
nod = *nodrat;
if(!r || r->op != OCONST) {
diag(n, "DOT and no offset");
break;
}
nod.xoffset += (long)r->vconst;
nod.type = n->type;
cgen(&nod, nn);
break;
case OCOND:
bcgen(l, 1);
p1 = p;
cgen(r->left, nn);
gbranch(OGOTO);
patch(p1, pc);
p1 = p;
cgen(r->right, nn);
patch(p1, pc);
break;
case OPOSTINC:
case OPOSTDEC:
v = 1;
if(l->type->etype == TIND)
v = l->type->link->width;
if(o == OPOSTDEC)
v = -v;
if(l->op == OBIT)
goto bitinc;
if(nn == Z)
goto pre;
if(hardleft)
reglcgen(&nod, l, Z);
else
nod = *l;
gmove(&nod, nn);
if(typefd[n->type->etype]) {
regalloc(&nod1, l, Z);
gmove(&nod, &nod1);
if(v < 0)
gopcode(OSUB, n->type, nodfconst(-v), &nod1);
else
gopcode(OADD, n->type, nodfconst(v), &nod1);
gmove(&nod1, &nod);
regfree(&nod1);
} else
gopcode(OADD, n->type, nodconst(v), &nod);
if(hardleft)
regfree(&nod);
break;
case OPREINC:
case OPREDEC:
v = 1;
if(l->type->etype == TIND)
v = l->type->link->width;
if(o == OPREDEC)
v = -v;
if(l->op == OBIT)
goto bitinc;
pre:
if(hardleft)
reglcgen(&nod, l, Z);
else
nod = *l;
if(typefd[n->type->etype]) {
regalloc(&nod1, l, Z);
gmove(&nod, &nod1);
if(v < 0)
gopcode(OSUB, n->type, nodfconst(-v), &nod1);
else
gopcode(OADD, n->type, nodfconst(v), &nod1);
gmove(&nod1, &nod);
regfree(&nod1);
} else
gopcode(OADD, n->type, nodconst(v), &nod);
if(nn != Z)
gmove(&nod, nn);
if(hardleft)
regfree(&nod);
break;
bitinc:
if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
bitload(l, &nod, &nod1, &nod2, Z);
gmove(&nod, nn);
gopcode(OADD, tfield, nodconst(v), &nod);
bitstore(l, &nod, &nod1, &nod2, Z);
break;
}
bitload(l, &nod, &nod1, &nod2, nn);
gopcode(OADD, tfield, nodconst(v), &nod);
bitstore(l, &nod, &nod1, &nod2, nn);
break;
}
done:
cursafe = curs;
}
void
reglcgen(Node *t, Node *n, Node *nn)
{
Node *r;
long v;
regialloc(t, n, nn);
if(n->op == OIND) {
r = n->left;
while(r->op == OADD)
r = r->right;
if(sconst(r)) {
v = r->vconst;
r->vconst = 0;
lcgen(n, t);
t->xoffset += v;
r->vconst = v;
regind(t, n);
return;
}
}
lcgen(n, t);
regind(t, n);
}
void
lcgen(Node *n, Node *nn)
{
Prog *p1;
Node nod;
if(debug['g']) {
prtree(nn, "lcgen lhs");
prtree(n, "lcgen");
}
if(n == Z || n->type == T)
return;
if(nn == Z) {
nn = &nod;
regalloc(&nod, n, Z);
}
switch(n->op) {
default:
if(n->addable < INDEXED) {
diag(n, "unknown op in lcgen: %O", n->op);
break;
}
gopcode(OADDR, n->type, n, nn);
break;
case OCOMMA:
cgen(n->left, n->left);
lcgen(n->right, nn);
break;
case OIND:
cgen(n->left, nn);
break;
case OCOND:
bcgen(n->left, 1);
p1 = p;
lcgen(n->right->left, nn);
gbranch(OGOTO);
patch(p1, pc);
p1 = p;
lcgen(n->right->right, nn);
patch(p1, pc);
break;
}
}
void
bcgen(Node *n, int true)
{
if(n->type == T)
gbranch(OGOTO);
else
boolgen(n, true, Z);
}
void
boolgen(Node *n, int true, Node *nn)
{
int o;
Prog *p1, *p2;
Node *l, *r, nod, nod1;
long curs;
if(debug['g']) {
prtree(nn, "boolgen lhs");
prtree(n, "boolgen");
}
curs = cursafe;
l = n->left;
r = n->right;
switch(n->op) {
default:
o = ONE;
if(true)
o = OEQ;
/* bad, 13 is address of external that becomes constant */
if(n->addable >= INDEXED && n->addable != 13) {
if(typefd[n->type->etype]) {
regalloc(&nod1, n, Z);
gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */
gopcode(o, n->type, n, &nod1);
regfree(&nod1);
} else
gopcode(o, n->type, n, nodconst(0));
goto com;
}
regalloc(&nod, n, nn);
cgen(n, &nod);
if(typefd[n->type->etype]) {
regalloc(&nod1, n, Z);
gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */
gopcode(o, n->type, &nod, &nod1);
regfree(&nod1);
} else
gopcode(o, n->type, &nod, nodconst(0));
regfree(&nod);
goto com;
case OCONST:
o = vconst(n);
if(!true)
o = !o;
gbranch(OGOTO);
if(o) {
p1 = p;
gbranch(OGOTO);
patch(p1, pc);
}
goto com;
case OCOMMA:
cgen(l, Z);
boolgen(r, true, nn);
break;
case ONOT:
boolgen(l, !true, nn);
break;
case OCOND:
bcgen(l, 1);
p1 = p;
bcgen(r->left, true);
p2 = p;
gbranch(OGOTO);
patch(p1, pc);
p1 = p;
bcgen(r->right, !true);
patch(p2, pc);
p2 = p;
gbranch(OGOTO);
patch(p1, pc);
patch(p2, pc);
goto com;
case OANDAND:
if(!true)
goto caseor;
caseand:
bcgen(l, true);
p1 = p;
bcgen(r, !true);
p2 = p;
patch(p1, pc);
gbranch(OGOTO);
patch(p2, pc);
goto com;
case OOROR:
if(!true)
goto caseand;
caseor:
bcgen(l, !true);
p1 = p;
bcgen(r, !true);
p2 = p;
gbranch(OGOTO);
patch(p1, pc);
patch(p2, pc);
goto com;
case OEQ:
case ONE:
case OLE:
case OLT:
case OGE:
case OGT:
case OHI:
case OHS:
case OLO:
case OLS:
o = n->op;
if(true)
o = comrel[relindex(o)];
if(l->complex >= FNX && r->complex >= FNX) {
regret(&nod, r);
cgen(r, &nod);
regsalloc(&nod1, r);
gmove(&nod, &nod1);
regfree(&nod);
nod = *n;
nod.right = &nod1;
boolgen(&nod, true, nn);
break;
}
if(immconst(l)) {
o = invrel[relindex(o)];
/* bad, 13 is address of external that becomes constant */
if(r->addable < INDEXED || r->addable == 13) {
regalloc(&nod, r, nn);
cgen(r, &nod);
gopcode(o, l->type, &nod, l);
regfree(&nod);
} else
gopcode(o, l->type, r, l);
goto com;
}
if(typefd[l->type->etype])
o = invrel[relindex(logrel[relindex(o)])];
if(l->complex >= r->complex) {
regalloc(&nod, l, nn);
cgen(l, &nod);
if(r->addable < INDEXED || hardconst(r) || typefd[l->type->etype]) {
regalloc(&nod1, r, Z);
cgen(r, &nod1);
gopcode(o, l->type, &nod, &nod1);
regfree(&nod1);
} else
gopcode(o, l->type, &nod, r);
regfree(&nod);
goto com;
}
regalloc(&nod, r, nn);
cgen(r, &nod);
if(l->addable < INDEXED || l->addable == 13 || hardconst(l)) {
regalloc(&nod1, l, Z);
cgen(l, &nod1);
if(typechl[l->type->etype] && ewidth[l->type->etype] <= ewidth[TINT])
gopcode(o, types[TINT], &nod1, &nod);
else
gopcode(o, l->type, &nod1, &nod);
regfree(&nod1);
} else
gopcode(o, l->type, l, &nod);
regfree(&nod);
com:
if(nn != Z) {
p1 = p;
gmove(nodconst(1L), nn);
gbranch(OGOTO);
p2 = p;
patch(p1, pc);
gmove(nodconst(0L), nn);
patch(p2, pc);
}
break;
}
cursafe = curs;
}
void
sugen(Node *n, Node *nn, long w)
{
Prog *p1;
Node nod0, nod1, nod2, nod3, nod4, *l, *r;
Type *t;
int v, c, mt, mo;
vlong o0, o1;
if(n == Z || n->type == T)
return;
if(debug['g']) {
prtree(nn, "sugen lhs");
prtree(n, "sugen");
}
if(nn == nodrat)
if(w > nrathole)
nrathole = w;
switch(n->op) {
case OIND:
if(nn == Z) {
nullwarn(n->left, Z);
break;
}
default:
goto copy;
case OCONST:
goto copy;
case ODOT:
l = n->left;
sugen(l, nodrat, l->type->width);
if(nn == Z)
break;
warn(n, "non-interruptable temporary");
nod1 = *nodrat;
r = n->right;
if(!r || r->op != OCONST) {
diag(n, "DOT and no offset");
break;
}
nod1.xoffset += (long)r->vconst;
nod1.type = n->type;
sugen(&nod1, nn, w);
break;
case OSTRUCT:
/*
* rewrite so lhs has no fn call
*/
if(nn != Z && side(nn)) {
nod1 = *n;
nod1.type = typ(TIND, n->type);
regret(&nod2, &nod1);
lcgen(nn, &nod2);
regsalloc(&nod0, &nod1);
cgen(&nod2, &nod0);
regfree(&nod2);
nod1 = *n;
nod1.op = OIND;
nod1.left = &nod0;
nod1.right = Z;
nod1.complex = 1;
sugen(n, &nod1, w);
return;
}
r = n->left;
for(t = n->type->link; t != T; t = t->down) {
l = r;
if(r->op == OLIST) {
l = r->left;
r = r->right;
}
if(nn == Z) {
cgen(l, nn);
continue;
}
/*
* hand craft *(&nn + o) = l
*/
nod0 = znode;
nod0.op = OAS;
nod0.type = t;
nod0.left = &nod1;
nod0.right = nil;
nod1 = znode;
nod1.op = OIND;
nod1.type = t;
nod1.left = &nod2;
nod2 = znode;
nod2.op = OADD;
nod2.type = typ(TIND, t);
nod2.left = &nod3;
nod2.right = &nod4;
nod3 = znode;
nod3.op = OADDR;
nod3.type = nod2.type;
nod3.left = nn;
nod4 = znode;
nod4.op = OCONST;
nod4.type = nod2.type;
nod4.vconst = t->offset;
ccom(&nod0);
acom(&nod0);
xcom(&nod0);
nod0.addable = 0;
nod0.right = l;
/* prtree(&nod0, "hand craft"); /* */
cgen(&nod0, Z);
}
break;
case OAS:
if(nn == Z) {
if(n->addable < INDEXED)
sugen(n->right, n->left, w);
break;
}
sugen(n->right, nodrat, w);
warn(n, "non-interruptable temporary");
sugen(nodrat, n->left, w);
sugen(nodrat, nn, w);
break;
case OFUNC:
if(nn == Z) {
sugen(n, nodrat, w);
break;
}
if(nn->op != OIND) {
nn = new1(OADDR, nn, Z);
nn->type = types[TIND];
nn->addable = 0;
} else
nn = nn->left;
n = new(OFUNC, n->left, new(OLIST, nn, n->right));
n->complex = FNX;
n->type = types[TVOID];
n->left->type = types[TVOID];
cgen(n, Z);
break;
case OCOND:
bcgen(n->left, 1);
p1 = p;
sugen(n->right->left, nn, w);
gbranch(OGOTO);
patch(p1, pc);
p1 = p;
sugen(n->right->right, nn, w);
patch(p1, pc);
break;
case OCOMMA:
cgen(n->left, Z);
sugen(n->right, nn, w);
break;
}
return;
copy:
if(nn == Z) {
switch(n->op) {
case OASADD:
case OASSUB:
case OASAND:
case OASOR:
case OASXOR:
case OASMUL:
case OASLMUL:
case OASASHL:
case OASASHR:
case OASLSHR:
break;
case OPOSTINC:
case OPOSTDEC:
case OPREINC:
case OPREDEC:
break;
default:
return;
}
}
if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
t = nn->type;
nn->type = types[TLONG];
regialloc(&nod1, nn, Z);
lcgen(nn, &nod1);
regsalloc(&nod2, &nod1);
nn->type = t;
gins(AMOVQ, &nod1, &nod2);
regfree(&nod1);
nod2.type = typ(TIND, t);
nod1 = nod2;
nod1.op = OIND;
nod1.left = &nod2;
nod1.right = Z;
nod1.complex = 1;
nod1.type = t;
sugen(n, &nod1, w);
return;
}
c = cursafe;
if(w <= 32) {
if(n->left != Z && n->left->complex >= FNX
&& n->right != Z && n->right->complex >= FNX) {
regsalloc(&nod1, n->right);
cgen(n->right, &nod1);
nod2 = *n;
nod2.right = &nod1;
cgen(&nod2, nn);
cursafe = c;
return;
}
if(w & 7) {
mt = TLONG;
mo = AMOVL;
} else {
mt = TVLONG;
mo = AMOVQ;
}
if(n->complex > nn->complex) {
t = n->type;
n->type = types[mt];
regalloc(&nod0, n, Z);
if(!vaddr(n, 0)) {
reglcgen(&nod1, n, Z);
n->type = t;
n = &nod1;
}
else
n->type = t;
t = nn->type;
nn->type = types[mt];
if(!vaddr(nn, 0)) {
reglcgen(&nod2, nn, Z);
nn->type = t;
nn = &nod2;
}
else
nn->type = t;
} else {
t = nn->type;
nn->type = types[mt];
regalloc(&nod0, nn, Z);
if(!vaddr(nn, 0)) {
reglcgen(&nod2, nn, Z);
nn->type = t;
nn = &nod2;
}
else
nn->type = t;
t = n->type;
n->type = types[mt];
if(!vaddr(n, 0)) {
reglcgen(&nod1, n, Z);
n->type = t;
n = &nod1;
}
else
n->type = t;
}
o0 = n->xoffset;
o1 = nn->xoffset;
w /= ewidth[mt];
while(--w >= 0) {
gins(mo, n, &nod0);
gins(mo, &nod0, nn);
n->xoffset += ewidth[mt];
nn->xoffset += ewidth[mt];
}
n->xoffset = o0;
nn->xoffset = o1;
if(nn == &nod2)
regfree(&nod2);
if(n == &nod1)
regfree(&nod1);
regfree(&nod0);
return;
}
t = n->type;
if(t != types[TIND]){
n->type = types[TIND];
sugen(n, nn, w);
n->type = t;
return;
}
t = nn->type;
if(t != types[TIND]){
nn->type = types[TIND];
sugen(n, nn, w);
nn->type = t;
return;
}
if(nodreg(&nod1, n, D_SI)) {
regsalloc(&nod4, &nod1);
gmove(&nod1, &nod4);
v = reg[D_SI];
reg[D_SI] = 0;
sugen(n, nn, w);
reg[D_SI] = v;
gmove(&nod4, &nod1);
cursafe = c;
return;
}
if(nodreg(&nod2, nn, D_DI)) {
regsalloc(&nod4, &nod2);
gmove(&nod2, &nod4);
v = reg[D_DI];
reg[D_DI] = 0;
sugen(n, nn, w);
reg[D_DI] = v;
gmove(&nod4, &nod2);
cursafe = c;
return;
}
if(nodreg(&nod3, Z, D_CX)) {
regsalloc(&nod4, &nod3);
gmove(&nod3, &nod4);
v = reg[D_CX];
reg[D_CX] = 0;
sugen(n, nn, w);
reg[D_CX] = v;
gmove(&nod4, &nod3);
cursafe = c;
return;
}
if(n->complex > nn->complex){
reg[nod1.reg]++;
lcgen(n, &nod1);
reg[nod2.reg]++;
lcgen(nn, &nod2);
} else {
reg[nod2.reg]++;
lcgen(nn, &nod2);
reg[nod1.reg]++;
lcgen(n, &nod1);
}
reg[nod3.reg]++;
gins(AMOVL, nodconst(w/SZ_LONG), &nod3);
gins(ACLD, Z, Z);
gins(AREP, Z, Z);
gins(AMOVSL, Z, Z);
if(w & (SZ_LONG-1)) {
/* odd length of packed structure */
gins(AMOVL, nodconst(w & (SZ_LONG-1)), &nod3);
gins(AREP, Z, Z);
gins(AMOVSB, Z, Z);
}
reg[nod3.reg]--;
reg[nod2.reg]--;
reg[nod1.reg]--;
}
/*
* TO DO
*/
void
layout(Node *f, Node *t, int c, int cv, Node *cn)
{
Node t1, t2;
while(c > 3) {
layout(f, t, 2, 0, Z);
c -= 2;
}
regalloc(&t1, &lregnode, Z);
regalloc(&t2, &lregnode, Z);
if(c > 0) {
gmove(f, &t1);
f->xoffset += SZ_INT;
}
if(cn != Z)
gmove(nodconst(cv), cn);
if(c > 1) {
gmove(f, &t2);
f->xoffset += SZ_INT;
}
if(c > 0) {
gmove(&t1, t);
t->xoffset += SZ_INT;
}
if(c > 2) {
gmove(f, &t1);
f->xoffset += SZ_INT;
}
if(c > 1) {
gmove(&t2, t);
t->xoffset += SZ_INT;
}
if(c > 2) {
gmove(&t1, t);
t->xoffset += SZ_INT;
}
regfree(&t1);
regfree(&t2);
}
/*
* constant is not vlong or fits as 32-bit signed immediate
*/
int
immconst(Node *n)
{
long v;
if(n->op != OCONST || !typechlpv[n->type->etype])
return 0;
if(typechl[n->type->etype])
return 1;
v = n->vconst;
return n->vconst == (vlong)v;
}
/*
* if a constant and vlong, doesn't fit as 32-bit signed immediate
*/
int
hardconst(Node *n)
{
return n->op == OCONST && !immconst(n);
}
/*
* casting up to t2 covers an intermediate cast to t1
*/
int
castup(Type *t1, Type *t2)
{
int ft;
if(!nilcast(t1, t2))
return 0;
/* known to be small to large */
ft = t1->etype;
switch(t2->etype){
case TINT:
case TLONG:
return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR;
case TUINT:
case TULONG:
return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR;
case TVLONG:
return ft == TLONG || ft == TINT || ft == TSHORT;
case TUVLONG:
return ft == TULONG || ft == TUINT || ft == TUSHORT;
}
return 0;
}
void
zeroregm(Node *n)
{
gins(AMOVL, nodconst(0), n);
}
/* do we need to load the address of a vlong? */
int
vaddr(Node *n, int a)
{
switch(n->op) {
case ONAME:
if(a)
return 1;
return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
case OCONST:
case OREGISTER:
case OINDREG:
return 1;
}
return 0;
}
long
hi64v(Node *n)
{
if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
return (long)(n->vconst) & ~0L;
else
return (long)((uvlong)n->vconst>>32) & ~0L;
}
long
lo64v(Node *n)
{
if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
return (long)((uvlong)n->vconst>>32) & ~0L;
else
return (long)(n->vconst) & ~0L;
}
Node *
hi64(Node *n)
{
return nodconst(hi64v(n));
}
Node *
lo64(Node *n)
{
return nodconst(lo64v(n));
}
int
cond(int op)
{
switch(op) {
case OANDAND:
case OOROR:
case ONOT:
return 1;
case OEQ:
case ONE:
case OLE:
case OLT:
case OGE:
case OGT:
case OHI:
case OHS:
case OLO:
case OLS:
return 1;
}
return 0;
}