tree-cfgcleanup.c (cfgcleanup_altered_bbs): New global variable.
* tree-cfgcleanup.c (cfgcleanup_altered_bbs): New global variable. (remove_fallthru_edge): Use remove_edge_and_dominated_blocks. (cleanup_control_expr_graph): Do not invalidate dominance info. Record altered blocks. (cleanup_control_flow, cleanup_forwarder_blocks): Removed. (cleanup_control_flow_bb, split_bbs_on_noreturn_calls, cleanup_tree_cfg_bb): New functions. (remove_forwarder_block): Do not maintain the worklist of blocks. Record altered blocks. (cleanup_tree_cfg_1): Iterate over cfgcleanup_altered_bbs, not over whole cfg. (cleanup_tree_cfg): Do not iterate cleanup_tree_cfg_1. Only call delete_unreachable_blocks if dominators are not available. * tree-inline.c (optimize_inline_calls): Free dominance information earlier. * tree-flow.h (remove_edge_and_dominated_blocks, cfgcleanup_altered_bbs): Altered. * tree-cfg.c (replace_uses_by, tree_merge_blocks): Record altered blocks. (get_all_dominated_blocks, remove_edge_and_dominated_blocks): New functions. (tree_purge_dead_eh_edges): Use remove_edge_and_dominated_blocks, do not invalidate dominators. From-SVN: r124203
This commit is contained in:
parent
468a823ba9
commit
672987e82f
|
@ -1,3 +1,29 @@
|
||||||
|
2007-04-27 Zdenek Dvorak <dvorakz@suse.cz>
|
||||||
|
|
||||||
|
* tree-cfgcleanup.c (cfgcleanup_altered_bbs): New global variable.
|
||||||
|
(remove_fallthru_edge): Use remove_edge_and_dominated_blocks.
|
||||||
|
(cleanup_control_expr_graph): Do not invalidate dominance info.
|
||||||
|
Record altered blocks.
|
||||||
|
(cleanup_control_flow, cleanup_forwarder_blocks): Removed.
|
||||||
|
(cleanup_control_flow_bb, split_bbs_on_noreturn_calls,
|
||||||
|
cleanup_tree_cfg_bb): New functions.
|
||||||
|
(remove_forwarder_block): Do not maintain the worklist of blocks.
|
||||||
|
Record altered blocks.
|
||||||
|
(cleanup_tree_cfg_1): Iterate over cfgcleanup_altered_bbs,
|
||||||
|
not over whole cfg.
|
||||||
|
(cleanup_tree_cfg): Do not iterate cleanup_tree_cfg_1. Only call
|
||||||
|
delete_unreachable_blocks if dominators are not available.
|
||||||
|
* tree-inline.c (optimize_inline_calls): Free dominance information
|
||||||
|
earlier.
|
||||||
|
* tree-flow.h (remove_edge_and_dominated_blocks,
|
||||||
|
cfgcleanup_altered_bbs): Altered.
|
||||||
|
* tree-cfg.c (replace_uses_by, tree_merge_blocks): Record altered
|
||||||
|
blocks.
|
||||||
|
(get_all_dominated_blocks, remove_edge_and_dominated_blocks): New
|
||||||
|
functions.
|
||||||
|
(tree_purge_dead_eh_edges): Use remove_edge_and_dominated_blocks,
|
||||||
|
do not invalidate dominators.
|
||||||
|
|
||||||
2007-04-26 Anatoly Sokolov <aesok@post.ru>
|
2007-04-26 Anatoly Sokolov <aesok@post.ru>
|
||||||
|
|
||||||
* config/avr/avr.c (avr_mcu_types): Add support for ATmega8HVA and
|
* config/avr/avr.c (avr_mcu_types): Add support for ATmega8HVA and
|
||||||
|
|
165
gcc/tree-cfg.c
165
gcc/tree-cfg.c
|
@ -1199,6 +1199,8 @@ replace_uses_by (tree name, tree val)
|
||||||
tree rhs;
|
tree rhs;
|
||||||
|
|
||||||
fold_stmt_inplace (stmt);
|
fold_stmt_inplace (stmt);
|
||||||
|
if (cfgcleanup_altered_bbs)
|
||||||
|
bitmap_set_bit (cfgcleanup_altered_bbs, bb_for_stmt (stmt)->index);
|
||||||
|
|
||||||
/* FIXME. This should go in pop_stmt_changes. */
|
/* FIXME. This should go in pop_stmt_changes. */
|
||||||
rhs = get_rhs (stmt);
|
rhs = get_rhs (stmt);
|
||||||
|
@ -1312,6 +1314,9 @@ tree_merge_blocks (basic_block a, basic_block b)
|
||||||
last = tsi_last (bb_stmt_list (a));
|
last = tsi_last (bb_stmt_list (a));
|
||||||
tsi_link_after (&last, bb_stmt_list (b), TSI_NEW_STMT);
|
tsi_link_after (&last, bb_stmt_list (b), TSI_NEW_STMT);
|
||||||
set_bb_stmt_list (b, NULL_TREE);
|
set_bb_stmt_list (b, NULL_TREE);
|
||||||
|
|
||||||
|
if (cfgcleanup_altered_bbs)
|
||||||
|
bitmap_set_bit (cfgcleanup_altered_bbs, a->index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5429,6 +5434,144 @@ tree_purge_dead_abnormal_call_edges (basic_block bb)
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stores all basic blocks dominated by BB to DOM_BBS. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_all_dominated_blocks (basic_block bb, VEC (basic_block, heap) **dom_bbs)
|
||||||
|
{
|
||||||
|
basic_block son;
|
||||||
|
|
||||||
|
VEC_safe_push (basic_block, heap, *dom_bbs, bb);
|
||||||
|
for (son = first_dom_son (CDI_DOMINATORS, bb);
|
||||||
|
son;
|
||||||
|
son = next_dom_son (CDI_DOMINATORS, son))
|
||||||
|
get_all_dominated_blocks (son, dom_bbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Removes edge E and all the blocks dominated by it, and updates dominance
|
||||||
|
information. The IL in E->src needs to be updated separately.
|
||||||
|
If dominance info is not available, only the edge E is removed.*/
|
||||||
|
|
||||||
|
void
|
||||||
|
remove_edge_and_dominated_blocks (edge e)
|
||||||
|
{
|
||||||
|
VEC (basic_block, heap) *bbs_to_remove = NULL;
|
||||||
|
VEC (basic_block, heap) *bbs_to_fix_dom = NULL;
|
||||||
|
bitmap df, df_idom;
|
||||||
|
edge f;
|
||||||
|
edge_iterator ei;
|
||||||
|
bool none_removed = false;
|
||||||
|
unsigned i;
|
||||||
|
basic_block bb, dbb;
|
||||||
|
bitmap_iterator bi;
|
||||||
|
|
||||||
|
if (!dom_computed[CDI_DOMINATORS])
|
||||||
|
{
|
||||||
|
remove_edge (e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No updating is needed for edges to exit. */
|
||||||
|
if (e->dest == EXIT_BLOCK_PTR)
|
||||||
|
{
|
||||||
|
if (cfgcleanup_altered_bbs)
|
||||||
|
bitmap_set_bit (cfgcleanup_altered_bbs, e->src->index);
|
||||||
|
remove_edge (e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First, we find the basic blocks to remove. If E->dest has a predecessor
|
||||||
|
that is not dominated by E->dest, then this set is empty. Otherwise,
|
||||||
|
all the basic blocks dominated by E->dest are removed.
|
||||||
|
|
||||||
|
Also, to DF_IDOM we store the immediate dominators of the blocks in
|
||||||
|
the dominance frontier of E (i.e., of the successors of the
|
||||||
|
removed blocks, if there are any, and of E->dest otherwise). */
|
||||||
|
FOR_EACH_EDGE (f, ei, e->dest->preds)
|
||||||
|
{
|
||||||
|
if (f == e)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!dominated_by_p (CDI_DOMINATORS, f->src, e->dest))
|
||||||
|
{
|
||||||
|
none_removed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
df = BITMAP_ALLOC (NULL);
|
||||||
|
df_idom = BITMAP_ALLOC (NULL);
|
||||||
|
|
||||||
|
if (none_removed)
|
||||||
|
bitmap_set_bit (df_idom,
|
||||||
|
get_immediate_dominator (CDI_DOMINATORS, e->dest)->index);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
get_all_dominated_blocks (e->dest, &bbs_to_remove);
|
||||||
|
for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++)
|
||||||
|
{
|
||||||
|
FOR_EACH_EDGE (f, ei, bb->succs)
|
||||||
|
{
|
||||||
|
if (f->dest != EXIT_BLOCK_PTR)
|
||||||
|
bitmap_set_bit (df, f->dest->index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++)
|
||||||
|
bitmap_clear_bit (df, bb->index);
|
||||||
|
|
||||||
|
EXECUTE_IF_SET_IN_BITMAP (df, 0, i, bi)
|
||||||
|
{
|
||||||
|
bb = BASIC_BLOCK (i);
|
||||||
|
bitmap_set_bit (df_idom,
|
||||||
|
get_immediate_dominator (CDI_DOMINATORS, bb)->index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfgcleanup_altered_bbs)
|
||||||
|
{
|
||||||
|
/* Record the set of the altered basic blocks. */
|
||||||
|
bitmap_set_bit (cfgcleanup_altered_bbs, e->src->index);
|
||||||
|
bitmap_ior_into (cfgcleanup_altered_bbs, df);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove E and the cancelled blocks. */
|
||||||
|
if (none_removed)
|
||||||
|
remove_edge (e);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++)
|
||||||
|
delete_basic_block (bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the dominance information. The immediate dominator may change only
|
||||||
|
for blocks whose immediate dominator belongs to DF_IDOM:
|
||||||
|
|
||||||
|
Suppose that idom(X) = Y before removal of E and idom(X) != Y after the
|
||||||
|
removal. Let Z the arbitrary block such that idom(Z) = Y and
|
||||||
|
Z dominates X after the removal. Before removal, there exists a path P
|
||||||
|
from Y to X that avoids Z. Let F be the last edge on P that is
|
||||||
|
removed, and let W = F->dest. Before removal, idom(W) = Y (since Y
|
||||||
|
dominates W, and because of P, Z does not dominate W), and W belongs to
|
||||||
|
the dominance frontier of E. Therefore, Y belongs to DF_IDOM. */
|
||||||
|
EXECUTE_IF_SET_IN_BITMAP (df_idom, 0, i, bi)
|
||||||
|
{
|
||||||
|
bb = BASIC_BLOCK (i);
|
||||||
|
for (dbb = first_dom_son (CDI_DOMINATORS, bb);
|
||||||
|
dbb;
|
||||||
|
dbb = next_dom_son (CDI_DOMINATORS, dbb))
|
||||||
|
VEC_safe_push (basic_block, heap, bbs_to_fix_dom, dbb);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterate_fix_dominators (CDI_DOMINATORS,
|
||||||
|
VEC_address (basic_block, bbs_to_fix_dom),
|
||||||
|
VEC_length (basic_block, bbs_to_fix_dom));
|
||||||
|
|
||||||
|
BITMAP_FREE (df);
|
||||||
|
BITMAP_FREE (df_idom);
|
||||||
|
VEC_free (basic_block, heap, bbs_to_remove);
|
||||||
|
VEC_free (basic_block, heap, bbs_to_fix_dom);
|
||||||
|
}
|
||||||
|
|
||||||
/* Purge dead EH edges from basic block BB. */
|
/* Purge dead EH edges from basic block BB. */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -5446,33 +5589,13 @@ tree_purge_dead_eh_edges (basic_block bb)
|
||||||
{
|
{
|
||||||
if (e->flags & EDGE_EH)
|
if (e->flags & EDGE_EH)
|
||||||
{
|
{
|
||||||
remove_edge (e);
|
remove_edge_and_dominated_blocks (e);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ei_next (&ei);
|
ei_next (&ei);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Removal of dead EH edges might change dominators of not
|
|
||||||
just immediate successors. E.g. when bb1 is changed so that
|
|
||||||
it no longer can throw and bb1->bb3 and bb1->bb4 are dead
|
|
||||||
eh edges purged by this function in:
|
|
||||||
0
|
|
||||||
/ \
|
|
||||||
v v
|
|
||||||
1-->2
|
|
||||||
/ \ |
|
|
||||||
v v |
|
|
||||||
3-->4 |
|
|
||||||
\ v
|
|
||||||
--->5
|
|
||||||
|
|
|
||||||
-
|
|
||||||
idom(bb5) must be recomputed. For now just free the dominance
|
|
||||||
info. */
|
|
||||||
if (changed)
|
|
||||||
free_dominance_info (CDI_DOMINATORS);
|
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,15 @@ Boston, MA 02110-1301, USA. */
|
||||||
#include "tree-ssa-propagate.h"
|
#include "tree-ssa-propagate.h"
|
||||||
#include "tree-scalar-evolution.h"
|
#include "tree-scalar-evolution.h"
|
||||||
|
|
||||||
|
/* The set of blocks in that at least one of the following changes happened:
|
||||||
|
-- the statement at the end of the block was changed
|
||||||
|
-- the block was newly created
|
||||||
|
-- the set of the predecessors of the block changed
|
||||||
|
-- the set of the successors of the block changed
|
||||||
|
??? Maybe we could track these changes separately, since they determine
|
||||||
|
what cleanups it makes sense to try on the block. */
|
||||||
|
bitmap cfgcleanup_altered_bbs;
|
||||||
|
|
||||||
/* Remove any fallthru edge from EV. Return true if an edge was removed. */
|
/* Remove any fallthru edge from EV. Return true if an edge was removed. */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -59,7 +68,7 @@ remove_fallthru_edge (VEC(edge,gc) *ev)
|
||||||
FOR_EACH_EDGE (e, ei, ev)
|
FOR_EACH_EDGE (e, ei, ev)
|
||||||
if ((e->flags & EDGE_FALLTHRU) != 0)
|
if ((e->flags & EDGE_FALLTHRU) != 0)
|
||||||
{
|
{
|
||||||
remove_edge (e);
|
remove_edge_and_dominated_blocks (e);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -124,7 +133,7 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
|
||||||
|
|
||||||
taken_edge->probability += e->probability;
|
taken_edge->probability += e->probability;
|
||||||
taken_edge->count += e->count;
|
taken_edge->count += e->count;
|
||||||
remove_edge (e);
|
remove_edge_and_dominated_blocks (e);
|
||||||
retval = true;
|
retval = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -138,106 +147,82 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
|
||||||
else
|
else
|
||||||
taken_edge = single_succ_edge (bb);
|
taken_edge = single_succ_edge (bb);
|
||||||
|
|
||||||
|
bitmap_set_bit (cfgcleanup_altered_bbs, bb->index);
|
||||||
bsi_remove (&bsi, true);
|
bsi_remove (&bsi, true);
|
||||||
taken_edge->flags = EDGE_FALLTHRU;
|
taken_edge->flags = EDGE_FALLTHRU;
|
||||||
|
|
||||||
/* We removed some paths from the cfg. */
|
|
||||||
free_dominance_info (CDI_DOMINATORS);
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to remove superfluous control structures. */
|
/* Try to remove superfluous control structures in basic block BB. Returns
|
||||||
|
true if anything changes. */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
cleanup_control_flow (void)
|
cleanup_control_flow_bb (basic_block bb)
|
||||||
{
|
{
|
||||||
basic_block bb;
|
|
||||||
block_stmt_iterator bsi;
|
block_stmt_iterator bsi;
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
tree stmt;
|
tree stmt;
|
||||||
|
|
||||||
/* Detect cases where a mid-block call is now known not to return. */
|
/* If the last statement of the block could throw and now cannot,
|
||||||
if (cfun->gimple_df)
|
we need to prune cfg. */
|
||||||
while (VEC_length (tree, MODIFIED_NORETURN_CALLS (cfun)))
|
retval |= tree_purge_dead_eh_edges (bb);
|
||||||
{
|
|
||||||
stmt = VEC_pop (tree, MODIFIED_NORETURN_CALLS (cfun));
|
|
||||||
bb = bb_for_stmt (stmt);
|
|
||||||
if (bb != NULL && last_stmt (bb) != stmt && noreturn_call_p (stmt))
|
|
||||||
split_block (bb, stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
FOR_EACH_BB (bb)
|
bsi = bsi_last (bb);
|
||||||
|
if (bsi_end_p (bsi))
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
stmt = bsi_stmt (bsi);
|
||||||
|
|
||||||
|
if (TREE_CODE (stmt) == COND_EXPR
|
||||||
|
|| TREE_CODE (stmt) == SWITCH_EXPR)
|
||||||
|
retval |= cleanup_control_expr_graph (bb, bsi);
|
||||||
|
/* If we had a computed goto which has a compile-time determinable
|
||||||
|
destination, then we can eliminate the goto. */
|
||||||
|
else if (TREE_CODE (stmt) == GOTO_EXPR
|
||||||
|
&& TREE_CODE (GOTO_DESTINATION (stmt)) == ADDR_EXPR
|
||||||
|
&& (TREE_CODE (TREE_OPERAND (GOTO_DESTINATION (stmt), 0))
|
||||||
|
== LABEL_DECL))
|
||||||
{
|
{
|
||||||
bsi = bsi_last (bb);
|
edge e;
|
||||||
|
tree label;
|
||||||
|
edge_iterator ei;
|
||||||
|
basic_block target_block;
|
||||||
|
|
||||||
/* If the last statement of the block could throw and now cannot,
|
/* First look at all the outgoing edges. Delete any outgoing
|
||||||
we need to prune cfg. */
|
edges which do not go to the right block. For the one
|
||||||
retval |= tree_purge_dead_eh_edges (bb);
|
edge which goes to the right block, fix up its flags. */
|
||||||
|
label = TREE_OPERAND (GOTO_DESTINATION (stmt), 0);
|
||||||
if (bsi_end_p (bsi))
|
target_block = label_to_block (label);
|
||||||
continue;
|
for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
|
||||||
|
|
||||||
stmt = bsi_stmt (bsi);
|
|
||||||
|
|
||||||
if (TREE_CODE (stmt) == COND_EXPR
|
|
||||||
|| TREE_CODE (stmt) == SWITCH_EXPR)
|
|
||||||
retval |= cleanup_control_expr_graph (bb, bsi);
|
|
||||||
/* If we had a computed goto which has a compile-time determinable
|
|
||||||
destination, then we can eliminate the goto. */
|
|
||||||
else if (TREE_CODE (stmt) == GOTO_EXPR
|
|
||||||
&& TREE_CODE (GOTO_DESTINATION (stmt)) == ADDR_EXPR
|
|
||||||
&& (TREE_CODE (TREE_OPERAND (GOTO_DESTINATION (stmt), 0))
|
|
||||||
== LABEL_DECL))
|
|
||||||
{
|
{
|
||||||
edge e;
|
if (e->dest != target_block)
|
||||||
tree label;
|
remove_edge_and_dominated_blocks (e);
|
||||||
edge_iterator ei;
|
else
|
||||||
basic_block target_block;
|
|
||||||
bool removed_edge = false;
|
|
||||||
|
|
||||||
/* First look at all the outgoing edges. Delete any outgoing
|
|
||||||
edges which do not go to the right block. For the one
|
|
||||||
edge which goes to the right block, fix up its flags. */
|
|
||||||
label = TREE_OPERAND (GOTO_DESTINATION (stmt), 0);
|
|
||||||
target_block = label_to_block (label);
|
|
||||||
for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
|
|
||||||
{
|
{
|
||||||
if (e->dest != target_block)
|
/* Turn off the EDGE_ABNORMAL flag. */
|
||||||
{
|
e->flags &= ~EDGE_ABNORMAL;
|
||||||
removed_edge = true;
|
|
||||||
remove_edge (e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Turn off the EDGE_ABNORMAL flag. */
|
|
||||||
e->flags &= ~EDGE_ABNORMAL;
|
|
||||||
|
|
||||||
/* And set EDGE_FALLTHRU. */
|
/* And set EDGE_FALLTHRU. */
|
||||||
e->flags |= EDGE_FALLTHRU;
|
e->flags |= EDGE_FALLTHRU;
|
||||||
ei_next (&ei);
|
ei_next (&ei);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we removed one or more edges, then we will need to fix the
|
|
||||||
dominators. It may be possible to incrementally update them. */
|
|
||||||
if (removed_edge)
|
|
||||||
free_dominance_info (CDI_DOMINATORS);
|
|
||||||
|
|
||||||
/* Remove the GOTO_EXPR as it is not needed. The CFG has all the
|
|
||||||
relevant information we need. */
|
|
||||||
bsi_remove (&bsi, true);
|
|
||||||
retval = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for indirect calls that have been turned into
|
bitmap_set_bit (cfgcleanup_altered_bbs, bb->index);
|
||||||
noreturn calls. */
|
bitmap_set_bit (cfgcleanup_altered_bbs, target_block->index);
|
||||||
else if (noreturn_call_p (stmt) && remove_fallthru_edge (bb->succs))
|
|
||||||
{
|
/* Remove the GOTO_EXPR as it is not needed. The CFG has all the
|
||||||
free_dominance_info (CDI_DOMINATORS);
|
relevant information we need. */
|
||||||
retval = true;
|
bsi_remove (&bsi, true);
|
||||||
}
|
retval = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for indirect calls that have been turned into
|
||||||
|
noreturn calls. */
|
||||||
|
else if (noreturn_call_p (stmt) && remove_fallthru_edge (bb->succs))
|
||||||
|
retval = true;
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,12 +351,10 @@ phi_alternatives_equal (basic_block dest, edge e1, edge e2)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Removes forwarder block BB. Returns false if this failed. If a new
|
/* Removes forwarder block BB. Returns false if this failed. */
|
||||||
forwarder block is created due to redirection of edges, it is
|
|
||||||
stored to worklist. */
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
remove_forwarder_block (basic_block bb, basic_block **worklist)
|
remove_forwarder_block (basic_block bb)
|
||||||
{
|
{
|
||||||
edge succ = single_succ_edge (bb), e, s;
|
edge succ = single_succ_edge (bb), e, s;
|
||||||
basic_block dest = succ->dest;
|
basic_block dest = succ->dest;
|
||||||
|
@ -434,6 +417,8 @@ remove_forwarder_block (basic_block bb, basic_block **worklist)
|
||||||
/* Redirect the edges. */
|
/* Redirect the edges. */
|
||||||
for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
|
for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
|
||||||
{
|
{
|
||||||
|
bitmap_set_bit (cfgcleanup_altered_bbs, e->src->index);
|
||||||
|
|
||||||
if (e->flags & EDGE_ABNORMAL)
|
if (e->flags & EDGE_ABNORMAL)
|
||||||
{
|
{
|
||||||
/* If there is an abnormal edge, redirect it anyway, and
|
/* If there is an abnormal edge, redirect it anyway, and
|
||||||
|
@ -450,15 +435,6 @@ remove_forwarder_block (basic_block bb, basic_block **worklist)
|
||||||
for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
|
for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
|
||||||
add_phi_arg (phi, PHI_ARG_DEF (phi, succ->dest_idx), s);
|
add_phi_arg (phi, PHI_ARG_DEF (phi, succ->dest_idx), s);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
/* The source basic block might become a forwarder. We know
|
|
||||||
that it was not a forwarder before, since it used to have
|
|
||||||
at least two outgoing edges, so we may just add it to
|
|
||||||
worklist. */
|
|
||||||
if (tree_forwarder_block_p (s->src, false))
|
|
||||||
*(*worklist)++ = s->src;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (seen_abnormal_edge)
|
if (seen_abnormal_edge)
|
||||||
|
@ -476,6 +452,8 @@ remove_forwarder_block (basic_block bb, basic_block **worklist)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitmap_set_bit (cfgcleanup_altered_bbs, dest->index);
|
||||||
|
|
||||||
/* Update the dominators. */
|
/* Update the dominators. */
|
||||||
if (dom_info_available_p (CDI_DOMINATORS))
|
if (dom_info_available_p (CDI_DOMINATORS))
|
||||||
{
|
{
|
||||||
|
@ -501,65 +479,120 @@ remove_forwarder_block (basic_block bb, basic_block **worklist)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Removes forwarder blocks. */
|
/* Split basic blocks on calls in the middle of a basic block that are now
|
||||||
|
known not to return, and remove the unreachable code. */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
cleanup_forwarder_blocks (void)
|
split_bbs_on_noreturn_calls (void)
|
||||||
{
|
{
|
||||||
basic_block bb;
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
basic_block *worklist = XNEWVEC (basic_block, n_basic_blocks);
|
tree stmt;
|
||||||
basic_block *current = worklist;
|
basic_block bb;
|
||||||
|
|
||||||
FOR_EACH_BB (bb)
|
/* Detect cases where a mid-block call is now known not to return. */
|
||||||
{
|
if (cfun->gimple_df)
|
||||||
if (tree_forwarder_block_p (bb, false))
|
while (VEC_length (tree, MODIFIED_NORETURN_CALLS (cfun)))
|
||||||
*current++ = bb;
|
{
|
||||||
}
|
stmt = VEC_pop (tree, MODIFIED_NORETURN_CALLS (cfun));
|
||||||
|
bb = bb_for_stmt (stmt);
|
||||||
|
if (bb == NULL
|
||||||
|
|| last_stmt (bb) == stmt
|
||||||
|
|| !noreturn_call_p (stmt))
|
||||||
|
continue;
|
||||||
|
|
||||||
while (current != worklist)
|
changed = true;
|
||||||
{
|
split_block (bb, stmt);
|
||||||
bb = *--current;
|
remove_fallthru_edge (bb->succs);
|
||||||
changed |= remove_forwarder_block (bb, ¤t);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
free (worklist);
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do one round of CFG cleanup. */
|
/* Tries to cleanup cfg in basic block BB. Returns true if anything
|
||||||
|
changes. */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
cleanup_tree_cfg_1 (void)
|
cleanup_tree_cfg_bb (basic_block bb)
|
||||||
{
|
{
|
||||||
bool retval;
|
bool retval = false;
|
||||||
|
|
||||||
retval = cleanup_control_flow ();
|
retval = cleanup_control_flow_bb (bb);
|
||||||
retval |= delete_unreachable_blocks ();
|
|
||||||
|
|
||||||
/* Forwarder blocks can carry line number information which is
|
/* Forwarder blocks can carry line number information which is
|
||||||
useful when debugging, so we only clean them up when
|
useful when debugging, so we only clean them up when
|
||||||
optimizing. */
|
optimizing. */
|
||||||
|
|
||||||
if (optimize > 0)
|
if (optimize > 0
|
||||||
{
|
&& tree_forwarder_block_p (bb, false)
|
||||||
/* cleanup_forwarder_blocks can redirect edges out of
|
&& remove_forwarder_block (bb))
|
||||||
SWITCH_EXPRs, which can get expensive. So we want to enable
|
return true;
|
||||||
recording of edge to CASE_LABEL_EXPR mappings around the call
|
|
||||||
to cleanup_forwarder_blocks. */
|
|
||||||
start_recording_case_labels ();
|
|
||||||
retval |= cleanup_forwarder_blocks ();
|
|
||||||
end_recording_case_labels ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Merging the blocks may create new opportunities for folding
|
/* Merging the blocks may create new opportunities for folding
|
||||||
conditional branches (due to the elimination of single-valued PHI
|
conditional branches (due to the elimination of single-valued PHI
|
||||||
nodes). */
|
nodes). */
|
||||||
retval |= merge_seq_blocks ();
|
if (single_succ_p (bb)
|
||||||
|
&& can_merge_blocks_p (bb, single_succ (bb)))
|
||||||
|
{
|
||||||
|
merge_blocks (bb, single_succ (bb));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Iterate the cfg cleanups, while anything changes. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
cleanup_tree_cfg_1 (void)
|
||||||
|
{
|
||||||
|
bool retval = false;
|
||||||
|
basic_block bb;
|
||||||
|
unsigned i, n;
|
||||||
|
|
||||||
|
retval |= split_bbs_on_noreturn_calls ();
|
||||||
|
|
||||||
|
/* Prepare the worklists of altered blocks. */
|
||||||
|
cfgcleanup_altered_bbs = BITMAP_ALLOC (NULL);
|
||||||
|
|
||||||
|
/* During forwarder block cleanup, we may redirect edges out of
|
||||||
|
SWITCH_EXPRs, which can get expensive. So we want to enable
|
||||||
|
recording of edge to CASE_LABEL_EXPR. */
|
||||||
|
start_recording_case_labels ();
|
||||||
|
|
||||||
|
/* Start by iterating over all basic blocks. We cannot use FOR_EACH_BB,
|
||||||
|
since the basic blocks may get removed. */
|
||||||
|
n = last_basic_block;
|
||||||
|
for (i = NUM_FIXED_BLOCKS; i < n; i++)
|
||||||
|
{
|
||||||
|
bb = BASIC_BLOCK (i);
|
||||||
|
if (bb)
|
||||||
|
retval |= cleanup_tree_cfg_bb (bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now process the altered blocks, as long as any are available. */
|
||||||
|
while (!bitmap_empty_p (cfgcleanup_altered_bbs))
|
||||||
|
{
|
||||||
|
i = bitmap_first_set_bit (cfgcleanup_altered_bbs);
|
||||||
|
bitmap_clear_bit (cfgcleanup_altered_bbs, i);
|
||||||
|
if (i < NUM_FIXED_BLOCKS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bb = BASIC_BLOCK (i);
|
||||||
|
if (!bb)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
retval |= cleanup_tree_cfg_bb (bb);
|
||||||
|
|
||||||
|
/* Rerun split_bbs_on_noreturn_calls, in case we have altered any noreturn
|
||||||
|
calls. */
|
||||||
|
retval |= split_bbs_on_noreturn_calls ();
|
||||||
|
}
|
||||||
|
|
||||||
|
end_recording_case_labels ();
|
||||||
|
BITMAP_FREE (cfgcleanup_altered_bbs);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Remove unreachable blocks and other miscellaneous clean up work.
|
/* Remove unreachable blocks and other miscellaneous clean up work.
|
||||||
Return true if the flowgraph was modified, false otherwise. */
|
Return true if the flowgraph was modified, false otherwise. */
|
||||||
|
@ -567,20 +600,26 @@ cleanup_tree_cfg_1 (void)
|
||||||
bool
|
bool
|
||||||
cleanup_tree_cfg (void)
|
cleanup_tree_cfg (void)
|
||||||
{
|
{
|
||||||
bool retval, changed;
|
bool changed;
|
||||||
|
|
||||||
timevar_push (TV_TREE_CLEANUP_CFG);
|
timevar_push (TV_TREE_CLEANUP_CFG);
|
||||||
|
|
||||||
/* Iterate until there are no more cleanups left to do. If any
|
/* Iterate until there are no more cleanups left to do. If any
|
||||||
iteration changed the flowgraph, set CHANGED to true. */
|
iteration changed the flowgraph, set CHANGED to true.
|
||||||
changed = false;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
retval = cleanup_tree_cfg_1 ();
|
|
||||||
changed |= retval;
|
|
||||||
}
|
|
||||||
while (retval);
|
|
||||||
|
|
||||||
|
If dominance information is available, there cannot be any unreachable
|
||||||
|
blocks. */
|
||||||
|
if (!dom_computed[CDI_DOMINATORS])
|
||||||
|
{
|
||||||
|
changed = delete_unreachable_blocks ();
|
||||||
|
calculate_dominance_info (CDI_DOMINATORS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
changed = false;
|
||||||
|
|
||||||
|
changed |= cleanup_tree_cfg_1 ();
|
||||||
|
|
||||||
|
gcc_assert (dom_computed[CDI_DOMINATORS]);
|
||||||
compact_blocks ();
|
compact_blocks ();
|
||||||
|
|
||||||
#ifdef ENABLE_CHECKING
|
#ifdef ENABLE_CHECKING
|
||||||
|
@ -602,7 +641,6 @@ cleanup_tree_cfg_loop (void)
|
||||||
if (changed && current_loops != NULL)
|
if (changed && current_loops != NULL)
|
||||||
{
|
{
|
||||||
bitmap changed_bbs = BITMAP_ALLOC (NULL);
|
bitmap changed_bbs = BITMAP_ALLOC (NULL);
|
||||||
calculate_dominance_info (CDI_DOMINATORS);
|
|
||||||
fix_loop_structure (changed_bbs);
|
fix_loop_structure (changed_bbs);
|
||||||
|
|
||||||
/* This usually does nothing. But sometimes parts of cfg that originally
|
/* This usually does nothing. But sometimes parts of cfg that originally
|
||||||
|
|
|
@ -778,8 +778,10 @@ extern void start_recording_case_labels (void);
|
||||||
extern void end_recording_case_labels (void);
|
extern void end_recording_case_labels (void);
|
||||||
extern basic_block move_sese_region_to_fn (struct function *, basic_block,
|
extern basic_block move_sese_region_to_fn (struct function *, basic_block,
|
||||||
basic_block);
|
basic_block);
|
||||||
|
void remove_edge_and_dominated_blocks (edge);
|
||||||
|
|
||||||
/* In tree-cfgcleanup.c */
|
/* In tree-cfgcleanup.c */
|
||||||
|
extern bitmap cfgcleanup_altered_bbs;
|
||||||
extern bool cleanup_tree_cfg (void);
|
extern bool cleanup_tree_cfg (void);
|
||||||
extern bool cleanup_tree_cfg_loop (void);
|
extern bool cleanup_tree_cfg_loop (void);
|
||||||
|
|
||||||
|
|
|
@ -2804,6 +2804,10 @@ optimize_inline_calls (tree fn)
|
||||||
|
|
||||||
push_gimplify_context ();
|
push_gimplify_context ();
|
||||||
|
|
||||||
|
/* We make no attempts to keep dominance info up-to-date. */
|
||||||
|
free_dominance_info (CDI_DOMINATORS);
|
||||||
|
free_dominance_info (CDI_POST_DOMINATORS);
|
||||||
|
|
||||||
/* Reach the trees by walking over the CFG, and note the
|
/* Reach the trees by walking over the CFG, and note the
|
||||||
enclosing basic-blocks in the call edges. */
|
enclosing basic-blocks in the call edges. */
|
||||||
/* We walk the blocks going forward, because inlined function bodies
|
/* We walk the blocks going forward, because inlined function bodies
|
||||||
|
@ -2840,9 +2844,6 @@ optimize_inline_calls (tree fn)
|
||||||
fold_cond_expr_cond ();
|
fold_cond_expr_cond ();
|
||||||
if (current_function_has_nonlocal_label)
|
if (current_function_has_nonlocal_label)
|
||||||
make_nonlocal_label_edges ();
|
make_nonlocal_label_edges ();
|
||||||
/* We make no attempts to keep dominance info up-to-date. */
|
|
||||||
free_dominance_info (CDI_DOMINATORS);
|
|
||||||
free_dominance_info (CDI_POST_DOMINATORS);
|
|
||||||
/* It would be nice to check SSA/CFG/statement consistency here, but it is
|
/* It would be nice to check SSA/CFG/statement consistency here, but it is
|
||||||
not possible yet - the IPA passes might make various functions to not
|
not possible yet - the IPA passes might make various functions to not
|
||||||
throw and they don't care to proactively update local EH info. This is
|
throw and they don't care to proactively update local EH info. This is
|
||||||
|
|
Loading…
Reference in New Issue