plan9fox/sys/src/cmd/vc/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

1211 lines
20 KiB
C

#include "gc.h"
static void genasop(int, Node*, Node*, Node*);
void
cgen(Node *n, Node *nn)
{
Node *l, *r;
Prog *p1;
Node nod, nod1, nod2, nod3, nod4;
int o;
long v, curs;
if(debug['g']) {
prtree(nn, "cgen lhs");
prtree(n, "cgen");
}
if(n == Z || n->type == T)
return;
if(typesuv[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(n->complex >= FNX)
if(l->complex >= FNX)
if(r != Z && r->complex >= FNX)
switch(o) {
default:
regret(&nod, r);
cgen(r, &nod);
regsalloc(&nod1, r);
gopcode(OAS, &nod, Z, &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;
}
switch(o) {
default:
diag(n, "unknown op in cgen: %O", o);
break;
case OAS:
if(l->op == OBIT)
goto bitas;
if(l->addable >= INDEXED && l->complex < FNX) {
if(nn != Z || r->addable < INDEXED) {
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) {
reglcgen(&nod1, l, Z);
if(r->addable >= INDEXED) {
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);
gopcode(OAS, &nod1, Z, &nod2);
bitstore(l, &nod, &nod1, &nod2, nn);
break;
case OBIT:
if(nn == Z) {
nullwarn(l, Z);
break;
}
bitload(n, &nod, Z, Z, nn);
gopcode(OAS, &nod, Z, nn);
regfree(&nod);
break;
case OADD:
case OSUB:
case OAND:
case OOR:
case OXOR:
case OLSHR:
case OASHL:
case OASHR:
/*
* immediate operands
*/
if(nn != Z)
if(r->op == OCONST)
if(!typefd[n->type->etype]) {
cgen(l, nn);
if(r->vconst == 0)
if(o != OAND)
break;
if(nn != Z)
gopcode(o, r, Z, nn);
break;
}
case OLMUL:
case OLDIV:
case OLMOD:
case OMUL:
case ODIV:
case OMOD:
if(nn == Z) {
nullwarn(l, r);
break;
}
if(o == OMUL || o == OLMUL) {
if(mulcon(n, nn))
break;
}
if(l->complex >= r->complex) {
regalloc(&nod, l, nn);
cgen(l, &nod);
regalloc(&nod1, r, Z);
cgen(r, &nod1);
gopcode(o, &nod1, Z, &nod);
} else {
regalloc(&nod, r, nn);
cgen(r, &nod);
regalloc(&nod1, l, Z);
cgen(l, &nod1);
gopcode(o, &nod, &nod1, &nod);
}
gopcode(OAS, &nod, Z, nn);
regfree(&nod);
regfree(&nod1);
break;
case OASLSHR:
case OASASHL:
case OASASHR:
case OASAND:
case OASADD:
case OASSUB:
case OASXOR:
case OASOR:
if(l->op == OBIT)
goto asbitop;
if(r->op == OCONST)
if(!typefd[r->type->etype])
if(!typefd[n->type->etype]) {
if(l->addable < INDEXED)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
regalloc(&nod, l, nn);
gopcode(OAS, &nod2, Z, &nod);
gopcode(o, r, Z, &nod);
gopcode(OAS, &nod, Z, &nod2);
regfree(&nod);
if(l->addable < INDEXED)
regfree(&nod2);
break;
}
genasop(o, l, r, nn);
break;
case OASLMUL:
case OASLDIV:
case OASLMOD:
case OASMUL:
case OASDIV:
case OASMOD:
if(l->op == OBIT)
goto asbitop;
genasop(o, l, r, nn);
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);
gopcode(o, &nod3, Z, &nod4);
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);
gopcode(OAS, &nod, Z, &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, Z);
gopcode(OFUNC, Z, Z, &nod);
regfree(&nod);
} else
gopcode(OFUNC, Z, Z, l);
if(REGARG)
if(o != reg[REGARG])
reg[REGARG]--;
if(nn != Z) {
regret(&nod, n);
gopcode(OAS, &nod, Z, 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);
gopcode(OAS, &nod, Z, 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)) {
if(nocast(n->type, nn->type)) {
cgen(l, nn);
break;
}
}
regalloc(&nod, l, nn);
cgen(l, &nod);
regalloc(&nod1, n, &nod);
gopcode(OAS, &nod, Z, &nod1);
gopcode(OAS, &nod1, Z, nn);
regfree(&nod1);
regfree(&nod);
break;
case ODOT:
sugen(l, nodrat, l->type->width);
if(nn != Z) {
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(l->addable < INDEXED)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
regalloc(&nod, l, nn);
gopcode(OAS, &nod2, Z, &nod);
if(nn != Z)
gmove(&nod, nn);
regalloc(&nod1, l, Z);
if(typefd[l->type->etype]) {
regalloc(&nod3, l, Z);
if(v < 0) {
gopcode(OAS, nodfconst(-v), Z, &nod3);
gopcode(OSUB, &nod3, &nod, &nod1);
} else {
gopcode(OAS, nodfconst(v), Z, &nod3);
gopcode(OADD, &nod3, &nod, &nod1);
}
regfree(&nod3);
} else
gopcode(OADD, nodconst(v), &nod, &nod1);
gopcode(OAS, &nod1, Z, &nod2);
regfree(&nod);
regfree(&nod1);
if(l->addable < INDEXED)
regfree(&nod2);
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(l->addable < INDEXED)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
regalloc(&nod, l, nn);
gopcode(OAS, &nod2, Z, &nod);
if(typefd[l->type->etype]) {
regalloc(&nod3, l, Z);
if(v < 0) {
gopcode(OAS, nodfconst(-v), Z, &nod3);
gopcode(OSUB, &nod3, Z, &nod);
} else {
gopcode(OAS, nodfconst(v), Z, &nod3);
gopcode(OADD, &nod3, Z, &nod);
}
regfree(&nod3);
} else
gopcode(OADD, nodconst(v), Z, &nod);
gopcode(OAS, &nod, Z, &nod2);
if(nn != Z) {
gmove(&nod, nn);
if(l->op == ONAME) /* in x=++i, emit USED(i) */
gins(ANOP, l, Z);
}
regfree(&nod);
if(l->addable < INDEXED)
regfree(&nod2);
break;
bitinc:
if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
bitload(l, &nod, &nod1, &nod2, Z);
gopcode(OAS, &nod, Z, nn);
gopcode(OADD, nodconst(v), Z, &nod);
bitstore(l, &nod, &nod1, &nod2, Z);
break;
}
bitload(l, &nod, &nod1, &nod2, nn);
gopcode(OADD, nodconst(v), Z, &nod);
bitstore(l, &nod, &nod1, &nod2, nn);
break;
}
cursafe = curs;
}
static void
genasop(int o, Node *l, Node *r, Node *nn)
{
Node nod, nod1, nod2;
int hardleft;
hardleft = l->addable < INDEXED || l->complex >= FNX;
if(l->complex >= r->complex) {
if(hardleft)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
regalloc(&nod1, r, Z);
cgen(r, &nod1);
} else {
regalloc(&nod1, r, Z);
cgen(r, &nod1);
if(hardleft)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
}
if(nod1.type == nod2.type || !typefd[nod1.type->etype])
regalloc(&nod, &nod2, nn);
else
regalloc(&nod, &nod1, Z);
gmove(&nod2, &nod);
gopcode(o, &nod1, Z, &nod);
gmove(&nod, &nod2);
if(nn != Z)
gmove(&nod2, nn);
regfree(&nod);
regfree(&nod1);
if(hardleft)
regfree(&nod2);
}
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;
}
nod = *n;
nod.op = OADDR;
nod.left = n;
nod.right = Z;
nod.type = types[TIND];
gopcode(OAS, &nod, Z, 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:
regalloc(&nod, n, nn);
cgen(n, &nod);
if(nn == Z || typefd[n->type->etype]) {
o = ONE;
if(true)
o = comrel[relindex(o)];
if(typefd[n->type->etype]) {
nodreg(&nod1, n, NREG+FREGZERO);
gopcode(o, &nod, &nod1, Z);
} else
gopcode(o, &nod, Z, Z);
regfree(&nod);
goto com;
}
if(true)
gopcode(OCOND, &nod, nodconst(0), &nod);
else
gopcode(OCOND, nodconst(1), &nod, &nod);
gopcode(OAS, &nod, Z, nn);
regfree(&nod);
break;
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);
gopcode(OAS, &nod, Z, &nod1);
regfree(&nod);
nod = *n;
nod.right = &nod1;
boolgen(&nod, true, nn);
break;
}
if(nn != Z && !typefd[l->type->etype]) {
if(l->complex >= r->complex) {
regalloc(&nod1, l, nn);
cgen(l, &nod1);
regalloc(&nod, r, Z);
cgen(r, &nod);
} else {
regalloc(&nod, r, nn);
cgen(r, &nod);
regalloc(&nod1, l, Z);
cgen(l, &nod1);
}
switch(o) {
case OEQ:
gopcode(OSUB, &nod1, &nod, &nod);
gopcode(OCOND, &nod, nodconst(0), &nod);
break;
case ONE:
gopcode(OSUB, &nod1, &nod, &nod);
gopcode(OCOND, nodconst(1), &nod, &nod);
break;
case OLE:
gopcode(OCOMMA, &nod1, &nod, &nod);
break;
case OGT:
gopcode(OCOMMA, &nod1, &nod, &nod);
gopcode(OXOR, nodconst(1), &nod, &nod);
break;
case OLT:
gopcode(OCOMMA, &nod, &nod1, &nod);
gopcode(OXOR, nodconst(1), &nod, &nod);
break;
case OGE:
gopcode(OCOMMA, &nod, &nod1, &nod);
break;
case OLS:
gopcode(OCOND, &nod1, &nod, &nod);
break;
case OHI:
gopcode(OCOND, &nod1, &nod, &nod);
gopcode(OXOR, nodconst(1), &nod, &nod);
break;
case OLO:
gopcode(OCOND, &nod, &nod1, &nod);
gopcode(OXOR, nodconst(1), &nod, &nod);
break;
case OHS:
gopcode(OCOND, &nod, &nod1, &nod);
break;
}
gopcode(OAS, &nod, Z, nn);
regfree(&nod);
regfree(&nod1);
break;
}
if(sconst(l)) {
switch(o) {
default:
if(l->vconst != 0)
break;
case OGT:
case OHI:
case OLE:
case OLS:
regalloc(&nod, r, nn);
cgen(r, &nod);
gopcode(o, l, &nod, Z);
regfree(&nod);
goto com;
}
}
if(sconst(r)) {
switch(o) {
default:
if(r->vconst != 0)
break;
case OGE:
case OHS:
case OLT:
case OLO:
regalloc(&nod, l, nn);
cgen(l, &nod);
gopcode(o, &nod, r, Z);
regfree(&nod);
goto com;
}
}
if(l->complex >= r->complex) {
regalloc(&nod1, l, nn);
cgen(l, &nod1);
regalloc(&nod, r, Z);
cgen(r, &nod);
} else {
regalloc(&nod, r, nn);
cgen(r, &nod);
regalloc(&nod1, l, Z);
cgen(l, &nod1);
}
gopcode(o, &nod1, &nod, Z);
regfree(&nod);
regfree(&nod1);
com:
if(nn != Z) {
p1 = p;
gopcode(OAS, nodconst(1), Z, nn);
gbranch(OGOTO);
p2 = p;
patch(p1, pc);
gopcode(OAS, nodconst(0), Z, 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;
long pc1;
int i, m, c;
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:
if(n->type && typev[n->type->etype]) {
if(nn == Z) {
nullwarn(n->left, Z);
break;
}
t = nn->type;
nn->type = types[TLONG];
reglcgen(&nod1, nn, Z);
nn->type = t;
if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
else
gopcode(OAS, nod32const(n->vconst), Z, &nod1);
nod1.xoffset += SZ_LONG;
if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
gopcode(OAS, nod32const(n->vconst), Z, &nod1);
else
gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
regfree(&nod1);
break;
}
goto copy;
case ODOT:
l = n->left;
sugen(l, nodrat, l->type->width);
if(nn != Z) {
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 side effects
*/
if(nn != Z && side(nn)) {
nod1 = *n;
nod1.type = typ(TIND, n->type);
regalloc(&nod2, &nod1, Z);
lcgen(nn, &nod2);
regsalloc(&nod0, &nod1);
gopcode(OAS, &nod2, Z, &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 = l;
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;
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)
return;
if(n->complex >= FNX && nn->complex >= FNX) {
t = nn->type;
nn->type = types[TLONG];
regialloc(&nod1, nn, Z);
lcgen(nn, &nod1);
regsalloc(&nod2, &nod1);
nn->type = t;
gopcode(OAS, &nod1, Z, &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;
}
if(n->complex > nn->complex) {
t = n->type;
n->type = types[TLONG];
reglcgen(&nod1, n, Z);
n->type = t;
t = nn->type;
nn->type = types[TLONG];
reglcgen(&nod2, nn, Z);
nn->type = t;
} else {
t = nn->type;
nn->type = types[TLONG];
reglcgen(&nod2, nn, Z);
nn->type = t;
t = n->type;
n->type = types[TLONG];
reglcgen(&nod1, n, Z);
n->type = t;
}
w /= SZ_LONG;
if(w <= 5) {
layout(&nod1, &nod2, w, 0, Z);
goto out;
}
/*
* minimize space for unrolling loop
* 3,4,5 times. (6 or more is never minimum)
* if small structure, try 2 also.
*/
c = 0; /* set */
m = 100;
i = 3;
if(w <= 15)
i = 2;
for(; i<=5; i++)
if(i + w%i <= m) {
c = i;
m = c + w%c;
}
regalloc(&nod3, &regnode, Z);
layout(&nod1, &nod2, w%c, w/c, &nod3);
pc1 = pc;
layout(&nod1, &nod2, c, 0, Z);
gopcode(OSUB, nodconst(1), Z, &nod3);
nod1.op = OREGISTER;
gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1);
nod2.op = OREGISTER;
gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2);
gopcode(OEQ, &nod3, Z, Z);
p->as = ABGTZ;
patch(p, pc1);
regfree(&nod3);
out:
regfree(&nod1);
regfree(&nod2);
}
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, &regnode, Z);
regalloc(&t2, &regnode, Z);
t1.type = types[TLONG];
t2.type = types[TLONG];
if(c > 0) {
gopcode(OAS, f, Z, &t1);
f->xoffset += SZ_LONG;
}
if(cn != Z)
gopcode(OAS, nodconst(cv), Z, cn);
if(c > 1) {
gopcode(OAS, f, Z, &t2);
f->xoffset += SZ_LONG;
}
if(c > 0) {
gopcode(OAS, &t1, Z, t);
t->xoffset += SZ_LONG;
}
if(c > 2) {
gopcode(OAS, f, Z, &t1);
f->xoffset += SZ_LONG;
}
if(c > 1) {
gopcode(OAS, &t2, Z, t);
t->xoffset += SZ_LONG;
}
if(c > 2) {
gopcode(OAS, &t1, Z, t);
t->xoffset += SZ_LONG;
}
regfree(&t1);
regfree(&t2);
}