OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-live.c
index 883cca8..31eac11 100644 (file)
@@ -1,5 +1,5 @@
 /* Liveness for SSA trees.
 /* Liveness for SSA trees.
-   Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010
+   Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Andrew MacLeod <amacleod@redhat.com>
 
    Free Software Foundation, Inc.
    Contributed by Andrew MacLeod <amacleod@redhat.com>
 
@@ -31,9 +31,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dump.h"
 #include "tree-ssa-live.h"
 #include "diagnostic-core.h"
 #include "tree-dump.h"
 #include "tree-ssa-live.h"
 #include "diagnostic-core.h"
-#include "toplev.h"
 #include "debug.h"
 #include "flags.h"
 #include "debug.h"
 #include "flags.h"
+#include "gimple.h"
 
 #ifdef ENABLE_CHECKING
 static void  verify_live_on_entry (tree_live_info_p);
 
 #ifdef ENABLE_CHECKING
 static void  verify_live_on_entry (tree_live_info_p);
@@ -157,10 +157,8 @@ delete_var_map (var_map map)
 {
   var_map_base_fini (map);
   partition_delete (map->var_partition);
 {
   var_map_base_fini (map);
   partition_delete (map->var_partition);
-  if (map->partition_to_view)
-    free (map->partition_to_view);
-  if (map->view_to_partition)
-    free (map->view_to_partition);
+  free (map->partition_to_view);
+  free (map->view_to_partition);
   free (map);
 }
 
   free (map);
 }
 
@@ -361,13 +359,13 @@ mark_all_vars_used_1 (tree *tp, int *walk_subtrees, void *data)
       && (b = TREE_BLOCK (t)) != NULL)
     TREE_USED (b) = true;
 
       && (b = TREE_BLOCK (t)) != NULL)
     TREE_USED (b) = true;
 
-  /* Ignore TREE_ORIGINAL for TARGET_MEM_REFS, as well as other
-     fields that do not contain vars.  */
+  /* Ignore TMR_OFFSET and TMR_STEP for TARGET_MEM_REFS, as those
+     fields do not contain vars.  */
   if (TREE_CODE (t) == TARGET_MEM_REF)
     {
   if (TREE_CODE (t) == TARGET_MEM_REF)
     {
-      mark_all_vars_used (&TMR_SYMBOL (t), data);
       mark_all_vars_used (&TMR_BASE (t), data);
       mark_all_vars_used (&TMR_INDEX (t), data);
       mark_all_vars_used (&TMR_BASE (t), data);
       mark_all_vars_used (&TMR_INDEX (t), data);
+      mark_all_vars_used (&TMR_INDEX2 (t), data);
       *walk_subtrees = 0;
       return NULL;
     }
       *walk_subtrees = 0;
       return NULL;
     }
