OSDN Git Service

Fix grammar/spelling.
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfgcleanup.c
index eae0c84..8348d25 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
@@ -23,23 +23,18 @@ along with GCC; see the file COPYING3.  If not see
 #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"
+#include "diagnostic-core.h"
 #include "flags.h"
 #include "function.h"
-#include "expr.h"
 #include "ggc.h"
 #include "langhooks.h"
-#include "diagnostic.h"
 #include "tree-flow.h"
 #include "timevar.h"
 #include "tree-dump.h"
 #include "tree-pass.h"
-#include "toplev.h"
 #include "except.h"
 #include "cfgloop.h"
 #include "cfglayout.h"
@@ -103,20 +98,28 @@ cleanup_control_expr_graph (basic_block bb, gimple_stmt_iterator gsi)
            /* 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)
+           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))
+                   && 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)
+           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))
+                   && 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),
@@ -259,6 +262,7 @@ 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
@@ -273,9 +277,9 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted)
       || (single_succ_edge (bb)->flags & EDGE_ABNORMAL))
     return false;
 
-#if ENABLE_CHECKING
-  gcc_assert (bb != ENTRY_BLOCK_PTR);
-#endif
+  gcc_checking_assert (bb != ENTRY_BLOCK_PTR);
+
+  locus = single_succ_edge (bb)->goto_locus;
 
   /* There should not be an edge coming from entry, or an EH edge.  */
   {
@@ -285,6 +289,10 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted)
     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,
@@ -298,6 +306,8 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted)
        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
@@ -324,21 +334,6 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted)
   return true;
 }
 
-/* Return true if BB has at least one abnormal incoming edge.  */
-
-static inline bool
-has_abnormal_incoming_edge_p (basic_block bb)
-{
-  edge e;
-  edge_iterator ei;
-
-  FOR_EACH_EDGE (e, ei, bb->preds)
-    if (e->flags & EDGE_ABNORMAL)
-      return true;
-
-  return false;
-}
-
 /* 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.  */
@@ -404,8 +399,8 @@ remove_forwarder_block (basic_block bb)
 
      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.  */
-  if (has_abnormal_incoming_edge_p (bb)
-      && (has_abnormal_incoming_edge_p (dest)
+  if (bb_has_abnormal_pred (bb)
+      && (bb_has_abnormal_pred (dest)
          || !gimple_seq_empty_p (phi_nodes (dest))))
     return false;
 
@@ -425,7 +420,7 @@ remove_forwarder_block (basic_block bb)
        }
     }
 
-  can_move_debug_stmts = single_pred_p (dest);
+  can_move_debug_stmts = MAY_HAVE_DEBUG_STMTS && single_pred_p (dest);
 
   /* Redirect the edges.  */
   for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
@@ -481,8 +476,7 @@ remove_forwarder_block (basic_block bb)
        gsi_next (&gsi);
     }
 
-  /* Move debug statements if the destination has just a single
-     predecessor.  */
+  /* Move debug statements if the destination has a single predecessor.  */
   if (can_move_debug_stmts)
     {
       gsi_to = gsi_after_labels (dest);
@@ -523,6 +517,68 @@ remove_forwarder_block (basic_block bb)
   return true;
 }
 
+/* STMT is a call that has been discovered noreturn.  Fixup the CFG
+   and remove LHS.  Return true if something changed.  */
+
+bool
+fixup_noreturn_call (gimple stmt)
+{
+  basic_block bb = gimple_bb (stmt);
+  bool changed = false;
+
+  if (gimple_call_builtin_p (stmt, BUILT_IN_RETURN))
+    return false;
+
+  /* First split basic block if stmt is not last.  */
+  if (stmt != gsi_stmt (gsi_last_bb (bb)))
+    split_block (bb, stmt);
+
+  changed |= remove_fallthru_edge (bb->succs);
+
+  /* If there is LHS, remove it.  */
+  if (gimple_call_lhs (stmt))
+    {
+      tree op = gimple_call_lhs (stmt);
+      gimple_call_set_lhs (stmt, NULL_TREE);
+
+      /* We need to remove SSA name to avoid checking errors.
+        All uses are dominated by the noreturn and thus will
+        be removed afterwards.
+        We proactively remove affected non-PHI statements to avoid
+        fixup_cfg from trying to update them and crashing.  */
+      if (TREE_CODE (op) == SSA_NAME)
+       {
+         use_operand_p use_p;
+          imm_use_iterator iter;
+         gimple use_stmt;
+         bitmap_iterator bi;
+         unsigned int bb_index;
+
+         bitmap blocks = BITMAP_ALLOC (NULL);
+
+          FOR_EACH_IMM_USE_STMT (use_stmt, iter, op)
+           {
+             if (gimple_code (use_stmt) != GIMPLE_PHI)
+               bitmap_set_bit (blocks, gimple_bb (use_stmt)->index);
+             else
+               FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
+                 SET_USE (use_p, error_mark_node);
+           }
+         EXECUTE_IF_SET_IN_BITMAP (blocks, 0, bb_index, bi)
+           delete_basic_block (BASIC_BLOCK (bb_index));
+         BITMAP_FREE (blocks);
+         release_ssa_name (op);
+       }
+      update_stmt (stmt);
+      changed = true;
+    }
+  /* Similarly remove VDEF if there is any.  */
+  else if (gimple_vdef (stmt))
+    update_stmt (stmt);
+  return changed;
+}
+
+
 /* Split basic blocks on calls in the middle of a basic block that are now
    known not to return, and remove the unreachable code.  */
 
