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;
}
}
+ 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;
/* 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. */
}
}
- 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
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
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++;
}