/* CFG cleanup for trees.
- Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
-#include "rtl.h"
#include "tm_p.h"
-#include "hard-reg-set.h"
#include "basic-block.h"
#include "output.h"
#include "toplev.h"
edge e;
edge_iterator ei;
bool warned;
+ location_t loc;
fold_defer_overflow_warnings ();
- val = gimple_fold (stmt);
+ loc = gimple_location (stmt);
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_COND:
+ {
+ tree lhs = gimple_cond_lhs (stmt);
+ tree rhs = gimple_cond_rhs (stmt);
+ /* For conditions try harder and lookup single-argument
+ PHI nodes. Only do so from the same basic-block though
+ as other basic-blocks may be dead already. */
+ if (TREE_CODE (lhs) == SSA_NAME
+ && !name_registered_for_update_p (lhs))
+ {
+ gimple def_stmt = SSA_NAME_DEF_STMT (lhs);
+ if (gimple_code (def_stmt) == GIMPLE_PHI
+ && gimple_phi_num_args (def_stmt) == 1
+ && gimple_bb (def_stmt) == gimple_bb (stmt)
+ && (TREE_CODE (PHI_ARG_DEF (def_stmt, 0)) != SSA_NAME
+ || !name_registered_for_update_p (PHI_ARG_DEF (def_stmt,
+ 0))))
+ lhs = PHI_ARG_DEF (def_stmt, 0);
+ }
+ if (TREE_CODE (rhs) == SSA_NAME
+ && !name_registered_for_update_p (rhs))
+ {
+ gimple def_stmt = SSA_NAME_DEF_STMT (rhs);
+ if (gimple_code (def_stmt) == GIMPLE_PHI
+ && gimple_phi_num_args (def_stmt) == 1
+ && gimple_bb (def_stmt) == gimple_bb (stmt)
+ && (TREE_CODE (PHI_ARG_DEF (def_stmt, 0)) != SSA_NAME
+ || !name_registered_for_update_p (PHI_ARG_DEF (def_stmt,
+ 0))))
+ rhs = PHI_ARG_DEF (def_stmt, 0);
+ }
+ val = fold_binary_loc (loc, gimple_cond_code (stmt),
+ boolean_type_node, lhs, rhs);
+ break;
+ }
+
+ case GIMPLE_SWITCH:
+ val = gimple_switch_index (stmt);
+ break;
+
+ default:
+ val = NULL_TREE;
+ }
taken_edge = find_taken_edge (bb, val);
if (!taken_edge)
{
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
gcc_assert (bb != ENTRY_BLOCK_PTR);
#endif
+ locus = single_succ_edge (bb)->goto_locus;
+
/* There should not be an edge coming from entry, or an EH edge. */
{
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->preds)
if (e->src == ENTRY_BLOCK_PTR || (e->flags & EDGE_EH))
return false;
+ /* If goto_locus of any of the edges differs, prevent removing
+ the forwarder block for -O0. */
+ else if (optimize == 0 && e->goto_locus != locus)
+ return false;
}
/* Now walk through the statements backward. We can ignore labels,
case GIMPLE_LABEL:
if (DECL_NONLOCAL (gimple_label_label (stmt)))
return false;
+ if (optimize == 0 && gimple_location (stmt) != locus)
+ return false;
break;
/* ??? For now, hope there's a corresponding debug
gimple label;
edge_iterator ei;
gimple_stmt_iterator gsi, gsi_to;
+ bool can_move_debug_stmts;
/* We check for infinite loops already in tree_forwarder_block_p.
However it may happen that the infinite loop is created
if (dest == bb)
return false;
- /* If the destination block consists of a nonlocal label, do not merge
- it. */
+ /* If the destination block consists of a nonlocal label or is a
+ EH landing pad, do not merge it. */
label = first_stmt (dest);
if (label
&& gimple_code (label) == GIMPLE_LABEL
- && DECL_NONLOCAL (gimple_label_label (label)))
+ && (DECL_NONLOCAL (gimple_label_label (label))
+ || EH_LANDING_PAD_NR (gimple_label_label (label)) != 0))
return false;
/* If there is an abnormal edge to basic block BB, but not into
}
}
+ can_move_debug_stmts = single_pred_p (dest);
+
/* Redirect the edges. */
for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
{
/* Move debug statements if the destination has just a single
predecessor. */
- if (single_pred_p (dest))
+ if (can_move_debug_stmts)
{
gsi_to = gsi_after_labels (dest);
for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); )
{
- if (!is_gimple_debug (gsi_stmt (gsi)))
+ gimple debug = gsi_stmt (gsi);
+ if (!is_gimple_debug (debug))
break;
gsi_remove (&gsi, false);
- gsi_insert_before (&gsi_to, label, GSI_SAME_STMT);
+ gsi_insert_before (&gsi_to, debug, GSI_SAME_STMT);
}
}
retval = cleanup_control_flow_bb (bb);
- /* Forwarder blocks can carry line number information which is
- useful when debugging, so we only clean them up when
- optimizing. */
- if (optimize > 0
- && tree_forwarder_block_p (bb, false)
+ if (tree_forwarder_block_p (bb, false)
&& remove_forwarder_block (bb))
return true;
/* We have to feed into another basic block with PHI
nodes. */
- if (!phi_nodes (dest)
+ if (gimple_seq_empty_p (phi_nodes (dest))
/* We don't want to deal with a basic block with
abnormal edges. */
|| has_abnormal_incoming_edge_p (bb))