OSDN Git Service

* gcc-interface/gigi.h (gnat_mark_addressable): Rename parameter.
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfgcleanup.c
index 433900c..b8f5a54 100644 (file)
@@ -1,5 +1,5 @@
 /* CFG cleanup for trees.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -23,9 +23,7 @@ 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"
@@ -90,9 +88,55 @@ cleanup_control_expr_graph (basic_block bb, gimple_stmt_iterator gsi)
       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)
        {
@@ -221,9 +265,7 @@ static bool
 tree_forwarder_block_p (basic_block bb, bool phi_wanted)
 {
   gimple_stmt_iterator gsi;
-  edge_iterator ei;
-  edge e, succ;
-  basic_block dest;
+  location_t locus;
 
   /* BB must have a single outgoing edge.  */
   if (single_succ_p (bb) != 1
@@ -242,6 +284,22 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted)
   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;
+    edge e;
+
+    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,
      anything else means this is not a forwarder block.  */
   for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
@@ -253,6 +311,13 @@ 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
+            assignment at the destination.  */
+       case GIMPLE_DEBUG:
          break;
 
        default:
@@ -260,9 +325,6 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted)
        }
     }
 
-  if (find_edge (ENTRY_BLOCK_PTR, bb))
-    return false;
-
   if (current_loops)
     {
       basic_block dest;
@@ -274,23 +336,6 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted)
       if (dest->loop_father->header == dest)
        return false;
     }
-
-  /* If we have an EH edge leaving this block, make sure that the
-     destination of this block has only one predecessor.  This ensures
-     that we don't get into the situation where we try to remove two
-     forwarders that go to the same basic block but are handlers for
-     different EH regions.  */
-  succ = single_succ_edge (bb);
-  dest = succ->dest;
-  FOR_EACH_EDGE (e, ei, bb->preds)
-    {
-      if (e->flags & EDGE_EH)
-        {
-         if (!single_pred_p (dest))
-           return false;
-       }
-    }
-
   return true;
 }
 
@@ -346,7 +391,7 @@ remove_forwarder_block (basic_block bb)
   gimple label;
   edge_iterator ei;
   gimple_stmt_iterator gsi, gsi_to;
-  bool seen_abnormal_edge = false;
+  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
@@ -354,12 +399,13 @@ remove_forwarder_block (basic_block bb)
   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
@@ -373,14 +419,10 @@ 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))
-    {
-      seen_abnormal_edge = true;
-
-      if (has_abnormal_incoming_edge_p (dest)
-         || !gimple_seq_empty_p (phi_nodes (dest)))
-       return false;
-    }
+  if (has_abnormal_incoming_edge_p (bb)
+      && (has_abnormal_incoming_edge_p (dest)
+         || !gimple_seq_empty_p (phi_nodes (dest))))
+    return false;
 
   /* 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
@@ -398,6 +440,8 @@ remove_forwarder_block (basic_block bb)
        }
     }
 
+  can_move_debug_stmts = single_pred_p (dest);
+
   /* Redirect the edges.  */
   for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
     {
@@ -421,22 +465,49 @@ remove_forwarder_block (basic_block bb)
               gsi_next (&gsi))
            {
              gimple phi = gsi_stmt (gsi);
-             add_phi_arg (phi, gimple_phi_arg_def (phi, succ->dest_idx), s);
+             source_location l = gimple_phi_arg_location_from_edge (phi, succ);
+             add_phi_arg (phi, gimple_phi_arg_def (phi, succ->dest_idx), s, l);
            }
        }
     }
 
