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.
 /* 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.
    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 "coretypes.h"
 #include "tm.h"
 #include "tree.h"
-#include "rtl.h"
 #include "tm_p.h"
 #include "tm_p.h"
-#include "hard-reg-set.h"
 #include "basic-block.h"
 #include "output.h"
 #include "toplev.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;
       edge e;
       edge_iterator ei;
       bool warned;
+      location_t loc;
 
       fold_defer_overflow_warnings ();
 
       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)
        {
       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;
 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
 
   /* 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
 
   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))
   /* 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;
        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:
          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;
   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 (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;
 }
 
   return true;
 }
 
@@ -346,7 +391,7 @@ remove_forwarder_block (basic_block bb)
   gimple label;
   edge_iterator ei;
   gimple_stmt_iterator gsi, gsi_to;
   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
 
   /* 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 (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
   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
     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.  */
 
      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
 
   /* 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)); )
     {
   /* 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);
               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_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);
       {
        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
        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;
            || 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);
 
   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
     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);
     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;
 
       && remove_forwarder_block (bb))
     return true;
 
@@ -607,7 +679,7 @@ cleanup_tree_cfg_1 (void)
         calls.  */
       retval |= split_bbs_on_noreturn_calls ();
     }
         calls.  */
       retval |= split_bbs_on_noreturn_calls ();
     }
-  
+
   end_recording_case_labels ();
   BITMAP_FREE (cfgcleanup_altered_bbs);
   return retval;
   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);
        {
          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)
            {
 
          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;
                  if (def == old_arg)
                    {
                      def = new_arg;
+                     locus = redirect_edge_var_map_location (vm);
                      break;
                    }
                }
            }
 
                      break;
                    }
                }
            }
 
-         add_phi_arg (phi, def, s);
+         add_phi_arg (phi, def, s, locus);
        }
 
       redirect_edge_var_map_clear (e);
        }
 
       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.  */
 
       /* 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))
          /* 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;
 }
 
   return 1;
 }
 
-struct gimple_opt_pass pass_merge_phi = 
+struct gimple_opt_pass pass_merge_phi =
 {
  {
   GIMPLE_PASS,
 {
  {
   GIMPLE_PASS,