remove_forwarder_block is never called without calling tree_forwarder_block_p
before hand so this merges the two functions and simplifies the code slightly.
tree_forwarder_block_p was only returning true at the very end (except for one
location in the code checking the loop which is fixed here) so this nature to
merge the two functions even.
move_debug_stmts_from_forwarder and phi_alternatives_equal definitions were
moved
to before maybe_remove_forwarder_block.
Bootstrapped and tested on x86_64-linux-gnu.
gcc/ChangeLog:
* tree-cfgcleanup.cc (tree_forwarder_block_p): Merge this and ...
(remove_forwarder_block): This into ...
(maybe_remove_forwarder_block): Here.
(cleanup_tree_cfg_bb): Call only maybe_remove_forwarder_block.
(pass_merge_phi::execute): Likewise.
Signed-off-by: Andrew Pinski <[email protected]>
---
gcc/tree-cfgcleanup.cc | 207 ++++++++++++++++++++---------------------
1 file changed, 100 insertions(+), 107 deletions(-)
diff --git a/gcc/tree-cfgcleanup.cc b/gcc/tree-cfgcleanup.cc
index 9aeb4f3fc99..b9384db9f3d 100644
--- a/gcc/tree-cfgcleanup.cc
+++ b/gcc/tree-cfgcleanup.cc
@@ -378,15 +378,103 @@ cleanup_control_flow_bb (basic_block bb)
return retval;
}
+
+/* If all the PHI nodes in DEST have alternatives for E1 and E2 and
+ those alternatives are equal in each of the PHI nodes, then return
+ true, else return false. */
+
+bool
+phi_alternatives_equal (basic_block dest, edge e1, edge e2)
+{
+ int n1 = e1->dest_idx;
+ int n2 = e2->dest_idx;
+ gphi_iterator gsi;
+
+ for (gsi = gsi_start_phis (dest); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gphi *phi = gsi.phi ();
+ tree val1 = gimple_phi_arg_def (phi, n1);
+ tree val2 = gimple_phi_arg_def (phi, n2);
+
+ gcc_assert (val1 != NULL_TREE);
+ gcc_assert (val2 != NULL_TREE);
+
+ if (!operand_equal_for_phi_arg_p (val1, val2))
+ return false;
+ }
+
+ return true;
+}
+
+/* Move debug stmts from the forwarder block SRC to DEST or PRED. */
+
+static void
+move_debug_stmts_from_forwarder (basic_block src,
+ basic_block dest, bool dest_single_pred_p,
+ basic_block pred, bool pred_single_succ_p)
+{
+ if (!MAY_HAVE_DEBUG_STMTS)
+ return;
+
+ /* If we cannot move to the destination but to the predecessor do that. */
+ if (!dest_single_pred_p && pred_single_succ_p)
+ {
+ gimple_stmt_iterator gsi_to = gsi_last_bb (pred);
+ if (gsi_end_p (gsi_to) || !stmt_ends_bb_p (gsi_stmt (gsi_to)))
+ {
+ for (gimple_stmt_iterator gsi = gsi_after_labels (src);
+ !gsi_end_p (gsi);)
+ {
+ gimple *debug = gsi_stmt (gsi);
+ gcc_assert (is_gimple_debug (debug));
+ gsi_move_after (&gsi, &gsi_to);
+ }
+ return;
+ }
+ }
+
+ /* Else move to DEST or drop/reset them. */
+ gimple_stmt_iterator gsi_to = gsi_after_labels (dest);
+ for (gimple_stmt_iterator gsi = gsi_after_labels (src); !gsi_end_p (gsi);)
+ {
+ gimple *debug = gsi_stmt (gsi);
+ gcc_assert (is_gimple_debug (debug));
+ /* Move debug binds anyway, but not anything else like begin-stmt
+ markers unless they are always valid at the destination. */
+ if (dest_single_pred_p
+ || gimple_debug_bind_p (debug))
+ {
+ gsi_move_before (&gsi, &gsi_to);
+ /* Reset debug-binds that are not always valid at the destination.
+ Simply dropping them can cause earlier values to become live,
+ generating wrong debug information.
+ ??? There are several things we could improve here. For
+ one we might be able to move stmts to the predecessor.
+ For anther, if the debug stmt is immediately followed by a
+ (debug) definition in the destination (on a post-dominated path?)
+ we can elide it without any bad effects. */
+ if (!dest_single_pred_p)
+ {
+ gimple_debug_bind_reset_value (debug);
+ update_stmt (debug);
+ }
+ }
+ else
+ gsi_next (&gsi);
+ }
+}
+
/* Return true if basic block BB does nothing except pass control
flow to another block and that we can safely insert a label at
- the start of the successor block.
+ the start of the successor block and was removed.
As a precondition, we require that BB be not equal to
- the entry block. */
+ the entry block.
+ If CAN_SPLIT is true, we can split the edge to have
+ another bb with with the phi. */
static bool
-tree_forwarder_block_p (basic_block bb)
+maybe_remove_forwarder_block (basic_block bb, bool can_split = false)
{
gimple_stmt_iterator gsi;
location_t locus;
@@ -460,11 +548,12 @@ tree_forwarder_block_p (basic_block bb)
}
}
+ bool has_phi = !gimple_seq_empty_p (phi_nodes (bb));
/* If BB has PHIs and does not dominate DEST,
then the PHI nodes at DEST must be the only
users of the results of the PHI nodes at BB.
So only check when BB dominates dest. */
- if (!gimple_seq_empty_p (phi_nodes (bb))
+ if (has_phi
&& dominated_by_p (CDI_DOMINATORS, dest, bb))
{
gphi_iterator gsi;
@@ -513,9 +602,10 @@ tree_forwarder_block_p (basic_block bb)
/* If bb doesn't have a single predecessor we'd make this
loop have multiple latches. Don't do that if that
would in turn require disambiguating them. */
- return (single_pred_p (bb)
- || loops_state_satisfies_p
- (LOOPS_MAY_HAVE_MULTIPLE_LATCHES));
+ if (!single_pred_p (bb)
+ && !loops_state_satisfies_p
+ (LOOPS_MAY_HAVE_MULTIPLE_LATCHES))
+ return false;
}
/* cleanup_tree_cfg_noloop just created the loop preheader, don't
remove it if it has phis. */
@@ -530,104 +620,9 @@ tree_forwarder_block_p (basic_block bb)
}
}
- return true;
-}
-
-/* If all the PHI nodes in DEST have alternatives for E1 and E2 and
- those alternatives are equal in each of the PHI nodes, then return
- true, else return false. */
-
-bool
-phi_alternatives_equal (basic_block dest, edge e1, edge e2)
-{
- int n1 = e1->dest_idx;
- int n2 = e2->dest_idx;
- gphi_iterator gsi;
-
- for (gsi = gsi_start_phis (dest); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gphi *phi = gsi.phi ();
- tree val1 = gimple_phi_arg_def (phi, n1);
- tree val2 = gimple_phi_arg_def (phi, n2);
-
- gcc_assert (val1 != NULL_TREE);
- gcc_assert (val2 != NULL_TREE);
-
- if (!operand_equal_for_phi_arg_p (val1, val2))
- return false;
- }
-
- return true;
-}
-
-/* Move debug stmts from the forwarder block SRC to DEST or PRED. */
-
-static void
-move_debug_stmts_from_forwarder (basic_block src,
- basic_block dest, bool dest_single_pred_p,
- basic_block pred, bool pred_single_succ_p)
-{
- if (!MAY_HAVE_DEBUG_STMTS)
- return;
-
- /* If we cannot move to the destination but to the predecessor do that. */
- if (!dest_single_pred_p && pred_single_succ_p)
- {
- gimple_stmt_iterator gsi_to = gsi_last_bb (pred);
- if (gsi_end_p (gsi_to) || !stmt_ends_bb_p (gsi_stmt (gsi_to)))
- {
- for (gimple_stmt_iterator gsi = gsi_after_labels (src);
- !gsi_end_p (gsi);)
- {
- gimple *debug = gsi_stmt (gsi);
- gcc_assert (is_gimple_debug (debug));
- gsi_move_after (&gsi, &gsi_to);
- }
- return;
- }
- }
-
- /* Else move to DEST or drop/reset them. */
- gimple_stmt_iterator gsi_to = gsi_after_labels (dest);
- for (gimple_stmt_iterator gsi = gsi_after_labels (src); !gsi_end_p (gsi);)
- {
- gimple *debug = gsi_stmt (gsi);
- gcc_assert (is_gimple_debug (debug));
- /* Move debug binds anyway, but not anything else like begin-stmt
- markers unless they are always valid at the destination. */
- if (dest_single_pred_p
- || gimple_debug_bind_p (debug))
- {
- gsi_move_before (&gsi, &gsi_to);
- /* Reset debug-binds that are not always valid at the destination.
- Simply dropping them can cause earlier values to become live,
- generating wrong debug information.
- ??? There are several things we could improve here. For
- one we might be able to move stmts to the predecessor.
- For anther, if the debug stmt is immediately followed by a
- (debug) definition in the destination (on a post-dominated path?)
- we can elide it without any bad effects. */
- if (!dest_single_pred_p)
- {
- gimple_debug_bind_reset_value (debug);
- update_stmt (debug);
- }
- }
- else
- gsi_next (&gsi);
- }
-}
-
-/* Removes forwarder block BB. Returns false if this failed. */
-
-static bool
-remove_forwarder_block (basic_block bb, bool can_split = false)
-{
edge succ = single_succ_edge (bb), e, s;
- basic_block dest = succ->dest;
gimple *stmt;
- gimple_stmt_iterator gsi, gsi_to;
- bool has_phi = !gimple_seq_empty_p (phi_nodes (bb));
+ gimple_stmt_iterator gsi_to;
/* If there is an abnormal edge to basic block BB, but not into
dest, problems might occur during removal of the phi node at out
@@ -872,8 +867,7 @@ want_merge_blocks_p (basic_block bb1, basic_block bb2)
static bool
cleanup_tree_cfg_bb (basic_block bb)
{
- if (tree_forwarder_block_p (bb)
- && remove_forwarder_block (bb))
+ if (maybe_remove_forwarder_block (bb))
return true;
/* If there is a merge opportunity with the predecessor
@@ -1384,8 +1378,7 @@ pass_merge_phi::execute (function *fun)
continue;
/* Look for a forwarder block with PHI nodes. */
- if (tree_forwarder_block_p (bb)
- && remove_forwarder_block (bb, true))
+ if (maybe_remove_forwarder_block (bb, true))
forwarder_removed++;
}
--
2.43.0