-  if (seen_abnormal_edge)
+  /* Move nonlocal labels and computed goto targets as well as user
+     defined labels and labels with an EH landing pad number to the
+     new block, so that the redirection of the abnormal edges works,
+     jump targets end up in a sane place and debug information for
+     labels is retained.  */
+  gsi_to = gsi_start_bb (dest);
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
+    {
+      tree decl;
+      label = gsi_stmt (gsi);
+      if (is_gimple_debug (label))
+       break;
+      decl = gimple_label_label (label);
+      if (EH_LANDING_PAD_NR (decl) != 0
+         || DECL_NONLOCAL (decl)
+         || FORCED_LABEL (decl)
+         || !DECL_ARTIFICIAL (decl))
+       {
+         gsi_remove (&gsi, false);
+         gsi_insert_before (&gsi_to, label, GSI_SAME_STMT);
+       }
+      else
+       gsi_next (&gsi);
+    }
+
+  /* Move debug statements if the destination has just a single
+     predecessor.  */
+  if (can_move_debug_stmts)
     {
-      /* Move the labels to the new block, so that the redirection of
-        the abnormal edges works.  */
-      gsi_to = gsi_start_bb (dest);
-      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
+      gsi_to = gsi_after_labels (dest);
+      for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); )
        {
-         label = gsi_stmt (gsi);
-         gcc_assert (gimple_code (label) == GIMPLE_LABEL);
+         gimple debug = gsi_stmt (gsi);
+         if (!is_gimple_debug (debug))
+           break;
          gsi_remove (&gsi, false);
-         gsi_insert_before (&gsi_to, label, GSI_CONTINUE_LINKING);
+         gsi_insert_before (&gsi_to, debug, GSI_SAME_STMT);
        }
     }
 
@@ -483,7 +554,12 @@ split_bbs_on_noreturn_calls (void)
       {
        stmt = VEC_pop (gimple, MODIFIED_NORETURN_CALLS (cfun));
        bb = gimple_bb (stmt);
+       /* BB might be deleted at this point, so verify first
+          BB is present in the cfg.  */
        if (bb == NULL
+           || bb->index < NUM_FIXED_BLOCKS
+           || bb->index >= n_basic_blocks
+           || BASIC_BLOCK (bb->index) != bb
            || last_stmt (bb) == stmt
            || !gimple_call_noreturn_p (stmt))
          continue;
@@ -512,7 +588,7 @@ cleanup_omp_return (basic_block bb)
   control_bb = single_pred (bb);
   stmt = last_stmt (control_bb);
 
-  if (gimple_code (stmt) != GIMPLE_OMP_SECTIONS_SWITCH)
+  if (stmt == NULL || gimple_code (stmt) != GIMPLE_OMP_SECTIONS_SWITCH)
     return false;
 
   /* The block with the control statement normally has two entry edges -- one
@@ -538,12 +614,8 @@ cleanup_tree_cfg_bb (basic_block 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.  */
-  if (optimize > 0
-      && tree_forwarder_block_p (bb, false)
+
+  if (tree_forwarder_block_p (bb, false)
       && remove_forwarder_block (bb))
     return true;
 
@@ -607,7 +679,7 @@ cleanup_tree_cfg_1 (void)
         calls.  */
       retval |= split_bbs_on_noreturn_calls ();
     }
-  
+
   end_recording_case_labels ();
   BITMAP_FREE (cfgcleanup_altered_bbs);
   return retval;
@@ -759,6 +831,7 @@ remove_forwarder_block_with_phi (basic_block bb)
        {
          gimple phi = gsi_stmt (gsi);
          tree def = gimple_phi_arg_def (phi, succ->dest_idx);
+         source_location locus = gimple_phi_arg_location_from_edge (phi, succ);
 
          if (TREE_CODE (def) == SSA_NAME)
            {
@@ -778,12 +851,13 @@ remove_forwarder_block_with_phi (basic_block bb)
                  if (def == old_arg)
                    {
                      def = new_arg;
+                     locus = redirect_edge_var_map_location (vm);
                      break;
                    }
                }
            }
 
-         add_phi_arg (phi, def, s);
+         add_phi_arg (phi, def, s, locus);
        }
 
       redirect_edge_var_map_clear (e);
@@ -855,7 +929,7 @@ merge_phi_nodes (void)
 
       /* 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))
@@ -923,7 +997,7 @@ gate_merge_phi (void)
   return 1;
 }
 
-struct gimple_opt_pass pass_merge_phi = 
+struct gimple_opt_pass pass_merge_phi =
 {
  {
   GIMPLE_PASS,