OSDN Git Service

PR libfortran/40549
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-live.c
index fa3834d..d416694 100644 (file)
@@ -1,5 +1,5 @@
 /* Liveness for SSA trees.
-   Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation,
+   Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
    Inc.
    Contributed by Andrew MacLeod <amacleod@redhat.com>
 
@@ -136,9 +136,6 @@ init_var_map (int size)
 
   map = (var_map) xmalloc (sizeof (struct _var_map));
   map->var_partition = partition_new (size);
-  map->partition_to_var 
-             = (tree *)xmalloc (size * sizeof (tree));
-  memset (map->partition_to_var, 0, size * sizeof (tree));
 
   map->partition_to_view = NULL;
   map->view_to_partition = NULL;
@@ -157,7 +154,6 @@ void
 delete_var_map (var_map map)
 {
   var_map_base_fini (map);
-  free (map->partition_to_var);
   partition_delete (map->var_partition);
   if (map->partition_to_view)
     free (map->partition_to_view);
@@ -175,41 +171,16 @@ int
 var_union (var_map map, tree var1, tree var2)
 {
   int p1, p2, p3;
-  tree root_var = NULL_TREE;
-  tree other_var = NULL_TREE;
+
+  gcc_assert (TREE_CODE (var1) == SSA_NAME);
+  gcc_assert (TREE_CODE (var2) == SSA_NAME);
 
   /* This is independent of partition_to_view. If partition_to_view is 
      on, then whichever one of these partitions is absorbed will never have a
      dereference into the partition_to_view array any more.  */
 
-  if (TREE_CODE (var1) == SSA_NAME)
-    p1 = partition_find (map->var_partition, SSA_NAME_VERSION (var1));
-  else
-    {
-      p1 = var_to_partition (map, var1);
-      if (map->view_to_partition)
-        p1 = map->view_to_partition[p1];
-      root_var = var1;
-    }
-  
-  if (TREE_CODE (var2) == SSA_NAME)
-    p2 = partition_find (map->var_partition, SSA_NAME_VERSION (var2));
-  else
-    {
-      p2 = var_to_partition (map, var2);
-      if (map->view_to_partition)
-        p2 = map->view_to_partition[p2];
-
-      /* If there is no root_var set, or it's not a user variable, set the
-        root_var to this one.  */
-      if (!root_var || (DECL_P (root_var) && DECL_IGNORED_P (root_var)))
-        {
-         other_var = root_var;
-         root_var = var2;
-       }
-      else 
-       other_var = var2;
-    }
+  p1 = partition_find (map->var_partition, SSA_NAME_VERSION (var1));
+  p2 = partition_find (map->var_partition, SSA_NAME_VERSION (var2));
 
   gcc_assert (p1 != NO_PARTITION);
   gcc_assert (p2 != NO_PARTITION);
@@ -222,11 +193,6 @@ var_union (var_map map, tree var1, tree var2)
   if (map->partition_to_view)
     p3 = map->partition_to_view[p3];
 
-  if (root_var)
-    change_partition_var (map, root_var, p3);
-  if (other_var)
-    change_partition_var (map, other_var, p3);
-
   return p3;
 }
 
@@ -278,7 +244,9 @@ partition_view_init (var_map map)
   for (x = 0; x < map->partition_size; x++)
     {
       tmp = partition_find (map->var_partition, x);
-      if (map->partition_to_var[tmp] != NULL_TREE && !bitmap_bit_p (used, tmp))
+      if (ssa_name (tmp) != NULL_TREE && is_gimple_reg (ssa_name (tmp))
+         && (!has_zero_uses (ssa_name (tmp))
+             || !SSA_NAME_IS_DEFAULT_DEF (ssa_name (tmp))))
        bitmap_set_bit (used, tmp);
     }
 
