This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Huge Increase in Unstripped Executable Size G++ 2.95 to 3.2


hi -

I didn't get comments on the last version of the
-feliminate-unused-dwarf2-types patch that i posted.  References
for the previous versions:

http://gcc.gnu.org/ml/gcc-patches/2002-06/msg01473.html
http://gcc.gnu.org/ml/gcc-patches/2002-07/msg00255.html
http://gcc.gnu.org/ml/gcc-patches/2002-10/msg00071.html

I have not changed the functionality; however, there were a few
conflicts with changes that went in after i posted that patch.
Thus, i include below the patch based on the current cvs mainline.

With this patch, turning on -feliminate-unused-dwarf2-types
will remove from the dwarf2 output any types that are declared
but not actually used.  It will also remove from the file table
entries to which there are no references.

This patch makes no changes in the gcc testsuite results, even
if i change the default for the switch to 1.  It causes one failure
in the gdb test suite, where the test was asking for information
about a type that was declared but not used.

I've had this in my local tree for a while now, and i haven't run into
any debugging problems stemming from it.

There were a couple comments about the option name: that maybe
it should be something like -feliminate-unused-debug-types,
or that maybe it should not be an option at all, and be always
on.  Such changes are easy to make, but i'd like to hear what
other people think.

A caveat is that this may not interact well with the mechanism for
dwarf2 duplicate removal.  As i understand how that works, it relies
on a given header file generating the same debugging information,
regardless of what compilation unit it is included into.  This
patch will invalidate that assumption.

sss


Index: dwarf2out.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/dwarf2out.c,v
retrieving revision 1.401
diff -u -p -c -r1.401 dwarf2out.c
*** dwarf2out.c	20 Feb 2003 17:51:39 -0000	1.401
--- dwarf2out.c	28 Feb 2003 17:21:14 -0000
*************** static GTY(()) limbo_die_node *limbo_die
*** 3458,3463 ****
--- 3458,3464 ----
  
  /* Filenames referenced by this compilation unit.  */
  static GTY(()) varray_type file_table;
+ static GTY(()) varray_type file_table_emitted;
  static GTY(()) size_t file_table_last_lookup_index;
  
  /* A pointer to the base of a table of references to DIE's that describe
*************** static void add_loc_descr_to_loc_list   
*** 3844,3849 ****
--- 3845,3858 ----
  static void output_loc_list		PARAMS ((dw_loc_list_ref));
  static char *gen_internal_sym 		PARAMS ((const char *));
  
+ static void prune_unmark_dies		PARAMS ((dw_die_ref));
+ static void prune_unused_types_mark     PARAMS ((dw_die_ref, int));
+ static void prune_unused_types_walk     PARAMS ((dw_die_ref));
+ static void prune_unused_types_walk_attribs PARAMS ((dw_die_ref));
+ static void prune_unused_types_prune    PARAMS ((dw_die_ref));
+ static void prune_unused_types          PARAMS ((void));
+ static int maybe_emit_file              PARAMS ((int));
+ 
  /* Section names used to hold DWARF debugging information.  */
  #ifndef DEBUG_INFO_SECTION
  #define DEBUG_INFO_SECTION	".debug_info"
*************** splice_child_die (parent, child)
*** 5217,5222 ****
--- 5226,5232 ----
  	break;
        }
  
+   child->die_parent = parent;
    child->die_sib = parent->die_child;
    parent->die_child = child;
  }
*************** lookup_filename (file_name)
*** 12352,12366 ****
    file_table_last_lookup_index = n;
    save_file_name = (char *) ggc_strdup (file_name);
    VARRAY_PUSH_CHAR_PTR (file_table, save_file_name);
  
!   if (DWARF2_ASM_LINE_DEBUG_INFO)
      {
!       fprintf (asm_out_file, "\t.file %lu ", (unsigned long) i);
!       output_quoted_string (asm_out_file, file_name);
!       fputc ('\n', asm_out_file);
      }
! 
!   return i;
  }
  
  static void
--- 12362,12392 ----
    file_table_last_lookup_index = n;
    save_file_name = (char *) ggc_strdup (file_name);
    VARRAY_PUSH_CHAR_PTR (file_table, save_file_name);
