Patchwork [Google,4.7] Backport upstream fission changes (issue6852101)

login
register
mail settings
Submitter Sterling Augustine
Date Nov. 29, 2012, 6:26 p.m.
Message ID <20121129182657.ACD8AA1947@sterling.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/202802/
State New
Headers show

Comments

Sterling Augustine - Nov. 29, 2012, 6:26 p.m.
This patch backports to gcc-google-4_7 the many changes to the fission
implementation required to merge fission into trunk.

See http://gcc.gnu.org/ml/gcc-patches/2012-10/msg02684.html and susbsequent
messages for a full description of what needed to change.  Most of the original
patch was already in google-4_7, so this is essentially a diff between the
two implementations.

These changes to make the resulting debug info smaller, so are useful
to have on this branch.

OK for Google 4.7?

Tested by running bootstrap and validating the results.

Sterling

Changelog.google-4_7

2012-11-27  Sterling Augustine  <saugustine@google.com>

	Backport changes to fission implementation required by
	trunk.  See
	http://gcc.gnu.org/ml/gcc-patches/2012-10/msg02684.html and
	susbsequent messages for a full description of what needed to
	change for it to be accepted into trunk.  Most of the original
	changes were already in google-4_7, so this is just the diff
	between the two implementations.

	These changes to make the resulting debug info smaller, so are useful
	to have on this branch.

	* dwarf2out.h (addr_table_entry_struct): Forward declare.
	(dw_val_struct): Change name and associated type of field val_index
	to val_entry.
	* dwarf2out.c (NOT_INDEXED, NO_INDEX_ASSIGNED, UNRELOCATED_OFFSET,
	RELOCATED_OFFSET): New defines.
	(ate_kind): New enum with enumerators ate_kind_rtx,
	ate_kind_rtx_dtprel, ate_kind_label.
	(addr_table_entry_struct, addr_table_entry): New structure and type.
	(dw_loc_list_struct): Change field name from begin_index to
	begin_entry, likewise with the type.
	(new_loc_descr, build_cfa_loc, new_addr_loc_descr, add_AT_flag,
	add_AT_int, add_AT_unsigned, add_AT_double, add_AT_vec,
	add_AT_string, add_AT_die_ref, add_AT_fde_ref,
	add_AT_loc, add_AT_loc_list, add_AT_addr, add_AT_file, add_AT_vms_delta,
	add_AT_lbl_id, add_AT_lineptr, add_AT_macptr, add_AT_offset):
	Change field name from val_index to val_entry, and intialize properly.
	(size_of_loc_descr, output_loc_operands): Add assertion and update call.
	(set_AT_index): Remove obsolete function.
	(remove_addr_table_entry, add_AT_lbl_id,
	add_AT_range_list, add_ranges_by_labels): Update prototypes, adjust
	all calls in file.
	(dtprel_bool): New enum with dtprel_false and dtprel_true.
	(dw_addr_op, new_addr_loc_descr): Update functions to use dtprel_bool,
	plus additional logic to handle val_entries. Use RELOCATED_OFFSET
	and UNRELOCATED_OFFSET.
	(AT_index, output_loc_list): Update comment.  Update logic to handle
	val_entry.
	(add_AT_low_high_pc): Update comment.  Change field name from
	val_index to val_entry, and call add_addr_table entry.
	(indirect_string_node, index_string_table): Delete obsolete types,
	variables and tables.
	(AT_string_form): Move most logic to ...
	(find_string_form): ... here and ...
	(set_indirect_string): ... here. New function.
	(addr_index_table): Change type from vector to hash table.
	(addr_table_entry_do_hash, addr_table_entry_eq, init_addr_table_entry,
	index_addr_table_entry): New functions.
	(add_addr_table_entry): Update prototype.  Convert logic to
	hash tables.
	(remove_loc_list_addr_table_entries): Convert logic to hash tables.
	(size_of_die, value_format, output_attr_index_or_value): Use
	NOT_INDEXED and NO_INDEX_ASSIGNED.
	(output_range_list_offset): Use RELOCATED_OFFSET.  Update comment.
	(output_comdat_type_unit): Check OBJECT_FORMAT_ELF.
	(add_ranges_by_labels, loc_descriptor, mem_loc_descriptor,
	loc_list_from_tree, add_const_value_attribute): Update comment.  Use
	dtprel_bool enumerators.
	(output_macinfo_op): Fix FIXME by handling DW_FORM_strp's and
	DW_FORM_GNU_str_index.
	(save_macinfo_strings, index_string, output_index_string_offset,
	output_index_string, output_indirect_strings, output_addr_table_entry):
	New functions.
	(output_indirect_string): Check refcount.
	(output_addr_table): Update logic for hash tables.
	(resolve_addr_in_expr, resolve_addr, hash_loc_operands,
	compare_loc_operands, index_location_lists): Update logic for val_entry.
	(dwarf2out_finish): Update logic for val_entry. Call
	htab_traverse_noresize multiple times, save macinfo_strings,
	index_string output_addr_table, output_indirect_strings. Add comments.
	Remove calls to output_addr_table, output_index_strings,
	and index_location_lists.





--
This patch is available for review at 1
Cary Coutant - Dec. 3, 2012, 10:25 p.m.
> 2012-11-27  Sterling Augustine  <saugustine@google.com>
>
>         Backport changes to fission implementation required by
>         trunk.  See
>         http://gcc.gnu.org/ml/gcc-patches/2012-10/msg02684.html and
>         susbsequent messages for a full description of what needed to
>         change for it to be accepted into trunk.  Most of the original
>         changes were already in google-4_7, so this is just the diff
>         between the two implementations.
>
>         These changes to make the resulting debug info smaller, so are useful
>         to have on this branch.
>
>         * dwarf2out.h (addr_table_entry_struct): Forward declare.
>         (dw_val_struct): Change name and associated type of field val_index
>         to val_entry.
>         * dwarf2out.c (NOT_INDEXED, NO_INDEX_ASSIGNED, UNRELOCATED_OFFSET,
>         RELOCATED_OFFSET): New defines.
>         (ate_kind): New enum with enumerators ate_kind_rtx,
>         ate_kind_rtx_dtprel, ate_kind_label.
>         (addr_table_entry_struct, addr_table_entry): New structure and type.
>         (dw_loc_list_struct): Change field name from begin_index to
>         begin_entry, likewise with the type.
>         (new_loc_descr, build_cfa_loc, new_addr_loc_descr, add_AT_flag,
>         add_AT_int, add_AT_unsigned, add_AT_double, add_AT_vec,
>         add_AT_string, add_AT_die_ref, add_AT_fde_ref,
>         add_AT_loc, add_AT_loc_list, add_AT_addr, add_AT_file, add_AT_vms_delta,
>         add_AT_lbl_id, add_AT_lineptr, add_AT_macptr, add_AT_offset):
>         Change field name from val_index to val_entry, and intialize properly.
>         (size_of_loc_descr, output_loc_operands): Add assertion and update call.
>         (set_AT_index): Remove obsolete function.
>         (remove_addr_table_entry, add_AT_lbl_id,
>         add_AT_range_list, add_ranges_by_labels): Update prototypes, adjust
>         all calls in file.
>         (dtprel_bool): New enum with dtprel_false and dtprel_true.
>         (dw_addr_op, new_addr_loc_descr): Update functions to use dtprel_bool,
>         plus additional logic to handle val_entries. Use RELOCATED_OFFSET
>         and UNRELOCATED_OFFSET.
>         (AT_index, output_loc_list): Update comment.  Update logic to handle
>         val_entry.
>         (add_AT_low_high_pc): Update comment.  Change field name from
>         val_index to val_entry, and call add_addr_table entry.
>         (indirect_string_node, index_string_table): Delete obsolete types,
>         variables and tables.
>         (AT_string_form): Move most logic to ...
>         (find_string_form): ... here and ...
>         (set_indirect_string): ... here. New function.
>         (addr_index_table): Change type from vector to hash table.
>         (addr_table_entry_do_hash, addr_table_entry_eq, init_addr_table_entry,
>         index_addr_table_entry): New functions.
>         (add_addr_table_entry): Update prototype.  Convert logic to
>         hash tables.
>         (remove_loc_list_addr_table_entries): Convert logic to hash tables.
>         (size_of_die, value_format, output_attr_index_or_value): Use
>         NOT_INDEXED and NO_INDEX_ASSIGNED.
>         (output_range_list_offset): Use RELOCATED_OFFSET.  Update comment.
>         (output_comdat_type_unit): Check OBJECT_FORMAT_ELF.
>         (add_ranges_by_labels, loc_descriptor, mem_loc_descriptor,
>         loc_list_from_tree, add_const_value_attribute): Update comment.  Use
>         dtprel_bool enumerators.
>         (output_macinfo_op): Fix FIXME by handling DW_FORM_strp's and
>         DW_FORM_GNU_str_index.
>         (save_macinfo_strings, index_string, output_index_string_offset,
>         output_index_string, output_indirect_strings, output_addr_table_entry):
>         New functions.
>         (output_indirect_string): Check refcount.
>         (output_addr_table): Update logic for hash tables.
>         (resolve_addr_in_expr, resolve_addr, hash_loc_operands,
>         compare_loc_operands, index_location_lists): Update logic for val_entry.
>         (dwarf2out_finish): Update logic for val_entry. Call
>         htab_traverse_noresize multiple times, save macinfo_strings,
>         index_string output_addr_table, output_indirect_strings. Add comments.
>         Remove calls to output_addr_table, output_index_strings,
>         and index_location_lists.