@@ -376,11 +374,9 @@ mark_all_vars_used_1 (tree *tp, int *walk_subtrees, void *data)
      eliminated as unused.  */
   if (TREE_CODE (t) == VAR_DECL)
     {
      eliminated as unused.  */
   if (TREE_CODE (t) == VAR_DECL)
     {
-      if (data != NULL && bitmap_bit_p ((bitmap) data, DECL_UID (t)))
-       {
-         bitmap_clear_bit ((bitmap) data, DECL_UID (t));
-         mark_all_vars_used (&DECL_INITIAL (t), data);
-       }
+      if (data != NULL && bitmap_clear_bit ((bitmap) data, DECL_UID (t))
+         && DECL_CONTEXT (t) == current_function_decl)
+       mark_all_vars_used (&DECL_INITIAL (t), data);
       set_is_used (t);
     }
   /* remove_unused_scope_block_p requires information about labels
       set_is_used (t);
     }
   /* remove_unused_scope_block_p requires information about labels
@@ -430,12 +426,11 @@ remove_unused_scope_block_p (tree scope)
 {
   tree *t, *next;
   bool unused = !TREE_USED (scope);
 {
   tree *t, *next;
   bool unused = !TREE_USED (scope);
-  var_ann_t ann;
   int nsubblocks = 0;
 
   for (t = &BLOCK_VARS (scope); *t; t = next)
     {
   int nsubblocks = 0;
 
   for (t = &BLOCK_VARS (scope); *t; t = next)
     {
-      next = &TREE_CHAIN (*t);
+      next = &DECL_CHAIN (*t);
 
       /* Debug info of nested function refers to the block of the
         function.  We might stil call it even if all statements
 
       /* Debug info of nested function refers to the block of the
         function.  We might stil call it even if all statements
@@ -456,10 +451,13 @@ remove_unused_scope_block_p (tree scope)
       else if (TREE_CODE (*t) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (*t))
        unused = false;
 
       else if (TREE_CODE (*t) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (*t))
        unused = false;
 
-      /* Remove everything we don't generate debug info for.  */
-      else if (DECL_IGNORED_P (*t))
+      /* Remove everything we don't generate debug info for.
+        Don't remove larger vars though, because BLOCK_VARS are
+        used also during expansion to determine which variables
+        might share stack space.  */
+      else if (DECL_IGNORED_P (*t) && is_gimple_reg (*t))
        {
        {
-         *t = TREE_CHAIN (*t);
+         *t = DECL_CHAIN (*t);
          next = t;
        }
 
          next = t;
        }
 
@@ -467,8 +465,7 @@ remove_unused_scope_block_p (tree scope)
         info about optimized-out variables in the scope blocks.
         Exception are the scope blocks not containing any instructions
         at all so user can't get into the scopes at first place.  */
         info about optimized-out variables in the scope blocks.
         Exception are the scope blocks not containing any instructions
         at all so user can't get into the scopes at first place.  */
-      else if ((ann = var_ann (*t)) != NULL
-               && ann->used)
+      else if (var_ann (*t) != NULL && is_used_p (*t))
        unused = false;
       else if (TREE_CODE (*t) == LABEL_DECL && TREE_USED (*t))
        /* For labels that are still used in the IL, the decision to
        unused = false;
       else if (TREE_CODE (*t) == LABEL_DECL && TREE_USED (*t))
        /* For labels that are still used in the IL, the decision to
@@ -493,16 +490,21 @@ remove_unused_scope_block_p (tree scope)
         can be considered dead.  We only want to keep around blocks user can
         breakpoint into and ask about value of optimized out variables.
 
         can be considered dead.  We only want to keep around blocks user can
         breakpoint into and ask about value of optimized out variables.
 
-        Similarly we need to keep around types at least until all variables of
-        all nested blocks are gone.  We track no information on whether given
-        type is used or not.  */
+        Similarly we need to keep around types at least until all
+        variables of all nested blocks are gone.  We track no
+        information on whether given type is used or not, so we have
+        to keep them even when not emitting debug information,
+        otherwise we may end up remapping variables and their (local)
+        types in different orders depending on whether debug
+        information is being generated.  */
 
 
-      else if (debug_info_level == DINFO_LEVEL_NORMAL
+      else if (TREE_CODE (*t) == TYPE_DECL
+              || debug_info_level == DINFO_LEVEL_NORMAL
               || debug_info_level == DINFO_LEVEL_VERBOSE)
        ;
       else
        {
               || debug_info_level == DINFO_LEVEL_VERBOSE)
        ;
       else
        {
-         *t = TREE_CHAIN (*t);
+         *t = DECL_CHAIN (*t);
          next = t;
        }
     }
          next = t;
        }
     }
@@ -625,16 +627,14 @@ dump_scope_block (FILE *file, int indent, tree scope, int flags)
        }
     }
   fprintf (file, " \n");
        }
     }
   fprintf (file, " \n");
-  for (var = BLOCK_VARS (scope); var; var = TREE_CHAIN (var))
+  for (var = BLOCK_VARS (scope); var; var = DECL_CHAIN (var))
     {
       bool used = false;
     {
       bool used = false;
-      var_ann_t ann;
 
 
-      if ((ann = var_ann (var))
-         && ann->used)
-       used = true;
+      if (var_ann (var))
+       used = is_used_p (var);
 
 
-      fprintf (file, "%*s",indent, "");
+      fprintf (file, "%*s", indent, "");
       print_generic_decl (file, var, flags);
       fprintf (file, "%s\n", used ? "" : " (unused)");
     }
       print_generic_decl (file, var, flags);
       fprintf (file, "%s\n", used ? "" : " (unused)");
     }
@@ -687,9 +687,9 @@ remove_unused_locals (void)
   basic_block bb;
   tree var, t;
   referenced_var_iterator rvi;
   basic_block bb;
   tree var, t;
   referenced_var_iterator rvi;
