#include "irop.h"
#include "irouts.h"
#include "irgmod.h"
+#include "iropt_dbg.h"
#include "debug.h"
#include "error.h"
#include "irdump.h"
/* define this to check that all type translations are monotone */
-#define VERIFY_MONOTONE
+#undef VERIFY_MONOTONE
/* define this to check the consistency of partitions */
#define CHECK_PARTITIONS
-/* define this to disable followers (may be buggy) */
-#undef NO_FOLLOWER
-
typedef struct node_t node_t;
typedef struct partition_t partition_t;
typedef struct opcode_key_t opcode_key_t;
return Z_prime;
} /* split_no_followers */
-#ifdef NO_FOLLOWER
-
-#define split(Z, g, env) split_no_followers(*(Z), g, env)
-
-#else
-
/**
* Make the Follower -> Leader transition for a node.
*
break;
}
case iro_Sub:
+ case iro_Shr:
+ case iro_Shl:
+ case iro_Shrs:
+ case iro_Rotl:
if (input == 1) {
- /* only a Sub x,0 might be a follower */
+ /* only a Sub x,0 / Shift x,0 might be a follower */
return 0;
}
break;
- case iro_Or:
case iro_Add:
+ case iro_Or:
+ case iro_Eor:
pred = get_irn_node(get_irn_n(irn, input));
if (is_tarval(pred->type.tv) && tarval_is_null(pred->type.tv))
return 0;
return X_prime;
} /* split */
-#endif /* NO_FOLLOWER */
/**
* Returns non-zero if the i'th input of a Phi node is live.
if (is_constant_type(y->type)) {
ir_opcode code = get_irn_opcode(succ);
- if (code == iro_Sub || code == iro_Cmp)
+ if (code == iro_Sub || code == iro_Eor || code == iro_Cmp)
add_to_cprop(y, env);
}
}
} /* compute_Sub */
+/**
+ * (Re-)compute the type for an Eor. Special case: both nodes are congruent.
+ *
+ * @param node the node
+ */
+static void compute_Eor(node_t *node) {
+ ir_node *eor = node->node;
+ node_t *l = get_irn_node(get_Eor_left(eor));
+ node_t *r = get_irn_node(get_Eor_right(eor));
+ lattice_elem_t a = l->type;
+ lattice_elem_t b = r->type;
+ tarval *tv;
+
+ if (a.tv == tarval_top || b.tv == tarval_top) {
+ node->type.tv = tarval_top;
+ } else if (is_con(a) && is_con(b)) {
+ if (is_tarval(a.tv) && is_tarval(b.tv)) {
+ node->type.tv = tarval_eor(a.tv, b.tv);
+ } else if (is_tarval(a.tv) && tarval_is_null(a.tv)) {
+ node->type = b;
+ } else if (is_tarval(b.tv) && tarval_is_null(b.tv)) {
+ node->type = a;
+ } else {
+ node->type.tv = tarval_bottom;
+ }
+ node->by_all_const = 1;
+ } else if (r->part == l->part) {
+ ir_mode *mode = get_irn_mode(eor);
+ tv = get_mode_null(mode);
+
+ /* if the node was ONCE evaluated by all constants, but now
+ this breakes AND we cat by partition a different result, switch to bottom.
+ This happens because initially all nodes are in the same partition ... */
+ if (node->by_all_const && node->type.tv != tv)
+ tv = tarval_bottom;
+ node->type.tv = tv;
+ } else {
+ node->type.tv = tarval_bottom;
+ }
+} /* compute_Eor */
+
/**
* (Re-)compute the type for Cmp.
*
lattice_elem_t b = r->type;
if (a.tv == tarval_top || b.tv == tarval_top) {
+#ifdef WITH_UNKNOWN
/*
* Top is congruent to any other value, we can
* calculate the compare result.
*/
node->type.tv = tarval_b_true;
+#else
+ node->type.tv = tarval_top;
+#endif
} else if (is_con(a) && is_con(b)) {
/* both nodes are constants, we can probably do something */
node->type.tv = tarval_b_true;
tarval *tv;
if (a.tv == tarval_top || b.tv == tarval_top) {
+#ifdef WITH_UNKNOWN
/* see above */
tv = new_tarval_from_long((pnc & pn_Cmp_Eq) ^ pn_Cmp_Eq, mode_b);
goto not_equal;
+#else
+ node->type.tv = tarval_top;
+#endif
} else if (is_con(a) && is_con(b)) {
default_compute(node);
node->by_all_const = 1;
* NaN != NaN is defined, so we must check this here.
*/
tv = new_tarval_from_long(pnc & pn_Cmp_Eq, mode_b);
+#ifdef WITH_UNKNOWN
not_equal:
+#endif
/* if the node was ONCE evaluated by all constants, but now
this breakes AND we cat by partition a different result, switch to bottom.
return node;
} /* identity_comm_zero_binop */
-#define identity_Add identity_comm_zero_binop
-#define identity_Or identity_comm_zero_binop
+/**
+ * Calculates the Identity for Shift nodes.
+ */
+static node_t *identity_shift(node_t *node) {
+ ir_node *op = node->node;
+ node_t *b = get_irn_node(get_binop_right(op));
+ ir_mode *mode = get_irn_mode(b->node);
+ tarval *zero;
+
+ /* node: no input should be tarval_top, else the binop would be also
+ * Top and not being split. */
+ zero = get_mode_null(mode);
+ if (b->type.tv == zero)
+ return get_irn_node(get_binop_left(op));
+ return node;
+} /* identity_shift */
/**
* Calculates the Identity for Mul nodes.
switch (get_irn_opcode(irn)) {
case iro_Phi:
return identity_Phi(node);
- case iro_Add:
- return identity_Add(node);
case iro_Mul:
return identity_Mul(node);
+ case iro_Add:
case iro_Or:
- return identity_Or(node);
+ case iro_Eor:
+ return identity_comm_zero_binop(node);
+ case iro_Shr:
+ case iro_Shl:
+ case iro_Shrs:
+ case iro_Rotl:
+ return identity_shift(node);
case iro_And:
return identity_And(node);
case iro_Sub:
for (x = fallen; x != NULL; x = x->next)
x->on_fallen = 0;
-#ifndef NO_FOLLOWER
if (old_type_was_T_or_C) {
node_t *y, *tmp;
}
}
}
-#endif
split_by(Y, env);
}
} /* propagate */
return 1;
}
return 0;
-}
+} /* can_exchange */
/**
* Block Post-Walker, apply the analysis results on control flow by
ir_node **ins, **in_X;
ir_node *phi, *next;
- if (block == get_irg_end_block(current_ir_graph) ||
- block == get_irg_start_block(current_ir_graph)) {
+ n = get_Block_n_cfgpreds(block);
+
+ if (node->type.tv == tarval_unreachable) {
+ env->modified = 1;
+
+ for (i = n - 1; i >= 0; --i) {
+ ir_node *pred = get_Block_cfgpred(block, i);
+
+ if (! is_Bad(pred)) {
+ node_t *pred_bl = get_irn_node(get_nodes_block(skip_Proj(pred)));
+
+ if (pred_bl->flagged == 0) {
+ pred_bl->flagged = 3;
+
+ if (pred_bl->type.tv == tarval_reachable) {
+ /*
+ * We will remove an edge from block to its pred.
+ * This might leave the pred block as an endless loop
+ */
+ if (! is_backedge(block, i))
+ keep_alive(pred_bl->node);
+ }
+ }
+ }
+ }
+
/* the EndBlock is always reachable even if the analysis
finds out the opposite :-) */
+ if (block != get_irg_end_block(current_ir_graph)) {
+ /* mark dead blocks */
+ set_Block_dead(block);
+ DB((dbg, LEVEL_1, "Removing dead %+F\n", block));
+ } else {
+ /* the endblock is unreachable */
+ set_irn_in(block, 0, NULL);
+ }
return;
}
- if (node->type.tv == tarval_unreachable) {
- /* mark dead blocks */
- set_Block_dead(block);
- return;
- }
-
- n = get_Block_n_cfgpreds(block);
if (n == 1) {
/* only one predecessor combine */
ir_node *pred = skip_Proj(get_Block_cfgpred(block, 0));
if (can_exchange(pred)) {
- exchange(block, get_nodes_block(pred));
+ ir_node *new_block = get_nodes_block(pred);
+ DB((dbg, LEVEL_1, "Fuse %+F with %+F\n", block, new_block));
+ DBG_OPT_COMBO(block, new_block, FS_OPT_COMBO_CF);
+ exchange(block, new_block);
+ node->node = new_block;
env->modified = 1;
}
return;
if (node->type.tv == tarval_reachable) {
in_X[k++] = pred;
+ } else {
+ DB((dbg, LEVEL_1, "Removing dead input %d from %+F (%+F)\n", i, block, pred));
+ if (! is_Bad(pred)) {
+ node_t *pred_bl = get_irn_node(get_nodes_block(skip_Proj(pred)));
+
+ if (pred_bl->flagged == 0) {
+ pred_bl->flagged = 3;
+
+ if (pred_bl->type.tv == tarval_reachable) {
+ /*
+ * We will remove an edge from block to its pred.
+ * This might leave the pred block as an endless loop
+ */
+ if (! is_backedge(block, i))
+ keep_alive(pred_bl->node);
+ }
+ }
+ }
}
}
if (k >= n)
set_irn_node(c, node);
node->node = c;
DB((dbg, LEVEL_1, "%+F is replaced by %+F\n", phi, c));
+ DBG_OPT_COMBO(phi, c, FS_OPT_COMBO_CONST);
exchange(phi, c);
env->modified = 1;
} else {
ins[j++] = get_Phi_pred(phi, i);
}
}
- if (j <= 1) {
+ if (j == 1) {
/* this Phi is replaced by a single predecessor */
ir_node *s = ins[0];
+ node_t *phi_node = get_irn_node(phi);
node->node = s;
DB((dbg, LEVEL_1, "%+F is replaced by %+F because of cf change\n", phi, s));
+ DBG_OPT_COMBO(phi, s, FS_OPT_COMBO_FOLLOWER);
exchange(phi, s);
+ phi_node->node = s;
env->modified = 1;
} else {
set_irn_in(phi, j, ins);
}
}
- if (k <= 1) {
+ if (k == 1) {
/* this Block has only one live predecessor */
ir_node *pred = skip_Proj(in_X[0]);
if (can_exchange(pred)) {
- exchange(block, get_nodes_block(pred));
+ ir_node *new_block = get_nodes_block(pred);
+ DBG_OPT_COMBO(block, new_block, FS_OPT_COMBO_CF);
+ exchange(block, new_block);
+ node->node = new_block;
env->modified = 1;
}
} else {
env->modified = 1;
}
else if (node->type.tv == tarval_unreachable) {
- ir_node *bad = get_irg_bad(current_ir_graph);
-
- /* see comment above */
- set_irn_node(bad, node);
- node->node = bad;
- DB((dbg, LEVEL_1, "%+F is unreachable\n", irn));
- exchange(irn, bad);
- env->modified = 1;
+ /* don't kick away Unknown */
+ if (! is_Unknown(irn)) {
+ ir_node *bad = get_irg_bad(current_ir_graph);
+
+ /* see comment above */
+ set_irn_node(bad, node);
+ node->node = bad;
+ DB((dbg, LEVEL_1, "%+F is unreachable\n", irn));
+ exchange(irn, bad);
+ env->modified = 1;
+ }
}
else if (get_irn_mode(irn) == mode_X) {
if (is_Proj(irn)) {
node_t *sel = get_irn_node(get_Cond_selector(cond));
if (is_tarval(sel->type.tv) && tarval_is_constant(sel->type.tv)) {
- /* Cond selector is a constant, make a Jmp */
- ir_node *jmp = new_r_Jmp(current_ir_graph, block->node);
+ /* Cond selector is a constant and the Proj is reachable, make a Jmp */
+ ir_node *jmp = new_r_Jmp(current_ir_graph, block->node);
set_irn_node(jmp, node);
node->node = jmp;
DB((dbg, LEVEL_1, "%+F is replaced by %+F\n", irn, jmp));
+ DBG_OPT_COMBO(irn, jmp, FS_OPT_COMBO_CF);
exchange(irn, jmp);
env->modified = 1;
}
set_irn_node(c, node);
node->node = c;
DB((dbg, LEVEL_1, "%+F is replaced by %+F\n", irn, c));
+ DBG_OPT_COMBO(irn, c, FS_OPT_COMBO_CONST);
exchange(irn, c);
env->modified = 1;
}
node->node = symc;
DB((dbg, LEVEL_1, "%+F is replaced by %+F\n", irn, symc));
+ DBG_OPT_COMBO(irn, symc, FS_OPT_COMBO_CONST);
exchange(irn, symc);
env->modified = 1;
}
if (leader != irn) {
DB((dbg, LEVEL_1, "%+F from part%d is replaced by %+F\n", irn, node->part->nr, leader));
+ if (node->is_follower)
+ DBG_OPT_COMBO(irn, leader, FS_OPT_COMBO_FOLLOWER);
+ else
+ DBG_OPT_COMBO(irn, leader, FS_OPT_COMBO_CONGRUENT);
exchange(irn, leader);
env->modified = 1;
}
ir_node *ka = get_End_keepalive(end, i);
node_t *node = get_irn_node(ka);
- /* Use the flagged bits to mark already visited nodes.
- * This should not be ready but better safe than sorry. */
- if (node->flagged == 0) {
- node->flagged = 3;
-
- if (! is_Block(ka))
- node = get_irn_node(get_nodes_block(ka));
+ if (! is_Block(ka))
+ node = get_irn_node(get_nodes_block(ka));
- if (node->type.tv != tarval_unreachable)
- in[j++] = ka;
- }
+ if (node->type.tv != tarval_unreachable)
+ in[j++] = ka;
}
if (j != n) {
set_End_keepalives(end, j, in);
SET(Phi);
SET(Add);
SET(Sub);
+ SET(Eor);
SET(SymConst);
SET(Cmp);
SET(Proj);
env.modified = 0;
assure_irg_outs(irg);
+ assure_cf_loop(irg);
+
/* we have our own value_of function */
set_value_of_func(get_node_tarval);
set_compute_functions();
DEBUG_ONLY(part_nr = 0);
+ ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
+
/* create the initial partition and place it on the work list */
env.initial = new_partition(&env);
add_to_worklist(env.initial, &env);
irg_walk_graph(irg, init_block_phis, create_initial_partitions, &env);
+#ifdef WITH_UNKNOWN
tarval_UNKNOWN = env.nonstd_cond ? tarval_bad : tarval_top;
+#else
+ tarval_UNKNOWN = tarval_bad;
+#endif
/* all nodes on the initial partition have type Top */
env.initial->type_is_T_or_C = 1;
set_irg_loopinfo_inconsistent(irg);
}
+ ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
+
pmap_destroy(env.type2id_map);
del_set(env.opcode2id_map);
obstack_free(&env.obst, NULL);