This is OK for the google/gcc-4_7 branch. Thanks!

-cary
Sterling Augustine - Dec. 4, 2012, 7:35 p.m.
On Thu, Nov 29, 2012 at 10:26 AM, Sterling Augustine
<saugustine@google.com> wrote:
> This patch backports to gcc-google-4_7 the many changes to the fission
> implementation required to merge fission into trunk.

Committed as posted. Thanks!

Patch

Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(revision 193909)
+++ gcc/dwarf2out.c	(working copy)
@@ -202,6 +202,9 @@ 
 
 /* A vector for a table that contains frame description
    information for each routine.  */
+#define NOT_INDEXED (-1U)
+#define NO_INDEX_ASSIGNED (-2U)
+
 static GTY(()) VEC(dw_fde_ref, gc) *fde_vec;
 
 struct GTY(()) indirect_string_node {
@@ -1216,14 +1219,35 @@ 
 DEF_VEC_P(dw_die_ref);
 DEF_VEC_ALLOC_P(dw_die_ref,heap);
 
+/* Describe an entry into the .debug_addr section.  */
+
+enum ate_kind {
+  ate_kind_rtx,
+  ate_kind_rtx_dtprel,
+  ate_kind_label
+};
+
+typedef struct GTY(()) addr_table_entry_struct {
+  enum ate_kind kind;
+  unsigned int refcount;
+  unsigned int index;
+  union addr_table_entry_struct_union
+    {
+      rtx GTY ((tag ("0"))) rtl;
+      char * GTY ((tag ("1"))) label;
+    }
+  GTY ((desc ("%1.kind"))) addr;
+}
+addr_table_entry;
+
 /* Location lists are ranges + location descriptions for that range,
    so you can track variables that are in different places over
    their entire life.  */
 typedef struct GTY(()) dw_loc_list_struct {
   dw_loc_list_ref dw_loc_next;
-  const char *begin; /* Label and index for begin address of range */
-  unsigned int begin_index;
-  const char *end;  /* Label for end address of range */
+  const char *begin; /* Label and addr_entry for start of range */
+  addr_table_entry *begin_entry;
+  const char *end;  /* Label for end of range */
   char *ll_symbol; /* Label for beginning of location list.
 		      Only on head of list */
   const char *section; /* Section this loclist is relative to */
@@ -1599,10 +1623,10 @@ 
 
   descr->dw_loc_opc = op;
   descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
-  descr->dw_loc_oprnd1.val_index = -1U;
+  descr->dw_loc_oprnd1.val_entry = NULL;
   descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
   descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
-  descr->dw_loc_oprnd2.val_index = -1U;
+  descr->dw_loc_oprnd2.val_entry = NULL;
   descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
 
   return descr;
@@ -1809,7 +1833,8 @@ 
       break;
     case DW_OP_GNU_addr_index:
     case DW_OP_GNU_const_index:
-      size += size_of_uleb128 (loc->dw_loc_oprnd1.val_index);
+      gcc_assert (loc->dw_loc_oprnd1.val_entry->index != NO_INDEX_ASSIGNED);
+      size += size_of_uleb128 (loc->dw_loc_oprnd1.val_entry->index);
       break;
     case DW_OP_const1u:
     case DW_OP_const1s:
@@ -2249,7 +2274,8 @@ 
 
     case DW_OP_GNU_addr_index:
     case DW_OP_GNU_const_index:
-      dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_index,
+      gcc_assert (loc->dw_loc_oprnd1.val_entry->index != NO_INDEX_ASSIGNED);
+      dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_entry->index,
                                    "(index into .debug_addr)");
       break;
 
@@ -2613,7 +2639,7 @@ 
     {
       head = new_reg_loc_descr (cfa->reg, cfa->base_offset);
       head->dw_loc_oprnd1.val_class = dw_val_class_const;
-      head->dw_loc_oprnd1.val_index = -1U;
+      head->dw_loc_oprnd1.val_entry = NULL;
       tmp = new_loc_descr (DW_OP_deref, 0, 0);
       add_loc_descr (&head, tmp);
       if (offset != 0)
@@ -3242,7 +3268,6 @@ 
 static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
 static inline enum dw_val_class AT_class (dw_attr_ref);
 static inline unsigned int AT_index (dw_attr_ref);
-static inline void set_AT_index (dw_attr_ref, unsigned int);
 static void add_AT_flag (dw_die_ref, enum dwarf_attribute, unsigned);
 static inline unsigned AT_flag (dw_attr_ref);
 static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
@@ -3270,18 +3295,17 @@ 
 static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
 			     dw_loc_list_ref);
 static inline dw_loc_list_ref AT_loc_list (dw_attr_ref);
-static unsigned int add_addr_table_entry (dw_attr_node *);
-static void remove_addr_table_entry (unsigned int);
+static addr_table_entry *add_addr_table_entry (void *, enum ate_kind);
+static void remove_addr_table_entry (addr_table_entry *);
 static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
 static inline rtx AT_addr (dw_attr_ref);
-static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *,
-			   bool);
+static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
 static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
 static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *);
 static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
 			   unsigned HOST_WIDE_INT);
 static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
-			       unsigned long, bool);
+                               unsigned long, bool);
 static inline const char *AT_lbl (dw_attr_ref);
 static dw_attr_ref get_AT (dw_die_ref, enum dwarf_attribute);
 static const char *get_AT_low_pc (dw_die_ref);
@@ -3392,7 +3416,7 @@ 
 static unsigned int add_ranges_num (int);
 static unsigned int add_ranges (const_tree);
 static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
-				  bool *, bool);
+                                  bool *, bool);
 static void output_ranges (void);
 static dw_line_info_table *new_line_info_table (void);
 static void output_line_info (bool);
@@ -3534,49 +3558,49 @@ 
 static void schedule_generic_params_dies_gen (tree t);
 static void gen_scheduled_generic_parms_dies (void);
 
-/* Return the operator to use for an address of a variable.
-   DTPREL is true for thread-local variables whose address
-   is really an offset relative to the TLS pointer, which
-   will need link-time relocation, but will not need relocation 
-   by the DWARF consumer.  For those, we use DW_OP_const*.
-   For regular variables, which need both link-time relocation
-   and consumer-level relocation (e.g., to account for
-   shared objects loaded at a random address), we use 
-   DW_OP_addr*.  */
+/* enum for tracking thread-local variables whose address is really an offset
+   relative to the TLS pointer, which will need link-time relocation, but will
+   not need relocation by the DWARF consumer.  */
 
-static inline enum dwarf_location_atom dw_addr_op (bool dtprel)
+enum dtprel_bool
 {
-  if (dtprel)
+  dtprel_false = 0,
+  dtprel_true = 1
+};
+
+/* Return the operator to use for an address of a variable.  For dtprel_true, we
+   use DW_OP_const*.  For regular variables, which need both link-time
+   relocation and consumer-level relocation (e.g., to account for shared objects
+   loaded at a random address), we use DW_OP_addr*.  */
+
+static inline enum dwarf_location_atom
+dw_addr_op (enum dtprel_bool dtprel)
+{
+  if (dtprel == dtprel_true)
     return (dwarf_split_debug_info ? DW_OP_GNU_const_index
             : (DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u));
   else
-    return (dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr);
+    return dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr;
 }
 
 /* Return a pointer to a newly allocated address location description.  If
    dwarf_split_debug_info is true, then record the address with the appropriate
    relocation.  */
 static inline dw_loc_descr_ref
-new_addr_loc_descr (rtx addr, int dtprel)
+new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
 {
   dw_loc_descr_ref ref = new_loc_descr (dw_addr_op (dtprel), 0, 0);
 
   ref->dw_loc_oprnd1.val_class = dw_val_class_addr;
-  ref->dw_loc_oprnd1.val_index = -1U;
   ref->dw_loc_oprnd1.v.val_addr = addr;
   ref->dtprel = dtprel;
   if (dwarf_split_debug_info)
-    {
-      dw_attr_node attr;
+    ref->dw_loc_oprnd1.val_entry
+        = add_addr_table_entry (addr,
+                                dtprel ? ate_kind_rtx_dtprel : ate_kind_rtx);
+  else
+    ref->dw_loc_oprnd1.val_entry = NULL;
 
-      attr.dw_attr = DW_AT_location;
-      attr.dw_attr_val.val_class = (dtprel
-                                    ? dw_val_class_loc : dw_val_class_addr);
-      attr.dw_attr_val.val_index = -1U;
-      attr.dw_attr_val.v.val_addr = addr;
-
-      ref->dw_loc_oprnd1.val_index = add_addr_table_entry (&attr);
-    }
   return ref;
 }
 