+   VARRAY_PUSH_UINT (file_table_emitted, 0);
+ 
+   return i;
+ }
  
! static int
! maybe_emit_file (fileno)
!      int fileno;
! {
!   static int emitcount = 0;  
!   if (DWARF2_ASM_LINE_DEBUG_INFO && fileno > 0)
      {
!       if (!VARRAY_UINT (file_table_emitted, fileno))
!         {
!           VARRAY_UINT (file_table_emitted, fileno) = ++emitcount;
!           fprintf (asm_out_file, "\t.file %u ",
!                    VARRAY_UINT (file_table_emitted, fileno));
!           output_quoted_string (asm_out_file,
!                                 VARRAY_CHAR_PTR (file_table, fileno));
!           fputc ('\n', asm_out_file);
!         }
!       return VARRAY_UINT (file_table_emitted, fileno);
      }
!   else
!     return fileno;
  }
  
  static void
*************** init_file_table ()
*** 12368,12376 ****
--- 12394,12404 ----
  {
    /* Allocate the initial hunk of the file_table.  */
    VARRAY_CHAR_PTR_INIT (file_table, 64, "file_table");
+   VARRAY_UINT_INIT (file_table_emitted, 64, "file_table_emitted");
  
    /* Skip the first entry - file numbers begin at 1.  */
    VARRAY_PUSH_CHAR_PTR (file_table, NULL);
+   VARRAY_PUSH_UINT (file_table_emitted, 0);
    file_table_last_lookup_index = 0;
  }
  
*************** dwarf2out_source_line (line, filename)
*** 12396,12401 ****
--- 12424,12431 ----
  	{
  	  unsigned file_num = lookup_filename (filename);
  
+           file_num = maybe_emit_file (file_num);
+ 
  	  /* Emit the .loc directive understood by GNU as.  */
  	  fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
  
*************** dwarf2out_start_source_file (lineno, fil
*** 12487,12492 ****
--- 12517,12523 ----
        dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
        dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
  				   lineno);
+       maybe_emit_file (lookup_filename (filename));
        dw2_asm_output_data_uleb128 (lookup_filename (filename),
  				   "Filename we just started");
      }
*************** output_indirect_string (h, v)
*** 12646,12651 ****
--- 12677,12890 ----
    return 1;
  }
  
