OSDN Git Service

* gcc.dg/vect/vect.exp: Run tests with -funroll-loops for SPU in case
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-live.c
index 0113b1b..c277980 100644 (file)
@@ -1,12 +1,13 @@
 /* Liveness for SSA trees.
-   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation,
+   Inc.
    Contributed by Andrew MacLeod <amacleod@redhat.com>
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -15,9 +16,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -30,6 +30,8 @@ Boston, MA 02110-1301, USA.  */
 #include "tree-dump.h"
 #include "tree-ssa-live.h"
 #include "toplev.h"
+#include "debug.h"
+#include "flags.h"
 
 #ifdef ENABLE_CHECKING
 static void  verify_live_on_entry (tree_live_info_p);
@@ -45,7 +47,7 @@ static void  verify_live_on_entry (tree_live_info_p);
    At the end of out-of-ssa, each partition becomes a "real" variable and is
    rewritten as a compiler variable.
 
-   The var_map datat structure is used to manage these partitions.  It allows
+   The var_map data structure is used to manage these partitions.  It allows
    partitions to be combined, and determines which partition belongs to what
    ssa_name or variable, and vice versa.  */
 
@@ -396,26 +398,32 @@ change_partition_var (var_map map, tree var, int part)
 }
 
 
-static inline void mark_all_vars_used (tree *);
+static inline void mark_all_vars_used (tree *, void *data);
 
 /* Helper function for mark_all_vars_used, called via walk_tree.  */
 
 static tree
 mark_all_vars_used_1 (tree *tp, int *walk_subtrees,
-                     void *data ATTRIBUTE_UNUSED)
+                     void *data)
 {
   tree t = *tp;
+  enum tree_code_class c = TREE_CODE_CLASS (TREE_CODE (t));
+  tree b;
 
   if (TREE_CODE (t) == SSA_NAME)
     t = SSA_NAME_VAR (t);
+  if ((IS_EXPR_CODE_CLASS (c)
+       || IS_GIMPLE_STMT_CODE_CLASS (c))
+      && (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.  */
   if (TREE_CODE (t) == TARGET_MEM_REF)
     {
-      mark_all_vars_used (&TMR_SYMBOL (t));
-      mark_all_vars_used (&TMR_BASE (t));
-      mark_all_vars_used (&TMR_INDEX (t));
+      mark_all_vars_used (&TMR_SYMBOL (t), data);
+      mark_all_vars_used (&TMR_BASE (t), data);
+      mark_all_vars_used (&TMR_INDEX (t), data);
       *walk_subtrees = 0;
       return NULL;
     }
@@ -423,7 +431,14 @@ mark_all_vars_used_1 (tree *tp, int *walk_subtrees,
   /* Only need to mark VAR_DECLS; parameters and return results are not
      eliminated as unused.  */
   if (TREE_CODE (t) == VAR_DECL)
-    set_is_used (t);
+    {
+      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);
+       }
+      set_is_used (t);
+    }
 
   if (IS_TYPE_OR_DECL_P (t))
     *walk_subtrees = 0;
@@ -431,14 +446,128 @@ mark_all_vars_used_1 (tree *tp, int *walk_subtrees,
   return NULL;
 }
 
+/* Mark the scope block SCOPE and its subblocks unused when they can be
+   possibly eliminated if dead.  */
+
+static void
+mark_scope_block_unused (tree scope)
+{
+  tree t;
+  TREE_USED (scope) = false;
+  if (!(*debug_hooks->ignore_block) (scope))
+    TREE_USED (scope) = true;
+  for (t = BLOCK_SUBBLOCKS (scope); t ; t = BLOCK_CHAIN (t))
+    mark_scope_block_unused (t);
+}
+
+/* Look if the block is dead (by possibly eliminating its dead subblocks)
+   and return true if so.  
+   Block is declared dead if:
+     1) No statements are associated with it.
+     2) Declares no live variables
+     3) All subblocks are dead
+       or there is precisely one subblocks and the block
+       has same abstract origin as outer block and declares
+       no variables, so it is pure wrapper.
+   When we are not outputting full debug info, we also eliminate dead variables
+   out of scope blocks to let them to be recycled by GGC and to save copying work
+   done by the inliner.  */
+
+static bool
+remove_unused_scope_block_p (tree scope)
+{
+  tree *t, *next;
+  bool unused = !TREE_USED (scope);
+  var_ann_t ann;
+  int nsubblocks = 0;
+
+  for (t = &BLOCK_VARS (scope); *t; t = next)
+    {
+      next = &TREE_CHAIN (*t);
+
+      /* Debug info of nested function refers to the block of the
+        function.  */
+      if (TREE_CODE (*t) == FUNCTION_DECL)
+       unused = false;
+
+      /* When we are outputting debug info, we usually want to output
+        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)
+       unused = false;
+
+      /* When we are not doing full debug info, we however can keep around
+        only the used variables for cfgexpand's memory packing saving quite
+        a lot of memory.  */
+      else if (debug_info_level == DINFO_LEVEL_NORMAL
+              || debug_info_level == DINFO_LEVEL_VERBOSE
+              /* Removing declarations before inlining is going to affect
+                 DECL_UID that in turn is going to affect hashtables and
+                 code generation.  */
+              || !cfun->after_inlining)
+       unused = false;
+
+      else
+       {
+         *t = TREE_CHAIN (*t);
+         next = t;
+       }
+    }
+
+  for (t = &BLOCK_SUBBLOCKS (scope); *t ;)
+    if (remove_unused_scope_block_p (*t))
+      {
+       if (BLOCK_SUBBLOCKS (*t))
+         {
+           tree next = BLOCK_CHAIN (*t);
+           tree supercontext = BLOCK_SUPERCONTEXT (*t);
+           *t = BLOCK_SUBBLOCKS (*t);
+           gcc_assert (!BLOCK_CHAIN (*t));
+           BLOCK_CHAIN (*t) = next;
+           BLOCK_SUPERCONTEXT (*t) = supercontext;
+           t = &BLOCK_CHAIN (*t);
+           nsubblocks ++;
+         }
+       else
+         {
+           gcc_assert (!BLOCK_VARS (*t));
+           *t = BLOCK_CHAIN (*t);
+         }
+      }
+    else
+      {
+        t = &BLOCK_CHAIN (*t);
+       nsubblocks ++;
+      }
+   /* Outer scope is always used.  */
+   if (!BLOCK_SUPERCONTEXT (scope)
+       || TREE_CODE (BLOCK_SUPERCONTEXT (scope)) == FUNCTION_DECL)
+     unused = false;
+   /* If there are more than one live subblocks, it is used.  */
+   else if (nsubblocks > 1)
+     unused = false;
+   /* When there is only one subblock, see if it is just wrapper we can
+      ignore.  Wrappers are not declaring any variables and not changing
+      abstract origin.  */
+   else if (nsubblocks == 1
+           && (BLOCK_VARS (scope)
+               || ((debug_info_level == DINFO_LEVEL_NORMAL
+                    || debug_info_level == DINFO_LEVEL_VERBOSE)
+                   && ((BLOCK_ABSTRACT_ORIGIN (scope)
+                       != BLOCK_ABSTRACT_ORIGIN (BLOCK_SUPERCONTEXT (scope)))))))
+     unused = false;
+   return unused;
+}
 
 /* Mark all VAR_DECLS under *EXPR_P as used, so that they won't be 
    eliminated during the tree->rtl conversion process.  */
 
 static inline void
-mark_all_vars_used (tree *expr_p)
+mark_all_vars_used (tree *expr_p, void *data)
 {
-  walk_tree (expr_p, mark_all_vars_used_1, NULL, NULL);
+  walk_tree (expr_p, mark_all_vars_used_1, data, NULL);
 }
 
 
@@ -451,7 +580,9 @@ remove_unused_locals (void)
   tree t, *cell;
   referenced_var_iterator rvi;
   var_ann_t ann;
+  bitmap global_unused_vars = NULL;
 
+  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;
@@ -464,7 +595,7 @@ remove_unused_locals (void)
 
       /* Walk the statements.  */
       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-       mark_all_vars_used (bsi_stmt_ptr (bsi));
+       mark_all_vars_used (bsi_stmt_ptr (bsi), NULL);
 
       for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
         {
@@ -476,18 +607,18 @@ remove_unused_locals (void)
            continue;
 
           def = PHI_RESULT (phi);
-          mark_all_vars_used (&def);
+         mark_all_vars_used (&def, NULL);
 
           FOR_EACH_PHI_ARG (arg_p, phi, i, SSA_OP_ALL_USES)
             {
              tree arg = USE_FROM_PTR (arg_p);
-             mark_all_vars_used (&arg);
+             mark_all_vars_used (&arg, NULL);
             }
         }
     }
 
-  /* Remove unmarked vars and clear used flag.  */
-  for (cell = &cfun->unexpanded_var_list; *cell; )
+  /* Remove unmarked local vars from local_decls.  */
+  for (cell = &cfun->local_decls; *cell; )
     {
       tree var = TREE_VALUE (*cell);
 
@@ -495,25 +626,64 @@ remove_unused_locals (void)
          && (!(ann = var_ann (var))
              || !ann->used))
        {
-         *cell = TREE_CHAIN (*cell);
-         continue;
+         if (is_global_var (var))
+           {
+             if (global_unused_vars == NULL)
+               global_unused_vars = BITMAP_ALLOC (NULL);
+             bitmap_set_bit (global_unused_vars, DECL_UID (var));
+           }
+         else
+           {
+             *cell = TREE_CHAIN (*cell);
+             continue;
+           }
        }
-
       cell = &TREE_CHAIN (*cell);
     }
 
