Line 277... |
Line 277... |
if (!ii->op[1] && !ii->op[2]) {
|
if (!ii->op[1] && !ii->op[2]) {
|
change_insn_type (ii, II_ADD);
|
change_insn_type (ii, II_ADD);
|
ii->op[1] = 0; ii->opt[1] = OPT_CONST;
|
ii->op[1] = 0; ii->opt[1] = OPT_CONST;
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
ii->opt[3] = OPT_NONE;
|
ii->opt[3] = OPT_NONE;
|
return 0;
|
return 1;
|
|
}
|
|
if (ii->op[1] == ii->opt[3] && ii->opt[1] == ii->opt[3]) {
|
|
ii->op[1] = 1; ii->opt[1] = OPT_CONST;
|
|
return 1;
|
|
}
|
|
if (ii->op[2] == ii->opt[3] && ii->opt[2] == ii->opt[3]) {
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
return 1;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
return 0;
|
return 0;
|
Line 385... |
Line 393... |
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
/* returns number of instructions, using instruction ref */
|
|
static int insn_uses (cuc_func *f, int ref)
|
|
{
|
|
int b, i, j;
|
|
int cnt = 0;
|
|
for (b = 0; b < f->num_bb; b++)
|
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
|
for (j = 0; j < MAX_OPERANDS; j++)
|
|
if (f->bb[b].insn[i].opt[j] & OPT_REF && f->bb[b].insn[i].op[j] == ref) cnt++;
|
|
return cnt;
|
|
}
|
|
|
|
/* handles some common CMOV, CMOV-CMOV cases;
|
|
returns nonzero if anything optimized */
|
|
static int optimize_cmov_more (cuc_func *f, int ref)
|
|
{
|
|
int t = 0;
|
|
cuc_insn *ii = &f->INSN(ref);
|
|
assert (ii->index == II_CMOV);
|
|
|
|
/* In case of x = cmov x, y; or x = cmov y, x; we have
|
|
asynchroneous loop -> remove it */
|
|
if ((ii->opt[1] & OPT_REF) && ii->op[1] == ref) t = 1;
|
|
if ((ii->opt[2] & OPT_REF) && ii->op[2] == ref) t = 2;
|
|
if (ii->opt[1] == ii->opt[2] && ii->op[1] == ii->op[2]) t = 2;
|
|
if (t) {
|
|
change_insn_type (ii, II_ADD);
|
|
cucdebug (2, "%8x:cmov %i\n", ref, t);
|
|
ii->opt[t] = OPT_CONST;
|
|
ii->op[t] = 0;
|
|
ii->opt[3] = OPT_NONE;
|
|
return 1;
|
|
}
|
|
if (!(ii->type & IT_COND)) {
|
|
for (t = 1; t <= 2; t++) {
|
|
/* cmov L, X, Y, C1
|
|
cmov Z, L, Y, C2
|
|
can be replaced with simpler:
|
|
cmov L, C1, C2, C2
|
|
cmov Z, X, Y, L */
|
|
if (ii->opt[t] == OPT_REF && f->INSN(ii->op[t]).index == II_CMOV) {
|
|
int r = ii->op[t];
|
|
unsigned long x, xt, y, yt;
|
|
cuc_insn *prev = &f->INSN(r);
|
|
cuc_check (f);
|
|
cucdebug (3, "%x-%x\n", ref, r);
|
|
assert (!(prev->type & IT_COND));
|
|
if (prev->op[3 - t] != ii->op[3 - t] || prev->opt[3 - t] != ii->opt[3 - t]
|
|
|| insn_uses (f, r) > 1) continue;
|
|
cucdebug (3, "%x-%x cmov more\n", ref, r);
|
|
prev->type |= IT_COND;
|
|
x = prev->op[t]; xt = prev->opt[t];
|
|
y = prev->op[3 - t]; yt = prev->opt[3 - t];
|
|
prev->op[t] = ii->op[3]; prev->opt[t] = ii->opt[3]; /* C2 */
|
|
ii->op[3] = r; ii->opt[3] = OPT_REF; /* L */
|
|
prev->op[3 - t] = prev->op[3]; prev->opt[3 - t] = prev->opt[3]; /* C1 */
|
|
prev->op[3] = prev->op[t]; prev->opt[3] = prev->opt[t]; /* C2 */
|
|
ii->op[t] = x; ii->opt[t] = xt; /* X */
|
|
ii->op[3 - t] = y; ii->opt[3 - t] = yt; /* Y */
|
|
prev->op[0] = -1; prev->opt[0] = OPT_REGISTER | OPT_DEST;
|
|
cuc_check (f);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ii->opt[3] == OPT_REF) {
|
|
cuc_insn *prev = &f->INSN(ii->op[3]);
|
|
assert (prev->type & IT_COND);
|
|
if (prev->index == II_CMOV) {
|
|
} else if (prev->index == II_ADD) {
|
|
if (prev->opt[2] & OPT_CONST && prev->op[2] == 0) {
|
|
ii->op[3] = prev->op[1]; ii->opt[3] = prev->opt[1];
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
/* Optimizes dataflow tree */
|
/* Optimizes dataflow tree */
|
void optimize_tree (cuc_func *f)
|
void optimize_tree (cuc_func *f)
|
{
|
{
|
int b, i, j;
|
int b, i, j;
|
int modified;
|
int modified;
|
|
|
do {
|
do {
|
modified = 0;
|
modified = 0;
|
|
if (cuc_debug) cuc_check (f);
|
for (b = 0; b < f->num_bb; b++) if (!(f->bb[b].type & BB_DEAD)) {
|
for (b = 0; b < f->num_bb; b++) if (!(f->bb[b].type & BB_DEAD)) {
|
for (i = 0; i < f->bb[b].ninsn; i++) {
|
for (i = 0; i < f->bb[b].ninsn; i++) {
|
cuc_insn *ii = &f->bb[b].insn[i];
|
cuc_insn *ii = &f->bb[b].insn[i];
|
/* We tend to have the third parameter const if instruction is cumutative */
|
/* We tend to have the third parameter const if instruction is cumutative */
|
if ((ii->opt[1] & OPT_CONST) && !(ii->opt[2] & OPT_CONST)) {
|
if ((ii->opt[1] & OPT_CONST) && !(ii->opt[2] & OPT_CONST)) {
|
Line 438... |
Line 527... |
modified = 1; cucdebug (2, "%8x:promote%i %8x %8x\n", REF (b, i), j, ii->op[j], t->op[1]);
|
modified = 1; cucdebug (2, "%8x:promote%i %8x %8x\n", REF (b, i), j, ii->op[j], t->op[1]);
|
ii->op[j] = t->op[1]; ii->opt[j] = t->opt[1];
|
ii->op[j] = t->op[1]; ii->opt[j] = t->opt[1];
|
}
|
}
|
}
|
}
|
|
|
/* In case of x = cmov x, y; or x = cmov y, x; we have
|
/* handle some CMOV cases more deeply */
|
asynchroneous loop -> remove it */
|
if (ii->index == II_CMOV && optimize_cmov_more (f, REF (b, i))) {
|
if (ii->index == II_CMOV) {
|
|
int f = 0;
|
|
if ((ii->opt[1] & OPT_REF) && ii->op[1] == REF (b, i)) f = 1;
|
|
if ((ii->opt[2] & OPT_REF) && ii->op[2] == REF (b, i)) f = 2;
|
|
if (ii->opt[1] == ii->opt[2] && ii->op[1] == ii->op[2]) f = 2;
|
|
if (f) {
|
|
change_insn_type (ii, II_ADD);
|
|
cucdebug (2, "%8x:cmov %i\n", REF(b, i), f);
|
|
ii->opt[f] = OPT_CONST;
|
|
ii->op[f] = 0;
|
|
ii->opt[3] = OPT_NONE;
|
|
modified = 1;
|
modified = 1;
|
continue;
|
continue;
|
}
|
}
|
}
|
|
|
|
/* Do nothing to volatile instructions */
|
/* Do nothing to volatile instructions */
|
if (ii->type & IT_VOLATILE) continue;
|
if (ii->type & IT_VOLATILE) continue;
|
|
|
/* Check whether we can simplify the instruction */
|
/* Check whether we can simplify the instruction */
|
Line 491... |
Line 568... |
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
modified = 1; cucdebug (2, "%8x:const\n", REF (b, i));
|
modified = 1; cucdebug (2, "%8x:const\n", REF (b, i));
|
}
|
}
|
} else if (ii->opt[1] & OPT_REF) {
|
} else if (ii->opt[1] & OPT_REF) {
|
cuc_insn *prev = &f->INSN(ii->op[1]);
|
cuc_insn *prev = &f->INSN(ii->op[1]);
|
/* Is this just a link? */
|
/* Is this just a move? */
|
if (ii->index == II_ADD
|
if (ii->index == II_ADD
|
&& !(ii->type & IT_MEMADD) && ii->op[2] == 0) {
|
&& !(ii->type & IT_MEMADD) && ii->op[2] == 0) {
|
int b1, i1, j1;
|
int b1, i1, j1;
|
cucdebug (2, "%8x:link %8x: ", REF(b, i), ii->op[1]);
|
cucdebug (2, "%8x:link %8x: ", REF(b, i), ii->op[1]);
|
for (b1 = 0; b1 < f->num_bb; b1++) if (!(f->bb[b1].type & BB_DEAD))
|
for (b1 = 0; b1 < f->num_bb; b1++) if (!(f->bb[b1].type & BB_DEAD))
|
Line 757... |
Line 834... |
/* CSE -- common subexpression elimination */
|
/* CSE -- common subexpression elimination */
|
void cse (cuc_func *f)
|
void cse (cuc_func *f)
|
{
|
{
|
int b, i, j, b1, i1, b2, i2, j2;
|
int b, i, j, b1, i1, b2, i2, j2;
|
for (b1 = 0; b1 < f->num_bb; b1++)
|
for (b1 = 0; b1 < f->num_bb; b1++)
|
for (i1 = 0; i1 < f->bb[b1].ninsn; i1++)
|
for (i1 = 0; i1 < f->bb[b1].ninsn; i1++) if (f->bb[b1].insn[i1].index != II_NOP
|
|
&& f->bb[b1].insn[i1].index != II_LRBB && !(f->bb[b1].insn[i1].type & IT_MEMORY)
|
|
&& !(f->bb[b1].insn[i1].type & IT_MEMADD))
|
for (b2 = 0; b2 < f->num_bb; b2++)
|
for (b2 = 0; b2 < f->num_bb; b2++)
|
for (i2 = 0; i2 < f->bb[b2].ninsn; i2++) {
|
for (i2 = 0; i2 < f->bb[b2].ninsn; i2++)
|
|
if (f->bb[b2].insn[i2].index != II_NOP && f->bb[b2].insn[i2].index != II_LRBB
|
|
&& !(f->bb[b2].insn[i2].type & IT_MEMORY) && !(f->bb[b2].insn[i2].type & IT_MEMADD)
|
|
&& (b1 != b2 || i2 > i1)) {
|
cuc_insn *ii1 = &f->bb[b1].insn[i1];
|
cuc_insn *ii1 = &f->bb[b1].insn[i1];
|
cuc_insn *ii2 = &f->bb[b2].insn[i2];
|
cuc_insn *ii2 = &f->bb[b2].insn[i2];
|
|
int ok = 1;
|
|
|
/* Do we have an exact match? */
|
/* Do we have an exact match? */
|
if (ii1->index == ii2->index) continue;
|
if (ii1->index != ii2->index) continue;
|
if (ii1->type & IT_VOLATILE) continue;
|
if (ii2->type & IT_VOLATILE) continue;
|
|
|
if (ii1->op[1] != ii2->op[1] || ii1->opt[1] != ii2->opt[1]) continue;
|
/* Check all operands also */
|
if (ii1->op[2] != ii2->op[2] || ii1->opt[2] != ii2->opt[2]) continue;
|
for (j = 0; j < MAX_OPERANDS; j++) {
|
if (ii1->opt[3] != ii2->opt[3]) continue;
|
if (ii1->opt[j] != ii2->opt[j]) {
|
if (ii1->opt[3] != OPT_NONE && ii1->op[3] != ii2->op[3]) continue;
|
ok = 0;
|
|
break;
|
/* Check if we drive outputs? */
|
}
|
if ((ii1->opt[0] & OPT_REGISTER) && ii1->op[0] >= 0)
|
if (ii1->opt[j] & OPT_DEST) continue;
|
if ((ii2->opt[0] & OPT_REGISTER) && ii2->op[0] >= 0) continue;
|
if (ii1->opt[j] != OPT_NONE && ii1->op[j] != ii2->op[j]) {
|
else ii2->op[0] = ii1->op[0];
|
ok = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ok) {
|
/* remove duplicated instruction and relink the references */
|
/* remove duplicated instruction and relink the references */
|
|
cucdebug (3, "%x - %x are same\n", REF(b1, i1), REF(b2, i2));
|
change_insn_type (ii2, II_NOP);
|
change_insn_type (ii2, II_NOP);
|
for (b = 0; b < f->num_bb; b++)
|
for (b = 0; b < f->num_bb; b++)
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
for (j = 0; j < MAX_OPERANDS; j++)
|
for (j = 0; j < MAX_OPERANDS; j++)
|
if (f->bb[b].insn[i].opt[j] & OPT_REF && f->bb[b].insn[i].op[j] == REF (b2, i2))
|
if (f->bb[b].insn[i].opt[j] & OPT_REF
|
|
&& f->bb[b].insn[i].op[j] == REF (b2, i2))
|
f->bb[b].insn[i].op[j] = REF (b1, i1);
|
f->bb[b].insn[i].op[j] = REF (b1, i1);
|
}
|
}
|
}
|
}
|
|
}
|
|
|
static int count_cmovs (cuc_insn *ii, int match)
|
static int count_cmovs (cuc_insn *ii, int match)
|
{
|
{
|
int c = 0, j;
|
int c = 0, j;
|
if (match & 2) {
|
if (match & 2) {
|