@@ -3586,7 +3610,7 @@ 
 #define DEBUG_INFO_SECTION	".debug_info"
 #endif
 #ifndef DEBUG_DWO_INFO_SECTION
-#define DEBUG_DWO_INFO_SECTION	".debug_info.dwo"
+#define DEBUG_DWO_INFO_SECTION ".debug_info.dwo"
 #endif
 #ifndef DEBUG_ABBREV_SECTION
 #define DEBUG_ABBREV_SECTION	".debug_abbrev"
@@ -3598,13 +3622,13 @@ 
 #define DEBUG_ARANGES_SECTION	".debug_aranges"
 #endif
 #ifndef DEBUG_ADDR_SECTION
-#define DEBUG_ADDR_SECTION	".debug_addr"
+#define DEBUG_ADDR_SECTION     ".debug_addr"
 #endif
 #ifndef DEBUG_NORM_MACINFO_SECTION
-#define DEBUG_NORM_MACINFO_SECTION	".debug_macinfo"
+#define DEBUG_NORM_MACINFO_SECTION     ".debug_macinfo"
 #endif
 #ifndef DEBUG_DWO_MACINFO_SECTION
-#define DEBUG_DWO_MACINFO_SECTION	".debug_macinfo.dwo"
+#define DEBUG_DWO_MACINFO_SECTION      ".debug_macinfo.dwo"
 #endif
 #ifndef DEBUG_MACINFO_SECTION
 #define DEBUG_MACINFO_SECTION                                           \
@@ -3615,7 +3639,7 @@ 
 #define DEBUG_NORM_MACRO_SECTION ".debug_macro"
 #endif
 #ifndef DEBUG_DWO_MACRO_SECTION
-#define DEBUG_DWO_MACRO_SECTION	".debug_macro.dwo"
+#define DEBUG_DWO_MACRO_SECTION        ".debug_macro.dwo"
 #endif
 #ifndef DEBUG_MACRO_SECTION
 #define DEBUG_MACRO_SECTION                                             \
@@ -3626,13 +3650,13 @@ 
 #define DEBUG_LINE_SECTION	".debug_line"
 #endif
 #ifndef DEBUG_DWO_LINE_SECTION
-#define DEBUG_DWO_LINE_SECTION	".debug_line.dwo"
+#define DEBUG_DWO_LINE_SECTION ".debug_line.dwo"
 #endif
 #ifndef DEBUG_LOC_SECTION
 #define DEBUG_LOC_SECTION	".debug_loc"
 #endif
 #ifndef DEBUG_DWO_LOC_SECTION
-#define DEBUG_DWO_LOC_SECTION	".debug_loc.dwo"
+#define DEBUG_DWO_LOC_SECTION  ".debug_loc.dwo"
 #endif
 #ifndef DEBUG_PUBNAMES_SECTION
 #define DEBUG_PUBNAMES_SECTION	\
@@ -4419,30 +4443,20 @@ 
 }
 
 /* Return the index for any attribute that will be referenced with a
-   DW_FORM_GNU_addr_index.  Strings have their indices handled differently to
-   account for reference counting pruning.  */
+   DW_FORM_GNU_addr_index or DW_FORM_GNU_str_index.  String indices
+   are stored in dw_attr_val.v.val_str for reference counting
+   pruning.  */
 
 static inline unsigned int
 AT_index (dw_attr_ref a)
 {
   if (AT_class (a) == dw_val_class_str)
     return a->dw_attr_val.v.val_str->index;
-  else
-    return a->dw_attr_val.val_index;
+  else if (a->dw_attr_val.val_entry != NULL)
+    return a->dw_attr_val.val_entry->index;
+  return NOT_INDEXED;
 }
 
-/* Set the index for any attribute that will be referenced with a
-   DW_FORM_GNU_addr_index.  */
-
-static inline void
-set_AT_index (dw_attr_ref a, unsigned int index)
-{
-  if (AT_class (a) == dw_val_class_str)
-    a->dw_attr_val.v.val_str->index = index;
-  else
-    a->dw_attr_val.val_index = index;
-}
-
 /* Add a flag value attribute to a DIE.  */
 
 static inline void
@@ -4452,7 +4466,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_flag;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_flag = flag;
   add_dwarf_attr (die, &attr);
 }
@@ -4473,7 +4487,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_const;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_int = int_val;
   add_dwarf_attr (die, &attr);
 }
@@ -4495,7 +4509,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_unsigned = unsigned_val;
   add_dwarf_attr (die, &attr);
 }
@@ -4517,7 +4531,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_const_double;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_double.high = high;
   attr.dw_attr_val.v.val_double.low = low;
   add_dwarf_attr (die, &attr);
@@ -4533,7 +4547,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_vec;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_vec.length = length;
   attr.dw_attr_val.v.val_vec.elt_size = elt_size;
   attr.dw_attr_val.v.val_vec.array = array;
@@ -4550,38 +4564,48 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_data8;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   memcpy (attr.dw_attr_val.v.val_data8, data8, 8);
   add_dwarf_attr (die, &attr);
 }
 
-/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE.  */
+/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE.  When using
+   dwarf_split_debug_info, address attributes in dies destined for the
+   final executable have force_direct set to avoid using indexed
+   references.  */
+
 static inline void
 add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high,
 		    bool force_direct)
 {
   dw_attr_node attr;
+  char * lbl_id;
 
+  lbl_id = xstrdup (lbl_low);
   attr.dw_attr = DW_AT_low_pc;
   attr.dw_attr_val.val_class = dw_val_class_lbl_id;
-  attr.dw_attr_val.val_index = -1U;
-  attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_low);
+  attr.dw_attr_val.v.val_lbl_id = lbl_id;
+  if (dwarf_split_debug_info && !force_direct)
+    attr.dw_attr_val.val_entry
+        = add_addr_table_entry (lbl_id, ate_kind_label);
+  else
+    attr.dw_attr_val.val_entry = NULL;
   add_dwarf_attr (die, &attr);
-  if (dwarf_split_debug_info && !force_direct)
-    set_AT_index (get_AT (die, DW_AT_low_pc), add_addr_table_entry (&attr));
 
   attr.dw_attr = DW_AT_high_pc;
   if (dwarf_version < 4)
     attr.dw_attr_val.val_class = dw_val_class_lbl_id;
   else
     attr.dw_attr_val.val_class = dw_val_class_high_pc;
-  attr.dw_attr_val.val_index = -1U;
-  attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_high);
-  add_dwarf_attr (die, &attr);
+  lbl_id = xstrdup (lbl_high);
+  attr.dw_attr_val.v.val_lbl_id = lbl_id;
   if (attr.dw_attr_val.val_class == dw_val_class_lbl_id
       && dwarf_split_debug_info && !force_direct)
-    set_AT_index (get_AT (die, DW_AT_high_pc), add_addr_table_entry (&attr));
-
+    attr.dw_attr_val.val_entry
+        = add_addr_table_entry (lbl_id, ate_kind_label);
+  else
+    attr.dw_attr_val.val_entry = NULL;
+  add_dwarf_attr (die, &attr);
 }
 
 /* Hash and equality functions for debug_str_hash.  */
@@ -4638,7 +4662,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_str;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_str = node;
   add_dwarf_attr (die, &attr);
 }
@@ -4650,27 +4674,43 @@ 
   return a->dw_attr_val.v.val_str->str;
 }
 
-/* A vector for a table of strings in the form DW_FORM_GNU_index_str.  */
+/* Call this function directly to bypass AT_string_form's logic to put
+   the string inline in the die. */
 
-typedef struct indirect_string_node indirect_string_node;
-DEF_VEC_O(indirect_string_node);
-DEF_VEC_ALLOC_O(indirect_string_node, gc);
-static GTY (()) VEC (indirect_string_node, gc) *index_string_table;
+static void
+set_indirect_string (struct indirect_string_node *node)
+{
+  char label[32];
+  /* Already indirect is a no op.  */
+  if (node->form == DW_FORM_strp || node->form == DW_FORM_GNU_str_index)
+    {
+      gcc_assert (node->label);
+      return;
+    }
+  ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+  ++dw2_string_counter;
+  node->label = xstrdup (label);
 
+  if (!dwarf_split_debug_info)
+    {
+      node->form = DW_FORM_strp;
+      node->index = NOT_INDEXED;
+    }
+  else
+    {
+      node->form = DW_FORM_GNU_str_index;
+      node->index = NO_INDEX_ASSIGNED;
+    }
+}
+
 /* Find out whether a string should be output inline in DIE
    or out-of-line in .debug_str section.  */
 
 static enum dwarf_form