@@ -297,7 +265,6 @@ partition_view_fini (var_map map, bitmap selected)
 {
   bitmap_iterator bi;
   unsigned count, i, x, limit;
-  tree var;
 
   gcc_assert (selected);
 
@@ -317,11 +284,6 @@ partition_view_fini (var_map map, bitmap selected)
        {
          map->partition_to_view[x] = i;
          map->view_to_partition[i] = x;
-         var = map->partition_to_var[x];
-         /* If any one of the members of a partition is not an SSA_NAME, make
-            sure it is the representative.  */
-         if (TREE_CODE (var) != SSA_NAME)
-           change_partition_var (map, var, i);
          i++;
        }
       gcc_assert (i == count);
@@ -379,25 +341,6 @@ partition_view_bitmap (var_map map, bitmap only, bool want_bases)
 }
 
 
-/* This function is used to change the representative variable in MAP for VAR's 
-   partition to a regular non-ssa variable.  This allows partitions to be 
-   mapped back to real variables.  */
-  
-void 
-change_partition_var (var_map map, tree var, int part)
-{
-  var_ann_t ann;
-
-  gcc_assert (TREE_CODE (var) != SSA_NAME);
-
-  ann = var_ann (var);
-  ann->out_of_ssa_tag = 1;
-  VAR_ANN_PARTITION (ann) = part;
-  if (map->view_to_partition)
-    map->partition_to_var[map->view_to_partition[part]] = var;
-}
-
-
 static inline void mark_all_vars_used (tree *, void *data);
 
 /* Helper function for mark_all_vars_used, called via walk_tree.  */
@@ -485,10 +428,31 @@ remove_unused_scope_block_p (tree scope)
       next = &TREE_CHAIN (*t);
 
       /* Debug info of nested function refers to the block of the
-        function.  */
+        function.  We might stil call it even if all statements
+        of function it was nested into was elliminated.
+        
+        TODO: We can actually look into cgraph to see if function
+        will be output to file.  */
       if (TREE_CODE (*t) == FUNCTION_DECL)
        unused = false;
 
+      /* If a decl has a value expr, we need to instantiate it
+        regardless of debug info generation, to avoid codegen
+        differences in memory overlap tests.  update_equiv_regs() may
+        indirectly call validate_equiv_mem() to test whether a
+        SET_DEST overlaps with others, and if the value expr changes
+        by virtual register instantiation, we may get end up with
+        different results.  */
+      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))
+       {
+         *t = TREE_CHAIN (*t);
+         next = t;
+       }
+
       /* 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
@@ -499,15 +463,24 @@ remove_unused_scope_block_p (tree scope)
 
       /* 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.  */
+        a lot of memory.  
+
+        For sake of -g3, we keep around those vars but we don't count this as
+        use of block, so innermost block with no used vars and no instructions
+        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.  */
+
       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);
@@ -522,41 +495,80 @@ remove_unused_scope_block_p (tree scope)
          {
            tree next = BLOCK_CHAIN (*t);
            tree supercontext = BLOCK_SUPERCONTEXT (*t);
+
            *t = BLOCK_SUBBLOCKS (*t);
-           gcc_assert (!BLOCK_CHAIN (*t));
+           while (BLOCK_CHAIN (*t))
+             {
+               BLOCK_SUPERCONTEXT (*t) = supercontext;
+               t = &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);
-         }
+         *t = BLOCK_CHAIN (*t);
       }
     else
       {
         t = &BLOCK_CHAIN (*t);
        nsubblocks ++;
       }
+
+
+   if (!unused)
+     ;
    /* Outer scope is always used.  */
-   if (!BLOCK_SUPERCONTEXT (scope)
-       || TREE_CODE (BLOCK_SUPERCONTEXT (scope)) == FUNCTION_DECL)
+   else 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)
+   /* Innermost blocks with no live variables nor statements can be always
+      eliminated.  */
+   else if (!nsubblocks)
+     ;
+   /* If there are live subblocks and we still have some unused variables
+      or types declared, we must keep them.
+      Before inliing we must not depend on debug info verbosity to keep
+      DECL_UIDs stable.  */
+   else if (!cfun->after_inlining && BLOCK_VARS (scope))
      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)))))))
