aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-cfgcleanup.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-cfgcleanup.cc')
-rw-r--r--gcc/tree-cfgcleanup.cc663
1 files changed, 289 insertions, 374 deletions
diff --git a/gcc/tree-cfgcleanup.cc b/gcc/tree-cfgcleanup.cc
index 9a8a668..093fde9 100644
--- a/gcc/tree-cfgcleanup.cc
+++ b/gcc/tree-cfgcleanup.cc
@@ -46,6 +46,8 @@ along with GCC; see the file COPYING3. If not see
#include "cgraph.h"
#include "tree-into-ssa.h"
#include "tree-cfgcleanup.h"
+#include "gimple-pretty-print.h"
+#include "target.h"
/* The set of blocks in that at least one of the following changes happened:
@@ -122,6 +124,41 @@ convert_single_case_switch (gswitch *swtch, gimple_stmt_iterator &gsi)
return true;
}
+/* Canonicalize _Bool == 0 and _Bool != 1 to _Bool != 0 of STMT in BB by
+ swapping edges of the BB. */
+bool
+canonicalize_bool_cond (gcond *stmt, basic_block bb)
+{
+ tree rhs1 = gimple_cond_lhs (stmt);
+ tree rhs2 = gimple_cond_rhs (stmt);
+ enum tree_code code = gimple_cond_code (stmt);
+ if (code != EQ_EXPR && code != NE_EXPR)
+ return false;
+ if (TREE_CODE (TREE_TYPE (rhs1)) != BOOLEAN_TYPE
+ && (!INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
+ || TYPE_PRECISION (TREE_TYPE (rhs1)) != 1))
+ return false;
+
+ /* Canonicalize _Bool == 0 and _Bool != 1 to _Bool != 0 by swapping edges. */
+ if (code == EQ_EXPR && !integer_zerop (rhs2))
+ return false;
+ if (code == NE_EXPR && !integer_onep (rhs2))
+ return false;
+
+ gimple_cond_set_code (stmt, NE_EXPR);
+ gimple_cond_set_rhs (stmt, build_zero_cst (TREE_TYPE (rhs1)));
+ EDGE_SUCC (bb, 0)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
+ EDGE_SUCC (bb, 1)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
+
+ if (dump_file)
+ {
+ fprintf (dump_file, " Swapped '");
+ print_gimple_expr (dump_file, stmt, 0);
+ fprintf (dump_file, "'\n");
+ }
+ return true;
+}
+
/* Disconnect an unreachable block in the control expression starting
at block BB. */
@@ -145,6 +182,9 @@ cleanup_control_expr_graph (basic_block bb, gimple_stmt_iterator gsi)
&& convert_single_case_switch (as_a<gswitch *> (stmt), gsi))
stmt = gsi_stmt (gsi);
+ if (gimple_code (stmt) == GIMPLE_COND)
+ canonicalize_bool_cond (as_a<gcond*> (stmt), bb);
+
fold_defer_overflow_warnings ();
switch (gimple_code (stmt))
{
@@ -338,114 +378,6 @@ cleanup_control_flow_bb (basic_block bb)
return retval;
}
-/* 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.
-
- As a precondition, we require that BB be not equal to
- the entry block. */
-
-static bool
-tree_forwarder_block_p (basic_block bb, bool phi_wanted)
-{
- gimple_stmt_iterator gsi;
- location_t locus;
-
- /* BB must have a single outgoing edge. */
- if (single_succ_p (bb) != 1
- /* If PHI_WANTED is false, BB must not have any PHI nodes.
- Otherwise, BB must have PHI nodes. */
- || gimple_seq_empty_p (phi_nodes (bb)) == phi_wanted
- /* BB may not be a predecessor of the exit block. */
- || single_succ (bb) == EXIT_BLOCK_PTR_FOR_FN (cfun)
- /* Nor should this be an infinite loop. */
- || single_succ (bb) == bb
- /* BB may not have an abnormal outgoing edge. */
- || (single_succ_edge (bb)->flags & EDGE_ABNORMAL))
- return false;
-
- gcc_checking_assert (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun));
-
- locus = single_succ_edge (bb)->goto_locus;
-
- /* There should not be an edge coming from entry, or an EH edge. */
- {
- edge_iterator ei;
- edge e;
-
- FOR_EACH_EDGE (e, ei, bb->preds)
- if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun) || (e->flags & EDGE_EH))
- return false;
- /* If goto_locus of any of the edges differs, prevent removing
- the forwarder block when not optimizing. */
- else if (!optimize
- && (LOCATION_LOCUS (e->goto_locus) != UNKNOWN_LOCATION
- || LOCATION_LOCUS (locus) != UNKNOWN_LOCATION)
- && e->goto_locus != locus)
- return false;
- }
-
- /* Now walk through the statements backward. We can ignore labels,
- anything else means this is not a forwarder block. */
- for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
- {
- gimple *stmt = gsi_stmt (gsi);
-
- switch (gimple_code (stmt))
- {
- case GIMPLE_LABEL:
- if (DECL_NONLOCAL (gimple_label_label (as_a <glabel *> (stmt))))
- return false;
- if (!optimize
- && (gimple_has_location (stmt)
- || LOCATION_LOCUS (locus) != UNKNOWN_LOCATION)
- && gimple_location (stmt) != locus)
- return false;
- break;
-
- /* ??? For now, hope there's a corresponding debug
- assignment at the destination. */
- case GIMPLE_DEBUG:
- break;
-
- default:
- return false;
- }
- }
-
- if (current_loops)
- {
- basic_block dest;
- /* Protect loop headers. */
- if (bb_loop_header_p (bb))
- return false;
-
- dest = EDGE_SUCC (bb, 0)->dest;
- /* Protect loop preheaders and latches if requested. */
- if (dest->loop_father->header == dest)
- {
- if (bb->loop_father == dest->loop_father)
- {
- if (loops_state_satisfies_p (LOOPS_HAVE_SIMPLE_LATCHES))
- return false;
- /* 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));
- }
- else if (bb->loop_father == loop_outer (dest->loop_father))
- return !loops_state_satisfies_p (LOOPS_HAVE_PREHEADERS);
- /* Always preserve other edges into loop headers that are
- not simple latches or preheaders. */
- return false;
- }
- }
-
- 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. */
@@ -531,31 +463,61 @@ move_debug_stmts_from_forwarder (basic_block src,
}
}
-/* Removes forwarder block BB. Returns false if this failed. */
+/* 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 and was removed.
+
+ As a precondition, we require that BB be not equal to
+ the entry block.
+ If CAN_SPLIT is true, we can split the edge to have
+ another bb with with the phi. */
static bool
-remove_forwarder_block (basic_block bb)
+maybe_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;
- edge_iterator ei;
- gimple_stmt_iterator gsi, gsi_to;
+ gimple_stmt_iterator gsi;
+ location_t locus;
- /* We check for infinite loops already in tree_forwarder_block_p.
- However it may happen that the infinite loop is created
- afterwards due to removal of forwarders. */
- if (dest == bb)
+ /* BB must have a single outgoing edge. */
+ if (!single_succ_p (bb)
+ /* BB may not be a predecessor of the exit block. */
+ || single_succ (bb) == EXIT_BLOCK_PTR_FOR_FN (cfun)
+ /* Nor should this be an infinite loop. */
+ || single_succ (bb) == bb
+ /* BB may not have an abnormal outgoing edge. */
+ || (single_succ_edge (bb)->flags & EDGE_ABNORMAL))
return false;
- /* If the destination block consists of a nonlocal label or is a
- EH landing pad, do not merge it. */
- stmt = first_stmt (dest);
- if (stmt)
- if (glabel *label_stmt = dyn_cast <glabel *> (stmt))
- if (DECL_NONLOCAL (gimple_label_label (label_stmt))
- || EH_LANDING_PAD_NR (gimple_label_label (label_stmt)) != 0)
+ gcc_checking_assert (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun));
+
+ locus = single_succ_edge (bb)->goto_locus;
+
+ /* There should not be an edge coming from entry, or an EH edge. */
+ {
+ edge_iterator ei;
+ edge e;
+
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun) || (e->flags & EDGE_EH))
return false;
+ /* If goto_locus of any of the edges differs, prevent removing
+ the forwarder block when not optimizing. */
+ else if (!optimize
+ && (LOCATION_LOCUS (e->goto_locus) != UNKNOWN_LOCATION
+ || LOCATION_LOCUS (locus) != UNKNOWN_LOCATION)
+ && e->goto_locus != locus)
+ return false;
+ }
+
+ /* If this bb has a single predecessor and that predecssor
+ has a single successor, this bb will be merged with the
+ predecessor so ignore it for removing of the forwarder block. */
+ if (single_pred_p (bb)
+ && single_succ_p (single_pred_edge (bb)->src))
+ return false;
+
+ bool has_phi = !gimple_seq_empty_p (phi_nodes (bb));
+ basic_block dest = single_succ_edge (bb)->dest;
/* 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
@@ -567,17 +529,131 @@ remove_forwarder_block (basic_block bb)
does not like it.
So if there is an abnormal edge to BB, proceed only if there is
- no abnormal edge to DEST and there are no phi nodes in DEST. */
+ no abnormal edge to DEST and there are no phi nodes in DEST.
+ If the BB has phi, we don't want to deal with abnormal edges either. */
if (bb_has_abnormal_pred (bb)
&& (bb_has_abnormal_pred (dest)
- || !gimple_seq_empty_p (phi_nodes (dest))))
+ || !gimple_seq_empty_p (phi_nodes (dest))
+ || has_phi))
+ return false;
+
+ /* When we have a phi, we have to feed into another
+ basic block with PHI nodes. */
+ if (has_phi && gimple_seq_empty_p (phi_nodes (dest)))
return false;
+ /* Now walk through the statements backward. We can ignore labels,
+ anything else means this is not a forwarder block. */
+ for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_LABEL:
+ if (DECL_NONLOCAL (gimple_label_label (as_a <glabel *> (stmt)))
+ || EH_LANDING_PAD_NR (gimple_label_label (as_a <glabel *> (stmt))))
+ return false;
+ if (!optimize
+ && (gimple_has_location (stmt)
+ || LOCATION_LOCUS (locus) != UNKNOWN_LOCATION)
+ && gimple_location (stmt) != locus)
+ return false;
+ break;
+
+ /* ??? For now, hope there's a corresponding debug
+ assignment at the destination. */
+ case GIMPLE_DEBUG:
+ break;
+
+ default:
+ return false;
+ }
+ }
+ /* 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 (has_phi
+ && dominated_by_p (CDI_DOMINATORS, dest, bb))
+ {
+ gphi_iterator gsi;
+ unsigned int dest_idx = single_succ_edge (bb)->dest_idx;
+
+ /* BB dominates DEST. There may be many users of the PHI
+ nodes in BB. However, there is still a trivial case we
+ can handle. If the result of every PHI in BB is used
+ only by a PHI in DEST, then we can trivially merge the
+ PHI nodes from BB into DEST. */
+ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gphi *phi = gsi.phi ();
+ tree result = gimple_phi_result (phi);
+ use_operand_p imm_use;
+ gimple *use_stmt;
+
+ /* If the PHI's result is never used, then we can just
+ ignore it an. */
+ if (has_zero_uses (result))
+ continue;
+
+ /* Get the single use of the result of this PHI node. */
+ if (!single_imm_use (result, &imm_use, &use_stmt)
+ || gimple_code (use_stmt) != GIMPLE_PHI
+ || gimple_bb (use_stmt) != dest
+ || gimple_phi_arg_def (use_stmt, dest_idx) != result)
+ return false;
+ }
+ }
+
+ if (current_loops)
+ {
+ /* Protect loop headers. */
+ if (bb_loop_header_p (bb))
+ return false;
+
+ /* Protect loop preheaders and latches if requested. */
+ if (dest->loop_father->header == dest)
+ {
+ if (bb->loop_father == dest->loop_father)
+ {
+ if (loops_state_satisfies_p (LOOPS_HAVE_SIMPLE_LATCHES))
+ return false;
+ /* 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. */
+ 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. */
+ else if (bb->loop_father == loop_outer (dest->loop_father)
+ && !has_phi
+ && !loops_state_satisfies_p (LOOPS_HAVE_PREHEADERS))
+ ;
+ else
+ /* Always preserve other edges into loop headers that are
+ not simple latches or preheaders. */
+ return false;
+ }
+ }
+
+ edge succ = single_succ_edge (bb), e, s;
+ gimple *stmt;
+ gimple_stmt_iterator gsi_to;
+
/* If there are phi nodes in DEST, and some of the blocks that are
predecessors of BB are also predecessors of DEST, check that the
- phi node arguments match. */
- if (!gimple_seq_empty_p (phi_nodes (dest)))
+ phi node arguments match.
+ Otherwise we have to split the edge and that becomes
+ a "forwarder" again. */
+ if ((!can_split || !has_phi)
+ && !gimple_seq_empty_p (phi_nodes (dest)))
{
+ edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->preds)
{
s = find_edge (e->src, dest);
@@ -595,9 +671,19 @@ remove_forwarder_block (basic_block bb)
bool dest_single_pred_p = single_pred_p (dest);
/* Redirect the edges. */
- for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
+ for (edge_iterator ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
{
- bitmap_set_bit (cfgcleanup_altered_bbs, e->src->index);
+ if (cfgcleanup_altered_bbs)
+ bitmap_set_bit (cfgcleanup_altered_bbs, e->src->index);
+ s = find_edge (e->src, dest);
+
+ /* See if we can split the edge if we already have an edge from src to dest. */
+ if (can_split && has_phi)
+ /* PHI arguments are different. Create a forwarder block by
+ splitting E so that we can merge PHI arguments on E to
+ DEST. */
+ if (s && !phi_alternatives_equal (dest, s, succ))
+ e = single_succ_edge (split_edge (e));
if (e->flags & EDGE_ABNORMAL)
{
@@ -610,10 +696,24 @@ remove_forwarder_block (basic_block bb)
if (s == e)
{
+ /* If we merge the forwarder with phis into a loop header
+ verify if we are creating another loop latch edge.
+ If so, reset number of iteration information of the loop. */
+ if (has_phi
+ && dest->loop_father
+ && dest->loop_father->header == dest
+ && dominated_by_p (CDI_DOMINATORS, e->src, dest))
+ {
+ dest->loop_father->any_upper_bound = false;
+ dest->loop_father->any_likely_upper_bound = false;
+ free_numbers_of_iterations_estimates (dest->loop_father);
+ }
/* Copy arguments for the phi nodes, since the edge was not
here before. */
- copy_phi_arg_into_existing_phi (succ, s);
+ copy_phi_arg_into_existing_phi (succ, s, has_phi);
}
+ else
+ redirect_edge_var_map_clear (s);
}
/* Move nonlocal labels and computed goto targets as well as user
@@ -646,26 +746,24 @@ remove_forwarder_block (basic_block bb)
move_debug_stmts_from_forwarder (bb, dest, dest_single_pred_p,
pred, pred && single_succ_p (pred));
- bitmap_set_bit (cfgcleanup_altered_bbs, dest->index);
+ if (cfgcleanup_altered_bbs)
+ bitmap_set_bit (cfgcleanup_altered_bbs, dest->index);
/* Update the dominators. */
- if (dom_info_available_p (CDI_DOMINATORS))
- {
- basic_block dom, dombb, domdest;
-
- dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
- domdest = get_immediate_dominator (CDI_DOMINATORS, dest);
- if (domdest == bb)
- {
- /* Shortcut to avoid calling (relatively expensive)
- nearest_common_dominator unless necessary. */
- dom = dombb;
- }
- else
- dom = nearest_common_dominator (CDI_DOMINATORS, domdest, dombb);
+ basic_block dom, dombb, domdest;
- set_immediate_dominator (CDI_DOMINATORS, dest, dom);
+ dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
+ domdest = get_immediate_dominator (CDI_DOMINATORS, dest);
+ if (domdest == bb)
+ {
+ /* Shortcut to avoid calling (relatively expensive)
+ nearest_common_dominator unless necessary. */
+ dom = dombb;
}
+ else
+ dom = nearest_common_dominator (CDI_DOMINATORS, domdest, dombb);
+
+ set_immediate_dominator (CDI_DOMINATORS, dest, dom);
/* Adjust latch infomation of BB's parent loop as otherwise
the cfg hook has a hard time not to kill the loop. */
@@ -767,8 +865,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, false)
- && remove_forwarder_block (bb))
+ if (maybe_remove_forwarder_block (bb))
return true;
/* If there is a merge opportunity with the predecessor
@@ -1211,155 +1308,6 @@ cleanup_tree_cfg (unsigned ssa_update_flags)
return changed;
}
-/* Tries to merge the PHI nodes at BB into those at BB's sole successor.
- Returns true if successful. */
-
-static bool
-remove_forwarder_block_with_phi (basic_block bb)
-{
- edge succ = single_succ_edge (bb);
- basic_block dest = succ->dest;
- gimple *label;
- basic_block dombb, domdest, dom;
-
- /* We check for infinite loops already in tree_forwarder_block_p.
- However it may happen that the infinite loop is created
- afterwards due to removal of forwarders. */
- if (dest == bb)
- return false;
-
- /* Removal of forwarders may expose new natural loops and thus
- a block may turn into a loop header. */
- if (current_loops && bb_loop_header_p (bb))
- return false;
-
- /* If the destination block consists of a nonlocal label, do not
- merge it. */
- label = first_stmt (dest);
- if (label)
- if (glabel *label_stmt = dyn_cast <glabel *> (label))
- if (DECL_NONLOCAL (gimple_label_label (label_stmt)))
- return false;
-
- /* Record BB's single pred in case we need to update the father
- loop's latch information later. */
- basic_block pred = NULL;
- if (single_pred_p (bb))
- pred = single_pred (bb);
- bool dest_single_pred_p = single_pred_p (dest);
-
- /* Redirect each incoming edge to BB to DEST. */
- while (EDGE_COUNT (bb->preds) > 0)
- {
- edge e = EDGE_PRED (bb, 0), s;
- gphi_iterator gsi;
-
- s = find_edge (e->src, dest);
- if (s)
- {
- /* We already have an edge S from E->src to DEST. If S and
- E->dest's sole successor edge have the same PHI arguments
- at DEST, redirect S to DEST. */
- if (phi_alternatives_equal (dest, s, succ))
- {
- e = redirect_edge_and_branch (e, dest);
- redirect_edge_var_map_clear (e);
- continue;
- }
-
- /* PHI arguments are different. Create a forwarder block by
- splitting E so that we can merge PHI arguments on E to
- DEST. */
- e = single_succ_edge (split_edge (e));
- }
- else
- {
- /* If we merge the forwarder into a loop header verify if we
- are creating another loop latch edge. If so, reset
- number of iteration information of the loop. */
- if (dest->loop_father->header == dest
- && dominated_by_p (CDI_DOMINATORS, e->src, dest))
- {
- dest->loop_father->any_upper_bound = false;
- dest->loop_father->any_likely_upper_bound = false;
- free_numbers_of_iterations_estimates (dest->loop_father);
- }
- }
-
- s = redirect_edge_and_branch (e, dest);
-
- /* redirect_edge_and_branch must not create a new edge. */
- gcc_assert (s == e);
-
- /* Add to the PHI nodes at DEST each PHI argument removed at the
- destination of E. */
- for (gsi = gsi_start_phis (dest);
- !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gphi *phi = gsi.phi ();
- tree def = gimple_phi_arg_def (phi, succ->dest_idx);
- location_t locus = gimple_phi_arg_location_from_edge (phi, succ);
-
- if (TREE_CODE (def) == SSA_NAME)
- {
- /* If DEF is one of the results of PHI nodes removed during
- redirection, replace it with the PHI argument that used
- to be on E. */
- vec<edge_var_map> *head = redirect_edge_var_map_vector (e);
- size_t length = head ? head->length () : 0;
- for (size_t i = 0; i < length; i++)
- {
- edge_var_map *vm = &(*head)[i];
- tree old_arg = redirect_edge_var_map_result (vm);
- tree new_arg = redirect_edge_var_map_def (vm);
-
- if (def == old_arg)
- {
- def = new_arg;
- locus = redirect_edge_var_map_location (vm);
- break;
- }
- }
- }
-
- add_phi_arg (phi, def, s, locus);
- }
-
- redirect_edge_var_map_clear (e);
- }
-
- /* Move debug statements. Reset them if the destination does not
- have a single predecessor. */
- move_debug_stmts_from_forwarder (bb, dest, dest_single_pred_p,
- pred, pred && single_succ_p (pred));
-
- /* Update the dominators. */
- dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
- domdest = get_immediate_dominator (CDI_DOMINATORS, dest);
- if (domdest == bb)
- {
- /* Shortcut to avoid calling (relatively expensive)
- nearest_common_dominator unless necessary. */
- dom = dombb;
- }
- else
- dom = nearest_common_dominator (CDI_DOMINATORS, domdest, dombb);
-
- set_immediate_dominator (CDI_DOMINATORS, dest, dom);
-
- /* Adjust latch infomation of BB's parent loop as otherwise
- the cfg hook has a hard time not to kill the loop. */
- if (current_loops && bb->loop_father->latch == bb)
- bb->loop_father->latch = pred;
-
- /* Remove BB since all of BB's incoming edges have been redirected
- to DEST. */
- delete_basic_block (bb);
-
- return true;
-}
-
/* This pass merges PHI nodes if one feeds into another. For example,
suppose we have the following:
@@ -1416,91 +1364,30 @@ public:
unsigned int
pass_merge_phi::execute (function *fun)
{
- basic_block *worklist = XNEWVEC (basic_block, n_basic_blocks_for_fn (fun));
- basic_block *current = worklist;
- basic_block bb;
-
+ int forwarder_removed = 0;
calculate_dominance_info (CDI_DOMINATORS);
/* Find all PHI nodes that we may be able to merge. */
- FOR_EACH_BB_FN (bb, fun)
+ unsigned n = last_basic_block_for_fn (fun);
+ for (unsigned i = NUM_FIXED_BLOCKS; i < n; i++)
{
- basic_block dest;
-
- /* Look for a forwarder block with PHI nodes. */
- if (!tree_forwarder_block_p (bb, true))
- continue;
-
- dest = single_succ (bb);
-
- /* We have to feed into another basic block with PHI
- nodes. */
- if (gimple_seq_empty_p (phi_nodes (dest))
- /* We don't want to deal with a basic block with
- abnormal edges. */
- || bb_has_abnormal_pred (bb))
+ basic_block bb = BASIC_BLOCK_FOR_FN (fun, i);
+ if (!bb)
continue;
- if (!dominated_by_p (CDI_DOMINATORS, dest, bb))
- {
- /* If BB does not dominate DEST, then the PHI nodes at
- DEST must be the only users of the results of the PHI
- nodes at BB. */
- *current++ = bb;
- }
- else
- {
- gphi_iterator gsi;
- unsigned int dest_idx = single_succ_edge (bb)->dest_idx;
-
- /* BB dominates DEST. There may be many users of the PHI
- nodes in BB. However, there is still a trivial case we
- can handle. If the result of every PHI in BB is used
- only by a PHI in DEST, then we can trivially merge the
- PHI nodes from BB into DEST. */
- for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gphi *phi = gsi.phi ();
- tree result = gimple_phi_result (phi);
- use_operand_p imm_use;
- gimple *use_stmt;
-
- /* If the PHI's result is never used, then we can just
- ignore it. */
- if (has_zero_uses (result))
- continue;
-
- /* Get the single use of the result of this PHI node. */
- if (!single_imm_use (result, &imm_use, &use_stmt)
- || gimple_code (use_stmt) != GIMPLE_PHI
- || gimple_bb (use_stmt) != dest
- || gimple_phi_arg_def (use_stmt, dest_idx) != result)
- break;
- }
-
- /* If the loop above iterated through all the PHI nodes
- in BB, then we can merge the PHIs from BB into DEST. */
- if (gsi_end_p (gsi))
- *current++ = bb;
- }
- }
-
- /* Now let's drain WORKLIST. */
- bool changed = false;
- while (current != worklist)
- {
- bb = *--current;
- changed |= remove_forwarder_block_with_phi (bb);
+ /* Look for a forwarder block with PHI nodes. */
+ if (maybe_remove_forwarder_block (bb, true))
+ forwarder_removed++;
}
- free (worklist);
/* Removing forwarder blocks can cause formerly irreducible loops
to become reducible if we merged two entry blocks. */
- if (changed
+ if (forwarder_removed != 0
&& current_loops)
loops_state_set (LOOPS_NEED_FIXUP);
+ statistics_counter_event (fun, "Forwarder blocks removed",
+ forwarder_removed);
return 0;
}
@@ -1528,8 +1415,36 @@ execute_cleanup_cfg_post_optimizing (void)
}
maybe_remove_unreachable_handlers ();
cleanup_dead_labels ();
- if (group_case_labels ())
- todo |= TODO_cleanup_cfg;
+ if (group_case_labels () && cleanup_tree_cfg ())
+ todo |= TODO_update_ssa;
+
+ /* When optimizing undo the merging of forwarder blocks
+ that phis for better out of ssa expansion. */
+ if (optimize)
+ make_forwarders_with_degenerate_phis (cfun);
+
+ basic_block bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (bb);
+ /* If the first (and only) bb and the only non debug
+ statement is __builtin_unreachable call, then replace it with a trap
+ so the function is at least one instruction in size. */
+ if (!gsi_end_p (gsi)
+ && gimple_call_builtin_p (gsi_stmt (gsi), BUILT_IN_UNREACHABLE))
+ {
+ if (targetm.have_trap ())
+ {
+ gimple_call_set_fndecl (gsi_stmt (gsi), builtin_decl_implicit (BUILT_IN_UNREACHABLE_TRAP));
+ update_stmt (gsi_stmt (gsi));
+ }
+ /* If the target does not have a trap, convert it into an infinite loop. */
+ else
+ {
+ gsi_remove (&gsi, true);
+ make_single_succ_edge (bb, bb, EDGE_FALLTHRU);
+ fix_loop_structure (NULL);
+ }
+ }
+
if ((flag_compare_debug_opt || flag_compare_debug)
&& flag_dump_final_insns)
{