-AT_string_form (dw_attr_ref a)
+find_string_form (struct indirect_string_node *node)
 {
-  static unsigned int index_string_count = 0;
-  struct indirect_string_node *node;
   unsigned int len;
-  char label[32];
 
-  gcc_assert (a && AT_class (a) == dw_val_class_str);
-
-  node = a->dw_attr_val.v.val_str;
   if (node->form)
     return node->form;
 
@@ -4689,23 +4729,21 @@ 
       && (len - DWARF_OFFSET_SIZE) * node->refcount <= len))
     return node->form = DW_FORM_string;
 
-  ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
-  ++dw2_string_counter;
-  node->label = xstrdup (label);
+  set_indirect_string (node);
 
-  if (!dwarf_split_debug_info)
-    node->form = DW_FORM_strp;
-  else
-    {
-      node->form = DW_FORM_GNU_str_index;
-      set_AT_index (a, index_string_count);
-      index_string_count++;
-      VEC_safe_push (indirect_string_node, gc, index_string_table, node);
-    }
-
   return node->form;
 }
 
+/* Find out whether the string referenced from the attribute should be
+   output inline in DIE or out-of-line in .debug_str section.  */
+
+static enum dwarf_form
+AT_string_form (dw_attr_ref a)
+{
+  gcc_assert (a && AT_class (a) == dw_val_class_str);
+  return find_string_form (a->dw_attr_val.v.val_str);
+}
+
 /* Add a DIE reference attribute value to a DIE.  */
 
 static inline void
@@ -4724,7 +4762,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_die_ref;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_die_ref.die = targ_die;
   attr.dw_attr_val.v.val_die_ref.external = 0;
   add_dwarf_attr (die, &attr);
@@ -4773,7 +4811,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_fde_ref;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_fde_index = targ_fde;
   add_dwarf_attr (die, &attr);
 }
@@ -4787,7 +4825,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_loc;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_loc = loc;
   add_dwarf_attr (die, &attr);
 }
@@ -4806,7 +4844,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_loc_list;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_loc_list = loc_list;
   add_dwarf_attr (die, &attr);
   have_location_lists = true;
@@ -4826,34 +4864,121 @@ 
   return &a->dw_attr_val.v.val_loc_list;
 }
 
-/* A table of entries into the .debug_addr section.  */
+/* Table of entries into the .debug_addr section.  */
 
-static GTY (()) VEC (dw_attr_node,gc) * addr_index_table;
+static GTY ((param_is (addr_table_entry))) htab_t addr_index_table;
 
-static unsigned int
-add_addr_table_entry (dw_attr_node *attr)
+/* Hash an address_table_entry.  */
+
+static hashval_t
+addr_table_entry_do_hash (const void *x)
 {
-  gcc_assert (dwarf_split_debug_info);
+  const addr_table_entry *a = (const addr_table_entry *) x;
+  switch (a->kind)
+    {
+      case ate_kind_rtx:
+        return iterative_hash_rtx (a->addr.rtl, 0);
+      case ate_kind_rtx_dtprel:
+        return iterative_hash_rtx (a->addr.rtl, 1);
+      case ate_kind_label:
+        return htab_hash_string (a->addr.label);
+      default:
+        gcc_unreachable ();
+    }
+}
 
-  VEC_safe_push (dw_attr_node, gc, addr_index_table, attr);
-  return VEC_length (dw_attr_node, addr_index_table) - 1;
+/* Determine equality for two address_table_entries.  */
+
+static int
+addr_table_entry_eq (const void *x1, const void *x2)
+{
+  const addr_table_entry *a1 = (const addr_table_entry *) x1;
+  const addr_table_entry *a2 = (const addr_table_entry *) x2;
+
+  if (a1->kind != a2->kind)
+    return 0;
+  switch (a1->kind)
+    {
+      case ate_kind_rtx:
+      case ate_kind_rtx_dtprel:
+        return rtx_equal_p (a1->addr.rtl, a2->addr.rtl);
+      case ate_kind_label:
+        return strcmp (a1->addr.label, a2->addr.label) == 0;
+      default:
+        gcc_unreachable ();
+    }
 }
 
-/* Remove an entry from the addr table.  Since we have already numbered
-   all the entries, the best we can do here is null it out.  */
+/* Initialize an addr_table_entry.  */
 
-static void
-remove_addr_table_entry (unsigned int i)
+void
+init_addr_table_entry (addr_table_entry *e, enum ate_kind kind, void *addr);
+
+void
+init_addr_table_entry (addr_table_entry *e, enum ate_kind kind, void *addr)
 {
-  dw_attr_node *attr;
+  e->kind = kind;
+  switch (kind)
+    {
+      case ate_kind_rtx:
+      case ate_kind_rtx_dtprel:
+        e->addr.rtl = (rtx) addr;
+        break;
+      case ate_kind_label:
+        e->addr.label = (char *) addr;
+        break;
+    }
+  e->refcount = 0;
+  e->index = NO_INDEX_ASSIGNED;
+}
 
+/* Add attr to the address table entry to the table.  Defer setting an
+   index until output time.  */
+
+static addr_table_entry *
+add_addr_table_entry (void *addr, enum ate_kind kind)
+{
+  addr_table_entry *node;
+  addr_table_entry finder;
+  void **slot;
+
   gcc_assert (dwarf_split_debug_info);
-  gcc_assert (i < VEC_length (dw_attr_node, addr_index_table));
+  if (! addr_index_table)
+    addr_index_table = htab_create_ggc (10, addr_table_entry_do_hash,
+                                        addr_table_entry_eq, NULL);
+  init_addr_table_entry (&finder, kind, addr);
+  slot = htab_find_slot (addr_index_table, &finder, INSERT);
 
-  attr = VEC_index (dw_attr_node, addr_index_table, i);
-  attr->dw_attr = (enum dwarf_attribute) 0;
+  if (*slot == HTAB_EMPTY_ENTRY)
+    {
+      node = ggc_alloc_cleared_addr_table_entry ();
+      init_addr_table_entry (node, kind, addr);
+      *slot = node;
+    }
+  else
+    node = (addr_table_entry *) *slot;
+
+  node->refcount++;
+  return node;
 }
 
+/* Remove an entry from the addr table by decrementing its refcount.
+   Strictly, decrementing the refcount would be enough, but the
+   assertion that the entry is actually in the table has found
+   bugs.  */
+
+static void
+remove_addr_table_entry (addr_table_entry *entry)
+{
+  addr_table_entry *node;
+
+  gcc_assert (dwarf_split_debug_info && addr_index_table);
+  node = (addr_table_entry *) htab_find (addr_index_table, entry);
+  /* After an index is assigned, the table is frozen.  */
+  gcc_assert (node->refcount > 0 && node->index == NO_INDEX_ASSIGNED);
+  node->refcount--;
+}
+
 /* Given a location list, remove all addresses it refers to from the
    address_table.  */
 
@@ -4861,25 +4986,55 @@ 
 remove_loc_list_addr_table_entries (dw_loc_descr_ref descr)
 {
   for (; descr; descr = descr->dw_loc_next)
-    if (descr->dw_loc_oprnd1.val_index != -1U)
-      remove_addr_table_entry (descr->dw_loc_oprnd1.val_index);
+    if (descr->dw_loc_oprnd1.val_entry != NULL)
+      {
+        gcc_assert (descr->dw_loc_oprnd1.val_entry->index == NO_INDEX_ASSIGNED);
+        remove_addr_table_entry (descr->dw_loc_oprnd1.val_entry);
+      }
 }
 
-/* Add an address constant attribute value to a DIE.  */
+/* A helper function for dwarf2out_finish called through
+   htab_traverse.  Assign an addr_table_entry its index.  All entries
+   must be collected into the table when this function is called,
+   because the indexing code relies on htab_traverse to traverse nodes
+   in the same order for each run. */
 
+static int
+index_addr_table_entry (void **h, void *v)
+{
+  addr_table_entry *node = (addr_table_entry *) *h;
+  unsigned int *index = (unsigned int *) v;
+
+  /* Don't index unreferenced nodes.  */
+  if (node->refcount == 0)
+    return 1;
+
+  gcc_assert(node->index == NO_INDEX_ASSIGNED);
+  node->index = *index;
+  *index += 1;
+
+  return 1;
+}
+
+/* Add an address constant attribute value to a DIE.  When using
+   dwarf_split_debug_info, address attributes in dies destined for the
+   final executable should be direct references--setting the parameter
+   force_direct ensures this behavior.  */
+
 static inline void
 add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr,
-	     bool force_direct)
+             bool force_direct)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_addr;
-  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_addr = addr;
+  if (dwarf_split_debug_info && !force_direct)
+    attr.dw_attr_val.val_entry = add_addr_table_entry (addr, ate_kind_rtx);
+  else
+    attr.dw_attr_val.val_entry = NULL;
   add_dwarf_attr (die, &attr);