-  var_ann_t ann;
   bitmap global_unused_vars = NULL;
   bitmap global_unused_vars = NULL;
-  unsigned ix;
+  unsigned srcidx, dstidx, num;
+  bool have_local_clobbers = false;
 
   /* Removing declarations from lexical blocks when not optimizing is
      not only a waste of time, it actually causes differences in stack
 
   /* Removing declarations from lexical blocks when not optimizing is
      not only a waste of time, it actually causes differences in stack
@@ -697,11 +697,13 @@ remove_unused_locals (void)
   if (!optimize)
     return;
 
   if (!optimize)
     return;
 
+  timevar_push (TV_REMOVE_UNUSED);
+
   mark_scope_block_unused (DECL_INITIAL (current_function_decl));
 
   /* Assume all locals are unused.  */
   mark_scope_block_unused (DECL_INITIAL (current_function_decl));
 
   /* Assume all locals are unused.  */
-  FOR_EACH_REFERENCED_VAR (t, rvi)
-    var_ann (t)->used = false;
+  FOR_EACH_REFERENCED_VAR (cfun, t, rvi)
+    clear_is_used (t);
 
   /* Walk the CFG marking all referenced symbols.  */
   FOR_EACH_BB (bb)
 
   /* Walk the CFG marking all referenced symbols.  */
   FOR_EACH_BB (bb)
@@ -720,6 +722,12 @@ remove_unused_locals (void)
          if (is_gimple_debug (stmt))
            continue;
 
          if (is_gimple_debug (stmt))
            continue;
 
+         if (gimple_clobber_p (stmt))
+           {
+             have_local_clobbers = true;
+             continue;
+           }
+
          if (b)
            TREE_USED (b) = true;
 
          if (b)
            TREE_USED (b) = true;
 
@@ -753,14 +761,51 @@ remove_unused_locals (void)
          TREE_USED (e->goto_block) = true;
     }
 
          TREE_USED (e->goto_block) = true;
     }
 
+  /* We do a two-pass approach about the out-of-scope clobbers.  We want
+     to remove them if they are the only references to a local variable,
+     but we want to retain them when there's any other.  So the first pass
+     ignores them, and the second pass (if there were any) tries to remove
+     them.  */
+  if (have_local_clobbers)
+    FOR_EACH_BB (bb)
+      {
+       gimple_stmt_iterator gsi;
+
+       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
+         {
+           gimple stmt = gsi_stmt (gsi);
+           tree b = gimple_block (stmt);
+
+           if (gimple_clobber_p (stmt))
+             {
+               tree lhs = gimple_assign_lhs (stmt);
+               lhs = get_base_address (lhs);
+               if (TREE_CODE (lhs) == SSA_NAME)
+                 lhs = SSA_NAME_VAR (lhs);
+               if (DECL_P (lhs) && (!var_ann (lhs) || !is_used_p (lhs)))
+                 {
+                   unlink_stmt_vdef (stmt);
+                   gsi_remove (&gsi, true);
+                   release_defs (stmt);
+                   continue;
+                 }
+               if (b)
+                 TREE_USED (b) = true;
+             }
+           gsi_next (&gsi);
+         }
+      }
+
   cfun->has_local_explicit_reg_vars = false;
 
   /* Remove unmarked local vars from local_decls.  */
   cfun->has_local_explicit_reg_vars = false;
 
   /* Remove unmarked local vars from local_decls.  */