+ 
+ 
+ /* Clear the marks for a die and its children.
+    Be cool if the mark isn't set. */
+ 
+ static void
+ prune_unmark_dies (die)
+      dw_die_ref die;
+ {
+   dw_die_ref c;
+   die->die_mark = 0;
+   for (c = die->die_child; c; c = c->die_sib)
+     prune_unmark_dies (c);
+ }
+ 
+ 
+ /* Given DIE that we're marking as used, find any other dies
+    it references as attributes and mark them as used.  */
+ 
+ static void
+ prune_unused_types_walk_attribs (die)
+      dw_die_ref die;
+ {
+   dw_attr_ref a;
+ 
+   for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+     {
+       if (a->dw_attr_val.val_class == dw_val_class_die_ref)
+         {
+           /* A reference to another DIE.
+              Make sure that it will get emitted.  */
+           prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
+         }
+       else if (a->dw_attr == DW_AT_decl_file)
+         {
+           /* A reference to a file.  Make sure the file name is emitted.  */
+           a->dw_attr_val.v.val_unsigned =
+             maybe_emit_file (a->dw_attr_val.v.val_unsigned);
+         }
+     }
+ }
+ 
+ 
+ /* Mark DIE as being used.  If DOKIDS is true, then walk down
+    to DIE's children.  */
+ 
+ static void
+ prune_unused_types_mark (die, dokids)
+      dw_die_ref die;
+      int dokids;
+ {
+   dw_die_ref c;
+ 
+   if (die->die_mark == 0) {
+     /* We haven't done this node yet.  Mark it as used.  */
+     die->die_mark = 1;
+ 
+     /* We also have to mark its parents as used.
+        (But we don't want to mark our parents' kids due to this.)  */
+     if (die->die_parent)
+       prune_unused_types_mark (die->die_parent, 0);
+ 
+     /* Mark any referenced nodes.  */
+     prune_unused_types_walk_attribs (die);
+   }
+ 
+   if (dokids && die->die_mark != 2)
+     {
+       /* We need to walk the children, but haven't done so yet.
+          Remember that we've walked the kids.  */
+       die->die_mark = 2;
+ 
+       /* Walk them.  */
+       for (c = die->die_child; c; c = c->die_sib)
+         {
+           /* If this is an array type, we need to make sure our
+              kids get marked, even if they're types. */
+           if (die->die_tag == DW_TAG_array_type)
+             prune_unused_types_mark (c, 1);
+           else
+             prune_unused_types_walk (c);
+         }
+     }
+ }
+ 
+ 
+ /* Walk the tree DIE and mark types that we actually use.  */
+ 
+ static void
+ prune_unused_types_walk (die)
+      dw_die_ref die;
+ {
+   dw_die_ref c;
+ 
+   /* Don't do anything if this node is already marked.  */
+   if (die->die_mark)
+     return;
+ 
+   switch (die->die_tag) {
+   case DW_TAG_const_type:
+   case DW_TAG_packed_type:
+   case DW_TAG_pointer_type:
+   case DW_TAG_reference_type:
+   case DW_TAG_volatile_type:
+   case DW_TAG_typedef:
+   case DW_TAG_array_type:
+   case DW_TAG_structure_type:
+   case DW_TAG_union_type:
+   case DW_TAG_class_type:
+   case DW_TAG_friend:
+   case DW_TAG_variant_part:
+   case DW_TAG_enumeration_type:
+   case DW_TAG_subroutine_type:
+   case DW_TAG_string_type:
+   case DW_TAG_set_type:
+   case DW_TAG_subrange_type:
+   case DW_TAG_ptr_to_member_type:
+   case DW_TAG_file_type:
+     /* It's a type node --- don't mark it.  */
+     return;
+ 
+   default:
+     /* Mark everything else.  */
+     break;
+   }
+ 
+   die->die_mark = 1;
+ 
+   /* Now, mark any dies referenced from here.  */
+   prune_unused_types_walk_attribs (die);
+ 
+   /* Mark children.  */
+   for (c = die->die_child; c; c = c->die_sib)
+     prune_unused_types_walk (c);
+ }
+ 
+ 
+ /* Remove from the tree DIE any dies that aren't marked.  */
+ 
+ static void
+ prune_unused_types_prune (die)
+      dw_die_ref die;
+ {
+   dw_die_ref c, p, n;
+   if (!die->die_mark)
+     abort();
+ 
+   p = NULL;
+   for (c = die->die_child; c; c = n)
+     {
+       n = c->die_sib;
+       if (c->die_mark)
+         {
+           prune_unused_types_prune (c);
+           p = c;
+         }
+       else
+         {
+           if (p)
+             p->die_sib = n;
+           else
+             die->die_child = n;
+           free_die (c);
+         }
+     }
+ }
+ 
+ 
+ /* Remove dies representing declarations that we never use.  */
+ 
+ static void
+ prune_unused_types ()
+ {
+   unsigned int i;
+   limbo_die_node *node;
+ 
+   /* Clear all the marks.  */
+   prune_unmark_dies (comp_unit_die);
+   for (node = limbo_die_list; node; node = node->next)
+     prune_unmark_dies (node->die);
+ 
+   /* Set the mark on nodes that are actually used.  */
+   prune_unused_types_walk (comp_unit_die);
+   for (node = limbo_die_list; node; node = node->next)
+     prune_unused_types_walk (node->die);
+ 
+   /* Also set the mark on nodes referenced from the
+      pubname_table or arange_table.  */
+   for (i=0; i < pubname_table_in_use; i++)
+     {
+       prune_unused_types_mark (pubname_table[i].die, 1);
+     }
+   for (i=0; i < arange_table_in_use; i++)
+     {
+       prune_unused_types_mark (arange_table[i], 1);
+     }
+ 
+   /* Get rid of nodes that aren't marked.  */
+   prune_unused_types_prune (comp_unit_die);
+   for (node = limbo_die_list; node; node = node->next)
+     prune_unused_types_prune (node->die);
+ 
+   /* Leave the marks clear.  */
+   prune_unmark_dies (comp_unit_die);
+   for (node = limbo_die_list; node; node = node->next)
+     prune_unmark_dies (node->die);
+ }
+ 
  /* Output stuff that dwarf requires at the end of every file,
     and generate the DWARF-2 debugging info.  */
  