-  if (dwarf_split_debug_info && !force_direct)
-    set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
 }
 
 /* Get the RTX from to an address DIE attribute.  */
@@ -4901,7 +5056,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_file;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_file = fd;
   add_dwarf_attr (die, &attr);
 }
@@ -4925,7 +5080,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_vms_delta;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1);
   attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2);
   add_dwarf_attr (die, &attr);
@@ -4935,17 +5090,19 @@ 
 
 static inline void
 add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind,
-	       const char *lbl_id, bool force_direct)
+               const char *lbl_id)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_lbl_id;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
+  if (dwarf_split_debug_info)
+    attr.dw_attr_val.val_entry
+        = add_addr_table_entry (attr.dw_attr_val.v.val_lbl_id,
+                                ate_kind_label);
   add_dwarf_attr (die, &attr);
-  if (dwarf_split_debug_info && !force_direct)
-    set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
 }
 
 /* Add a section offset attribute value to a DIE, an offset into the
@@ -4959,7 +5116,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_lineptr;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
   add_dwarf_attr (die, &attr);
 }
@@ -4975,7 +5132,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_macptr;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
   add_dwarf_attr (die, &attr);
 }
@@ -4990,25 +5147,34 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_offset;
-  attr.dw_attr_val.val_index = -1U;
+  attr.dw_attr_val.val_entry = NULL;
   attr.dw_attr_val.v.val_offset = offset;
   add_dwarf_attr (die, &attr);
 }
 
-/* Add a range_list attribute value to a DIE.  */
+/* Add a range_list attribute value to a DIE.  When using
+   dwarf_split_debug_info, address attributes in dies destined for the
+   final executable should be direct references--setting the parameter
+   force_direct ensures this behavior.  */
 
+#define UNRELOCATED_OFFSET ((addr_table_entry *) 1)
+#define RELOCATED_OFFSET (NULL)
+
 static void
 add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
-		   long unsigned int offset, bool force_direct)
+                   long unsigned int offset, bool force_direct)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_range_list;
-  /* This is a bit of a misnomer--the offset isn't an index, but we need to
-     save force_direct for output.  */
-  attr.dw_attr_val.val_index
-      = (dwarf_split_debug_info && !force_direct) ? offset : -1U;
+  /* For the range_list attribute, use val_entry to store whether the
+     offset should follow split-debug-info or normal semantics.  This
+     value is read in output_range_list_offset.  */
+  if (dwarf_split_debug_info && !force_direct)
+    attr.dw_attr_val.val_entry = UNRELOCATED_OFFSET;
+  else
+    attr.dw_attr_val.val_entry = RELOCATED_OFFSET;
   attr.dw_attr_val.v.val_offset = offset;
   add_dwarf_attr (die, &attr);
 }
@@ -8055,8 +8221,11 @@ 
       switch (AT_class (a))
 	{
 	case dw_val_class_addr:
-          if (dwarf_split_debug_info && AT_index (a) != -1U)
-            size += size_of_uleb128 (AT_index (a));
+          if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED)
+            {
+              gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED);
+              size += size_of_uleb128 (AT_index (a));
+            }
           else
             size += DWARF2_ADDR_SIZE;
 	  break;
@@ -8076,8 +8245,11 @@ 
 	  }
 	  break;
 	case dw_val_class_loc_list:
-          if (dwarf_split_debug_info && AT_index (a) != -1U)
-            size += size_of_uleb128 (AT_index (a));
+          if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED)
+            {
+              gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED);
+              size += size_of_uleb128 (AT_index (a));
+            }
           else
             size += DWARF_OFFSET_SIZE;
 	  break;
@@ -8142,8 +8314,11 @@ 
 	  size += DWARF_OFFSET_SIZE;
 	  break;
 	case dw_val_class_lbl_id:
-          if (dwarf_split_debug_info && AT_index (a) != -1U)
-            size += size_of_uleb128 (AT_index (a));
+          if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED)
+            {
+              gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED);
+              size += size_of_uleb128 (AT_index (a));
+            }
           else
             size += DWARF2_ADDR_SIZE;
 	  break;
@@ -8155,7 +8330,7 @@ 
           form = AT_string_form (a);
           if (form == DW_FORM_strp)
 	    size += DWARF_OFFSET_SIZE;
-	  else if (form == DW_FORM_GNU_str_index)
+         else if (form == DW_FORM_GNU_str_index)
             size += size_of_uleb128 (AT_index (a));
 	  else
 	    size += strlen (a->dw_attr_val.v.val_str->str) + 1;
@@ -8361,8 +8536,8 @@ 
 	case DW_AT_high_pc:
 	case DW_AT_entry_pc:
 	case DW_AT_trampoline:
-          return (dwarf_split_debug_info && AT_index (a) != -1U
-		  ? DW_FORM_GNU_addr_index : DW_FORM_addr);
+          return (AT_index (a) == NOT_INDEXED
+                  ? DW_FORM_addr : DW_FORM_GNU_addr_index);
 	default:
 	  break;
 	}
@@ -8480,8 +8655,8 @@ 
     case dw_val_class_fde_ref:
       return DW_FORM_data;
     case dw_val_class_lbl_id:
-      return (dwarf_split_debug_info && AT_index (a) != -1U
-	      ? DW_FORM_GNU_addr_index : DW_FORM_addr);
+      return (AT_index (a) == NOT_INDEXED
+              ? DW_FORM_addr : DW_FORM_GNU_addr_index);
     case dw_val_class_lineptr:
     case dw_val_class_macptr:
       return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
@@ -8603,7 +8778,7 @@ 
   dw_loc_list_ref retlist = ggc_alloc_cleared_dw_loc_list_node ();
 
   retlist->begin = begin;
-  retlist->begin_index = -1U;
+  retlist->begin_entry = NULL;
   retlist->end = end;
   retlist->expr = expr;
   retlist->section = section;
@@ -8653,7 +8828,7 @@ 
           dw2_asm_output_data (1, DW_LLE_start_length_entry,
                                "Location list start/length entry (%s)",
                                list_head->ll_symbol);
-          dw2_asm_output_data_uleb128 (curr->begin_index,
+          dw2_asm_output_data_uleb128 (curr->begin_entry->index,
                                        "Location list range start index (%s)",
                                        curr->begin);
           /* The length field is 4 bytes.  If we ever need to support
@@ -8704,14 +8879,16 @@ 
     }
 }
 
-/* Output the offset into the debug_range section.  */
+/* Output a range_list offset into the debug_range section.  Emit a
+   relocated reference if val_entry is NULL, otherwise, emit an
+   indirect reference.  */
 
 static void
 output_range_list_offset (dw_attr_ref a)
 {
   const char *name = dwarf_attr_name (a->dw_attr);
 
-  if (!dwarf_split_debug_info || AT_index (a) == -1U)
+  if (a->dw_attr_val.val_entry == RELOCATED_OFFSET)
     {
       char *p = strchr (ranges_section_label, '\0');
       sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, a->dw_attr_val.v.val_offset);
@@ -8747,7 +8924,7 @@ 
 {
   const char *name = dwarf_attr_name (a->dw_attr);
 
-  if (dwarf_split_debug_info && AT_index (a) != -1U)
+  if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED)
     {
       dw2_asm_output_data_uleb128 (AT_index (a), "%s", name);
       return;
@@ -8757,6 +8934,7 @@ 
       case dw_val_class_addr:
         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
         break;
+      case dw_val_class_high_pc:
       case dw_val_class_lbl_id:
         dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
         break;
@@ -8989,12 +9167,12 @@ 
 	  break;
 
 	case dw_val_class_str:
-	  if (a->dw_attr_val.v.val_str->form == DW_FORM_strp)
-	    dw2_asm_output_offset (DWARF_OFFSET_SIZE,
-				   a->dw_attr_val.v.val_str->label,
-				   debug_str_section,
-				   "%s: \"%s\"", name, AT_string (a));
-	  else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index)
+          if (a->dw_attr_val.v.val_str->form == DW_FORM_strp)
+            dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+                                   a->dw_attr_val.v.val_str->label,
+                                   debug_str_section,
+                                   "%s: \"%s\"", name, AT_string (a));
+          else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index)
             dw2_asm_output_data_uleb128 (AT_index (a),
                                          "%s: \"%s\"", name, AT_string (a));
           else
@@ -9170,9 +9348,9 @@ 
 static dw_die_ref
 get_skeleton_type_unit (void)
 {
-  /* For split_debug_sections with use_type info, all type units int the
-     skeleton sections have identical dies (but different headers).  This single
-     die will be output many times.  */
+  /* For dwarf_split_debug_sections with use_type info, all type units in the
+     skeleton sections have identical dies (but different headers).  This
+     single die will be output many times.  */
 
   static dw_die_ref skeleton_type_unit = NULL;
 
@@ -9218,7 +9396,7 @@ 
 			 "Offset Into Abbrev. Section");
   dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
 