+   /* For terse debug info we can eliminate info on unused variables.  */
+   else if (debug_info_level == DINFO_LEVEL_NONE
+           || debug_info_level == DINFO_LEVEL_TERSE)
+     {
+       /* Even for -g0/-g1 don't prune outer scopes from artificial
+         functions, otherwise diagnostics using tree_nonartificial_location
+         will not be emitted properly.  */
+       if (inlined_function_outer_scope_p (scope))
+        {
+          tree ao = scope;
+
+          while (ao
+                 && TREE_CODE (ao) == BLOCK
+                 && BLOCK_ABSTRACT_ORIGIN (ao) != ao)
+            ao = BLOCK_ABSTRACT_ORIGIN (ao);
+          if (ao
+              && TREE_CODE (ao) == FUNCTION_DECL
+              && DECL_DECLARED_INLINE_P (ao)
+              && lookup_attribute ("artificial", DECL_ATTRIBUTES (ao)))
+            unused = false;
+        }
+     }
+   else if (BLOCK_VARS (scope) || BLOCK_NUM_NONLOCALIZED_VARS (scope))
      unused = false;
+   /* See if this block is important for representation of inlined function.
+      Inlined functions are always represented by block with
+      block_ultimate_origin being set to FUNCTION_DECL and DECL_SOURCE_LOCATION
+      set...  */
+   else if (inlined_function_outer_scope_p (scope))
+     unused = false;
+   else
+   /* Verfify that only blocks with source location set
+      are entry points to the inlined functions.  */
+     gcc_assert (BLOCK_SOURCE_LOCATION (scope) == UNKNOWN_LOCATION);
+
+   TREE_USED (scope) = !unused;
    return unused;
 }
 
@@ -570,6 +582,81 @@ mark_all_vars_used (tree *expr_p, void *data)
 }
 
 
+/* Dump scope blocks starting at SCOPE to FILE.  INDENT is the
+   indentation level and FLAGS is as in print_generic_expr.  */
+
+static void
+dump_scope_block (FILE *file, int indent, tree scope, int flags)
+{
+  tree var, t;
+  unsigned int i;
+
+  fprintf (file, "\n%*s{ Scope block #%i%s%s",indent, "" , BLOCK_NUMBER (scope),
+          TREE_USED (scope) ? "" : " (unused)",
+          BLOCK_ABSTRACT (scope) ? " (abstract)": "");
+  if (BLOCK_SOURCE_LOCATION (scope) != UNKNOWN_LOCATION)
+    {
+      expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (scope));
+      fprintf (file, " %s:%i", s.file, s.line);
+    }
+  if (BLOCK_ABSTRACT_ORIGIN (scope))
+    {
+      tree origin = block_ultimate_origin (scope);
+      if (origin)
+       {
+         fprintf (file, " Originating from :");
+         if (DECL_P (origin))
+           print_generic_decl (file, origin, flags);
+         else
+           fprintf (file, "#%i", BLOCK_NUMBER (origin));
+       }
+    }
+  fprintf (file, " \n");
+  for (var = BLOCK_VARS (scope); var; var = TREE_CHAIN (var))
+    {
+      bool used = false;
+      var_ann_t ann;
+
+      if ((ann = var_ann (var))
+         && ann->used)
+       used = true;
+
+      fprintf (file, "%*s",indent, "");
+      print_generic_decl (file, var, flags);
+      fprintf (file, "%s\n", used ? "" : " (unused)");
+    }
+  for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (scope); i++)
+    {
+      fprintf (file, "%*s",indent, "");
+      print_generic_decl (file, BLOCK_NONLOCALIZED_VAR (scope, i),
+                         flags);
+      fprintf (file, " (nonlocalized)\n");
+    }
+  for (t = BLOCK_SUBBLOCKS (scope); t ; t = BLOCK_CHAIN (t))
+    dump_scope_block (file, indent + 2, t, flags);
+  fprintf (file, "\n%*s}\n",indent, "");
+}
+
+
+/* Dump the tree of lexical scopes of current_function_decl to FILE.
+   FLAGS is as in print_generic_expr.  */
+
+void
+dump_scope_blocks (FILE *file, int flags)
+{
+  dump_scope_block (file, 0, DECL_INITIAL (current_function_decl), flags);
+}
+
+
+/* Dump the tree of lexical scopes of current_function_decl to stderr.
+   FLAGS is as in print_generic_expr.  */
+
+void
+debug_scope_blocks (int flags)
+{
+  dump_scope_blocks (stderr, flags);
+}
+
 /* Remove local variables that are not referenced in the IL.  */
 
 void
