/* is empty if it contains only a Jmp node. */
/* Blocks can only be removed if they are not needed for the */
/* semantics of Phi nodes. */
/* is empty if it contains only a Jmp node. */
/* Blocks can only be removed if they are not needed for the */
/* semantics of Phi nodes. */
* Note that the simple case that Block has only these two
* predecessors are already handled in equivalent_node_Block().
*/
* Note that the simple case that Block has only these two
* predecessors are already handled in equivalent_node_Block().
*/
for (i = 0; i < n; ++i) {
ir_node *pred_i = get_Block_cfgpred(bl, i);
for (i = 0; i < n; ++i) {
ir_node *pred_i = get_Block_cfgpred(bl, i);
set_irn_n(bl, j, new_Bad());
DBG_OPT_IFSIM2(cond_i, jmp);
set_irn_n(bl, j, new_Bad());
DBG_OPT_IFSIM2(cond_i, jmp);
/* We would have to run gigo() if new is bad, so we
promote it directly below. Nevertheless, we sometimes reach a block
the first time through a dataflow node. In this case we optimized the
/* We would have to run gigo() if new is bad, so we
promote it directly below. Nevertheless, we sometimes reach a block
the first time through a dataflow node. In this case we optimized the
/**
* Block walker removing control flow from dead block by
* inspecting dominance info.
* Do not replace blocks by Bad. This optimization shall
* ensure, that all Bad control flow predecessors are
* removed, and no new other Bads are introduced.
/**
* Block walker removing control flow from dead block by
* inspecting dominance info.
* Do not replace blocks by Bad. This optimization shall
* ensure, that all Bad control flow predecessors are
* removed, and no new other Bads are introduced.
if (is_Block_dead(pred_bl) || (get_Block_dom_depth(pred_bl) < 0)) {
set_Block_dead(pred_bl);
exchange(pred_X, new_Bad());
*changed = 1;
if (is_Block_dead(pred_bl) || (get_Block_dom_depth(pred_bl) < 0)) {
set_Block_dead(pred_bl);
exchange(pred_X, new_Bad());
*changed = 1;
* than Jmp (and Proj).
* Links all Proj nodes to their predecessors.
* Collects all switch-Conds in a list.
*/
static void collect_nodes(ir_node *n, void *ctx) {
* than Jmp (and Proj).
* Links all Proj nodes to their predecessors.
* Collects all switch-Conds in a list.
*/
static void collect_nodes(ir_node *n, void *ctx) {
- if (op != op_Block) {
- ir_node *b = get_nodes_block(n);
+ if (code == iro_Block) {
+ /* mark the block as non-removable if it is labeled */
+ if (has_Block_label(n))
+ set_Block_non_removable(n);
+ } else {
+ ir_node *b = get_nodes_block(n);
/* Collect Phi nodes to compact ins along with block's ins. */
set_irn_link(n, get_irn_link(b));
set_irn_link(b, n);
/* Collect Phi nodes to compact ins along with block's ins. */
set_irn_link(n, get_irn_link(b));
set_irn_link(b, n);
- } else if (op != op_Jmp && !is_Bad(b)) { /* Check for non empty block. */
- mark_Block_block_visited(b);
+ } else if (code != iro_Jmp && !is_Bad(b)) { /* Check for non-empty block. */
+ set_Block_non_removable(b);
ir_node *pred = get_Proj_pred(n);
set_irn_link(n, get_irn_link(pred));
set_irn_link(pred, n);
ir_node *pred = get_Proj_pred(n);
set_irn_link(n, get_irn_link(pred));
set_irn_link(pred, n);
ir_node *sel = get_Cond_selector(n);
if (mode_is_int(get_irn_mode(sel))) {
/* found a switch-Cond, collect */
ir_node *sel = get_Cond_selector(n);
if (mode_is_int(get_irn_mode(sel))) {
/* found a switch-Cond, collect */
/** Returns true if pred is predecessor of block. */
static int is_pred_of(ir_node *pred, ir_node *b) {
/** Returns true if pred is predecessor of block. */
static int is_pred_of(ir_node *pred, ir_node *b) {
if (!get_opt_optimize() || !get_opt_control_flow_strong_simplification()) {
/* Mark block so that is will not be removed: optimization is turned off. */
if (!get_opt_optimize() || !get_opt_control_flow_strong_simplification()) {
/* Mark block so that is will not be removed: optimization is turned off. */
/* There are no Phi nodes ==> all predecessors are dispensable. */
n_preds = get_Block_n_cfgpreds(pred);
} else {
/* There are no Phi nodes ==> all predecessors are dispensable. */
n_preds = get_Block_n_cfgpreds(pred);
} else {
Handle all pred blocks with preds < pos as if they were already removed. */
for (i = 0; i < pos; i++) {
ir_node *b_pred = get_Block_cfgpred_block(b, i);
Handle all pred blocks with preds < pos as if they were already removed. */
for (i = 0; i < pos; i++) {
ir_node *b_pred = get_Block_cfgpred_block(b, i);
- if (! is_Block_dead(b_pred) &&
- get_Block_block_visited(b_pred) + 1
- < get_irg_block_visited(current_ir_graph)) {
- for (j = 0; j < get_Block_n_cfgpreds(b_pred); j++) {
+ if (! is_Block_dead(b_pred) && is_Block_removable(b_pred)) {
+ for (j = get_Block_n_cfgpreds(b_pred) - 1; j >= 0; --j) {
ir_node *b_pred_pred = get_Block_cfgpred_block(b_pred, j);
if (is_pred_of(b_pred_pred, pred))
goto non_dispensable;
ir_node *b_pred_pred = get_Block_cfgpred_block(b_pred, j);
if (is_pred_of(b_pred_pred, pred))
goto non_dispensable;
for (i = 0, k = get_Block_n_cfgpreds(b); i < k; ++i) {
max_preds += test_whether_dispensable(b, i);
}
for (i = 0, k = get_Block_n_cfgpreds(b); i < k; ++i) {
max_preds += test_whether_dispensable(b, i);
}
for (i = 0, n = get_Block_n_cfgpreds(b); i < n; ++i) {
pred = get_Block_cfgpred_block(b, i);
for (i = 0, n = get_Block_n_cfgpreds(b); i < n; ++i) {
pred = get_Block_cfgpred_block(b, i);
/* case Phi 2: It's an empty block and not yet visited. */
ir_node *phi_pred = get_Phi_pred(phi, i);
/* case Phi 2: It's an empty block and not yet visited. */
ir_node *phi_pred = get_Phi_pred(phi, i);
for (k = 0, n = get_Block_n_cfgpreds(b); k < n; ++k) {
ir_node *predb = get_nodes_block(get_Block_cfgpred(b, k));
for (k = 0, n = get_Block_n_cfgpreds(b); k < n; ++k) {
ir_node *predb = get_nodes_block(get_Block_cfgpred(b, k));
for (i = 0; i < k; i++) {
pred = get_Block_cfgpred_block(b, i);
for (i = 0; i < k; i++) {
pred = get_Block_cfgpred_block(b, i);
/* It's an empty block and not yet visited. */
for (j = 0; j < get_Block_n_cfgpreds(pred); j++) {
if (! is_Bad(get_Block_cfgpred(pred, j)))
/* It's an empty block and not yet visited. */
for (j = 0; j < get_Block_n_cfgpreds(pred); j++) {
if (! is_Bad(get_Block_cfgpred(pred, j)))
/* It's an empty block and not yet visited. */
for (j = 0; j < get_Block_n_cfgpreds(pred); j++) {
if (! is_Bad(get_Block_cfgpred(pred, j)))
/* It's an empty block and not yet visited. */
for (j = 0; j < get_Block_n_cfgpreds(pred); j++) {
if (! is_Bad(get_Block_cfgpred(pred, j)))
for (i = 0; i < get_Block_n_cfgpreds(b); i++) {
pred = get_Block_cfgpred_block(b, i);
for (i = 0; i < get_Block_n_cfgpreds(b); i++) {
pred = get_Block_cfgpred_block(b, i);
/* case 2: It's an empty block and not yet visited. */
assert(get_Block_n_cfgpreds(b) > 1);
/* Else it should be optimized by equivalent_node. */
for (j = 0; j < get_Block_n_cfgpreds(pred); j++) {
/* case 2: It's an empty block and not yet visited. */
assert(get_Block_n_cfgpreds(b) > 1);
/* Else it should be optimized by equivalent_node. */
for (j = 0; j < get_Block_n_cfgpreds(pred); j++) {
/* because of breaking loops, not all predecessors are Bad-clean,
* so we must check this here again */
/* because of breaking loops, not all predecessors are Bad-clean,
* so we must check this here again */
}
/* Remove block as it might be kept alive. */
exchange(pred, b/*new_Bad()*/);
}
/* Remove block as it might be kept alive. */
exchange(pred, b/*new_Bad()*/);
* It walks only over block nodes and adapts these and the Phi nodes in these blocks,
* which it finds in a linked list computed by the first pass.
*
* It walks only over block nodes and adapts these and the Phi nodes in these blocks,
* which it finds in a linked list computed by the first pass.
*
- if (get_opt_optimize() && get_opt_unreachable_code()) {
- ir_node *end;
-
- /* kill dead blocks using dom info */
- assure_doms(irg);
- irg_block_walk_graph(irg, NULL, remove_dead_block_cf, &env.changed);
+ /* ALWAYS kill unreachable control flow. Backend cannot handle it anyway.
+ Use dominator info to kill blocks. Also optimize useless Conds. */
+ assure_doms(irg);
+ irg_block_walk_graph(irg, NULL, remove_unreachable_blocks_and_conds, &env.changed);
- /* fix the keep-alives */
- end = get_irg_end(irg);
- for (i = 0, n = get_End_n_keepalives(end); i < n; ++i) {
- ir_node *ka = get_End_keepalive(end, i);
+ /* fix the keep-alives */
+ for (i = 0, n = get_End_n_keepalives(end); i < n; ++i) {
+ ir_node *ka = get_End_keepalive(end, i);
- if (is_Block(ka)) {
- /* do NOT keep dead blocks */
- if (get_Block_dom_depth(ka) < 0) {
- set_End_keepalive(end, i, new_Bad());
- env.changed = 1;
- }
- } else if (is_Block_dead(get_nodes_block(ka)) ||
- get_Block_dom_depth(get_nodes_block(ka)) < 0) {
- /* do NOT keep nodes in dead blocks */
+ if (is_Block(ka)) {
+ /* do NOT keep dead blocks */
+ if (is_Block_dead(ka) || get_Block_dom_depth(ka) < 0) {
+ } else if (is_Block_dead(get_nodes_block(ka)) ||
+ get_Block_dom_depth(get_nodes_block(ka)) < 0) {
+ /* do NOT keep nodes in dead blocks */
+ set_End_keepalive(end, i, new_Bad());
+ env.changed = 1;
- /* Use block visited flag to mark non-empty blocks. */
- inc_irg_block_visited(irg);
- set_using_block_visited(irg);
- set_using_irn_link(irg);
+ ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
env.list = plist_new();
irg_walk(end, merge_blocks, collect_nodes, &env);
env.list = plist_new();
irg_walk(end, merge_blocks, collect_nodes, &env);
- clear_using_block_visited(irg);
- clear_using_irn_link(irg);
+ ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
+
+ if (env.changed) {
+ /* Handle graph state if was changed. */
+ set_irg_outs_inconsistent(irg);
+ set_irg_doms_inconsistent(irg);
+ set_irg_extblk_inconsistent(irg);
+ set_irg_loopinfo_inconsistent(irg);
+ env.changed = 0;
+ }
/* handle all collected switch-Conds */
foreach_plist(env.list, el) {
/* handle all collected switch-Conds */
foreach_plist(env.list, el) {
- /* Handle graph state if was changed. */
- set_irg_outs_inconsistent(irg);
- set_irg_doms_inconsistent(irg);
- set_irg_extblk_inconsistent(irg);
- set_irg_loopinfo_inconsistent(irg);
+ /* The Cond optimization might generate unreachable code, so restart if
+ it happens. */
+ goto restart;
/* fix the keep alive */
for (i = j = 0; i < n; i++) {
ir_node *ka = get_End_keepalive(end, i);
/* fix the keep alive */
for (i = j = 0; i < n; i++) {
ir_node *ka = get_End_keepalive(end, i);
- if (irn_not_visited(ka)) {
- ir_op *op = get_irn_op(ka);
-
- if ((op == op_Block) && Block_not_block_visited(ka)) {
+ if (!irn_visited(ka)) {
+ if (is_Block(ka) && !Block_block_visited(ka)) {
/* irg_block_walk() will increase the block visited flag, but we must visit only
these blocks that are not visited yet, so decrease it first. */
set_irg_block_visited(irg, get_irg_block_visited(irg) - 1);
irg_block_walk(ka, optimize_blocks, remove_simple_blocks, &env.changed);
mark_irn_visited(ka);
in[j++] = ka;
/* irg_block_walk() will increase the block visited flag, but we must visit only
these blocks that are not visited yet, so decrease it first. */
set_irg_block_visited(irg, get_irg_block_visited(irg) - 1);
irg_block_walk(ka, optimize_blocks, remove_simple_blocks, &env.changed);
mark_irn_visited(ka);
in[j++] = ka;