]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR tree-optimization/37709 (inlining causes explosion in debug info)
authorJan Hubicka <jh@suse.cz>
Mon, 23 Feb 2009 13:10:53 +0000 (14:10 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Mon, 23 Feb 2009 13:10:53 +0000 (13:10 +0000)
PR tree-optimization/37709
* tree.c (block_ultimate_origin): Move here from dwarf2out.
* tree.h (block_ultimate_origin): Declare.
* dwarf2out.c (block_ultimate_origin): Move to tree.c
* tree-ssa-live.c (remove_unused_scope_block_p):
Eliminate blocks containig no instructions nor live variables nor
nested blocks.
(dump_scope_block): New function.
(remove_unused_locals): Enable removal of dead blocks by default;
enable dumping at TDF_DETAILS.

From-SVN: r144381

gcc/ChangeLog
gcc/dbxout.c
gcc/dwarf2out.c
gcc/tree-ssa-live.c
gcc/tree.c
gcc/tree.h

index 1961e74811c6fafd91ac2672da2d9758924fd1ba..01968baaf2aabe4328ba3075adb0a452940509fa 100644 (file)
@@ -1,3 +1,16 @@
+2009-02-23  Jan Hubicka  <jh@suse.cz>
+
+       PR tree-optimization/37709                                              
+       * tree.c (block_ultimate_origin): Move here from dwarf2out.             
+       * tree.h (block_ultimate_origin): Declare.                              
+       * dwarf2out.c (block_ultimate_origin): Move to tree.c                   
+       * tree-ssa-live.c (remove_unused_scope_block_p):
+       Eliminate blocks containig no instructions nor live variables nor
+       nested blocks.
+       (dump_scope_block): New function.
+       (remove_unused_locals): Enable removal of dead blocks by default;
+       enable dumping at TDF_DETAILS.                                          
+
 2008-02-21  H.J. Lu  <hongjiu.lu@intel.com>
 
        * config/i386/i386.c (classify_argument): Don't allow COImode
index f4a2792bc93fb1433872176914bf0e6755dcc0d4..6cfa55f932808d1ab2aa71682cafda026e3605c9 100644 (file)
@@ -3593,7 +3593,7 @@ dbxout_block (tree block, int depth, tree args)
   while (block)
     {
       /* Ignore blocks never expanded or otherwise marked as real.  */
-      if (TREE_USED (block) && TREE_ASM_WRITTEN (block))
+      if (TREE_ASM_WRITTEN (block))
        {
          int did_output;
          int blocknum = BLOCK_NUMBER (block);
index d3de6e6afc68af6d8db44c999851fff3ad678d25..2e5f032c2a260acfb4b7cfa0ed992ba2151d671a 100644 (file)
@@ -4947,7 +4947,6 @@ static const char *dwarf_tag_name (unsigned);
 static const char *dwarf_attr_name (unsigned);
 static const char *dwarf_form_name (unsigned);
 static tree decl_ultimate_origin (const_tree);
-static tree block_ultimate_origin (const_tree);
 static tree decl_class_context (tree);
 static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
 static inline enum dw_val_class AT_class (dw_attr_ref);
@@ -5772,51 +5771,6 @@ decl_ultimate_origin (const_tree decl)
   return DECL_ABSTRACT_ORIGIN (decl);
 }
 
-/* Determine the "ultimate origin" of a block.  The block may be an inlined
-   instance of an inlined instance of a block which is local to an inline
-   function, so we have to trace all of the way back through the origin chain
-   to find out what sort of node actually served as the original seed for the
-   given block.  */
-
-static tree
-block_ultimate_origin (const_tree block)
-{
-  tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
-
-  /* output_inline_function sets BLOCK_ABSTRACT_ORIGIN for all the
-     nodes in the function to point to themselves; ignore that if
-     we're trying to output the abstract instance of this function.  */
-  if (BLOCK_ABSTRACT (block) && immediate_origin == block)
-    return NULL_TREE;
-
-  if (immediate_origin == NULL_TREE)
-    return NULL_TREE;
-  else
-    {
-      tree ret_val;
-      tree lookahead = immediate_origin;
-
-      do
-       {
-         ret_val = lookahead;
-         lookahead = (TREE_CODE (ret_val) == BLOCK
-                      ? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
-       }
-      while (lookahead != NULL && lookahead != ret_val);
-
-      /* The block's abstract origin chain may not be the *ultimate* origin of
-        the block. It could lead to a DECL that has an abstract origin set.
-        If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
-        will give us if it has one).  Note that DECL's abstract origins are
-        supposed to be the most distant ancestor (or so decl_ultimate_origin
-        claims), so we don't need to loop following the DECL origins.  */
-      if (DECL_P (ret_val))
-       return DECL_ORIGIN (ret_val);
-
-      return ret_val;
-    }
-}
-
 /* Get the class to which DECL belongs, if any.  In g++, the DECL_CONTEXT
    of a virtual function may refer to a base class, so we check the 'this'
    parameter.  */
index 8ebf30ec9269b318aa252227f23990ed8df42f77..81e65f732e1c5cba80317a01cd45d9a91e93b57e 100644 (file)
@@ -485,10 +485,13 @@ 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;
-
       /* Remove everything we don't generate debug info for.  */
       else if (DECL_IGNORED_P (*t))
        {
@@ -506,15 +509,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);
@@ -537,10 +549,7 @@ remove_unused_scope_block_p (tree scope)
            nsubblocks ++;
          }
        else
-         {
-           gcc_assert (!BLOCK_VARS (*t));
-           *t = BLOCK_CHAIN (*t);
-         }
+         *t = BLOCK_CHAIN (*t);
       }
     else
       {
@@ -576,6 +585,38 @@ mark_all_vars_used (tree *expr_p, void *data)
   walk_tree (expr_p, mark_all_vars_used_1, data, NULL);
 }
 
+/* Dump scope blocks.  */
+
+static void
+dump_scope_block (FILE *file, int indent, tree scope, int flags)
+{
+  tree var, t;
+
+  fprintf (file, "\n%*sScope block #%i %s\n",indent, "" , BLOCK_NUMBER (scope),
+          TREE_USED (scope) ? "" : "(unused)");
+  if (BLOCK_ABSTRACT_ORIGIN (scope) && DECL_P (block_ultimate_origin (scope)))
+    {
+      fprintf (file, "\n%*sOriginating from ",indent + 1, "");
+      print_generic_decl (file, block_ultimate_origin (scope), flags);
+      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 (t = BLOCK_SUBBLOCKS (scope); t ; t = BLOCK_CHAIN (t))
+    dump_scope_block (file, indent + 2, t, flags);
+}
+
 
 /* Remove local variables that are not referenced in the IL.  */
 
@@ -588,8 +629,7 @@ remove_unused_locals (void)
   var_ann_t ann;
   bitmap global_unused_vars = NULL;
 
-  if (optimize)
-    mark_scope_block_unused (DECL_INITIAL (current_function_decl));
+  mark_scope_block_unused (DECL_INITIAL (current_function_decl));
 
   /* Assume all locals are unused.  */
   FOR_EACH_REFERENCED_VAR (t, rvi)
@@ -716,8 +756,12 @@ remove_unused_locals (void)
        && !TREE_ADDRESSABLE (t)
        && (optimize || DECL_ARTIFICIAL (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_block (dump_file, 0, DECL_INITIAL (current_function_decl), false);
+    }
 }
 
 
index 03c54cc1cb17b0a785f8b07c80cbdf475d37a010..423c8681cf2fb20d31fdee9ae88eca4af2e56059 100644 (file)
@@ -9199,4 +9199,49 @@ build_target_option_node (void)
   return t;
 }
 
+/* Determine the "ultimate origin" of a block.  The block may be an inlined
+   instance of an inlined instance of a block which is local to an inline
+   function, so we have to trace all of the way back through the origin chain
+   to find out what sort of node actually served as the original seed for the
+   given block.  */
+
+tree
+block_ultimate_origin (const_tree block)
+{
+  tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
+
+  /* output_inline_function sets BLOCK_ABSTRACT_ORIGIN for all the
+     nodes in the function to point to themselves; ignore that if
+     we're trying to output the abstract instance of this function.  */
+  if (BLOCK_ABSTRACT (block) && immediate_origin == block)
+    return NULL_TREE;
+
+  if (immediate_origin == NULL_TREE)
+    return NULL_TREE;
+  else
+    {
+      tree ret_val;
+      tree lookahead = immediate_origin;
+
+      do
+       {
+         ret_val = lookahead;
+         lookahead = (TREE_CODE (ret_val) == BLOCK
+                      ? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
+       }
+      while (lookahead != NULL && lookahead != ret_val);
+
+      /* The block's abstract origin chain may not be the *ultimate* origin of
+        the block. It could lead to a DECL that has an abstract origin set.
+        If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
+        will give us if it has one).  Note that DECL's abstract origins are
+        supposed to be the most distant ancestor (or so decl_ultimate_origin
+        claims), so we don't need to loop following the DECL origins.  */
+      if (DECL_P (ret_val))
+       return DECL_ORIGIN (ret_val);
+
+      return ret_val;
+    }
+}
+
 #include "gt-tree.h"
index 5a7e765784f191d7329882811f83e104156286c2..ae4291326d995dabd2e4c739ca9b2a074b804d30 100644 (file)
@@ -5022,6 +5022,7 @@ extern bool gimple_alloca_call_p (const_gimple);
 extern bool alloca_call_p (const_tree);
 extern bool must_pass_in_stack_var_size (enum machine_mode, const_tree);
 extern bool must_pass_in_stack_var_size_or_pad (enum machine_mode, const_tree);
+extern tree block_ultimate_origin (const_tree);
 
 /* In attribs.c.  */