#include "gc.h" voidnoretval(int n){ if(n & 1) { gins(ANOP, Z, Z); p->to.type = REGRET; } if(n & 2) { gins(ANOP, Z, Z); p->to.type = FREGRET; }} /* welcome to commute */static voidcommute(Node *n){ Node *l, *r; l = n->left; r = n->right; if(r->complex > l->complex) { n->left = r; n->right = l; }} voidindexshift(Node *n){ int g; if(!typechlpv[n->type->etype]) return; simplifyshift(n); if(n->op == OASHL && n->right->op == OCONST){ g = vconst(n->right); if(g >= 0 && g <= 3) n->addable = 7; }} /* * calculate addressability as follows * NAME ==> 10/11 name+value(SB/SP) * REGISTER ==> 12 register * CONST ==> 20 $value * *(20) ==> 21 value * &(10) ==> 13 $name+value(SB) * &(11) ==> 1 $name+value(SP) * (13) + (20) ==> 13 fold constants * (1) + (20) ==> 1 fold constants * *(13) ==> 10 back to name * *(1) ==> 11 back to name * * (20) * (X) ==> 7 multiplier in indexing * (X,7) + (13,1) ==> 8 adder in indexing (addresses) * (8) ==> &9(OINDEX) index, almost addressable * * calculate complexity (number of registers) */voidxcom(Node *n){ Node *l, *r; int g; if(n == Z) return; l = n->left; r = n->right; n->complex = 0; n->addable = 0; switch(n->op) { case OCONST: n->addable = 20; break; case ONAME: n->addable = 10; if(n->class == CPARAM || n->class == CAUTO) n->addable = 11; break; case OREGISTER: n->addable = 12; break; case OINDREG: n->addable = 12; break; case OADDR: xcom(l); if(l->addable == 10) n->addable = 13; else if(l->addable == 11) n->addable = 1; break; case OADD: xcom(l); xcom(r); if(n->type->etype != TIND) break; switch(r->addable) { case 20: switch(l->addable) { case 1: case 13: commadd: l->type = n->type; *n = *l; l = new(0, Z, Z); *l = *(n->left); l->xoffset += r->vconst; n->left = l; r = n->right; goto brk; } break; case 1: case 13: case 10: case 11: /* l is the base, r is the index */ if(l->addable != 20) n->addable = 8; break; } switch(l->addable) { case 20: switch(r->addable) { case 13: case 1: r = n->left; l = n->right; n->left = l; n->right = r; goto commadd; } break; case 13: case 1: case 10: case 11: /* r is the base, l is the index */ if(r->addable != 20) n->addable = 8; break; } if(n->addable == 8 && !side(n)) { indx(n); l = new1(OINDEX, idx.basetree, idx.regtree); l->scale = idx.scale; l->addable = 9; l->complex = l->right->complex; l->type = l->left->type; n->op = OADDR; n->left = l; n->right = Z; n->addable = 8; break; } break; case OINDEX: xcom(l); xcom(r); n->addable = 9; break; case OIND: xcom(l); if(l->op == OADDR) { l = l->left; l->type = n->type; *n = *l; return; } switch(l->addable) { case 20: n->addable = 21; break; case 1: n->addable = 11; break; case 13: n->addable = 10; break; } break; case OASHL: xcom(l); xcom(r); indexshift(n); break; case OMUL: case OLMUL: xcom(l); xcom(r); g = vlog(l); if(g >= 0) { n->left = r; n->right = l; l = r; r = n->right; } g = vlog(r); if(g >= 0) { n->op = OASHL; r->vconst = g; r->type = types[TINT]; indexshift(n); break; } commute(n); break; case OASLDIV: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OASLSHR; r->vconst = g; r->type = types[TINT]; } break; case OLDIV: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OLSHR; r->vconst = g; r->type = types[TINT]; indexshift(n); break; } break; case OASLMOD: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OASAND; r->vconst--; } break; case OLMOD: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OAND; r->vconst--; } break; case OASMUL: case OASLMUL: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OASASHL; r->vconst = g; } break; case OLSHR: case OASHR: xcom(l); xcom(r); indexshift(n); break; default: if(l != Z) xcom(l); if(r != Z) xcom(r); break; }brk: if(n->addable >= 10) return; if(l != Z) n->complex = l->complex; if(r != Z) { if(r->complex == n->complex) n->complex = r->complex+1; else if(r->complex > n->complex) n->complex = r->complex; } if(n->complex == 0) n->complex++; switch(n->op) { case OFUNC: n->complex = FNX; break; case OCAST: if(l->type->etype == TUVLONG && typefd[n->type->etype]) n->complex += 2; break; case OLMOD: case OMOD: case OLMUL: case OLDIV: case OMUL: case ODIV: case OASLMUL: case OASLDIV: case OASLMOD: case OASMUL: case OASDIV: case OASMOD: if(r->complex >= l->complex) { n->complex = l->complex + 3; if(r->complex > n->complex) n->complex = r->complex; } else { n->complex = r->complex + 3; if(l->complex > n->complex) n->complex = l->complex; } break; case OLSHR: case OASHL: case OASHR: case OASLSHR: case OASASHL: case OASASHR: if(r->complex >= l->complex) { n->complex = l->complex + 2; if(r->complex > n->complex) n->complex = r->complex; } else { n->complex = r->complex + 2; if(l->complex > n->complex) n->complex = l->complex; } break; case OADD: case OXOR: case OAND: case OOR: /* * immediate operators, make const on right */ if(l->op == OCONST) { n->left = r; n->right = l; } break; case OEQ: case ONE: case OLE: case OLT: case OGE: case OGT: case OHI: case OHS: case OLO: case OLS: /* * compare operators, make const on left */ if(r->op == OCONST) { n->left = r; n->right = l; n->op = invrel[relindex(n->op)]; } break; }} voidindx(Node *n){ Node *l, *r; if(debug['x']) prtree(n, "indx"); l = n->left; r = n->right; if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) { n->right = l; n->left = r; l = r; r = n->right; } if(l->addable != 7) { idx.regtree = l; idx.scale = 1; } else if(l->right->addable == 20) { idx.regtree = l->left; idx.scale = 1 << l->right->vconst; } else if(l->left->addable == 20) { idx.regtree = l->right; idx.scale = 1 << l->left->vconst; } else diag(n, "bad index"); idx.basetree = r; if(debug['x']) { print("scale = %d\n", idx.scale); prtree(idx.regtree, "index"); prtree(idx.basetree, "base"); }}
#include "gc.h"
void
noretval(int n)
{
if(n & 1) {
gins(ANOP, Z, Z);
p->to.type = REGRET;
}
if(n & 2) {
gins(ANOP, Z, Z);
p->to.type = FREGRET;
}
}
/* welcome to commute */
static void
commute(Node *n)
{
Node *l, *r;
l = n->left;
r = n->right;
if(r->complex > l->complex) {
n->left = r;
n->right = l;
}
}
void
indexshift(Node *n)
{
int g;
if(!typechlpv[n->type->etype])
return;
simplifyshift(n);
if(n->op == OASHL && n->right->op == OCONST){
g = vconst(n->right);
if(g >= 0 && g <= 3)
n->addable = 7;
}
}
/*
* calculate addressability as follows
* NAME ==> 10/11 name+value(SB/SP)
* REGISTER ==> 12 register
* CONST ==> 20 $value
* *(20) ==> 21 value
* &(10) ==> 13 $name+value(SB)
* &(11) ==> 1 $name+value(SP)
* (13) + (20) ==> 13 fold constants
* (1) + (20) ==> 1 fold constants
* *(13) ==> 10 back to name
* *(1) ==> 11 back to name
*
* (20) * (X) ==> 7 multiplier in indexing
* (X,7) + (13,1) ==> 8 adder in indexing (addresses)
* (8) ==> &9(OINDEX) index, almost addressable
*
* calculate complexity (number of registers)
*/
void
xcom(Node *n)
{
Node *l, *r;
int g;
if(n == Z)
return;
l = n->left;
r = n->right;
n->complex = 0;
n->addable = 0;
switch(n->op) {
case OCONST:
n->addable = 20;
break;
case ONAME:
n->addable = 10;
if(n->class == CPARAM || n->class == CAUTO)
n->addable = 11;
break;
case OREGISTER:
n->addable = 12;
break;
case OINDREG:
n->addable = 12;
break;
case OADDR:
xcom(l);
if(l->addable == 10)
n->addable = 13;
else
if(l->addable == 11)
n->addable = 1;
break;
case OADD:
xcom(l);
xcom(r);
if(n->type->etype != TIND)
break;
switch(r->addable) {
case 20:
switch(l->addable) {
case 1:
case 13:
commadd:
l->type = n->type;
*n = *l;
l = new(0, Z, Z);
*l = *(n->left);
l->xoffset += r->vconst;
n->left = l;
r = n->right;
goto brk;
}
break;
case 1:
case 13:
case 10:
case 11:
/* l is the base, r is the index */
if(l->addable != 20)
n->addable = 8;
break;
}
switch(l->addable) {
case 20:
switch(r->addable) {
case 13:
case 1:
r = n->left;
l = n->right;
n->left = l;
n->right = r;
goto commadd;
}
break;
case 13:
case 1:
case 10:
case 11:
/* r is the base, l is the index */
if(r->addable != 20)
n->addable = 8;
break;
}
if(n->addable == 8 && !side(n)) {
indx(n);
l = new1(OINDEX, idx.basetree, idx.regtree);
l->scale = idx.scale;
l->addable = 9;
l->complex = l->right->complex;
l->type = l->left->type;
n->op = OADDR;
n->left = l;
n->right = Z;
n->addable = 8;
break;
}
break;
case OINDEX:
xcom(l);
xcom(r);
n->addable = 9;
break;
case OIND:
xcom(l);
if(l->op == OADDR) {
l = l->left;
l->type = n->type;
*n = *l;
return;
}
switch(l->addable) {
case 20:
n->addable = 21;
break;
case 1:
n->addable = 11;
break;
case 13:
n->addable = 10;
break;
}
break;
case OASHL:
xcom(l);
xcom(r);
indexshift(n);
break;
case OMUL:
case OLMUL:
xcom(l);
xcom(r);
g = vlog(l);
if(g >= 0) {
n->left = r;
n->right = l;
l = r;
r = n->right;
}
g = vlog(r);
if(g >= 0) {
n->op = OASHL;
r->vconst = g;
r->type = types[TINT];
indexshift(n);
break;
}
commute(n);
break;
case OASLDIV:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OASLSHR;
r->vconst = g;
r->type = types[TINT];
}
break;
case OLDIV:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OLSHR;
r->vconst = g;
r->type = types[TINT];
indexshift(n);
break;
}
break;
case OASLMOD:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OASAND;
r->vconst--;
}
break;
case OLMOD:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OAND;
r->vconst--;
}
break;
case OASMUL:
case OASLMUL:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OASASHL;
r->vconst = g;
}
break;
case OLSHR:
case OASHR:
xcom(l);
xcom(r);
indexshift(n);
break;
default:
if(l != Z)
xcom(l);
if(r != Z)
xcom(r);
break;
}
brk:
if(n->addable >= 10)
return;
if(l != Z)
n->complex = l->complex;
if(r != Z) {
if(r->complex == n->complex)
n->complex = r->complex+1;
else
if(r->complex > n->complex)
n->complex = r->complex;
}
if(n->complex == 0)
n->complex++;
switch(n->op) {
case OFUNC:
n->complex = FNX;
break;
case OCAST:
if(l->type->etype == TUVLONG && typefd[n->type->etype])
n->complex += 2;
break;
case OLMOD:
case OMOD:
case OLMUL:
case OLDIV:
case OMUL:
case ODIV:
case OASLMUL:
case OASLDIV:
case OASLMOD:
case OASMUL:
case OASDIV:
case OASMOD:
if(r->complex >= l->complex) {
n->complex = l->complex + 3;
if(r->complex > n->complex)
n->complex = r->complex;
} else {
n->complex = r->complex + 3;
if(l->complex > n->complex)
n->complex = l->complex;
}
break;
case OLSHR:
case OASHL:
case OASHR:
case OASLSHR:
case OASASHL:
case OASASHR:
if(r->complex >= l->complex) {
n->complex = l->complex + 2;
if(r->complex > n->complex)
n->complex = r->complex;
} else {
n->complex = r->complex + 2;
if(l->complex > n->complex)
n->complex = l->complex;
}
break;
case OADD:
case OXOR:
case OAND:
case OOR:
/*
* immediate operators, make const on right
*/
if(l->op == OCONST) {
n->left = r;
n->right = l;
}
break;
case OEQ:
case ONE:
case OLE:
case OLT:
case OGE:
case OGT:
case OHI:
case OHS:
case OLO:
case OLS:
/*
* compare operators, make const on left
*/
if(r->op == OCONST) {
n->left = r;
n->right = l;
n->op = invrel[relindex(n->op)];
}
break;
}
}
void
indx(Node *n)
{
Node *l, *r;
if(debug['x'])
prtree(n, "indx");
l = n->left;
r = n->right;
if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
n->right = l;
n->left = r;
l = r;
r = n->right;
}
if(l->addable != 7) {
idx.regtree = l;
idx.scale = 1;
} else
if(l->right->addable == 20) {
idx.regtree = l->left;
idx.scale = 1 << l->right->vconst;
} else
if(l->left->addable == 20) {
idx.regtree = l->right;
idx.scale = 1 << l->left->vconst;
} else
diag(n, "bad index");
idx.basetree = r;
if(debug['x']) {
print("scale = %d\n", idx.scale);
prtree(idx.regtree, "index");
prtree(idx.basetree, "base");
}
}