different code of dwarf2out.c.

I had a draft patch to use DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref_udata and
DW_FORM_ref4 which should be slightly smaller than just DW_FORM_ref_udata.
But it produced larger files than just DW_FORM_ref_udata.  Assuming it was due
to multiplied abbrev definitions.  One would need to decide when if it is
worth to create a new smaller-sized abbrev but that seems too complicated for
such kind of optimization.  There exist other project(s) in development for
DWARF optimizations as a post-processing tool, this patch is meant just as
a very simple way to reduce the (possibly intermediate) DWARF files.

It is incompatible with GNU binutils readelf, a pending simple fix is:
	[patch] Fix readelf for DW_FORM_ref_udata
	http://sourceware.org/ml/binutils/2011-10/msg00201.html

No regressions on {x86_64,x86_64-m32,i686}-fedora16pre-linux-gnu
(4.7.0 20111002).  No changes in readelf -w output on libstdc++.so.

My former DW_AT_sibling patch will be updated on top of this one:
	Re: [patch#2] dwarf2out: Drop the size + performance overhead of DW_AT_sibling
	http://gcc.gnu.org/ml/gcc-patches/2011-10/msg01869.html
These two optimizations are not incremental to each other as both benefit
primarily from common DW_AT_sibling.  That size decrease 3.49% will be less
after this patch; moreover when not all DW_AT_sibling attrs will be dropped.


Thanks,
Jan


gcc/
2011-10-21  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* dwarf2out.c (DW_FORM_ref): Remove.
	(size_of_die) <dw_val_class_die_ref>: Use size_of_uleb128 for
	!AT_ref_external references.
	(calc_die_sizes_change): New variable.
	(calc_die_sizes): Permit die_offset incrementals.  Set
	CALC_DIE_SIZES_CHANGE accordingly.
	(value_format) <dw_val_class_die_ref>: Return DW_FORM_ref_udata for
	!AT_ref_external references.
	(output_die) <dw_val_class_die_ref>: Use dw2_asm_output_data_uleb128
	for !AT_ref_external references.
	(output_unit_prep): New function, call calc_die_sizes repeatedly based
	on CALC_DIE_SIZES_CHANGE.
	(output_comp_unit, output_comdat_type_unit): Move some code to
	output_unit_prep.

--- gcc/dwarf2out.c
+++ gcc/dwarf2out.c
@@ -226,7 +226,6 @@ static GTY(()) rtx current_unit_personality;
 
 /* Data and reference forms for relocatable data.  */
 #define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4)
-#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4)
 
 #ifndef DEBUG_FRAME_SECTION
 #define DEBUG_FRAME_SECTION	".debug_frame"
@@ -7700,7 +7699,7 @@ size_of_die (dw_die_ref die)
 		size += DWARF_OFFSET_SIZE;
 	    }
 	  else
-	    size += DWARF_OFFSET_SIZE;
+	    size += size_of_uleb128 (AT_ref (a)->die_offset);
 	  break;
 	case dw_val_class_fde_ref:
 	  size += DWARF_OFFSET_SIZE;
@@ -7735,6 +7734,10 @@ size_of_die (dw_die_ref die)
   return size;
 }
 
+/* Has calc_die_sizes changed any DIE_OFFSET?  */
+
+static bool calc_die_sizes_change;
+
 /* Size the debugging information associated with a given DIE.  Visits the
    DIE's children recursively.  Updates the global variable next_die_offset, on
    each time through.  Uses the current value of next_die_offset to update the
@@ -7745,9 +7748,12 @@ calc_die_sizes (dw_die_ref die)
 {
   dw_die_ref c;
 
-  gcc_assert (die->die_offset == 0
-	      || (unsigned long int) die->die_offset == next_die_offset);
-  die->die_offset = next_die_offset;
+  gcc_assert ((unsigned long int) die->die_offset <= next_die_offset);
+  if ((unsigned long int) die->die_offset != next_die_offset)
+    {
+      die->die_offset = next_die_offset;
+      calc_die_sizes_change = true;
+    }
   next_die_offset += size_of_die (die);
 
   FOR_EACH_CHILD (die, c, calc_die_sizes (c));
@@ -8018,7 +8024,7 @@ value_format (dw_attr_ref a)
       if (AT_ref_external (a))
 	return use_debug_types ? DW_FORM_ref_sig8 : DW_FORM_ref_addr;
       else
-	return DW_FORM_ref;
+	return DW_FORM_ref_udata;
     case dw_val_class_fde_ref:
       return DW_FORM_data;
     case dw_val_class_lbl_id:
@@ -8397,8 +8403,7 @@ output_die (dw_die_ref die)
 	  else
 	    {
 	      gcc_assert (AT_ref (a)->die_offset);
-	      dw2_asm_output_data (DWARF_OFFSET_SIZE, AT_ref (a)->die_offset,
-				   "%s", name);
+	      dw2_asm_output_data_uleb128 (AT_ref (a)->die_offset, "%s", name);
 	    }
 	  break;
 
@@ -8496,6 +8501,28 @@ output_compilation_unit_header (void)
   dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
 }
 
+/* Perform initializations common for .debug_info and .debug_types sections.  */
+
+static void
+output_unit_prep (dw_die_ref die, unsigned long init_die_offset)
+{
+  /* First mark all the DIEs in this CU so we know which get local refs.  */
+  mark_dies (die);
+
+  build_abbrev_table (die);
+
+  /* The DIE sizes can increase, due to DW_FORM_ref_udata size increase
+     dependent on increases of other DIE_OFFSETs.  */
+  do
+    {
+      /* Initialize the beginning DIE offset - and calculate sizes/offsets.  */
+      next_die_offset = init_die_offset;
+      calc_die_sizes_change = false;
+      calc_die_sizes (die);
+    }
+  while (calc_die_sizes_change);
+}
+
 /* Output the compilation unit DIE and its children.  */
 
 static void
@@ -8511,15 +8538,8 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
   /* Even if there are no children of this DIE, we must output the information
      about the compilation unit.  Otherwise, on an empty translation unit, we
      will generate a present, but empty, .debug_info section.  IRIX 6.5 `nm'
-     will then complain when examining the file.  First mark all the DIEs in
-     this CU so we know which get local refs.  */
-  mark_dies (die);
-
-  build_abbrev_table (die);
-
-  /* Initialize the beginning DIE offset - and calculate sizes/offsets.  */
-  next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
-  calc_die_sizes (die);
+     will then complain when examining the file.  */
+  output_unit_prep (die, DWARF_COMPILE_UNIT_HEADER_SIZE);
 
   oldsym = die->die_id.die_symbol;
   if (oldsym)
@@ -8563,14 +8583,7 @@ output_comdat_type_unit (comdat_type_node *node)
   tree comdat_key;
 #endif
 
-  /* First mark all the DIEs in this CU so we know which get local refs.  */
-  mark_dies (node->root_die);
-
-  build_abbrev_table (node->root_die);
-
-  /* Initialize the beginning DIE offset - and calculate sizes/offsets.  */
-  next_die_offset = DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE;
-  calc_die_sizes (node->root_die);
+  output_unit_prep (node->root_die, DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE);
 
 #if defined (OBJECT_FORMAT_ELF)
   secname = ".debug_types";