-  comp_unit->die_abbrev = 1;
+  comp_unit->die_abbrev = SKELETON_COMP_DIE_ABBREV;
   output_die (comp_unit);
 
   /* Build the skeleton debug_abbrev section.  */
@@ -9286,6 +9464,7 @@ 
 
   unmark_dies (node->root_die);
 
+#if defined (OBJECT_FORMAT_ELF)
   if (dwarf_split_debug_info)
     {
       /* Produce the skeleton type-unit header.  */
@@ -9298,7 +9477,6 @@ 
         dw2_asm_output_data (4, 0xffffffff,
           "Initial length escape value indicating 64-bit DWARF extension");
 
-      /* One for the terminating NULL byte.  */
       dw2_asm_output_data (DWARF_OFFSET_SIZE,
                            DWARF_COMPILE_UNIT_HEADER_SIZE
                            - DWARF_INITIAL_LENGTH_SIZE
@@ -9316,6 +9494,7 @@ 
 
       output_die (get_skeleton_type_unit ());
     }
+#endif
 }
 
 /* Return the DWARF2/3 pubname associated with a decl.  */
@@ -9699,8 +9878,10 @@ 
   return add_ranges_num (block ? BLOCK_NUMBER (block) : 0);
 }
 
-/* Add a new entry to .debug_ranges corresponding to a pair of
-   labels.  */
+/* Add a new entry to .debug_ranges corresponding to a pair of labels.
+   When using dwarf_split_debug_info, address attributes in dies destined
+   for the final executable should be direct references--setting the
+   parameter force_direct ensures this behavior.  */
 
 static void
 add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
@@ -12649,7 +12830,7 @@ 
 	  if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
 	    break;
 
-          temp = new_addr_loc_descr (rtl, true);
+          temp = new_addr_loc_descr (rtl, dtprel_true);
 
 	  mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
 	  add_loc_descr (&mem_loc_result, temp);
@@ -12661,7 +12842,7 @@ 
 	break;
 
     symref:
-      mem_loc_result = new_addr_loc_descr (rtl, 0);
+      mem_loc_result = new_addr_loc_descr (rtl, dtprel_false);
       VEC_safe_push (rtx, gc, used_rtx_array, rtl);
       break;
 
@@ -13563,7 +13744,7 @@ 
       if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
 	  && (dwarf_version >= 4 || !dwarf_strict))
 	{
-	  loc_result = new_addr_loc_descr (rtl, 0);
+         loc_result = new_addr_loc_descr (rtl, dtprel_false);
 	  add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
 	  VEC_safe_push (rtx, gc, used_rtx_array, rtl);
 	}
@@ -14264,8 +14445,8 @@ 
       if (DECL_THREAD_LOCAL_P (loc))
 	{
 	  rtx rtl;
-	  enum dwarf_location_atom tls_op;
-	  bool dtprel = false;
+         enum dwarf_location_atom tls_op;
+         enum dtprel_bool dtprel = dtprel_false;
 
 	  if (targetm.have_tls)
 	    {
@@ -14282,8 +14463,8 @@ 
 		  operand shouldn't be.  */
 	      if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
 		return 0;
-	      dtprel = true;
-	      tls_op = DW_OP_GNU_push_tls_address;
+             dtprel = dtprel_true;
+             tls_op = DW_OP_GNU_push_tls_address;
 	    }
 	  else
 	    {
@@ -14309,7 +14490,7 @@ 
 	    return 0;
 
           ret = new_addr_loc_descr (rtl, dtprel);
-	  ret1 = new_loc_descr (tls_op, 0, 0);
+          ret1 = new_loc_descr (tls_op, 0, 0);
 	  add_loc_descr (&ret, ret1);
 
 	  have_address = 1;
@@ -14354,7 +14535,7 @@ 
 	    return 0;
 	  }
 	else if (CONSTANT_P (rtl) && const_ok_for_output (rtl))
-          ret = new_addr_loc_descr (rtl, 0);
+          ret = new_addr_loc_descr (rtl, dtprel_false);
 	else
 	  {
 	    enum machine_mode mode, mem_mode;
@@ -15292,7 +15473,7 @@ 
 	  dw_loc_descr_ref loc_result;
 	  resolve_one_addr (&rtl, NULL);
 	rtl_addr:
-	  loc_result = new_addr_loc_descr (rtl, 0);
+          loc_result = new_addr_loc_descr (rtl, dtprel_false);
 	  add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
 	  add_AT_loc (die, DW_AT_location, loc_result);
 	  VEC_safe_push (rtx, gc, used_rtx_array, rtl);
@@ -16822,7 +17003,7 @@ 
   add_name_attribute (die, VMS_DEBUG_MAIN_POINTER);
   ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL,
 			       FUNC_LABEL_ID (cfun));
-  add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
+  add_AT_lbl_id (die, DW_AT_entry_pc, label);
 
   /* Make it the first child of comp_unit_die ().  */
   die->die_parent = comp_unit_die ();
@@ -17436,7 +17617,7 @@ 
   if (DECL_ABSTRACT (decl))
     equate_decl_number_to_die (decl, decl_die);
   else
-    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl), false);
+    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
 }
 #endif
 
@@ -17957,7 +18138,7 @@ 
   if (stmt_die == NULL)
     stmt_die = subr_die;
   die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE);
-  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label, false);
+  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label);
   if (ca_loc->tail_call_p)
     add_AT_flag (die, DW_AT_GNU_tail_call, 1);
   if (ca_loc->symbol_ref)
@@ -17966,7 +18147,7 @@ 
       if (tdie)
 	add_AT_die_ref (die, DW_AT_abstract_origin, tdie);
       else
-	add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref, false);
+        add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref, false);
     }
   return die;
 }
@@ -18896,7 +19077,7 @@ 
 	  gcc_assert (!INSN_DELETED_P (insn));
 
 	  ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
-	  add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
+          add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
 	}
       else if (insn
 	       && NOTE_P (insn)
@@ -18904,7 +19085,7 @@ 
 	       && CODE_LABEL_NUMBER (insn) != -1)
 	{
 	  ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER (insn));
-	  add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
+          add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
 	}
     }
 }
@@ -18943,7 +19124,7 @@ 
 	{
 	  ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
 				       BLOCK_NUMBER (stmt));
-	  add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
+	  add_AT_lbl_id (die, DW_AT_entry_pc, label);
 	}
 
       add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt), false);
@@ -21612,24 +21793,22 @@ 
     case DW_MACRO_GNU_define_indirect:
     case DW_MACRO_GNU_undef_indirect:
       node = find_AT_string (ref->info);
-      /* FIXME: needs to change for dwarf_split_debug_info.  */
-      if (node->form != DW_FORM_strp)
-	{
-	  char label[32];
-	  ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
-	  ++dw2_string_counter;
-	  node->label = xstrdup (label);
-	  node->form = DW_FORM_strp;
-	}
+      gcc_assert (node
+                  && ((node->form == DW_FORM_strp)
+                      || (node->form == DW_FORM_GNU_str_index)));
       dw2_asm_output_data (1, ref->code,
 			   ref->code == DW_MACRO_GNU_define_indirect
 			   ? "Define macro indirect"
 			   : "Undefine macro indirect");
       dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
 				   (unsigned long) ref->lineno);
-      dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
-			     debug_str_section, "The macro: \"%s\"",
-			     ref->info);
+      if (node->form == DW_FORM_strp)
+        dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+                               debug_str_section, "The macro: \"%s\"",
+                               ref->info);
+      else
+        dw2_asm_output_data_uleb128 (node->index, "The macro: \"%s\"",
+                                     ref->info);
       break;
     case DW_MACRO_GNU_transparent_include:
       dw2_asm_output_data (1, ref->code, "Transparent include");
@@ -21772,6 +21951,42 @@ 
   return count;
 }
 
+/* Save any strings needed by the macinfo table in the debug str
+   table.  All strings must be collected into the table by the time
+   index_string is called.  */
+
+static void
+save_macinfo_strings (void)
+{
+  unsigned len;
+  unsigned i;
+  macinfo_entry *ref;
+
+  for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++)
+    {
+      switch (ref->code)
+        {
+          /* Match the logic in output_macinfo_op to decide on
+             indirect strings.  */
+          case DW_MACINFO_define:
+          case DW_MACINFO_undef:
+            len = strlen (ref->info) + 1;
+            if (!dwarf_strict
+                && len > DWARF_OFFSET_SIZE
+                && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
+                && (debug_str_section->common.flags & SECTION_MERGE) != 0)
+              set_indirect_string (find_AT_string (ref->info));
+            break;
+          case DW_MACRO_GNU_define_indirect:
+          case DW_MACRO_GNU_undef_indirect:
+            set_indirect_string (find_AT_string (ref->info));
+            break;
+          default:
+            break;
+        }
+    }
+}
+
 /* Output macinfo section(s).  */
 
 static void
