OSDN Git Service

2008-04-20 Thomas Koenig <tkoenig@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfgcleanup.c
index 00fed83..8970a9b 100644 (file)
@@ -507,6 +507,36 @@ split_bbs_on_noreturn_calls (void)
   return changed;
 }
 
+/* If OMP_RETURN in basic block BB is unreachable, remove it.  */
+
+static bool
+cleanup_omp_return (basic_block bb)
+{
+  tree stmt = last_stmt (bb);
+  basic_block control_bb;
+
+  if (stmt == NULL_TREE
+      || TREE_CODE (stmt) != OMP_RETURN
+      || !single_pred_p (bb))
+    return false;
+
+  control_bb = single_pred (bb);
+  stmt = last_stmt (control_bb);
+
+  if (TREE_CODE (stmt) != 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.  */
 
@@ -515,8 +545,11 @@ cleanup_tree_cfg_bb (basic_block bb)
 {
   bool retval = false;
 
-  retval = cleanup_control_flow_bb (bb);
+  if (cleanup_omp_return (bb))
+    return true;
 
+  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.  */
@@ -596,8 +629,8 @@ cleanup_tree_cfg_1 (void)
 /* Remove unreachable blocks and other miscellaneous clean up work.
    Return true if the flowgraph was modified, false otherwise.  */
 
-bool
-cleanup_tree_cfg (void)
+static bool
+cleanup_tree_cfg_noloop (void)
 {
   bool changed;
 
@@ -632,34 +665,47 @@ cleanup_tree_cfg (void)
 
   timevar_pop (TV_TREE_CLEANUP_CFG);
 
+  if (changed && current_loops)
+    loops_state_set (LOOPS_NEED_FIXUP);
+
   return changed;
 }
 
-/* Cleanup cfg and repair loop structures.  */
+/* Repairs loop structures.  */
 
-bool
-cleanup_tree_cfg_loop (void)
+static void
+repair_loop_structures (void)
 {
-  bool changed = cleanup_tree_cfg ();
+  bitmap changed_bbs = BITMAP_ALLOC (NULL);
+  fix_loop_structure (changed_bbs);
 
-  if (changed && current_loops != NULL)
-    {
-      bitmap changed_bbs = BITMAP_ALLOC (NULL);
-      fix_loop_structure (changed_bbs);
-
-      /* This usually does nothing.  But sometimes parts of cfg that originally
-        were inside a loop get out of it due to edge removal (since they
-        become unreachable by back edges from latch).  */
-      if ((current_loops->state & LOOP_CLOSED_SSA) != 0)
-       rewrite_into_loop_closed_ssa (changed_bbs, TODO_update_ssa);
+  /* This usually does nothing.  But sometimes parts of cfg that originally
+     were inside a loop get out of it due to edge removal (since they
+     become unreachable by back edges from latch).  */
+  if (loops_state_satisfies_p (LOOP_CLOSED_SSA))
+    rewrite_into_loop_closed_ssa (changed_bbs, TODO_update_ssa);
 
-      BITMAP_FREE (changed_bbs);
+  BITMAP_FREE (changed_bbs);
 
 #ifdef ENABLE_CHECKING
-      verify_loop_structure ();
+  verify_loop_structure ();
 #endif
-      scev_reset ();
-    }
+  scev_reset ();
+
+  loops_state_clear (LOOPS_NEED_FIXUP);
+}
+
+/* Cleanup cfg and repair loop structures.  */
+
+bool
+cleanup_tree_cfg (void)
+{
+  bool changed = cleanup_tree_cfg_noloop ();
+
+  if (current_loops != NULL
+      && loops_state_satisfies_p (LOOPS_NEED_FIXUP))
+    repair_loop_structures ();
+
   return changed;
 }
 
@@ -702,7 +748,7 @@ remove_forwarder_block_with_phi (basic_block bb)
          if (phi_alternatives_equal (dest, s, succ))
            {
              e = redirect_edge_and_branch (e, dest);
-             PENDING_STMT (e) = NULL_TREE;
+             redirect_edge_var_map_clear (e);
              continue;
            }
 
@@ -725,15 +771,18 @@ remove_forwarder_block_with_phi (basic_block bb)
 
          if (TREE_CODE (def) == SSA_NAME)
            {
-             tree var;
+             edge_var_map_vector head;
+             edge_var_map *vm;
+             size_t i;
 
              /* 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.  */
-             for (var = PENDING_STMT (e); var; var = TREE_CHAIN (var))
+             head = redirect_edge_var_map_vector (e);
+             for (i = 0; VEC_iterate (edge_var_map, head, i, vm); ++i)
                {
-                 tree old_arg = TREE_PURPOSE (var);
-                 tree new_arg = TREE_VALUE (var);
+                 tree old_arg = redirect_edge_var_map_result (vm);
+                 tree new_arg = redirect_edge_var_map_def (vm);
 
                  if (def == old_arg)
                    {
@@ -746,7 +795,7 @@ remove_forwarder_block_with_phi (basic_block bb)
          add_phi_arg (phi, def, s);
        }
 
-      PENDING_STMT (e) = NULL;
+      redirect_edge_var_map_clear (e);
     }
 
   /* Update the dominators.  */
@@ -881,7 +930,10 @@ gate_merge_phi (void)
   return 1;
 }
 
-struct tree_opt_pass pass_merge_phi = {
+struct gimple_opt_pass pass_merge_phi = 
+{
+ {
+  GIMPLE_PASS,
   "mergephi",                  /* name */
   gate_merge_phi,              /* gate */
   merge_phi_nodes,             /* execute */
@@ -894,6 +946,6 @@ struct tree_opt_pass pass_merge_phi = {
   0,                           /* properties_destroyed */
   0,                           /* todo_flags_start */
   TODO_dump_func | TODO_ggc_collect    /* todo_flags_finish */
-  | TODO_verify_ssa,
-  0                            /* letter */
+  | TODO_verify_ssa
+ }
 };