@@ -543,68 +599,26 @@ split_bbs_on_noreturn_calls (void)
           BB is present in the cfg.  */
        if (bb == NULL
            || bb->index < NUM_FIXED_BLOCKS
-           || bb->index >= n_basic_blocks
+           || bb->index >= last_basic_block
            || BASIC_BLOCK (bb->index) != bb
-           || last_stmt (bb) == stmt
            || !gimple_call_noreturn_p (stmt))
          continue;
 
-       changed = true;
-       split_block (bb, stmt);
-       remove_fallthru_edge (bb->succs);
+       changed |= fixup_noreturn_call (stmt);
       }
 
   return changed;
 }
 
-/* If GIMPLE_OMP_RETURN in basic block BB is unreachable, remove it.  */
-
-static bool
-cleanup_omp_return (basic_block bb)
-{
-  gimple stmt = last_stmt (bb);
-  basic_block control_bb;
-
-  if (stmt == NULL
-      || gimple_code (stmt) != GIMPLE_OMP_RETURN
-      || !single_pred_p (bb))
-    return false;
-
-  control_bb = single_pred (bb);
-  stmt = last_stmt (control_bb);
-
-  if (stmt == NULL || gimple_code (stmt) != GIMPLE_OMP_SECTIONS_SWITCH)
-    return false;
-
-  /* The block with the control statement normally has two entry edges -- one
-     from entry, one from continue.  If continue is removed, return is
-     unreachable, so we remove it here as well.  */
-  if (EDGE_COUNT (control_bb->preds) == 2)
-    return false;
-
-  gcc_assert (EDGE_COUNT (control_bb->preds) == 1);
-  remove_edge_and_dominated_blocks (single_pred_edge (bb));
-  return true;
-}
-
 /* Tries to cleanup cfg in basic block BB.  Returns true if anything
    changes.  */
 
 static bool
 cleanup_tree_cfg_bb (basic_block bb)
 {
-  bool retval = false;
-
-  if (cleanup_omp_return (bb))
-    return true;
-
-  retval = cleanup_control_flow_bb (bb);
+  bool 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;
 
@@ -725,7 +739,10 @@ cleanup_tree_cfg_noloop (void)
 static void
 repair_loop_structures (void)
 {
-  bitmap changed_bbs = BITMAP_ALLOC (NULL);
+  bitmap changed_bbs;
+
+  timevar_push (TV_REPAIR_LOOPS);
+  changed_bbs = BITMAP_ALLOC (NULL);
   fix_loop_structure (changed_bbs);
 
   /* This usually does nothing.  But sometimes parts of cfg that originally
@@ -742,6 +759,7 @@ repair_loop_structures (void)
   scev_reset ();
 
   loops_state_clear (LOOPS_NEED_FIXUP);
+  timevar_pop (TV_REPAIR_LOOPS);
 }
 
 /* Cleanup cfg and repair loop structures.  */
@@ -832,7 +850,7 @@ remove_forwarder_block_with_phi (basic_block bb)
                 redirection, replace it with the PHI argument that used
                 to be on E.  */
              head = redirect_edge_var_map_vector (e);
-             for (i = 0; VEC_iterate (edge_var_map, head, i, vm); ++i)
+             FOR_EACH_VEC_ELT (edge_var_map, head, i, vm)
                {
                  tree old_arg = redirect_edge_var_map_result (vm);
                  tree new_arg = redirect_edge_var_map_def (vm);
@@ -921,7 +939,7 @@ merge_phi_nodes (void)
       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))
+         || bb_has_abnormal_pred (bb))
        continue;
 
       if (!dominated_by_p (CDI_DOMINATORS, dest, bb))
@@ -1001,7 +1019,7 @@ struct gimple_opt_pass pass_merge_phi =
   0,                           /* properties_provided */
   0,                           /* properties_destroyed */
   0,                           /* todo_flags_start */
-  TODO_dump_func | TODO_ggc_collect    /* todo_flags_finish */
+  TODO_ggc_collect             /* todo_flags_finish */
   | TODO_verify_ssa
  }
 };