-  for (ix = 0; VEC_iterate (tree, cfun->local_decls, ix, var); )
+  num = VEC_length (tree, cfun->local_decls);
+  for (srcidx = 0, dstidx = 0; srcidx < num; srcidx++)
     {
     {
+      var = VEC_index (tree, cfun->local_decls, srcidx);
       if (TREE_CODE (var) != FUNCTION_DECL
       if (TREE_CODE (var) != FUNCTION_DECL
-         && (!(ann = var_ann (var))
-             || !ann->used))
+         && (!var_ann (var)
+             || !is_used_p (var)))
        {
          if (is_global_var (var))
            {
        {
          if (is_global_var (var))
            {
@@ -769,18 +814,19 @@ remove_unused_locals (void)
              bitmap_set_bit (global_unused_vars, DECL_UID (var));
            }
          else
              bitmap_set_bit (global_unused_vars, DECL_UID (var));
            }
          else
-           {
-             VEC_unordered_remove (tree, cfun->local_decls, ix);
-             continue;
-           }
+           continue;
        }
       else if (TREE_CODE (var) == VAR_DECL
               && DECL_HARD_REGISTER (var)
               && !is_global_var (var))
        cfun->has_local_explicit_reg_vars = true;
 
        }
       else if (TREE_CODE (var) == VAR_DECL
               && DECL_HARD_REGISTER (var)
               && !is_global_var (var))
        cfun->has_local_explicit_reg_vars = true;
 
-      ix++;
+      if (srcidx != dstidx)
+       VEC_replace (tree, cfun->local_decls, dstidx, var);
+      dstidx++;
     }
     }
+  if (dstidx != num)
+    VEC_truncate (tree, cfun->local_decls, dstidx);
 
   /* Remove unmarked global vars from local_decls.  */
   if (global_unused_vars != NULL)
 
   /* Remove unmarked global vars from local_decls.  */
   if (global_unused_vars != NULL)
@@ -790,32 +836,35 @@ remove_unused_locals (void)
       FOR_EACH_LOCAL_DECL (cfun, ix, var)
        if (TREE_CODE (var) == VAR_DECL
            && is_global_var (var)
       FOR_EACH_LOCAL_DECL (cfun, ix, var)
        if (TREE_CODE (var) == VAR_DECL
            && is_global_var (var)
-           && (ann = var_ann (var)) != NULL
-           && ann->used)
+           && var_ann (var) != NULL
+           && is_used_p (var)
+           && DECL_CONTEXT (var) == current_function_decl)
          mark_all_vars_used (&DECL_INITIAL (var), global_unused_vars);
 
          mark_all_vars_used (&DECL_INITIAL (var), global_unused_vars);
 
-      for (ix = 0; VEC_iterate (tree, cfun->local_decls, ix, var); )
-       if (TREE_CODE (var) == VAR_DECL
-           && is_global_var (var)
-           && bitmap_bit_p (global_unused_vars, DECL_UID (var)))
-         VEC_unordered_remove (tree, cfun->local_decls, ix);
-       else
-         ix++;
+      num = VEC_length (tree, cfun->local_decls);
+      for (srcidx = 0, dstidx = 0; srcidx < num; srcidx++)
+       {
+         var = VEC_index (tree, cfun->local_decls, srcidx);
+         if (TREE_CODE (var) == VAR_DECL
+             && is_global_var (var)
+             && bitmap_bit_p (global_unused_vars, DECL_UID (var)))
+           continue;
+
+         if (srcidx != dstidx)
+           VEC_replace (tree, cfun->local_decls, dstidx, var);
+         dstidx++;
+       }
+      if (dstidx != num)
+       VEC_truncate (tree, cfun->local_decls, dstidx);
       BITMAP_FREE (global_unused_vars);
     }
 
       BITMAP_FREE (global_unused_vars);
     }
 
-  /* Remove unused variables from REFERENCED_VARs.  As a special
-     exception keep the variables that are believed to be aliased.
-     Those can't be easily removed from the alias sets and operand
-     caches.  They will be removed shortly after the next may_alias
-     pass is performed.  */
-  FOR_EACH_REFERENCED_VAR (t, rvi)
+  /* Remove unused variables from REFERENCED_VARs.  */
+  FOR_EACH_REFERENCED_VAR (cfun, t, rvi)
     if (!is_global_var (t)
        && TREE_CODE (t) != PARM_DECL
        && TREE_CODE (t) != RESULT_DECL
     if (!is_global_var (t)
        && TREE_CODE (t) != PARM_DECL
        && TREE_CODE (t) != RESULT_DECL
-       && !(ann = var_ann (t))->used
-       && !ann->is_heapvar
-       && !TREE_ADDRESSABLE (t))
+       && !is_used_p (t))
       remove_referenced_var (t);
   remove_unused_scope_block_p (DECL_INITIAL (current_function_decl));
   if (dump_file && (dump_flags & TDF_DETAILS))
       remove_referenced_var (t);
   remove_unused_scope_block_p (DECL_INITIAL (current_function_decl));
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -823,6 +872,8 @@ remove_unused_locals (void)
       fprintf (dump_file, "Scope blocks after cleanups:\n");
       dump_scope_blocks (dump_file, dump_flags);
     }
       fprintf (dump_file, "Scope blocks after cleanups:\n");
       dump_scope_blocks (dump_file, dump_flags);
     }