@@ -581,8 +668,13 @@ remove_unused_locals (void)
   var_ann_t ann;
   bitmap global_unused_vars = NULL;
 
-  if (optimize)
-    mark_scope_block_unused (DECL_INITIAL (current_function_decl));
+  /* Removing declarations from lexical blocks when not optimizing is
+     not only a waste of time, it actually causes differences in stack
+     layout.  */
+  if (!optimize)
+    return;
+
+  mark_scope_block_unused (DECL_INITIAL (current_function_decl));
 
   /* Assume all locals are unused.  */
   FOR_EACH_REFERENCED_VAR (t, rvi)
@@ -593,6 +685,8 @@ remove_unused_locals (void)
     {
       gimple_stmt_iterator gsi;
       size_t i;
+      edge_iterator ei;
+      edge e;
 
       /* Walk the statements.  */
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -627,8 +721,14 @@ remove_unused_locals (void)
              mark_all_vars_used (&arg, NULL);
             }
         }
+
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       if (e->goto_locus)
+         TREE_USED (e->goto_block) = true;
     }
 
+  cfun->has_local_explicit_reg_vars = false;
+
   /* Remove unmarked local vars from local_decls.  */
   for (cell = &cfun->local_decls; *cell; )
     {
@@ -650,6 +750,10 @@ remove_unused_locals (void)
              continue;
            }
        }
+      else if (TREE_CODE (var) == VAR_DECL
+              && DECL_HARD_REGISTER (var)
+              && !is_global_var (var))
+       cfun->has_local_explicit_reg_vars = true;
       cell = &TREE_CHAIN (*cell);
     }
 
@@ -673,8 +777,7 @@ remove_unused_locals (void)
 
          if (TREE_CODE (var) == VAR_DECL
              && is_global_var (var)
-             && bitmap_bit_p (global_unused_vars, DECL_UID (var))
-             && (optimize || DECL_ARTIFICIAL (var)))
+             && bitmap_bit_p (global_unused_vars, DECL_UID (var)))
            *cell = TREE_CHAIN (*cell);
          else
            cell = &TREE_CHAIN (*cell);
@@ -689,16 +792,18 @@ remove_unused_locals (void)
      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->symbol_mem_tag
-       && !TREE_ADDRESSABLE (t)
-       && (optimize || DECL_ARTIFICIAL (t)))
+       && !ann->is_heapvar
+       && !TREE_ADDRESSABLE (t))
       remove_referenced_var (t);
-  if (optimize)
-    remove_unused_scope_block_p (DECL_INITIAL (current_function_decl));
+  remove_unused_scope_block_p (DECL_INITIAL (current_function_decl));
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Scope blocks after cleanups:\n");
+      dump_scope_blocks (dump_file, dump_flags);
+    }
 }
 
 
@@ -993,7 +1098,7 @@ dump_var_map (FILE *f, var_map map)
       else
        p = x;
 
-      if (map->partition_to_var[p] == NULL_TREE)
+      if (ssa_name (p) == NULL_TREE)
         continue;
 
       t = 0;