*************** dwarf2out_finish (input_filename)
*** 12739,12744 ****
--- 12978,12986 ----
       They will go into limbo_die_list.  */
    if (flag_eliminate_dwarf2_dups)
      break_out_includes (comp_unit_die);
+ 
+   if (flag_eliminate_unused_dwarf2_types)
+     prune_unused_types ();
  
    /* Traverse the DIE's and add add sibling attributes to those DIE's
       that have children.  */
Index: toplev.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.719
diff -u -p -c -r1.719 toplev.c
*** toplev.c	22 Feb 2003 19:25:19 -0000	1.719
--- toplev.c	28 Feb 2003 17:21:18 -0000
*************** tree current_function_func_begin_label;
*** 378,383 ****
--- 378,387 ----
  
  int flag_eliminate_dwarf2_dups = 0;
  
+ /* Nonzero if doing dwarf2 unused type elimination.  */
+ 
+ int flag_eliminate_unused_dwarf2_types = 0;
+ 
  /* Nonzero if generating code to do profiling.  */
  
  int profile_flag = 0;
*************** static const lang_independent_options f_
*** 990,995 ****
--- 994,1001 ----
  {
    {"eliminate-dwarf2-dups", &flag_eliminate_dwarf2_dups, 1,
     N_("Perform DWARF2 duplicate elimination") },
+   {"eliminate-unused-dwarf2-types", &flag_eliminate_unused_dwarf2_types, 1,
+    N_("Perform DWARF2 unused type elimination") },
    {"float-store", &flag_float_store, 1,
     N_("Do not store floats in registers") },
    {"defer-pop", &flag_defer_pop, 1,
Index: flags.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/flags.h,v
retrieving revision 1.99
diff -u -p -c -r1.99 flags.h
*** flags.h	20 Feb 2003 20:56:51 -0000	1.99
--- flags.h	28 Feb 2003 17:21:22 -0000
*************** extern int flag_gcse_sm;
*** 641,646 ****
--- 641,650 ----
  
  extern int flag_eliminate_dwarf2_dups;
  
+ /* Nonzero means we should do dwarf2 unused type elimination.  */
+ 
+ extern int flag_eliminate_unused_dwarf2_types;
+ 
  /* Nonzero means to collect statistics which might be expensive
     and to print them when we are done.  */
  extern int flag_detailed_statistics;
Index: doc/invoke.texi
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.247
diff -u -p -c -r1.247 invoke.texi
*** doc/invoke.texi	23 Feb 2003 16:56:04 -0000	1.247
--- doc/invoke.texi	28 Feb 2003 17:21:25 -0000
*************** in the following sections.
*** 258,263 ****
--- 258,264 ----
  -p  -pg  -print-file-name= at var{library}  -print-libgcc-file-name @gol
  -print-multi-directory  -print-multi-lib @gol
  -print-prog-name= at var{program}  -print-search-dirs  -Q @gol
+ -feliminate-unused-dwarf2-types @gol
  -save-temps  -time}
  
  @item Optimization Options
*************** anything else.
*** 3411,3416 ****
--- 3412,3429 ----
  @opindex dumpspecs
  Print the compiler's built-in specs---and don't do anything else.  (This
  is used when GCC itself is being built.)  @xref{Spec Files}.
+ 
+ @item -feliminate-unused-dwarf2-types
+ @opindex feliminate-unused-dwarf2-types
+ Normally, when producing DWARF2 output, GCC will emit debugging
+ information for all types declared in a compilation
+ unit, regardless of whether or not they are actually used
+ in that compilation unit.  Sometimes this is useful, such as
+ if, in the debugger, you want to cast a value to a type that is
+ not actually used in your program (but is declared).  More often,
+ however, this results in a significant amount of wasted space.
+ With this option, GCC will avoid producing debug symbol output
+ for types that are nowhere used in the source file being compiled.
  @end table
  
  @node Optimize Options


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]