+
+  timevar_pop (TV_REMOVE_UNUSED);
 }
 
 
 }
 
 
@@ -1185,6 +1236,94 @@ dump_live_info (FILE *f, tree_live_info_p live, int flag)
     }
 }
 
     }
 }
 
+struct GTY(()) numbered_tree_d
+{
+  tree t;
+  int num;
+};
+typedef struct numbered_tree_d numbered_tree;
+
+DEF_VEC_O (numbered_tree);
+DEF_VEC_ALLOC_O (numbered_tree, heap);
+
+/* Compare two declarations references by their DECL_UID / sequence number.
+   Called via qsort.  */
+
+static int
+compare_decls_by_uid (const void *pa, const void *pb)
+{
+  const numbered_tree *nt_a = ((const numbered_tree *)pa);
+  const numbered_tree *nt_b = ((const numbered_tree *)pb);
+
+  if (DECL_UID (nt_a->t) != DECL_UID (nt_b->t))
+    return  DECL_UID (nt_a->t) - DECL_UID (nt_b->t);
+  return nt_a->num - nt_b->num;
+}
+
+/* Called via walk_gimple_stmt / walk_gimple_op by dump_enumerated_decls.  */
+static tree
+dump_enumerated_decls_push (tree *tp, int *walk_subtrees, void *data)
+{
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+  VEC (numbered_tree, heap) **list = (VEC (numbered_tree, heap) **) &wi->info;
+  numbered_tree nt;
+
+  if (!DECL_P (*tp))
+    return NULL_TREE;
+  nt.t = *tp;
+  nt.num = VEC_length (numbered_tree, *list);
+  VEC_safe_push (numbered_tree, heap, *list, &nt);
+  *walk_subtrees = 0;
+  return NULL_TREE;
+}
+
+/* Find all the declarations used by the current function, sort them by uid,
+   and emit the sorted list.  Each declaration is tagged with a sequence
+   number indicating when it was found during statement / tree walking,
+   so that TDF_NOUID comparisons of anonymous declarations are still
+   meaningful.  Where a declaration was encountered more than once, we
+   emit only the sequence number of the first encounter.
+   FILE is the dump file where to output the list and FLAGS is as in
+   print_generic_expr.  */
+void
+dump_enumerated_decls (FILE *file, int flags)
+{
+  basic_block bb;
+  struct walk_stmt_info wi;
+  VEC (numbered_tree, heap) *decl_list = VEC_alloc (numbered_tree, heap, 40);
+
+  memset (&wi, '\0', sizeof (wi));
+  wi.info = (void*) decl_list;
+  FOR_EACH_BB (bb)
+    {
+      gimple_stmt_iterator gsi;
+
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       if (!is_gimple_debug (gsi_stmt (gsi)))
+         walk_gimple_stmt (&gsi, NULL, dump_enumerated_decls_push, &wi);
+    }
+  decl_list = (VEC (numbered_tree, heap) *) wi.info;
+  VEC_qsort (numbered_tree, decl_list, compare_decls_by_uid);
+  if (VEC_length (numbered_tree, decl_list))
+    {
+      unsigned ix;
+      numbered_tree *ntp;
+      tree last = NULL_TREE;
+
+      fprintf (file, "Declarations used by %s, sorted by DECL_UID:\n",
+              current_function_name ());
+      FOR_EACH_VEC_ELT (numbered_tree, decl_list, ix, ntp)
+       {
+         if (ntp->t == last)
+           continue;
+         fprintf (file, "%d: ", ntp->num);
+         print_generic_decl (file, ntp->t, flags);
+         fprintf (file, "\n");
+         last = ntp->t;
+       }
+    }
+  VEC_free (numbered_tree, heap, decl_list);
+}
 
 #ifdef ENABLE_CHECKING
 /* Verify that SSA_VAR is a non-virtual SSA_NAME.  */
 
 #ifdef ENABLE_CHECKING
 /* Verify that SSA_VAR is a non-virtual SSA_NAME.  */