summaryrefslogtreecommitdiff
path: root/gcc/tree-cfg.c
diff options
context:
space:
mode:
authorrakdver <rakdver@138bc75d-0d04-0410-961f-82ee72b054a4>2005-05-17 19:55:53 +0000
committerrakdver <rakdver@138bc75d-0d04-0410-961f-82ee72b054a4>2005-05-17 19:55:53 +0000
commit8171a1dd58f689ea938c7a771c5ec6020cca13d5 (patch)
treed5471dc3f0c17a518b2a28a858669d705b2a853d /gcc/tree-cfg.c
parent9ba78c6a99a114f5e01304cbbebfa12e2af95057 (diff)
downloadgcc-8171a1dd58f689ea938c7a771c5ec6020cca13d5.tar.gz
* tree-cfg.c (tree_can_merge_blocks_p): Allow phi nodes in the
merged block. (replace_uses_by): New function. (tree_merge_blocks): Eliminate the phi nodes in the merged block. * tree-flow.h (fold_stmt_inplace): Declare. * tree-ssa-ccp.c (fold_stmt_inplace): New function. * tree-ssa-dom.c (tree_ssa_dominator_optimize): Update dominance info after cfg cleanup. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@99850 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-cfg.c')
-rw-r--r--gcc/tree-cfg.c96
1 files changed, 93 insertions, 3 deletions
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index be7e0f53dbb..4beb0e74290 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -1261,6 +1261,7 @@ tree_can_merge_blocks_p (basic_block a, basic_block b)
{
tree stmt;
block_stmt_iterator bsi;
+ tree phi;
if (!single_succ_p (a))
return false;
@@ -1288,9 +1289,19 @@ tree_can_merge_blocks_p (basic_block a, basic_block b)
&& DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt)))
return false;
- /* There may be no PHI nodes at the start of B. */
- if (phi_nodes (b))
- return false;
+ /* It must be possible to eliminate all phi nodes in B. If ssa form
+ is not up-to-date, we cannot eliminate any phis. */
+ phi = phi_nodes (b);
+ if (phi)
+ {
+ if (need_ssa_update_p ())
+ return false;
+
+ for (; phi; phi = PHI_CHAIN (phi))
+ if (!is_gimple_reg (PHI_RESULT (phi))
+ && !may_propagate_copy (PHI_RESULT (phi), PHI_ARG_DEF (phi, 0)))
+ return false;
+ }
/* Do not remove user labels. */
for (bsi = bsi_start (b); !bsi_end_p (bsi); bsi_next (&bsi))
@@ -1310,6 +1321,55 @@ tree_can_merge_blocks_p (basic_block a, basic_block b)
return true;
}
+/* Replaces all uses of NAME by VAL. */
+
+static void
+replace_uses_by (tree name, tree val)
+{
+ imm_use_iterator imm_iter;
+ use_operand_p use;
+ tree stmt;
+ edge e;
+ unsigned i;
+ VEC(tree,heap) *stmts = VEC_alloc (tree, heap, 20);
+
+ FOR_EACH_IMM_USE_SAFE (use, imm_iter, name)
+ {
+ stmt = USE_STMT (use);
+
+ SET_USE (use, val);
+
+ if (TREE_CODE (stmt) == PHI_NODE)
+ {
+ e = PHI_ARG_EDGE (stmt, PHI_ARG_INDEX_FROM_USE (use));
+ if (e->flags & EDGE_ABNORMAL)
+ {
+ /* This can only occur for virtual operands, since
+ for the real ones SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
+ would prevent replacement. */
+ gcc_assert (!is_gimple_reg (name));
+ SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
+ }
+ }
+ else
+ VEC_safe_push (tree, heap, stmts, stmt);
+ }
+
+ /* We do not update the statements in the loop above. Consider
+ x = w * w;
+
+ If we performed the update in the first loop, the statement
+ would be rescanned after first occurence of w is replaced,
+ the new uses would be placed to the beginning of the list,
+ and we would never process them. */
+ for (i = 0; VEC_iterate (tree, stmts, i, stmt); i++)
+ {
+ fold_stmt_inplace (stmt);
+ update_stmt (stmt);
+ }
+
+ VEC_free (tree, heap, stmts);
+}
/* Merge block B into block A. */
@@ -1318,10 +1378,40 @@ tree_merge_blocks (basic_block a, basic_block b)
{
block_stmt_iterator bsi;
tree_stmt_iterator last;
+ tree phi;
if (dump_file)
fprintf (dump_file, "Merging blocks %d and %d\n", a->index, b->index);
+ /* Remove the phi nodes. */
+ bsi = bsi_last (a);
+ for (phi = phi_nodes (b); phi; phi = phi_nodes (b))
+ {
+ tree def = PHI_RESULT (phi), use = PHI_ARG_DEF (phi, 0);
+ tree copy;
+
+ if (!may_propagate_copy (def, use)
+ /* Propagating pointers might cause the set of vops for statements
+ to be changed, and thus require ssa form update. */
+ || (is_gimple_reg (def)
+ && POINTER_TYPE_P (TREE_TYPE (def))))
+ {
+ gcc_assert (is_gimple_reg (def));
+
+ /* Note that just emiting the copies is fine -- there is no problem
+ with ordering of phi nodes. This is because A is the single
+ predecessor of B, therefore results of the phi nodes cannot
+ appear as arguments of the phi nodes. */
+ copy = build2 (MODIFY_EXPR, void_type_node, def, use);
+ bsi_insert_after (&bsi, copy, BSI_NEW_STMT);
+ SET_PHI_RESULT (phi, NULL_TREE);
+ SSA_NAME_DEF_STMT (def) = copy;
+ }
+ else
+ replace_uses_by (def, use);
+ remove_phi_node (phi, NULL);
+ }
+
/* Ensure that B follows A. */
move_block_after (b, a);