@@ -21965,7 +22180,7 @@ 
       debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
                                                    SECTION_DEBUG, NULL);
       ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
-				   DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0);
+                                  DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0);
 
       /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
          the main .o, but the skeleton_line goes into the split off dwo.  */
@@ -21987,7 +22202,7 @@ 
   debug_macinfo_section = get_section (dwarf_strict
 				       ? DEBUG_MACINFO_SECTION
 				       : DEBUG_MACRO_SECTION,
-				       DEBUG_MACRO_SECTION_FLAGS, NULL);
+                                       DEBUG_MACRO_SECTION_FLAGS, NULL);
   debug_line_section = get_section (DEBUG_LINE_SECTION,
 				    SECTION_DEBUG, NULL);
   debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
@@ -21995,7 +22210,7 @@ 
   debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
 					SECTION_DEBUG, NULL);
   debug_str_section = get_section (DEBUG_STR_SECTION,
-                                   DEBUG_STR_SECTION_FLAGS, NULL);
+				   DEBUG_STR_SECTION_FLAGS, NULL);
   debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
 				      SECTION_DEBUG, NULL);
   debug_frame_section = get_section (DEBUG_FRAME_SECTION,
@@ -22020,7 +22235,7 @@ 
   ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
 			       DEBUG_RANGES_SECTION_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
-			       DEBUG_ADDR_SECTION_LABEL, 0);
+                               DEBUG_ADDR_SECTION_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
 			       dwarf_strict
 			       ? DEBUG_MACINFO_SECTION_LABEL
@@ -22052,6 +22267,71 @@ 
 }
 
 /* A helper function for dwarf2out_finish called through
+   htab_traverse.  Assign a string its index.  All strings must be
+   collected into the table by the time index_string is called,
+   because the indexing code relies on htab_traverse to traverse nodes
+   in the same order for each run. */
+
+static int
+index_string (void **h, void *v)
+{
+  struct indirect_string_node *node = (struct indirect_string_node *) *h;
+  unsigned int *index = (unsigned int *) v;
+
+  find_string_form (node);
+  if (node->form == DW_FORM_GNU_str_index && node->refcount > 0)
+    {
+      gcc_assert(node->index == NO_INDEX_ASSIGNED);
+      node->index = *index;
+      *index += 1;
+    }
+  return 1;
+}
+
+/* A helper function for output_indirect_strings called through
+   htab_traverse.  Output the offset to a string and update the
+   current offset.  */
+
+static int
+output_index_string_offset (void **h, void *v)
+{
+  struct indirect_string_node *node = (struct indirect_string_node *) *h;
+  unsigned int *offset = (unsigned int *) v;
+
+  if (node->form == DW_FORM_GNU_str_index && node->refcount > 0)
+    {
+      /* Assert that this node has been assigned an index.  */
+      gcc_assert (node->index != NO_INDEX_ASSIGNED
+                  && node->index != NOT_INDEXED);
+      dw2_asm_output_data (DWARF_OFFSET_SIZE, *offset,
+                           "indexed string 0x%x: %s", node->index, node->str);
+      *offset += strlen (node->str) + 1;
+    }
+  return 1;
+}
+
+/* A helper function for dwarf2out_finish called through
+   htab_traverse.  Output the indexed string.  */
+
+static int
+output_index_string (void **h, void *v)
+{
+  struct indirect_string_node *node = (struct indirect_string_node *) *h;
+  unsigned int *cur_idx = (unsigned int *) v;
+
+  if (node->form == DW_FORM_GNU_str_index && node->refcount > 0)
+    {
+      /* Assert that the strings are output in the same order as their
+         indexes were assigned.  */
+      gcc_assert (*cur_idx == node->index);
+      ASM_OUTPUT_LABEL (asm_out_file, node->label);
+      assemble_string (node->str, strlen (node->str) + 1);
+      *cur_idx += 1;
+    }
+  return 1;
+}
+
+/* A helper function for dwarf2out_finish called through
    htab_traverse.  Emit one queued .debug_str string.  */
 
 static int
@@ -22059,9 +22339,8 @@ 
 {
   struct indirect_string_node *node = (struct indirect_string_node *) *h;
 
-  if (node->form == DW_FORM_strp)
+  if (node->form == DW_FORM_strp && node->refcount > 0)
     {
-      switch_to_section (debug_str_section);
       ASM_OUTPUT_LABEL (asm_out_file, node->label);
       assemble_string (node->str, strlen (node->str) + 1);
     }
@@ -22069,77 +22348,85 @@ 
   return 1;
 }
 
+/* Output the indexed string table.  */
+
 static void
-output_index_strings (void)
+output_indirect_strings (void)
 {
-  unsigned int i;
-  unsigned int len = 0;
-  struct indirect_string_node *node;
+  if (!dwarf_split_debug_info)
+    {
+      switch_to_section (debug_str_section);
+      htab_traverse (debug_str_hash, output_indirect_string, NULL);
+    }
+  else
+    {
+      unsigned int offset = 0;
+      unsigned int cur_idx = 0;
 
-  if (VEC_empty (indirect_string_node, index_string_table))
-    return;
+      switch_to_section (debug_str_offsets_section);
+      htab_traverse_noresize (debug_str_hash,
+                              output_index_string_offset,
+                              &offset);
+      switch_to_section (debug_str_section);
+      htab_traverse_noresize (debug_str_hash,
+                              output_index_string,
+                              &cur_idx);
+    }
+}
 
-  switch_to_section (debug_str_offsets_section);
-  for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
-       i++)
+/* Callback for htab_traverse to assign an index to an entry in the
+   table, and to write that entry to the .debug_addr section.  */
+
+static int
+output_addr_table_entry (void **slot, void *data)
+{
+  addr_table_entry *entry = (addr_table_entry *) *slot;
+  unsigned int *cur_index = (unsigned int *)data;
+
+  if (entry->refcount == 0)
     {
-      gcc_assert (node->form == DW_FORM_GNU_str_index);
-      dw2_asm_output_data (DWARF_OFFSET_SIZE, len,
-                           "indexed string 0x%x: %s", i, node->str);
-      len += strlen (node->str) + 1;
+      gcc_assert (entry->index == NO_INDEX_ASSIGNED
+                  || entry->index == NOT_INDEXED);
+      return 1;
     }
-  switch_to_section (debug_str_section);
-  for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
-       i++)
+
+  gcc_assert (entry->index == *cur_index);
+  (*cur_index)++;
+
+  switch (entry->kind)
     {
-      ASM_OUTPUT_LABEL (asm_out_file, node->label);
-      assemble_string (node->str, strlen (node->str) + 1);
+      case ate_kind_rtx:
+        dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, entry->addr.rtl,
+                                 "0x%x", entry->index);
+        break;
+      case ate_kind_rtx_dtprel:
+        gcc_assert (targetm.asm_out.output_dwarf_dtprel);
+        targetm.asm_out.output_dwarf_dtprel (asm_out_file,
+                                             DWARF2_ADDR_SIZE,
+                                             entry->addr.rtl);
+        fputc ('\n', asm_out_file);
+        break;
+      case ate_kind_label:
+        dw2_asm_output_addr (DWARF2_ADDR_SIZE, entry->addr.label,
+                                 "0x%x", entry->index);
+        break;
+      default:
+        gcc_unreachable ();
     }
+  return 1;
 }
 
-/* Write the index table.  */
+/* Produce the .debug_addr section.  */
 
 static void
 output_addr_table (void)
 {
-  unsigned int i;
-  dw_attr_node *node;
-
-  if (VEC_empty (dw_attr_node, addr_index_table))
+  unsigned int index = 0;
+  if (addr_index_table == NULL || htab_size (addr_index_table) == 0)
     return;
 
   switch_to_section (debug_addr_section);
-  for (i = 0; VEC_iterate (dw_attr_node, addr_index_table, i, node); i++)
-    {
-      const char *name;
-
-      if (node->dw_attr == 0)
-	{
-	  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, "<Removed entry>");
-	  continue;
-	}
-
-      name = dwarf_attr_name (node->dw_attr);
-      switch (AT_class (node))
-        {
-          case dw_val_class_addr:
-            dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (node),
-                                     "%s", name);
-            break;
-          case dw_val_class_loc:
-            gcc_assert (targetm.asm_out.output_dwarf_dtprel);
-            targetm.asm_out.output_dwarf_dtprel (asm_out_file,
-                                                 DWARF2_ADDR_SIZE,
-                                                 node->dw_attr_val.v.val_addr);
-            fputc ('\n', asm_out_file);
-            break;
-          case dw_val_class_lbl_id:
-            dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (node), "%s", name);
-            break;
-          default:
-            gcc_unreachable ();
-        }
-    }
+  htab_traverse_noresize (addr_index_table, output_addr_table_entry, &index);
 }
 
 #if ENABLE_ASSERT_CHECKING