-  /* Remove unused variables from REFERENCED_VARs.  As an special exception
-     keep the variables that are believed to be aliased.  Those can't be
-     easily removed from the alias sets and and operand caches.
-     They will be removed shortly after next may_alias pass is performed.  */
+  /* Remove unmarked global vars from local_decls.  */
+  if (global_unused_vars != NULL)
+    {
+      for (t = cfun->local_decls; t; t = TREE_CHAIN (t))
+       {
+         tree var = TREE_VALUE (t);
+
+         if (TREE_CODE (var) == VAR_DECL
+             && is_global_var (var)
+             && (ann = var_ann (var)) != NULL
+             && ann->used)
+           mark_all_vars_used (&DECL_INITIAL (var), global_unused_vars);
+       }
+
+      for (cell = &cfun->local_decls; *cell; )
+       {
+         tree var = TREE_VALUE (*cell);
+
+         if (TREE_CODE (var) == VAR_DECL
+             && is_global_var (var)
+             && bitmap_bit_p (global_unused_vars, DECL_UID (var)))
+           *cell = TREE_CHAIN (*cell);
+         else
+           cell = &TREE_CHAIN (*cell);
+       }
+      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)
     if (!is_global_var (t)
        && !MTAG_P (t)
        && TREE_CODE (t) != PARM_DECL
        && TREE_CODE (t) != RESULT_DECL
        && !(ann = var_ann (t))->used
-       && !ann->is_aliased && !is_call_clobbered (t) && !ann->symbol_mem_tag)
-        remove_referenced_var (t);
+       && !ann->symbol_mem_tag
+       && !TREE_ADDRESSABLE (t))
+      remove_referenced_var (t);
+  remove_unused_scope_block_p (DECL_INITIAL (current_function_decl));
 }
 
 
@@ -567,7 +737,7 @@ delete_tree_live_info (tree_live_info_p live)
 }
 
 
-/* Visit basic block BB and propogate any required live on entry bits from 
+/* Visit basic block BB and propagate any required live on entry bits from 
    LIVE into the predecessors.  VISITED is the bitmap of visited blocks.  
    TMP is a temporary work bitmap which is passed in to avoid reallocating
    it each time.  */
@@ -623,7 +793,7 @@ live_worklist (tree_live_info_p live)
 
   sbitmap_zero (visited);
 
-  /* Visit all the blocks in reverse order and propogate live on entry values
+  /* Visit all the blocks in reverse order and propagate live on entry values
      into the predecessors blocks.  */
   FOR_EACH_BB_REVERSE (bb)
     loe_visit_block (live, bb, visited, tmp);