@@ -22749,11 +23036,10 @@ 
       case DW_OP_GNU_addr_index:
       case DW_OP_GNU_const_index:
         {
-          unsigned int idx = loc->dw_loc_oprnd1.val_index;
-          dw_attr_node *node = VEC_index (dw_attr_node, addr_index_table, idx);
           if ((loc->dw_loc_opc == DW_OP_GNU_addr_index
                || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel))
-              && resolve_one_addr (&node->dw_attr_val.v.val_addr, NULL))
+              && resolve_one_addr (&loc->dw_loc_oprnd1.val_entry->addr.rtl,
+                                   NULL))
             return false;
         }
 	break;
@@ -22898,8 +23184,8 @@ 
 			gcc_assert (!next->ll_symbol);
 			next->ll_symbol = (*curr)->ll_symbol;
 		      }
-		    if (dwarf_split_debug_info)
-		      remove_loc_list_addr_table_entries (l);
+                    if (dwarf_split_debug_info)
+                      remove_loc_list_addr_table_entries (l);
 		    *curr = next;
 		  }
 		else
@@ -22939,8 +23225,8 @@ 
 	       || l->dw_loc_next != NULL)
 	      && !resolve_addr_in_expr (l))
 	    {
-	      if (dwarf_split_debug_info)
-		remove_loc_list_addr_table_entries (l);
+              if (dwarf_split_debug_info)
+                remove_loc_list_addr_table_entries (l);
 	      remove_AT (die, a->dw_attr);
 	      ix--;
 	    }
@@ -22952,8 +23238,8 @@ 
 	if (a->dw_attr == DW_AT_const_value
 	    && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL))
 	  {
-	    if (AT_index (a) != -1U)
-	      remove_addr_table_entry (AT_index (a));
+            if (AT_index (a) != NOT_INDEXED)
+              remove_addr_table_entry (a->dw_attr_val.val_entry);
 	    remove_AT (die, a->dw_attr);
 	    ix--;
 	  }
@@ -22977,8 +23263,8 @@ 
 	      }
 	    else
 	      {
-		if (AT_index (a) != -1U)
-		  remove_addr_table_entry (AT_index (a));
+                if (AT_index (a) != NOT_INDEXED)
+                  remove_addr_table_entry (a->dw_attr_val.val_entry);
 		remove_AT (die, a->dw_attr);
 		ix--;
 	      }
@@ -23115,14 +23401,12 @@ 
     case DW_OP_GNU_addr_index:
     case DW_OP_GNU_const_index:
       {
-        dw_attr_ref attr = VEC_index (dw_attr_node, addr_index_table,
-                                      val1->val_index);
         if (loc->dtprel)
-	  {
+          {
             unsigned char dtprel = 0xd1;
             hash = iterative_hash_object (dtprel, hash);
           }
-        hash = iterative_hash_rtx (attr->dw_attr_val.v.val_addr, hash);
+        hash = iterative_hash_rtx (val1->val_entry->addr.rtl, hash);
       }
       break;
     case DW_OP_GNU_implicit_pointer:
@@ -23310,8 +23594,8 @@ 
 	 can cause irrelevant differences in dw_loc_addr.  */
       gcc_assert (valx1->val_class == dw_val_class_loc
 		  && valy1->val_class == dw_val_class_loc
-		  && (dwarf_split_debug_info
-		      || x->dw_loc_addr == y->dw_loc_addr));
+                  && (dwarf_split_debug_info
+                      || x->dw_loc_addr == y->dw_loc_addr));
       return valx1->v.val_loc->dw_loc_addr == valy1->v.val_loc->dw_loc_addr;
     case DW_OP_implicit_value:
       if (valx1->v.val_unsigned != valy1->v.val_unsigned
@@ -23345,14 +23629,9 @@ 
     case DW_OP_GNU_addr_index:
     case DW_OP_GNU_const_index:
       {
-        dw_attr_node *attrx1 = VEC_index (dw_attr_node,
-                                          addr_index_table,
-                                          valx1->val_index);
-        dw_attr_node *attry1 = VEC_index (dw_attr_node,
-                                          addr_index_table,
-                                          valy1->val_index);
-        return rtx_equal_p (attrx1->dw_attr_val.v.val_addr,
-                            attry1->dw_attr_val.v.val_addr);
+        rtx ax1 = valx1->val_entry->addr.rtl;
+        rtx ay1 = valy1->val_entry->addr.rtl;
+        return rtx_equal_p (ax1, ay1);
       }
     case DW_OP_GNU_implicit_pointer:
       return valx1->val_class == dw_val_class_die_ref
@@ -23502,19 +23781,15 @@ 
         dw_loc_list_ref curr;
         for (curr = list; curr != NULL; curr = curr->dw_loc_next)
           {
-            dw_attr_node attr;
-
             /* Don't index an entry that has already been indexed
-	       or won't be output.  */
-            if (curr->begin_index != -1U
-	        || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
-	      continue;
+               or won't be output.  */
+            if (curr->begin_entry != NULL
+                || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
+              continue;
 
-            attr.dw_attr = DW_AT_location;
-            attr.dw_attr_val.val_class = dw_val_class_lbl_id;
-            attr.dw_attr_val.val_index = -1U;
-            attr.dw_attr_val.v.val_lbl_id = xstrdup (curr->begin);
-            curr->begin_index = add_addr_table_entry (&attr);
+            curr->begin_entry
+                = add_addr_table_entry (xstrdup (curr->begin),
+                                        ate_kind_label);
           }
       }
 
@@ -23760,11 +24035,26 @@ 
 		   dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
 		   macinfo_section_label);
 
+  if (dwarf_split_debug_info && addr_index_table != NULL)
+    {
+      /* optimize_location_lists calculates the size of the lists,
+         so index them first, and assign indices to the entries.
+         Although optimize_location_lists will remove entries from
+         the table, it only does so for duplicates, and therefore
+         only reduces ref_counts to 1.  */
+      unsigned int index = 0;
+      index_location_lists (comp_unit_die ());
+      htab_traverse_noresize (addr_index_table,
+                              index_addr_table_entry, &index);
+    }
   if (have_location_lists)
+    optimize_location_lists (comp_unit_die ());
+
+  save_macinfo_strings ();
+  if (dwarf_split_debug_info)
     {
-      optimize_location_lists (comp_unit_die ());
-      if (dwarf_split_debug_info)
-        index_location_lists (comp_unit_die ());
+      unsigned int index = 0;
+      htab_traverse_noresize (debug_str_hash, index_string, &index);
     }
 
   /* Output all of the compilation units.  We put the main one last so that
@@ -23795,6 +24085,10 @@ 
     }
   htab_delete (comdat_type_table);
 
+  /* The AT_pubnames attribute needs to go in all skeleton dies, including
+     both the main_cu and all skeleton TUs.  Making this call unconditional
+     would end up either adding a second copy of the AT_pubnames attribute, or
+     requiring a special case in add_top_level_skeleton_die_attrs.  */
   if (!dwarf_split_debug_info)
     add_AT_pubnames (comp_unit_die ());
 
@@ -23819,8 +24113,12 @@ 
       /* Add the base offset of the ranges table to the skeleton
 	 comp-unit DIE.  */
       if (ranges_table_in_use)
-	add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base,
-			ranges_section_label);
+        add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base,
+                        ranges_section_label);
+
+      switch_to_section (debug_addr_section);
+      ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label);
+      output_addr_table ();
     }
 
   /* Output the main compilation unit if non-empty or if .debug_macinfo
@@ -23895,17 +24193,11 @@ 
       switch_to_section (debug_skeleton_line_section);
       ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
       output_line_info (true);
-
-      output_index_strings ();
-
-      switch_to_section (debug_addr_section);
-      ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label);
-      output_addr_table ();
     }
 
   /* If we emitted any indirect strings, output the string table too.  */
   if (debug_str_hash)
-    htab_traverse (debug_str_hash, output_indirect_string, NULL);
+    output_indirect_strings ();
 }
 
 #include "gt-dwarf2out.h"
Index: gcc/dwarf2out.h
===================================================================
--- gcc/dwarf2out.h	(revision 193909)
+++ gcc/dwarf2out.h	(working copy)
@@ -167,12 +167,14 @@ 
 }
 dw_vec_const;
 
+struct addr_table_entry_struct;
+
 /* The dw_val_node describes an attribute's value, as it is
    represented internally.  */
 
 typedef struct GTY(()) dw_val_struct {
   enum dw_val_class val_class;
-  unsigned int val_index;
+  struct addr_table_entry_struct * GTY(()) val_entry;
   union dw_val_struct_union
     {
       rtx GTY ((tag ("dw_val_class_addr"))) val_addr;