OSDN Git Service

2010-01-14 Alexander Monakov <amonakov@ispras.ru>
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index c621162..02c0afd 100644 (file)
@@ -89,6 +89,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "hashtab.h"
 #include "cgraph.h"
 #include "input.h"
+#include "gimple.h"
+#include "tree-pass.h"
 
 #ifdef DWARF2_DEBUGGING_INFO
 static void dwarf2out_source_line (unsigned int, const char *, int, bool);
@@ -96,6 +98,22 @@ static void dwarf2out_source_line (unsigned int, const char *, int, bool);
 static rtx last_var_location_insn;
 #endif
 
+#ifdef VMS_DEBUGGING_INFO
+int vms_file_stats_name (const char *, long long *, long *, char *, int *);
+
+/* Define this macro to be a nonzero value if the directory specifications
+    which are output in the debug info should end with a separator.  */
+#define DWARF2_DIR_SHOULD_END_WITH_SEPARATOR 1
+/* Define this macro to evaluate to a nonzero value if GCC should refrain
+   from generating indirect strings in DWARF2 debug information, for instance
+   if your target is stuck with an old version of GDB that is unable to
+   process them properly or uses VMS Debug.  */
+#define DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET 1
+#else
+#define DWARF2_DIR_SHOULD_END_WITH_SEPARATOR 0
+#define DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET 0
+#endif
+
 #ifndef DWARF2_FRAME_INFO
 # ifdef DWARF2_DEBUGGING_INFO
 #  define DWARF2_FRAME_INFO \
@@ -147,7 +165,7 @@ dwarf2out_do_cfi_asm (void)
 #endif
   if (!flag_dwarf2_cfi_asm || !dwarf2out_do_frame ())
     return false;
-  if (saved_do_cfi_asm || !eh_personality_libfunc)
+  if (saved_do_cfi_asm)
     return true;
   if (!HAVE_GAS_CFI_PERSONALITY_DIRECTIVE)
     return false;
@@ -161,6 +179,16 @@ dwarf2out_do_cfi_asm (void)
   if ((enc & 0x70) != 0 && (enc & 0x70) != DW_EH_PE_pcrel)
     return false;
 
+  if (!HAVE_GAS_CFI_SECTIONS_DIRECTIVE)
+    {
+#ifdef TARGET_UNWIND_INFO
+      return false;
+#else
+      if (USING_SJLJ_EXCEPTIONS || (!flag_unwind_tables && !flag_exceptions))
+       return false;
+#endif
+    }
+
   saved_do_cfi_asm = true;
   return true;
 }
@@ -196,10 +224,16 @@ static GTY(()) section *debug_line_section;
 static GTY(()) section *debug_loc_section;
 static GTY(()) section *debug_pubnames_section;
 static GTY(()) section *debug_pubtypes_section;
+static GTY(()) section *debug_dcall_section;
+static GTY(()) section *debug_vcall_section;
 static GTY(()) section *debug_str_section;
 static GTY(()) section *debug_ranges_section;
 static GTY(()) section *debug_frame_section;
 
+/* Personality decl of current unit.  Used only when assembler does not support
+   personality CFI.  */
+static GTY(()) rtx current_unit_personality;
+
 /* How to start an assembler comment.  */
 #ifndef ASM_COMMENT_START
 #define ASM_COMMENT_START ";#"
@@ -316,6 +350,12 @@ dw_fde_node;
 #define DWARF_OFFSET_SIZE 4
 #endif
 
+/* The size in bytes of a DWARF 4 type signature.  */
+
+#ifndef DWARF_TYPE_SIGNATURE_SIZE
+#define DWARF_TYPE_SIGNATURE_SIZE 8
+#endif
+
 /* According to the (draft) DWARF 3 specification, the initial length
    should either be 4 or 12 bytes.  When it's 12 bytes, the first 4
    bytes are 0xffffffff, followed by the length stored in the next 8
@@ -391,6 +431,10 @@ struct GTY(()) indirect_string_node {
 
 static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
 
+/* True if the compilation unit has location entries that reference
+   debug strings.  */
+static GTY(()) bool debug_str_hash_forced = false;
+
 static GTY(()) int dw2_string_counter;
 static GTY(()) unsigned long dwarf2out_cfi_label_num;
 
@@ -426,8 +470,6 @@ static void output_cfi (dw_cfi_ref, dw_fde_ref, int);
 static void output_cfi_directive (dw_cfi_ref);
 static void output_call_frame_info (int);
 static void dwarf2out_note_section_used (void);
-static void dwarf2out_stack_adjust (rtx, bool);
-static void dwarf2out_args_size_adjust (HOST_WIDE_INT, const char *);
 static void flush_queued_reg_saves (void);
 static bool clobbers_queued_reg_save (const_rtx);
 static void dwarf2out_frame_debug_expr (rtx, const char *);
@@ -762,7 +804,7 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi)
 
       /* Emit the state save.  */
       emit_cfa_remember = false;
-      cfi_remember = new_cfi (); 
+      cfi_remember = new_cfi ();
       cfi_remember->dw_cfi_opc = DW_CFA_remember_state;
       add_fde_cfi (label, cfi_remember);
     }
@@ -1000,7 +1042,7 @@ def_cfa_1 (const char *label, dw_cfa_location *loc_p)
   if (loc.reg == old_cfa.reg && !loc.indirect)
     {
       /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, indicating
-        the CFA register did not change but the offset did.  The data 
+        the CFA register did not change but the offset did.  The data
         factoring for DW_CFA_def_cfa_offset_sf happens in output_cfi, or
         in the assembler via the .cfi_def_cfa_offset directive.  */
       if (loc.offset < 0)
@@ -1113,25 +1155,6 @@ dwarf2out_window_save (const char *label)
   add_fde_cfi (label, cfi);
 }
 
-/* Add a CFI to update the running total of the size of arguments
-   pushed onto the stack.  */
-
-void
-dwarf2out_args_size (const char *label, HOST_WIDE_INT size)
-{
-  dw_cfi_ref cfi;
-
-  if (size == old_args_size)
-    return;
-
-  old_args_size = size;
-
-  cfi = new_cfi ();
-  cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
-  cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
-  add_fde_cfi (label, cfi);
-}
-
 /* Entry point for saving a register to the stack.  REG is the GCC register
    number.  LABEL and OFFSET are passed to reg_save.  */
 
@@ -1482,13 +1505,58 @@ compute_barrier_args_size (void)
   VEC_free (rtx, heap, next);
 }
 
+/* Add a CFI to update the running total of the size of arguments
+   pushed onto the stack.  */
+
+static void
+dwarf2out_args_size (const char *label, HOST_WIDE_INT size)
+{
+  dw_cfi_ref cfi;
+
+  if (size == old_args_size)
+    return;
+
+  old_args_size = size;
+
+  cfi = new_cfi ();
+  cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
+  cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
+  add_fde_cfi (label, cfi);
+}
+
+/* Record a stack adjustment of OFFSET bytes.  */
+
+static void
+dwarf2out_stack_adjust (HOST_WIDE_INT offset, const char *label)
+{
+  if (cfa.reg == STACK_POINTER_REGNUM)
+    cfa.offset += offset;
+
+  if (cfa_store.reg == STACK_POINTER_REGNUM)
+    cfa_store.offset += offset;
+
+  if (ACCUMULATE_OUTGOING_ARGS)
+    return;
+
+#ifndef STACK_GROWS_DOWNWARD
+  offset = -offset;
+#endif
+
+  args_size += offset;
+  if (args_size < 0)
+    args_size = 0;
+
+  def_cfa_1 (label, &cfa);
+  if (flag_asynchronous_unwind_tables)
+    dwarf2out_args_size (label, args_size);
+}
 
 /* Check INSN to see if it looks like a push or a stack adjustment, and
-   make a note of it if it does.  EH uses this information to find out how
-   much extra space it needs to pop off the stack.  */
+   make a note of it if it does.  EH uses this information to find out
+   how much extra space it needs to pop off the stack.  */
 
 static void
-dwarf2out_stack_adjust (rtx insn, bool after_p)
+dwarf2out_notice_stack_adjust (rtx insn, bool after_p)
 {
   HOST_WIDE_INT offset;
   const char *label;
@@ -1572,31 +1640,7 @@ dwarf2out_stack_adjust (rtx insn, bool after_p)
     return;
 
   label = dwarf2out_cfi_label (false);
-  dwarf2out_args_size_adjust (offset, label);
-}
-
-/* Adjust args_size based on stack adjustment OFFSET.  */
-
-static void
-dwarf2out_args_size_adjust (HOST_WIDE_INT offset, const char *label)
-{
-  if (cfa.reg == STACK_POINTER_REGNUM)
-    cfa.offset += offset;
-
-  if (cfa_store.reg == STACK_POINTER_REGNUM)
-    cfa_store.offset += offset;
-
-#ifndef STACK_GROWS_DOWNWARD
-  offset = -offset;
-#endif
-
-  args_size += offset;
-  if (args_size < 0)
-    args_size = 0;
-
-  def_cfa_1 (label, &cfa);
-  if (flag_asynchronous_unwind_tables)
-    dwarf2out_args_size (label, args_size);
+  dwarf2out_stack_adjust (offset, label);
 }
 
 #endif
@@ -1841,7 +1885,7 @@ dwarf2out_frame_debug_cfa_offset (rtx set, const char *label)
   addr = XEXP (set, 0);
   gcc_assert (MEM_P (addr));
   addr = XEXP (addr, 0);
-  
+
   /* As documented, only consider extremely simple addresses.  */
   switch (GET_CODE (addr))
     {
@@ -2174,7 +2218,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
              HOST_WIDE_INT offset = stack_adjust_offset (elem, args_size, 0);
 
              if (offset != 0)
-               dwarf2out_args_size_adjust (offset, label);
+               dwarf2out_stack_adjust (offset, label);
            }
        }
       return;
@@ -2667,10 +2711,13 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
   if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn))
     flush_queued_reg_saves ();
 
-  if (! RTX_FRAME_RELATED_P (insn))
+  if (!RTX_FRAME_RELATED_P (insn))
     {
+      /* ??? This should be done unconditionally since stack adjustments
+        matter if the stack pointer is not the CFA register anymore but
+        is still used to save registers.  */
       if (!ACCUMULATE_OUTGOING_ARGS)
-       dwarf2out_stack_adjust (insn, after_p);
+       dwarf2out_notice_stack_adjust (insn, after_p);
       return;
     }
 
@@ -2828,7 +2875,7 @@ dwarf2out_begin_epilogue (rtx insn)
 void
 dwarf2out_frame_debug_restore_state (void)
 {
-  dw_cfi_ref cfi = new_cfi (); 
+  dw_cfi_ref cfi = new_cfi ();
   const char *label = dwarf2out_cfi_label (false);
 
   cfi->dw_cfi_opc = DW_CFA_restore_state;
@@ -2916,12 +2963,12 @@ dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
 
 #if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
 
-/* Switch to eh_frame_section.  If we don't have an eh_frame_section,
-   switch to the data section instead, and write out a synthetic label
-   for collect2.  */
+/* Switch [BACK] to eh_frame_section.  If we don't have an eh_frame_section,
+   switch to the data section instead, and write out a synthetic start label
+   for collect2 the first time around.  */
 
 static void
-switch_to_eh_frame_section (void)
+switch_to_eh_frame_section (bool back)
 {
   tree label;
 
@@ -2964,11 +3011,32 @@ switch_to_eh_frame_section (void)
       /* We have no special eh_frame section.  Put the information in
         the data section and emit special labels to guide collect2.  */
       switch_to_section (data_section);
-      label = get_file_function_name ("F");
-      ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
-      targetm.asm_out.globalize_label (asm_out_file,
-                                      IDENTIFIER_POINTER (label));
-      ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+
+      if (!back)
+       {
+         label = get_file_function_name ("F");
+         ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+         targetm.asm_out.globalize_label (asm_out_file,
+                                          IDENTIFIER_POINTER (label));
+         ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+       }
+    }
+}
+
+/* Switch [BACK] to the eh or debug frame table section, depending on
+   FOR_EH.  */
+
+static void
+switch_to_frame_table_section (int for_eh, bool back)
+{
+  if (for_eh)
+    switch_to_eh_frame_section (back);
+  else
+    {
+      if (!debug_frame_section)
+       debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+                                          SECTION_DEBUG, NULL);
+      switch_to_section (debug_frame_section);
     }
 }
 
@@ -3214,55 +3282,330 @@ output_cfi_directive (dw_cfi_ref cfi)
     }
 }
 
-/* Return true if *CFIP should be output after switching sections.  */
+DEF_VEC_P (dw_cfi_ref);
+DEF_VEC_ALLOC_P (dw_cfi_ref, heap);
 
-static bool
-output_cfi_p (dw_cfi_ref *cfip, dw_cfi_ref *cfi_args_sizep)
+/* Output CFIs to bring current FDE to the same state as after executing
+   CFIs in CFI chain.  DO_CFI_ASM is true if .cfi_* directives shall
+   be emitted, false otherwise.  If it is false, FDE and FOR_EH are the
+   other arguments to pass to output_cfi.  */
+
+static void
+output_cfis (dw_cfi_ref cfi, bool do_cfi_asm, dw_fde_ref fde, bool for_eh)
 {
-  dw_cfi_ref cfi = *cfip, cfi2;
+  struct dw_cfi_struct cfi_buf;
+  dw_cfi_ref cfi2;
+  dw_cfi_ref cfi_args_size = NULL, cfi_cfa = NULL, cfi_cfa_offset = NULL;
+  VEC (dw_cfi_ref, heap) *regs = VEC_alloc (dw_cfi_ref, heap, 32);
+  unsigned int len, idx;
 
-  switch (cfi->dw_cfi_opc)
-    {
-    case DW_CFA_advance_loc:
-    case DW_CFA_advance_loc1:
-    case DW_CFA_advance_loc2:
-    case DW_CFA_advance_loc4:
-    case DW_CFA_MIPS_advance_loc8:
-    case DW_CFA_set_loc:
-      /* All advances should be ignored.  */
-      return false;
-    case DW_CFA_remember_state:
-      /* Skip everything between .cfi_remember_state and
-        .cfi_restore_state.  */
-      for (cfi2 = cfi->dw_cfi_next; cfi2; cfi2 = cfi2->dw_cfi_next)
-       if (cfi2->dw_cfi_opc == DW_CFA_restore_state)
+  for (;; cfi = cfi->dw_cfi_next)
+    switch (cfi ? cfi->dw_cfi_opc : DW_CFA_nop)
+      {
+      case DW_CFA_advance_loc:
+      case DW_CFA_advance_loc1:
+      case DW_CFA_advance_loc2:
+      case DW_CFA_advance_loc4:
+      case DW_CFA_MIPS_advance_loc8:
+      case DW_CFA_set_loc:
+       /* All advances should be ignored.  */
+       break;
+      case DW_CFA_remember_state:
+       {
+         dw_cfi_ref args_size = cfi_args_size;
+
+         /* Skip everything between .cfi_remember_state and
+            .cfi_restore_state.  */
+         for (cfi2 = cfi->dw_cfi_next; cfi2; cfi2 = cfi2->dw_cfi_next)
+           if (cfi2->dw_cfi_opc == DW_CFA_restore_state)
+             break;
+           else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size)
+             args_size = cfi2;
+           else
+             gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state);
+
+         if (cfi2 == NULL)
+           goto flush_all;
+         else
+           {
+             cfi = cfi2;
+             cfi_args_size = args_size;
+           }
          break;
-       else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size)
-         *cfi_args_sizep = cfi2;
-       else
-         gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state);
-      if (cfi2 == NULL)
-       return true;
-      *cfip = cfi2;
-      return false;
-    case DW_CFA_def_cfa_offset:
-    case DW_CFA_def_cfa_offset_sf:
-      /* Only keep the last of these if they are consecutive.  */
-      for (cfi2 = cfi->dw_cfi_next; cfi2; cfi2 = cfi2->dw_cfi_next)
-       if (cfi2->dw_cfi_opc == cfi->dw_cfi_opc)
-         *cfip = cfi2;
-       else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size)
-         *cfi_args_sizep = cfi2;
+       }
+      case DW_CFA_GNU_args_size:
+       cfi_args_size = cfi;
+       break;
+      case DW_CFA_GNU_window_save:
+       goto flush_all;
+      case DW_CFA_offset:
+      case DW_CFA_offset_extended:
+      case DW_CFA_offset_extended_sf:
+      case DW_CFA_restore:
+      case DW_CFA_restore_extended:
+      case DW_CFA_undefined:
+      case DW_CFA_same_value:
+      case DW_CFA_register:
+      case DW_CFA_val_offset:
+      case DW_CFA_val_offset_sf:
+      case DW_CFA_expression:
+      case DW_CFA_val_expression:
+      case DW_CFA_GNU_negative_offset_extended:
+       if (VEC_length (dw_cfi_ref, regs) <= cfi->dw_cfi_oprnd1.dw_cfi_reg_num)
+         VEC_safe_grow_cleared (dw_cfi_ref, heap, regs,
+                                cfi->dw_cfi_oprnd1.dw_cfi_reg_num + 1);
+       VEC_replace (dw_cfi_ref, regs, cfi->dw_cfi_oprnd1.dw_cfi_reg_num, cfi);
+       break;
+      case DW_CFA_def_cfa:
+      case DW_CFA_def_cfa_sf:
+      case DW_CFA_def_cfa_expression:
+       cfi_cfa = cfi;
+       cfi_cfa_offset = cfi;
+       break;
+      case DW_CFA_def_cfa_register:
+       cfi_cfa = cfi;
+       break;
+      case DW_CFA_def_cfa_offset:
+      case DW_CFA_def_cfa_offset_sf:
+       cfi_cfa_offset = cfi;
+       break;
+      case DW_CFA_nop:
+       gcc_assert (cfi == NULL);
+      flush_all:
+       len = VEC_length (dw_cfi_ref, regs);
+       for (idx = 0; idx < len; idx++)
+         {
+           cfi2 = VEC_replace (dw_cfi_ref, regs, idx, NULL);
+           if (cfi2 != NULL
+               && cfi2->dw_cfi_opc != DW_CFA_restore
+               && cfi2->dw_cfi_opc != DW_CFA_restore_extended)
+             {
+               if (do_cfi_asm)
+                 output_cfi_directive (cfi2);
+               else
+                 output_cfi (cfi2, fde, for_eh);
+             }
+         }
+       if (cfi_cfa && cfi_cfa_offset && cfi_cfa_offset != cfi_cfa)
+         {
+           gcc_assert (cfi_cfa->dw_cfi_opc != DW_CFA_def_cfa_expression);
+           cfi_buf = *cfi_cfa;
+           switch (cfi_cfa_offset->dw_cfi_opc)
+             {
+             case DW_CFA_def_cfa_offset:
+               cfi_buf.dw_cfi_opc = DW_CFA_def_cfa;
+               cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1;
+               break;
+             case DW_CFA_def_cfa_offset_sf:
+               cfi_buf.dw_cfi_opc = DW_CFA_def_cfa_sf;
+               cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1;
+               break;
+             case DW_CFA_def_cfa:
+             case DW_CFA_def_cfa_sf:
+               cfi_buf.dw_cfi_opc = cfi_cfa_offset->dw_cfi_opc;
+               cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd2;
+               break;
+             default:
+               gcc_unreachable ();
+             }
+           cfi_cfa = &cfi_buf;
+         }
+       else if (cfi_cfa_offset)
+         cfi_cfa = cfi_cfa_offset;
+       if (cfi_cfa)
+         {
+           if (do_cfi_asm)
+             output_cfi_directive (cfi_cfa);
+           else
+             output_cfi (cfi_cfa, fde, for_eh);
+         }
+       cfi_cfa = NULL;
+       cfi_cfa_offset = NULL;
+       if (cfi_args_size
+           && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset)
+         {
+           if (do_cfi_asm)
+             output_cfi_directive (cfi_args_size);
+           else
+             output_cfi (cfi_args_size, fde, for_eh);
+         }
+       cfi_args_size = NULL;
+       if (cfi == NULL)
+         {
+           VEC_free (dw_cfi_ref, heap, regs);
+           return;
+         }
+       else if (do_cfi_asm)
+         output_cfi_directive (cfi);
        else
-         break;
-      return true;
-    case DW_CFA_GNU_args_size:
-      /* One DW_CFA_GNU_args_size, the last one, is enough.  */
-      *cfi_args_sizep = cfi;
-      return false;
-    default:
-      return true;
+         output_cfi (cfi, fde, for_eh);
+       break;
+      default:
+       gcc_unreachable ();
+    }
+}
+
+/* Output one FDE.  */
+
+static void
+output_fde (dw_fde_ref fde, bool for_eh, bool second,
+           char *section_start_label, int fde_encoding, char *augmentation,
+           bool any_lsda_needed, int lsda_encoding)
+{
+  const char *begin, *end;
+  static unsigned int j;
+  char l1[20], l2[20];
+  dw_cfi_ref cfi;
+
+  targetm.asm_out.unwind_label (asm_out_file, fde->decl, for_eh,
+                               /* empty */ 0);
+  targetm.asm_out.internal_label (asm_out_file, FDE_LABEL,
+                                 for_eh + j);
+  ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + j);
+  ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + j);
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
+    dw2_asm_output_data (4, 0xffffffff, "Initial length escape value"
+                        " indicating 64-bit DWARF extension");
+  dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
+                       "FDE Length");
+  ASM_OUTPUT_LABEL (asm_out_file, l1);
+
+  if (for_eh)
+    dw2_asm_output_delta (4, l1, section_start_label, "FDE CIE offset");
+  else
+    dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label,
+                          debug_frame_section, "FDE CIE offset");
+
+  if (!fde->dw_fde_switched_sections)
+    {
+      begin = fde->dw_fde_begin;
+      end = fde->dw_fde_end;
+    }
+  else
+    {
+      /* For the first section, prefer dw_fde_begin over
+        dw_fde_{hot,cold}_section_label, as the latter
+        might be separated from the real start of the
+        function by alignment padding.  */
+      if (!second)
+       begin = fde->dw_fde_begin;
+      else if (fde->dw_fde_switched_cold_to_hot)
+       begin = fde->dw_fde_hot_section_label;
+      else
+       begin = fde->dw_fde_unlikely_section_label;
+      if (second ^ fde->dw_fde_switched_cold_to_hot)
+       end = fde->dw_fde_unlikely_section_end_label;
+      else
+       end = fde->dw_fde_hot_section_end_label;
+    }
+
+  if (for_eh)
+    {
+      rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, begin);
+      SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
+      dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref, false,
+                                      "FDE initial location");
+      dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+                           end, begin, "FDE address range");
+    }
+  else
+    {
+      dw2_asm_output_addr (DWARF2_ADDR_SIZE, begin, "FDE initial location");
+      dw2_asm_output_delta (DWARF2_ADDR_SIZE, end, begin, "FDE address range");
+    }
+
+  if (augmentation[0])
+    {
+      if (any_lsda_needed)
+       {
+         int size = size_of_encoded_value (lsda_encoding);
+
+         if (lsda_encoding == DW_EH_PE_aligned)
+           {
+             int offset = (  4         /* Length */
+                           + 4         /* CIE offset */
+                           + 2 * size_of_encoded_value (fde_encoding)
+                           + 1         /* Augmentation size */ );
+             int pad = -offset & (PTR_SIZE - 1);
+
+             size += pad;
+             gcc_assert (size_of_uleb128 (size) == 1);
+           }
+
+         dw2_asm_output_data_uleb128 (size, "Augmentation size");
+
+         if (fde->uses_eh_lsda)
+           {
+             ASM_GENERATE_INTERNAL_LABEL (l1, second ? "LLSDAC" : "LLSDA",
+                                          fde->funcdef_number);
+             dw2_asm_output_encoded_addr_rtx (lsda_encoding,
+                                              gen_rtx_SYMBOL_REF (Pmode, l1),
+                                              false,
+                                              "Language Specific Data Area");
+           }
+         else
+           {
+             if (lsda_encoding == DW_EH_PE_aligned)
+               ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+             dw2_asm_output_data (size_of_encoded_value (lsda_encoding), 0,
+                                  "Language Specific Data Area (none)");
+           }
+       }
+      else
+       dw2_asm_output_data_uleb128 (0, "Augmentation size");
+    }
+
+  /* Loop through the Call Frame Instructions associated with
+     this FDE.  */
+  fde->dw_fde_current_label = begin;
+  if (!fde->dw_fde_switched_sections)
+    for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
+      output_cfi (cfi, fde, for_eh);
+  else if (!second)
+    {
+      if (fde->dw_fde_switch_cfi)
+       for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
+         {
+           output_cfi (cfi, fde, for_eh);
+           if (cfi == fde->dw_fde_switch_cfi)
+             break;
+         }
     }
+  else
+    {
+      dw_cfi_ref cfi_next = fde->dw_fde_cfi;
+
+      if (fde->dw_fde_switch_cfi)
+       {
+         cfi_next = fde->dw_fde_switch_cfi->dw_cfi_next;
+         fde->dw_fde_switch_cfi->dw_cfi_next = NULL;
+         output_cfis (fde->dw_fde_cfi, false, fde, for_eh);
+         fde->dw_fde_switch_cfi->dw_cfi_next = cfi_next;
+       }
+      for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next)
+       output_cfi (cfi, fde, for_eh);
+    }
+
+  /* If we are to emit a ref/link from function bodies to their frame tables,
+     do it now.  This is typically performed to make sure that tables
+     associated with functions are dragged with them and not discarded in
+     garbage collecting links. We need to do this on a per function basis to
+     cope with -ffunction-sections.  */
+
+#ifdef ASM_OUTPUT_DWARF_TABLE_REF
+  /* Switch to the function section, emit the ref to the tables, and
+     switch *back* into the table section.  */
+  switch_to_section (function_section (fde->decl));
+  ASM_OUTPUT_DWARF_TABLE_REF (section_start_label);
+  switch_to_frame_table_section (for_eh, true);
+#endif
+
+  /* Pad the FDE out to an address sized boundary.  */
+  ASM_OUTPUT_ALIGN (asm_out_file,
+                   floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
+  ASM_OUTPUT_LABEL (asm_out_file, l2);
+
+  j += 2;
 }
 
 /* Output the call frame information used to record information
@@ -3272,7 +3615,7 @@ output_cfi_p (dw_cfi_ref *cfip, dw_cfi_ref *cfi_args_sizep)
 static void
 output_call_frame_info (int for_eh)
 {
-  unsigned int i, j;
+  unsigned int i;
   dw_fde_ref fde;
   dw_cfi_ref cfi;
   char l1[20], l2[20], section_start_label[20];
@@ -3283,6 +3626,7 @@ output_call_frame_info (int for_eh)
   int per_encoding = DW_EH_PE_absptr;
   int lsda_encoding = DW_EH_PE_absptr;
   int return_reg;
+  rtx personality = NULL;
   int dw_cie_version;
 
   /* Don't emit a CIE if there won't be any FDEs.  */
@@ -3335,15 +3679,8 @@ output_call_frame_info (int for_eh)
   if (flag_debug_asm)
     app_enable ();
 
-  if (for_eh)
-    switch_to_eh_frame_section ();
-  else
-    {
-      if (!debug_frame_section)
-       debug_frame_section = get_section (DEBUG_FRAME_SECTION,
-                                          SECTION_DEBUG, NULL);
-      switch_to_section (debug_frame_section);
-    }
+  /* Switch to the proper frame section, first time.  */
+  switch_to_frame_table_section (for_eh, false);
 
   ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
   ASM_OUTPUT_LABEL (asm_out_file, section_start_label);
@@ -3375,6 +3712,8 @@ output_call_frame_info (int for_eh)
 
   augmentation[0] = 0;
   augmentation_size = 0;
+
+  personality = current_unit_personality;
   if (for_eh)
     {
       char *p;
@@ -3394,11 +3733,11 @@ output_call_frame_info (int for_eh)
       lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
 
       p = augmentation + 1;
-      if (eh_personality_libfunc)
+      if (personality)
        {
          *p++ = 'P';
          augmentation_size += 1 + size_of_encoded_value (per_encoding);
-         assemble_external_libcall (eh_personality_libfunc);
+         assemble_external_libcall (personality);
        }
       if (any_lsda_needed)
        {
@@ -3417,7 +3756,7 @@ output_call_frame_info (int for_eh)
        }
 
       /* Ug.  Some platforms can't do unaligned dynamic relocations at all.  */
-      if (eh_personality_libfunc && per_encoding == DW_EH_PE_aligned)
+      if (personality && per_encoding == DW_EH_PE_aligned)
        {
          int offset = (  4             /* Length */
                        + 4             /* CIE Id */
@@ -3451,12 +3790,12 @@ output_call_frame_info (int for_eh)
   if (augmentation[0])
     {
       dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size");
-      if (eh_personality_libfunc)
+      if (personality)
        {
          dw2_asm_output_data (1, per_encoding, "Personality (%s)",
                               eh_data_format_name (per_encoding));
          dw2_asm_output_encoded_addr_rtx (per_encoding,
-                                          eh_personality_libfunc,
+                                          personality,
                                           true, NULL);
        }
 
@@ -3478,7 +3817,7 @@ output_call_frame_info (int for_eh)
   ASM_OUTPUT_LABEL (asm_out_file, l2);
 
   /* Loop through all of the FDE's.  */
-  for (i = 0, j = 0; i < fde_table_in_use; i++)
+  for (i = 0; i < fde_table_in_use; i++)
     {
       unsigned int k;
       fde = &fde_table[i];
@@ -3491,153 +3830,8 @@ output_call_frame_info (int for_eh)
        continue;
 
       for (k = 0; k < (fde->dw_fde_switched_sections ? 2 : 1); k++)
-       {
-         const char *begin, *end;
-
-         targetm.asm_out.unwind_label (asm_out_file, fde->decl, for_eh,
-                                       /* empty */ 0);
-         targetm.asm_out.internal_label (asm_out_file, FDE_LABEL,
-                                         for_eh + j);
-         ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + j);
-         ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + j);
-         if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
-           dw2_asm_output_data (4, 0xffffffff, "Initial length escape value"
-                                " indicating 64-bit DWARF extension");
-         dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
-                               "FDE Length");
-         ASM_OUTPUT_LABEL (asm_out_file, l1);
-
-         if (for_eh)
-           dw2_asm_output_delta (4, l1, section_start_label,
-                                 "FDE CIE offset");
-         else
-           dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label,
-                                  debug_frame_section, "FDE CIE offset");
-
-         if (!fde->dw_fde_switched_sections)
-           {
-             begin = fde->dw_fde_begin;
-             end = fde->dw_fde_end;
-           }
-         else if (k ^ fde->dw_fde_switched_cold_to_hot)
-           {
-             begin = fde->dw_fde_unlikely_section_label;
-             end = fde->dw_fde_unlikely_section_end_label;
-           }
-         else
-           {
-             begin = fde->dw_fde_hot_section_label;
-             end = fde->dw_fde_hot_section_end_label;
-           }
-
-         if (for_eh)
-           {
-             rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, begin);
-             SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
-             dw2_asm_output_encoded_addr_rtx (fde_encoding,
-                                              sym_ref,
-                                              false,
-                                              "FDE initial location");
-             dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
-                                   end, begin, "FDE address range");
-           }
-         else
-           {
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE, begin,
-                                  "FDE initial location");
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE, end, begin,
-                                   "FDE address range");
-           }
-
-         if (augmentation[0])
-           {
-             if (any_lsda_needed)
-               {
-                 int size = size_of_encoded_value (lsda_encoding);
-
-                 if (lsda_encoding == DW_EH_PE_aligned)
-                   {
-                     int offset = (  4         /* Length */
-                                   + 4         /* CIE offset */
-                                   + 2 * size_of_encoded_value (fde_encoding)
-                                   + 1         /* Augmentation size */ );
-                     int pad = -offset & (PTR_SIZE - 1);
-
-                     size += pad;
-                     gcc_assert (size_of_uleb128 (size) == 1);
-                   }
-
-                 dw2_asm_output_data_uleb128 (size, "Augmentation size");
-
-                 if (fde->uses_eh_lsda)
-                   {
-                      ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
-                                                   fde->funcdef_number);
-                     dw2_asm_output_encoded_addr_rtx (lsda_encoding,
-                                               gen_rtx_SYMBOL_REF (Pmode, l1),
-                                               false,
-                                               "Language Specific Data Area");
-                   }
-                 else
-                   {
-                     if (lsda_encoding == DW_EH_PE_aligned)
-                       ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
-                     dw2_asm_output_data (
-                               size_of_encoded_value (lsda_encoding), 0,
-                               "Language Specific Data Area (none)");
-                   }
-               }
-             else
-               dw2_asm_output_data_uleb128 (0, "Augmentation size");
-           }
-
-         /* Loop through the Call Frame Instructions associated with
-            this FDE.  */
-         fde->dw_fde_current_label = begin;
-         if (!fde->dw_fde_switched_sections)
-           for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
-             output_cfi (cfi, fde, for_eh);
-         else if (k == 0)
-           {
-             if (fde->dw_fde_switch_cfi)
-               for (cfi = fde->dw_fde_cfi; cfi != NULL;
-                    cfi = cfi->dw_cfi_next)
-                 {
-                   output_cfi (cfi, fde, for_eh);
-                   if (cfi == fde->dw_fde_switch_cfi)
-                     break;
-                 }
-           }
-         else
-           {
-             dw_cfi_ref cfi_next = fde->dw_fde_cfi;
-
-             if (fde->dw_fde_switch_cfi)
-               {
-                 dw_cfi_ref cfi_args_size = NULL;
-                 cfi_next = fde->dw_fde_switch_cfi->dw_cfi_next;
-                 fde->dw_fde_switch_cfi->dw_cfi_next = NULL;
-                 for (cfi = fde->dw_fde_cfi; cfi != NULL;
-                      cfi = cfi->dw_cfi_next)
-                   if (output_cfi_p (&cfi, &cfi_args_size))
-                     output_cfi (cfi, fde, for_eh);
-                 if (cfi_args_size
-                     && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset)
-                   output_cfi (cfi_args_size, fde, for_eh);
-                 fde->dw_fde_switch_cfi->dw_cfi_next = cfi_next;
-               }
-             for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next)
-               output_cfi (cfi, fde, for_eh);
-           }
-
-         /* Pad the FDE out to an address sized boundary.  */
-         ASM_OUTPUT_ALIGN (asm_out_file,
-                           floor_log2 ((for_eh
-                                        ? PTR_SIZE : DWARF2_ADDR_SIZE)));
-         ASM_OUTPUT_LABEL (asm_out_file, l2);
-
-         j += 2;
-       }
+       output_fde (fde, for_eh, k, section_start_label, fde_encoding,
+                   augmentation, any_lsda_needed, lsda_encoding);
     }
 
   if (for_eh && targetm.terminate_dw2_eh_frame_info)
@@ -3656,17 +3850,18 @@ output_call_frame_info (int for_eh)
 /* Emit .cfi_startproc and .cfi_personality/.cfi_lsda if needed.  */
 
 static void
-dwarf2out_do_cfi_startproc (void)
+dwarf2out_do_cfi_startproc (bool second)
 {
   int enc;
   rtx ref;
+  rtx personality = get_personality_function (current_function_decl);
 
   fprintf (asm_out_file, "\t.cfi_startproc\n");
 
-  if (eh_personality_libfunc)
+  if (personality)
     {
       enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
-      ref = eh_personality_libfunc;
+      ref = personality;
 
       /* ??? The GAS support isn't entirely consistent.  We have to
         handle indirect support ourselves, but PC-relative is done
@@ -3685,7 +3880,7 @@ dwarf2out_do_cfi_startproc (void)
       char lab[20];
 
       enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
-      ASM_GENERATE_INTERNAL_LABEL (lab, "LLSDA",
+      ASM_GENERATE_INTERNAL_LABEL (lab, second ? "LLSDAC" : "LLSDA",
                                   current_function_funcdef_no);
       ref = gen_rtx_SYMBOL_REF (Pmode, lab);
       SYMBOL_REF_FLAGS (ref) = SYMBOL_FLAG_LOCAL;
@@ -3804,7 +3999,21 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
 #endif
 
   if (dwarf2out_do_cfi_asm ())
-    dwarf2out_do_cfi_startproc ();
+    dwarf2out_do_cfi_startproc (false);
+  else
+    {
+      rtx personality = get_personality_function (current_function_decl);
+      if (!current_unit_personality)
+        current_unit_personality = personality;
+
+      /* We cannot keep a current personality per function as without CFI
+        asm at the point where we emit the CFI data there is no current
+        function anymore.  */
+      if (personality
+         && current_unit_personality != personality)
+       sorry ("Multiple EH personalities are supported only with assemblers "
+              "supporting .cfi.personality directive.");
+    }
 }
 
 /* Output a marker (i.e. a label) for the absolute end of the generated code
@@ -3913,16 +4122,10 @@ dwarf2out_switch_text_section (void)
 
   if (dwarf2out_do_cfi_asm ())
     {
-      dw_cfi_ref cfi, cfi_args_size = NULL;
-
-      dwarf2out_do_cfi_startproc ();
+      dwarf2out_do_cfi_startproc (true);
       /* As this is a different FDE, insert all current CFI instructions
         again.  */
-      for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
-       if (output_cfi_p (&cfi, &cfi_args_size))
-         output_cfi_directive (cfi);
-      if (cfi_args_size && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset)
-       output_cfi_directive (cfi_args_size);
+      output_cfis (fde->dw_fde_cfi, true, fde, true);
     }
   else
     {
@@ -3963,6 +4166,9 @@ DEF_VEC_ALLOC_O(deferred_locations,gc);
 
 static GTY(()) VEC(deferred_locations, gc) *deferred_locations_list;
 
+DEF_VEC_P(dw_die_ref);
+DEF_VEC_ALLOC_P(dw_die_ref,heap);
+
 /* Each DIE may have a series of attribute/value pairs.  Values
    can take on several forms.  The forms that are used in this
    implementation are listed below.  */
@@ -3976,7 +4182,7 @@ enum dw_val_class
   dw_val_class_range_list,
   dw_val_class_const,
   dw_val_class_unsigned_const,
-  dw_val_class_long_long,
+  dw_val_class_const_double,
   dw_val_class_vec,
   dw_val_class_flag,
   dw_val_class_die_ref,
@@ -3985,18 +4191,10 @@ enum dw_val_class
   dw_val_class_lineptr,
   dw_val_class_str,
   dw_val_class_macptr,
-  dw_val_class_file
+  dw_val_class_file,
+  dw_val_class_data8
 };
 
-/* Describe a double word constant value.  */
-/* ??? Every instance of long_long in the code really means CONST_DOUBLE.  */
-
-typedef struct GTY(()) dw_long_long_struct {
-  unsigned long hi;
-  unsigned long low;
-}
-dw_long_long_const;
-
 /* Describe a floating point constant value, or a vector constant value.  */
 
 typedef struct GTY(()) dw_vec_struct {
@@ -4019,7 +4217,7 @@ typedef struct GTY(()) dw_val_struct {
       dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
       HOST_WIDE_INT GTY ((default)) val_int;
       unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
-      dw_long_long_const GTY ((tag ("dw_val_class_long_long"))) val_long_long;
+      double_int GTY ((tag ("dw_val_class_const_double"))) val_double;
       dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
       struct dw_val_die_union
        {
@@ -4031,6 +4229,7 @@ typedef struct GTY(()) dw_val_struct {
       char * GTY ((tag ("dw_val_class_lbl_id"))) val_lbl_id;
       unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag;
       struct dwarf_file_data * GTY ((tag ("dw_val_class_file"))) val_file;
+      unsigned char GTY ((tag ("dw_val_class_data8"))) val_data8[8];
     }
   GTY ((desc ("%1.val_class"))) v;
 }
@@ -4374,6 +4573,10 @@ dwarf_stack_op_name (unsigned int op)
       return "DW_OP_call4";
     case DW_OP_call_ref:
       return "DW_OP_call_ref";
+    case DW_OP_implicit_value:
+      return "DW_OP_implicit_value";
+    case DW_OP_stack_value:
+      return "DW_OP_stack_value";
     case DW_OP_form_tls_address:
       return "DW_OP_form_tls_address";
     case DW_OP_call_frame_cfa:
@@ -4480,6 +4683,18 @@ loc_descr_plus_const (dw_loc_descr_ref *list_head, HOST_WIDE_INT offset)
     }
 }
 
+#ifdef DWARF2_DEBUGGING_INFO
+/* Add a constant OFFSET to a location list.  */
+
+static void
+loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset)
+{
+  dw_loc_list_ref d;
+  for (d = list_head; d != NULL; d = d->dw_loc_next)
+    loc_descr_plus_const (&d->expr, offset);
+}
+#endif
+
 /* Return the size of a location descriptor.  */
 
 static unsigned long
@@ -4584,6 +4799,10 @@ size_of_loc_descr (dw_loc_descr_ref loc)
     case DW_OP_call_ref:
       size += DWARF2_ADDR_SIZE;
       break;
+    case DW_OP_implicit_value:
+      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned)
+             + loc->dw_loc_oprnd1.v.val_unsigned;
+      break;
     default:
       break;
     }
@@ -4619,6 +4838,10 @@ size_of_locs (dw_loc_descr_ref loc)
   return size;
 }
 
+#ifdef DWARF2_DEBUGGING_INFO
+static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
+#endif
+
 /* Output location description stack opcode's operands (if any).  */
 
 static void
@@ -4640,7 +4863,7 @@ output_loc_operands (dw_loc_descr_ref loc)
       break;
     case DW_OP_const8u:
     case DW_OP_const8s:
-      gcc_assert (HOST_BITS_PER_LONG >= 64);
+      gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
       dw2_asm_output_data (8, val1->v.val_int, NULL);
       break;
     case DW_OP_skip:
@@ -4654,6 +4877,60 @@ output_loc_operands (dw_loc_descr_ref loc)
        dw2_asm_output_data (2, offset, NULL);
       }
       break;
+    case DW_OP_implicit_value:
+      dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+      switch (val2->val_class)
+       {
+       case dw_val_class_const:
+         dw2_asm_output_data (val1->v.val_unsigned, val2->v.val_int, NULL);
+         break;
+       case dw_val_class_vec:
+         {
+           unsigned int elt_size = val2->v.val_vec.elt_size;
+           unsigned int len = val2->v.val_vec.length;
+           unsigned int i;
+           unsigned char *p;
+
+           if (elt_size > sizeof (HOST_WIDE_INT))
+             {
+               elt_size /= 2;
+               len *= 2;
+             }
+           for (i = 0, p = val2->v.val_vec.array;
+                i < len;
+                i++, p += elt_size)
+             dw2_asm_output_data (elt_size, extract_int (p, elt_size),
+                                  "fp or vector constant word %u", i);
+         }
+         break;
+       case dw_val_class_const_double:
+         {
+           unsigned HOST_WIDE_INT first, second;
+
+           if (WORDS_BIG_ENDIAN)
+             {
+               first = val2->v.val_double.high;
+               second = val2->v.val_double.low;
+             }
+           else
+             {
+               first = val2->v.val_double.low;
+               second = val2->v.val_double.high;
+             }
+           dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
+                                first, NULL);
+           dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
+                                second, NULL);
+         }
+         break;
+       case dw_val_class_addr:
+         gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE);
+         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val2->v.val_addr, NULL);
+         break;
+       default:
+         gcc_unreachable ();
+       }
+      break;
 #else
     case DW_OP_const2u:
     case DW_OP_const2s:
@@ -4663,6 +4940,7 @@ output_loc_operands (dw_loc_descr_ref loc)
     case DW_OP_const8s:
     case DW_OP_skip:
     case DW_OP_bra:
+    case DW_OP_implicit_value:
       /* We currently don't make any attempt to make sure these are
         aligned properly like we do for the main unwind info, so
         don't support emitting things larger than a byte if we're
@@ -4794,6 +5072,7 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
   switch (loc->dw_loc_opc)
     {
     case DW_OP_addr:
+    case DW_OP_implicit_value:
       /* We cannot output addresses in .cfi_escape, only bytes.  */
       gcc_unreachable ();
 
@@ -4820,7 +5099,7 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
 
     case DW_OP_const8u:
     case DW_OP_const8s:
-      gcc_assert (HOST_BITS_PER_LONG >= 64);
+      gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
       fputc (',', asm_out_file);
       dw2_asm_output_data_raw (8, val1->v.val_int);
       break;
@@ -5125,6 +5404,7 @@ static int output_indirect_string (void **, void *);
 
 static void dwarf2out_init (const char *);
 static void dwarf2out_finish (const char *);
+static void dwarf2out_assembly_start (void);
 static void dwarf2out_define (unsigned int, const char *);
 static void dwarf2out_undef (unsigned int, const char *);
 static void dwarf2out_start_source_file (unsigned, const char *);
@@ -5139,6 +5419,10 @@ static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
                                                 dw_die_ref);
 static void dwarf2out_abstract_function (tree);
 static void dwarf2out_var_location (rtx);
+static void dwarf2out_direct_call (tree);
+static void dwarf2out_virtual_call_token (tree, int);
+static void dwarf2out_copy_call_info (rtx, rtx);
+static void dwarf2out_virtual_call (int);
 static void dwarf2out_begin_function (tree);
 static void dwarf2out_set_name (tree, tree);
 
@@ -5148,6 +5432,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
 {
   dwarf2out_init,
   dwarf2out_finish,
+  dwarf2out_assembly_start,
   dwarf2out_define,
   dwarf2out_undef,
   dwarf2out_start_source_file,
@@ -5174,6 +5459,10 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   debug_nothing_int,           /* handle_pch */
   dwarf2out_var_location,
   dwarf2out_switch_text_section,
+  dwarf2out_direct_call,
+  dwarf2out_virtual_call_token,
+  dwarf2out_copy_call_info,
+  dwarf2out_virtual_call,
   dwarf2out_set_name,
   1                             /* start_end_main_source_file */
 };
@@ -5201,6 +5490,7 @@ typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref;
 typedef struct pubname_struct *pubname_ref;
 typedef struct dw_ranges_struct *dw_ranges_ref;
 typedef struct dw_ranges_by_label_struct *dw_ranges_by_label_ref;
+typedef struct comdat_type_struct *comdat_type_node_ref;
 
 /* Each entry in the line_info_table maintains the file and
    line number associated with the label generated for that
@@ -5241,7 +5531,12 @@ DEF_VEC_ALLOC_O(dw_attr_node,gc);
 
 typedef struct GTY((chain_circular ("%h.die_sib"))) die_struct {
   enum dwarf_tag die_tag;
-  char *die_symbol;
+  union die_symbol_or_type_node
+    {
+      char * GTY ((tag ("0"))) die_symbol;
+      comdat_type_node_ref GTY ((tag ("1"))) die_type_node;
+    }
+  GTY ((desc ("dwarf_version >= 4"))) die_id;
   VEC(dw_attr_node,gc) * die_attr;
   dw_die_ref die_parent;
   dw_die_ref die_child;
@@ -5287,6 +5582,16 @@ struct GTY(()) dw_ranges_by_label_struct {
   const char *end;
 };
 
+/* The comdat type node structure.  */
+typedef struct GTY(()) comdat_type_struct
+{
+  dw_die_ref root_die;
+  dw_die_ref type_die;
+  char signature[DWARF_TYPE_SIGNATURE_SIZE];
+  struct comdat_type_struct *next;
+}
+comdat_type_node;
+
 /* The limbo die list structure.  */
 typedef struct GTY(()) limbo_die_struct {
   dw_die_ref die;
@@ -5295,6 +5600,14 @@ typedef struct GTY(()) limbo_die_struct {
 }
 limbo_die_node;
 
+typedef struct GTY(()) skeleton_chain_struct
+{
+  dw_die_ref old_die;
+  dw_die_ref new_die;
+  struct skeleton_chain_struct *parent;
+}
+skeleton_chain_node;
+
 /* How to start an assembler comment.  */
 #ifndef ASM_COMMENT_START
 #define ASM_COMMENT_START ";#"
@@ -5328,6 +5641,11 @@ limbo_die_node;
 #define DWARF_COMPILE_UNIT_HEADER_SIZE \
   (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 3)
 
+/* Fixed size portion of the DWARF comdat type unit header.  */
+#define DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE \
+  (DWARF_COMPILE_UNIT_HEADER_SIZE + DWARF_TYPE_SIGNATURE_SIZE \
+   + DWARF_OFFSET_SIZE)
+
 /* Fixed size portion of public names info.  */
 #define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
 
@@ -5378,6 +5696,9 @@ static unsigned long next_die_offset;
 /* Record the root of the DIE's built for the current compilation unit.  */
 static GTY(()) dw_die_ref comp_unit_die;
 
+/* A list of type DIEs that have been separated into comdat sections.  */
+static GTY(()) comdat_type_node *comdat_type_list;
+
 /* A list of DIEs with a NULL parent waiting to be relocated.  */
 static GTY(()) limbo_die_node *limbo_die_list;
 
@@ -5397,6 +5718,14 @@ static GTY ((param_is (struct die_struct))) htab_t decl_die_table;
    The key is DECL_UID() ^ die_parent.  */
 static GTY ((param_is (struct die_struct))) htab_t common_block_die_table;
 
+typedef struct GTY(()) die_arg_entry_struct {
+    dw_die_ref die;
+    tree arg;
+} die_arg_entry;
+
+DEF_VEC_O(die_arg_entry);
+DEF_VEC_ALLOC_O(die_arg_entry,gc);
+
 /* Node of the variable location list.  */
 struct GTY ((chain_next ("%h.next"))) var_loc_node {
   rtx GTY (()) var_loc_note;
@@ -5514,6 +5843,45 @@ static GTY(()) bool have_location_lists;
 /* Unique label counter.  */
 static GTY(()) unsigned int loclabel_num;
 
+/* Unique label counter for point-of-call tables.  */
+static GTY(()) unsigned int poc_label_num;
+
+/* The direct call table structure.  */
+
+typedef struct GTY(()) dcall_struct {
+  unsigned int poc_label_num;
+  tree poc_decl;
+  dw_die_ref targ_die;
+}
+dcall_entry;
+
+DEF_VEC_O(dcall_entry);
+DEF_VEC_ALLOC_O(dcall_entry, gc);
+
+/* The virtual call table structure.  */
+
+typedef struct GTY(()) vcall_struct {
+  unsigned int poc_label_num;
+  unsigned int vtable_slot;
+}
+vcall_entry;
+
+DEF_VEC_O(vcall_entry);
+DEF_VEC_ALLOC_O(vcall_entry, gc);
+
+/* Pointers to the direct and virtual call tables.  */
+static GTY (()) VEC (dcall_entry, gc) * dcall_table = NULL;
+static GTY (()) VEC (vcall_entry, gc) * vcall_table = NULL;
+
+/* A hash table to map INSN_UIDs to vtable slot indexes.  */
+
+struct GTY (()) vcall_insn {
+  int insn_uid;
+  unsigned int vtable_slot;
+};
+
+static GTY ((param_is (struct vcall_insn))) htab_t vcall_insn_table;
+
 #ifdef DWARF2_DEBUGGING_INFO
 /* Record whether the function being analyzed contains inlined functions.  */
 static int current_function_has_inlines;
@@ -5531,6 +5899,8 @@ static GTY(()) int label_num;
 /* Cached result of previous call to lookup_filename.  */
 static GTY(()) struct dwarf_file_data * file_table_last_lookup;
 
+static GTY(()) VEC(die_arg_entry,gc) *tmpl_value_parm_die_table;
+
 #ifdef DWARF2_DEBUGGING_INFO
 
 /* Offset from the "steady-state frame pointer" to the frame base,
@@ -5555,10 +5925,11 @@ static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
 static inline HOST_WIDE_INT AT_int (dw_attr_ref);
 static void add_AT_unsigned (dw_die_ref, enum dwarf_attribute, unsigned HOST_WIDE_INT);
 static inline unsigned HOST_WIDE_INT AT_unsigned (dw_attr_ref);
-static void add_AT_long_long (dw_die_ref, enum dwarf_attribute, unsigned long,
-                             unsigned long);
+static void add_AT_double (dw_die_ref, enum dwarf_attribute,
+                          HOST_WIDE_INT, unsigned HOST_WIDE_INT);
 static inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int,
                               unsigned int, unsigned char *);
+static void add_AT_data8 (dw_die_ref, enum dwarf_attribute, unsigned char *);
 static hashval_t debug_str_do_hash (const void *);
 static int debug_str_eq (const void *, const void *);
 static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *);
@@ -5621,6 +5992,16 @@ static dw_die_ref pop_compile_unit (dw_die_ref);
 static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
 static void attr_checksum (dw_attr_ref, struct md5_ctx *, int *);
 static void die_checksum (dw_die_ref, struct md5_ctx *, int *);
+static void checksum_sleb128 (HOST_WIDE_INT, struct md5_ctx *);
+static void checksum_uleb128 (unsigned HOST_WIDE_INT, struct md5_ctx *);
+static void loc_checksum_ordered (dw_loc_descr_ref, struct md5_ctx *);
+static void attr_checksum_ordered (enum dwarf_tag, dw_attr_ref,
+                                  struct md5_ctx *, int *);
+struct checksum_attributes;
+static void collect_checksum_attributes (struct checksum_attributes *, dw_die_ref);
+static void die_checksum_ordered (dw_die_ref, struct md5_ctx *, int *);
+static void checksum_die_context (dw_die_ref, struct md5_ctx *);
+static void generate_type_signature (dw_die_ref, comdat_type_node *);
 static int same_loc_p (dw_loc_descr_ref, dw_loc_descr_ref, int *);
 static int same_dw_val_p (const dw_val_node *, const dw_val_node *, int *);
 static int same_attr_p (dw_attr_ref, dw_attr_ref, int *);
@@ -5632,6 +6013,22 @@ static int is_comdat_die (dw_die_ref);
 static int is_symbol_die (dw_die_ref);
 static void assign_symbol_names (dw_die_ref);
 static void break_out_includes (dw_die_ref);
+static int is_declaration_die (dw_die_ref);
+static int should_move_die_to_comdat (dw_die_ref);
+static dw_die_ref clone_as_declaration (dw_die_ref);
+static dw_die_ref clone_die (dw_die_ref);
+static dw_die_ref clone_tree (dw_die_ref);
+static void copy_declaration_context (dw_die_ref, dw_die_ref);
+static void generate_skeleton_ancestor_tree (skeleton_chain_node *);
+static void generate_skeleton_bottom_up (skeleton_chain_node *);
+static dw_die_ref generate_skeleton (dw_die_ref);
+static dw_die_ref remove_child_or_replace_with_skeleton (dw_die_ref,
+                                                         dw_die_ref);
+static void break_out_comdat_types (dw_die_ref);
+static dw_die_ref copy_ancestor_tree (dw_die_ref, dw_die_ref, htab_t);
+static void copy_decls_walk (dw_die_ref, dw_die_ref, htab_t);
+static void copy_decls_for_unworthy_types (dw_die_ref);
+
 static hashval_t htab_cu_hash (const void *);
 static int htab_cu_eq (const void *, const void *);
 static void htab_cu_del (void *);
@@ -5655,6 +6052,7 @@ static void output_die_symbol (dw_die_ref);
 static void output_die (dw_die_ref);
 static void output_compilation_unit_header (void);
 static void output_comp_unit (dw_die_ref, int);
+static void output_comdat_type_unit (comdat_type_node *);
 static const char *dwarf2_name (tree, int);
 static void add_pubname (tree, dw_die_ref);
 static void add_pubname_string (const char *, dw_die_ref);
@@ -5664,7 +6062,8 @@ static void add_arange (tree, dw_die_ref);
 static void output_aranges (void);
 static unsigned int add_ranges_num (int);
 static unsigned int add_ranges (const_tree);
-static unsigned int add_ranges_by_labels (const char *, const char *);
+static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
+                                 bool *);
 static void output_ranges (void);
 static void output_line_info (void);
 static void output_file_names (void);
@@ -5672,6 +6071,8 @@ static dw_die_ref base_type_die (tree);
 static int is_base_type (tree);
 static dw_die_ref subrange_type_die (tree, tree, tree, dw_die_ref);
 static dw_die_ref modified_type_die (tree, int, int, dw_die_ref);
+static dw_die_ref generic_parameter_die (tree, tree, bool, dw_die_ref);
+static dw_die_ref template_parameter_pack_die (tree, tree, dw_die_ref);
 static int type_is_enum (const_tree);
 static unsigned int dbx_reg_number (const_rtx);
 static void add_loc_descr_op_piece (dw_loc_descr_ref *, int);
@@ -5683,13 +6084,15 @@ static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx,
 static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT,
                                         enum var_init_status);
 static int is_based_loc (const_rtx);
+static int resolve_one_addr (rtx *, void *);
 static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode,
                                            enum var_init_status);
 static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
                                               enum var_init_status);
-static dw_loc_descr_ref loc_descriptor (rtx, enum var_init_status);
-static dw_loc_descr_ref loc_descriptor_from_tree_1 (tree, int);
-static dw_loc_descr_ref loc_descriptor_from_tree (tree);
+static dw_loc_descr_ref loc_descriptor (rtx, enum machine_mode mode,
+                                       enum var_init_status);
+static dw_loc_list_ref loc_list_from_tree (tree, int);
+static dw_loc_descr_ref loc_descriptor_from_tree (tree, int);
 static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
 static tree field_type (const_tree);
 static unsigned int simple_type_align_in_bits (const_tree);
@@ -5697,16 +6100,16 @@ static unsigned int simple_decl_align_in_bits (const_tree);
 static unsigned HOST_WIDE_INT simple_type_size_in_bits (const_tree);
 static HOST_WIDE_INT field_byte_offset (const_tree);
 static void add_AT_location_description        (dw_die_ref, enum dwarf_attribute,
-                                        dw_loc_descr_ref);
+                                        dw_loc_list_ref);
 static void add_data_member_location_attribute (dw_die_ref, tree);
-static void add_const_value_attribute (dw_die_ref, rtx);
+static bool add_const_value_attribute (dw_die_ref, rtx);
 static void insert_int (HOST_WIDE_INT, unsigned, unsigned char *);
-static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
 static void insert_float (const_rtx, unsigned char *);
 static rtx rtl_for_decl_location (tree);
-static void add_location_or_const_value_attribute (dw_die_ref, tree,
+static bool add_location_or_const_value_attribute (dw_die_ref, tree,
                                                   enum dwarf_attribute);
-static void tree_add_const_value_attribute (dw_die_ref, tree);
+static bool tree_add_const_value_attribute (dw_die_ref, tree);
+static bool tree_add_const_value_attribute_for_decl (dw_die_ref, tree);
 static void add_name_attribute (dw_die_ref, const char *);
 static void add_comp_dir_attribute (dw_die_ref);
 static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree);
@@ -5738,7 +6141,8 @@ static void gen_descr_array_type_die (tree, struct array_descr_info *, dw_die_re
 static void gen_entry_point_die (tree, dw_die_ref);
 #endif
 static dw_die_ref gen_enumeration_type_die (tree, dw_die_ref);
-static dw_die_ref gen_formal_parameter_die (tree, tree, dw_die_ref);
+static dw_die_ref gen_formal_parameter_die (tree, tree, bool, dw_die_ref);
+static dw_die_ref gen_formal_parameter_pack_die  (tree, tree, dw_die_ref, tree*);
 static void gen_unspecified_parameters_die (tree, dw_die_ref);
 static void gen_formal_types_die (tree, dw_die_ref);
 static void gen_subprogram_die (tree, dw_die_ref);
@@ -5760,6 +6164,7 @@ static void gen_type_die (tree, dw_die_ref);
 static void gen_block_die (tree, dw_die_ref, int);
 static void decls_for_scope (tree, dw_die_ref, int);
 static int is_redundant_typedef (const_tree);
+static inline dw_die_ref get_context_die (tree);
 static void gen_namespace_die (tree, dw_die_ref);
 static void gen_decl_die (tree, tree, dw_die_ref);
 static dw_die_ref force_decl_die (tree);
@@ -5769,13 +6174,11 @@ static dw_die_ref declare_in_namespace (tree, dw_die_ref);
 static struct dwarf_file_data * lookup_filename (const char *);
 static void retry_incomplete_types (void);
 static void gen_type_die_for_member (tree, tree, dw_die_ref);
+static void gen_generic_params_dies (tree);
 static void splice_child_die (dw_die_ref, dw_die_ref);
 static int file_info_cmp (const void *, const void *);
 static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
-                                    const char *, const char *, unsigned);
-static void add_loc_descr_to_loc_list (dw_loc_list_ref *, dw_loc_descr_ref,
-                                      const char *, const char *,
-                                      const char *);
+                                    const char *, const char *);
 static void output_loc_list (dw_loc_list_ref);
 static char *gen_internal_sym (const char *);
 
@@ -5786,6 +6189,8 @@ static void prune_unused_types_walk_attribs (dw_die_ref);
 static void prune_unused_types_prune (dw_die_ref);
 static void prune_unused_types (void);
 static int maybe_emit_file (struct dwarf_file_data *fd);
+static void append_entry_to_tmpl_value_parm_die_table (dw_die_ref, tree);
+static void gen_remaining_tmpl_value_param_die_attribute (void);
 
 /* Section names used to hold DWARF debugging information.  */
 #ifndef DEBUG_INFO_SECTION
@@ -5812,6 +6217,12 @@ static int maybe_emit_file (struct dwarf_file_data *fd);
 #ifndef DEBUG_PUBTYPES_SECTION
 #define DEBUG_PUBTYPES_SECTION ".debug_pubtypes"
 #endif
+#ifndef DEBUG_DCALL_SECTION
+#define DEBUG_DCALL_SECTION    ".debug_dcall"
+#endif
+#ifndef DEBUG_VCALL_SECTION
+#define DEBUG_VCALL_SECTION    ".debug_vcall"
+#endif
 #ifndef DEBUG_STR_SECTION
 #define DEBUG_STR_SECTION      ".debug_str"
 #endif
@@ -6070,6 +6481,16 @@ dwarf_tag_name (unsigned int tag)
       return "DW_TAG_condition";
     case DW_TAG_shared_type:
       return "DW_TAG_shared_type";
+    case DW_TAG_type_unit:
+      return "DW_TAG_type_unit";
+    case DW_TAG_rvalue_reference_type:
+      return "DW_TAG_rvalue_reference_type";
+    case DW_TAG_template_alias:
+      return "DW_TAG_template_alias";
+    case DW_TAG_GNU_template_parameter_pack:
+      return "DW_TAG_GNU_template_parameter_pack";
+    case DW_TAG_GNU_formal_parameter_pack:
+      return "DW_TAG_GNU_formal_parameter_pack";
     case DW_TAG_MIPS_loop:
       return "DW_TAG_MIPS_loop";
     case DW_TAG_format_label:
@@ -6082,6 +6503,8 @@ dwarf_tag_name (unsigned int tag)
       return "DW_TAG_GNU_BINCL";
     case DW_TAG_GNU_EINCL:
       return "DW_TAG_GNU_EINCL";
+    case DW_TAG_GNU_template_template_param:
+      return "DW_TAG_GNU_template_template_param";
     default:
       return "DW_TAG_<unknown>";
     }
@@ -6246,6 +6669,19 @@ dwarf_attr_name (unsigned int attr)
     case DW_AT_call_line:
       return "DW_AT_call_line";
 
+    case DW_AT_signature:
+      return "DW_AT_signature";
+    case DW_AT_main_subprogram:
+      return "DW_AT_main_subprogram";
+    case DW_AT_data_bit_offset:
+      return "DW_AT_data_bit_offset";
+    case DW_AT_const_expr:
+      return "DW_AT_const_expr";
+    case DW_AT_enum_class:
+      return "DW_AT_enum_class";
+    case DW_AT_linkage_name:
+      return "DW_AT_linkage_name";
+
     case DW_AT_MIPS_fde:
       return "DW_AT_MIPS_fde";
     case DW_AT_MIPS_loop_begin:
@@ -6283,6 +6719,24 @@ dwarf_attr_name (unsigned int attr)
       return "DW_AT_body_end";
     case DW_AT_GNU_vector:
       return "DW_AT_GNU_vector";
+    case DW_AT_GNU_guarded_by:
+      return "DW_AT_GNU_guarded_by";
+    case DW_AT_GNU_pt_guarded_by:
+      return "DW_AT_GNU_pt_guarded_by";
+    case DW_AT_GNU_guarded:
+      return "DW_AT_GNU_guarded";
+    case DW_AT_GNU_pt_guarded:
+      return "DW_AT_GNU_pt_guarded";
+    case DW_AT_GNU_locks_excluded:
+      return "DW_AT_GNU_locks_excluded";
+    case DW_AT_GNU_exclusive_locks_required:
+      return "DW_AT_GNU_exclusive_locks_required";
+    case DW_AT_GNU_shared_locks_required:
+      return "DW_AT_GNU_shared_locks_required";
+    case DW_AT_GNU_odr_signature:
+      return "DW_AT_GNU_odr_signature";
+    case DW_AT_GNU_template_name:
+      return "DW_AT_GNU_template_name";
 
     case DW_AT_VMS_rtnbeg_pd_address:
       return "DW_AT_VMS_rtnbeg_pd_address";
@@ -6341,6 +6795,14 @@ dwarf_form_name (unsigned int form)
       return "DW_FORM_ref_udata";
     case DW_FORM_indirect:
       return "DW_FORM_indirect";
+    case DW_FORM_sec_offset:
+      return "DW_FORM_sec_offset";
+    case DW_FORM_exprloc:
+      return "DW_FORM_exprloc";
+    case DW_FORM_flag_present:
+      return "DW_FORM_flag_present";
+    case DW_FORM_ref_sig8:
+      return "DW_FORM_ref_sig8";
     default:
       return "DW_FORM_<unknown>";
     }
@@ -6476,15 +6938,15 @@ AT_unsigned (dw_attr_ref a)
 /* Add an unsigned double integer attribute value to a DIE.  */
 
 static inline void
-add_AT_long_long (dw_die_ref die, enum dwarf_attribute attr_kind,
-                 long unsigned int val_hi, long unsigned int val_low)
+add_AT_double (dw_die_ref die, enum dwarf_attribute attr_kind,
+              HOST_WIDE_INT high, unsigned HOST_WIDE_INT low)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_long_long;
-  attr.dw_attr_val.v.val_long_long.hi = val_hi;
-  attr.dw_attr_val.v.val_long_long.low = val_low;
+  attr.dw_attr_val.val_class = dw_val_class_const_double;
+  attr.dw_attr_val.v.val_double.high = high;
+  attr.dw_attr_val.v.val_double.low = low;
   add_dwarf_attr (die, &attr);
 }
 
@@ -6504,6 +6966,20 @@ add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind,
   add_dwarf_attr (die, &attr);
 }
 
+/* Add an 8-byte data attribute value to a DIE.  */
+
+static inline void
+add_AT_data8 (dw_die_ref die, enum dwarf_attribute attr_kind,
+              unsigned char data8[8])
+{
+  dw_attr_node attr;
+
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_data8;
+  memcpy (attr.dw_attr_val.v.val_data8, data8, 8);
+  add_dwarf_attr (die, &attr);
+}
+
 /* Hash and equality functions for debug_str_hash.  */
 
 static hashval_t
@@ -6519,6 +6995,8 @@ debug_str_eq (const void *x1, const void *x2)
                 (const char *)x2) == 0;
 }
 
+/* Add STR to the indirect string hash table.  */
+
 static struct indirect_string_node *
 find_AT_string (const char *str)
 {
@@ -6561,6 +7039,37 @@ add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str)
   add_dwarf_attr (die, &attr);
 }
 
+/* Create a label for an indirect string node, ensuring it is going to
+   be output, unless its reference count goes down to zero.  */
+
+static inline void
+gen_label_for_indirect_string (struct indirect_string_node *node)
+{
+  char label[32];
+
+  if (node->label)
+    return;
+
+  ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+  ++dw2_string_counter;
+  node->label = xstrdup (label);
+}
+
+/* Create a SYMBOL_REF rtx whose value is the initial address of a
+   debug string STR.  */
+
+static inline rtx
+get_debug_string_label (const char *str)
+{
+  struct indirect_string_node *node = find_AT_string (str);
+
+  debug_str_hash_forced = true;
+
+  gen_label_for_indirect_string (node);
+
+  return gen_rtx_SYMBOL_REF (Pmode, node->label);
+}
+
 static inline const char *
 AT_string (dw_attr_ref a)
 {
@@ -6576,7 +7085,6 @@ AT_string_form (dw_attr_ref a)
 {
   struct indirect_string_node *node;
   unsigned int len;
-  char label[32];
 
   gcc_assert (a && AT_class (a) == dw_val_class_str);
 
@@ -6594,13 +7102,12 @@ AT_string_form (dw_attr_ref a)
   /* If we cannot expect the linker to merge strings in .debug_str
      section, only put it into .debug_str if it is worth even in this
      single module.  */
-  if ((debug_str_section->common.flags & SECTION_MERGE) == 0
-      && (len - DWARF_OFFSET_SIZE) * node->refcount <= len)
+  if (DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
+      || ((debug_str_section->common.flags & SECTION_MERGE) == 0
+      && (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);
+  gen_label_for_indirect_string (node);
 
   return node->form = DW_FORM_strp;
 }
@@ -6705,6 +7212,13 @@ AT_loc_list (dw_attr_ref a)
   return a->dw_attr_val.v.val_loc_list;
 }
 
+static inline dw_loc_list_ref *
+AT_loc_list_ptr (dw_attr_ref a)
+{
+  gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
+  return &a->dw_attr_val.v.val_loc_list;
+}
+
 /* Add an address constant attribute value to a DIE.  */
 
 static inline void
@@ -7026,6 +7540,43 @@ remove_child_with_prev (dw_die_ref child, dw_die_ref prev)
     child->die_parent->die_child = prev;
 }
 
+/* Replace OLD_CHILD with NEW_CHILD.  PREV must have the property that
+   PREV->DIE_SIB == OLD_CHILD.  Does not alter OLD_CHILD.  */
+
+static void
+replace_child (dw_die_ref old_child, dw_die_ref new_child, dw_die_ref prev)
+{
+  dw_die_ref parent = old_child->die_parent;
+
+  gcc_assert (parent == prev->die_parent);
+  gcc_assert (prev->die_sib == old_child);
+
+  new_child->die_parent = parent;
+  if (prev == old_child)
+    {
+      gcc_assert (parent->die_child == old_child);
+      new_child->die_sib = new_child;
+    }
+  else
+    {
+      prev->die_sib = new_child;
+      new_child->die_sib = old_child->die_sib;
+    }
+  if (old_child->die_parent->die_child == old_child)
+    old_child->die_parent->die_child = new_child;
+}
+
+/* Move all children from OLD_PARENT to NEW_PARENT.  */
+
+static void
+move_all_children (dw_die_ref old_parent, dw_die_ref new_parent)
+{
+  dw_die_ref c;
+  new_parent->die_child = old_parent->die_child;
+  old_parent->die_child = NULL;
+  FOR_EACH_CHILD (new_parent, c, c->die_parent = new_parent);
+}
+
 /* Remove child DIE whose die_tag is TAG.  Do nothing if no child
    matches TAG.  */
 
@@ -7190,6 +7741,8 @@ decl_loc_table_eq (const void *x, const void *y)
 static inline var_loc_list *
 lookup_decl_loc (const_tree decl)
 {
+  if (!decl_loc_table)
+    return NULL;
   return (var_loc_list *)
     htab_find_with_hash (decl_loc_table, decl, DECL_UID (decl));
 }
@@ -7245,8 +7798,7 @@ add_var_loc_to_decl (tree decl, struct var_loc_node *loc)
          temp->last = loc;
        }
     }
-  /* Do not add empty location to the beginning of the list.  */
-  else if (NOTE_VAR_LOCATION_LOC (loc->var_loc_note) != NULL_RTX)
+  else
     {
       temp->first = loc;
       temp->last = loc;
@@ -7266,6 +7818,17 @@ print_spaces (FILE *outfile)
   fprintf (outfile, "%*s", print_indent, "");
 }
 
+/* Print a type signature in hex.  */
+
+static inline void
+print_signature (FILE *outfile, char *sig)
+{
+  int i;
+
+  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+    fprintf (outfile, "%02x", sig[i] & 0xff);
+}
+
 /* Print the information associated with a given DIE, and its children.
    This routine is a debugging aid only.  */
 
@@ -7282,6 +7845,13 @@ print_die (dw_die_ref die, FILE *outfile)
   print_spaces (outfile);
   fprintf (outfile, "  abbrev id: %lu", die->die_abbrev);
   fprintf (outfile, " offset: %ld\n", die->die_offset);
+  if (dwarf_version >= 4 && die->die_id.die_type_node)
+    {
+      print_spaces (outfile);
+      fprintf (outfile, "  signature: ");
+      print_signature (outfile, die->die_id.die_type_node->signature);
+      fprintf (outfile, "\n");
+    }
 
   for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
     {
@@ -7312,10 +7882,11 @@ print_die (dw_die_ref die, FILE *outfile)
        case dw_val_class_unsigned_const:
          fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, AT_unsigned (a));
          break;
-       case dw_val_class_long_long:
-         fprintf (outfile, "constant (%lu,%lu)",
-                  a->dw_attr_val.v.val_long_long.hi,
-                  a->dw_attr_val.v.val_long_long.low);
+       case dw_val_class_const_double:
+         fprintf (outfile, "constant ("HOST_WIDE_INT_PRINT_DEC","\
+                           HOST_WIDE_INT_PRINT_UNSIGNED")",
+                  a->dw_attr_val.v.val_double.high,
+                  a->dw_attr_val.v.val_double.low);
          break;
        case dw_val_class_vec:
          fprintf (outfile, "floating-point or vector constant");
@@ -7326,8 +7897,15 @@ print_die (dw_die_ref die, FILE *outfile)
        case dw_val_class_die_ref:
          if (AT_ref (a) != NULL)
            {
-             if (AT_ref (a)->die_symbol)
-               fprintf (outfile, "die -> label: %s", AT_ref (a)->die_symbol);
+             if (dwarf_version >= 4 && AT_ref (a)->die_id.die_type_node)
+               {
+                 fprintf (outfile, "die -> signature: ");
+                 print_signature (outfile,
+                                  AT_ref (a)->die_id.die_type_node->signature);
+                }
+             else if (dwarf_version < 4 && AT_ref (a)->die_id.die_symbol)
+               fprintf (outfile, "die -> label: %s",
+                        AT_ref (a)->die_id.die_symbol);
              else
                fprintf (outfile, "die -> %ld", AT_ref (a)->die_offset);
            }
@@ -7349,6 +7927,14 @@ print_die (dw_die_ref die, FILE *outfile)
          fprintf (outfile, "\"%s\" (%d)", AT_file (a)->filename,
                   AT_file (a)->emitted_number);
          break;
+       case dw_val_class_data8:
+         {
+           int i;
+
+            for (i = 0; i < 8; i++)
+              fprintf (outfile, "%02x", a->dw_attr_val.v.val_data8[i]);
+           break;
+          }
        default:
          break;
        }
@@ -7471,8 +8057,8 @@ attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
     case dw_val_class_unsigned_const:
       CHECKSUM (at->dw_attr_val.v.val_unsigned);
       break;
-    case dw_val_class_long_long:
-      CHECKSUM (at->dw_attr_val.v.val_long_long);
+    case dw_val_class_const_double:
+      CHECKSUM (at->dw_attr_val.v.val_double);
       break;
     case dw_val_class_vec:
       CHECKSUM (at->dw_attr_val.v.val_vec);
@@ -7513,6 +8099,10 @@ attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
       CHECKSUM_STRING (AT_file (at)->filename);
       break;
 
+    case dw_val_class_data8:
+      CHECKSUM (at->dw_attr_val.v.val_data8);
+      break;
+
     default:
       break;
     }
@@ -7546,24 +8136,644 @@ die_checksum (dw_die_ref die, struct md5_ctx *ctx, int *mark)
 #undef CHECKSUM
 #undef CHECKSUM_STRING
 
-/* Do the location expressions look same?  */
-static inline int
-same_loc_p (dw_loc_descr_ref loc1, dw_loc_descr_ref loc2, int *mark)
+/* For DWARF-4 types, include the trailing NULL when checksumming strings.  */
+#define CHECKSUM(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx)
+#define CHECKSUM_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO) + 1, ctx)
+#define CHECKSUM_SLEB128(FOO) checksum_sleb128 ((FOO), ctx)
+#define CHECKSUM_ULEB128(FOO) checksum_uleb128 ((FOO), ctx)
+#define CHECKSUM_ATTR(FOO) \
+  if (FOO) attr_checksum_ordered (die->die_tag, (FOO), ctx, mark)
+
+/* Calculate the checksum of a number in signed LEB128 format.  */
+
+static void
+checksum_sleb128 (HOST_WIDE_INT value, struct md5_ctx *ctx)
 {
-  return loc1->dw_loc_opc == loc2->dw_loc_opc
-        && same_dw_val_p (&loc1->dw_loc_oprnd1, &loc2->dw_loc_oprnd1, mark)
-        && same_dw_val_p (&loc1->dw_loc_oprnd2, &loc2->dw_loc_oprnd2, mark);
+  unsigned char byte;
+  bool more;
+
+  while (1)
+    {
+      byte = (value & 0x7f);
+      value >>= 7;
+      more = !((value == 0 && (byte & 0x40) == 0)
+               || (value == -1 && (byte & 0x40) != 0));
+      if (more)
+       byte |= 0x80;
+      CHECKSUM (byte);
+      if (!more)
+       break;
+    }
 }
 
-/* Do the values look the same?  */
-static int
-same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
+/* Calculate the checksum of a number in unsigned LEB128 format.  */
+
+static void
+checksum_uleb128 (unsigned HOST_WIDE_INT value, struct md5_ctx *ctx)
 {
-  dw_loc_descr_ref loc1, loc2;
-  rtx r1, r2;
+  while (1)
+    {
+      unsigned char byte = (value & 0x7f);
+      value >>= 7;
+      if (value != 0)
+       /* More bytes to follow.  */
+       byte |= 0x80;
+      CHECKSUM (byte);
+      if (value == 0)
+       break;
+    }
+}
 
-  if (v1->val_class != v2->val_class)
-    return 0;
+/* Checksum the context of the DIE.  This adds the names of any
+   surrounding namespaces or structures to the checksum.  */
+
+static void
+checksum_die_context (dw_die_ref die, struct md5_ctx *ctx)
+{
+  const char *name;
+  dw_die_ref spec;
+  int tag = die->die_tag;
+
+  if (tag != DW_TAG_namespace
+      && tag != DW_TAG_structure_type
+      && tag != DW_TAG_class_type)
+    return;
+
+  name = get_AT_string (die, DW_AT_name);
+
+  spec = get_AT_ref (die, DW_AT_specification);
+  if (spec != NULL)
+    die = spec;
+
+  if (die->die_parent != NULL)
+    checksum_die_context (die->die_parent, ctx);
+
+  CHECKSUM_ULEB128 ('C');
+  CHECKSUM_ULEB128 (tag);
+  if (name != NULL)
+    CHECKSUM_STRING (name);
+}
+
+/* Calculate the checksum of a location expression.  */
+
+static inline void
+loc_checksum_ordered (dw_loc_descr_ref loc, struct md5_ctx *ctx)
+{
+  /* Special case for lone DW_OP_plus_uconst: checksum as if the location
+     were emitted as a DW_FORM_sdata instead of a location expression.  */
+  if (loc->dw_loc_opc == DW_OP_plus_uconst && loc->dw_loc_next == NULL)
+    {
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_SLEB128 ((HOST_WIDE_INT) loc->dw_loc_oprnd1.v.val_unsigned);
+      return;
+    }
+
+  /* Otherwise, just checksum the raw location expression.  */
+  while (loc != NULL)
+    {
+      CHECKSUM_ULEB128 (loc->dw_loc_opc);
+      CHECKSUM (loc->dw_loc_oprnd1);
+      CHECKSUM (loc->dw_loc_oprnd2);
+      loc = loc->dw_loc_next;
+    }
+}
+
+/* Calculate the checksum of an attribute.  */
+
+static void
+attr_checksum_ordered (enum dwarf_tag tag, dw_attr_ref at,
+                      struct md5_ctx *ctx, int *mark)
+{
+  dw_loc_descr_ref loc;
+  rtx r;
+
+  if (AT_class (at) == dw_val_class_die_ref)
+    {
+      dw_die_ref target_die = AT_ref (at);
+
+      /* For pointer and reference types, we checksum only the (qualified)
+        name of the target type (if there is a name).  For friend entries,
+        we checksum only the (qualified) name of the target type or function.
+        This allows the checksum to remain the same whether the target type
+        is complete or not.  */
+      if ((at->dw_attr == DW_AT_type
+          && (tag == DW_TAG_pointer_type
+              || tag == DW_TAG_reference_type
+              || tag == DW_TAG_ptr_to_member_type))
+         || (at->dw_attr == DW_AT_friend
+             && tag == DW_TAG_friend))
+       {
+         dw_attr_ref name_attr = get_AT (target_die, DW_AT_name);
+
+         if (name_attr != NULL)
+           {
+             dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification);
+
+             if (decl == NULL)
+               decl = target_die;
+             CHECKSUM_ULEB128 ('N');
+             CHECKSUM_ULEB128 (at->dw_attr);
+             if (decl->die_parent != NULL)
+               checksum_die_context (decl->die_parent, ctx);
+             CHECKSUM_ULEB128 ('E');
+             CHECKSUM_STRING (AT_string (name_attr));
+             return;
+           }
+       }
+
+      /* For all other references to another DIE, we check to see if the
+         target DIE has already been visited.  If it has, we emit a
+         backward reference; if not, we descend recursively.  */
+      if (target_die->die_mark > 0)
+        {
+         CHECKSUM_ULEB128 ('R');
+         CHECKSUM_ULEB128 (at->dw_attr);
+         CHECKSUM_ULEB128 (target_die->die_mark);
+        }
+      else
+        {
+         dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification);
+
+         if (decl == NULL)
+           decl = target_die;
+         target_die->die_mark = ++(*mark);
+         CHECKSUM_ULEB128 ('T');
+         CHECKSUM_ULEB128 (at->dw_attr);
+         if (decl->die_parent != NULL)
+           checksum_die_context (decl->die_parent, ctx);
+         die_checksum_ordered (target_die, ctx, mark);
+        }
+      return;
+    }
+
+  CHECKSUM_ULEB128 ('A');
+  CHECKSUM_ULEB128 (at->dw_attr);
+
+  switch (AT_class (at))
+    {
+    case dw_val_class_const:
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_SLEB128 (at->dw_attr_val.v.val_int);
+      break;
+
+    case dw_val_class_unsigned_const:
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_SLEB128 ((int) at->dw_attr_val.v.val_unsigned);
+      break;
+
+    case dw_val_class_const_double:
+      CHECKSUM_ULEB128 (DW_FORM_block);
+      CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_double));
+      CHECKSUM (at->dw_attr_val.v.val_double);
+      break;
+
+    case dw_val_class_vec:
+      CHECKSUM_ULEB128 (DW_FORM_block);
+      CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_vec));
+      CHECKSUM (at->dw_attr_val.v.val_vec);
+      break;
+
+    case dw_val_class_flag:
+      CHECKSUM_ULEB128 (DW_FORM_flag);
+      CHECKSUM_ULEB128 (at->dw_attr_val.v.val_flag ? 1 : 0);
+      break;
+
+    case dw_val_class_str:
+      CHECKSUM_ULEB128 (DW_FORM_string);
+      CHECKSUM_STRING (AT_string (at));
+      break;
+
+    case dw_val_class_addr:
+      r = AT_addr (at);
+      gcc_assert (GET_CODE (r) == SYMBOL_REF);
+      CHECKSUM_ULEB128 (DW_FORM_string);
+      CHECKSUM_STRING (XSTR (r, 0));
+      break;
+
+    case dw_val_class_offset:
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_ULEB128 (at->dw_attr_val.v.val_offset);
+      break;
+
+    case dw_val_class_loc:
+      for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
+       loc_checksum_ordered (loc, ctx);
+      break;
+
+    case dw_val_class_fde_ref:
+    case dw_val_class_lbl_id:
+    case dw_val_class_lineptr:
+    case dw_val_class_macptr:
+      break;
+
+    case dw_val_class_file:
+      CHECKSUM_ULEB128 (DW_FORM_string);
+      CHECKSUM_STRING (AT_file (at)->filename);
+      break;
+
+    case dw_val_class_data8:
+      CHECKSUM (at->dw_attr_val.v.val_data8);
+      break;
+
+    default:
+      break;
+    }
+}
+
+struct checksum_attributes
+{
+  dw_attr_ref at_name;
+  dw_attr_ref at_type;
+  dw_attr_ref at_friend;
+  dw_attr_ref at_accessibility;
+  dw_attr_ref at_address_class;
+  dw_attr_ref at_allocated;
+  dw_attr_ref at_artificial;
+  dw_attr_ref at_associated;
+  dw_attr_ref at_binary_scale;
+  dw_attr_ref at_bit_offset;
+  dw_attr_ref at_bit_size;
+  dw_attr_ref at_bit_stride;
+  dw_attr_ref at_byte_size;
+  dw_attr_ref at_byte_stride;
+  dw_attr_ref at_const_value;
+  dw_attr_ref at_containing_type;
+  dw_attr_ref at_count;
+  dw_attr_ref at_data_location;
+  dw_attr_ref at_data_member_location;
+  dw_attr_ref at_decimal_scale;
+  dw_attr_ref at_decimal_sign;
+  dw_attr_ref at_default_value;
+  dw_attr_ref at_digit_count;
+  dw_attr_ref at_discr;
+  dw_attr_ref at_discr_list;
+  dw_attr_ref at_discr_value;
+  dw_attr_ref at_encoding;
+  dw_attr_ref at_endianity;
+  dw_attr_ref at_explicit;
+  dw_attr_ref at_is_optional;
+  dw_attr_ref at_location;
+  dw_attr_ref at_lower_bound;
+  dw_attr_ref at_mutable;
+  dw_attr_ref at_ordering;
+  dw_attr_ref at_picture_string;
+  dw_attr_ref at_prototyped;
+  dw_attr_ref at_small;
+  dw_attr_ref at_segment;
+  dw_attr_ref at_string_length;
+  dw_attr_ref at_threads_scaled;
+  dw_attr_ref at_upper_bound;
+  dw_attr_ref at_use_location;
+  dw_attr_ref at_use_UTF8;
+  dw_attr_ref at_variable_parameter;
+  dw_attr_ref at_virtuality;
+  dw_attr_ref at_visibility;
+  dw_attr_ref at_vtable_elem_location;
+};
+
+/* Collect the attributes that we will want to use for the checksum.  */
+
+static void
+collect_checksum_attributes (struct checksum_attributes *attrs, dw_die_ref die)
+{
+  dw_attr_ref a;
+  unsigned ix;
+
+  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+    {
+      switch (a->dw_attr)
+        {
+        case DW_AT_name:
+          attrs->at_name = a;
+          break;
+        case DW_AT_type:
+          attrs->at_type = a;
+          break;
+        case DW_AT_friend:
+          attrs->at_friend = a;
+          break;
+        case DW_AT_accessibility:
+          attrs->at_accessibility = a;
+          break;
+        case DW_AT_address_class:
+          attrs->at_address_class = a;
+          break;
+        case DW_AT_allocated:
+          attrs->at_allocated = a;
+          break;
+        case DW_AT_artificial:
+          attrs->at_artificial = a;
+          break;
+        case DW_AT_associated:
+          attrs->at_associated = a;
+          break;
+        case DW_AT_binary_scale:
+          attrs->at_binary_scale = a;
+          break;
+        case DW_AT_bit_offset:
+          attrs->at_bit_offset = a;
+          break;
+        case DW_AT_bit_size:
+          attrs->at_bit_size = a;
+          break;
+        case DW_AT_bit_stride:
+          attrs->at_bit_stride = a;
+          break;
+        case DW_AT_byte_size:
+          attrs->at_byte_size = a;
+          break;
+        case DW_AT_byte_stride:
+          attrs->at_byte_stride = a;
+          break;
+        case DW_AT_const_value:
+          attrs->at_const_value = a;
+          break;
+        case DW_AT_containing_type:
+          attrs->at_containing_type = a;
+          break;
+        case DW_AT_count:
+          attrs->at_count = a;
+          break;
+        case DW_AT_data_location:
+          attrs->at_data_location = a;
+          break;
+        case DW_AT_data_member_location:
+          attrs->at_data_member_location = a;
+          break;
+        case DW_AT_decimal_scale:
+          attrs->at_decimal_scale = a;
+          break;
+        case DW_AT_decimal_sign:
+          attrs->at_decimal_sign = a;
+          break;
+        case DW_AT_default_value:
+          attrs->at_default_value = a;
+          break;
+        case DW_AT_digit_count:
+          attrs->at_digit_count = a;
+          break;
+        case DW_AT_discr:
+          attrs->at_discr = a;
+          break;
+        case DW_AT_discr_list:
+          attrs->at_discr_list = a;
+          break;
+        case DW_AT_discr_value:
+          attrs->at_discr_value = a;
+          break;
+        case DW_AT_encoding:
+          attrs->at_encoding = a;
+          break;
+        case DW_AT_endianity:
+          attrs->at_endianity = a;
+          break;
+        case DW_AT_explicit:
+          attrs->at_explicit = a;
+          break;
+        case DW_AT_is_optional:
+          attrs->at_is_optional = a;
+          break;
+        case DW_AT_location:
+          attrs->at_location = a;
+          break;
+        case DW_AT_lower_bound:
+          attrs->at_lower_bound = a;
+          break;
+        case DW_AT_mutable:
+          attrs->at_mutable = a;
+          break;
+        case DW_AT_ordering:
+          attrs->at_ordering = a;
+          break;
+        case DW_AT_picture_string:
+          attrs->at_picture_string = a;
+          break;
+        case DW_AT_prototyped:
+          attrs->at_prototyped = a;
+          break;
+        case DW_AT_small:
+          attrs->at_small = a;
+          break;
+        case DW_AT_segment:
+          attrs->at_segment = a;
+          break;
+        case DW_AT_string_length:
+          attrs->at_string_length = a;
+          break;
+        case DW_AT_threads_scaled:
+          attrs->at_threads_scaled = a;
+          break;
+        case DW_AT_upper_bound:
+          attrs->at_upper_bound = a;
+          break;
+        case DW_AT_use_location:
+          attrs->at_use_location = a;
+          break;
+        case DW_AT_use_UTF8:
+          attrs->at_use_UTF8 = a;
+          break;
+        case DW_AT_variable_parameter:
+          attrs->at_variable_parameter = a;
+          break;
+        case DW_AT_virtuality:
+          attrs->at_virtuality = a;
+          break;
+        case DW_AT_visibility:
+          attrs->at_visibility = a;
+          break;
+        case DW_AT_vtable_elem_location:
+          attrs->at_vtable_elem_location = a;
+          break;
+        default:
+          break;
+        }
+    }
+}
+
+/* Calculate the checksum of a DIE, using an ordered subset of attributes.  */
+
+static void
+die_checksum_ordered (dw_die_ref die, struct md5_ctx *ctx, int *mark)
+{
+  dw_die_ref c;
+  dw_die_ref decl;
+  struct checksum_attributes attrs;
+
+  CHECKSUM_ULEB128 ('D');
+  CHECKSUM_ULEB128 (die->die_tag);
+
+  memset (&attrs, 0, sizeof (attrs));
+
+  decl = get_AT_ref (die, DW_AT_specification);
+  if (decl != NULL)
+    collect_checksum_attributes (&attrs, decl);
+  collect_checksum_attributes (&attrs, die);
+
+  CHECKSUM_ATTR (attrs.at_name);
+  CHECKSUM_ATTR (attrs.at_accessibility);
+  CHECKSUM_ATTR (attrs.at_address_class);
+  CHECKSUM_ATTR (attrs.at_allocated);
+  CHECKSUM_ATTR (attrs.at_artificial);
+  CHECKSUM_ATTR (attrs.at_associated);
+  CHECKSUM_ATTR (attrs.at_binary_scale);
+  CHECKSUM_ATTR (attrs.at_bit_offset);
+  CHECKSUM_ATTR (attrs.at_bit_size);
+  CHECKSUM_ATTR (attrs.at_bit_stride);
+  CHECKSUM_ATTR (attrs.at_byte_size);
+  CHECKSUM_ATTR (attrs.at_byte_stride);
+  CHECKSUM_ATTR (attrs.at_const_value);
+  CHECKSUM_ATTR (attrs.at_containing_type);
+  CHECKSUM_ATTR (attrs.at_count);
+  CHECKSUM_ATTR (attrs.at_data_location);
+  CHECKSUM_ATTR (attrs.at_data_member_location);
+  CHECKSUM_ATTR (attrs.at_decimal_scale);
+  CHECKSUM_ATTR (attrs.at_decimal_sign);
+  CHECKSUM_ATTR (attrs.at_default_value);
+  CHECKSUM_ATTR (attrs.at_digit_count);
+  CHECKSUM_ATTR (attrs.at_discr);
+  CHECKSUM_ATTR (attrs.at_discr_list);
+  CHECKSUM_ATTR (attrs.at_discr_value);
+  CHECKSUM_ATTR (attrs.at_encoding);
+  CHECKSUM_ATTR (attrs.at_endianity);
+  CHECKSUM_ATTR (attrs.at_explicit);
+  CHECKSUM_ATTR (attrs.at_is_optional);
+  CHECKSUM_ATTR (attrs.at_location);
+  CHECKSUM_ATTR (attrs.at_lower_bound);
+  CHECKSUM_ATTR (attrs.at_mutable);
+  CHECKSUM_ATTR (attrs.at_ordering);
+  CHECKSUM_ATTR (attrs.at_picture_string);
+  CHECKSUM_ATTR (attrs.at_prototyped);
+  CHECKSUM_ATTR (attrs.at_small);
+  CHECKSUM_ATTR (attrs.at_segment);
+  CHECKSUM_ATTR (attrs.at_string_length);
+  CHECKSUM_ATTR (attrs.at_threads_scaled);
+  CHECKSUM_ATTR (attrs.at_upper_bound);
+  CHECKSUM_ATTR (attrs.at_use_location);
+  CHECKSUM_ATTR (attrs.at_use_UTF8);
+  CHECKSUM_ATTR (attrs.at_variable_parameter);
+  CHECKSUM_ATTR (attrs.at_virtuality);
+  CHECKSUM_ATTR (attrs.at_visibility);
+  CHECKSUM_ATTR (attrs.at_vtable_elem_location);
+  CHECKSUM_ATTR (attrs.at_type);
+  CHECKSUM_ATTR (attrs.at_friend);
+
+  /* Checksum the child DIEs, except for nested types and member functions.  */
+  c = die->die_child;
+  if (c) do {
+    dw_attr_ref name_attr;
+
+    c = c->die_sib;
+    name_attr = get_AT (c, DW_AT_name);
+    if ((is_type_die (c) || c->die_tag == DW_TAG_subprogram)
+        && name_attr != NULL)
+      {
+        CHECKSUM_ULEB128 ('S');
+        CHECKSUM_ULEB128 (c->die_tag);
+        CHECKSUM_STRING (AT_string (name_attr));
+      }
+    else
+      {
+        /* Mark this DIE so it gets processed when unmarking.  */
+        if (c->die_mark == 0)
+          c->die_mark = -1;
+        die_checksum_ordered (c, ctx, mark);
+      }
+  } while (c != die->die_child);
+
+  CHECKSUM_ULEB128 (0);
+}
+
+#undef CHECKSUM
+#undef CHECKSUM_STRING
+#undef CHECKSUM_ATTR
+#undef CHECKSUM_LEB128
+#undef CHECKSUM_ULEB128
+
+/* Generate the type signature for DIE.  This is computed by generating an
+   MD5 checksum over the DIE's tag, its relevant attributes, and its
+   children.  Attributes that are references to other DIEs are processed
+   by recursion, using the MARK field to prevent infinite recursion.
+   If the DIE is nested inside a namespace or another type, we also
+   need to include that context in the signature.  The lower 64 bits
+   of the resulting MD5 checksum comprise the signature.  */
+
+static void
+generate_type_signature (dw_die_ref die, comdat_type_node *type_node)
+{
+  int mark;
+  const char *name;
+  unsigned char checksum[16];
+  struct md5_ctx ctx;
+  dw_die_ref decl;
+
+  name = get_AT_string (die, DW_AT_name);
+  decl = get_AT_ref (die, DW_AT_specification);
+
+  /* First, compute a signature for just the type name (and its surrounding
+     context, if any.  This is stored in the type unit DIE for link-time
+     ODR (one-definition rule) checking.  */
+
+  if (is_cxx() && name != NULL)
+    {
+      md5_init_ctx (&ctx);
+
+      /* Checksum the names of surrounding namespaces and structures.  */
+      if (decl != NULL && decl->die_parent != NULL)
+        checksum_die_context (decl->die_parent, &ctx);
+
+      md5_process_bytes (&die->die_tag, sizeof (die->die_tag), &ctx);
+      md5_process_bytes (name, strlen (name) + 1, &ctx);
+      md5_finish_ctx (&ctx, checksum);
+
+      add_AT_data8 (type_node->root_die, DW_AT_GNU_odr_signature, &checksum[8]);
+    }
+
+  /* Next, compute the complete type signature.  */
+
+  md5_init_ctx (&ctx);
+  mark = 1;
+  die->die_mark = mark;
+
+  /* Checksum the names of surrounding namespaces and structures.  */
+  if (decl != NULL && decl->die_parent != NULL)
+    checksum_die_context (decl->die_parent, &ctx);
+
+  /* Checksum the DIE and its children.  */
+  die_checksum_ordered (die, &ctx, &mark);
+  unmark_all_dies (die);
+  md5_finish_ctx (&ctx, checksum);
+
+  /* Store the signature in the type node and link the type DIE and the
+     type node together.  */
+  memcpy (type_node->signature, &checksum[16 - DWARF_TYPE_SIGNATURE_SIZE],
+          DWARF_TYPE_SIGNATURE_SIZE);
+  die->die_id.die_type_node = type_node;
+  type_node->type_die = die;
+
+  /* If the DIE is a specification, link its declaration to the type node
+     as well.  */
+  if (decl != NULL)
+    decl->die_id.die_type_node = type_node;
+}
+
+/* Do the location expressions look same?  */
+static inline int
+same_loc_p (dw_loc_descr_ref loc1, dw_loc_descr_ref loc2, int *mark)
+{
+  return loc1->dw_loc_opc == loc2->dw_loc_opc
+        && same_dw_val_p (&loc1->dw_loc_oprnd1, &loc2->dw_loc_oprnd1, mark)
+        && same_dw_val_p (&loc1->dw_loc_oprnd2, &loc2->dw_loc_oprnd2, mark);
+}
+
+/* Do the values look the same?  */
+static int
+same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
+{
+  dw_loc_descr_ref loc1, loc2;
+  rtx r1, r2;
+
+  if (v1->val_class != v2->val_class)
+    return 0;
 
   switch (v1->val_class)
     {
@@ -7571,9 +8781,9 @@ same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
       return v1->v.val_int == v2->v.val_int;
     case dw_val_class_unsigned_const:
       return v1->v.val_unsigned == v2->v.val_unsigned;
-    case dw_val_class_long_long:
-      return v1->v.val_long_long.hi == v2->v.val_long_long.hi
-            && v1->v.val_long_long.low == v2->v.val_long_long.low;
+    case dw_val_class_const_double:
+      return v1->v.val_double.high == v2->v.val_double.high
+            && v1->v.val_double.low == v2->v.val_double.low;
     case dw_val_class_vec:
       if (v1->v.val_vec.length != v2->v.val_vec.length
          || v1->v.val_vec.elt_size != v2->v.val_vec.elt_size)
@@ -7592,8 +8802,7 @@ same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
       r2 = v2->v.val_addr;
       if (GET_CODE (r1) != GET_CODE (r2))
        return 0;
-      gcc_assert (GET_CODE (r1) == SYMBOL_REF);
-      return !strcmp (XSTR (r1, 0), XSTR (r2, 0));
+      return !rtx_equal_p (r1, r2);
 
     case dw_val_class_offset:
       return v1->v.val_offset == v2->v.val_offset;
@@ -7618,6 +8827,9 @@ same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
     case dw_val_class_file:
       return v1->v.val_file == v2->v.val_file;
 
+    case dw_val_class_data8:
+      return !memcmp (v1->v.val_data8, v2->v.val_data8, 8);
+
     default:
       return 1;
     }
@@ -7744,7 +8956,7 @@ compute_section_prefix (dw_die_ref unit_die)
       p += 2;
     }
 
-  comdat_symbol_id = unit_die->die_symbol = xstrdup (name);
+  comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
   comdat_symbol_number = 0;
 }
 
@@ -7816,8 +9028,7 @@ static int
 is_symbol_die (dw_die_ref c)
 {
   return (is_type_die (c)
-         || (get_AT (c, DW_AT_declaration)
-             && !get_AT (c, DW_AT_specification))
+         || is_declaration_die (c)
          || c->die_tag == DW_TAG_namespace
          || c->die_tag == DW_TAG_module);
 }
@@ -7846,10 +9057,10 @@ assign_symbol_names (dw_die_ref die)
 
          sprintf (p, "%s.%s.%x", DIE_LABEL_PREFIX,
                   comdat_symbol_id, comdat_symbol_number++);
-         die->die_symbol = xstrdup (p);
+         die->die_id.die_symbol = xstrdup (p);
        }
       else
-       die->die_symbol = gen_internal_sym ("LDIE");
+       die->die_id.die_symbol = gen_internal_sym ("LDIE");
     }
 
   FOR_EACH_CHILD (die, c, assign_symbol_names (c));
@@ -7869,7 +9080,7 @@ htab_cu_hash (const void *of)
   const struct cu_hash_table_entry *const entry =
     (const struct cu_hash_table_entry *) of;
 
-  return htab_hash_string (entry->cu->die_symbol);
+  return htab_hash_string (entry->cu->die_id.die_symbol);
 }
 
 static int
@@ -7879,7 +9090,7 @@ htab_cu_eq (const void *of1, const void *of2)
     (const struct cu_hash_table_entry *) of1;
   const struct die_struct *const entry2 = (const struct die_struct *) of2;
 
-  return !strcmp (entry1->cu->die_symbol, entry2->die_symbol);
+  return !strcmp (entry1->cu->die_id.die_symbol, entry2->die_id.die_symbol);
 }
 
 static void
@@ -7907,7 +9118,7 @@ check_duplicate_cu (dw_die_ref cu, htab_t htable, unsigned int *sym_num)
   dummy.max_comdat_num = 0;
 
   slot = (struct cu_hash_table_entry **)
-    htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol),
+    htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_id.die_symbol),
        INSERT);
   entry = *slot;
 
@@ -7939,7 +9150,7 @@ record_comdat_symbol_number (dw_die_ref cu, htab_t htable, unsigned int sym_num)
   struct cu_hash_table_entry **slot, *entry;
 
   slot = (struct cu_hash_table_entry **)
-    htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol),
+    htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_id.die_symbol),
        NO_INSERT);
   entry = *slot;
 
@@ -8012,2442 +9223,4311 @@ break_out_includes (dw_die_ref die)
   htab_delete (cu_hash_table);
 }
 
-/* Traverse the DIE and add a sibling attribute if it may have the
-   effect of speeding up access to siblings.  To save some space,
-   avoid generating sibling attributes for DIE's without children.  */
-
-static void
-add_sibling_attributes (dw_die_ref die)
-{
-  dw_die_ref c;
-
-  if (! die->die_child)
-    return;
-
-  if (die->die_parent && die != die->die_parent->die_child)
-    add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
-
-  FOR_EACH_CHILD (die, c, add_sibling_attributes (c));
-}
-
-/* Output all location lists for the DIE and its children.  */
+/* Return non-zero if this DIE is a declaration.  */
 
-static void
-output_location_lists (dw_die_ref die)
+static int
+is_declaration_die (dw_die_ref die)
 {
-  dw_die_ref c;
   dw_attr_ref a;
   unsigned ix;
 
   for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    if (AT_class (a) == dw_val_class_loc_list)
-      output_loc_list (AT_loc_list (a));
+    if (a->dw_attr == DW_AT_declaration)
+      return 1;
 
-  FOR_EACH_CHILD (die, c, output_location_lists (c));
+  return 0;
 }
 
-/* The format of each DIE (and its attribute value pairs) is encoded in an
-   abbreviation table.  This routine builds the abbreviation table and assigns
-   a unique abbreviation id for each abbreviation entry.  The children of each
-   die are visited recursively.  */
+/* Return non-zero if this is a type DIE that should be moved to a
+   COMDAT .debug_types section.  */
 
-static void
-build_abbrev_table (dw_die_ref die)
+static int
+should_move_die_to_comdat (dw_die_ref die)
 {
-  unsigned long abbrev_id;
-  unsigned int n_alloc;
-  dw_die_ref c;
-  dw_attr_ref a;
-  unsigned ix;
-
-  /* Scan the DIE references, and mark as external any that refer to
-     DIEs from other CUs (i.e. those which are not marked).  */
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    if (AT_class (a) == dw_val_class_die_ref
-       && AT_ref (a)->die_mark == 0)
-      {
-       gcc_assert (AT_ref (a)->die_symbol);
-       set_AT_ref_external (a, 1);
-      }
-
-  for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+  switch (die->die_tag)
     {
-      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
-      dw_attr_ref die_a, abbrev_a;
-      unsigned ix;
-      bool ok = true;
-
-      if (abbrev->die_tag != die->die_tag)
-       continue;
-      if ((abbrev->die_child != NULL) != (die->die_child != NULL))
-       continue;
-
-      if (VEC_length (dw_attr_node, abbrev->die_attr)
-         != VEC_length (dw_attr_node, die->die_attr))
-       continue;
-
-      for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, die_a); ix++)
-       {
-         abbrev_a = VEC_index (dw_attr_node, abbrev->die_attr, ix);
-         if ((abbrev_a->dw_attr != die_a->dw_attr)
-             || (value_format (abbrev_a) != value_format (die_a)))
-           {
-             ok = false;
-             break;
-           }
-       }
-      if (ok)
-       break;
+    case DW_TAG_class_type:
+    case DW_TAG_structure_type:
+    case DW_TAG_enumeration_type:
+    case DW_TAG_union_type:
+      /* Don't move declarations or inlined instances.  */
+      if (is_declaration_die (die) || get_AT (die, DW_AT_abstract_origin))
+        return 0;
+      return 1;
+    case DW_TAG_array_type:
+    case DW_TAG_interface_type:
+    case DW_TAG_pointer_type:
+    case DW_TAG_reference_type:
+    case DW_TAG_string_type:
+    case DW_TAG_subroutine_type:
+    case DW_TAG_ptr_to_member_type:
+    case DW_TAG_set_type:
+    case DW_TAG_subrange_type:
+    case DW_TAG_base_type:
+    case DW_TAG_const_type:
+    case DW_TAG_file_type:
+    case DW_TAG_packed_type:
+    case DW_TAG_volatile_type:
+    case DW_TAG_typedef:
+    default:
+      return 0;
     }
+}
 
-  if (abbrev_id >= abbrev_die_table_in_use)
-    {
-      if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
-       {
-         n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
-         abbrev_die_table = GGC_RESIZEVEC (dw_die_ref, abbrev_die_table,
-                                           n_alloc);
+/* Make a clone of DIE.  */
 
-         memset (&abbrev_die_table[abbrev_die_table_allocated], 0,
-                (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
-         abbrev_die_table_allocated = n_alloc;
-       }
+static dw_die_ref
+clone_die (dw_die_ref die)
+{
+  dw_die_ref clone;
+  dw_attr_ref a;
+  unsigned ix;
 
-      ++abbrev_die_table_in_use;
-      abbrev_die_table[abbrev_id] = die;
-    }
+  clone = GGC_CNEW (die_node);
+  clone->die_tag = die->die_tag;
 
-  die->die_abbrev = abbrev_id;
-  FOR_EACH_CHILD (die, c, build_abbrev_table (c));
+  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+    add_dwarf_attr (clone, a);
+
+  return clone;
 }
-\f
-/* Return the power-of-two number of bytes necessary to represent VALUE.  */
 
-static int
-constant_size (unsigned HOST_WIDE_INT value)
-{
-  int log;
+/* Make a clone of the tree rooted at DIE.  */
 
-  if (value == 0)
-    log = 0;
-  else
-    log = floor_log2 (value);
+static dw_die_ref
+clone_tree (dw_die_ref die)
+{
+  dw_die_ref c;
+  dw_die_ref clone = clone_die (die);
 
-  log = log / 8;
-  log = 1 << (floor_log2 (log) + 1);
+  FOR_EACH_CHILD (die, c, add_child_die (clone, clone_tree(c)));
 
-  return log;
+  return clone;
 }
 
-/* Return the size of a DIE as it is represented in the
-   .debug_info section.  */
+/* Make a clone of DIE as a declaration.  */
 
-static unsigned long
-size_of_die (dw_die_ref die)
+static dw_die_ref
+clone_as_declaration (dw_die_ref die)
 {
-  unsigned long size = 0;
+  dw_die_ref clone;
+  dw_die_ref decl;
   dw_attr_ref a;
   unsigned ix;
 
-  size += size_of_uleb128 (die->die_abbrev);
+  /* If the DIE is already a declaration, just clone it.  */
+  if (is_declaration_die (die))
+    return clone_die (die);
+
+  /* If the DIE is a specification, just clone its declaration DIE.  */
+  decl = get_AT_ref (die, DW_AT_specification);
+  if (decl != NULL)
+    return clone_die (decl);
+
+  clone = GGC_CNEW (die_node);
+  clone->die_tag = die->die_tag;
+
   for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
     {
-      switch (AT_class (a))
-       {
-       case dw_val_class_addr:
-         size += DWARF2_ADDR_SIZE;
-         break;
-       case dw_val_class_offset:
-         size += DWARF_OFFSET_SIZE;
-         break;
-       case dw_val_class_loc:
-         {
-           unsigned long lsize = size_of_locs (AT_loc (a));
+      /* We don't want to copy over all attributes.
+         For example we don't want DW_AT_byte_size because otherwise we will no
+         longer have a declaration and GDB will treat it as a definition.  */
 
-           /* Block length.  */
-           size += constant_size (lsize);
-           size += lsize;
-         }
-         break;
-       case dw_val_class_loc_list:
-         size += DWARF_OFFSET_SIZE;
-         break;
-       case dw_val_class_range_list:
-         size += DWARF_OFFSET_SIZE;
-         break;
-       case dw_val_class_const:
-         size += size_of_sleb128 (AT_int (a));
-         break;
-       case dw_val_class_unsigned_const:
-         size += constant_size (AT_unsigned (a));
-         break;
-       case dw_val_class_long_long:
-         size += 1 + 2*HOST_BITS_PER_LONG/HOST_BITS_PER_CHAR; /* block */
-         break;
-       case dw_val_class_vec:
-         size += constant_size (a->dw_attr_val.v.val_vec.length
-                                * a->dw_attr_val.v.val_vec.elt_size)
-                 + a->dw_attr_val.v.val_vec.length
-                   * a->dw_attr_val.v.val_vec.elt_size; /* block */
-         break;
-       case dw_val_class_flag:
-         size += 1;
-         break;
-       case dw_val_class_die_ref:
-         /* In DWARF2, DW_FORM_ref_addr is sized by target address length,
-            whereas in DWARF3 it's always sized as an offset.  */
-         if (AT_ref_external (a) && dwarf_version == 2)
-           size += DWARF2_ADDR_SIZE;
-         else
-           size += DWARF_OFFSET_SIZE;
-         break;
-       case dw_val_class_fde_ref:
-         size += DWARF_OFFSET_SIZE;
-         break;
-       case dw_val_class_lbl_id:
-         size += DWARF2_ADDR_SIZE;
-         break;
-       case dw_val_class_lineptr:
-       case dw_val_class_macptr:
-         size += DWARF_OFFSET_SIZE;
-         break;
-       case dw_val_class_str:
-         if (AT_string_form (a) == DW_FORM_strp)
-           size += DWARF_OFFSET_SIZE;
-         else
-           size += strlen (a->dw_attr_val.v.val_str->str) + 1;
-         break;
-       case dw_val_class_file:
-         size += constant_size (maybe_emit_file (a->dw_attr_val.v.val_file));
-         break;
-       default:
-         gcc_unreachable ();
-       }
+      switch (a->dw_attr)
+        {
+        case DW_AT_artificial:
+        case DW_AT_containing_type:
+        case DW_AT_external:
+        case DW_AT_name:
+        case DW_AT_type:
+        case DW_AT_virtuality:
+        case DW_AT_MIPS_linkage_name:
+          add_dwarf_attr (clone, a);
+          break;
+        case DW_AT_byte_size:
+        default:
+          break;
+        }
     }
 
-  return size;
+  if (die->die_id.die_type_node)
+    add_AT_die_ref (clone, DW_AT_signature, die);
+
+  add_AT_flag (clone, DW_AT_declaration, 1);
+  return clone;
 }
 
-/* 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
-   die_offset field in each DIE.  */
+/* Copy the declaration context to the new compile unit DIE.  This includes
+   any surrounding namespace or type declarations.  If the DIE has an
+   AT_specification attribute, it also includes attributes and children
+   attached to the specification.  */
 
 static void
-calc_die_sizes (dw_die_ref die)
+copy_declaration_context (dw_die_ref unit, dw_die_ref die)
 {
-  dw_die_ref c;
+  dw_die_ref decl;
+  dw_die_ref new_decl;
 
-  die->die_offset = next_die_offset;
-  next_die_offset += size_of_die (die);
+  decl = get_AT_ref (die, DW_AT_specification);
+  if (decl == NULL)
+    decl = die;
+  else
+    {
+      unsigned ix;
+      dw_die_ref c;
+      dw_attr_ref a;
 
-  FOR_EACH_CHILD (die, c, calc_die_sizes (c));
+      /* Copy the type node pointer from the new DIE to the original
+         declaration DIE so we can forward references later.  */
+      decl->die_id.die_type_node = die->die_id.die_type_node;
 
-  if (die->die_child != NULL)
-    /* Count the null byte used to terminate sibling lists.  */
-    next_die_offset += 1;
+      remove_AT (die, DW_AT_specification);
+
+      for (ix = 0; VEC_iterate (dw_attr_node, decl->die_attr, ix, a); ix++)
+        {
+          if (a->dw_attr != DW_AT_name
+              && a->dw_attr != DW_AT_declaration
+              && a->dw_attr != DW_AT_external)
+            add_dwarf_attr (die, a);
+        }
+
+      FOR_EACH_CHILD (decl, c, add_child_die (die, clone_tree(c)));
+    }
+
+  if (decl->die_parent != NULL
+      && decl->die_parent->die_tag != DW_TAG_compile_unit
+      && decl->die_parent->die_tag != DW_TAG_type_unit)
+    {
+      new_decl = copy_ancestor_tree (unit, decl, NULL);
+      if (new_decl != NULL)
+        {
+          remove_AT (new_decl, DW_AT_signature);
+          add_AT_specification (die, new_decl);
+        }
+    }
 }
 
-/* Set the marks for a die and its children.  We do this so
-   that we know whether or not a reference needs to use FORM_ref_addr; only
-   DIEs in the same CU will be marked.  We used to clear out the offset
-   and use that as the flag, but ran into ordering problems.  */
+/* Generate the skeleton ancestor tree for the given NODE, then clone
+   the DIE and add the clone into the tree.  */
 
 static void
-mark_dies (dw_die_ref die)
+generate_skeleton_ancestor_tree (skeleton_chain_node *node)
 {
-  dw_die_ref c;
+  if (node->new_die != NULL)
+    return;
 
-  gcc_assert (!die->die_mark);
+  node->new_die = clone_as_declaration (node->old_die);
 
-  die->die_mark = 1;
-  FOR_EACH_CHILD (die, c, mark_dies (c));
+  if (node->parent != NULL)
+    {
+      generate_skeleton_ancestor_tree (node->parent);
+      add_child_die (node->parent->new_die, node->new_die);
+    }
 }
 
-/* Clear the marks for a die and its children.  */
+/* Generate a skeleton tree of DIEs containing any declarations that are
+   found in the original tree.  We traverse the tree looking for declaration
+   DIEs, and construct the skeleton from the bottom up whenever we find one.  */
 
 static void
-unmark_dies (dw_die_ref die)
+generate_skeleton_bottom_up (skeleton_chain_node *parent)
 {
+  skeleton_chain_node node;
   dw_die_ref c;
+  dw_die_ref first;
+  dw_die_ref prev = NULL;
+  dw_die_ref next = NULL;
 
-  gcc_assert (die->die_mark);
+  node.parent = parent;
 
-  die->die_mark = 0;
-  FOR_EACH_CHILD (die, c, unmark_dies (c));
+  first = c = parent->old_die->die_child;
+  if (c)
+    next = c->die_sib;
+  if (c) do {
+    if (prev == NULL || prev->die_sib == c)
+      prev = c;
+    c = next;
+    next = (c == first ? NULL : c->die_sib);
+    node.old_die = c;
+    node.new_die = NULL;
+    if (is_declaration_die (c))
+      {
+        /* Clone the existing DIE, move the original to the skeleton
+           tree (which is in the main CU), and put the clone, with
+           all the original's children, where the original came from.  */
+        dw_die_ref clone = clone_die (c);
+        move_all_children (c, clone);
+
+        replace_child (c, clone, prev);
+        generate_skeleton_ancestor_tree (parent);
+        add_child_die (parent->new_die, c);
+        node.new_die = c;
+        c = clone;
+      }
+    generate_skeleton_bottom_up (&node);
+  } while (next != NULL);
 }
 
-/* Clear the marks for a die, its children and referred dies.  */
+/* Wrapper function for generate_skeleton_bottom_up.  */
 
-static void
-unmark_all_dies (dw_die_ref die)
+static dw_die_ref
+generate_skeleton (dw_die_ref die)
 {
-  dw_die_ref c;
-  dw_attr_ref a;
-  unsigned ix;
+  skeleton_chain_node node;
 
-  if (!die->die_mark)
-    return;
-  die->die_mark = 0;
+  node.old_die = die;
+  node.new_die = NULL;
+  node.parent = NULL;
 
-  FOR_EACH_CHILD (die, c, unmark_all_dies (c));
+  /* If this type definition is nested inside another type,
+     always leave at least a declaration in its place.  */
+  if (die->die_parent != NULL && is_type_die (die->die_parent))
+    node.new_die = clone_as_declaration (die);
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    if (AT_class (a) == dw_val_class_die_ref)
-      unmark_all_dies (AT_ref (a));
+  generate_skeleton_bottom_up (&node);
+  return node.new_die;
 }
 
-/* Return the size of the .debug_pubnames or .debug_pubtypes table
-   generated for the compilation unit.  */
+/* Remove the DIE from its parent, possibly replacing it with a cloned
+   declaration.  The original DIE will be moved to a new compile unit
+   so that existing references to it follow it to the new location.  If
+   any of the original DIE's descendants is a declaration, we need to
+   replace the original DIE with a skeleton tree and move the
+   declarations back into the skeleton tree.  */
 
-static unsigned long
-size_of_pubnames (VEC (pubname_entry, gc) * names)
+static dw_die_ref
+remove_child_or_replace_with_skeleton (dw_die_ref child, dw_die_ref prev)
 {
-  unsigned long size;
-  unsigned i;
-  pubname_ref p;
+  dw_die_ref skeleton;
 
-  size = DWARF_PUBNAMES_HEADER_SIZE;
-  for (i = 0; VEC_iterate (pubname_entry, names, i, p); i++)
-    if (names != pubtype_table
-       || p->die->die_offset != 0
-       || !flag_eliminate_unused_debug_types)
-      size += strlen (p->name) + DWARF_OFFSET_SIZE + 1;
+  skeleton = generate_skeleton (child);
+  if (skeleton == NULL)
+    remove_child_with_prev (child, prev);
+  else
+    {
+      skeleton->die_id.die_type_node = child->die_id.die_type_node;
+      replace_child (child, skeleton, prev);
+    }
 
-  size += DWARF_OFFSET_SIZE;
-  return size;
+  return skeleton;
 }
 
-/* Return the size of the information in the .debug_aranges section.  */
+/* Traverse the DIE and set up additional .debug_types sections for each
+   type worthy of being placed in a COMDAT section.  */
 
-static unsigned long
-size_of_aranges (void)
+static void
+break_out_comdat_types (dw_die_ref die)
 {
-  unsigned long size;
+  dw_die_ref c;
+  dw_die_ref first;
+  dw_die_ref prev = NULL;
+  dw_die_ref next = NULL;
+  dw_die_ref unit = NULL;
 
-  size = DWARF_ARANGES_HEADER_SIZE;
+  first = c = die->die_child;
+  if (c)
+    next = c->die_sib;
+  if (c) do {
+    if (prev == NULL || prev->die_sib == c)
+      prev = c;
+    c = next;
+    next = (c == first ? NULL : c->die_sib);
+    if (should_move_die_to_comdat (c))
+      {
+        dw_die_ref replacement;
+       comdat_type_node_ref type_node;
 
-  /* Count the address/length pair for this compilation unit.  */
-  if (text_section_used)
-    size += 2 * DWARF2_ADDR_SIZE;
-  if (cold_text_section_used)
-    size += 2 * DWARF2_ADDR_SIZE;
-  size += 2 * DWARF2_ADDR_SIZE * arange_table_in_use;
+        /* Create a new type unit DIE as the root for the new tree, and
+           add it to the list of comdat types.  */
+        unit = new_die (DW_TAG_type_unit, NULL, NULL);
+        add_AT_unsigned (unit, DW_AT_language,
+                         get_AT_unsigned (comp_unit_die, DW_AT_language));
+        type_node = GGC_CNEW (comdat_type_node);
+        type_node->root_die = unit;
+        type_node->next = comdat_type_list;
+        comdat_type_list = type_node;
 
-  /* Count the two zero words used to terminated the address range table.  */
-  size += 2 * DWARF2_ADDR_SIZE;
-  return size;
+        /* Generate the type signature.  */
+        generate_type_signature (c, type_node);
+
+        /* Copy the declaration context, attributes, and children of the
+           declaration into the new compile unit DIE.  */
+       copy_declaration_context (unit, c);
+
+        /* Remove this DIE from the main CU.  */
+       replacement = remove_child_or_replace_with_skeleton (c, prev);
+
+        /* Break out nested types into their own type units.  */
+        break_out_comdat_types (c);
+
+        /* Add the DIE to the new compunit.  */
+       add_child_die (unit, c);
+
+        if (replacement != NULL)
+          c = replacement;
+      }
+    else if (c->die_tag == DW_TAG_namespace
+             || c->die_tag == DW_TAG_class_type
+             || c->die_tag == DW_TAG_structure_type
+             || c->die_tag == DW_TAG_union_type)
+      {
+        /* Look for nested types that can be broken out.  */
+        break_out_comdat_types (c);
+      }
+  } while (next != NULL);
 }
-\f
-/* Select the encoding of an attribute value.  */
 
-static enum dwarf_form
-value_format (dw_attr_ref a)
+/* Structure to map a DIE in one CU to its copy in a comdat type unit.  */
+
+struct decl_table_entry
 {
-  switch (a->dw_attr_val.val_class)
-    {
-    case dw_val_class_addr:
-      return DW_FORM_addr;
-    case dw_val_class_range_list:
-    case dw_val_class_offset:
-    case dw_val_class_loc_list:
-      switch (DWARF_OFFSET_SIZE)
-       {
-       case 4:
-         return DW_FORM_data4;
-       case 8:
-         return DW_FORM_data8;
-       default:
-         gcc_unreachable ();
-       }
-    case dw_val_class_loc:
-      switch (constant_size (size_of_locs (AT_loc (a))))
-       {
-       case 1:
-         return DW_FORM_block1;
-       case 2:
-         return DW_FORM_block2;
-       default:
-         gcc_unreachable ();
-       }
-    case dw_val_class_const:
-      return DW_FORM_sdata;
-    case dw_val_class_unsigned_const:
-      switch (constant_size (AT_unsigned (a)))
-       {
-       case 1:
-         return DW_FORM_data1;
-       case 2:
-         return DW_FORM_data2;
-       case 4:
-         return DW_FORM_data4;
-       case 8:
-         return DW_FORM_data8;
-       default:
-         gcc_unreachable ();
-       }
-    case dw_val_class_long_long:
-      return DW_FORM_block1;
-    case dw_val_class_vec:
-      switch (constant_size (a->dw_attr_val.v.val_vec.length
-                            * a->dw_attr_val.v.val_vec.elt_size))
-       {
-       case 1:
-         return DW_FORM_block1;
-       case 2:
-         return DW_FORM_block2;
-       case 4:
-         return DW_FORM_block4;
-       default:
-         gcc_unreachable ();
-       }
-    case dw_val_class_flag:
-      return DW_FORM_flag;
-    case dw_val_class_die_ref:
-      if (AT_ref_external (a))
-       return DW_FORM_ref_addr;
-      else
-       return DW_FORM_ref;
-    case dw_val_class_fde_ref:
-      return DW_FORM_data;
-    case dw_val_class_lbl_id:
-      return DW_FORM_addr;
-    case dw_val_class_lineptr:
-    case dw_val_class_macptr:
-      return DW_FORM_data;
-    case dw_val_class_str:
-      return AT_string_form (a);
-    case dw_val_class_file:
-      switch (constant_size (maybe_emit_file (a->dw_attr_val.v.val_file)))
-       {
-       case 1:
-         return DW_FORM_data1;
-       case 2:
-         return DW_FORM_data2;
-       case 4:
-         return DW_FORM_data4;
-       default:
-         gcc_unreachable ();
-       }
+  dw_die_ref orig;
+  dw_die_ref copy;
+};
 
-    default:
-      gcc_unreachable ();
-    }
+/* Routines to manipulate hash table of copied declarations.  */
+
+static hashval_t
+htab_decl_hash (const void *of)
+{
+  const struct decl_table_entry *const entry =
+    (const struct decl_table_entry *) of;
+
+  return htab_hash_pointer (entry->orig);
 }
 
-/* Output the encoding of an attribute value.  */
+static int
+htab_decl_eq (const void *of1, const void *of2)
+{
+  const struct decl_table_entry *const entry1 =
+    (const struct decl_table_entry *) of1;
+  const struct die_struct *const entry2 = (const struct die_struct *) of2;
+
+  return entry1->orig == entry2;
+}
 
 static void
-output_value_format (dw_attr_ref a)
+htab_decl_del (void *what)
 {
-  enum dwarf_form form = value_format (a);
+  struct decl_table_entry *entry = (struct decl_table_entry *) what;
 
-  dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
+  free (entry);
 }
 
-/* Output the .debug_abbrev section which defines the DIE abbreviation
-   table.  */
+/* Copy DIE and its ancestors, up to, but not including, the compile unit
+   or type unit entry, to a new tree.  Adds the new tree to UNIT and returns
+   a pointer to the copy of DIE.  If DECL_TABLE is provided, it is used
+   to check if the ancestor has already been copied into UNIT.  */
 
-static void
-output_abbrev_section (void)
+static dw_die_ref
+copy_ancestor_tree (dw_die_ref unit, dw_die_ref die, htab_t decl_table)
 {
-  unsigned long abbrev_id;
+  dw_die_ref parent = die->die_parent;
+  dw_die_ref new_parent = unit;
+  dw_die_ref copy;
+  void **slot = NULL;
+  struct decl_table_entry *entry = NULL;
 
-  for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+  if (decl_table)
     {
-      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
-      unsigned ix;
-      dw_attr_ref a_attr;
+      /* Check if the entry has already been copied to UNIT.  */
+      slot = htab_find_slot_with_hash (decl_table, die,
+                                       htab_hash_pointer (die), INSERT);
+      if (*slot != HTAB_EMPTY_ENTRY)
+        {
+          entry = (struct decl_table_entry *) *slot;
+          return entry->copy;
+        }
 
-      dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
-      dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
-                                  dwarf_tag_name (abbrev->die_tag));
+      /* Record in DECL_TABLE that DIE has been copied to UNIT.  */
+      entry = XCNEW (struct decl_table_entry);
+      entry->orig = die;
+      entry->copy = NULL;
+      *slot = entry;
+    }
 
-      if (abbrev->die_child != NULL)
-       dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
-      else
-       dw2_asm_output_data (1, DW_children_no, "DW_children_no");
+  if (parent != NULL)
+    {
+      dw_die_ref spec = get_AT_ref (parent, DW_AT_specification);
+      if (spec != NULL)
+        parent = spec;
+      if (parent->die_tag != DW_TAG_compile_unit
+          && parent->die_tag != DW_TAG_type_unit)
+        new_parent = copy_ancestor_tree (unit, parent, decl_table);
+    }
 
-      for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
-          ix++)
-       {
-         dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
-                                      dwarf_attr_name (a_attr->dw_attr));
-         output_value_format (a_attr);
-       }
+  copy = clone_as_declaration (die);
+  add_child_die (new_parent, copy);
 
-      dw2_asm_output_data (1, 0, NULL);
-      dw2_asm_output_data (1, 0, NULL);
+  if (decl_table != NULL)
+    {
+      /* Make sure the copy is marked as part of the type unit.  */
+      copy->die_mark = 1;
+      /* Record the pointer to the copy.  */
+      entry->copy = copy;
     }
 
-  /* Terminate the table.  */
-  dw2_asm_output_data (1, 0, NULL);
+  return copy;
 }
 
-/* Output a symbol we can use to refer to this DIE from another CU.  */
+/* Walk the DIE and its children, looking for references to incomplete
+   or trivial types that are unmarked (i.e., that are not in the current
+   type_unit).  */
 
-static inline void
-output_die_symbol (dw_die_ref die)
+static void
+copy_decls_walk (dw_die_ref unit, dw_die_ref die, htab_t decl_table)
 {
-  char *sym = die->die_symbol;
+  dw_die_ref c;
+  dw_attr_ref a;
+  unsigned ix;
 
-  if (sym == 0)
-    return;
+  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+    {
+      if (AT_class (a) == dw_val_class_die_ref)
+        {
+          dw_die_ref targ = AT_ref (a);
+          comdat_type_node_ref type_node = targ->die_id.die_type_node;
+          void **slot;
+          struct decl_table_entry *entry;
 
-  if (strncmp (sym, DIE_LABEL_PREFIX, sizeof (DIE_LABEL_PREFIX) - 1) == 0)
-    /* We make these global, not weak; if the target doesn't support
-       .linkonce, it doesn't support combining the sections, so debugging
-       will break.  */
-    targetm.asm_out.globalize_label (asm_out_file, sym);
+          if (targ->die_mark != 0 || type_node != NULL)
+            continue;
 
-  ASM_OUTPUT_LABEL (asm_out_file, sym);
+          slot = htab_find_slot_with_hash (decl_table, targ,
+                                           htab_hash_pointer (targ), INSERT);
+
+          if (*slot != HTAB_EMPTY_ENTRY)
+            {
+              /* TARG has already been copied, so we just need to
+                 modify the reference to point to the copy.  */
+              entry = (struct decl_table_entry *) *slot;
+              a->dw_attr_val.v.val_die_ref.die = entry->copy;
+            }
+          else
+            {
+              dw_die_ref parent = unit;
+              dw_die_ref copy = clone_tree (targ);
+
+              /* Make sure the cloned tree is marked as part of the
+                 type unit.  */
+              mark_dies (copy);
+
+              /* Record in DECL_TABLE that TARG has been copied.
+                 Need to do this now, before the recursive call,
+                 because DECL_TABLE may be expanded and SLOT
+                 would no longer be a valid pointer.  */
+              entry = XCNEW (struct decl_table_entry);
+              entry->orig = targ;
+              entry->copy = copy;
+              *slot = entry;
+
+              /* If TARG has surrounding context, copy its ancestor tree
+                 into the new type unit.  */
+              if (targ->die_parent != NULL
+                  && targ->die_parent->die_tag != DW_TAG_compile_unit
+                  && targ->die_parent->die_tag != DW_TAG_type_unit)
+                parent = copy_ancestor_tree (unit, targ->die_parent,
+                                             decl_table);
+
+              add_child_die (parent, copy);
+              a->dw_attr_val.v.val_die_ref.die = copy;
+
+              /* Make sure the newly-copied DIE is walked.  If it was
+                 installed in a previously-added context, it won't
+                 get visited otherwise.  */
+              if (parent != unit)
+                copy_decls_walk (unit, parent, decl_table);
+            }
+        }
+    }
+
+  FOR_EACH_CHILD (die, c, copy_decls_walk (unit, c, decl_table));
 }
 
-/* Return a new location list, given the begin and end range, and the
-   expression. gensym tells us whether to generate a new internal symbol for
-   this location list node, which is done for the head of the list only.  */
+/* Copy declarations for "unworthy" types into the new comdat section.
+   Incomplete types, modified types, and certain other types aren't broken
+   out into comdat sections of their own, so they don't have a signature,
+   and we need to copy the declaration into the same section so that we
+   don't have an external reference.  */
 
-static inline dw_loc_list_ref
-new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
-             const char *section, unsigned int gensym)
+static void
+copy_decls_for_unworthy_types (dw_die_ref unit)
 {
-  dw_loc_list_ref retlist = GGC_CNEW (dw_loc_list_node);
-
-  retlist->begin = begin;
-  retlist->end = end;
-  retlist->expr = expr;
-  retlist->section = section;
-  if (gensym)
-    retlist->ll_symbol = gen_internal_sym ("LLST");
+  htab_t decl_table;
 
-  return retlist;
+  mark_dies (unit);
+  decl_table = htab_create (10, htab_decl_hash, htab_decl_eq, htab_decl_del);
+  copy_decls_walk (unit, unit, decl_table);
+  htab_delete (decl_table);
+  unmark_dies (unit);
 }
 
-/* Add a location description expression to a location list.  */
+/* Traverse the DIE and add a sibling attribute if it may have the
+   effect of speeding up access to siblings.  To save some space,
+   avoid generating sibling attributes for DIE's without children.  */
 
-static inline void
-add_loc_descr_to_loc_list (dw_loc_list_ref *list_head, dw_loc_descr_ref descr,
-                          const char *begin, const char *end,
-                          const char *section)
+static void
+add_sibling_attributes (dw_die_ref die)
 {
-  dw_loc_list_ref *d;
+  dw_die_ref c;
 
-  /* Find the end of the chain.  */
-  for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
-    ;
+  if (! die->die_child)
+    return;
 
-  /* Add a new location list node to the list.  */
-  *d = new_loc_list (descr, begin, end, section, 0);
+  if (die->die_parent && die != die->die_parent->die_child)
+    add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
+
+  FOR_EACH_CHILD (die, c, add_sibling_attributes (c));
 }
 
-/* Output the location list given to us.  */
+/* Output all location lists for the DIE and its children.  */
 
 static void
-output_loc_list (dw_loc_list_ref list_head)
+output_location_lists (dw_die_ref die)
 {
-  dw_loc_list_ref curr = list_head;
+  dw_die_ref c;
+  dw_attr_ref a;
+  unsigned ix;
 
-  ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
+  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+    if (AT_class (a) == dw_val_class_loc_list)
+      output_loc_list (AT_loc_list (a));
 
-  /* Walk the location list, and output each range + expression.  */
-  for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
-    {
-      unsigned long size;
-      /* Don't output an entry that starts and ends at the same address.  */
-      if (strcmp (curr->begin, curr->end) == 0)
-       continue;
-      if (!have_multiple_function_sections)
-       {
-         dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
-                               "Location list begin address (%s)",
-                               list_head->ll_symbol);
-         dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->end, curr->section,
-                               "Location list end address (%s)",
-                               list_head->ll_symbol);
-       }
-      else
+  FOR_EACH_CHILD (die, c, output_location_lists (c));
+}
+
+/* The format of each DIE (and its attribute value pairs) is encoded in an
+   abbreviation table.  This routine builds the abbreviation table and assigns
+   a unique abbreviation id for each abbreviation entry.  The children of each
+   die are visited recursively.  */
+
+static void
+build_abbrev_table (dw_die_ref die)
+{
+  unsigned long abbrev_id;
+  unsigned int n_alloc;
+  dw_die_ref c;
+  dw_attr_ref a;
+  unsigned ix;
+
+  /* Scan the DIE references, and mark as external any that refer to
+     DIEs from other CUs (i.e. those which are not marked).  */
+  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+    if (AT_class (a) == dw_val_class_die_ref
+       && AT_ref (a)->die_mark == 0)
+      {
+       gcc_assert (dwarf_version >= 4 || AT_ref (a)->die_id.die_symbol);
+       set_AT_ref_external (a, 1);
+      }
+
+  for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+    {
+      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
+      dw_attr_ref die_a, abbrev_a;
+      unsigned ix;
+      bool ok = true;
+
+      if (abbrev->die_tag != die->die_tag)
+       continue;
+      if ((abbrev->die_child != NULL) != (die->die_child != NULL))
+       continue;
+
+      if (VEC_length (dw_attr_node, abbrev->die_attr)
+         != VEC_length (dw_attr_node, die->die_attr))
+       continue;
+
+      for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, die_a); ix++)
        {
-         dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->begin,
-                              "Location list begin address (%s)",
-                              list_head->ll_symbol);
-         dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->end,
-                              "Location list end address (%s)",
-                              list_head->ll_symbol);
+         abbrev_a = VEC_index (dw_attr_node, abbrev->die_attr, ix);
+         if ((abbrev_a->dw_attr != die_a->dw_attr)
+             || (value_format (abbrev_a) != value_format (die_a)))
+           {
+             ok = false;
+             break;
+           }
        }
-      size = size_of_locs (curr->expr);
+      if (ok)
+       break;
+    }
 
-      /* Output the block length for this list of location operations.  */
-      gcc_assert (size <= 0xffff);
-      dw2_asm_output_data (2, size, "%s", "Location expression size");
+  if (abbrev_id >= abbrev_die_table_in_use)
+    {
+      if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
+       {
+         n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
+         abbrev_die_table = GGC_RESIZEVEC (dw_die_ref, abbrev_die_table,
+                                           n_alloc);
 
-      output_loc_sequence (curr->expr);
+         memset (&abbrev_die_table[abbrev_die_table_allocated], 0,
+                (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
+         abbrev_die_table_allocated = n_alloc;
+       }
+
+      ++abbrev_die_table_in_use;
+      abbrev_die_table[abbrev_id] = die;
     }
 
-  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
-                      "Location list terminator begin (%s)",
-                      list_head->ll_symbol);
-  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
-                      "Location list terminator end (%s)",
-                      list_head->ll_symbol);
+  die->die_abbrev = abbrev_id;
+  FOR_EACH_CHILD (die, c, build_abbrev_table (c));
 }
+\f
+/* Return the power-of-two number of bytes necessary to represent VALUE.  */
 
-/* Output the DIE and its attributes.  Called recursively to generate
-   the definitions of each child DIE.  */
+static int
+constant_size (unsigned HOST_WIDE_INT value)
+{
+  int log;
 
-static void
-output_die (dw_die_ref die)
+  if (value == 0)
+    log = 0;
+  else
+    log = floor_log2 (value);
+
+  log = log / 8;
+  log = 1 << (floor_log2 (log) + 1);
+
+  return log;
+}
+
+/* Return the size of a DIE as it is represented in the
+   .debug_info section.  */
+
+static unsigned long
+size_of_die (dw_die_ref die)
 {
+  unsigned long size = 0;
   dw_attr_ref a;
-  dw_die_ref c;
-  unsigned long size;
   unsigned ix;
 
-  /* If someone in another CU might refer to us, set up a symbol for
-     them to point to.  */
-  if (die->die_symbol)
-    output_die_symbol (die);
-
-  dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (0x%lx) %s)",
-                              (unsigned long)die->die_offset,
-                              dwarf_tag_name (die->die_tag));
-
+  size += size_of_uleb128 (die->die_abbrev);
   for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
     {
-      const char *name = dwarf_attr_name (a->dw_attr);
-
       switch (AT_class (a))
        {
        case dw_val_class_addr:
-         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
+         size += DWARF2_ADDR_SIZE;
          break;
-
        case dw_val_class_offset:
-         dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
-                              "%s", name);
+         size += DWARF_OFFSET_SIZE;
          break;
-
-       case dw_val_class_range_list:
+       case dw_val_class_loc:
          {
-           char *p = strchr (ranges_section_label, '\0');
+           unsigned long lsize = size_of_locs (AT_loc (a));
 
-           sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
-                    a->dw_attr_val.v.val_offset);
-           dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
-                                  debug_ranges_section, "%s", name);
-           *p = '\0';
+           /* Block length.  */
+           size += constant_size (lsize);
+           size += lsize;
          }
          break;
-
-       case dw_val_class_loc:
-         size = size_of_locs (AT_loc (a));
-
-         /* Output the block length for this list of location operations.  */
-         dw2_asm_output_data (constant_size (size), size, "%s", name);
-
-         output_loc_sequence (AT_loc (a));
+       case dw_val_class_loc_list:
+         size += DWARF_OFFSET_SIZE;
+         break;
+       case dw_val_class_range_list:
+         size += DWARF_OFFSET_SIZE;
          break;
-
        case dw_val_class_const:
-         /* ??? It would be slightly more efficient to use a scheme like is
-            used for unsigned constants below, but gdb 4.x does not sign
-            extend.  Gdb 5.x does sign extend.  */
-         dw2_asm_output_data_sleb128 (AT_int (a), "%s", name);
+         size += size_of_sleb128 (AT_int (a));
          break;
-
        case dw_val_class_unsigned_const:
-         dw2_asm_output_data (constant_size (AT_unsigned (a)),
-                              AT_unsigned (a), "%s", name);
+         size += constant_size (AT_unsigned (a));
          break;
-
-       case dw_val_class_long_long:
-         {
-           unsigned HOST_WIDE_INT first, second;
-
-           dw2_asm_output_data (1,
-                                2 * HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
-                                "%s", name);
-
-           if (WORDS_BIG_ENDIAN)
-             {
-               first = a->dw_attr_val.v.val_long_long.hi;
-               second = a->dw_attr_val.v.val_long_long.low;
-             }
-           else
-             {
-               first = a->dw_attr_val.v.val_long_long.low;
-               second = a->dw_attr_val.v.val_long_long.hi;
-             }
-
-           dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
-                                first, "long long constant");
-           dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
-                                second, NULL);
-         }
+       case dw_val_class_const_double:
+         size += 2 * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
+         if (HOST_BITS_PER_WIDE_INT >= 64)
+           size++; /* block */
          break;
-
        case dw_val_class_vec:
-         {
-           unsigned int elt_size = a->dw_attr_val.v.val_vec.elt_size;
-           unsigned int len = a->dw_attr_val.v.val_vec.length;
-           unsigned int i;
-           unsigned char *p;
-
-           dw2_asm_output_data (constant_size (len * elt_size),
-                                len * elt_size, "%s", name);
-           if (elt_size > sizeof (HOST_WIDE_INT))
-             {
-               elt_size /= 2;
-               len *= 2;
-             }
-           for (i = 0, p = a->dw_attr_val.v.val_vec.array;
-                i < len;
-                i++, p += elt_size)
-             dw2_asm_output_data (elt_size, extract_int (p, elt_size),
-                                  "fp or vector constant word %u", i);
-           break;
-         }
-
-       case dw_val_class_flag:
-         dw2_asm_output_data (1, AT_flag (a), "%s", name);
+         size += constant_size (a->dw_attr_val.v.val_vec.length
+                                * a->dw_attr_val.v.val_vec.elt_size)
+                 + a->dw_attr_val.v.val_vec.length
+                   * a->dw_attr_val.v.val_vec.elt_size; /* block */
          break;
-
-       case dw_val_class_loc_list:
-         {
-           char *sym = AT_loc_list (a)->ll_symbol;
-
-           gcc_assert (sym);
-           dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
-                                  "%s", name);
-         }
+       case dw_val_class_flag:
+         size += 1;
          break;
-
        case dw_val_class_die_ref:
          if (AT_ref_external (a))
            {
-             char *sym = AT_ref (a)->die_symbol;
-             int size;
-
-             gcc_assert (sym);
-
-             /* In DWARF2, DW_FORM_ref_addr is sized by target address
-                length, whereas in DWARF3 it's always sized as an offset.  */
-             if (dwarf_version == 2)
-               size = DWARF2_ADDR_SIZE;
+             /* In DWARF4, we use DW_FORM_sig8; for earlier versions
+                we use DW_FORM_ref_addr.  In DWARF2, DW_FORM_ref_addr
+                is sized by target address length, whereas in DWARF3
+                it's always sized as an offset.  */
+             if (dwarf_version >= 4)
+               size += DWARF_TYPE_SIGNATURE_SIZE;
+             else if (dwarf_version == 2)
+               size += DWARF2_ADDR_SIZE;
              else
-               size = DWARF_OFFSET_SIZE;
-             dw2_asm_output_offset (size, sym, debug_info_section, "%s", name);
+               size += DWARF_OFFSET_SIZE;
            }
          else
-           {
-             gcc_assert (AT_ref (a)->die_offset);
-             dw2_asm_output_data (DWARF_OFFSET_SIZE, AT_ref (a)->die_offset,
-                                  "%s", name);
-           }
+           size += DWARF_OFFSET_SIZE;
          break;
-
        case dw_val_class_fde_ref:
-         {
-           char l1[20];
-
-           ASM_GENERATE_INTERNAL_LABEL (l1, FDE_LABEL,
-                                        a->dw_attr_val.v.val_fde_index * 2);
-           dw2_asm_output_offset (DWARF_OFFSET_SIZE, l1, debug_frame_section,
-                                  "%s", name);
-         }
+         size += DWARF_OFFSET_SIZE;
          break;
-
        case dw_val_class_lbl_id:
-         dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
+         size += DWARF2_ADDR_SIZE;
          break;
-
        case dw_val_class_lineptr:
-         dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
-                                debug_line_section, "%s", name);
-         break;
-
        case dw_val_class_macptr:
-         dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
-                                debug_macinfo_section, "%s", name);
+         size += DWARF_OFFSET_SIZE;
          break;
-
        case dw_val_class_str:
          if (AT_string_form (a) == 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));
+           size += DWARF_OFFSET_SIZE;
          else
-           dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
+           size += strlen (a->dw_attr_val.v.val_str->str) + 1;
          break;
-
        case dw_val_class_file:
-         {
-           int f = maybe_emit_file (a->dw_attr_val.v.val_file);
-
-           dw2_asm_output_data (constant_size (f), f, "%s (%s)", name,
-                                a->dw_attr_val.v.val_file->filename);
-           break;
-         }
-
+         size += constant_size (maybe_emit_file (a->dw_attr_val.v.val_file));
+         break;
+       case dw_val_class_data8:
+         size += 8;
+         break;
        default:
          gcc_unreachable ();
        }
     }
 
-  FOR_EACH_CHILD (die, c, output_die (c));
-
-  /* Add null byte to terminate sibling list.  */
-  if (die->die_child != NULL)
-    dw2_asm_output_data (1, 0, "end of children of DIE 0x%lx",
-                        (unsigned long) die->die_offset);
-}
-
-/* Output the compilation unit that appears at the beginning of the
-   .debug_info section, and precedes the DIE descriptions.  */
-
-static void
-output_compilation_unit_header (void)
-{
-  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
-    dw2_asm_output_data (4, 0xffffffff,
-      "Initial length escape value indicating 64-bit DWARF extension");
-  dw2_asm_output_data (DWARF_OFFSET_SIZE,
-                      next_die_offset - DWARF_INITIAL_LENGTH_SIZE,
-                      "Length of Compilation Unit Info");
-  dw2_asm_output_data (2, dwarf_version, "DWARF version number");
-  dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
-                        debug_abbrev_section,
-                        "Offset Into Abbrev. Section");
-  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+  return size;
 }
 
-/* Output the compilation unit DIE and its children.  */
+/* 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
+   die_offset field in each DIE.  */
 
 static void
-output_comp_unit (dw_die_ref die, int output_if_empty)
+calc_die_sizes (dw_die_ref die)
 {
-  const char *secname;
-  char *oldsym, *tmp;
-
-  /* Unless we are outputting main CU, we may throw away empty ones.  */
-  if (!output_if_empty && die->die_child == NULL)
-    return;
-
-  /* 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);
-
-  oldsym = die->die_symbol;
-  if (oldsym)
-    {
-      tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
-
-      sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym);
-      secname = tmp;
-      die->die_symbol = NULL;
-      switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
-    }
-  else
-    switch_to_section (debug_info_section);
-
-  /* Output debugging information.  */
-  output_compilation_unit_header ();
-  output_die (die);
+  dw_die_ref c;
 
-  /* Leave the marks on the main CU, so we can check them in
-     output_pubnames.  */
-  if (oldsym)
-    {
-      unmark_dies (die);
-      die->die_symbol = oldsym;
-    }
-}
+  die->die_offset = next_die_offset;
+  next_die_offset += size_of_die (die);
 
-/* Return the DWARF2/3 pubname associated with a decl.  */
+  FOR_EACH_CHILD (die, c, calc_die_sizes (c));
 
-static const char *
-dwarf2_name (tree decl, int scope)
-{
-  return lang_hooks.dwarf_name (decl, scope ? 1 : 0);
+  if (die->die_child != NULL)
+    /* Count the null byte used to terminate sibling lists.  */
+    next_die_offset += 1;
 }
 
-/* Add a new entry to .debug_pubnames if appropriate.  */
+/* Set the marks for a die and its children.  We do this so
+   that we know whether or not a reference needs to use FORM_ref_addr; only
+   DIEs in the same CU will be marked.  We used to clear out the offset
+   and use that as the flag, but ran into ordering problems.  */
 
 static void
-add_pubname_string (const char *str, dw_die_ref die)
+mark_dies (dw_die_ref die)
 {
-  pubname_entry e;
+  dw_die_ref c;
 
-  e.die = die;
-  e.name = xstrdup (str);
-  VEC_safe_push (pubname_entry, gc, pubname_table, &e);
-}
+  gcc_assert (!die->die_mark);
 
-static void
-add_pubname (tree decl, dw_die_ref die)
-{
-  if (TREE_PUBLIC (decl))
-    add_pubname_string (dwarf2_name (decl, 1), die);
+  die->die_mark = 1;
+  FOR_EACH_CHILD (die, c, mark_dies (c));
 }
 
-/* Add a new entry to .debug_pubtypes if appropriate.  */
+/* Clear the marks for a die and its children.  */
 
 static void
-add_pubtype (tree decl, dw_die_ref die)
+unmark_dies (dw_die_ref die)
 {
-  pubname_entry e;
+  dw_die_ref c;
 
-  e.name = NULL;
-  if ((TREE_PUBLIC (decl)
-       || die->die_parent == comp_unit_die)
-      && (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl)))
-    {
-      e.die = die;
-      if (TYPE_P (decl))
-       {
-         if (TYPE_NAME (decl))
-           {
-             if (TREE_CODE (TYPE_NAME (decl)) == IDENTIFIER_NODE)
-               e.name = IDENTIFIER_POINTER (TYPE_NAME (decl));
-             else if (TREE_CODE (TYPE_NAME (decl)) == TYPE_DECL
-                      && DECL_NAME (TYPE_NAME (decl)))
-               e.name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl)));
-             else
-              e.name = xstrdup ((const char *) get_AT_string (die, DW_AT_name));
-           }
-       }
-      else
-       e.name = xstrdup (dwarf2_name (decl, 1));
+  if (dwarf_version < 4)
+    gcc_assert (die->die_mark);
 
-      /* If we don't have a name for the type, there's no point in adding
-        it to the table.  */
-      if (e.name && e.name[0] != '\0')
-       VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
-    }
+  die->die_mark = 0;
+  FOR_EACH_CHILD (die, c, unmark_dies (c));
 }
 
-/* Output the public names table used to speed up access to externally
-   visible names; or the public types table used to find type definitions.  */
+/* Clear the marks for a die, its children and referred dies.  */
 
 static void
-output_pubnames (VEC (pubname_entry, gc) * names)
+unmark_all_dies (dw_die_ref die)
 {
-  unsigned i;
-  unsigned long pubnames_length = size_of_pubnames (names);
-  pubname_ref pub;
-
-  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
-    dw2_asm_output_data (4, 0xffffffff,
-      "Initial length escape value indicating 64-bit DWARF extension");
-  if (names == pubname_table)
-    dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
-                        "Length of Public Names Info");
-  else
-    dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
-                        "Length of Public Type Names Info");
-  /* Version number for pubnames/pubtypes is still 2, even in DWARF3.  */
-  dw2_asm_output_data (2, 2, "DWARF Version");
-  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
-                        debug_info_section,
-                        "Offset of Compilation Unit Info");
-  dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
-                      "Compilation Unit Length");
-
-  for (i = 0; VEC_iterate (pubname_entry, names, i, pub); i++)
-    {
-      /* We shouldn't see pubnames for DIEs outside of the main CU.  */
-      if (names == pubname_table)
-       gcc_assert (pub->die->die_mark);
+  dw_die_ref c;
+  dw_attr_ref a;
+  unsigned ix;
 
-      if (names != pubtype_table
-         || pub->die->die_offset != 0
-         || !flag_eliminate_unused_debug_types)
-       {
-         dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
-                              "DIE offset");
+  if (!die->die_mark)
+    return;
+  die->die_mark = 0;
 
-         dw2_asm_output_nstring (pub->name, -1, "external name");
-       }
-    }
+  FOR_EACH_CHILD (die, c, unmark_all_dies (c));
 
-  dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL);
+  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+    if (AT_class (a) == dw_val_class_die_ref)
+      unmark_all_dies (AT_ref (a));
 }
 
-/* Add a new entry to .debug_aranges if appropriate.  */
+/* Return the size of the .debug_pubnames or .debug_pubtypes table
+   generated for the compilation unit.  */
 
-static void
-add_arange (tree decl, dw_die_ref die)
+static unsigned long
+size_of_pubnames (VEC (pubname_entry, gc) * names)
 {
-  if (! DECL_SECTION_NAME (decl))
-    return;
+  unsigned long size;
+  unsigned i;
+  pubname_ref p;
 
-  if (arange_table_in_use == arange_table_allocated)
-    {
-      arange_table_allocated += ARANGE_TABLE_INCREMENT;
-      arange_table = GGC_RESIZEVEC (dw_die_ref, arange_table,
-                                   arange_table_allocated);
-      memset (arange_table + arange_table_in_use, 0,
-             ARANGE_TABLE_INCREMENT * sizeof (dw_die_ref));
-    }
+  size = DWARF_PUBNAMES_HEADER_SIZE;
+  for (i = 0; VEC_iterate (pubname_entry, names, i, p); i++)
+    if (names != pubtype_table
+       || p->die->die_offset != 0
+       || !flag_eliminate_unused_debug_types)
+      size += strlen (p->name) + DWARF_OFFSET_SIZE + 1;
 
-  arange_table[arange_table_in_use++] = die;
+  size += DWARF_OFFSET_SIZE;
+  return size;
 }
 
-/* Output the information that goes into the .debug_aranges table.
-   Namely, define the beginning and ending address range of the
-   text section generated for this compilation unit.  */
+/* Return the size of the information in the .debug_aranges section.  */
 
-static void
-output_aranges (void)
+static unsigned long
+size_of_aranges (void)
 {
-  unsigned i;
-  unsigned long aranges_length = size_of_aranges ();
+  unsigned long size;
 
-  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
-    dw2_asm_output_data (4, 0xffffffff,
-      "Initial length escape value indicating 64-bit DWARF extension");
-  dw2_asm_output_data (DWARF_OFFSET_SIZE, aranges_length,
-                      "Length of Address Ranges Info");
-  /* Version number for aranges is still 2, even in DWARF3.  */
-  dw2_asm_output_data (2, 2, "DWARF Version");
-  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
-                        debug_info_section,
-                        "Offset of Compilation Unit Info");
-  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
-  dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
-
-  /* We need to align to twice the pointer size here.  */
-  if (DWARF_ARANGES_PAD_SIZE)
-    {
-      /* Pad using a 2 byte words so that padding is correct for any
-        pointer size.  */
-      dw2_asm_output_data (2, 0, "Pad to %d byte boundary",
-                          2 * DWARF2_ADDR_SIZE);
-      for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
-       dw2_asm_output_data (2, 0, NULL);
-    }
+  size = DWARF_ARANGES_HEADER_SIZE;
 
-  /* It is necessary not to output these entries if the sections were
-     not used; if the sections were not used, the length will be 0 and
-     the address may end up as 0 if the section is discarded by ld
-     --gc-sections, leaving an invalid (0, 0) entry that can be
-     confused with the terminator.  */
+  /* Count the address/length pair for this compilation unit.  */
   if (text_section_used)
-    {
-      dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_section_label, "Address");
-      dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
-                           text_section_label, "Length");
-    }
+    size += 2 * DWARF2_ADDR_SIZE;
   if (cold_text_section_used)
-    {
-      dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label,
-                          "Address");
-      dw2_asm_output_delta (DWARF2_ADDR_SIZE, cold_end_label,
-                           cold_text_section_label, "Length");
-    }
-
-  for (i = 0; i < arange_table_in_use; i++)
-    {
-      dw_die_ref die = arange_table[i];
+    size += 2 * DWARF2_ADDR_SIZE;
+  size += 2 * DWARF2_ADDR_SIZE * arange_table_in_use;
 
-      /* We shouldn't see aranges for DIEs outside of the main CU.  */
-      gcc_assert (die->die_mark);
+  /* Count the two zero words used to terminated the address range table.  */
+  size += 2 * DWARF2_ADDR_SIZE;
+  return size;
+}
+\f
+/* Select the encoding of an attribute value.  */
 
-      if (die->die_tag == DW_TAG_subprogram)
+static enum dwarf_form
+value_format (dw_attr_ref a)
+{
+  switch (a->dw_attr_val.val_class)
+    {
+    case dw_val_class_addr:
+      /* Only very few attributes allow DW_FORM_addr.  */
+      switch (a->dw_attr)
        {
-         dw2_asm_output_addr (DWARF2_ADDR_SIZE, get_AT_low_pc (die),
-                              "Address");
-         dw2_asm_output_delta (DWARF2_ADDR_SIZE, get_AT_hi_pc (die),
-                               get_AT_low_pc (die), "Length");
+       case DW_AT_low_pc:
+       case DW_AT_high_pc:
+       case DW_AT_entry_pc:
+       case DW_AT_trampoline:
+         return DW_FORM_addr;
+       default:
+         break;
+       }
+      switch (DWARF2_ADDR_SIZE)
+       {
+       case 1:
+         return DW_FORM_data1;
+       case 2:
+         return DW_FORM_data2;
+       case 4:
+         return DW_FORM_data4;
+       case 8:
+         return DW_FORM_data8;
+       default:
+         gcc_unreachable ();
+       }
+    case dw_val_class_range_list:
+    case dw_val_class_offset:
+    case dw_val_class_loc_list:
+      switch (DWARF_OFFSET_SIZE)
+       {
+       case 4:
+         return DW_FORM_data4;
+       case 8:
+         return DW_FORM_data8;
+       default:
+         gcc_unreachable ();
+       }
+    case dw_val_class_loc:
+      switch (constant_size (size_of_locs (AT_loc (a))))
+       {
+       case 1:
+         return DW_FORM_block1;
+       case 2:
+         return DW_FORM_block2;
+       default:
+         gcc_unreachable ();
+       }
+    case dw_val_class_const:
+      return DW_FORM_sdata;
+    case dw_val_class_unsigned_const:
+      switch (constant_size (AT_unsigned (a)))
+       {
+       case 1:
+         return DW_FORM_data1;
+       case 2:
+         return DW_FORM_data2;
+       case 4:
+         return DW_FORM_data4;
+       case 8:
+         return DW_FORM_data8;
+       default:
+         gcc_unreachable ();
+       }
+    case dw_val_class_const_double:
+      switch (HOST_BITS_PER_WIDE_INT)
+       {
+       case 8:
+         return DW_FORM_data2;
+       case 16:
+         return DW_FORM_data4;
+       case 32:
+         return DW_FORM_data8;
+       case 64:
+       default:
+         return DW_FORM_block1;
+       }
+    case dw_val_class_vec:
+      switch (constant_size (a->dw_attr_val.v.val_vec.length
+                            * a->dw_attr_val.v.val_vec.elt_size))
+       {
+       case 1:
+         return DW_FORM_block1;
+       case 2:
+         return DW_FORM_block2;
+       case 4:
+         return DW_FORM_block4;
+       default:
+         gcc_unreachable ();
        }
+    case dw_val_class_flag:
+      return DW_FORM_flag;
+    case dw_val_class_die_ref:
+      if (AT_ref_external (a))
+       return dwarf_version >= 4 ? DW_FORM_sig8 : DW_FORM_ref_addr;
       else
+       return DW_FORM_ref;
+    case dw_val_class_fde_ref:
+      return DW_FORM_data;
+    case dw_val_class_lbl_id:
+      return DW_FORM_addr;
+    case dw_val_class_lineptr:
+    case dw_val_class_macptr:
+      return DW_FORM_data;
+    case dw_val_class_str:
+      return AT_string_form (a);
+    case dw_val_class_file:
+      switch (constant_size (maybe_emit_file (a->dw_attr_val.v.val_file)))
        {
-         /* A static variable; extract the symbol from DW_AT_location.
-            Note that this code isn't currently hit, as we only emit
-            aranges for functions (jason 9/23/99).  */
-         dw_attr_ref a = get_AT (die, DW_AT_location);
-         dw_loc_descr_ref loc;
-
-         gcc_assert (a && AT_class (a) == dw_val_class_loc);
+       case 1:
+         return DW_FORM_data1;
+       case 2:
+         return DW_FORM_data2;
+       case 4:
+         return DW_FORM_data4;
+       default:
+         gcc_unreachable ();
+       }
 
-         loc = AT_loc (a);
-         gcc_assert (loc->dw_loc_opc == DW_OP_addr);
+    case dw_val_class_data8:
+      return DW_FORM_data8;
 
-         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE,
-                                  loc->dw_loc_oprnd1.v.val_addr, "Address");
-         dw2_asm_output_data (DWARF2_ADDR_SIZE,
-                              get_AT_unsigned (die, DW_AT_byte_size),
-                              "Length");
-       }
+    default:
+      gcc_unreachable ();
     }
+}
 
-  /* Output the terminator words.  */
-  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
-  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+/* Output the encoding of an attribute value.  */
+
+static void
+output_value_format (dw_attr_ref a)
+{
+  enum dwarf_form form = value_format (a);
+
+  dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
 }
 
-/* Add a new entry to .debug_ranges.  Return the offset at which it
-   was placed.  */
+/* Output the .debug_abbrev section which defines the DIE abbreviation
+   table.  */
 
-static unsigned int
-add_ranges_num (int num)
+static void
+output_abbrev_section (void)
 {
-  unsigned int in_use = ranges_table_in_use;
+  unsigned long abbrev_id;
 
-  if (in_use == ranges_table_allocated)
+  for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
     {
-      ranges_table_allocated += RANGES_TABLE_INCREMENT;
-      ranges_table = GGC_RESIZEVEC (struct dw_ranges_struct, ranges_table,
-                                   ranges_table_allocated);
-      memset (ranges_table + ranges_table_in_use, 0,
-             RANGES_TABLE_INCREMENT * sizeof (struct dw_ranges_struct));
-    }
+      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
+      unsigned ix;
+      dw_attr_ref a_attr;
 
-  ranges_table[in_use].num = num;
-  ranges_table_in_use = in_use + 1;
+      dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
+      dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
+                                  dwarf_tag_name (abbrev->die_tag));
 
-  return in_use * 2 * DWARF2_ADDR_SIZE;
-}
+      if (abbrev->die_child != NULL)
+       dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
+      else
+       dw2_asm_output_data (1, DW_children_no, "DW_children_no");
 
-/* Add a new entry to .debug_ranges corresponding to a block, or a
-   range terminator if BLOCK is NULL.  */
+      for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
+          ix++)
+       {
+         dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
+                                      dwarf_attr_name (a_attr->dw_attr));
+         output_value_format (a_attr);
+       }
 
-static unsigned int
-add_ranges (const_tree block)
-{
-  return add_ranges_num (block ? BLOCK_NUMBER (block) : 0);
+      dw2_asm_output_data (1, 0, NULL);
+      dw2_asm_output_data (1, 0, NULL);
+    }
+
+  /* Terminate the table.  */
+  dw2_asm_output_data (1, 0, NULL);
 }
 
-/* Add a new entry to .debug_ranges corresponding to a pair of
-   labels.  */
+/* Output a symbol we can use to refer to this DIE from another CU.  */
 
-static unsigned int
-add_ranges_by_labels (const char *begin, const char *end)
+static inline void
+output_die_symbol (dw_die_ref die)
 {
-  unsigned int in_use = ranges_by_label_in_use;
+  char *sym = die->die_id.die_symbol;
 
-  if (in_use == ranges_by_label_allocated)
-    {
-      ranges_by_label_allocated += RANGES_TABLE_INCREMENT;
-      ranges_by_label = GGC_RESIZEVEC (struct dw_ranges_by_label_struct,
-                                      ranges_by_label,
-                                      ranges_by_label_allocated);
-      memset (ranges_by_label + ranges_by_label_in_use, 0,
-             RANGES_TABLE_INCREMENT
-             * sizeof (struct dw_ranges_by_label_struct));
-    }
+  if (sym == 0)
+    return;
 
-  ranges_by_label[in_use].begin = begin;
-  ranges_by_label[in_use].end = end;
-  ranges_by_label_in_use = in_use + 1;
+  if (strncmp (sym, DIE_LABEL_PREFIX, sizeof (DIE_LABEL_PREFIX) - 1) == 0)
+    /* We make these global, not weak; if the target doesn't support
+       .linkonce, it doesn't support combining the sections, so debugging
+       will break.  */
+    targetm.asm_out.globalize_label (asm_out_file, sym);
 
-  return add_ranges_num (-(int)in_use - 1);
+  ASM_OUTPUT_LABEL (asm_out_file, sym);
 }
 
-static void
-output_ranges (void)
+/* Return a new location list, given the begin and end range, and the
+   expression.  */
+
+static inline dw_loc_list_ref
+new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
+             const char *section)
 {
-  unsigned i;
-  static const char *const start_fmt = "Offset 0x%x";
-  const char *fmt = start_fmt;
+  dw_loc_list_ref retlist = GGC_CNEW (dw_loc_list_node);
 
-  for (i = 0; i < ranges_table_in_use; i++)
-    {
-      int block_num = ranges_table[i].num;
+  retlist->begin = begin;
+  retlist->end = end;
+  retlist->expr = expr;
+  retlist->section = section;
 
-      if (block_num > 0)
-       {
-         char blabel[MAX_ARTIFICIAL_LABEL_BYTES];
-         char elabel[MAX_ARTIFICIAL_LABEL_BYTES];
+  return retlist;
+}
 
-         ASM_GENERATE_INTERNAL_LABEL (blabel, BLOCK_BEGIN_LABEL, block_num);
-         ASM_GENERATE_INTERNAL_LABEL (elabel, BLOCK_END_LABEL, block_num);
+/* Generate a new internal symbol for this location list node, if it
+   hasn't got one yet.  */
 
-         /* If all code is in the text section, then the compilation
-            unit base address defaults to DW_AT_low_pc, which is the
-            base of the text section.  */
-         if (!have_multiple_function_sections)
-           {
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
-                                   text_section_label,
-                                   fmt, i * 2 * DWARF2_ADDR_SIZE);
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
-                                   text_section_label, NULL);
-           }
+static inline void
+gen_llsym (dw_loc_list_ref list)
+{
+  gcc_assert (!list->ll_symbol);
+  list->ll_symbol = gen_internal_sym ("LLST");
+}
 
-         /* Otherwise, the compilation unit base address is zero,
-            which allows us to use absolute addresses, and not worry
-            about whether the target supports cross-section
-            arithmetic.  */
-         else
-           {
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
-                                  fmt, i * 2 * DWARF2_ADDR_SIZE);
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE, elabel, NULL);
-           }
+/* Output the location list given to us.  */
 
-         fmt = NULL;
-       }
+static void
+output_loc_list (dw_loc_list_ref list_head)
+{
+  dw_loc_list_ref curr = list_head;
 
-      /* Negative block_num stands for an index into ranges_by_label.  */
-      else if (block_num < 0)
-       {
-         int lab_idx = - block_num - 1;
+  ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
 
-         if (!have_multiple_function_sections)
-           {
-             gcc_unreachable ();
-#if 0
-             /* If we ever use add_ranges_by_labels () for a single
-                function section, all we have to do is to take out
-                the #if 0 above.  */
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE,
-                                   ranges_by_label[lab_idx].begin,
-                                   text_section_label,
-                                   fmt, i * 2 * DWARF2_ADDR_SIZE);
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE,
-                                   ranges_by_label[lab_idx].end,
-                                   text_section_label, NULL);
-#endif
-           }
-         else
-           {
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE,
-                                  ranges_by_label[lab_idx].begin,
-                                  fmt, i * 2 * DWARF2_ADDR_SIZE);
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE,
-                                  ranges_by_label[lab_idx].end,
-                                  NULL);
-           }
+  /* Walk the location list, and output each range + expression.  */
+  for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
+    {
+      unsigned long size;
+      /* Don't output an entry that starts and ends at the same address.  */
+      if (strcmp (curr->begin, curr->end) == 0)
+       continue;
+      if (!have_multiple_function_sections)
+       {
+         dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
+                               "Location list begin address (%s)",
+                               list_head->ll_symbol);
+         dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->end, curr->section,
+                               "Location list end address (%s)",
+                               list_head->ll_symbol);
        }
       else
        {
-         dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
-         dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
-         fmt = start_fmt;
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->begin,
+                              "Location list begin address (%s)",
+                              list_head->ll_symbol);
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->end,
+                              "Location list end address (%s)",
+                              list_head->ll_symbol);
        }
+      size = size_of_locs (curr->expr);
+
+      /* Output the block length for this list of location operations.  */
+      gcc_assert (size <= 0xffff);
+      dw2_asm_output_data (2, size, "%s", "Location expression size");
+
+      output_loc_sequence (curr->expr);
     }
+
+  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
+                      "Location list terminator begin (%s)",
+                      list_head->ll_symbol);
+  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
+                      "Location list terminator end (%s)",
+                      list_head->ll_symbol);
 }
 
-/* Data structure containing information about input files.  */
-struct file_info
-{
-  const char *path;    /* Complete file name.  */
-  const char *fname;   /* File name part.  */
-  int length;          /* Length of entire string.  */
-  struct dwarf_file_data * file_idx;   /* Index in input file table.  */
-  int dir_idx;         /* Index in directory table.  */
-};
+/* Output a type signature.  */
 
-/* Data structure containing information about directories with source
-   files.  */
-struct dir_info
+static inline void
+output_signature (const char *sig, const char *name)
 {
-  const char *path;    /* Path including directory name.  */
-  int length;          /* Path length.  */
-  int prefix;          /* Index of directory entry which is a prefix.  */
-  int count;           /* Number of files in this directory.  */
-  int dir_idx;         /* Index of directory used as base.  */
-};
+  int i;
 
-/* Callback function for file_info comparison.  We sort by looking at
-   the directories in the path.  */
+  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+    dw2_asm_output_data (1, sig[i], i == 0 ? "%s" : NULL, name);
+}
 
-static int
-file_info_cmp (const void *p1, const void *p2)
+/* Output the DIE and its attributes.  Called recursively to generate
+   the definitions of each child DIE.  */
+
+static void
+output_die (dw_die_ref die)
 {
-  const struct file_info *const s1 = (const struct file_info *) p1;
-  const struct file_info *const s2 = (const struct file_info *) p2;
-  const unsigned char *cp1;
-  const unsigned char *cp2;
+  dw_attr_ref a;
+  dw_die_ref c;
+  unsigned long size;
+  unsigned ix;
 
-  /* Take care of file names without directories.  We need to make sure that
-     we return consistent values to qsort since some will get confused if
-     we return the same value when identical operands are passed in opposite
-     orders.  So if neither has a directory, return 0 and otherwise return
-     1 or -1 depending on which one has the directory.  */
-  if ((s1->path == s1->fname || s2->path == s2->fname))
-    return (s2->path == s2->fname) - (s1->path == s1->fname);
+  /* If someone in another CU might refer to us, set up a symbol for
+     them to point to.  */
+  if (dwarf_version < 4 && die->die_id.die_symbol)
+    output_die_symbol (die);
 
-  cp1 = (const unsigned char *) s1->path;
-  cp2 = (const unsigned char *) s2->path;
+  dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (0x%lx) %s)",
+                              (unsigned long)die->die_offset,
+                              dwarf_tag_name (die->die_tag));
 
-  while (1)
+  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
     {
-      ++cp1;
-      ++cp2;
-      /* Reached the end of the first path?  If so, handle like above.  */
-      if ((cp1 == (const unsigned char *) s1->fname)
-         || (cp2 == (const unsigned char *) s2->fname))
-       return ((cp2 == (const unsigned char *) s2->fname)
-               - (cp1 == (const unsigned char *) s1->fname));
-
-      /* Character of current path component the same?  */
-      else if (*cp1 != *cp2)
-       return *cp1 - *cp2;
-    }
-}
+      const char *name = dwarf_attr_name (a->dw_attr);
 
-struct file_name_acquire_data
-{
-  struct file_info *files;
-  int used_files;
-  int max_files;
-};
+      switch (AT_class (a))
+       {
+       case dw_val_class_addr:
+         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
+         break;
 
-/* Traversal function for the hash table.  */
+       case dw_val_class_offset:
+         dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
+                              "%s", name);
+         break;
 
-static int
-file_name_acquire (void ** slot, void *data)
-{
-  struct file_name_acquire_data *fnad = (struct file_name_acquire_data *) data;
-  struct dwarf_file_data *d = (struct dwarf_file_data *) *slot;
-  struct file_info *fi;
-  const char *f;
+       case dw_val_class_range_list:
+         {
+           char *p = strchr (ranges_section_label, '\0');
 
-  gcc_assert (fnad->max_files >= d->emitted_number);
+           sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
+                    a->dw_attr_val.v.val_offset);
+           dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
+                                  debug_ranges_section, "%s", name);
+           *p = '\0';
+         }
+         break;
 
-  if (! d->emitted_number)
-    return 1;
+       case dw_val_class_loc:
+         size = size_of_locs (AT_loc (a));
 
-  gcc_assert (fnad->max_files != fnad->used_files);
+         /* Output the block length for this list of location operations.  */
+         dw2_asm_output_data (constant_size (size), size, "%s", name);
 
-  fi = fnad->files + fnad->used_files++;
+         output_loc_sequence (AT_loc (a));
+         break;
 
-  /* Skip all leading "./".  */
-  f = d->filename;
-  while (f[0] == '.' && IS_DIR_SEPARATOR (f[1]))
-    f += 2;
+       case dw_val_class_const:
+         /* ??? It would be slightly more efficient to use a scheme like is
+            used for unsigned constants below, but gdb 4.x does not sign
+            extend.  Gdb 5.x does sign extend.  */
+         dw2_asm_output_data_sleb128 (AT_int (a), "%s", name);
+         break;
 
-  /* Create a new array entry.  */
-  fi->path = f;
-  fi->length = strlen (f);
-  fi->file_idx = d;
-
-  /* Search for the file name part.  */
-  f = strrchr (f, DIR_SEPARATOR);
-#if defined (DIR_SEPARATOR_2)
-  {
-    char *g = strrchr (fi->path, DIR_SEPARATOR_2);
+       case dw_val_class_unsigned_const:
+         dw2_asm_output_data (constant_size (AT_unsigned (a)),
+                              AT_unsigned (a), "%s", name);
+         break;
 
-    if (g != NULL)
-      {
-       if (f == NULL || f < g)
-         f = g;
-      }
-  }
-#endif
+       case dw_val_class_const_double:
+         {
+           unsigned HOST_WIDE_INT first, second;
 
-  fi->fname = f == NULL ? fi->path : f + 1;
-  return 1;
-}
+           if (HOST_BITS_PER_WIDE_INT >= 64)
+             dw2_asm_output_data (1,
+                                  2 * HOST_BITS_PER_WIDE_INT
+                                  / HOST_BITS_PER_CHAR,
+                                  NULL);
 
-/* Output the directory table and the file name table.  We try to minimize
-   the total amount of memory needed.  A heuristic is used to avoid large
-   slowdowns with many input files.  */
+           if (WORDS_BIG_ENDIAN)
+             {
+               first = a->dw_attr_val.v.val_double.high;
+               second = a->dw_attr_val.v.val_double.low;
+             }
+           else
+             {
+               first = a->dw_attr_val.v.val_double.low;
+               second = a->dw_attr_val.v.val_double.high;
+             }
 
-static void
-output_file_names (void)
-{
-  struct file_name_acquire_data fnad;
-  int numfiles;
-  struct file_info *files;
-  struct dir_info *dirs;
-  int *saved;
-  int *savehere;
-  int *backmap;
-  int ndirs;
-  int idx_offset;
-  int i;
-  int idx;
+           dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
+                                first, name);
+           dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
+                                second, NULL);
+         }
+         break;
 
-  if (!last_emitted_file)
-    {
-      dw2_asm_output_data (1, 0, "End directory table");
-      dw2_asm_output_data (1, 0, "End file name table");
-      return;
-    }
+       case dw_val_class_vec:
+         {
+           unsigned int elt_size = a->dw_attr_val.v.val_vec.elt_size;
+           unsigned int len = a->dw_attr_val.v.val_vec.length;
+           unsigned int i;
+           unsigned char *p;
 
-  numfiles = last_emitted_file->emitted_number;
+           dw2_asm_output_data (constant_size (len * elt_size),
+                                len * elt_size, "%s", name);
+           if (elt_size > sizeof (HOST_WIDE_INT))
+             {
+               elt_size /= 2;
+               len *= 2;
+             }
+           for (i = 0, p = a->dw_attr_val.v.val_vec.array;
+                i < len;
+                i++, p += elt_size)
+             dw2_asm_output_data (elt_size, extract_int (p, elt_size),
+                                  "fp or vector constant word %u", i);
+           break;
+         }
 
-  /* Allocate the various arrays we need.  */
-  files = XALLOCAVEC (struct file_info, numfiles);
-  dirs = XALLOCAVEC (struct dir_info, numfiles);
+       case dw_val_class_flag:
+         dw2_asm_output_data (1, AT_flag (a), "%s", name);
+         break;
 
-  fnad.files = files;
-  fnad.used_files = 0;
-  fnad.max_files = numfiles;
-  htab_traverse (file_table, file_name_acquire, &fnad);
-  gcc_assert (fnad.used_files == fnad.max_files);
+       case dw_val_class_loc_list:
+         {
+           char *sym = AT_loc_list (a)->ll_symbol;
 
-  qsort (files, numfiles, sizeof (files[0]), file_info_cmp);
+           gcc_assert (sym);
+           dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
+                                  "%s", name);
+         }
+         break;
 
-  /* Find all the different directories used.  */
-  dirs[0].path = files[0].path;
-  dirs[0].length = files[0].fname - files[0].path;
-  dirs[0].prefix = -1;
-  dirs[0].count = 1;
-  dirs[0].dir_idx = 0;
-  files[0].dir_idx = 0;
-  ndirs = 1;
+       case dw_val_class_die_ref:
+         if (AT_ref_external (a))
+           {
+             if (dwarf_version >= 4)
+               {
+                 comdat_type_node_ref type_node =
+                   AT_ref (a)->die_id.die_type_node;
 
-  for (i = 1; i < numfiles; i++)
-    if (files[i].fname - files[i].path == dirs[ndirs - 1].length
-       && memcmp (dirs[ndirs - 1].path, files[i].path,
-                  dirs[ndirs - 1].length) == 0)
-      {
-       /* Same directory as last entry.  */
-       files[i].dir_idx = ndirs - 1;
-       ++dirs[ndirs - 1].count;
-      }
-    else
-      {
-       int j;
+                 gcc_assert (type_node);
+                 output_signature (type_node->signature, name);
+               }
+             else
+               {
+                 char *sym = AT_ref (a)->die_id.die_symbol;
+                 int size;
+
+                 gcc_assert (sym);
+                 /* In DWARF2, DW_FORM_ref_addr is sized by target address
+                    length, whereas in DWARF3 it's always sized as an
+                    offset.  */
+                 if (dwarf_version == 2)
+                   size = DWARF2_ADDR_SIZE;
+                 else
+                   size = DWARF_OFFSET_SIZE;
+                 dw2_asm_output_offset (size, sym, debug_info_section, "%s",
+                                        name);
+               }
+           }
+         else
+           {
+             gcc_assert (AT_ref (a)->die_offset);
+             dw2_asm_output_data (DWARF_OFFSET_SIZE, AT_ref (a)->die_offset,
+                                  "%s", name);
+           }
+         break;
 
-       /* This is a new directory.  */
-       dirs[ndirs].path = files[i].path;
-       dirs[ndirs].length = files[i].fname - files[i].path;
-       dirs[ndirs].count = 1;
-       dirs[ndirs].dir_idx = ndirs;
-       files[i].dir_idx = ndirs;
+       case dw_val_class_fde_ref:
+         {
+           char l1[20];
 
-       /* Search for a prefix.  */
-       dirs[ndirs].prefix = -1;
-       for (j = 0; j < ndirs; j++)
-         if (dirs[j].length < dirs[ndirs].length
-             && dirs[j].length > 1
-             && (dirs[ndirs].prefix == -1
-                 || dirs[j].length > dirs[dirs[ndirs].prefix].length)
-             && memcmp (dirs[j].path, dirs[ndirs].path, dirs[j].length) == 0)
-           dirs[ndirs].prefix = j;
+           ASM_GENERATE_INTERNAL_LABEL (l1, FDE_LABEL,
+                                        a->dw_attr_val.v.val_fde_index * 2);
+           dw2_asm_output_offset (DWARF_OFFSET_SIZE, l1, debug_frame_section,
+                                  "%s", name);
+         }
+         break;
 
-       ++ndirs;
-      }
+       case dw_val_class_lbl_id:
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
+         break;
 
-  /* Now to the actual work.  We have to find a subset of the directories which
-     allow expressing the file name using references to the directory table
-     with the least amount of characters.  We do not do an exhaustive search
-     where we would have to check out every combination of every single
-     possible prefix.  Instead we use a heuristic which provides nearly optimal
-     results in most cases and never is much off.  */
-  saved = XALLOCAVEC (int, ndirs);
-  savehere = XALLOCAVEC (int, ndirs);
+       case dw_val_class_lineptr:
+         dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
+                                debug_line_section, "%s", name);
+         break;
 
-  memset (saved, '\0', ndirs * sizeof (saved[0]));
-  for (i = 0; i < ndirs; i++)
-    {
-      int j;
-      int total;
+       case dw_val_class_macptr:
+         dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
+                                debug_macinfo_section, "%s", name);
+         break;
 
-      /* We can always save some space for the current directory.  But this
-        does not mean it will be enough to justify adding the directory.  */
-      savehere[i] = dirs[i].length;
-      total = (savehere[i] - saved[i]) * dirs[i].count;
+       case dw_val_class_str:
+         if (AT_string_form (a) == 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
+           dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
+         break;
 
-      for (j = i + 1; j < ndirs; j++)
-       {
-         savehere[j] = 0;
-         if (saved[j] < dirs[i].length)
-           {
-             /* Determine whether the dirs[i] path is a prefix of the
-                dirs[j] path.  */
-             int k;
+       case dw_val_class_file:
+         {
+           int f = maybe_emit_file (a->dw_attr_val.v.val_file);
 
-             k = dirs[j].prefix;
-             while (k != -1 && k != (int) i)
-               k = dirs[k].prefix;
+           dw2_asm_output_data (constant_size (f), f, "%s (%s)", name,
+                                a->dw_attr_val.v.val_file->filename);
+           break;
+         }
 
-             if (k == (int) i)
-               {
-                 /* Yes it is.  We can possibly save some memory by
-                    writing the filenames in dirs[j] relative to
-                    dirs[i].  */
-                 savehere[j] = dirs[i].length;
-                 total += (savehere[j] - saved[j]) * dirs[j].count;
-               }
-           }
-       }
+       case dw_val_class_data8:
+         {
+           int i;
 
-      /* Check whether we can save enough to justify adding the dirs[i]
-        directory.  */
-      if (total > dirs[i].length + 1)
-       {
-         /* It's worthwhile adding.  */
-         for (j = i; j < ndirs; j++)
-           if (savehere[j] > 0)
-             {
-               /* Remember how much we saved for this directory so far.  */
-               saved[j] = savehere[j];
+           for (i = 0; i < 8; i++)
+             dw2_asm_output_data (1, a->dw_attr_val.v.val_data8[i],
+                                  i == 0 ? "%s" : NULL, name);
+           break;
+         }
 
-               /* Remember the prefix directory.  */
-               dirs[j].dir_idx = i;
-             }
+       default:
+         gcc_unreachable ();
        }
     }
 
-  /* Emit the directory name table.  */
-  idx = 1;
-  idx_offset = dirs[0].length > 0 ? 1 : 0;
-  for (i = 1 - idx_offset; i < ndirs; i++)
-    dw2_asm_output_nstring (dirs[i].path, dirs[i].length - 1,
-                           "Directory Entry: 0x%x", i + idx_offset);
+  FOR_EACH_CHILD (die, c, output_die (c));
 
-  dw2_asm_output_data (1, 0, "End directory table");
+  /* Add null byte to terminate sibling list.  */
+  if (die->die_child != NULL)
+    dw2_asm_output_data (1, 0, "end of children of DIE 0x%lx",
+                        (unsigned long) die->die_offset);
+}
 
-  /* We have to emit them in the order of emitted_number since that's
-     used in the debug info generation.  To do this efficiently we
-     generate a back-mapping of the indices first.  */
-  backmap = XALLOCAVEC (int, numfiles);
-  for (i = 0; i < numfiles; i++)
-    backmap[files[i].file_idx->emitted_number - 1] = i;
+/* Output the compilation unit that appears at the beginning of the
+   .debug_info section, and precedes the DIE descriptions.  */
 
-  /* Now write all the file names.  */
-  for (i = 0; i < numfiles; i++)
-    {
-      int file_idx = backmap[i];
-      int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
+static void
+output_compilation_unit_header (void)
+{
+  int ver = dwarf_version;
 
-      dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
-                             "File Entry: 0x%x", (unsigned) i + 1);
+  /* Don't mark the output as DWARF-4 until we make full use of the
+     version 4 extensions, and gdb supports them.  For now, -gdwarf-4
+     selects only a few extensions from the DWARF-4 spec.  */
+  if (ver > 3)
+    ver = 3;
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+    dw2_asm_output_data (4, 0xffffffff,
+      "Initial length escape value indicating 64-bit DWARF extension");
+  dw2_asm_output_data (DWARF_OFFSET_SIZE,
+                      next_die_offset - DWARF_INITIAL_LENGTH_SIZE,
+                      "Length of Compilation Unit Info");
+  dw2_asm_output_data (2, ver, "DWARF version number");
+  dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
+                        debug_abbrev_section,
+                        "Offset Into Abbrev. Section");
+  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+}
 
-      /* Include directory index.  */
-      dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+/* Output the compilation unit DIE and its children.  */
 
-      /* Modification time.  */
-      dw2_asm_output_data_uleb128 (0, NULL);
+static void
+output_comp_unit (dw_die_ref die, int output_if_empty)
+{
+  const char *secname;
+  char *oldsym, *tmp;
 
-      /* File length in bytes.  */
-      dw2_asm_output_data_uleb128 (0, NULL);
+  /* Unless we are outputting main CU, we may throw away empty ones.  */
+  if (!output_if_empty && die->die_child == NULL)
+    return;
+
+  /* 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);
+
+  oldsym = die->die_id.die_symbol;
+  if (oldsym)
+    {
+      tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
+
+      sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym);
+      secname = tmp;
+      die->die_id.die_symbol = NULL;
+      switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
     }
+  else
+    switch_to_section (debug_info_section);
 
-  dw2_asm_output_data (1, 0, "End file name table");
-}
+  /* Output debugging information.  */
+  output_compilation_unit_header ();
+  output_die (die);
 
+  /* Leave the marks on the main CU, so we can check them in
+     output_pubnames.  */
+  if (oldsym)
+    {
+      unmark_dies (die);
+      die->die_id.die_symbol = oldsym;
+    }
+}
 
-/* Output the source line number correspondence information.  This
-   information goes into the .debug_line section.  */
+/* Output a comdat type unit DIE and its children.  */
 
 static void
-output_line_info (void)
+output_comdat_type_unit (comdat_type_node *node)
 {
-  char l1[20], l2[20], p1[20], p2[20];
-  char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
-  char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES];
-  unsigned opc;
-  unsigned n_op_args;
-  unsigned long lt_index;
-  unsigned long current_line;
-  long line_offset;
-  long line_delta;
-  unsigned long current_file;
-  unsigned long function;
+  const char *secname;
+  char *tmp;
+  int i;
+#if defined (OBJECT_FORMAT_ELF)
+  tree comdat_key;
+#endif
 
-  ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (p1, LN_PROLOG_AS_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (p2, LN_PROLOG_END_LABEL, 0);
+  /* First mark all the DIEs in this CU so we know which get local refs.  */
+  mark_dies (node->root_die);
 
-  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
-    dw2_asm_output_data (4, 0xffffffff,
-      "Initial length escape value indicating 64-bit DWARF extension");
-  dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
-                       "Length of Source Line Info");
-  ASM_OUTPUT_LABEL (asm_out_file, l1);
+  build_abbrev_table (node->root_die);
 
-  dw2_asm_output_data (2, dwarf_version, "DWARF Version");
-  dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
-  ASM_OUTPUT_LABEL (asm_out_file, p1);
+  /* Initialize the beginning DIE offset - and calculate sizes/offsets.  */
+  next_die_offset = DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE;
+  calc_die_sizes (node->root_die);
+
+#if defined (OBJECT_FORMAT_ELF)
+  secname = ".debug_types";
+  tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2);
+  sprintf (tmp, "wt.");
+  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+    sprintf (tmp + 3 + i * 2, "%02x", node->signature[i] & 0xff);
+  comdat_key = get_identifier (tmp);
+  targetm.asm_out.named_section (secname,
+                                 SECTION_DEBUG | SECTION_LINKONCE,
+                                 comdat_key);
+#else
+  tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2);
+  sprintf (tmp, ".gnu.linkonce.wt.");
+  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+    sprintf (tmp + 17 + i * 2, "%02x", node->signature[i] & 0xff);
+  secname = tmp;
+  switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
+#endif
 
-  /* Define the architecture-dependent minimum instruction length (in
-   bytes).  In this implementation of DWARF, this field is used for
-   information purposes only.  Since GCC generates assembly language,
-   we have no a priori knowledge of how many instruction bytes are
-   generated for each source line, and therefore can use only the
-   DW_LNE_set_address and DW_LNS_fixed_advance_pc line information
-   commands.  Accordingly, we fix this as `1', which is "correct
-   enough" for all architectures, and don't let the target override.  */
-  dw2_asm_output_data (1, 1,
-                      "Minimum Instruction Length");
+  /* Output debugging information.  */
+  output_compilation_unit_header ();
+  output_signature (node->signature, "Type Signature");
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, node->type_die->die_offset,
+                      "Offset to Type DIE");
+  output_die (node->root_die);
 
-  dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START,
-                      "Default is_stmt_start flag");
-  dw2_asm_output_data (1, DWARF_LINE_BASE,
-                      "Line Base Value (Special Opcodes)");
-  dw2_asm_output_data (1, DWARF_LINE_RANGE,
-                      "Line Range Value (Special Opcodes)");
-  dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE,
-                      "Special Opcode Base");
+  unmark_dies (node->root_die);
+}
 
-  for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; opc++)
-    {
-      switch (opc)
-       {
-       case DW_LNS_advance_pc:
-       case DW_LNS_advance_line:
-       case DW_LNS_set_file:
-       case DW_LNS_set_column:
-       case DW_LNS_fixed_advance_pc:
-         n_op_args = 1;
-         break;
-       default:
-         n_op_args = 0;
-         break;
-       }
+/* Return the DWARF2/3 pubname associated with a decl.  */
 
-      dw2_asm_output_data (1, n_op_args, "opcode: 0x%x has %d args",
-                          opc, n_op_args);
-    }
+static const char *
+dwarf2_name (tree decl, int scope)
+{
+  return lang_hooks.dwarf_name (decl, scope ? 1 : 0);
+}
 
-  /* Write out the information about the files we use.  */
-  output_file_names ();
-  ASM_OUTPUT_LABEL (asm_out_file, p2);
+/* Add a new entry to .debug_pubnames if appropriate.  */
 
-  /* We used to set the address register to the first location in the text
-     section here, but that didn't accomplish anything since we already
-     have a line note for the opening brace of the first function.  */
+static void
+add_pubname_string (const char *str, dw_die_ref die)
+{
+  pubname_entry e;
 
-  /* Generate the line number to PC correspondence table, encoded as
-     a series of state machine operations.  */
-  current_file = 1;
-  current_line = 1;
+  e.die = die;
+  e.name = xstrdup (str);
+  VEC_safe_push (pubname_entry, gc, pubname_table, &e);
+}
 
-  if (cfun && in_cold_section_p)
-    strcpy (prev_line_label, crtl->subsections.cold_section_label);
-  else
-    strcpy (prev_line_label, text_section_label);
-  for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
+static void
+add_pubname (tree decl, dw_die_ref die)
+{
+  if (TREE_PUBLIC (decl))
     {
-      dw_line_info_ref line_info = &line_info_table[lt_index];
-
-#if 0
-      /* Disable this optimization for now; GDB wants to see two line notes
-        at the beginning of a function so it can find the end of the
-        prologue.  */
-
-      /* Don't emit anything for redundant notes.  Just updating the
-        address doesn't accomplish anything, because we already assume
-        that anything after the last address is this line.  */
-      if (line_info->dw_line_num == current_line
-         && line_info->dw_file_num == current_file)
-       continue;
-#endif
+      const char *name = dwarf2_name (decl, 1);
+      if (name)
+       add_pubname_string (name, die);
+    }
+}
 
-      /* Emit debug info for the address of the current line.
+/* Add a new entry to .debug_pubtypes if appropriate.  */
 
-        Unfortunately, we have little choice here currently, and must always
-        use the most general form.  GCC does not know the address delta
-        itself, so we can't use DW_LNS_advance_pc.  Many ports do have length
-        attributes which will give an upper bound on the address range.  We
-        could perhaps use length attributes to determine when it is safe to
-        use DW_LNS_fixed_advance_pc.  */
+static void
+add_pubtype (tree decl, dw_die_ref die)
+{
+  pubname_entry e;
 
-      ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index);
-      if (0)
+  e.name = NULL;
+  if ((TREE_PUBLIC (decl)
+       || die->die_parent == comp_unit_die)
+      && (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl)))
+    {
+      e.die = die;
+      if (TYPE_P (decl))
        {
-         /* This can handle deltas up to 0xffff.  This takes 3 bytes.  */
-         dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-                              "DW_LNS_fixed_advance_pc");
-         dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
+         if (TYPE_NAME (decl))
+           {
+             if (TREE_CODE (TYPE_NAME (decl)) == IDENTIFIER_NODE)
+               e.name = IDENTIFIER_POINTER (TYPE_NAME (decl));
+             else if (TREE_CODE (TYPE_NAME (decl)) == TYPE_DECL
+                      && DECL_NAME (TYPE_NAME (decl)))
+               e.name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl)));
+             else
+              e.name = xstrdup ((const char *) get_AT_string (die, DW_AT_name));
+           }
        }
       else
        {
-         /* This can handle any delta.  This takes
-            4+DWARF2_ADDR_SIZE bytes.  */
-         dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-         dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-         dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-         dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+         e.name = dwarf2_name (decl, 1);
+         if (e.name)
+           e.name = xstrdup (e.name);
        }
 
-      strcpy (prev_line_label, line_label);
+      /* If we don't have a name for the type, there's no point in adding
+        it to the table.  */
+      if (e.name && e.name[0] != '\0')
+       VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
+    }
+}
 
-      /* Emit debug info for the source file of the current line, if
-        different from the previous line.  */
-      if (line_info->dw_file_num != current_file)
-       {
-         current_file = line_info->dw_file_num;
-         dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
-         dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
-       }
+/* Output the public names table used to speed up access to externally
+   visible names; or the public types table used to find type definitions.  */
 
-      /* Emit debug info for the current line number, choosing the encoding
-        that uses the least amount of space.  */
-      if (line_info->dw_line_num != current_line)
+static void
+output_pubnames (VEC (pubname_entry, gc) * names)
+{
+  unsigned i;
+  unsigned long pubnames_length = size_of_pubnames (names);
+  pubname_ref pub;
+
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+    dw2_asm_output_data (4, 0xffffffff,
+      "Initial length escape value indicating 64-bit DWARF extension");
+  if (names == pubname_table)
+    dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
+                        "Length of Public Names Info");
+  else
+    dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
+                        "Length of Public Type Names Info");
+  /* Version number for pubnames/pubtypes is still 2, even in DWARF3.  */
+  dw2_asm_output_data (2, 2, "DWARF Version");
+  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+                        debug_info_section,
+                        "Offset of Compilation Unit Info");
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
+                      "Compilation Unit Length");
+
+  for (i = 0; VEC_iterate (pubname_entry, names, i, pub); i++)
+    {
+      /* We shouldn't see pubnames for DIEs outside of the main CU.  */
+      if (names == pubname_table)
+       gcc_assert (pub->die->die_mark);
+
+      if (names != pubtype_table
+         || pub->die->die_offset != 0
+         || !flag_eliminate_unused_debug_types)
        {
-         line_offset = line_info->dw_line_num - current_line;
-         line_delta = line_offset - DWARF_LINE_BASE;
-         current_line = line_info->dw_line_num;
-         if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
-           /* This can handle deltas from -10 to 234, using the current
-              definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE.  This
-              takes 1 byte.  */
-           dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
-                                "line %lu", current_line);
-         else
-           {
-             /* This can handle any delta.  This takes at least 4 bytes,
-                depending on the value being encoded.  */
-             dw2_asm_output_data (1, DW_LNS_advance_line,
-                                  "advance to line %lu", current_line);
-             dw2_asm_output_data_sleb128 (line_offset, NULL);
-             dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
-           }
+         dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
+                              "DIE offset");
+
+         dw2_asm_output_nstring (pub->name, -1, "external name");
        }
-      else
-       /* We still need to start a new row, so output a copy insn.  */
-       dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
     }
 
-  /* Emit debug info for the address of the end of the function.  */
-  if (0)
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL);
+}
+
+/* Add a new entry to .debug_aranges if appropriate.  */
+
+static void
+add_arange (tree decl, dw_die_ref die)
+{
+  if (! DECL_SECTION_NAME (decl))
+    return;
+
+  if (arange_table_in_use == arange_table_allocated)
     {
-      dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-                          "DW_LNS_fixed_advance_pc");
-      dw2_asm_output_delta (2, text_end_label, prev_line_label, NULL);
+      arange_table_allocated += ARANGE_TABLE_INCREMENT;
+      arange_table = GGC_RESIZEVEC (dw_die_ref, arange_table,
+                                   arange_table_allocated);
+      memset (arange_table + arange_table_in_use, 0,
+             ARANGE_TABLE_INCREMENT * sizeof (dw_die_ref));
     }
-  else
+
+  arange_table[arange_table_in_use++] = die;
+}
+
+/* Output the information that goes into the .debug_aranges table.
+   Namely, define the beginning and ending address range of the
+   text section generated for this compilation unit.  */
+
+static void
+output_aranges (void)
+{
+  unsigned i;
+  unsigned long aranges_length = size_of_aranges ();
+
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+    dw2_asm_output_data (4, 0xffffffff,
+      "Initial length escape value indicating 64-bit DWARF extension");
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, aranges_length,
+                      "Length of Address Ranges Info");
+  /* Version number for aranges is still 2, even in DWARF3.  */
+  dw2_asm_output_data (2, 2, "DWARF Version");
+  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+                        debug_info_section,
+                        "Offset of Compilation Unit Info");
+  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
+  dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
+
+  /* We need to align to twice the pointer size here.  */
+  if (DWARF_ARANGES_PAD_SIZE)
     {
-      dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-      dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-      dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-      dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_end_label, NULL);
+      /* Pad using a 2 byte words so that padding is correct for any
+        pointer size.  */
+      dw2_asm_output_data (2, 0, "Pad to %d byte boundary",
+                          2 * DWARF2_ADDR_SIZE);
+      for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
+       dw2_asm_output_data (2, 0, NULL);
     }
 
-  dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
-  dw2_asm_output_data_uleb128 (1, NULL);
-  dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
+  /* It is necessary not to output these entries if the sections were
+     not used; if the sections were not used, the length will be 0 and
+     the address may end up as 0 if the section is discarded by ld
+     --gc-sections, leaving an invalid (0, 0) entry that can be
+     confused with the terminator.  */
+  if (text_section_used)
+    {
+      dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_section_label, "Address");
+      dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
+                           text_section_label, "Length");
+    }
+  if (cold_text_section_used)
+    {
+      dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label,
+                          "Address");
+      dw2_asm_output_delta (DWARF2_ADDR_SIZE, cold_end_label,
+                           cold_text_section_label, "Length");
+    }
 
-  function = 0;
-  current_file = 1;
-  current_line = 1;
-  for (lt_index = 0; lt_index < separate_line_info_table_in_use;)
+  for (i = 0; i < arange_table_in_use; i++)
     {
-      dw_separate_line_info_ref line_info
-       = &separate_line_info_table[lt_index];
+      dw_die_ref die = arange_table[i];
 
-#if 0
-      /* Don't emit anything for redundant notes.  */
-      if (line_info->dw_line_num == current_line
-         && line_info->dw_file_num == current_file
-         && line_info->function == function)
-       goto cont;
-#endif
+      /* We shouldn't see aranges for DIEs outside of the main CU.  */
+      gcc_assert (die->die_mark);
 
-      /* Emit debug info for the address of the current line.  If this is
-        a new function, or the first line of a function, then we need
-        to handle it differently.  */
-      ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL,
-                                  lt_index);
-      if (function != line_info->function)
+      if (die->die_tag == DW_TAG_subprogram)
        {
-         function = line_info->function;
-
-         /* Set the address register to the first line in the function.  */
-         dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-         dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-         dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-         dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, get_AT_low_pc (die),
+                              "Address");
+         dw2_asm_output_delta (DWARF2_ADDR_SIZE, get_AT_hi_pc (die),
+                               get_AT_low_pc (die), "Length");
        }
       else
        {
-         /* ??? See the DW_LNS_advance_pc comment above.  */
-         if (0)
-           {
-             dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-                                  "DW_LNS_fixed_advance_pc");
-             dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
-           }
-         else
-           {
-             dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-             dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-             dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
-           }
-       }
+         /* A static variable; extract the symbol from DW_AT_location.
+            Note that this code isn't currently hit, as we only emit
+            aranges for functions (jason 9/23/99).  */
+         dw_attr_ref a = get_AT (die, DW_AT_location);
+         dw_loc_descr_ref loc;
 
-      strcpy (prev_line_label, line_label);
+         gcc_assert (a && AT_class (a) == dw_val_class_loc);
 
-      /* Emit debug info for the source file of the current line, if
-        different from the previous line.  */
-      if (line_info->dw_file_num != current_file)
-       {
-         current_file = line_info->dw_file_num;
-         dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
-         dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
-       }
+         loc = AT_loc (a);
+         gcc_assert (loc->dw_loc_opc == DW_OP_addr);
 
-      /* Emit debug info for the current line number, choosing the encoding
-        that uses the least amount of space.  */
-      if (line_info->dw_line_num != current_line)
-       {
-         line_offset = line_info->dw_line_num - current_line;
-         line_delta = line_offset - DWARF_LINE_BASE;
-         current_line = line_info->dw_line_num;
-         if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
-           dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
-                                "line %lu", current_line);
-         else
-           {
-             dw2_asm_output_data (1, DW_LNS_advance_line,
-                                  "advance to line %lu", current_line);
-             dw2_asm_output_data_sleb128 (line_offset, NULL);
-             dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
-           }
+         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE,
+                                  loc->dw_loc_oprnd1.v.val_addr, "Address");
+         dw2_asm_output_data (DWARF2_ADDR_SIZE,
+                              get_AT_unsigned (die, DW_AT_byte_size),
+                              "Length");
        }
+    }
+
+  /* Output the terminator words.  */
+  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+}
+
+/* Add a new entry to .debug_ranges.  Return the offset at which it
+   was placed.  */
+
+static unsigned int
+add_ranges_num (int num)
+{
+  unsigned int in_use = ranges_table_in_use;
+
+  if (in_use == ranges_table_allocated)
+    {
+      ranges_table_allocated += RANGES_TABLE_INCREMENT;
+      ranges_table = GGC_RESIZEVEC (struct dw_ranges_struct, ranges_table,
+                                   ranges_table_allocated);
+      memset (ranges_table + ranges_table_in_use, 0,
+             RANGES_TABLE_INCREMENT * sizeof (struct dw_ranges_struct));
+    }
+
+  ranges_table[in_use].num = num;
+  ranges_table_in_use = in_use + 1;
+
+  return in_use * 2 * DWARF2_ADDR_SIZE;
+}
+
+/* Add a new entry to .debug_ranges corresponding to a block, or a
+   range terminator if BLOCK is NULL.  */
+
+static unsigned int
+add_ranges (const_tree block)
+{
+  return add_ranges_num (block ? BLOCK_NUMBER (block) : 0);
+}
+
+/* Add a new entry to .debug_ranges corresponding to a pair of
+   labels.  */
+
+static void
+add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
+                     bool *added)
+{
+  unsigned int in_use = ranges_by_label_in_use;
+  unsigned int offset;
+
+  if (in_use == ranges_by_label_allocated)
+    {
+      ranges_by_label_allocated += RANGES_TABLE_INCREMENT;
+      ranges_by_label = GGC_RESIZEVEC (struct dw_ranges_by_label_struct,
+                                      ranges_by_label,
+                                      ranges_by_label_allocated);
+      memset (ranges_by_label + ranges_by_label_in_use, 0,
+             RANGES_TABLE_INCREMENT
+             * sizeof (struct dw_ranges_by_label_struct));
+    }
+
+  ranges_by_label[in_use].begin = begin;
+  ranges_by_label[in_use].end = end;
+  ranges_by_label_in_use = in_use + 1;
+
+  offset = add_ranges_num (-(int)in_use - 1);
+  if (!*added)
+    {
+      add_AT_range_list (die, DW_AT_ranges, offset);
+      *added = true;
+    }
+}
+
+static void
+output_ranges (void)
+{
+  unsigned i;
+  static const char *const start_fmt = "Offset 0x%x";
+  const char *fmt = start_fmt;
+
+  for (i = 0; i < ranges_table_in_use; i++)
+    {
+      int block_num = ranges_table[i].num;
+
+      if (block_num > 0)
+       {
+         char blabel[MAX_ARTIFICIAL_LABEL_BYTES];
+         char elabel[MAX_ARTIFICIAL_LABEL_BYTES];
+
+         ASM_GENERATE_INTERNAL_LABEL (blabel, BLOCK_BEGIN_LABEL, block_num);
+         ASM_GENERATE_INTERNAL_LABEL (elabel, BLOCK_END_LABEL, block_num);
+
+         /* If all code is in the text section, then the compilation
+            unit base address defaults to DW_AT_low_pc, which is the
+            base of the text section.  */
+         if (!have_multiple_function_sections)
+           {
+             dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
+                                   text_section_label,
+                                   fmt, i * 2 * DWARF2_ADDR_SIZE);
+             dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
+                                   text_section_label, NULL);
+           }
+
+         /* Otherwise, the compilation unit base address is zero,
+            which allows us to use absolute addresses, and not worry
+            about whether the target supports cross-section
+            arithmetic.  */
+         else
+           {
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
+                                  fmt, i * 2 * DWARF2_ADDR_SIZE);
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE, elabel, NULL);
+           }
+
+         fmt = NULL;
+       }
+
+      /* Negative block_num stands for an index into ranges_by_label.  */
+      else if (block_num < 0)
+       {
+         int lab_idx = - block_num - 1;
+
+         if (!have_multiple_function_sections)
+           {
+             gcc_unreachable ();
+#if 0
+             /* If we ever use add_ranges_by_labels () for a single
+                function section, all we have to do is to take out
+                the #if 0 above.  */
+             dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+                                   ranges_by_label[lab_idx].begin,
+                                   text_section_label,
+                                   fmt, i * 2 * DWARF2_ADDR_SIZE);
+             dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+                                   ranges_by_label[lab_idx].end,
+                                   text_section_label, NULL);
+#endif
+           }
+         else
+           {
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+                                  ranges_by_label[lab_idx].begin,
+                                  fmt, i * 2 * DWARF2_ADDR_SIZE);
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+                                  ranges_by_label[lab_idx].end,
+                                  NULL);
+           }
+       }
+      else
+       {
+         dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+         dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+         fmt = start_fmt;
+       }
+    }
+}
+
+/* Data structure containing information about input files.  */
+struct file_info
+{
+  const char *path;    /* Complete file name.  */
+  const char *fname;   /* File name part.  */
+  int length;          /* Length of entire string.  */
+  struct dwarf_file_data * file_idx;   /* Index in input file table.  */
+  int dir_idx;         /* Index in directory table.  */
+};
+
+/* Data structure containing information about directories with source
+   files.  */
+struct dir_info
+{
+  const char *path;    /* Path including directory name.  */
+  int length;          /* Path length.  */
+  int prefix;          /* Index of directory entry which is a prefix.  */
+  int count;           /* Number of files in this directory.  */
+  int dir_idx;         /* Index of directory used as base.  */
+};
+
+/* Callback function for file_info comparison.  We sort by looking at
+   the directories in the path.  */
+
+static int
+file_info_cmp (const void *p1, const void *p2)
+{
+  const struct file_info *const s1 = (const struct file_info *) p1;
+  const struct file_info *const s2 = (const struct file_info *) p2;
+  const unsigned char *cp1;
+  const unsigned char *cp2;
+
+  /* Take care of file names without directories.  We need to make sure that
+     we return consistent values to qsort since some will get confused if
+     we return the same value when identical operands are passed in opposite
+     orders.  So if neither has a directory, return 0 and otherwise return
+     1 or -1 depending on which one has the directory.  */
+  if ((s1->path == s1->fname || s2->path == s2->fname))
+    return (s2->path == s2->fname) - (s1->path == s1->fname);
+
+  cp1 = (const unsigned char *) s1->path;
+  cp2 = (const unsigned char *) s2->path;
+
+  while (1)
+    {
+      ++cp1;
+      ++cp2;
+      /* Reached the end of the first path?  If so, handle like above.  */
+      if ((cp1 == (const unsigned char *) s1->fname)
+         || (cp2 == (const unsigned char *) s2->fname))
+       return ((cp2 == (const unsigned char *) s2->fname)
+               - (cp1 == (const unsigned char *) s1->fname));
+
+      /* Character of current path component the same?  */
+      else if (*cp1 != *cp2)
+       return *cp1 - *cp2;
+    }
+}
+
+struct file_name_acquire_data
+{
+  struct file_info *files;
+  int used_files;
+  int max_files;
+};
+
+/* Traversal function for the hash table.  */
+
+static int
+file_name_acquire (void ** slot, void *data)
+{
+  struct file_name_acquire_data *fnad = (struct file_name_acquire_data *) data;
+  struct dwarf_file_data *d = (struct dwarf_file_data *) *slot;
+  struct file_info *fi;
+  const char *f;
+
+  gcc_assert (fnad->max_files >= d->emitted_number);
+
+  if (! d->emitted_number)
+    return 1;
+
+  gcc_assert (fnad->max_files != fnad->used_files);
+
+  fi = fnad->files + fnad->used_files++;
+
+  /* Skip all leading "./".  */
+  f = d->filename;
+  while (f[0] == '.' && IS_DIR_SEPARATOR (f[1]))
+    f += 2;
+
+  /* Create a new array entry.  */
+  fi->path = f;
+  fi->length = strlen (f);
+  fi->file_idx = d;
+
+  /* Search for the file name part.  */
+  f = strrchr (f, DIR_SEPARATOR);
+#if defined (DIR_SEPARATOR_2)
+  {
+    char *g = strrchr (fi->path, DIR_SEPARATOR_2);
+
+    if (g != NULL)
+      {
+       if (f == NULL || f < g)
+         f = g;
+      }
+  }
+#endif
+
+  fi->fname = f == NULL ? fi->path : f + 1;
+  return 1;
+}
+
+/* Output the directory table and the file name table.  We try to minimize
+   the total amount of memory needed.  A heuristic is used to avoid large
+   slowdowns with many input files.  */
+
+static void
+output_file_names (void)
+{
+  struct file_name_acquire_data fnad;
+  int numfiles;
+  struct file_info *files;
+  struct dir_info *dirs;
+  int *saved;
+  int *savehere;
+  int *backmap;
+  int ndirs;
+  int idx_offset;
+  int i;
+
+  if (!last_emitted_file)
+    {
+      dw2_asm_output_data (1, 0, "End directory table");
+      dw2_asm_output_data (1, 0, "End file name table");
+      return;
+    }
+
+  numfiles = last_emitted_file->emitted_number;
+
+  /* Allocate the various arrays we need.  */
+  files = XALLOCAVEC (struct file_info, numfiles);
+  dirs = XALLOCAVEC (struct dir_info, numfiles);
+
+  fnad.files = files;
+  fnad.used_files = 0;
+  fnad.max_files = numfiles;
+  htab_traverse (file_table, file_name_acquire, &fnad);
+  gcc_assert (fnad.used_files == fnad.max_files);
+
+  qsort (files, numfiles, sizeof (files[0]), file_info_cmp);
+
+  /* Find all the different directories used.  */
+  dirs[0].path = files[0].path;
+  dirs[0].length = files[0].fname - files[0].path;
+  dirs[0].prefix = -1;
+  dirs[0].count = 1;
+  dirs[0].dir_idx = 0;
+  files[0].dir_idx = 0;
+  ndirs = 1;
+
+  for (i = 1; i < numfiles; i++)
+    if (files[i].fname - files[i].path == dirs[ndirs - 1].length
+       && memcmp (dirs[ndirs - 1].path, files[i].path,
+                  dirs[ndirs - 1].length) == 0)
+      {
+       /* Same directory as last entry.  */
+       files[i].dir_idx = ndirs - 1;
+       ++dirs[ndirs - 1].count;
+      }
+    else
+      {
+       int j;
+
+       /* This is a new directory.  */
+       dirs[ndirs].path = files[i].path;
+       dirs[ndirs].length = files[i].fname - files[i].path;
+       dirs[ndirs].count = 1;
+       dirs[ndirs].dir_idx = ndirs;
+       files[i].dir_idx = ndirs;
+
+       /* Search for a prefix.  */
+       dirs[ndirs].prefix = -1;
+       for (j = 0; j < ndirs; j++)
+         if (dirs[j].length < dirs[ndirs].length
+             && dirs[j].length > 1
+             && (dirs[ndirs].prefix == -1
+                 || dirs[j].length > dirs[dirs[ndirs].prefix].length)
+             && memcmp (dirs[j].path, dirs[ndirs].path, dirs[j].length) == 0)
+           dirs[ndirs].prefix = j;
+
+       ++ndirs;
+      }
+
+  /* Now to the actual work.  We have to find a subset of the directories which
+     allow expressing the file name using references to the directory table
+     with the least amount of characters.  We do not do an exhaustive search
+     where we would have to check out every combination of every single
+     possible prefix.  Instead we use a heuristic which provides nearly optimal
+     results in most cases and never is much off.  */
+  saved = XALLOCAVEC (int, ndirs);
+  savehere = XALLOCAVEC (int, ndirs);
+
+  memset (saved, '\0', ndirs * sizeof (saved[0]));
+  for (i = 0; i < ndirs; i++)
+    {
+      int j;
+      int total;
+
+      /* We can always save some space for the current directory.  But this
+        does not mean it will be enough to justify adding the directory.  */
+      savehere[i] = dirs[i].length;
+      total = (savehere[i] - saved[i]) * dirs[i].count;
+
+      for (j = i + 1; j < ndirs; j++)
+       {
+         savehere[j] = 0;
+         if (saved[j] < dirs[i].length)
+           {
+             /* Determine whether the dirs[i] path is a prefix of the
+                dirs[j] path.  */
+             int k;
+
+             k = dirs[j].prefix;
+             while (k != -1 && k != (int) i)
+               k = dirs[k].prefix;
+
+             if (k == (int) i)
+               {
+                 /* Yes it is.  We can possibly save some memory by
+                    writing the filenames in dirs[j] relative to
+                    dirs[i].  */
+                 savehere[j] = dirs[i].length;
+                 total += (savehere[j] - saved[j]) * dirs[j].count;
+               }
+           }
+       }
+
+      /* Check whether we can save enough to justify adding the dirs[i]
+        directory.  */
+      if (total > dirs[i].length + 1)
+       {
+         /* It's worthwhile adding.  */
+         for (j = i; j < ndirs; j++)
+           if (savehere[j] > 0)
+             {
+               /* Remember how much we saved for this directory so far.  */
+               saved[j] = savehere[j];
+
+               /* Remember the prefix directory.  */
+               dirs[j].dir_idx = i;
+             }
+       }
+    }
+
+  /* Emit the directory name table.  */
+  idx_offset = dirs[0].length > 0 ? 1 : 0;
+  for (i = 1 - idx_offset; i < ndirs; i++)
+    dw2_asm_output_nstring (dirs[i].path,
+                           dirs[i].length
+                            - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
+                           "Directory Entry: 0x%x", i + idx_offset);
+
+  dw2_asm_output_data (1, 0, "End directory table");
+
+  /* We have to emit them in the order of emitted_number since that's
+     used in the debug info generation.  To do this efficiently we
+     generate a back-mapping of the indices first.  */
+  backmap = XALLOCAVEC (int, numfiles);
+  for (i = 0; i < numfiles; i++)
+    backmap[files[i].file_idx->emitted_number - 1] = i;
+
+  /* Now write all the file names.  */
+  for (i = 0; i < numfiles; i++)
+    {
+      int file_idx = backmap[i];
+      int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
+
+#ifdef VMS_DEBUGGING_INFO
+#define MAX_VMS_VERSION_LEN 6 /* ";32768" */
+
+      /* Setting these fields can lead to debugger miscomparisons,
+         but VMS Debug requires them to be set correctly.  */
+
+      int ver;
+      long long cdt;
+      long siz;
+      int maxfilelen = strlen (files[file_idx].path)
+                              + dirs[dir_idx].length
+                              + MAX_VMS_VERSION_LEN + 1;
+      char *filebuf = XALLOCAVEC (char, maxfilelen);
+
+      vms_file_stats_name (files[file_idx].path, 0, 0, 0, &ver);
+      snprintf (filebuf, maxfilelen, "%s;%d",
+               files[file_idx].path + dirs[dir_idx].length, ver);
+
+      dw2_asm_output_nstring
+       (filebuf, -1, "File Entry: 0x%x", (unsigned) i + 1);
+
+      /* Include directory index.  */
+      dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+
+      /* Modification time.  */
+      dw2_asm_output_data_uleb128
+        ((vms_file_stats_name (files[file_idx].path, &cdt, 0, 0, 0) == 0)
+         ? cdt : 0,
+        NULL);
+
+      /* File length in bytes.  */
+      dw2_asm_output_data_uleb128
+        ((vms_file_stats_name (files[file_idx].path, 0, &siz, 0, 0) == 0)
+         ? siz : 0,
+        NULL);
+#else
+      dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
+                             "File Entry: 0x%x", (unsigned) i + 1);
+
+      /* Include directory index.  */
+      dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+
+      /* Modification time.  */
+      dw2_asm_output_data_uleb128 (0, NULL);
+
+      /* File length in bytes.  */
+      dw2_asm_output_data_uleb128 (0, NULL);
+#endif
+    }
+
+  dw2_asm_output_data (1, 0, "End file name table");
+}
+
+
+/* Output the source line number correspondence information.  This
+   information goes into the .debug_line section.  */
+
+static void
+output_line_info (void)
+{
+  char l1[20], l2[20], p1[20], p2[20];
+  char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
+  char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES];
+  unsigned opc;
+  unsigned n_op_args;
+  unsigned long lt_index;
+  unsigned long current_line;
+  long line_offset;
+  long line_delta;
+  unsigned long current_file;
+  unsigned long function;
+  int ver = dwarf_version;
+
+  /* Don't mark the output as DWARF-4 until we make full use of the
+     version 4 extensions, and gdb supports them.  For now, -gdwarf-4
+     selects only a few extensions from the DWARF-4 spec.  */
+  if (ver > 3)
+    ver = 3;
+
+  ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (p1, LN_PROLOG_AS_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (p2, LN_PROLOG_END_LABEL, 0);
+
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+    dw2_asm_output_data (4, 0xffffffff,
+      "Initial length escape value indicating 64-bit DWARF extension");
+  dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
+                       "Length of Source Line Info");
+  ASM_OUTPUT_LABEL (asm_out_file, l1);
+
+  dw2_asm_output_data (2, ver, "DWARF Version");
+  dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
+  ASM_OUTPUT_LABEL (asm_out_file, p1);
+
+  /* Define the architecture-dependent minimum instruction length (in
+   bytes).  In this implementation of DWARF, this field is used for
+   information purposes only.  Since GCC generates assembly language,
+   we have no a priori knowledge of how many instruction bytes are
+   generated for each source line, and therefore can use only the
+   DW_LNE_set_address and DW_LNS_fixed_advance_pc line information
+   commands.  Accordingly, we fix this as `1', which is "correct
+   enough" for all architectures, and don't let the target override.  */
+  dw2_asm_output_data (1, 1,
+                      "Minimum Instruction Length");
+
+  dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START,
+                      "Default is_stmt_start flag");
+  dw2_asm_output_data (1, DWARF_LINE_BASE,
+                      "Line Base Value (Special Opcodes)");
+  dw2_asm_output_data (1, DWARF_LINE_RANGE,
+                      "Line Range Value (Special Opcodes)");
+  dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE,
+                      "Special Opcode Base");
+
+  for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; opc++)
+    {
+      switch (opc)
+       {
+       case DW_LNS_advance_pc:
+       case DW_LNS_advance_line:
+       case DW_LNS_set_file:
+       case DW_LNS_set_column:
+       case DW_LNS_fixed_advance_pc:
+         n_op_args = 1;
+         break;
+       default:
+         n_op_args = 0;
+         break;
+       }
+
+      dw2_asm_output_data (1, n_op_args, "opcode: 0x%x has %d args",
+                          opc, n_op_args);
+    }
+
+  /* Write out the information about the files we use.  */
+  output_file_names ();
+  ASM_OUTPUT_LABEL (asm_out_file, p2);
+
+  /* We used to set the address register to the first location in the text
+     section here, but that didn't accomplish anything since we already
+     have a line note for the opening brace of the first function.  */
+
+  /* Generate the line number to PC correspondence table, encoded as
+     a series of state machine operations.  */
+  current_file = 1;
+  current_line = 1;
+
+  if (cfun && in_cold_section_p)
+    strcpy (prev_line_label, crtl->subsections.cold_section_label);
+  else
+    strcpy (prev_line_label, text_section_label);
+  for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
+    {
+      dw_line_info_ref line_info = &line_info_table[lt_index];
+
+#if 0
+      /* Disable this optimization for now; GDB wants to see two line notes
+        at the beginning of a function so it can find the end of the
+        prologue.  */
+
+      /* Don't emit anything for redundant notes.  Just updating the
+        address doesn't accomplish anything, because we already assume
+        that anything after the last address is this line.  */
+      if (line_info->dw_line_num == current_line
+         && line_info->dw_file_num == current_file)
+       continue;
+#endif
+
+      /* Emit debug info for the address of the current line.
+
+        Unfortunately, we have little choice here currently, and must always
+        use the most general form.  GCC does not know the address delta
+        itself, so we can't use DW_LNS_advance_pc.  Many ports do have length
+        attributes which will give an upper bound on the address range.  We
+        could perhaps use length attributes to determine when it is safe to
+        use DW_LNS_fixed_advance_pc.  */
+
+      ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index);
+      if (0)
+       {
+         /* This can handle deltas up to 0xffff.  This takes 3 bytes.  */
+         dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
+                              "DW_LNS_fixed_advance_pc");
+         dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
+       }
+      else
+       {
+         /* This can handle any delta.  This takes
+            4+DWARF2_ADDR_SIZE bytes.  */
+         dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+         dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+         dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+       }
+
+      strcpy (prev_line_label, line_label);
+
+      /* Emit debug info for the source file of the current line, if
+        different from the previous line.  */
+      if (line_info->dw_file_num != current_file)
+       {
+         current_file = line_info->dw_file_num;
+         dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
+         dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
+       }
+
+      /* Emit debug info for the current line number, choosing the encoding
+        that uses the least amount of space.  */
+      if (line_info->dw_line_num != current_line)
+       {
+         line_offset = line_info->dw_line_num - current_line;
+         line_delta = line_offset - DWARF_LINE_BASE;
+         current_line = line_info->dw_line_num;
+         if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
+           /* This can handle deltas from -10 to 234, using the current
+              definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE.  This
+              takes 1 byte.  */
+           dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
+                                "line %lu", current_line);
+         else
+           {
+             /* This can handle any delta.  This takes at least 4 bytes,
+                depending on the value being encoded.  */
+             dw2_asm_output_data (1, DW_LNS_advance_line,
+                                  "advance to line %lu", current_line);
+             dw2_asm_output_data_sleb128 (line_offset, NULL);
+             dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
+           }
+       }
+      else
+       /* We still need to start a new row, so output a copy insn.  */
+       dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
+    }
+
+  /* Emit debug info for the address of the end of the function.  */
+  if (0)
+    {
+      dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
+                          "DW_LNS_fixed_advance_pc");
+      dw2_asm_output_delta (2, text_end_label, prev_line_label, NULL);
+    }
+  else
+    {
+      dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+      dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+      dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+      dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_end_label, NULL);
+    }
+
+  dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
+  dw2_asm_output_data_uleb128 (1, NULL);
+  dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
+
+  function = 0;
+  current_file = 1;
+  current_line = 1;
+  for (lt_index = 0; lt_index < separate_line_info_table_in_use;)
+    {
+      dw_separate_line_info_ref line_info
+       = &separate_line_info_table[lt_index];
+
+#if 0
+      /* Don't emit anything for redundant notes.  */
+      if (line_info->dw_line_num == current_line
+         && line_info->dw_file_num == current_file
+         && line_info->function == function)
+       goto cont;
+#endif
+
+      /* Emit debug info for the address of the current line.  If this is
+        a new function, or the first line of a function, then we need
+        to handle it differently.  */
+      ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL,
+                                  lt_index);
+      if (function != line_info->function)
+       {
+         function = line_info->function;
+
+         /* Set the address register to the first line in the function.  */
+         dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+         dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+         dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+       }
+      else
+       {
+         /* ??? See the DW_LNS_advance_pc comment above.  */
+         if (0)
+           {
+             dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
+                                  "DW_LNS_fixed_advance_pc");
+             dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
+           }
+         else
+           {
+             dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+             dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+             dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+           }
+       }
+
+      strcpy (prev_line_label, line_label);
+
+      /* Emit debug info for the source file of the current line, if
+        different from the previous line.  */
+      if (line_info->dw_file_num != current_file)
+       {
+         current_file = line_info->dw_file_num;
+         dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
+         dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
+       }
+
+      /* Emit debug info for the current line number, choosing the encoding
+        that uses the least amount of space.  */
+      if (line_info->dw_line_num != current_line)
+       {
+         line_offset = line_info->dw_line_num - current_line;
+         line_delta = line_offset - DWARF_LINE_BASE;
+         current_line = line_info->dw_line_num;
+         if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
+           dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
+                                "line %lu", current_line);
+         else
+           {
+             dw2_asm_output_data (1, DW_LNS_advance_line,
+                                  "advance to line %lu", current_line);
+             dw2_asm_output_data_sleb128 (line_offset, NULL);
+             dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
+           }
+       }
+      else
+       dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
+
+#if 0
+    cont:
+#endif
+
+      lt_index++;
+
+      /* If we're done with a function, end its sequence.  */
+      if (lt_index == separate_line_info_table_in_use
+         || separate_line_info_table[lt_index].function != function)
+       {
+         current_file = 1;
+         current_line = 1;
+
+         /* Emit debug info for the address of the end of the function.  */
+         ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function);
+         if (0)
+           {
+             dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
+                                  "DW_LNS_fixed_advance_pc");
+             dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
+           }
+         else
+           {
+             dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+             dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+             dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+           }
+
+         /* Output the marker for the end of this sequence.  */
+         dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
+         dw2_asm_output_data_uleb128 (1, NULL);
+         dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
+       }
+    }
+
+  /* Output the marker for the end of the line number info.  */
+  ASM_OUTPUT_LABEL (asm_out_file, l2);
+}
+
+/* Return the size of the .debug_dcall table for the compilation unit.  */
+
+static unsigned long
+size_of_dcall_table (void)
+{
+  unsigned long size;
+  unsigned int i;
+  dcall_entry *p;
+  tree last_poc_decl = NULL;
+
+  /* Header:  version + debug info section pointer + pointer size.  */
+  size = 2 + DWARF_OFFSET_SIZE + 1;
+
+  /* Each entry:  code label + DIE offset.  */
+  for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, p); i++)
+    {
+      gcc_assert (p->targ_die != NULL);
+      /* Insert a "from" entry when the point-of-call DIE offset changes.  */
+      if (p->poc_decl != last_poc_decl)
+        {
+          dw_die_ref poc_die = lookup_decl_die (p->poc_decl);
+          gcc_assert (poc_die);
+          last_poc_decl = p->poc_decl;
+          if (poc_die)
+            size += (DWARF_OFFSET_SIZE
+                     + size_of_uleb128 (poc_die->die_offset));
+        }
+      size += DWARF_OFFSET_SIZE + size_of_uleb128 (p->targ_die->die_offset);
+    }
+
+  return size;
+}
+
+/* Output the direct call table used to disambiguate PC values when
+   identical function have been merged.  */
+
+static void
+output_dcall_table (void)
+{
+  unsigned i;
+  unsigned long dcall_length = size_of_dcall_table ();
+  dcall_entry *p;
+  char poc_label[MAX_ARTIFICIAL_LABEL_BYTES];
+  tree last_poc_decl = NULL;
+
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+    dw2_asm_output_data (4, 0xffffffff,
+      "Initial length escape value indicating 64-bit DWARF extension");
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, dcall_length,
+                      "Length of Direct Call Table");
+  dw2_asm_output_data (2, 4, "Version number");
+  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+                        debug_info_section,
+                        "Offset of Compilation Unit Info");
+  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+
+  for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, p); i++)
+    {
+      /* Insert a "from" entry when the point-of-call DIE offset changes.  */
+      if (p->poc_decl != last_poc_decl)
+        {
+          dw_die_ref poc_die = lookup_decl_die (p->poc_decl);
+          last_poc_decl = p->poc_decl;
+          if (poc_die)
+            {
+              dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "New caller");
+              dw2_asm_output_data_uleb128 (poc_die->die_offset,
+                                           "Caller DIE offset");
+            }
+        }
+      ASM_GENERATE_INTERNAL_LABEL (poc_label, "LPOC", p->poc_label_num);
+      dw2_asm_output_addr (DWARF_OFFSET_SIZE, poc_label, "Point of call");
+      dw2_asm_output_data_uleb128 (p->targ_die->die_offset,
+                                   "Callee DIE offset");
+    }
+}
+\f
+/* Return the size of the .debug_vcall table for the compilation unit.  */
+
+static unsigned long
+size_of_vcall_table (void)
+{
+  unsigned long size;
+  unsigned int i;
+  vcall_entry *p;
+
+  /* Header:  version + pointer size.  */
+  size = 2 + 1;
+
+  /* Each entry:  code label + vtable slot index.  */
+  for (i = 0; VEC_iterate (vcall_entry, vcall_table, i, p); i++)
+    size += DWARF_OFFSET_SIZE + size_of_uleb128 (p->vtable_slot);
+
+  return size;
+}
+
+/* Output the virtual call table used to disambiguate PC values when
+   identical function have been merged.  */
+
+static void
+output_vcall_table (void)
+{
+  unsigned i;
+  unsigned long vcall_length = size_of_vcall_table ();
+  vcall_entry *p;
+  char poc_label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+    dw2_asm_output_data (4, 0xffffffff,
+      "Initial length escape value indicating 64-bit DWARF extension");
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, vcall_length,
+                      "Length of Virtual Call Table");
+  dw2_asm_output_data (2, 4, "Version number");
+  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+
+  for (i = 0; VEC_iterate (vcall_entry, vcall_table, i, p); i++)
+    {
+      ASM_GENERATE_INTERNAL_LABEL (poc_label, "LPOC", p->poc_label_num);
+      dw2_asm_output_addr (DWARF_OFFSET_SIZE, poc_label, "Point of call");
+      dw2_asm_output_data_uleb128 (p->vtable_slot, "Vtable slot");
+    }
+}
+\f
+/* Given a pointer to a tree node for some base type, return a pointer to
+   a DIE that describes the given type.
+
+   This routine must only be called for GCC type nodes that correspond to
+   Dwarf base (fundamental) types.  */
+
+static dw_die_ref
+base_type_die (tree type)
+{
+  dw_die_ref base_type_result;
+  enum dwarf_type encoding;
+
+  if (TREE_CODE (type) == ERROR_MARK || TREE_CODE (type) == VOID_TYPE)
+    return 0;
+
+  /* If this is a subtype that should not be emitted as a subrange type,
+     use the base type.  See subrange_type_for_debug_p.  */
+  if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type) != NULL_TREE)
+    type = TREE_TYPE (type);
+
+  switch (TREE_CODE (type))
+    {
+    case INTEGER_TYPE:
+      if (TYPE_STRING_FLAG (type))
+       {
+         if (TYPE_UNSIGNED (type))
+           encoding = DW_ATE_unsigned_char;
+         else
+           encoding = DW_ATE_signed_char;
+       }
+      else if (TYPE_UNSIGNED (type))
+       encoding = DW_ATE_unsigned;
+      else
+       encoding = DW_ATE_signed;
+      break;
+
+    case REAL_TYPE:
+      if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))
+       {
+         if (dwarf_version >= 3 || !dwarf_strict)
+           encoding = DW_ATE_decimal_float;
+         else
+           encoding = DW_ATE_lo_user;
+       }
+      else
+       encoding = DW_ATE_float;
+      break;
+
+    case FIXED_POINT_TYPE:
+      if (!(dwarf_version >= 3 || !dwarf_strict))
+       encoding = DW_ATE_lo_user;
+      else if (TYPE_UNSIGNED (type))
+       encoding = DW_ATE_unsigned_fixed;
+      else
+       encoding = DW_ATE_signed_fixed;
+      break;
+
+      /* Dwarf2 doesn't know anything about complex ints, so use
+        a user defined type for it.  */
+    case COMPLEX_TYPE:
+      if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
+       encoding = DW_ATE_complex_float;
+      else
+       encoding = DW_ATE_lo_user;
+      break;
+
+    case BOOLEAN_TYPE:
+      /* GNU FORTRAN/Ada/C++ BOOLEAN type.  */
+      encoding = DW_ATE_boolean;
+      break;
+
+    default:
+      /* No other TREE_CODEs are Dwarf fundamental types.  */
+      gcc_unreachable ();
+    }
+
+  base_type_result = new_die (DW_TAG_base_type, comp_unit_die, type);
+
+  /* This probably indicates a bug.  */
+  if (! TYPE_NAME (type))
+    add_name_attribute (base_type_result, "__unknown__");
+
+  add_AT_unsigned (base_type_result, DW_AT_byte_size,
+                  int_size_in_bytes (type));
+  add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
+
+  return base_type_result;
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return nonzero if the
+   given input type is a Dwarf "fundamental" type.  Otherwise return null.  */
+
+static inline int
+is_base_type (tree type)
+{
+  switch (TREE_CODE (type))
+    {
+    case ERROR_MARK:
+    case VOID_TYPE:
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case FIXED_POINT_TYPE:
+    case COMPLEX_TYPE:
+    case BOOLEAN_TYPE:
+      return 1;
+
+    case ARRAY_TYPE:
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+    case ENUMERAL_TYPE:
+    case FUNCTION_TYPE:
+    case METHOD_TYPE:
+    case POINTER_TYPE:
+    case REFERENCE_TYPE:
+    case OFFSET_TYPE:
+    case LANG_TYPE:
+    case VECTOR_TYPE:
+      return 0;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return 0;
+}
+
+/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
+   node, return the size in bits for the type if it is a constant, or else
+   return the alignment for the type if the type's size is not constant, or
+   else return BITS_PER_WORD if the type actually turns out to be an
+   ERROR_MARK node.  */
+
+static inline unsigned HOST_WIDE_INT
+simple_type_size_in_bits (const_tree type)
+{
+  if (TREE_CODE (type) == ERROR_MARK)
+    return BITS_PER_WORD;
+  else if (TYPE_SIZE (type) == NULL_TREE)
+    return 0;
+  else if (host_integerp (TYPE_SIZE (type), 1))
+    return tree_low_cst (TYPE_SIZE (type), 1);
+  else
+    return TYPE_ALIGN (type);
+}
+
+/*  Given a pointer to a tree node for a subrange type, return a pointer
+    to a DIE that describes the given type.  */
+
+static dw_die_ref
+subrange_type_die (tree type, tree low, tree high, dw_die_ref context_die)
+{
+  dw_die_ref subrange_die;
+  const HOST_WIDE_INT size_in_bytes = int_size_in_bytes (type);
+
+  if (context_die == NULL)
+    context_die = comp_unit_die;
+
+  subrange_die = new_die (DW_TAG_subrange_type, context_die, type);
+
+  if (int_size_in_bytes (TREE_TYPE (type)) != size_in_bytes)
+    {
+      /* The size of the subrange type and its base type do not match,
+        so we need to generate a size attribute for the subrange type.  */
+      add_AT_unsigned (subrange_die, DW_AT_byte_size, size_in_bytes);
+    }
+
+  if (low)
+    add_bound_info (subrange_die, DW_AT_lower_bound, low);
+  if (high)
+    add_bound_info (subrange_die, DW_AT_upper_bound, high);
+
+  return subrange_die;
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
+   entry that chains various modifiers in front of the given type.  */
+
+static dw_die_ref
+modified_type_die (tree type, int is_const_type, int is_volatile_type,
+                  dw_die_ref context_die)
+{
+  enum tree_code code = TREE_CODE (type);
+  dw_die_ref mod_type_die;
+  dw_die_ref sub_die = NULL;
+  tree item_type = NULL;
+  tree qualified_type;
+  tree name, low, high;
+
+  if (code == ERROR_MARK)
+    return NULL;
+
+  /* See if we already have the appropriately qualified variant of
+     this type.  */
+  qualified_type
+    = get_qualified_type (type,
+                         ((is_const_type ? TYPE_QUAL_CONST : 0)
+                          | (is_volatile_type ? TYPE_QUAL_VOLATILE : 0)));
+
+  /* If we do, then we can just use its DIE, if it exists.  */
+  if (qualified_type)
+    {
+      mod_type_die = lookup_type_die (qualified_type);
+      if (mod_type_die)
+       return mod_type_die;
+    }
+
+  name = qualified_type ? TYPE_NAME (qualified_type) : NULL;
+
+  /* Handle C typedef types.  */
+  if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name))
+    {
+      tree dtype = TREE_TYPE (name);
+
+      if (qualified_type == dtype)
+       {
+         /* For a named type, use the typedef.  */
+         gen_type_die (qualified_type, context_die);
+         return lookup_type_die (qualified_type);
+       }
+      else if (is_const_type < TYPE_READONLY (dtype)
+              || is_volatile_type < TYPE_VOLATILE (dtype)
+              || (is_const_type <= TYPE_READONLY (dtype)
+                  && is_volatile_type <= TYPE_VOLATILE (dtype)
+                  && DECL_ORIGINAL_TYPE (name) != type))
+       /* cv-unqualified version of named type.  Just use the unnamed
+          type to which it refers.  */
+       return modified_type_die (DECL_ORIGINAL_TYPE (name),
+                                 is_const_type, is_volatile_type,
+                                 context_die);
+      /* Else cv-qualified version of named type; fall through.  */
+    }
+
+  if (is_const_type)
+    {
+      mod_type_die = new_die (DW_TAG_const_type, comp_unit_die, type);
+      sub_die = modified_type_die (type, 0, is_volatile_type, context_die);
+    }
+  else if (is_volatile_type)
+    {
+      mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die, type);
+      sub_die = modified_type_die (type, 0, 0, context_die);
+    }
+  else if (code == POINTER_TYPE)
+    {
+      mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die, type);
+      add_AT_unsigned (mod_type_die, DW_AT_byte_size,
+                      simple_type_size_in_bits (type) / BITS_PER_UNIT);
+      item_type = TREE_TYPE (type);
+      if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type)))
+       add_AT_unsigned (mod_type_die, DW_AT_address_class,
+                        TYPE_ADDR_SPACE (item_type));
+    }
+  else if (code == REFERENCE_TYPE)
+    {
+      mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die, type);
+      add_AT_unsigned (mod_type_die, DW_AT_byte_size,
+                      simple_type_size_in_bits (type) / BITS_PER_UNIT);
+      item_type = TREE_TYPE (type);
+      if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type)))
+       add_AT_unsigned (mod_type_die, DW_AT_address_class,
+                        TYPE_ADDR_SPACE (item_type));
+    }
+  else if (code == INTEGER_TYPE
+          && TREE_TYPE (type) != NULL_TREE
+          && subrange_type_for_debug_p (type, &low, &high))
+    {
+      mod_type_die = subrange_type_die (type, low, high, context_die);
+      item_type = TREE_TYPE (type);
+    }
+  else if (is_base_type (type))
+    mod_type_die = base_type_die (type);
+  else
+    {
+      gen_type_die (type, context_die);
+
+      /* We have to get the type_main_variant here (and pass that to the
+        `lookup_type_die' routine) because the ..._TYPE node we have
+        might simply be a *copy* of some original type node (where the
+        copy was created to help us keep track of typedef names) and
+        that copy might have a different TYPE_UID from the original
+        ..._TYPE node.  */
+      if (TREE_CODE (type) != VECTOR_TYPE)
+       return lookup_type_die (type_main_variant (type));
+      else
+       /* Vectors have the debugging information in the type,
+          not the main variant.  */
+       return lookup_type_die (type);
+    }
+
+  /* Builtin types don't have a DECL_ORIGINAL_TYPE.  For those,
+     don't output a DW_TAG_typedef, since there isn't one in the
+     user's program; just attach a DW_AT_name to the type.
+     Don't attach a DW_AT_name to DW_TAG_const_type or DW_TAG_volatile_type
+     if the base type already has the same name.  */
+  if (name
+      && ((TREE_CODE (name) != TYPE_DECL
+          && (qualified_type == TYPE_MAIN_VARIANT (type)
+              || (!is_const_type && !is_volatile_type)))
+         || (TREE_CODE (name) == TYPE_DECL
+             && TREE_TYPE (name) == qualified_type
+             && DECL_NAME (name))))
+    {
+      if (TREE_CODE (name) == TYPE_DECL)
+       /* Could just call add_name_and_src_coords_attributes here,
+          but since this is a builtin type it doesn't have any
+          useful source coordinates anyway.  */
+       name = DECL_NAME (name);
+      add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
+    }
+
+  if (qualified_type)
+    equate_type_number_to_die (qualified_type, mod_type_die);
+
+  if (item_type)
+    /* We must do this after the equate_type_number_to_die call, in case
+       this is a recursive type.  This ensures that the modified_type_die
+       recursion will terminate even if the type is recursive.  Recursive
+       types are possible in Ada.  */
+    sub_die = modified_type_die (item_type,
+                                TYPE_READONLY (item_type),
+                                TYPE_VOLATILE (item_type),
+                                context_die);
+
+  if (sub_die != NULL)
+    add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
+
+  return mod_type_die;
+}
+
+/* Generate DIEs for the generic parameters of T.
+   T must be either a generic type or a generic function.
+   See http://gcc.gnu.org/wiki/TemplateParmsDwarf for more.  */
+
+static void
+gen_generic_params_dies (tree t)
+{
+  tree parms, args;
+  int parms_num, i;
+  dw_die_ref die = NULL;
+
+  if (!t || (TYPE_P (t) && !COMPLETE_TYPE_P (t)))
+    return;
+
+  if (TYPE_P (t))
+    die = lookup_type_die (t);
+  else if (DECL_P (t))
+    die = lookup_decl_die (t);
+
+  gcc_assert (die);
+
+  parms = lang_hooks.get_innermost_generic_parms (t);
+  if (!parms)
+    /* T has no generic parameter. It means T is neither a generic type
+       or function. End of story.  */
+    return;
+
+  parms_num = TREE_VEC_LENGTH (parms);
+  args = lang_hooks.get_innermost_generic_args (t);
+  for (i = 0; i < parms_num; i++)
+    {
+      tree parm, arg, arg_pack_elems;
+
+      parm = TREE_VEC_ELT (parms, i);
+      arg = TREE_VEC_ELT (args, i);
+      arg_pack_elems = lang_hooks.types.get_argument_pack_elems (arg);
+      gcc_assert (parm && TREE_VALUE (parm) && arg);
+
+      if (parm && TREE_VALUE (parm) && arg)
+       {
+         /* If PARM represents a template parameter pack,
+            emit a DW_TAG_GNU_template_parameter_pack DIE, followed
+            by DW_TAG_template_*_parameter DIEs for the argument
+            pack elements of ARG. Note that ARG would then be
+            an argument pack.  */
+         if (arg_pack_elems)
+           template_parameter_pack_die (TREE_VALUE (parm),
+                                        arg_pack_elems,
+                                        die);
+         else
+           generic_parameter_die (TREE_VALUE (parm), arg,
+                                  true /* Emit DW_AT_name */, die);
+       }
+    }
+}
+
+/* Create and return a DIE for PARM which should be
+   the representation of a generic type parameter.
+   For instance, in the C++ front end, PARM would be a template parameter.
+   ARG is the argument to PARM.
+   EMIT_NAME_P if tree, the DIE will have DW_AT_name attribute set to the
+   name of the PARM.
+   PARENT_DIE is the parent DIE which the new created DIE should be added to,
+   as a child node.  */
+
+static dw_die_ref
+generic_parameter_die (tree parm, tree arg,
+                      bool emit_name_p,
+                      dw_die_ref parent_die)
+{
+  dw_die_ref tmpl_die = NULL;
+  const char *name = NULL;
+
+  if (!parm || !DECL_NAME (parm) || !arg)
+    return NULL;
+
+  /* We support non-type generic parameters and arguments,
+     type generic parameters and arguments, as well as
+     generic generic parameters (a.k.a. template template parameters in C++)
+     and arguments.  */
+  if (TREE_CODE (parm) == PARM_DECL)
+    /* PARM is a nontype generic parameter  */
+    tmpl_die = new_die (DW_TAG_template_value_param, parent_die, parm);
+  else if (TREE_CODE (parm) == TYPE_DECL)
+    /* PARM is a type generic parameter.  */
+    tmpl_die = new_die (DW_TAG_template_type_param, parent_die, parm);
+  else if (lang_hooks.decls.generic_generic_parameter_decl_p (parm))
+    /* PARM is a generic generic parameter.
+       Its DIE is a GNU extension. It shall have a
+       DW_AT_name attribute to represent the name of the template template
+       parameter, and a DW_AT_GNU_template_name attribute to represent the
+       name of the template template argument.  */
+    tmpl_die = new_die (DW_TAG_GNU_template_template_param,
+                       parent_die, parm);
+  else
+    gcc_unreachable ();
+
+  if (tmpl_die)
+    {
+      tree tmpl_type;
+
+      /* If PARM is a generic parameter pack, it means we are
+         emitting debug info for a template argument pack element.
+        In other terms, ARG is a template argument pack element.
+        In that case, we don't emit any DW_AT_name attribute for
+        the die.  */
+      if (emit_name_p)
+       {
+         name = IDENTIFIER_POINTER (DECL_NAME (parm));
+         gcc_assert (name);
+         add_AT_string (tmpl_die, DW_AT_name, name);
+       }
+
+      if (!lang_hooks.decls.generic_generic_parameter_decl_p (parm))
+       {
+         /* DWARF3, 5.6.8 says if PARM is a non-type generic parameter
+            TMPL_DIE should have a child DW_AT_type attribute that is set
+            to the type of the argument to PARM, which is ARG.
+            If PARM is a type generic parameter, TMPL_DIE should have a
+            child DW_AT_type that is set to ARG.  */
+         tmpl_type = TYPE_P (arg) ? arg : TREE_TYPE (arg);
+         add_type_attribute (tmpl_die, tmpl_type, 0,
+                             TREE_THIS_VOLATILE (tmpl_type),
+                             parent_die);
+       }
+      else
+       {
+         /* So TMPL_DIE is a DIE representing a
+            a generic generic template parameter, a.k.a template template
+            parameter in C++ and arg is a template.  */
+
+         /* The DW_AT_GNU_template_name attribute of the DIE must be set
+            to the name of the argument.  */
+         name = dwarf2_name (TYPE_P (arg) ? TYPE_NAME (arg) : arg, 1);
+         if (name)
+           add_AT_string (tmpl_die, DW_AT_GNU_template_name, name);
+       }
+
+      if (TREE_CODE (parm) == PARM_DECL)
+       /* So PARM is a non-type generic parameter.
+          DWARF3 5.6.8 says we must set a DW_AT_const_value child
+          attribute of TMPL_DIE which value represents the value
+          of ARG.
+          We must be careful here:
+          The value of ARG might reference some function decls.
+          We might currently be emitting debug info for a generic
+          type and types are emitted before function decls, we don't
+          know if the function decls referenced by ARG will actually be
+          emitted after cgraph computations.
+          So must defer the generation of the DW_AT_const_value to
+          after cgraph is ready.  */
+       append_entry_to_tmpl_value_parm_die_table (tmpl_die, arg);
+    }
+
+  return tmpl_die;
+}
+
+/* Generate and return a  DW_TAG_GNU_template_parameter_pack DIE representing.
+   PARM_PACK must be a template parameter pack. The returned DIE
+   will be child DIE of PARENT_DIE.  */
+
+static dw_die_ref
+template_parameter_pack_die (tree parm_pack,
+                            tree parm_pack_args,
+                            dw_die_ref parent_die)
+{
+  dw_die_ref die;
+  int j;
+
+  gcc_assert (parent_die && parm_pack);
+
+  die = new_die (DW_TAG_GNU_template_parameter_pack, parent_die, parm_pack);
+  add_name_and_src_coords_attributes (die, parm_pack);
+  for (j = 0; j < TREE_VEC_LENGTH (parm_pack_args); j++)
+    generic_parameter_die (parm_pack,
+                          TREE_VEC_ELT (parm_pack_args, j),
+                          false /* Don't emit DW_AT_name */,
+                          die);
+  return die;
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
+   an enumerated type.  */
+
+static inline int
+type_is_enum (const_tree type)
+{
+  return TREE_CODE (type) == ENUMERAL_TYPE;
+}
+
+/* Return the DBX register number described by a given RTL node.  */
+
+static unsigned int
+dbx_reg_number (const_rtx rtl)
+{
+  unsigned regno = REGNO (rtl);
+
+  gcc_assert (regno < FIRST_PSEUDO_REGISTER);
+
+#ifdef LEAF_REG_REMAP
+  if (current_function_uses_only_leaf_regs)
+    {
+      int leaf_reg = LEAF_REG_REMAP (regno);
+      if (leaf_reg != -1)
+       regno = (unsigned) leaf_reg;
+    }
+#endif
+
+  return DBX_REGISTER_NUMBER (regno);
+}
+
+/* Optionally add a DW_OP_piece term to a location description expression.
+   DW_OP_piece is only added if the location description expression already
+   doesn't end with DW_OP_piece.  */
+
+static void
+add_loc_descr_op_piece (dw_loc_descr_ref *list_head, int size)
+{
+  dw_loc_descr_ref loc;
+
+  if (*list_head != NULL)
+    {
+      /* Find the end of the chain.  */
+      for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
+       ;
+
+      if (loc->dw_loc_opc != DW_OP_piece)
+       loc->dw_loc_next = new_loc_descr (DW_OP_piece, size, 0);
+    }
+}
+
+/* Return a location descriptor that designates a machine register or
+   zero if there is none.  */
+
+static dw_loc_descr_ref
+reg_loc_descriptor (rtx rtl, enum var_init_status initialized)
+{
+  rtx regs;
+
+  if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
+    return 0;
+
+  regs = targetm.dwarf_register_span (rtl);
+
+  if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
+    return multiple_reg_loc_descriptor (rtl, regs, initialized);
+  else
+    return one_reg_loc_descriptor (dbx_reg_number (rtl), initialized);
+}
+
+/* Return a location descriptor that designates a machine register for
+   a given hard register number.  */
+
+static dw_loc_descr_ref
+one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized)
+{
+  dw_loc_descr_ref reg_loc_descr;
+
+  if (regno <= 31)
+    reg_loc_descr
+      = new_loc_descr ((enum dwarf_location_atom) (DW_OP_reg0 + regno), 0, 0);
+  else
+    reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0);
+
+  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&reg_loc_descr, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
+  return reg_loc_descr;
+}
+
+/* Given an RTL of a register, return a location descriptor that
+   designates a value that spans more than one register.  */
+
+static dw_loc_descr_ref
+multiple_reg_loc_descriptor (rtx rtl, rtx regs,
+                            enum var_init_status initialized)
+{
+  int nregs, size, i;
+  unsigned reg;
+  dw_loc_descr_ref loc_result = NULL;
+
+  reg = REGNO (rtl);
+#ifdef LEAF_REG_REMAP
+  if (current_function_uses_only_leaf_regs)
+    {
+      int leaf_reg = LEAF_REG_REMAP (reg);
+      if (leaf_reg != -1)
+       reg = (unsigned) leaf_reg;
+    }
+#endif
+  gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
+  nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
+
+  /* Simple, contiguous registers.  */
+  if (regs == NULL_RTX)
+    {
+      size = GET_MODE_SIZE (GET_MODE (rtl)) / nregs;
+
+      loc_result = NULL;
+      while (nregs--)
+       {
+         dw_loc_descr_ref t;
+
+         t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg),
+                                     VAR_INIT_STATUS_INITIALIZED);
+         add_loc_descr (&loc_result, t);
+         add_loc_descr_op_piece (&loc_result, size);
+         ++reg;
+       }
+      return loc_result;
+    }
+
+  /* Now onto stupid register sets in non contiguous locations.  */
+
+  gcc_assert (GET_CODE (regs) == PARALLEL);
+
+  size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
+  loc_result = NULL;
+
+  for (i = 0; i < XVECLEN (regs, 0); ++i)
+    {
+      dw_loc_descr_ref t;
+
+      t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)),
+                                 VAR_INIT_STATUS_INITIALIZED);
+      add_loc_descr (&loc_result, t);
+      size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
+      add_loc_descr_op_piece (&loc_result, size);
+    }
+
+  if (loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+  return loc_result;
+}
+
+#endif /* DWARF2_DEBUGGING_INFO */
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+
+/* Return a location descriptor that designates a constant.  */
+
+static dw_loc_descr_ref
+int_loc_descriptor (HOST_WIDE_INT i)
+{
+  enum dwarf_location_atom op;
+
+  /* Pick the smallest representation of a constant, rather than just
+     defaulting to the LEB encoding.  */
+  if (i >= 0)
+    {
+      if (i <= 31)
+       op = (enum dwarf_location_atom) (DW_OP_lit0 + i);
+      else if (i <= 0xff)
+       op = DW_OP_const1u;
+      else if (i <= 0xffff)
+       op = DW_OP_const2u;
+      else if (HOST_BITS_PER_WIDE_INT == 32
+              || i <= 0xffffffff)
+       op = DW_OP_const4u;
+      else
+       op = DW_OP_constu;
+    }
+  else
+    {
+      if (i >= -0x80)
+       op = DW_OP_const1s;
+      else if (i >= -0x8000)
+       op = DW_OP_const2s;
+      else if (HOST_BITS_PER_WIDE_INT == 32
+              || i >= -0x80000000)
+       op = DW_OP_const4s;
       else
-       dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
+       op = DW_OP_consts;
+    }
 
-#if 0
-    cont:
+  return new_loc_descr (op, i, 0);
+}
 #endif
 
-      lt_index++;
+#ifdef DWARF2_DEBUGGING_INFO
+/* Return loc description representing "address" of integer value.
+   This can appear only as toplevel expression.  */
 
-      /* If we're done with a function, end its sequence.  */
-      if (lt_index == separate_line_info_table_in_use
-         || separate_line_info_table[lt_index].function != function)
-       {
-         current_file = 1;
-         current_line = 1;
+static dw_loc_descr_ref
+address_of_int_loc_descriptor (int size, HOST_WIDE_INT i)
+{
+  int litsize;
+  dw_loc_descr_ref loc_result = NULL;
 
-         /* Emit debug info for the address of the end of the function.  */
-         ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function);
-         if (0)
-           {
-             dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-                                  "DW_LNS_fixed_advance_pc");
-             dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
-           }
-         else
-           {
-             dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-             dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-             dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
-           }
+  if (!(dwarf_version >= 4 || !dwarf_strict))
+    return NULL;
 
-         /* Output the marker for the end of this sequence.  */
-         dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
-         dw2_asm_output_data_uleb128 (1, NULL);
-         dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
-       }
+  if (i >= 0)
+    {
+      if (i <= 31)
+       litsize = 1;
+      else if (i <= 0xff)
+       litsize = 2;
+      else if (i <= 0xffff)
+       litsize = 3;
+      else if (HOST_BITS_PER_WIDE_INT == 32
+              || i <= 0xffffffff)
+       litsize = 5;
+      else
+       litsize = 1 + size_of_uleb128 ((unsigned HOST_WIDE_INT) i);
+    }
+  else
+    {
+      if (i >= -0x80)
+       litsize = 2;
+      else if (i >= -0x8000)
+       litsize = 3;
+      else if (HOST_BITS_PER_WIDE_INT == 32
+              || i >= -0x80000000)
+       litsize = 5;
+      else
+       litsize = 1 + size_of_sleb128 (i);
+    }
+  /* Determine if DW_OP_stack_value or DW_OP_implicit_value
+     is more compact.  For DW_OP_stack_value we need:
+     litsize + 1 (DW_OP_stack_value)
+     and for DW_OP_implicit_value:
+     1 (DW_OP_implicit_value) + 1 (length) + size.  */
+  if ((int) DWARF2_ADDR_SIZE >= size && litsize + 1 <= 1 + 1 + size)
+    {
+      loc_result = int_loc_descriptor (i);
+      add_loc_descr (&loc_result,
+                    new_loc_descr (DW_OP_stack_value, 0, 0));
+      return loc_result;
     }
 
-  /* Output the marker for the end of the line number info.  */
-  ASM_OUTPUT_LABEL (asm_out_file, l2);
+  loc_result = new_loc_descr (DW_OP_implicit_value,
+                             size, 0);
+  loc_result->dw_loc_oprnd2.val_class = dw_val_class_const;
+  loc_result->dw_loc_oprnd2.v.val_int = i;
+  return loc_result;
 }
-\f
-/* Given a pointer to a tree node for some base type, return a pointer to
-   a DIE that describes the given type.
 
-   This routine must only be called for GCC type nodes that correspond to
-   Dwarf base (fundamental) types.  */
+/* Return a location descriptor that designates a base+offset location.  */
 
-static dw_die_ref
-base_type_die (tree type)
+static dw_loc_descr_ref
+based_loc_descr (rtx reg, HOST_WIDE_INT offset,
+                enum var_init_status initialized)
 {
-  dw_die_ref base_type_result;
-  enum dwarf_type encoding;
-
-  if (TREE_CODE (type) == ERROR_MARK || TREE_CODE (type) == VOID_TYPE)
-    return 0;
-
-  /* If this is a subtype that should not be emitted as a subrange type,
-     use the base type.  See subrange_type_for_debug_p.  */
-  if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type) != NULL_TREE)
-    type = TREE_TYPE (type);
+  unsigned int regno;
+  dw_loc_descr_ref result;
+  dw_fde_ref fde = current_fde ();
 
-  switch (TREE_CODE (type))
+  /* We only use "frame base" when we're sure we're talking about the
+     post-prologue local stack frame.  We do this by *not* running
+     register elimination until this point, and recognizing the special
+     argument pointer and soft frame pointer rtx's.  */
+  if (reg == arg_pointer_rtx || reg == frame_pointer_rtx)
     {
-    case INTEGER_TYPE:
-      if (TYPE_STRING_FLAG (type))
+      rtx elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+
+      if (elim != reg)
        {
-         if (TYPE_UNSIGNED (type))
-           encoding = DW_ATE_unsigned_char;
-         else
-           encoding = DW_ATE_signed_char;
+         if (GET_CODE (elim) == PLUS)
+           {
+             offset += INTVAL (XEXP (elim, 1));
+             elim = XEXP (elim, 0);
+           }
+         gcc_assert ((SUPPORTS_STACK_ALIGNMENT
+                      && (elim == hard_frame_pointer_rtx
+                          || elim == stack_pointer_rtx))
+                     || elim == (frame_pointer_needed
+                                 ? hard_frame_pointer_rtx
+                                 : stack_pointer_rtx));
+
+         /* If drap register is used to align stack, use frame
+            pointer + offset to access stack variables.  If stack
+            is aligned without drap, use stack pointer + offset to
+            access stack variables.  */
+         if (crtl->stack_realign_tried
+             && reg == frame_pointer_rtx)
+           {
+             int base_reg
+               = DWARF_FRAME_REGNUM ((fde && fde->drap_reg != INVALID_REGNUM)
+                                     ? HARD_FRAME_POINTER_REGNUM
+                                     : STACK_POINTER_REGNUM);
+             return new_reg_loc_descr (base_reg, offset);
+           }
+
+         offset += frame_pointer_fb_offset;
+         return new_loc_descr (DW_OP_fbreg, offset, 0);
        }
-      else if (TYPE_UNSIGNED (type))
-       encoding = DW_ATE_unsigned;
-      else
-       encoding = DW_ATE_signed;
-      break;
+    }
+  else if (fde
+          && fde->drap_reg != INVALID_REGNUM
+          && (fde->drap_reg == REGNO (reg)
+              || fde->vdrap_reg == REGNO (reg)))
+    {
+      /* Use cfa+offset to represent the location of arguments passed
+        on stack when drap is used to align stack.  */
+      return new_loc_descr (DW_OP_fbreg, offset, 0);
+    }
 
-    case REAL_TYPE:
-      if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))
-       encoding = DW_ATE_decimal_float;
-      else
-       encoding = DW_ATE_float;
-      break;
+  regno = dbx_reg_number (reg);
+  if (regno <= 31)
+    result = new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + regno),
+                           offset, 0);
+  else
+    result = new_loc_descr (DW_OP_bregx, regno, offset);
 
-    case FIXED_POINT_TYPE:
-      if (TYPE_UNSIGNED (type))
-       encoding = DW_ATE_unsigned_fixed;
-      else
-       encoding = DW_ATE_signed_fixed;
-      break;
+  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
 
-      /* Dwarf2 doesn't know anything about complex ints, so use
-        a user defined type for it.  */
-    case COMPLEX_TYPE:
-      if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
-       encoding = DW_ATE_complex_float;
-      else
-       encoding = DW_ATE_lo_user;
-      break;
+  return result;
+}
 
-    case BOOLEAN_TYPE:
-      /* GNU FORTRAN/Ada/C++ BOOLEAN type.  */
-      encoding = DW_ATE_boolean;
-      break;
+/* Return true if this RTL expression describes a base+offset calculation.  */
 
-    default:
-      /* No other TREE_CODEs are Dwarf fundamental types.  */
-      gcc_unreachable ();
-    }
+static inline int
+is_based_loc (const_rtx rtl)
+{
+  return (GET_CODE (rtl) == PLUS
+         && ((REG_P (XEXP (rtl, 0))
+              && REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
+              && CONST_INT_P (XEXP (rtl, 1)))));
+}
 
-  base_type_result = new_die (DW_TAG_base_type, comp_unit_die, type);
+/* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0)
+   failed.  */
 
-  /* This probably indicates a bug.  */
-  if (! TYPE_NAME (type))
-    add_name_attribute (base_type_result, "__unknown__");
+static dw_loc_descr_ref
+tls_mem_loc_descriptor (rtx mem)
+{
+  tree base;
+  dw_loc_descr_ref loc_result;
 
-  add_AT_unsigned (base_type_result, DW_AT_byte_size,
-                  int_size_in_bytes (type));
-  add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
+  if (MEM_EXPR (mem) == NULL_TREE || MEM_OFFSET (mem) == NULL_RTX)
+    return NULL;
 
-  return base_type_result;
+  base = get_base_address (MEM_EXPR (mem));
+  if (base == NULL
+      || TREE_CODE (base) != VAR_DECL
+      || !DECL_THREAD_LOCAL_P (base))
+    return NULL;
+
+  loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1);
+  if (loc_result == NULL)
+    return NULL;
+
+  if (INTVAL (MEM_OFFSET (mem)))
+    loc_descr_plus_const (&loc_result, INTVAL (MEM_OFFSET (mem)));
+
+  return loc_result;
 }
 
-/* Given a pointer to an arbitrary ..._TYPE tree node, return nonzero if the
-   given input type is a Dwarf "fundamental" type.  Otherwise return null.  */
+/* Output debug info about reason why we failed to expand expression as dwarf
+   expression.  */
 
-static inline int
-is_base_type (tree type)
+static void
+expansion_failed (tree expr, rtx rtl, char const *reason)
 {
-  switch (TREE_CODE (type))
+  if (dump_file && (dump_flags & TDF_DETAILS))
     {
-    case ERROR_MARK:
-    case VOID_TYPE:
-    case INTEGER_TYPE:
-    case REAL_TYPE:
-    case FIXED_POINT_TYPE:
-    case COMPLEX_TYPE:
-    case BOOLEAN_TYPE:
-      return 1;
+      fprintf (dump_file, "Failed to expand as dwarf: ");
+      if (expr)
+       print_generic_expr (dump_file, expr, dump_flags);
+      if (rtl)
+       {
+         fprintf (dump_file, "\n");
+         print_rtl (dump_file, rtl);
+       }
+      fprintf (dump_file, "\nReason: %s\n", reason);
+    }
+}
 
-    case ARRAY_TYPE:
-    case RECORD_TYPE:
-    case UNION_TYPE:
-    case QUAL_UNION_TYPE:
-    case ENUMERAL_TYPE:
-    case FUNCTION_TYPE:
-    case METHOD_TYPE:
-    case POINTER_TYPE:
-    case REFERENCE_TYPE:
-    case OFFSET_TYPE:
-    case LANG_TYPE:
-    case VECTOR_TYPE:
-      return 0;
+/* Helper function for const_ok_for_output, called either directly
+   or via for_each_rtx.  */
+
+static int
+const_ok_for_output_1 (rtx *rtlp, void *data ATTRIBUTE_UNUSED)
+{
+  rtx rtl = *rtlp;
+
+  if (GET_CODE (rtl) != SYMBOL_REF)
+    return 0;
 
-    default:
-      gcc_unreachable ();
+  if (CONSTANT_POOL_ADDRESS_P (rtl))
+    {
+      bool marked;
+      get_pool_constant_mark (rtl, &marked);
+      /* If all references to this pool constant were optimized away,
+        it was not output and thus we can't represent it.  */
+      if (!marked)
+       {
+         expansion_failed (NULL_TREE, rtl,
+                           "Constant was removed from constant pool.\n");
+         return 1;
+       }
+    }
+
+  if (SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
+    return 1;
+
+  /* Avoid references to external symbols in debug info, on several targets
+     the linker might even refuse to link when linking a shared library,
+     and in many other cases the relocations for .debug_info/.debug_loc are
+     dropped, so the address becomes zero anyway.  Hidden symbols, guaranteed
+     to be defined within the same shared library or executable are fine.  */
+  if (SYMBOL_REF_EXTERNAL_P (rtl))
+    {
+      tree decl = SYMBOL_REF_DECL (rtl);
+
+      if (decl == NULL || !targetm.binds_local_p (decl))
+       {
+         expansion_failed (NULL_TREE, rtl,
+                           "Symbol not defined in current TU.\n");
+         return 1;
+       }
     }
 
   return 0;
 }
 
-/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
-   node, return the size in bits for the type if it is a constant, or else
-   return the alignment for the type if the type's size is not constant, or
-   else return BITS_PER_WORD if the type actually turns out to be an
-   ERROR_MARK node.  */
+/* Return true if constant RTL can be emitted in DW_OP_addr or
+   DW_AT_const_value.  TLS SYMBOL_REFs, external SYMBOL_REFs or
+   non-marked constant pool SYMBOL_REFs can't be referenced in it.  */
 
-static inline unsigned HOST_WIDE_INT
-simple_type_size_in_bits (const_tree type)
+static bool
+const_ok_for_output (rtx rtl)
 {
-  if (TREE_CODE (type) == ERROR_MARK)
-    return BITS_PER_WORD;
-  else if (TYPE_SIZE (type) == NULL_TREE)
-    return 0;
-  else if (host_integerp (TYPE_SIZE (type), 1))
-    return tree_low_cst (TYPE_SIZE (type), 1);
-  else
-    return TYPE_ALIGN (type);
+  if (GET_CODE (rtl) == SYMBOL_REF)
+    return const_ok_for_output_1 (&rtl, NULL) == 0;
+
+  if (GET_CODE (rtl) == CONST)
+    return for_each_rtx (&XEXP (rtl, 0), const_ok_for_output_1, NULL) == 0;
+
+  return true;
 }
 
-/*  Given a pointer to a tree node for a subrange type, return a pointer
-    to a DIE that describes the given type.  */
+/* The following routine converts the RTL for a variable or parameter
+   (resident in memory) into an equivalent Dwarf representation of a
+   mechanism for getting the address of that same variable onto the top of a
+   hypothetical "address evaluation" stack.
 
-static dw_die_ref
-subrange_type_die (tree type, tree low, tree high, dw_die_ref context_die)
+   When creating memory location descriptors, we are effectively transforming
+   the RTL for a memory-resident object into its Dwarf postfix expression
+   equivalent.  This routine recursively descends an RTL tree, turning
+   it into Dwarf postfix code as it goes.
+
+   MODE is the mode of the memory reference, needed to handle some
+   autoincrement addressing modes.
+
+   CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the
+   location list for RTL.
+
+   Return 0 if we can't represent the location.  */
+
+static dw_loc_descr_ref
+mem_loc_descriptor (rtx rtl, enum machine_mode mode,
+                   enum var_init_status initialized)
 {
-  dw_die_ref subrange_die;
-  const HOST_WIDE_INT size_in_bytes = int_size_in_bytes (type);
+  dw_loc_descr_ref mem_loc_result = NULL;
+  enum dwarf_location_atom op;
+  dw_loc_descr_ref op0, op1;
 
-  if (context_die == NULL)
-    context_die = comp_unit_die;
+  /* Note that for a dynamically sized array, the location we will generate a
+     description of here will be the lowest numbered location which is
+     actually within the array.  That's *not* necessarily the same as the
+     zeroth element of the array.  */
 
-  subrange_die = new_die (DW_TAG_subrange_type, context_die, type);
+  rtl = targetm.delegitimize_address (rtl);
 
-  if (int_size_in_bytes (TREE_TYPE (type)) != size_in_bytes)
+  switch (GET_CODE (rtl))
     {
-      /* The size of the subrange type and its base type do not match,
-        so we need to generate a size attribute for the subrange type.  */
-      add_AT_unsigned (subrange_die, DW_AT_byte_size, size_in_bytes);
-    }
+    case POST_INC:
+    case POST_DEC:
+    case POST_MODIFY:
+      return mem_loc_descriptor (XEXP (rtl, 0), mode, initialized);
 
-  if (low)
-    add_bound_info (subrange_die, DW_AT_lower_bound, low);
-  if (high)
-    add_bound_info (subrange_die, DW_AT_upper_bound, high);
+    case SUBREG:
+      /* The case of a subreg may arise when we have a local (register)
+        variable or a formal (register) parameter which doesn't quite fill
+        up an entire register.  For now, just assume that it is
+        legitimate to make the Dwarf info refer to the whole register which
+        contains the given subreg.  */
+      if (!subreg_lowpart_p (rtl))
+       break;
+      rtl = SUBREG_REG (rtl);
+      if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE)
+       break;
+      if (GET_MODE_CLASS (GET_MODE (rtl)) != MODE_INT)
+       break;
+      mem_loc_result = mem_loc_descriptor (rtl, mode, initialized);
+      break;
 
-  return subrange_die;
-}
+    case REG:
+      /* Whenever a register number forms a part of the description of the
+        method for calculating the (dynamic) address of a memory resident
+        object, DWARF rules require the register number be referred to as
+        a "base register".  This distinction is not based in any way upon
+        what category of register the hardware believes the given register
+        belongs to.  This is strictly DWARF terminology we're dealing with
+        here. Note that in cases where the location of a memory-resident
+        data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
+        OP_CONST (0)) the actual DWARF location descriptor that we generate
+        may just be OP_BASEREG (basereg).  This may look deceptively like
+        the object in question was allocated to a register (rather than in
+        memory) so DWARF consumers need to be aware of the subtle
+        distinction between OP_REG and OP_BASEREG.  */
+      if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
+       mem_loc_result = based_loc_descr (rtl, 0, VAR_INIT_STATUS_INITIALIZED);
+      else if (stack_realign_drap
+              && crtl->drap_reg
+              && crtl->args.internal_arg_pointer == rtl
+              && REGNO (crtl->drap_reg) < FIRST_PSEUDO_REGISTER)
+       {
+         /* If RTL is internal_arg_pointer, which has been optimized
+            out, use DRAP instead.  */
+         mem_loc_result = based_loc_descr (crtl->drap_reg, 0,
+                                           VAR_INIT_STATUS_INITIALIZED);
+       }
+      break;
 
-/* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
-   entry that chains various modifiers in front of the given type.  */
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      if (op0 == 0)
+       break;
+      else
+       {
+         int shift = DWARF2_ADDR_SIZE
+                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+         shift *= BITS_PER_UNIT;
+         if (GET_CODE (rtl) == SIGN_EXTEND)
+           op = DW_OP_shra;
+         else
+           op = DW_OP_shr;
+         mem_loc_result = op0;
+         add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
+         add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
+         add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
+         add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+       }
+      break;
 
-static dw_die_ref
-modified_type_die (tree type, int is_const_type, int is_volatile_type,
-                  dw_die_ref context_die)
-{
-  enum tree_code code = TREE_CODE (type);
-  dw_die_ref mod_type_die;
-  dw_die_ref sub_die = NULL;
-  tree item_type = NULL;
-  tree qualified_type;
-  tree name, low, high;
+    case MEM:
+      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+                                          VAR_INIT_STATUS_INITIALIZED);
+      if (mem_loc_result == NULL)
+       mem_loc_result = tls_mem_loc_descriptor (rtl);
+      if (mem_loc_result != 0)
+       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
+      break;
 
-  if (code == ERROR_MARK)
-    return NULL;
+    case LO_SUM:
+        rtl = XEXP (rtl, 1);
 
-  /* See if we already have the appropriately qualified variant of
-     this type.  */
-  qualified_type
-    = get_qualified_type (type,
-                         ((is_const_type ? TYPE_QUAL_CONST : 0)
-                          | (is_volatile_type ? TYPE_QUAL_VOLATILE : 0)));
+      /* ... fall through ...  */
 
-  /* If we do, then we can just use its DIE, if it exists.  */
-  if (qualified_type)
-    {
-      mod_type_die = lookup_type_die (qualified_type);
-      if (mod_type_die)
-       return mod_type_die;
-    }
+    case LABEL_REF:
+      /* Some ports can transform a symbol ref into a label ref, because
+        the symbol ref is too far away and has to be dumped into a constant
+        pool.  */
+    case CONST:
+    case SYMBOL_REF:
+      /* Alternatively, the symbol in the constant pool might be referenced
+        by a different symbol.  */
+      if (GET_CODE (rtl) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (rtl))
+       {
+         bool marked;
+         rtx tmp = get_pool_constant_mark (rtl, &marked);
 
-  name = qualified_type ? TYPE_NAME (qualified_type) : NULL;
+         if (GET_CODE (tmp) == SYMBOL_REF)
+           {
+             rtl = tmp;
+             if (CONSTANT_POOL_ADDRESS_P (tmp))
+               get_pool_constant_mark (tmp, &marked);
+             else
+               marked = true;
+           }
 
-  /* Handle C typedef types.  */
-  if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name))
-    {
-      tree dtype = TREE_TYPE (name);
+         /* If all references to this pool constant were optimized away,
+            it was not output and thus we can't represent it.
+            FIXME: might try to use DW_OP_const_value here, though
+            DW_OP_piece complicates it.  */
+         if (!marked)
+           {
+             expansion_failed (NULL_TREE, rtl,
+                               "Constant was removed from constant pool.\n");
+             return 0;
+           }
+       }
 
-      if (qualified_type == dtype)
+      if (GET_CODE (rtl) == SYMBOL_REF
+         && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
        {
-         /* For a named type, use the typedef.  */
-         gen_type_die (qualified_type, context_die);
-         return lookup_type_die (qualified_type);
-       }
-      else if (is_const_type < TYPE_READONLY (dtype)
-              || is_volatile_type < TYPE_VOLATILE (dtype)
-              || (is_const_type <= TYPE_READONLY (dtype)
-                  && is_volatile_type <= TYPE_VOLATILE (dtype)
-                  && DECL_ORIGINAL_TYPE (name) != type))
-       /* cv-unqualified version of named type.  Just use the unnamed
-          type to which it refers.  */
-       return modified_type_die (DECL_ORIGINAL_TYPE (name),
-                                 is_const_type, is_volatile_type,
-                                 context_die);
-      /* Else cv-qualified version of named type; fall through.  */
-    }
+         dw_loc_descr_ref temp;
 
-  if (is_const_type)
-    {
-      mod_type_die = new_die (DW_TAG_const_type, comp_unit_die, type);
-      sub_die = modified_type_die (type, 0, is_volatile_type, context_die);
-    }
-  else if (is_volatile_type)
-    {
-      mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die, type);
-      sub_die = modified_type_die (type, 0, 0, context_die);
-    }
-  else if (code == POINTER_TYPE)
-    {
-      mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die, type);
-      add_AT_unsigned (mod_type_die, DW_AT_byte_size,
-                      simple_type_size_in_bits (type) / BITS_PER_UNIT);
-      item_type = TREE_TYPE (type);
-    }
-  else if (code == REFERENCE_TYPE)
-    {
-      mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die, type);
-      add_AT_unsigned (mod_type_die, DW_AT_byte_size,
-                      simple_type_size_in_bits (type) / BITS_PER_UNIT);
-      item_type = TREE_TYPE (type);
-    }
-  else if (code == INTEGER_TYPE
-          && TREE_TYPE (type) != NULL_TREE
-          && subrange_type_for_debug_p (type, &low, &high))
-    {
-      mod_type_die = subrange_type_die (type, low, high, context_die);
-      item_type = TREE_TYPE (type);
-    }
-  else if (is_base_type (type))
-    mod_type_die = base_type_die (type);
-  else
-    {
-      gen_type_die (type, context_die);
+         /* If this is not defined, we have no way to emit the data.  */
+         if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
+           break;
+
+         temp = new_loc_descr (DW_OP_addr, 0, 0);
+         temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
+         temp->dw_loc_oprnd1.v.val_addr = rtl;
+         temp->dtprel = true;
+
+         mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
+         add_loc_descr (&mem_loc_result, temp);
+
+         break;
+       }
 
-      /* We have to get the type_main_variant here (and pass that to the
-        `lookup_type_die' routine) because the ..._TYPE node we have
-        might simply be a *copy* of some original type node (where the
-        copy was created to help us keep track of typedef names) and
-        that copy might have a different TYPE_UID from the original
-        ..._TYPE node.  */
-      if (TREE_CODE (type) != VECTOR_TYPE)
-       return lookup_type_die (type_main_variant (type));
-      else
-       /* Vectors have the debugging information in the type,
-          not the main variant.  */
-       return lookup_type_die (type);
-    }
+      if (!const_ok_for_output (rtl))
+       break;
 
-  /* Builtin types don't have a DECL_ORIGINAL_TYPE.  For those,
-     don't output a DW_TAG_typedef, since there isn't one in the
-     user's program; just attach a DW_AT_name to the type.  */
-  if (name
-      && (TREE_CODE (name) != TYPE_DECL
-         || (TREE_TYPE (name) == qualified_type && DECL_NAME (name))))
-    {
-      if (TREE_CODE (name) == TYPE_DECL)
-       /* Could just call add_name_and_src_coords_attributes here,
-          but since this is a builtin type it doesn't have any
-          useful source coordinates anyway.  */
-       name = DECL_NAME (name);
-      add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
-    }
+    symref:
+      mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
+      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
+      mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+      break;
 
-  if (qualified_type)
-    equate_type_number_to_die (qualified_type, mod_type_die);
+    case CONCAT:
+    case CONCATN:
+    case VAR_LOCATION:
+      expansion_failed (NULL_TREE, rtl,
+                       "CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor");
+      return 0;
 
-  if (item_type)
-    /* We must do this after the equate_type_number_to_die call, in case
-       this is a recursive type.  This ensures that the modified_type_die
-       recursion will terminate even if the type is recursive.  Recursive
-       types are possible in Ada.  */
-    sub_die = modified_type_die (item_type,
-                                TYPE_READONLY (item_type),
-                                TYPE_VOLATILE (item_type),
-                                context_die);
+    case PRE_MODIFY:
+      /* Extract the PLUS expression nested inside and fall into
+        PLUS code below.  */
+      rtl = XEXP (rtl, 1);
+      goto plus;
 
-  if (sub_die != NULL)
-    add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
+    case PRE_INC:
+    case PRE_DEC:
+      /* Turn these into a PLUS expression and fall into the PLUS code
+        below.  */
+      rtl = gen_rtx_PLUS (word_mode, XEXP (rtl, 0),
+                         GEN_INT (GET_CODE (rtl) == PRE_INC
+                                  ? GET_MODE_UNIT_SIZE (mode)
+                                  : -GET_MODE_UNIT_SIZE (mode)));
 
-  return mod_type_die;
-}
+      /* ... fall through ...  */
 
-/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
-   an enumerated type.  */
+    case PLUS:
+    plus:
+      if (is_based_loc (rtl))
+       mem_loc_result = based_loc_descr (XEXP (rtl, 0),
+                                         INTVAL (XEXP (rtl, 1)),
+                                         VAR_INIT_STATUS_INITIALIZED);
+      else
+       {
+         mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                                              VAR_INIT_STATUS_INITIALIZED);
+         if (mem_loc_result == 0)
+           break;
 
-static inline int
-type_is_enum (const_tree type)
-{
-  return TREE_CODE (type) == ENUMERAL_TYPE;
-}
+         if (CONST_INT_P (XEXP (rtl, 1)))
+           loc_descr_plus_const (&mem_loc_result, INTVAL (XEXP (rtl, 1)));
+         else
+           {
+             dw_loc_descr_ref mem_loc_result2
+               = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                                     VAR_INIT_STATUS_INITIALIZED);
+             if (mem_loc_result2 == 0)
+               break;
+             add_loc_descr (&mem_loc_result, mem_loc_result2);
+             add_loc_descr (&mem_loc_result,
+                            new_loc_descr (DW_OP_plus, 0, 0));
+           }
+       }
+      break;
 
-/* Return the DBX register number described by a given RTL node.  */
+    /* If a pseudo-reg is optimized away, it is possible for it to
+       be replaced with a MEM containing a multiply or shift.  */
+    case MINUS:
+      op = DW_OP_minus;
+      goto do_binop;
 
-static unsigned int
-dbx_reg_number (const_rtx rtl)
-{
-  unsigned regno = REGNO (rtl);
+    case MULT:
+      op = DW_OP_mul;
+      goto do_binop;
 
-  gcc_assert (regno < FIRST_PSEUDO_REGISTER);
+    case DIV:
+      op = DW_OP_div;
+      goto do_binop;
 
-#ifdef LEAF_REG_REMAP
-  if (current_function_uses_only_leaf_regs)
-    {
-      int leaf_reg = LEAF_REG_REMAP (regno);
-      if (leaf_reg != -1)
-       regno = (unsigned) leaf_reg;
-    }
-#endif
+    case MOD:
+      op = DW_OP_mod;
+      goto do_binop;
 
-  return DBX_REGISTER_NUMBER (regno);
-}
+    case ASHIFT:
+      op = DW_OP_shl;
+      goto do_binop;
 
-/* Optionally add a DW_OP_piece term to a location description expression.
-   DW_OP_piece is only added if the location description expression already
-   doesn't end with DW_OP_piece.  */
+    case ASHIFTRT:
+      op = DW_OP_shra;
+      goto do_binop;
 
-static void
-add_loc_descr_op_piece (dw_loc_descr_ref *list_head, int size)
-{
-  dw_loc_descr_ref loc;
+    case LSHIFTRT:
+      op = DW_OP_shr;
+      goto do_binop;
 
-  if (*list_head != NULL)
-    {
-      /* Find the end of the chain.  */
-      for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
-       ;
+    case AND:
+      op = DW_OP_and;
+      goto do_binop;
 
-      if (loc->dw_loc_opc != DW_OP_piece)
-       loc->dw_loc_next = new_loc_descr (DW_OP_piece, size, 0);
-    }
-}
+    case IOR:
+      op = DW_OP_or;
+      goto do_binop;
 
-/* Return a location descriptor that designates a machine register or
-   zero if there is none.  */
+    case XOR:
+      op = DW_OP_xor;
+      goto do_binop;
 
-static dw_loc_descr_ref
-reg_loc_descriptor (rtx rtl, enum var_init_status initialized)
-{
-  rtx regs;
+    do_binop:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-  if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
-    return 0;
+      if (op0 == 0 || op1 == 0)
+       break;
 
-  regs = targetm.dwarf_register_span (rtl);
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      break;
 
-  if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
-    return multiple_reg_loc_descriptor (rtl, regs, initialized);
-  else
-    return one_reg_loc_descriptor (dbx_reg_number (rtl), initialized);
-}
+    case NOT:
+      op = DW_OP_not;
+      goto do_unop;
 
-/* Return a location descriptor that designates a machine register for
-   a given hard register number.  */
+    case ABS:
+      op = DW_OP_abs;
+      goto do_unop;
 
-static dw_loc_descr_ref
-one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized)
-{
-  dw_loc_descr_ref reg_loc_descr;
+    case NEG:
+      op = DW_OP_neg;
+      goto do_unop;
 
-  if (regno <= 31)
-    reg_loc_descr
-      = new_loc_descr ((enum dwarf_location_atom) (DW_OP_reg0 + regno), 0, 0);
-  else
-    reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0);
+    do_unop:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&reg_loc_descr, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+      if (op0 == 0)
+       break;
 
-  return reg_loc_descr;
-}
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      break;
 
-/* Given an RTL of a register, return a location descriptor that
-   designates a value that spans more than one register.  */
+    case CONST_INT:
+      mem_loc_result = int_loc_descriptor (INTVAL (rtl));
+      break;
 
-static dw_loc_descr_ref
-multiple_reg_loc_descriptor (rtx rtl, rtx regs,
-                            enum var_init_status initialized)
-{
-  int nregs, size, i;
-  unsigned reg;
-  dw_loc_descr_ref loc_result = NULL;
+    case EQ:
+      op = DW_OP_eq;
+      goto do_scompare;
 
-  reg = REGNO (rtl);
-#ifdef LEAF_REG_REMAP
-  if (current_function_uses_only_leaf_regs)
-    {
-      int leaf_reg = LEAF_REG_REMAP (reg);
-      if (leaf_reg != -1)
-       reg = (unsigned) leaf_reg;
-    }
-#endif
-  gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
-  nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
+    case GE:
+      op = DW_OP_ge;
+      goto do_scompare;
 
-  /* Simple, contiguous registers.  */
-  if (regs == NULL_RTX)
-    {
-      size = GET_MODE_SIZE (GET_MODE (rtl)) / nregs;
+    case GT:
+      op = DW_OP_gt;
+      goto do_scompare;
 
-      loc_result = NULL;
-      while (nregs--)
-       {
-         dw_loc_descr_ref t;
+    case LE:
+      op = DW_OP_le;
+      goto do_scompare;
 
-         t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg),
-                                     VAR_INIT_STATUS_INITIALIZED);
-         add_loc_descr (&loc_result, t);
-         add_loc_descr_op_piece (&loc_result, size);
-         ++reg;
-       }
-      return loc_result;
-    }
+    case LT:
+      op = DW_OP_lt;
+      goto do_scompare;
 
-  /* Now onto stupid register sets in non contiguous locations.  */
+    case NE:
+      op = DW_OP_ne;
+      goto do_scompare;
 
-  gcc_assert (GET_CODE (regs) == PARALLEL);
+    do_scompare:
+      if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
+         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+         || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+       break;
+
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+
+      if (op0 == 0 || op1 == 0)
+       break;
+
+      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+       {
+         int shift = DWARF2_ADDR_SIZE
+                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+         shift *= BITS_PER_UNIT;
+         add_loc_descr (&op0, int_loc_descriptor (shift));
+         add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+         if (CONST_INT_P (XEXP (rtl, 1)))
+           op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift);
+         else
+           {
+             add_loc_descr (&op1, int_loc_descriptor (shift));
+             add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+           }
+       }
 
-  size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
-  loc_result = NULL;
+    do_compare:
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      if (STORE_FLAG_VALUE != 1)
+       {
+         add_loc_descr (&mem_loc_result,
+                        int_loc_descriptor (STORE_FLAG_VALUE));
+         add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
+       }
+      break;
 
-  for (i = 0; i < XVECLEN (regs, 0); ++i)
-    {
-      dw_loc_descr_ref t;
+    case GEU:
+      op = DW_OP_ge;
+      goto do_ucompare;
 
-      t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)),
-                                 VAR_INIT_STATUS_INITIALIZED);
-      add_loc_descr (&loc_result, t);
-      size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
-      add_loc_descr_op_piece (&loc_result, size);
-    }
+    case GTU:
+      op = DW_OP_gt;
+      goto do_ucompare;
 
-  if (loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
-  return loc_result;
-}
+    case LEU:
+      op = DW_OP_le;
+      goto do_ucompare;
 
-#endif /* DWARF2_DEBUGGING_INFO */
+    case LTU:
+      op = DW_OP_lt;
+      goto do_ucompare;
 
-#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+    do_ucompare:
+      if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
+         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+         || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+       break;
 
-/* Return a location descriptor that designates a constant.  */
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-static dw_loc_descr_ref
-int_loc_descriptor (HOST_WIDE_INT i)
-{
-  enum dwarf_location_atom op;
+      if (op0 == 0 || op1 == 0)
+       break;
 
-  /* Pick the smallest representation of a constant, rather than just
-     defaulting to the LEB encoding.  */
-  if (i >= 0)
-    {
-      if (i <= 31)
-       op = (enum dwarf_location_atom) (DW_OP_lit0 + i);
-      else if (i <= 0xff)
-       op = DW_OP_const1u;
-      else if (i <= 0xffff)
-       op = DW_OP_const2u;
-      else if (HOST_BITS_PER_WIDE_INT == 32
-              || i <= 0xffffffff)
-       op = DW_OP_const4u;
-      else
-       op = DW_OP_constu;
-    }
-  else
-    {
-      if (i >= -0x80)
-       op = DW_OP_const1s;
-      else if (i >= -0x8000)
-       op = DW_OP_const2s;
-      else if (HOST_BITS_PER_WIDE_INT == 32
-              || i >= -0x80000000)
-       op = DW_OP_const4s;
+      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+       {
+         HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0)));
+         add_loc_descr (&op0, int_loc_descriptor (mask));
+         add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+         if (CONST_INT_P (XEXP (rtl, 1)))
+           op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask);
+         else
+           {
+             add_loc_descr (&op1, int_loc_descriptor (mask));
+             add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
+           }
+       }
       else
-       op = DW_OP_consts;
-    }
+       {
+         HOST_WIDE_INT bias = 1;
+         bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
+         add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+         if (CONST_INT_P (XEXP (rtl, 1)))
+           op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias
+                                     + INTVAL (XEXP (rtl, 1)));
+         else
+           add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+       }
+      goto do_compare;
+
+    case SMIN:
+    case SMAX:
+    case UMIN:
+    case UMAX:
+      if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
+         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+         || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+       break;
 
-  return new_loc_descr (op, i, 0);
-}
-#endif
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-#ifdef DWARF2_DEBUGGING_INFO
+      if (op0 == 0 || op1 == 0)
+       break;
 
-/* Return a location descriptor that designates a base+offset location.  */
+      add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
+      add_loc_descr (&op1, new_loc_descr (DW_OP_swap, 0, 0));
+      add_loc_descr (&op1, new_loc_descr (DW_OP_over, 0, 0));
+      if (GET_CODE (rtl) == UMIN || GET_CODE (rtl) == UMAX)
+       {
+         if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+           {
+             HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0)));
+             add_loc_descr (&op0, int_loc_descriptor (mask));
+             add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+             add_loc_descr (&op1, int_loc_descriptor (mask));
+             add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
+           }
+         else
+           {
+             HOST_WIDE_INT bias = 1;
+             bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
+             add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+             add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+           }
+       }
+      else if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+       {
+         int shift = DWARF2_ADDR_SIZE
+                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+         shift *= BITS_PER_UNIT;
+         add_loc_descr (&op0, int_loc_descriptor (shift));
+         add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+         add_loc_descr (&op1, int_loc_descriptor (shift));
+         add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+       }
 
-static dw_loc_descr_ref
-based_loc_descr (rtx reg, HOST_WIDE_INT offset,
-                enum var_init_status initialized)
-{
-  unsigned int regno;
-  dw_loc_descr_ref result;
-  dw_fde_ref fde = current_fde ();
+      if (GET_CODE (rtl) == SMIN || GET_CODE (rtl) == UMIN)
+       op = DW_OP_lt;
+      else
+       op = DW_OP_gt;
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      {
+       dw_loc_descr_ref bra_node, drop_node;
 
-  /* We only use "frame base" when we're sure we're talking about the
-     post-prologue local stack frame.  We do this by *not* running
-     register elimination until this point, and recognizing the special
-     argument pointer and soft frame pointer rtx's.  */
-  if (reg == arg_pointer_rtx || reg == frame_pointer_rtx)
-    {
-      rtx elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+       bra_node = new_loc_descr (DW_OP_bra, 0, 0);
+       add_loc_descr (&mem_loc_result, bra_node);
+       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_swap, 0, 0));
+       drop_node = new_loc_descr (DW_OP_drop, 0, 0);
+       add_loc_descr (&mem_loc_result, drop_node);
+       bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+       bra_node->dw_loc_oprnd1.v.val_loc = drop_node;
+      }
+      break;
 
-      if (elim != reg)
+    case ZERO_EXTRACT:
+    case SIGN_EXTRACT:
+      if (CONST_INT_P (XEXP (rtl, 1))
+         && CONST_INT_P (XEXP (rtl, 2))
+         && ((unsigned) INTVAL (XEXP (rtl, 1))
+             + (unsigned) INTVAL (XEXP (rtl, 2))
+             <= GET_MODE_BITSIZE (GET_MODE (rtl)))
+         && GET_MODE_BITSIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE
+         && GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0))) <= DWARF2_ADDR_SIZE)
        {
-         if (GET_CODE (elim) == PLUS)
+         int shift, size;
+         op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                                   VAR_INIT_STATUS_INITIALIZED);
+         if (op0 == 0)
+           break;
+         if (GET_CODE (rtl) == SIGN_EXTRACT)
+           op = DW_OP_shra;
+         else
+           op = DW_OP_shr;
+         mem_loc_result = op0;
+         size = INTVAL (XEXP (rtl, 1));
+         shift = INTVAL (XEXP (rtl, 2));
+         if (BITS_BIG_ENDIAN)
+           shift = GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0)))
+                   - shift - size;
+         if (shift + size != (int) DWARF2_ADDR_SIZE)
            {
-             offset += INTVAL (XEXP (elim, 1));
-             elim = XEXP (elim, 0);
+             add_loc_descr (&mem_loc_result,
+                            int_loc_descriptor (DWARF2_ADDR_SIZE
+                                                - shift - size));
+             add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
            }
-         gcc_assert ((SUPPORTS_STACK_ALIGNMENT
-                      && (elim == hard_frame_pointer_rtx
-                          || elim == stack_pointer_rtx))
-                     || elim == (frame_pointer_needed
-                                 ? hard_frame_pointer_rtx
-                                 : stack_pointer_rtx));
-
-         /* If drap register is used to align stack, use frame
-            pointer + offset to access stack variables.  If stack
-            is aligned without drap, use stack pointer + offset to
-            access stack variables.  */
-         if (crtl->stack_realign_tried
-             && reg == frame_pointer_rtx)
+         if (size != (int) DWARF2_ADDR_SIZE)
            {
-             int base_reg
-               = DWARF_FRAME_REGNUM ((fde && fde->drap_reg != INVALID_REGNUM)
-                                     ? HARD_FRAME_POINTER_REGNUM
-                                     : STACK_POINTER_REGNUM);
-             return new_reg_loc_descr (base_reg, offset);
+             add_loc_descr (&mem_loc_result,
+                            int_loc_descriptor (DWARF2_ADDR_SIZE - size));
+             add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
            }
-
-         offset += frame_pointer_fb_offset;
-         return new_loc_descr (DW_OP_fbreg, offset, 0);
        }
-    }
-  else if (fde
-          && fde->drap_reg != INVALID_REGNUM
-          && (fde->drap_reg == REGNO (reg)
-              || fde->vdrap_reg == REGNO (reg)))
-    {
-      /* Use cfa+offset to represent the location of arguments passed
-        on stack when drap is used to align stack.  */
-      return new_loc_descr (DW_OP_fbreg, offset, 0);
-    }
+      break;
 
-  regno = dbx_reg_number (reg);
-  if (regno <= 31)
-    result = new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + regno),
-                           offset, 0);
-  else
-    result = new_loc_descr (DW_OP_bregx, regno, offset);
+    case COMPARE:
+    case IF_THEN_ELSE:
+    case ROTATE:
+    case ROTATERT:
+    case TRUNCATE:
+      /* In theory, we could implement the above.  */
+      /* DWARF cannot represent the unsigned compare operations
+        natively.  */
+    case SS_MULT:
+    case US_MULT:
+    case SS_DIV:
+    case US_DIV:
+    case UDIV:
+    case UMOD:
+    case UNORDERED:
+    case ORDERED:
+    case UNEQ:
+    case UNGE:
+    case UNGT:
+    case UNLE:
+    case UNLT:
+    case LTGT:
+    case FLOAT_EXTEND:
+    case FLOAT_TRUNCATE:
+    case FLOAT:
+    case UNSIGNED_FLOAT:
+    case FIX:
+    case UNSIGNED_FIX:
+    case FRACT_CONVERT:
+    case UNSIGNED_FRACT_CONVERT:
+    case SAT_FRACT:
+    case UNSIGNED_SAT_FRACT:
+    case SQRT:
+    case BSWAP:
+    case FFS:
+    case CLZ:
+    case CTZ:
+    case POPCOUNT:
+    case PARITY:
+    case ASM_OPERANDS:
+    case UNSPEC:
+    case HIGH:
+      /* If delegitimize_address couldn't do anything with the UNSPEC, we
+        can't express it in the debug info.  This can happen e.g. with some
+        TLS UNSPECs.  */
+      break;
 
-  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+    case CONST_STRING:
+      resolve_one_addr (&rtl, NULL);
+      goto symref;
 
-  return result;
+    default:
+#ifdef ENABLE_CHECKING
+      print_rtl (stderr, rtl);
+      gcc_unreachable ();
+#else
+      break;
+#endif
+    }
+
+  if (mem_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
+  return mem_loc_result;
 }
 
-/* Return true if this RTL expression describes a base+offset calculation.  */
+/* Return a descriptor that describes the concatenation of two locations.
+   This is typically a complex variable.  */
 
-static inline int
-is_based_loc (const_rtx rtl)
+static dw_loc_descr_ref
+concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
 {
-  return (GET_CODE (rtl) == PLUS
-         && ((REG_P (XEXP (rtl, 0))
-              && REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
-              && CONST_INT_P (XEXP (rtl, 1)))));
+  dw_loc_descr_ref cc_loc_result = NULL;
+  dw_loc_descr_ref x0_ref
+    = loc_descriptor (x0, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+  dw_loc_descr_ref x1_ref
+    = loc_descriptor (x1, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+
+  if (x0_ref == 0 || x1_ref == 0)
+    return 0;
+
+  cc_loc_result = x0_ref;
+  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x0)));
+
+  add_loc_descr (&cc_loc_result, x1_ref);
+  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1)));
+
+  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
+  return cc_loc_result;
 }
 
-/* Return a descriptor that describes the concatenation of N locations
-   used to form the address of a memory location.  */
+/* Return a descriptor that describes the concatenation of N
+   locations.  */
 
 static dw_loc_descr_ref
-concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode,
-                           enum var_init_status initialized)
+concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
 {
   unsigned int i;
   dw_loc_descr_ref cc_loc_result = NULL;
@@ -10458,7 +13538,7 @@ concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode,
       dw_loc_descr_ref ref;
       rtx x = XVECEXP (concatn, 0, i);
 
-      ref = mem_loc_descriptor (x, mode, VAR_INIT_STATUS_INITIALIZED);
+      ref = loc_descriptor (x, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
       if (ref == NULL)
        return NULL;
 
@@ -10472,425 +13552,643 @@ concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode,
   return cc_loc_result;
 }
 
-/* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0)
-   failed.  */
-
-static dw_loc_descr_ref
-tls_mem_loc_descriptor (rtx mem)
-{
-  tree base;
-  dw_loc_descr_ref loc_result;
-
-  if (MEM_EXPR (mem) == NULL_TREE || MEM_OFFSET (mem) == NULL_RTX)
-    return NULL;
-
-  base = get_base_address (MEM_EXPR (mem));
-  if (base == NULL
-      || TREE_CODE (base) != VAR_DECL
-      || !DECL_THREAD_LOCAL_P (base))
-    return NULL;
-
-  loc_result = loc_descriptor_from_tree_1 (MEM_EXPR (mem), 2);
-  if (loc_result == NULL)
-    return NULL;
-
-  if (INTVAL (MEM_OFFSET (mem)))
-    loc_descr_plus_const (&loc_result, INTVAL (MEM_OFFSET (mem)));
-
-  return loc_result;
-}
-
-/* The following routine converts the RTL for a variable or parameter
-   (resident in memory) into an equivalent Dwarf representation of a
-   mechanism for getting the address of that same variable onto the top of a
-   hypothetical "address evaluation" stack.
-
-   When creating memory location descriptors, we are effectively transforming
-   the RTL for a memory-resident object into its Dwarf postfix expression
-   equivalent.  This routine recursively descends an RTL tree, turning
-   it into Dwarf postfix code as it goes.
-
-   MODE is the mode of the memory reference, needed to handle some
-   autoincrement addressing modes.
-
-   CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the
-   location list for RTL.
-
-   Return 0 if we can't represent the location.  */
-
-static dw_loc_descr_ref
-mem_loc_descriptor (rtx rtl, enum machine_mode mode,
-                   enum var_init_status initialized)
-{
-  dw_loc_descr_ref mem_loc_result = NULL;
-  enum dwarf_location_atom op;
+/* Output a proper Dwarf location descriptor for a variable or parameter
+   which is either allocated in a register or in a memory location.  For a
+   register, we just generate an OP_REG and the register number.  For a
+   memory location we provide a Dwarf postfix expression describing how to
+   generate the (dynamic) address of the object onto the address stack.
 
-  /* Note that for a dynamically sized array, the location we will generate a
-     description of here will be the lowest numbered location which is
-     actually within the array.  That's *not* necessarily the same as the
-     zeroth element of the array.  */
+   MODE is mode of the decl if this loc_descriptor is going to be used in
+   .debug_loc section where DW_OP_stack_value and DW_OP_implicit_value are
+   allowed, VOIDmode otherwise.
 
-  rtl = targetm.delegitimize_address (rtl);
+   If we don't know how to describe it, return 0.  */
+
+static dw_loc_descr_ref
+loc_descriptor (rtx rtl, enum machine_mode mode,
+               enum var_init_status initialized)
+{
+  dw_loc_descr_ref loc_result = NULL;
 
   switch (GET_CODE (rtl))
     {
-    case POST_INC:
-    case POST_DEC:
-    case POST_MODIFY:
-      /* POST_INC and POST_DEC can be handled just like a SUBREG.  So we
-        just fall into the SUBREG code.  */
-
-      /* ... fall through ...  */
-
     case SUBREG:
       /* The case of a subreg may arise when we have a local (register)
         variable or a formal (register) parameter which doesn't quite fill
         up an entire register.  For now, just assume that it is
         legitimate to make the Dwarf info refer to the whole register which
         contains the given subreg.  */
-      rtl = XEXP (rtl, 0);
-
-      /* ... fall through ...  */
+      loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized);
+      break;
 
     case REG:
-      /* Whenever a register number forms a part of the description of the
-        method for calculating the (dynamic) address of a memory resident
-        object, DWARF rules require the register number be referred to as
-        a "base register".  This distinction is not based in any way upon
-        what category of register the hardware believes the given register
-        belongs to.  This is strictly DWARF terminology we're dealing with
-        here. Note that in cases where the location of a memory-resident
-        data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
-        OP_CONST (0)) the actual DWARF location descriptor that we generate
-        may just be OP_BASEREG (basereg).  This may look deceptively like
-        the object in question was allocated to a register (rather than in
-        memory) so DWARF consumers need to be aware of the subtle
-        distinction between OP_REG and OP_BASEREG.  */
-      if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
-       mem_loc_result = based_loc_descr (rtl, 0, VAR_INIT_STATUS_INITIALIZED);
-      else if (stack_realign_drap
-              && crtl->drap_reg
-              && crtl->args.internal_arg_pointer == rtl
-              && REGNO (crtl->drap_reg) < FIRST_PSEUDO_REGISTER)
-       {
-         /* If RTL is internal_arg_pointer, which has been optimized
-            out, use DRAP instead.  */
-         mem_loc_result = based_loc_descr (crtl->drap_reg, 0,
-                                           VAR_INIT_STATUS_INITIALIZED);
-       }
+      loc_result = reg_loc_descriptor (rtl, initialized);
+      break;
+
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
+      loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
       break;
 
     case MEM:
-      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
-                                          VAR_INIT_STATUS_INITIALIZED);
-      if (mem_loc_result == NULL)
-       mem_loc_result = tls_mem_loc_descriptor (rtl);
-      if (mem_loc_result != 0)
-       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
+      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+                                      initialized);
+      if (loc_result == NULL)
+       loc_result = tls_mem_loc_descriptor (rtl);
       break;
 
-    case LO_SUM:
-        rtl = XEXP (rtl, 1);
+    case CONCAT:
+      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1),
+                                         initialized);
+      break;
 
-      /* ... fall through ...  */
+    case CONCATN:
+      loc_result = concatn_loc_descriptor (rtl, initialized);
+      break;
 
-    case LABEL_REF:
-      /* Some ports can transform a symbol ref into a label ref, because
-        the symbol ref is too far away and has to be dumped into a constant
-        pool.  */
-    case CONST:
-    case SYMBOL_REF:
-      /* Alternatively, the symbol in the constant pool might be referenced
-        by a different symbol.  */
-      if (GET_CODE (rtl) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (rtl))
+    case VAR_LOCATION:
+      /* Single part.  */
+      if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
        {
-         bool marked;
-         rtx tmp = get_pool_constant_mark (rtl, &marked);
+         loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), mode,
+                                      initialized);
+         break;
+       }
 
-         if (GET_CODE (tmp) == SYMBOL_REF)
-           {
-             rtl = tmp;
-             if (CONSTANT_POOL_ADDRESS_P (tmp))
-               get_pool_constant_mark (tmp, &marked);
-             else
-               marked = true;
-           }
+      rtl = XEXP (rtl, 1);
+      /* FALLTHRU */
 
-         /* If all references to this pool constant were optimized away,
-            it was not output and thus we can't represent it.
-            FIXME: might try to use DW_OP_const_value here, though
-            DW_OP_piece complicates it.  */
-         if (!marked)
-           return 0;
-       }
+    case PARALLEL:
+      {
+       rtvec par_elems = XVEC (rtl, 0);
+       int num_elem = GET_NUM_ELEM (par_elems);
+       enum machine_mode mode;
+       int i;
 
-      mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
-      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
-      mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
-      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
-      break;
+       /* Create the first one, so we have something to add to.  */
+       loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
+                                    VOIDmode, initialized);
+       if (loc_result == NULL)
+         return NULL;
+       mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
+       add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+       for (i = 1; i < num_elem; i++)
+         {
+           dw_loc_descr_ref temp;
 
-    case PRE_MODIFY:
-      /* Extract the PLUS expression nested inside and fall into
-        PLUS code below.  */
-      rtl = XEXP (rtl, 1);
-      goto plus;
+           temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
+                                  VOIDmode, initialized);
+           if (temp == NULL)
+             return NULL;
+           add_loc_descr (&loc_result, temp);
+           mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
+           add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+         }
+      }
+      break;
 
-    case PRE_INC:
-    case PRE_DEC:
-      /* Turn these into a PLUS expression and fall into the PLUS code
-        below.  */
-      rtl = gen_rtx_PLUS (word_mode, XEXP (rtl, 0),
-                         GEN_INT (GET_CODE (rtl) == PRE_INC
-                                  ? GET_MODE_UNIT_SIZE (mode)
-                                  : -GET_MODE_UNIT_SIZE (mode)));
+    case CONST_INT:
+      if (mode != VOIDmode && mode != BLKmode)
+       loc_result = address_of_int_loc_descriptor (GET_MODE_SIZE (mode),
+                                                   INTVAL (rtl));
+      break;
 
-      /* ... fall through ...  */
+    case CONST_DOUBLE:
+      if (mode == VOIDmode)
+       mode = GET_MODE (rtl);
 
-    case PLUS:
-    plus:
-      if (is_based_loc (rtl))
-       mem_loc_result = based_loc_descr (XEXP (rtl, 0),
-                                         INTVAL (XEXP (rtl, 1)),
-                                         VAR_INIT_STATUS_INITIALIZED);
-      else
+      if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
        {
-         mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                                              VAR_INIT_STATUS_INITIALIZED);
-         if (mem_loc_result == 0)
-           break;
-
-         if (CONST_INT_P (XEXP (rtl, 1)))
-           loc_descr_plus_const (&mem_loc_result, INTVAL (XEXP (rtl, 1)));
+         gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
+
+         /* Note that a CONST_DOUBLE rtx could represent either an integer
+            or a floating-point constant.  A CONST_DOUBLE is used whenever
+            the constant requires more than one word in order to be
+            adequately represented.  We output CONST_DOUBLEs as blocks.  */
+         loc_result = new_loc_descr (DW_OP_implicit_value,
+                                     GET_MODE_SIZE (mode), 0);
+         if (SCALAR_FLOAT_MODE_P (mode))
+           {
+             unsigned int length = GET_MODE_SIZE (mode);
+             unsigned char *array = GGC_NEWVEC (unsigned char, length);
+
+             insert_float (rtl, array);
+             loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+             loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4;
+             loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
+             loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+           }
          else
            {
-             dw_loc_descr_ref mem_loc_result2
-               = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                                     VAR_INIT_STATUS_INITIALIZED);
-             if (mem_loc_result2 == 0)
-               break;
-             add_loc_descr (&mem_loc_result, mem_loc_result2);
-             add_loc_descr (&mem_loc_result,
-                            new_loc_descr (DW_OP_plus, 0, 0));
+             loc_result->dw_loc_oprnd2.val_class = dw_val_class_const_double;
+             loc_result->dw_loc_oprnd2.v.val_double.high
+               = CONST_DOUBLE_HIGH (rtl);
+             loc_result->dw_loc_oprnd2.v.val_double.low
+               = CONST_DOUBLE_LOW (rtl);
            }
        }
       break;
 
-    /* If a pseudo-reg is optimized away, it is possible for it to
-       be replaced with a MEM containing a multiply or shift.  */
-    case MULT:
-      op = DW_OP_mul;
-      goto do_binop;
+    case CONST_VECTOR:
+      if (mode == VOIDmode)
+       mode = GET_MODE (rtl);
 
-    case ASHIFT:
-      op = DW_OP_shl;
-      goto do_binop;
+      if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
+       {
+         unsigned int elt_size = GET_MODE_UNIT_SIZE (GET_MODE (rtl));
+         unsigned int length = CONST_VECTOR_NUNITS (rtl);
+         unsigned char *array = GGC_NEWVEC (unsigned char, length * elt_size);
+         unsigned int i;
+         unsigned char *p;
+
+         gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
+         switch (GET_MODE_CLASS (mode))
+           {
+           case MODE_VECTOR_INT:
+             for (i = 0, p = array; i < length; i++, p += elt_size)
+               {
+                 rtx elt = CONST_VECTOR_ELT (rtl, i);
+                 HOST_WIDE_INT lo, hi;
 
-    case ASHIFTRT:
-      op = DW_OP_shra;
-      goto do_binop;
+                 switch (GET_CODE (elt))
+                   {
+                   case CONST_INT:
+                     lo = INTVAL (elt);
+                     hi = -(lo < 0);
+                     break;
 
-    case LSHIFTRT:
-      op = DW_OP_shr;
-      goto do_binop;
+                   case CONST_DOUBLE:
+                     lo = CONST_DOUBLE_LOW (elt);
+                     hi = CONST_DOUBLE_HIGH (elt);
+                     break;
 
-    do_binop:
-      {
-       dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                                                  VAR_INIT_STATUS_INITIALIZED);
-       dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                                                  VAR_INIT_STATUS_INITIALIZED);
+                   default:
+                     gcc_unreachable ();
+                   }
 
-       if (op0 == 0 || op1 == 0)
-         break;
+                 if (elt_size <= sizeof (HOST_WIDE_INT))
+                   insert_int (lo, elt_size, p);
+                 else
+                   {
+                     unsigned char *p0 = p;
+                     unsigned char *p1 = p + sizeof (HOST_WIDE_INT);
+
+                     gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
+                     if (WORDS_BIG_ENDIAN)
+                       {
+                         p0 = p1;
+                         p1 = p;
+                       }
+                     insert_int (lo, sizeof (HOST_WIDE_INT), p0);
+                     insert_int (hi, sizeof (HOST_WIDE_INT), p1);
+                   }
+               }
+             break;
 
-       mem_loc_result = op0;
-       add_loc_descr (&mem_loc_result, op1);
-       add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
-       break;
-      }
+           case MODE_VECTOR_FLOAT:
+             for (i = 0, p = array; i < length; i++, p += elt_size)
+               {
+                 rtx elt = CONST_VECTOR_ELT (rtl, i);
+                 insert_float (elt, p);
+               }
+             break;
 
-    case CONST_INT:
-      mem_loc_result = int_loc_descriptor (INTVAL (rtl));
-      break;
+           default:
+             gcc_unreachable ();
+           }
 
-    case CONCATN:
-      mem_loc_result = concatn_mem_loc_descriptor (rtl, mode,
-                                                  VAR_INIT_STATUS_INITIALIZED);
+         loc_result = new_loc_descr (DW_OP_implicit_value,
+                                     length * elt_size, 0);
+         loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+         loc_result->dw_loc_oprnd2.v.val_vec.length = length;
+         loc_result->dw_loc_oprnd2.v.val_vec.elt_size = elt_size;
+         loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+       }
       break;
 
-    case UNSPEC:
-      /* If delegitimize_address couldn't do anything with the UNSPEC, we
-        can't express it in the debug info.  This can happen e.g. with some
-        TLS UNSPECs.  */
+    case CONST:
+      if (mode == VOIDmode
+         || GET_CODE (XEXP (rtl, 0)) == CONST_INT
+         || GET_CODE (XEXP (rtl, 0)) == CONST_DOUBLE
+         || GET_CODE (XEXP (rtl, 0)) == CONST_VECTOR)
+       {
+         loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
+         break;
+       }
+      /* FALLTHROUGH */
+    case SYMBOL_REF:
+      if (!const_ok_for_output (rtl))
+       break;
+    case LABEL_REF:
+      if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
+         && (dwarf_version >= 4 || !dwarf_strict))
+       {
+         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
+         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
+         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+         add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
+         VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+       }
       break;
 
     default:
-      gcc_unreachable ();
+      if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE (rtl) == mode
+         && GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE
+         && (dwarf_version >= 4 || !dwarf_strict))
+       {
+         /* Value expression.  */
+         loc_result = mem_loc_descriptor (rtl, VOIDmode, initialized);
+         if (loc_result)
+           add_loc_descr (&loc_result,
+                          new_loc_descr (DW_OP_stack_value, 0, 0));
+       }
+      break;
+    }
+
+  return loc_result;
+}
+
+/* We need to figure out what section we should use as the base for the
+   address ranges where a given location is valid.
+   1. If this particular DECL has a section associated with it, use that.
+   2. If this function has a section associated with it, use that.
+   3. Otherwise, use the text section.
+   XXX: If you split a variable across multiple sections, we won't notice.  */
+
+static const char *
+secname_for_decl (const_tree decl)
+{
+  const char *secname;
+
+  if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl))
+    {
+      tree sectree = DECL_SECTION_NAME (decl);
+      secname = TREE_STRING_POINTER (sectree);
+    }
+  else if (current_function_decl && DECL_SECTION_NAME (current_function_decl))
+    {
+      tree sectree = DECL_SECTION_NAME (current_function_decl);
+      secname = TREE_STRING_POINTER (sectree);
     }
+  else if (cfun && in_cold_section_p)
+    secname = crtl->subsections.cold_section_label;
+  else
+    secname = text_section_label;
 
-  if (mem_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+  return secname;
+}
 
-  return mem_loc_result;
+/* Return true when DECL_BY_REFERENCE is defined and set for DECL.  */
+
+static bool
+decl_by_reference_p (tree decl)
+{
+  return ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL
+          || TREE_CODE (decl) == VAR_DECL)
+         && DECL_BY_REFERENCE (decl));
 }
 
-/* Return a descriptor that describes the concatenation of two locations.
-   This is typically a complex variable.  */
+/* Helper function for dw_loc_list.  Compute proper Dwarf location descriptor
+   for VARLOC.  */
 
 static dw_loc_descr_ref
-concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
+dw_loc_list_1 (tree loc, rtx varloc, int want_address,
+              enum var_init_status initialized)
 {
-  dw_loc_descr_ref cc_loc_result = NULL;
-  dw_loc_descr_ref x0_ref = loc_descriptor (x0, VAR_INIT_STATUS_INITIALIZED);
-  dw_loc_descr_ref x1_ref = loc_descriptor (x1, VAR_INIT_STATUS_INITIALIZED);
+  int have_address = 0;
+  dw_loc_descr_ref descr;
+  enum machine_mode mode;
 
-  if (x0_ref == 0 || x1_ref == 0)
+  if (want_address != 2)
+    {
+      gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
+      /* Single part.  */
+      if (GET_CODE (XEXP (varloc, 1)) != PARALLEL)
+       {
+         varloc = XEXP (XEXP (varloc, 1), 0);
+         mode = GET_MODE (varloc);
+         if (MEM_P (varloc))
+           {
+             varloc = XEXP (varloc, 0);
+             have_address = 1;
+           }
+         descr = mem_loc_descriptor (varloc, mode, initialized);
+       }
+      else
+       return 0;
+    }
+  else
+    {
+      descr = loc_descriptor (varloc, DECL_MODE (loc), initialized);
+      have_address = 1;
+    }
+
+  if (!descr)
     return 0;
 
-  cc_loc_result = x0_ref;
-  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x0)));
+  if (want_address == 2 && !have_address
+      && (dwarf_version >= 4 || !dwarf_strict))
+    {
+      if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE)
+       {
+         expansion_failed (loc, NULL_RTX,
+                           "DWARF address size mismatch");
+         return 0;
+       }
+      add_loc_descr (&descr, new_loc_descr (DW_OP_stack_value, 0, 0));
+      have_address = 1;
+    }
+  /* Show if we can't fill the request for an address.  */
+  if (want_address && !have_address)
+    {
+      expansion_failed (loc, NULL_RTX,
+                       "Want address and only have value");
+      return 0;
+    }
 
-  add_loc_descr (&cc_loc_result, x1_ref);
-  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1)));
+  /* If we've got an address and don't want one, dereference.  */
+  if (!want_address && have_address)
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
+      enum dwarf_location_atom op;
 
-  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+      if (size > DWARF2_ADDR_SIZE || size == -1)
+       {
+         expansion_failed (loc, NULL_RTX,
+                           "DWARF address size mismatch");
+         return 0;
+       }
+      else if (size == DWARF2_ADDR_SIZE)
+       op = DW_OP_deref;
+      else
+       op = DW_OP_deref_size;
 
-  return cc_loc_result;
+      add_loc_descr (&descr, new_loc_descr (op, size, 0));
+    }
+
+  return descr;
 }
 
-/* Return a descriptor that describes the concatenation of N
-   locations.  */
+/* Return the dwarf representation of the location list LOC_LIST of
+   DECL.  WANT_ADDRESS has the same meaning as in loc_list_from_tree
+   function.  */
 
-static dw_loc_descr_ref
-concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
+static dw_loc_list_ref
+dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
 {
-  unsigned int i;
-  dw_loc_descr_ref cc_loc_result = NULL;
-  unsigned int n = XVECLEN (concatn, 0);
+  const char *endname, *secname;
+  rtx varloc;
+  enum var_init_status initialized;
+  struct var_loc_node *node;
+  dw_loc_descr_ref descr;
+  char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
+  dw_loc_list_ref list = NULL;
+  dw_loc_list_ref *listp = &list;
+
+  /* Now that we know what section we are using for a base,
+     actually construct the list of locations.
+     The first location information is what is passed to the
+     function that creates the location list, and the remaining
+     locations just get added on to that list.
+     Note that we only know the start address for a location
+     (IE location changes), so to build the range, we use
+     the range [current location start, next location start].
+     This means we have to special case the last node, and generate
+     a range of [last location start, end of function label].  */
+
+  secname = secname_for_decl (decl);
+
+  for (node = loc_list->first; node->next; node = node->next)
+    if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
+      {
+       /* The variable has a location between NODE->LABEL and
+          NODE->NEXT->LABEL.  */
+       initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
+       varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+       descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
+       if (descr)
+         {
+           *listp = new_loc_list (descr, node->label, node->next->label,
+                                  secname);
+           listp = &(*listp)->dw_loc_next;
+         }
+      }
 
-  for (i = 0; i < n; ++i)
+  /* If the variable has a location at the last label
+     it keeps its location until the end of function.  */
+  if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
     {
-      dw_loc_descr_ref ref;
-      rtx x = XVECEXP (concatn, 0, i);
-
-      ref = loc_descriptor (x, VAR_INIT_STATUS_INITIALIZED);
-      if (ref == NULL)
-       return NULL;
+      initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
+      varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+      descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
+      if (descr)
+       {
+         if (!current_function_decl)
+           endname = text_end_label;
+         else
+           {
+             ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+                                          current_function_funcdef_no);
+             endname = ggc_strdup (label_id);
+           }
 
-      add_loc_descr (&cc_loc_result, ref);
-      add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
+         *listp = new_loc_list (descr, node->label, endname, secname);
+         listp = &(*listp)->dw_loc_next;
+       }
     }
 
-  if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+  /* Try to avoid the overhead of a location list emitting a location
+     expression instead, but only if we didn't have more than one
+     location entry in the first place.  If some entries were not
+     representable, we don't want to pretend a single entry that was
+     applies to the entire scope in which the variable is
+     available.  */
+  if (list && loc_list->first->next)
+    gen_llsym (list);
 
-  return cc_loc_result;
+  return list;
 }
 
-/* Output a proper Dwarf location descriptor for a variable or parameter
-   which is either allocated in a register or in a memory location.  For a
-   register, we just generate an OP_REG and the register number.  For a
-   memory location we provide a Dwarf postfix expression describing how to
-   generate the (dynamic) address of the object onto the address stack.
-
-   If we don't know how to describe it, return 0.  */
+/* Return if the loc_list has only single element and thus can be represented
+   as location description.   */
 
-static dw_loc_descr_ref
-loc_descriptor (rtx rtl, enum var_init_status initialized)
+static bool
+single_element_loc_list_p (dw_loc_list_ref list)
 {
-  dw_loc_descr_ref loc_result = NULL;
+  gcc_assert (!list->dw_loc_next || list->ll_symbol);
+  return !list->ll_symbol;
+}
 
-  switch (GET_CODE (rtl))
-    {
-    case SUBREG:
-      /* The case of a subreg may arise when we have a local (register)
-        variable or a formal (register) parameter which doesn't quite fill
-        up an entire register.  For now, just assume that it is
-        legitimate to make the Dwarf info refer to the whole register which
-        contains the given subreg.  */
-      rtl = SUBREG_REG (rtl);
+/* To each location in list LIST add loc descr REF.  */
 
-      /* ... fall through ...  */
+static void
+add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref)
+{
+  dw_loc_descr_ref copy;
+  add_loc_descr (&list->expr, ref);
+  list = list->dw_loc_next;
+  while (list)
+    {
+      copy = GGC_CNEW (dw_loc_descr_node);
+      memcpy (copy, ref, sizeof (dw_loc_descr_node));
+      add_loc_descr (&list->expr, copy);
+      while (copy->dw_loc_next)
+       {
+         dw_loc_descr_ref new_copy = GGC_CNEW (dw_loc_descr_node);
+         memcpy (new_copy, copy->dw_loc_next, sizeof (dw_loc_descr_node));
+         copy->dw_loc_next = new_copy;
+         copy = new_copy;
+       }
+      list = list->dw_loc_next;
+    }
+}
 
-    case REG:
-      loc_result = reg_loc_descriptor (rtl, initialized);
-      break;
+/* Given two lists RET and LIST
+   produce location list that is result of adding expression in LIST
+   to expression in RET on each possition in program.
+   Might be destructive on both RET and LIST.
 
-    case MEM:
-      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
-                                      initialized);
-      if (loc_result == NULL)
-       loc_result = tls_mem_loc_descriptor (rtl);
-      break;
+   TODO: We handle only simple cases of RET or LIST having at most one
+   element. General case would inolve sorting the lists in program order
+   and merging them that will need some additional work.
+   Adding that will improve quality of debug info especially for SRA-ed
+   structures.  */
 
-    case CONCAT:
-      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1),
-                                         initialized);
-      break;
+static void
+add_loc_list (dw_loc_list_ref *ret, dw_loc_list_ref list)
+{
+  if (!list)
+    return;
+  if (!*ret)
+    {
+      *ret = list;
+      return;
+    }
+  if (!list->dw_loc_next)
+    {
+      add_loc_descr_to_each (*ret, list->expr);
+      return;
+    }
+  if (!(*ret)->dw_loc_next)
+    {
+      add_loc_descr_to_each (list, (*ret)->expr);
+      *ret = list;
+      return;
+    }
+  expansion_failed (NULL_TREE, NULL_RTX,
+                   "Don't know how to merge two non-trivial"
+                   " location lists.\n");
+  *ret = NULL;
+  return;
+}
 
-    case CONCATN:
-      loc_result = concatn_loc_descriptor (rtl, initialized);
-      break;
+/* LOC is constant expression.  Try a luck, look it up in constant
+   pool and return its loc_descr of its address.  */
 
-    case VAR_LOCATION:
-      /* Single part.  */
-      if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
-       {
-         loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), initialized);
-         break;
-       }
+static dw_loc_descr_ref
+cst_pool_loc_descr (tree loc)
+{
+  /* Get an RTL for this, if something has been emitted.  */
+  rtx rtl = lookup_constant_def (loc);
+  enum machine_mode mode;
 
-      rtl = XEXP (rtl, 1);
-      /* FALLTHRU */
+  if (!rtl || !MEM_P (rtl))
+    {
+      gcc_assert (!rtl);
+      return 0;
+    }
+  gcc_assert (GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF);
 
-    case PARALLEL:
-      {
-       rtvec par_elems = XVEC (rtl, 0);
-       int num_elem = GET_NUM_ELEM (par_elems);
-       enum machine_mode mode;
-       int i;
+  /* TODO: We might get more coverage if we was actually delaying expansion
+     of all expressions till end of compilation when constant pools are fully
+     populated.  */
+  if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (XEXP (rtl, 0))))
+    {
+      expansion_failed (loc, NULL_RTX,
+                       "CST value in contant pool but not marked.");
+      return 0;
+    }
+  mode = GET_MODE (rtl);
+  rtl = XEXP (rtl, 0);
+  return mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
+}
 
-       /* Create the first one, so we have something to add to.  */
-       loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
-                                    initialized);
-       if (loc_result == NULL)
-         return NULL;
-       mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
-       add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
-       for (i = 1; i < num_elem; i++)
-         {
-           dw_loc_descr_ref temp;
+/* Return dw_loc_list representing address of addr_expr LOC
+   by looking for innder INDIRECT_REF expression and turing it
+   into simple arithmetics.  */
 
-           temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
-                                  initialized);
-           if (temp == NULL)
-             return NULL;
-           add_loc_descr (&loc_result, temp);
-           mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
-           add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
-         }
-      }
-      break;
+static dw_loc_list_ref
+loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev)
+{
+  tree obj, offset;
+  HOST_WIDE_INT bitsize, bitpos, bytepos;
+  enum machine_mode mode;
+  int volatilep;
+  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
+  dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
 
-    default:
-      gcc_unreachable ();
+  obj = get_inner_reference (TREE_OPERAND (loc, 0),
+                            &bitsize, &bitpos, &offset, &mode,
+                            &unsignedp, &volatilep, false);
+  STRIP_NOPS (obj);
+  if (bitpos % BITS_PER_UNIT)
+    {
+      expansion_failed (loc, NULL_RTX, "bitfield access");
+      return 0;
     }
-
-  return loc_result;
+  if (!INDIRECT_REF_P (obj))
+    {
+      expansion_failed (obj,
+                       NULL_RTX, "no indirect ref in inner refrence");
+      return 0;
+    }
+  if (!offset && !bitpos)
+    list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1);
+  else if (toplev
+          && int_size_in_bytes (TREE_TYPE (loc)) <= DWARF2_ADDR_SIZE
+          && (dwarf_version >= 4 || !dwarf_strict))
+    {
+      list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0);
+      if (!list_ret)
+       return 0;
+      if (offset)
+       {
+         /* Variable offset.  */
+         list_ret1 = loc_list_from_tree (offset, 0);
+         if (list_ret1 == 0)
+           return 0;
+         add_loc_list (&list_ret, list_ret1);
+         if (!list_ret)
+           return 0;
+         add_loc_descr_to_each (list_ret,
+                                new_loc_descr (DW_OP_plus, 0, 0));
+       }
+      bytepos = bitpos / BITS_PER_UNIT;
+      if (bytepos > 0)
+       add_loc_descr_to_each (list_ret,
+                              new_loc_descr (DW_OP_plus_uconst,
+                                             bytepos, 0));
+      else if (bytepos < 0)
+       loc_list_plus_const (list_ret, bytepos);
+      add_loc_descr_to_each (list_ret,
+                            new_loc_descr (DW_OP_stack_value, 0, 0));
+    }
+  return list_ret;
 }
 
-/* Similar, but generate the descriptor from trees instead of rtl.  This comes
-   up particularly with variable length arrays.  WANT_ADDRESS is 2 if this is
-   a top-level invocation of loc_descriptor_from_tree; is 1 if this is not a
-   top-level invocation, and we require the address of LOC; is 0 if we require
-   the value of LOC.  */
 
-static dw_loc_descr_ref
-loc_descriptor_from_tree_1 (tree loc, int want_address)
+/* Generate Dwarf location list representing LOC.
+   If WANT_ADDRESS is false, expression computing LOC will be computed
+   If WANT_ADDRESS is 1, expression computing address of LOC will be returned
+   if WANT_ADDRESS is 2, expression computing address useable in location
+     will be returned (i.e. DW_OP_reg can be used
+     to refer to register values).  */
+
+static dw_loc_list_ref
+loc_list_from_tree (tree loc, int want_address)
 {
-  dw_loc_descr_ref ret, ret1;
+  dw_loc_descr_ref ret = NULL, ret1 = NULL;
+  dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
   int have_address = 0;
   enum dwarf_location_atom op;
 
@@ -10901,6 +14199,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
   switch (TREE_CODE (loc))
     {
     case ERROR_MARK:
+      expansion_failed (loc, NULL_RTX, "ERROR_MARK");
       return 0;
 
     case PLACEHOLDER_EXPR:
@@ -10908,25 +14207,45 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
         position of other fields.  We don't try to encode this here.  The
         only user of this is Ada, which encodes the needed information using
         the names of types.  */
+      expansion_failed (loc, NULL_RTX, "PLACEHOLDER_EXPR");
       return 0;
 
     case CALL_EXPR:
+      expansion_failed (loc, NULL_RTX, "CALL_EXPR");
+      /* There are no opcodes for these operations.  */
       return 0;
 
     case PREINCREMENT_EXPR:
     case PREDECREMENT_EXPR:
     case POSTINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
+      expansion_failed (loc, NULL_RTX, "PRE/POST INDCREMENT/DECREMENT");
       /* There are no opcodes for these operations.  */
       return 0;
 
     case ADDR_EXPR:
-      /* If we already want an address, there's nothing we can do.  */
+      /* If we already want an address, see if there is INDIRECT_REF inside
+         e.g. for &this->field.  */
       if (want_address)
-       return 0;
-
-      /* Otherwise, process the argument and look for the address.  */
-      return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 1);
+       {
+         list_ret = loc_list_for_address_of_addr_expr_of_indirect_ref
+                      (loc, want_address == 2);
+         if (list_ret)
+           have_address = 1;
+         else if (decl_address_ip_invariant_p (TREE_OPERAND (loc, 0))
+                  && (ret = cst_pool_loc_descr (loc)))
+           have_address = 1;
+       }
+        /* Otherwise, process the argument and look for the address.  */
+      if (!list_ret && !ret)
+        list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 1);
+      else
+       {
+         if (want_address)
+           expansion_failed (loc, NULL_RTX, "need address of ADDR_EXPR");
+         return NULL;
+       }
+      break;
 
     case VAR_DECL:
       if (DECL_THREAD_LOCAL_P (loc))
@@ -10939,7 +14258,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
          if (targetm.have_tls)
            {
              /* If this is not defined, we have no way to emit the
-                data.  */
+                data.  */
              if (!targetm.asm_out.output_dwarf_dtprel)
                return 0;
 
@@ -10954,7 +14273,8 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
            }
          else
            {
-             if (!targetm.emutls.debug_form_tls_address)
+             if (!targetm.emutls.debug_form_tls_address
+                 || !(dwarf_version >= 3 || !dwarf_strict))
                return 0;
              loc = emutls_decl (loc);
              first_op = DW_OP_addr;
@@ -10986,17 +14306,28 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
 
     case PARM_DECL:
       if (DECL_HAS_VALUE_EXPR_P (loc))
-       return loc_descriptor_from_tree_1 (DECL_VALUE_EXPR (loc),
-                                          want_address);
+       return loc_list_from_tree (DECL_VALUE_EXPR (loc),
+                                  want_address);
       /* FALLTHRU */
 
     case RESULT_DECL:
     case FUNCTION_DECL:
       {
-       rtx rtl = rtl_for_decl_location (loc);
+       rtx rtl;
+       var_loc_list *loc_list = lookup_decl_loc (loc);
 
+       if (loc_list && loc_list->first)
+         {
+           list_ret = dw_loc_list (loc_list, loc, want_address);
+           have_address = want_address != 0;
+           break;
+         }
+       rtl = rtl_for_decl_location (loc);
        if (rtl == NULL_RTX)
-         return 0;
+         {
+           expansion_failed (loc, NULL_RTX, "DECL has no RTL");
+           return 0;
+         }
        else if (CONST_INT_P (rtl))
          {
            HOST_WIDE_INT val = INTVAL (rtl);
@@ -11005,8 +14336,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
            ret = int_loc_descriptor (val);
          }
        else if (GET_CODE (rtl) == CONST_STRING)
-         return 0;
-       else if (CONSTANT_P (rtl))
+         {
+           expansion_failed (loc, NULL_RTX, "CONST_STRING");
+           return 0;
+         }
+       else if (CONSTANT_P (rtl) && const_ok_for_output (rtl))
          {
            ret = new_loc_descr (DW_OP_addr, 0, 0);
            ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
@@ -11018,37 +14352,50 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
 
            /* Certain constructs can only be represented at top-level.  */
            if (want_address == 2)
-             return loc_descriptor (rtl, VAR_INIT_STATUS_INITIALIZED);
-
-           mode = GET_MODE (rtl);
-           if (MEM_P (rtl))
              {
-               rtl = XEXP (rtl, 0);
-               have_address = 1;
+               ret = loc_descriptor (rtl, VOIDmode,
+                                     VAR_INIT_STATUS_INITIALIZED);
+               have_address = 1;
+             }
+           else
+             {
+               mode = GET_MODE (rtl);
+               if (MEM_P (rtl))
+                 {
+                   rtl = XEXP (rtl, 0);
+                   have_address = 1;
+                 }
+               ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
              }
-           ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
+           if (!ret)
+             expansion_failed (loc, rtl,
+                               "failed to produce loc descriptor for rtl");
          }
       }
       break;
 
     case INDIRECT_REF:
-      ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
+    case ALIGN_INDIRECT_REF:
+    case MISALIGNED_INDIRECT_REF:
+      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
       have_address = 1;
       break;
 
     case COMPOUND_EXPR:
-      return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), want_address);
+      return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address);
 
     CASE_CONVERT:
     case VIEW_CONVERT_EXPR:
     case SAVE_EXPR:
     case MODIFY_EXPR:
-      return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), want_address);
+      return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address);
 
     case COMPONENT_REF:
     case BIT_FIELD_REF:
     case ARRAY_REF:
     case ARRAY_RANGE_REF:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
       {
        tree obj, offset;
        HOST_WIDE_INT bitsize, bitpos, bytepos;
@@ -11059,52 +14406,75 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
        obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
                                   &unsignedp, &volatilep, false);
 
-       if (obj == loc)
-         return 0;
+       gcc_assert (obj != loc);
 
-       ret = loc_descriptor_from_tree_1 (obj, 1);
-       if (ret == 0
-           || bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0)
+       list_ret = loc_list_from_tree (obj,
+                                      want_address == 2
+                                      && !bitpos && !offset ? 2 : 1);
+       /* TODO: We can extract value of the small expression via shifting even
+          for nonzero bitpos.  */
+       if (list_ret == 0)
          return 0;
+       if (bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0)
+         {
+           expansion_failed (loc, NULL_RTX,
+                             "bitfield access");
+           return 0;
+         }
 
        if (offset != NULL_TREE)
          {
            /* Variable offset.  */
-           ret1 = loc_descriptor_from_tree_1 (offset, 0);
-           if (ret1 == 0)
+           list_ret1 = loc_list_from_tree (offset, 0);
+           if (list_ret1 == 0)
              return 0;
-           add_loc_descr (&ret, ret1);
-           add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
+           add_loc_list (&list_ret, list_ret1);
+           if (!list_ret)
+             return 0;
+           add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus, 0, 0));
          }
 
        bytepos = bitpos / BITS_PER_UNIT;
-       loc_descr_plus_const (&ret, bytepos);
+       if (bytepos > 0)
+         add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0));
+       else if (bytepos < 0)
+         loc_list_plus_const (list_ret, bytepos);
 
        have_address = 1;
        break;
       }
 
     case INTEGER_CST:
-      if (host_integerp (loc, 0))
+      if ((want_address || !host_integerp (loc, 0))
+         && (ret = cst_pool_loc_descr (loc)))
+       have_address = 1;
+      else if (want_address == 2
+              && host_integerp (loc, 0)
+              && (ret = address_of_int_loc_descriptor
+                          (int_size_in_bytes (TREE_TYPE (loc)),
+                           tree_low_cst (loc, 0))))
+       have_address = 1;
+      else if (host_integerp (loc, 0))
        ret = int_loc_descriptor (tree_low_cst (loc, 0));
       else
-       return 0;
+       {
+         expansion_failed (loc, NULL_RTX,
+                           "Integer operand is not host integer");
+         return 0;
+       }
       break;
 
     case CONSTRUCTOR:
-      {
-       /* Get an RTL for this, if something has been emitted.  */
-       rtx rtl = lookup_constant_def (loc);
-       enum machine_mode mode;
-
-       if (!rtl || !MEM_P (rtl))
-         return 0;
-       mode = GET_MODE (rtl);
-       rtl = XEXP (rtl, 0);
-       ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
+    case REAL_CST:
+    case STRING_CST:
+    case COMPLEX_CST:
+      if ((ret = cst_pool_loc_descr (loc)))
        have_address = 1;
-       break;
-      }
+      else
+      /* We can construct small constants here using int_loc_descriptor.  */
+       expansion_failed (loc, NULL_RTX,
+                         "constructor or constant not in constant pool");
+      break;
 
     case TRUTH_AND_EXPR:
     case TRUTH_ANDIF_EXPR:
@@ -11158,11 +14528,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
       if (TREE_CODE (TREE_OPERAND (loc, 1)) == INTEGER_CST
          && host_integerp (TREE_OPERAND (loc, 1), 0))
        {
-         ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
-         if (ret == 0)
+         list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+         if (list_ret == 0)
            return 0;
 
-         loc_descr_plus_const (&ret, tree_low_cst (TREE_OPERAND (loc, 1), 0));
+         loc_list_plus_const (list_ret, tree_low_cst (TREE_OPERAND (loc, 1), 0));
          break;
        }
 
@@ -11206,13 +14576,15 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
       goto do_binop;
 
     do_binop:
-      ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
-      ret1 = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0);
-      if (ret == 0 || ret1 == 0)
+      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+      list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0);
+      if (list_ret == 0 || list_ret1 == 0)
        return 0;
 
-      add_loc_descr (&ret, ret1);
-      add_loc_descr (&ret, new_loc_descr (op, 0, 0));
+      add_loc_list (&list_ret, list_ret1);
+      if (list_ret == 0)
+       return 0;
+      add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0));
       break;
 
     case TRUTH_NOT_EXPR:
@@ -11229,11 +14601,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
       goto do_unop;
 
     do_unop:
-      ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
-      if (ret == 0)
+      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+      if (list_ret == 0)
        return 0;
 
-      add_loc_descr (&ret, new_loc_descr (op, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0));
       break;
 
     case MIN_EXPR:
@@ -11253,29 +14625,29 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
     case COND_EXPR:
       {
        dw_loc_descr_ref lhs
-         = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0);
-       dw_loc_descr_ref rhs
-         = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 2), 0);
+         = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
+       dw_loc_list_ref rhs
+         = loc_list_from_tree (TREE_OPERAND (loc, 2), 0);
        dw_loc_descr_ref bra_node, jump_node, tmp;
 
-       ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
-       if (ret == 0 || lhs == 0 || rhs == 0)
+       list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+       if (list_ret == 0 || lhs == 0 || rhs == 0)
          return 0;
 
        bra_node = new_loc_descr (DW_OP_bra, 0, 0);
-       add_loc_descr (&ret, bra_node);
+       add_loc_descr_to_each (list_ret, bra_node);
 
-       add_loc_descr (&ret, rhs);
+       add_loc_list (&list_ret, rhs);
        jump_node = new_loc_descr (DW_OP_skip, 0, 0);
-       add_loc_descr (&ret, jump_node);
+       add_loc_descr_to_each (list_ret, jump_node);
 
-       add_loc_descr (&ret, lhs);
+       add_loc_descr_to_each (list_ret, lhs);
        bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
        bra_node->dw_loc_oprnd1.v.val_loc = lhs;
 
        /* ??? Need a node to point the skip at.  Use a nop.  */
        tmp = new_loc_descr (DW_OP_nop, 0, 0);
-       add_loc_descr (&ret, tmp);
+       add_loc_descr_to_each (list_ret, tmp);
        jump_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
        jump_node->dw_loc_oprnd1.v.val_loc = tmp;
       }
@@ -11289,7 +14661,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
         up, for instance, with the C STMT_EXPR.  */
       if ((unsigned int) TREE_CODE (loc)
          >= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
-       return 0;
+       {
+         expansion_failed (loc, NULL_RTX,
+                           "language specific tree node");
+         return 0;
+       }
 
 #ifdef ENABLE_CHECKING
       /* Otherwise this is a generic code; we should just lists all of
@@ -11302,32 +14678,76 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
 #endif
     }
 
+  if (!ret && !list_ret)
+    return 0;
+
+  if (want_address == 2 && !have_address
+      && (dwarf_version >= 4 || !dwarf_strict))
+    {
+      if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE)
+       {
+         expansion_failed (loc, NULL_RTX,
+                           "DWARF address size mismatch");
+         return 0;
+       }
+      if (ret)
+       add_loc_descr (&ret, new_loc_descr (DW_OP_stack_value, 0, 0));
+      else
+       add_loc_descr_to_each (list_ret,
+                              new_loc_descr (DW_OP_stack_value, 0, 0));
+      have_address = 1;
+    }
   /* Show if we can't fill the request for an address.  */
   if (want_address && !have_address)
-    return 0;
+    {
+      expansion_failed (loc, NULL_RTX,
+                       "Want address and only have value");
+      return 0;
+    }
+
+  gcc_assert (!ret || !list_ret);
 
   /* If we've got an address and don't want one, dereference.  */
-  if (!want_address && have_address && ret)
+  if (!want_address && have_address)
     {
       HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
 
       if (size > DWARF2_ADDR_SIZE || size == -1)
-       return 0;
+       {
+         expansion_failed (loc, NULL_RTX,
+                           "DWARF address size mismatch");
+         return 0;
+       }
       else if (size == DWARF2_ADDR_SIZE)
        op = DW_OP_deref;
       else
        op = DW_OP_deref_size;
 
-      add_loc_descr (&ret, new_loc_descr (op, size, 0));
+      if (ret)
+       add_loc_descr (&ret, new_loc_descr (op, size, 0));
+      else
+       add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0));
     }
+  if (ret)
+    list_ret = new_loc_list (ret, NULL, NULL, NULL);
 
-  return ret;
+  return list_ret;
 }
 
-static inline dw_loc_descr_ref
-loc_descriptor_from_tree (tree loc)
+/* Same as above but return only single location expression.  */
+static dw_loc_descr_ref
+loc_descriptor_from_tree (tree loc, int want_address)
 {
-  return loc_descriptor_from_tree_1 (loc, 2);
+  dw_loc_list_ref ret = loc_list_from_tree (loc, want_address);
+  if (!ret)
+    return NULL;
+  if (ret->dw_loc_next)
+    {
+      expansion_failed (loc, NULL_RTX,
+                       "Location list where only loc descriptor needed");
+      return NULL;
+    }
+  return ret->expr;
 }
 
 /* Given a value, round it up to the lowest multiple of `boundary'
@@ -11437,9 +14857,9 @@ field_byte_offset (const_tree decl)
       field_size_tree = DECL_SIZE (decl);
 
       /* The size could be unspecified if there was an error, or for
-         a flexible array member.  */
+        a flexible array member.  */
       if (!field_size_tree)
-        field_size_tree = bitsize_zero_node;
+       field_size_tree = bitsize_zero_node;
 
       /* If the size of the field is not constant, use the type size.  */
       if (host_integerp (field_size_tree, 1))
@@ -11534,10 +14954,14 @@ field_byte_offset (const_tree decl)
 
 static inline void
 add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
-                            dw_loc_descr_ref descr)
+                            dw_loc_list_ref descr)
 {
-  if (descr != 0)
-    add_AT_loc (die, attr_kind, descr);
+  if (descr == 0)
+    return;
+  if (single_element_loc_list_p (descr))
+    add_AT_loc (die, attr_kind, descr->expr);
+  else
+    add_AT_loc_list (die, attr_kind, descr);
 }
 
 /* Attach the specialized form of location attribute used for data members of
@@ -11623,11 +15047,11 @@ add_data_member_location_attribute (dw_die_ref die, tree decl)
       else
        {
          enum dwarf_location_atom op;
-         
+
          /* The DWARF2 standard says that we should assume that the structure
             address is already on the stack, so we can specify a structure
             field address by using DW_OP_plus_uconst.  */
-         
+
 #ifdef MIPS_DEBUGGING_INFO
          /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst
             operator correctly.  It works only if we leave the offset on the
@@ -11636,7 +15060,7 @@ add_data_member_location_attribute (dw_die_ref die, tree decl)
 #else
          op = DW_OP_plus_uconst;
 #endif
-         
+
          loc_descr = new_loc_descr (op, offset, 0);
        }
     }
@@ -11700,7 +15124,7 @@ insert_float (const_rtx rtl, unsigned char *array)
    to an inlined function.  They can also arise in C++ where declared
    constants do not necessarily get memory "homes".  */
 
-static void
+static bool
 add_const_value_attribute (dw_die_ref die, rtx rtl)
 {
   switch (GET_CODE (rtl))
@@ -11714,13 +15138,13 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
        else
          add_AT_unsigned (die, DW_AT_const_value, (unsigned HOST_WIDE_INT) val);
       }
-      break;
+      return true;
 
     case CONST_DOUBLE:
       /* Note that a CONST_DOUBLE rtx could represent either an integer or a
         floating-point constant.  A CONST_DOUBLE is used whenever the
         constant requires more than one word in order to be adequately
-        represented.  We output CONST_DOUBLEs as blocks.  */
+        represented.  */
       {
        enum machine_mode mode = GET_MODE (rtl);
 
@@ -11733,15 +15157,10 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
            add_AT_vec (die, DW_AT_const_value, length / 4, 4, array);
          }
        else
-         {
-           /* ??? We really should be using HOST_WIDE_INT throughout.  */
-           gcc_assert (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT);
-
-           add_AT_long_long (die, DW_AT_const_value,
-                             CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
-         }
+         add_AT_double (die, DW_AT_const_value,
+                        CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
       }
-      break;
+      return true;
 
     case CONST_VECTOR:
       {
@@ -11809,18 +15228,35 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
 
        add_AT_vec (die, DW_AT_const_value, length, elt_size, array);
       }
-      break;
+      return true;
 
     case CONST_STRING:
-      add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0));
-      break;
+      if (dwarf_version >= 4 || !dwarf_strict)
+       {
+         dw_loc_descr_ref loc_result;
+         resolve_one_addr (&rtl, NULL);
+       rtl_addr:
+         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
+         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
+         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+         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);
+         return true;
+       }
+      return false;
 
+    case CONST:
+      if (CONSTANT_P (XEXP (rtl, 0)))
+       return add_const_value_attribute (die, XEXP (rtl, 0));
+      /* FALLTHROUGH */
     case SYMBOL_REF:
+      if (!const_ok_for_output (rtl))
+       return false;
     case LABEL_REF:
-    case CONST:
-      add_AT_addr (die, DW_AT_const_value, rtl);
-      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
-      break;
+      if (dwarf_version >= 4 || !dwarf_strict)
+       goto rtl_addr;
+      return false;
 
     case PLUS:
       /* In cases where an inlined instance of an inline function is passed
@@ -11834,13 +15270,27 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
         *value* which the artificial local variable always has during its
         lifetime.  We currently have no way to represent such quasi-constant
         values in Dwarf, so for now we just punt and generate nothing.  */
-      break;
+      return false;
+
+    case HIGH:
+    case CONST_FIXED:
+      return false;
+
+    case MEM:
+      if (GET_CODE (XEXP (rtl, 0)) == CONST_STRING
+         && MEM_READONLY_P (rtl)
+         && GET_MODE (rtl) == BLKmode)
+       {
+         add_AT_string (die, DW_AT_const_value, XSTR (XEXP (rtl, 0), 0));
+         return true;
+       }
+      return false;
 
     default:
       /* No other kinds of rtx should be possible here.  */
       gcc_unreachable ();
     }
-
+  return false;
 }
 
 /* Determine whether the evaluation of EXPR references any variables
@@ -11862,17 +15312,20 @@ reference_to_unused (tree * tp, int * walk_subtrees,
   else if (!cgraph_global_info_ready
           && (TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == FUNCTION_DECL))
     return *tp;
-  else if (DECL_P (*tp) && TREE_CODE (*tp) == VAR_DECL)
+  else if (TREE_CODE (*tp) == VAR_DECL)
     {
       struct varpool_node *node = varpool_node (*tp);
       if (!node->needed)
        return *tp;
     }
-  else if (DECL_P (*tp) && TREE_CODE (*tp) == FUNCTION_DECL
+  else if (TREE_CODE (*tp) == FUNCTION_DECL
           && (!DECL_EXTERNAL (*tp) || DECL_DECLARED_INLINE_P (*tp)))
     {
-      struct cgraph_node *node = cgraph_node (*tp);
-      if (node->process || TREE_ASM_WRITTEN (*tp))
+      /* The call graph machinery must have finished analyzing,
+         optimizing and gimplifying the CU by now.
+        So if *TP has no call graph node associated
+        to it, it means *TP will not be emitted.  */
+      if (!cgraph_get_node (*tp))
        return *tp;
     }
   else if (TREE_CODE (*tp) == STRING_CST && !TREE_ASM_WRITTEN (*tp))
@@ -11904,8 +15357,12 @@ rtl_for_decl_init (tree init, tree type)
                               TREE_STRING_LENGTH (init) - 1) == 0
          && ((size_t) TREE_STRING_LENGTH (init)
              == strlen (TREE_STRING_POINTER (init)) + 1))
-       rtl = gen_rtx_CONST_STRING (VOIDmode,
-                                   ggc_strdup (TREE_STRING_POINTER (init)));
+       {
+         rtl = gen_rtx_CONST_STRING (VOIDmode,
+                                     ggc_strdup (TREE_STRING_POINTER (init)));
+         rtl = gen_rtx_MEM (BLKmode, rtl);
+         MEM_READONLY_P (rtl) = 1;
+       }
     }
   /* Other aggregates, and complex values, could be represented using
      CONCAT: FIXME!  */
@@ -12166,37 +15623,28 @@ rtl_for_decl_location (tree decl)
   if (rtl)
     rtl = avoid_constant_pool_reference (rtl);
 
-  return rtl;
-}
-
-/* We need to figure out what section we should use as the base for the
-   address ranges where a given location is valid.
-   1. If this particular DECL has a section associated with it, use that.
-   2. If this function has a section associated with it, use that.
-   3. Otherwise, use the text section.
-   XXX: If you split a variable across multiple sections, we won't notice.  */
-
-static const char *
-secname_for_decl (const_tree decl)
-{
-  const char *secname;
-
-  if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl))
-    {
-      tree sectree = DECL_SECTION_NAME (decl);
-      secname = TREE_STRING_POINTER (sectree);
-    }
-  else if (current_function_decl && DECL_SECTION_NAME (current_function_decl))
-    {
-      tree sectree = DECL_SECTION_NAME (current_function_decl);
-      secname = TREE_STRING_POINTER (sectree);
+  /* Try harder to get a rtl.  If this symbol ends up not being emitted
+     in the current CU, resolve_addr will remove the expression referencing
+     it.  */
+  if (rtl == NULL_RTX
+      && TREE_CODE (decl) == VAR_DECL
+      && !DECL_EXTERNAL (decl)
+      && TREE_STATIC (decl)
+      && DECL_NAME (decl)
+      && !DECL_HARD_REGISTER (decl)
+      && DECL_MODE (decl) != VOIDmode)
+    {
+      rtl = DECL_RTL (decl);
+      /* Reset DECL_RTL back, as various parts of the compiler expects
+        DECL_RTL set meaning it is actually going to be output.  */
+      SET_DECL_RTL (decl, NULL);
+      if (!MEM_P (rtl)
+         || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF
+         || SYMBOL_REF_DECL (XEXP (rtl, 0)) != decl)
+       rtl = NULL_RTX;
     }
-  else if (cfun && in_cold_section_p)
-    secname = crtl->subsections.cold_section_label;
-  else
-    secname = text_section_label;
 
-  return secname;
+  return rtl;
 }
 
 /* Check whether decl is a Fortran COMMON symbol.  If not, NULL_TREE is
@@ -12212,12 +15660,11 @@ fortran_common (tree decl, HOST_WIDE_INT *value)
   tree offset;
   int volatilep = 0, unsignedp = 0;
 
-  /* If the decl isn't a VAR_DECL, or if it isn't public or static, or if
+  /* If the decl isn't a VAR_DECL, or if it isn't static, or if
      it does not have a value (the offset into the common area), or if it
      is thread local (as opposed to global) then it isn't common, and shouldn't
      be handled as such.  */
   if (TREE_CODE (decl) != VAR_DECL
-      || !TREE_PUBLIC (decl)
       || !TREE_STATIC (decl)
       || !DECL_HAS_VALUE_EXPR_P (decl)
       || !is_fortran ())
@@ -12249,60 +15696,6 @@ fortran_common (tree decl, HOST_WIDE_INT *value)
   return cvar;
 }
 
-/* Dereference a location expression LOC if DECL is passed by invisible
-   reference.  */
-
-static dw_loc_descr_ref
-loc_by_reference (dw_loc_descr_ref loc, tree decl)
-{
-  HOST_WIDE_INT size;
-  enum dwarf_location_atom op;
-
-  if (loc == NULL)
-    return NULL;
-
-  if ((TREE_CODE (decl) != PARM_DECL
-       && TREE_CODE (decl) != RESULT_DECL
-       && TREE_CODE (decl) != VAR_DECL)
-      || !DECL_BY_REFERENCE (decl))
-    return loc;
-
-  /* If loc is DW_OP_reg{0...31,x}, don't add DW_OP_deref, instead
-     change it into corresponding DW_OP_breg{0...31,x} 0.  Then the
-     location expression is considered to be address of a memory location,
-     rather than the register itself.  */
-  if (((loc->dw_loc_opc >= DW_OP_reg0 && loc->dw_loc_opc <= DW_OP_reg31)
-       || loc->dw_loc_opc == DW_OP_regx)
-      && (loc->dw_loc_next == NULL
-         || (loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_uninit
-             && loc->dw_loc_next->dw_loc_next == NULL)))
-    {
-      if (loc->dw_loc_opc == DW_OP_regx)
-       {
-         loc->dw_loc_opc = DW_OP_bregx;
-         loc->dw_loc_oprnd2.v.val_int = 0;
-       }
-      else
-       {
-         loc->dw_loc_opc
-           = (enum dwarf_location_atom)
-             (loc->dw_loc_opc + (DW_OP_breg0 - DW_OP_reg0));
-         loc->dw_loc_oprnd1.v.val_int = 0;
-       }
-      return loc;
-    }
-
-  size = int_size_in_bytes (TREE_TYPE (decl));
-  if (size > DWARF2_ADDR_SIZE || size == -1)
-    return 0;
-  else if (size == DWARF2_ADDR_SIZE)
-    op = DW_OP_deref;
-  else
-    op = DW_OP_deref_size;
-  add_loc_descr (&loc, new_loc_descr (op, size, 0));
-  return loc;
-}
-
 /* Generate *either* a DW_AT_location attribute or else a DW_AT_const_value
    data attribute for a variable or a parameter.  We generate the
    DW_AT_const_value attribute only in those cases where the given variable
@@ -12314,137 +15707,57 @@ loc_by_reference (dw_loc_descr_ref loc, tree decl)
    pointer.  This can happen for example if an actual argument in an inlined
    function call evaluates to a compile-time constant address.  */
 
-static void
+static bool
 add_location_or_const_value_attribute (dw_die_ref die, tree decl,
                                       enum dwarf_attribute attr)
 {
   rtx rtl;
-  dw_loc_descr_ref descr;
+  dw_loc_list_ref list;
   var_loc_list *loc_list;
-  struct var_loc_node *node;
+
   if (TREE_CODE (decl) == ERROR_MARK)
-    return;
+    return false;
 
   gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
              || TREE_CODE (decl) == RESULT_DECL);
 
-  /* See if we possibly have multiple locations for this variable.  */
-  loc_list = lookup_decl_loc (decl);
-
-  /* If it truly has multiple locations, the first and last node will
-     differ.  */
-  if (loc_list && loc_list->first != loc_list->last)
-    {
-      const char *endname, *secname;
-      dw_loc_list_ref list;
-      rtx varloc;
-      enum var_init_status initialized;
-
-      /* Now that we know what section we are using for a base,
-        actually construct the list of locations.
-        The first location information is what is passed to the
-        function that creates the location list, and the remaining
-        locations just get added on to that list.
-        Note that we only know the start address for a location
-        (IE location changes), so to build the range, we use
-        the range [current location start, next location start].
-        This means we have to special case the last node, and generate
-        a range of [last location start, end of function label].  */
-
-      node = loc_list->first;
-      varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-      secname = secname_for_decl (decl);
-
-      if (NOTE_VAR_LOCATION_LOC (node->var_loc_note))
-       initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-      else
-       initialized = VAR_INIT_STATUS_INITIALIZED;
-
-      descr = loc_by_reference (loc_descriptor (varloc, initialized), decl);
-      list = new_loc_list (descr, node->label, node->next->label, secname, 1);
-      node = node->next;
-
-      for (; node->next; node = node->next)
-       if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
-         {
-           /* The variable has a location between NODE->LABEL and
-              NODE->NEXT->LABEL.  */
-           enum var_init_status initialized =
-             NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-           varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-           descr = loc_by_reference (loc_descriptor (varloc, initialized),
-                                     decl);
-           add_loc_descr_to_loc_list (&list, descr,
-                                      node->label, node->next->label, secname);
-         }
-
-      /* If the variable has a location at the last label
-        it keeps its location until the end of function.  */
-      if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
-       {
-         char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
-         enum var_init_status initialized =
-           NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-
-         varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-         if (!current_function_decl)
-           endname = text_end_label;
-         else
-           {
-             ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
-                                          current_function_funcdef_no);
-             endname = ggc_strdup (label_id);
-           }
-         descr = loc_by_reference (loc_descriptor (varloc, initialized),
-                                   decl);
-         add_loc_descr_to_loc_list (&list, descr,
-                                    node->label, endname, secname);
-       }
-
-      /* Finally, add the location list to the DIE, and we are done.  */
-      add_AT_loc_list (die, attr, list);
-      return;
-    }
-
   /* Try to get some constant RTL for this decl, and use that as the value of
      the location.  */
 
   rtl = rtl_for_decl_location (decl);
-  if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING))
-    {
-      add_const_value_attribute (die, rtl);
-      return;
-    }
+  if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
+      && add_const_value_attribute (die, rtl))
+    return true;
 
-  /* If we have tried to generate the location otherwise, and it
-     didn't work out (we wouldn't be here if we did), and we have a one entry
-     location list, try generating a location from that.  */
-  if (loc_list && loc_list->first)
+  /* See if we have single element location list that is equivalent to
+     a constant value.  That way we are better to use add_const_value_attribute
+     rather than expanding constant value equivalent.  */
+  loc_list = lookup_decl_loc (decl);
+  if (loc_list
+      && loc_list->first
+      && loc_list->first == loc_list->last
+      && NOTE_VAR_LOCATION (loc_list->first->var_loc_note)
+      && NOTE_VAR_LOCATION_LOC (loc_list->first->var_loc_note))
     {
-      enum var_init_status status;
+      struct var_loc_node *node;
+
       node = loc_list->first;
-      status = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-      descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note), status);
-      if (descr)
-       {
-         descr = loc_by_reference (descr, decl);
-         add_AT_location_description (die, attr, descr);
-         return;
-       }
+      rtl = NOTE_VAR_LOCATION_LOC (node->var_loc_note);
+      if (GET_CODE (rtl) != PARALLEL)
+       rtl = XEXP (rtl, 0);
+      if ((CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
+         && add_const_value_attribute (die, rtl))
+        return true;
     }
-
-  /* We couldn't get any rtl, so try directly generating the location
-     description from the tree.  */
-  descr = loc_descriptor_from_tree (decl);
-  if (descr)
+  list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2);
+  if (list)
     {
-      descr = loc_by_reference (descr, decl);
-      add_AT_location_description (die, attr, descr);
-      return;
+      add_AT_location_description (die, attr, list);
+      return true;
     }
   /* None of that worked, so it must not really have a location;
      try adding a constant value attribute from the DECL_INITIAL.  */
-  tree_add_const_value_attribute (die, decl);
+  return tree_add_const_value_attribute_for_decl (die, decl);
 }
 
 /* Add VARIABLE and DIE into deferred locations list.  */
@@ -12605,29 +15918,25 @@ native_encode_initializer (tree init, unsigned char *array, int size)
     }
 }
 
-/* If we don't have a copy of this variable in memory for some reason (such
-   as a C++ member constant that doesn't have an out-of-line definition),
-   we should tell the debugger about the constant value.  */
+/* Attach a DW_AT_const_value attribute to DIE. The value of the
+   attribute is the const value T.  */
 
-static void
-tree_add_const_value_attribute (dw_die_ref var_die, tree decl)
+static bool
+tree_add_const_value_attribute (dw_die_ref die, tree t)
 {
   tree init;
-  tree type = TREE_TYPE (decl);
+  tree type = TREE_TYPE (t);
   rtx rtl;
 
-  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL)
-    return;
+  if (!t || !TREE_TYPE (t) || TREE_TYPE (t) == error_mark_node)
+    return false;
 
-  init = DECL_INITIAL (decl);
-  if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init)
-    /* OK */;
-  else
-    return;
+  init = t;
+  gcc_assert (!DECL_P (init));
 
   rtl = rtl_for_decl_init (init, type);
   if (rtl)
-    add_const_value_attribute (var_die, rtl);
+    return add_const_value_attribute (die, rtl);
   /* If the host and target are sane, try harder.  */
   else if (CHAR_BIT == 8 && BITS_PER_UNIT == 8
           && initializer_constant_valid_p (init, type))
@@ -12638,9 +15947,41 @@ tree_add_const_value_attribute (dw_die_ref var_die, tree decl)
          unsigned char *array = GGC_CNEWVEC (unsigned char, size);
 
          if (native_encode_initializer (init, array, size))
-           add_AT_vec (var_die, DW_AT_const_value, size, 1, array);
+           {
+             add_AT_vec (die, DW_AT_const_value, size, 1, array);
+             return true;
+           }
        }
     }
+  return false;
+}
+
+/* Attach a DW_AT_const_value attribute to VAR_DIE. The value of the
+   attribute is the const value of T, where T is an integral constant
+   variable with static storage duration
+   (so it can't be a PARM_DECL or a RESULT_DECL).  */
+
+static bool
+tree_add_const_value_attribute_for_decl (dw_die_ref var_die, tree decl)
+{
+
+  if (!decl
+      || (TREE_CODE (decl) != VAR_DECL
+         && TREE_CODE (decl) != CONST_DECL))
+    return false;
+
+    if (TREE_READONLY (decl)
+       && ! TREE_THIS_VOLATILE (decl)
+       && DECL_INITIAL (decl))
+      /* OK */;
+    else
+      return false;
+
+  /* Don't add DW_AT_const_value if abstract origin already has one.  */
+  if (get_AT (var_die, DW_AT_const_value))
+    return false;
+
+  return tree_add_const_value_attribute (var_die, DECL_INITIAL (decl));
 }
 
 /* Convert the CFI instructions for the current function into a
@@ -12690,8 +16031,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
        if (!cfa_equal_p (&last_cfa, &next_cfa))
          {
            *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
-                                      start_label, last_label, section,
-                                      list == NULL);
+                                      start_label, last_label, section);
 
            list_tail = &(*list_tail)->dw_loc_next;
            last_cfa = next_cfa;
@@ -12712,14 +16052,16 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
   if (!cfa_equal_p (&last_cfa, &next_cfa))
     {
       *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
-                                start_label, last_label, section,
-                                list == NULL);
+                                start_label, last_label, section);
       list_tail = &(*list_tail)->dw_loc_next;
       start_label = last_label;
     }
+
   *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
-                            start_label, fde->dw_fde_end, section,
-                            list == NULL);
+                            start_label, fde->dw_fde_end, section);
+
+  if (list && list->dw_loc_next)
+    gen_llsym (list);
 
   return list;
 }
@@ -12780,7 +16122,23 @@ static void
 add_comp_dir_attribute (dw_die_ref die)
 {
   const char *wd = get_src_pwd ();
-  if (wd != NULL)
+  char *wd1;
+
+  if (wd == NULL)
+    return;
+
+  if (DWARF2_DIR_SHOULD_END_WITH_SEPARATOR)
+    {
+      int wdlen;
+
+      wdlen = strlen (wd);
+      wd1 = GGC_NEWVEC (char, wdlen + 2);
+      strcpy (wd1, wd);
+      wd1 [wdlen] = DIR_SEPARATOR;
+      wd1 [wdlen + 1] = 0;
+      wd = wd1;
+    }
+
     add_AT_string (die, DW_AT_comp_dir, remap_debug_filename (wd));
 }
 
@@ -12797,14 +16155,33 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
 
     /* All fixed-bounds are represented by INTEGER_CST nodes.  */
     case INTEGER_CST:
-      if (! host_integerp (bound, 0)
-         || (bound_attr == DW_AT_lower_bound
-             && (((is_c_family () || is_java ()) &&  integer_zerop (bound))
-                 || (is_fortran () && integer_onep (bound)))))
-       /* Use the default.  */
-       ;
-      else
-       add_AT_unsigned (subrange_die, bound_attr, tree_low_cst (bound, 0));
+      {
+       unsigned int prec = simple_type_size_in_bits (TREE_TYPE (bound));
+
+       /* Use the default if possible.  */
+       if (bound_attr == DW_AT_lower_bound
+           && (((is_c_family () || is_java ()) && integer_zerop (bound))
+               || (is_fortran () && integer_onep (bound))))
+         ;
+
+       /* Otherwise represent the bound as an unsigned value with the
+          precision of its type.  The precision and signedness of the
+          type will be necessary to re-interpret it unambiguously.  */
+       else if (prec < HOST_BITS_PER_WIDE_INT)
+         {
+           unsigned HOST_WIDE_INT mask
+             = ((unsigned HOST_WIDE_INT) 1 << prec) - 1;
+           add_AT_unsigned (subrange_die, bound_attr,
+                            TREE_INT_CST_LOW (bound) & mask);
+         }
+       else if (prec == HOST_BITS_PER_WIDE_INT
+                || TREE_INT_CST_HIGH (bound) == 0)
+         add_AT_unsigned (subrange_die, bound_attr,
+                          TREE_INT_CST_LOW (bound));
+       else
+         add_AT_double (subrange_die, bound_attr, TREE_INT_CST_HIGH (bound),
+                        TREE_INT_CST_LOW (bound));
+      }
       break;
 
     CASE_CONVERT:
@@ -12820,7 +16197,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
     case RESULT_DECL:
       {
        dw_die_ref decl_die = lookup_decl_die (bound);
-       dw_loc_descr_ref loc;
+       dw_loc_list_ref loc;
 
        /* ??? Can this happen, or should the variable have been bound
           first?  Probably it can, since I imagine that we try to create
@@ -12831,7 +16208,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
          add_AT_die_ref (subrange_die, bound_attr, decl_die);
        else
          {
-           loc = loc_descriptor_from_tree_1 (bound, 0);
+           loc = loc_list_from_tree (bound, 0);
            add_AT_location_description (subrange_die, bound_attr, loc);
          }
        break;
@@ -12843,10 +16220,10 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
           evaluate the value of the array bound.  */
 
        dw_die_ref ctx, decl_die;
-       dw_loc_descr_ref loc;
+       dw_loc_list_ref list;
 
-       loc = loc_descriptor_from_tree (bound);
-       if (loc == NULL)
+       list = loc_list_from_tree (bound, 2);
+       if (list == NULL)
          break;
 
        if (current_function_decl == 0)
@@ -12857,7 +16234,10 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
        decl_die = new_die (DW_TAG_variable, ctx, bound);
        add_AT_flag (decl_die, DW_AT_artificial, 1);
        add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
-       add_AT_loc (decl_die, DW_AT_location, loc);
+       if (list->dw_loc_next)
+         add_AT_loc_list (decl_die, DW_AT_location, list);
+       else
+         add_AT_loc (decl_die, DW_AT_location, list->expr);
 
        add_AT_die_ref (subrange_die, bound_attr, decl_die);
        break;
@@ -13111,7 +16491,8 @@ add_pure_or_virtual_attribute (dw_die_ref die, tree func_decl)
                                   0));
 
       /* GNU extension: Record what type this method came from originally.  */
-      if (debug_info_level > DINFO_LEVEL_TERSE)
+      if (debug_info_level > DINFO_LEVEL_TERSE
+         && DECL_CONTEXT (func_decl))
        add_AT_die_ref (die, DW_AT_containing_type,
                        lookup_type_die (DECL_CONTEXT (func_decl)));
     }
@@ -13139,7 +16520,9 @@ add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
   decl_name = DECL_NAME (decl);
   if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL)
     {
-      add_name_attribute (die, dwarf2_name (decl, 0));
+      const char *name = dwarf2_name (decl, 0);
+      if (name)
+       add_name_attribute (die, name);
       if (! DECL_ARTIFICIAL (decl))
        add_src_coords_attributes (die, decl);
 
@@ -13173,7 +16556,7 @@ add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
     {
       add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
                   XEXP (DECL_RTL (decl), 0));
-      VEC_safe_push (tree, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
+      VEC_safe_push (rtx, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
     }
 #endif
 }
@@ -13463,12 +16846,12 @@ gen_array_type_die (tree type, dw_die_ref context_die)
               && DECL_P (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
        {
          tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
-         dw_loc_descr_ref loc = loc_descriptor_from_tree (szdecl);
+         dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2);
 
          size = int_size_in_bytes (TREE_TYPE (szdecl));
          if (loc && size > 0)
            {
-             add_AT_loc (array_die, DW_AT_string_length, loc);
+             add_AT_location_description (array_die, DW_AT_string_length, loc);
              if (size != DWARF2_ADDR_SIZE)
                add_AT_unsigned (array_die, DW_AT_byte_size, size);
            }
@@ -13527,7 +16910,7 @@ gen_array_type_die (tree type, dw_die_ref context_die)
     add_subscript_info (array_die, type, collapse_nested_arrays);
 
   /* Add representation of the type of the elements of this array type and
-     emit the corresponding DIE if we haven't done it already.  */  
+     emit the corresponding DIE if we haven't done it already.  */
   element_type = TREE_TYPE (type);
   if (collapse_nested_arrays)
     while (TREE_CODE (element_type) == ARRAY_TYPE)
@@ -13562,7 +16945,7 @@ descr_info_loc (tree val, tree base_decl)
     CASE_CONVERT:
       return descr_info_loc (TREE_OPERAND (val, 0), base_decl);
     case VAR_DECL:
-      return loc_descriptor_from_tree_1 (val, 0);
+      return loc_descriptor_from_tree (val, 0);
     case INTEGER_CST:
       if (host_integerp (val, 0))
        return int_loc_descriptor (tree_low_cst (val, 0));
@@ -13759,7 +17142,9 @@ record_type_tag (tree type)
       return DW_TAG_class_type;
 
     case RECORD_IS_INTERFACE:
-      return DW_TAG_interface_type;
+      if (dwarf_version >= 3 || !dwarf_strict)
+       return DW_TAG_interface_type;
+      return DW_TAG_structure_type;
 
     default:
       gcc_unreachable ();
@@ -13848,10 +17233,13 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die)
    DIE to represent a formal parameter object (or some inlining thereof).  If
    it's the latter, then this function is only being called to output a
    DW_TAG_formal_parameter DIE to stand as a placeholder for some formal
-   argument type of some subprogram type.  */
+   argument type of some subprogram type.
+   If EMIT_NAME_P is true, name and source coordinate attributes
+   are emitted.  */
 
 static dw_die_ref
-gen_formal_parameter_die (tree node, tree origin, dw_die_ref context_die)
+gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
+                         dw_die_ref context_die)
 {
   tree node_or_origin = node ? node : origin;
   dw_die_ref parm_die
@@ -13867,8 +17255,9 @@ gen_formal_parameter_die (tree node, tree origin, dw_die_ref context_die)
       else
        {
          tree type = TREE_TYPE (node);
-         add_name_and_src_coords_attributes (parm_die, node);
-         if (DECL_BY_REFERENCE (node))
+         if (emit_name_p)
+           add_name_and_src_coords_attributes (parm_die, node);
+         if (decl_by_reference_p (node))
            add_type_attribute (parm_die, TREE_TYPE (type), 0, 0,
                                context_die);
          else
@@ -13900,6 +17289,47 @@ gen_formal_parameter_die (tree node, tree origin, dw_die_ref context_die)
   return parm_die;
 }
 
+/* Generate and return a DW_TAG_GNU_formal_parameter_pack. Also generate
+   children DW_TAG_formal_parameter DIEs representing the arguments of the
+   parameter pack.
+
+   PARM_PACK must be a function parameter pack.
+   PACK_ARG is the first argument of the parameter pack. Its TREE_CHAIN
+   must point to the subsequent arguments of the function PACK_ARG belongs to.
+   SUBR_DIE is the DIE of the function PACK_ARG belongs to.
+   If NEXT_ARG is non NULL, *NEXT_ARG is set to the function argument
+   following the last one for which a DIE was generated.  */
+
+static dw_die_ref
+gen_formal_parameter_pack_die  (tree parm_pack,
+                               tree pack_arg,
+                               dw_die_ref subr_die,
+                               tree *next_arg)
+{
+  tree arg;
+  dw_die_ref parm_pack_die;
+
+  gcc_assert (parm_pack
+             && lang_hooks.function_parameter_pack_p (parm_pack)
+             && subr_die);
+
+  parm_pack_die = new_die (DW_TAG_GNU_formal_parameter_pack, subr_die, parm_pack);
+  add_src_coords_attributes (parm_pack_die, parm_pack);
+
+  for (arg = pack_arg; arg; arg = TREE_CHAIN (arg))
+    {
+      if (! lang_hooks.decls.function_parm_expanded_from_pack_p (arg,
+                                                                parm_pack))
+       break;
+      gen_formal_parameter_die (arg, NULL,
+                               false /* Don't emit name attribute.  */,
+                               parm_pack_die);
+    }
+  if (next_arg)
+    *next_arg = arg;
+  return parm_pack_die;
+}
+
 /* Generate a special type of DIE used as a stand-in for a trailing ellipsis
    at the end of an (ANSI prototyped) formal parameters list.  */
 
@@ -13943,7 +17373,9 @@ gen_formal_types_die (tree function_or_method_type, dw_die_ref context_die)
        break;
 
       /* Output a (nameless) DIE to represent the formal parameter itself.  */
-      parm_die = gen_formal_parameter_die (formal_type, NULL, context_die);
+      parm_die = gen_formal_parameter_die (formal_type, NULL,
+                                          true /* Emit name attribute.  */,
+                                          context_die);
       if ((TREE_CODE (function_or_method_type) == METHOD_TYPE
           && link == first_parm_type)
          || (arg && DECL_ARTIFICIAL (arg)))
@@ -13980,7 +17412,8 @@ gen_type_die_for_member (tree type, tree member, dw_die_ref context_die)
 
   /* If we're trying to avoid duplicate debug info, we may not have
      emitted the member decl for this function.  Emit it now.  */
-  if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
+  if (TYPE_STUB_DECL (type)
+      && TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
       && ! lookup_decl_die (member))
     {
       dw_die_ref type_die;
@@ -14018,17 +17451,23 @@ dwarf2out_abstract_function (tree decl)
   dw_die_ref old_die;
   tree save_fn;
   tree context;
-  int was_abstract = DECL_ABSTRACT (decl);
+  int was_abstract;
+  htab_t old_decl_loc_table;
 
   /* Make sure we have the actual abstract inline, not a clone.  */
   decl = DECL_ORIGIN (decl);
-  htab_empty (decl_loc_table);
 
   old_die = lookup_decl_die (decl);
   if (old_die && get_AT (old_die, DW_AT_inline))
     /* We've already generated the abstract instance.  */
     return;
 
+  /* We can be called while recursively when seeing block defining inlined subroutine
+     DIE.  Be sure to not clobber the outer location table nor use it or we would
+     get locations in abstract instantces.  */
+  old_decl_loc_table = decl_loc_table;
+  decl_loc_table = NULL;
+
   /* Be sure we've emitted the in-class declaration DIE (if any) first, so
      we don't get confused by DECL_ABSTRACT.  */
   if (debug_info_level > DINFO_LEVEL_TERSE)
@@ -14044,20 +17483,23 @@ dwarf2out_abstract_function (tree decl)
   current_function_decl = decl;
   push_cfun (DECL_STRUCT_FUNCTION (decl));
 
+  was_abstract = DECL_ABSTRACT (decl);
   set_decl_abstract_flags (decl, 1);
   dwarf2out_decl (decl);
   if (! was_abstract)
     set_decl_abstract_flags (decl, 0);
 
   current_function_decl = save_fn;
+  decl_loc_table = old_decl_loc_table;
   pop_cfun ();
 }
 
 /* Helper function of premark_used_types() which gets called through
-   htab_traverse_resize().
+   htab_traverse.
 
    Marks the DIE of a given type in *SLOT as perennial, so it never gets
    marked as unused by prune_unused_types.  */
+
 static int
 premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
 {
@@ -14071,7 +17513,42 @@ premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
   return 1;
 }
 
+/* Helper function of premark_types_used_by_global_vars which gets called
+   through htab_traverse.
+
+   Marks the DIE of a given type in *SLOT as perennial, so it never gets
+   marked as unused by prune_unused_types. The DIE of the type is marked
+   only if the global variable using the type will actually be emitted.  */
+
+static int
+premark_types_used_by_global_vars_helper (void **slot,
+                                         void *data ATTRIBUTE_UNUSED)
+{
+  struct types_used_by_vars_entry *entry;
+  dw_die_ref die;
+
+  entry = (struct types_used_by_vars_entry *) *slot;
+  gcc_assert (entry->type != NULL
+             && entry->var_decl != NULL);
+  die = lookup_type_die (entry->type);
+  if (die)
+    {
+      /* Ask cgraph if the global variable really is to be emitted.
+         If yes, then we'll keep the DIE of ENTRY->TYPE.  */
+      struct varpool_node *node = varpool_node (entry->var_decl);
+      if (node->needed)
+       {
+         die->die_perennial_p = 1;
+         /* Keep the parent DIEs as well.  */
+         while ((die = die->die_parent) && die->die_perennial_p == 0)
+           die->die_perennial_p = 1;
+       }
+    }
+  return 1;
+}
+
 /* Mark all members of used_types_hash as perennial.  */
+
 static void
 premark_used_types (void)
 {
@@ -14079,6 +17556,16 @@ premark_used_types (void)
     htab_traverse (cfun->used_types_hash, premark_used_types_helper, NULL);
 }
 
+/* Mark all members of types_used_by_vars_entry as perennial.  */
+
+static void
+premark_types_used_by_global_vars (void)
+{
+  if (types_used_by_vars_hash)
+    htab_traverse (types_used_by_vars_hash,
+                  premark_types_used_by_global_vars_helper, NULL);
+}
+
 /* Generate a DIE to represent a declared function (either file-scope or
    block-local).  */
 
@@ -14211,7 +17698,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 
          /* If this is an explicit function declaration then generate
             a DW_AT_explicit attribute.  */
-          if (lang_hooks.decls.function_decl_explicit_p (decl))
+         if (lang_hooks.decls.function_decl_explicit_p (decl)
+             && (dwarf_version >= 3 || !dwarf_strict))
            add_AT_flag (subr_die, DW_AT_explicit, 1);
 
          /* The first time we see a member function, it is in the context of
@@ -14320,9 +17808,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 
       if (cfun->static_chain_decl)
        add_AT_location_description (subr_die, DW_AT_static_link,
-                loc_descriptor_from_tree (cfun->static_chain_decl));
+                loc_list_from_tree (cfun->static_chain_decl, 2));
     }
 
+  /* Generate child dies for template paramaters.  */
+  if (debug_info_level > DINFO_LEVEL_TERSE)
+    gen_generic_params_dies (decl);
+
   /* Now output descriptions of the arguments for this function. This gets
      (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list
      for a FUNCTION_DECL doesn't indicate cases where there was a trailing
@@ -14343,21 +17835,46 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
   else
     {
       /* Generate DIEs to represent all known formal parameters.  */
-      tree arg_decls = DECL_ARGUMENTS (decl);
-      tree parm;
-
-      /* When generating DIEs, generate the unspecified_parameters DIE
-        instead if we come across the arg "__builtin_va_alist" */
-      for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
-       if (TREE_CODE (parm) == PARM_DECL)
-         {
-           if (DECL_NAME (parm)
-               && !strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)),
-                           "__builtin_va_alist"))
-             gen_unspecified_parameters_die (parm, subr_die);
-           else
+      tree parm = DECL_ARGUMENTS (decl);
+      tree generic_decl = lang_hooks.decls.get_generic_function_decl (decl);
+      tree generic_decl_parm = generic_decl
+                               ? DECL_ARGUMENTS (generic_decl)
+                               : NULL;
+
+      /* Now we want to walk the list of parameters of the function and
+        emit their relevant DIEs.
+
+        We consider the case of DECL being an instance of a generic function
+        as well as it being a normal function.
+
+        If DECL is an instance of a generic function we walk the
+        parameters of the generic function declaration _and_ the parameters of
+        DECL itself. This is useful because we want to emit specific DIEs for
+        function parameter packs and those are declared as part of the
+        generic function declaration. In that particular case,
+        the parameter pack yields a DW_TAG_GNU_formal_parameter_pack DIE.
+        That DIE has children DIEs representing the set of arguments
+        of the pack. Note that the set of pack arguments can be empty.
+        In that case, the DW_TAG_GNU_formal_parameter_pack DIE will not have any
+        children DIE.
+
+        Otherwise, we just consider the parameters of DECL.  */
+      while (generic_decl_parm || parm)
+       {
+         if (generic_decl_parm
+             && lang_hooks.function_parameter_pack_p (generic_decl_parm))
+           gen_formal_parameter_pack_die (generic_decl_parm,
+                                          parm, subr_die,
+                                          &parm);
+         else if (parm)
+           {
              gen_decl_die (parm, NULL, subr_die);
-         }
+             parm = TREE_CHAIN (parm);
+           }
+
+         if (generic_decl_parm)
+           generic_decl_parm = TREE_CHAIN (generic_decl_parm);
+       }
 
       /* Decide whether we need an unspecified_parameters DIE at the end.
         There are 2 more cases to do this for: 1) the ansi ... declaration -
@@ -14453,26 +17970,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL;
   dw_die_ref origin_die;
   int declaration = (DECL_EXTERNAL (decl_or_origin)
-                    /* If DECL is COMDAT and has not actually been
-                       emitted, we cannot take its address; there
-                       might end up being no definition anywhere in
-                       the program.  For example, consider the C++
-                       test case:
-
-                         template <class T>
-                         struct S { static const int i = 7; };
-
-                         template <class T>
-                         const int S<T>::i;
-
-                         int f() { return S<int>::i; }
-
-                       Here, S<int>::i is not DECL_EXTERNAL, but no
-                       definition is required, so the compiler will
-                       not emit a definition.  */
-                    || (TREE_CODE (decl_or_origin) == VAR_DECL
-                        && DECL_COMDAT (decl_or_origin)
-                        && !TREE_ASM_WRITTEN (decl_or_origin))
                     || class_or_namespace_scope_p (context_die));
 
   if (!origin)
@@ -14484,9 +17981,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
      of a data member.  */
   if (com_decl)
     {
-      tree field;
       dw_die_ref com_die;
-      dw_loc_descr_ref loc;
+      dw_loc_list_ref loc;
       die_node com_die_arg;
 
       var_die = lookup_decl_die (decl_or_origin);
@@ -14494,22 +17990,23 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
        {
          if (get_AT (var_die, DW_AT_location) == NULL)
            {
-             loc = loc_descriptor_from_tree (com_decl);
+             loc = loc_list_from_tree (com_decl, off ? 1 : 2);
              if (loc)
                {
                  if (off)
                    {
                      /* Optimize the common case.  */
-                     if (loc->dw_loc_opc == DW_OP_addr
-                         && loc->dw_loc_next == NULL
-                         && GET_CODE (loc->dw_loc_oprnd1.v.val_addr)
+                     if (single_element_loc_list_p (loc)
+                         && loc->expr->dw_loc_opc == DW_OP_addr
+                         && loc->expr->dw_loc_next == NULL
+                         && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr)
                             == SYMBOL_REF)
-                       loc->dw_loc_oprnd1.v.val_addr
-                         = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off);
+                       loc->expr->dw_loc_oprnd1.v.val_addr
+                         = plus_constant (loc->expr->dw_loc_oprnd1.v.val_addr, off);
                        else
-                         loc_descr_plus_const (&loc, off);
+                         loc_list_plus_const (loc, off);
                    }
-                 add_AT_loc (var_die, DW_AT_location, loc);
+                 add_AT_location_description (var_die, DW_AT_location, loc);
                  remove_AT (var_die, DW_AT_declaration);
                }
            }
@@ -14521,11 +18018,10 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
          = htab_create_ggc (10, common_block_die_table_hash,
                             common_block_die_table_eq, NULL);
 
-      field = TREE_OPERAND (DECL_VALUE_EXPR (decl), 0);
       com_die_arg.decl_id = DECL_UID (com_decl);
       com_die_arg.die_parent = context_die;
       com_die = (dw_die_ref) htab_find (common_block_die_table, &com_die_arg);
-      loc = loc_descriptor_from_tree (com_decl);
+      loc = loc_list_from_tree (com_decl, 2);
       if (com_die == NULL)
        {
          const char *cnam
@@ -14536,10 +18032,10 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
          add_name_and_src_coords_attributes (com_die, com_decl);
          if (loc)
            {
-             add_AT_loc (com_die, DW_AT_location, loc);
+             add_AT_location_description (com_die, DW_AT_location, loc);
              /* Avoid sharing the same loc descriptor between
                 DW_TAG_common_block and DW_TAG_variable.  */
-             loc = loc_descriptor_from_tree (com_decl);
+             loc = loc_list_from_tree (com_decl, 2);
            }
           else if (DECL_EXTERNAL (decl))
            add_AT_flag (com_die, DW_AT_declaration, 1);
@@ -14550,8 +18046,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
        }
       else if (get_AT (com_die, DW_AT_location) == NULL && loc)
        {
-         add_AT_loc (com_die, DW_AT_location, loc);
-         loc = loc_descriptor_from_tree (com_decl);
+         add_AT_location_description (com_die, DW_AT_location, loc);
+         loc = loc_list_from_tree (com_decl, 2);
          remove_AT (com_die, DW_AT_declaration);
        }
       var_die = new_die (DW_TAG_variable, com_die, decl);
@@ -14564,15 +18060,16 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
          if (off)
            {
              /* Optimize the common case.  */
-             if (loc->dw_loc_opc == DW_OP_addr
-                 && loc->dw_loc_next == NULL
-                 && GET_CODE (loc->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
-               loc->dw_loc_oprnd1.v.val_addr
-                 = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off);
+             if (single_element_loc_list_p (loc)
+                 && loc->expr->dw_loc_opc == DW_OP_addr
+                 && loc->expr->dw_loc_next == NULL
+                 && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
+               loc->expr->dw_loc_oprnd1.v.val_addr
+                 = plus_constant (loc->expr->dw_loc_oprnd1.v.val_addr, off);
              else
-               loc_descr_plus_const (&loc, off);
+               loc_list_plus_const (loc, off);
            }
-         add_AT_loc (var_die, DW_AT_location, loc);
+         add_AT_location_description (var_die, DW_AT_location, loc);
        }
       else if (DECL_EXTERNAL (decl))
        add_AT_flag (var_die, DW_AT_declaration, 1);
@@ -14584,8 +18081,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
      and if we already emitted a DIE for it, don't emit a second
      DIE for it again.  */
   if (old_die
-      && declaration
-      && old_die->die_parent == context_die)
+      && declaration)
     return;
 
   /* For static data members, the declaration in the class is supposed
@@ -14635,10 +18131,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
       tree type = TREE_TYPE (decl);
 
       add_name_and_src_coords_attributes (var_die, decl);
-      if ((TREE_CODE (decl) == PARM_DECL
-          || TREE_CODE (decl) == RESULT_DECL
-          || TREE_CODE (decl) == VAR_DECL)
-         && DECL_BY_REFERENCE (decl))
+      if (decl_by_reference_p (decl))
        add_type_attribute (var_die, TREE_TYPE (type), 0, 0, context_die);
       else
        add_type_attribute (var_die, type, TREE_READONLY (decl),
@@ -14684,7 +18177,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
       add_pubname (decl_or_origin, var_die);
     }
   else
-    tree_add_const_value_attribute (var_die, decl_or_origin);
+    tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
 }
 
 /* Generate a DIE to represent a named constant.  */
@@ -14702,7 +18195,7 @@ gen_const_die (tree decl, dw_die_ref context_die)
     add_AT_flag (const_die, DW_AT_external, 1);
   if (DECL_ARTIFICIAL (decl))
     add_AT_flag (const_die, DW_AT_artificial, 1);
-  tree_add_const_value_attribute (const_die, decl);
+  tree_add_const_value_attribute_for_decl (const_die, decl);
 }
 
 /* Generate a DIE to represent a label identifier.  */
@@ -14756,8 +18249,11 @@ add_call_src_coords_attributes (tree stmt, dw_die_ref die)
 {
   expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt));
 
-  add_AT_file (die, DW_AT_call_file, lookup_filename (s.file));
-  add_AT_unsigned (die, DW_AT_call_line, s.line);
+  if (dwarf_version >= 3 || !dwarf_strict)
+    {
+      add_AT_file (die, DW_AT_call_file, lookup_filename (s.file));
+      add_AT_unsigned (die, DW_AT_call_line, s.line);
+    }
 }
 
 
@@ -14769,7 +18265,8 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
 {
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
-  if (BLOCK_FRAGMENT_CHAIN (stmt))
+  if (BLOCK_FRAGMENT_CHAIN (stmt)
+      && (dwarf_version >= 3 || !dwarf_strict))
     {
       tree chain;
 
@@ -14820,7 +18317,13 @@ gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth)
 static void
 gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die, int depth)
 {
-  tree decl = block_ultimate_origin (stmt);
+  tree decl;
+
+  /* The instance of function that is effectively being inlined shall not
+     be abstract.  */
+  gcc_assert (! BLOCK_ABSTRACT (stmt));
+
+  decl = block_ultimate_origin (stmt);
 
   /* Emit info for the abstract instance first, if we haven't yet.  We
      must emit this even if the block is abstract, otherwise when we
@@ -14841,20 +18344,6 @@ gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die, int depth)
       decls_for_scope (stmt, subr_die, depth);
       current_function_has_inlines = 1;
     }
-  else
-    /* We may get here if we're the outer block of function A that was
-       inlined into function B that was inlined into function C.  When
-       generating debugging info for C, dwarf2out_abstract_function(B)
-       would mark all inlined blocks as abstract, including this one.
-       So, we wouldn't (and shouldn't) expect labels to be generated
-       for this one.  Instead, just emit debugging info for
-       declarations within the block.  This is particularly important
-       in the case of initializers of arguments passed from B to us:
-       if they're statement expressions containing declarations, we
-       wouldn't generate dies for their abstract variables, and then,
-       when generating dies for the real variables, we'd die (pun
-       intended :-)  */
-    gen_lexical_block_die (stmt, context_die, depth);
 }
 
 /* Generate a DIE for a field in a record, or structure.  */
@@ -14979,24 +18468,26 @@ gen_compile_unit_die (const char *filename)
 
   add_AT_string (die, DW_AT_producer, producer);
 
+  language = DW_LANG_C89;
   if (strcmp (language_string, "GNU C++") == 0)
     language = DW_LANG_C_plus_plus;
-  else if (strcmp (language_string, "GNU Ada") == 0)
-    language = DW_LANG_Ada95;
   else if (strcmp (language_string, "GNU F77") == 0)
     language = DW_LANG_Fortran77;
-  else if (strcmp (language_string, "GNU Fortran") == 0)
-    language = DW_LANG_Fortran95;
   else if (strcmp (language_string, "GNU Pascal") == 0)
     language = DW_LANG_Pascal83;
-  else if (strcmp (language_string, "GNU Java") == 0)
-    language = DW_LANG_Java;
-  else if (strcmp (language_string, "GNU Objective-C") == 0)
-    language = DW_LANG_ObjC;
-  else if (strcmp (language_string, "GNU Objective-C++") == 0)
-    language = DW_LANG_ObjC_plus_plus;
-  else
-    language = DW_LANG_C89;
+  else if (dwarf_version >= 3 || !dwarf_strict)
+    {
+      if (strcmp (language_string, "GNU Ada") == 0)
+       language = DW_LANG_Ada95;
+      else if (strcmp (language_string, "GNU Fortran") == 0)
+       language = DW_LANG_Fortran95;
+      else if (strcmp (language_string, "GNU Java") == 0)
+       language = DW_LANG_Java;
+      else if (strcmp (language_string, "GNU Objective-C") == 0)
+       language = DW_LANG_ObjC;
+      else if (strcmp (language_string, "GNU Objective-C++") == 0)
+       language = DW_LANG_ObjC_plus_plus;
+    }
 
   add_AT_unsigned (die, DW_AT_language, language);
   return die;
@@ -15129,6 +18620,11 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
   else
     remove_AT (type_die, DW_AT_declaration);
 
+  /* Generate child dies for template paramaters.  */
+  if (debug_info_level > DINFO_LEVEL_TERSE
+      && COMPLETE_TYPE_P (type))
+    gen_generic_params_dies (type);
+
   /* If this type has been completed, then give it a byte_size attribute and
      then give a list of members.  */
   if (complete && !ns_decl)
@@ -15261,7 +18757,7 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
          the type description DIE we want to generate.  */
       if (DECL_CONTEXT (TYPE_NAME (type))
          && TREE_CODE (DECL_CONTEXT (TYPE_NAME (type))) == NAMESPACE_DECL)
-       context_die = lookup_decl_die (DECL_CONTEXT (TYPE_NAME (type)));
+       context_die = get_context_die (DECL_CONTEXT (TYPE_NAME (type)));
 
       TREE_ASM_WRITTEN (type) = 1;
       gen_decl_die (TYPE_NAME (type), NULL, context_die);
@@ -15271,7 +18767,8 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
   /* If this is an array type with hidden descriptor, handle it first.  */
   if (!TREE_ASM_WRITTEN (type)
       && lang_hooks.types.get_array_descr_info
-      && lang_hooks.types.get_array_descr_info (type, &info))
+      && lang_hooks.types.get_array_descr_info (type, &info)
+      && (dwarf_version >= 3 || !dwarf_strict))
     {
       gen_descr_array_type_die (type, &info, context_die);
       TREE_ASM_WRITTEN (type) = 1;
@@ -15370,6 +18867,15 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
          context_die = lookup_type_die (TYPE_CONTEXT (type));
          need_pop = 1;
        }
+      else if (TYPE_CONTEXT (type) != NULL_TREE
+              && (TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL))
+       {
+         /* If this type is local to a function that hasn't been written
+            out yet, use a NULL context for now; it will be fixed up in
+            decls_for_scope.  */
+         context_die = lookup_decl_die (TYPE_CONTEXT (type));
+         need_pop = 0;
+       }
       else
        {
          context_die = declare_in_namespace (type, context_die);
@@ -15483,7 +18989,23 @@ gen_block_die (tree stmt, dw_die_ref context_die, int depth)
   if (must_output_die)
     {
       if (inlined_func)
-       gen_inlined_subroutine_die (stmt, context_die, depth);
+       {
+         /* If STMT block is abstract, that means we have been called
+            indirectly from dwarf2out_abstract_function.
+            That function rightfully marks the descendent blocks (of
+            the abstract function it is dealing with) as being abstract,
+            precisely to prevent us from emitting any
+            DW_TAG_inlined_subroutine DIE as a descendent
+            of an abstract function instance. So in that case, we should
+            not call gen_inlined_subroutine_die.
+
+            Later though, when cgraph asks dwarf2out to emit info
+            for the concrete instance of the function decl into which
+            the concrete instance of STMT got inlined, the later will lead
+            to the generation of a DW_TAG_inlined_subroutine DIE.  */
+         if (! BLOCK_ABSTRACT (stmt))
+           gen_inlined_subroutine_die (stmt, context_die, depth);
+       }
       else
        gen_lexical_block_die (stmt, context_die, depth);
     }
@@ -15584,7 +19106,7 @@ get_context_die (tree context)
     {
       /* Find die that represents this context.  */
       if (TYPE_P (context))
-       return force_type_die (context);
+       return force_type_die (TYPE_MAIN_VARIANT (context));
       else
        return force_decl_die (context);
     }
@@ -15630,7 +19152,11 @@ force_decl_die (tree decl)
          break;
 
        case NAMESPACE_DECL:
-         dwarf2out_decl (decl);
+         if (dwarf_version >= 3 || !dwarf_strict)
+           dwarf2out_decl (decl);
+         else
+           /* DWARF2 has neither DW_TAG_module, nor DW_TAG_namespace.  */
+           decl_die = comp_unit_die;
          break;
 
        default:
@@ -15733,7 +19259,11 @@ gen_namespace_die (tree decl, dw_die_ref context_die)
                               context_die, decl);
       /* For Fortran modules defined in different CU don't add src coords.  */
       if (namespace_die->die_tag == DW_TAG_module && DECL_EXTERNAL (decl))
-       add_name_attribute (namespace_die, dwarf2_name (decl, 0));
+       {
+         const char *name = dwarf2_name (decl, 0);
+         if (name)
+           add_name_attribute (namespace_die, name);
+       }
       else
        add_name_and_src_coords_attributes (namespace_die, decl);
       if (DECL_EXTERNAL (decl))
@@ -15893,9 +19423,7 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
 
       /* Output any DIEs that are needed to specify the type of this data
         object.  */
-      if ((TREE_CODE (decl_or_origin) == RESULT_DECL
-          || TREE_CODE (decl_or_origin) == VAR_DECL)
-          && DECL_BY_REFERENCE (decl_or_origin))
+      if (decl_by_reference_p (decl_or_origin))
        gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
       else
        gen_type_die (TREE_TYPE (decl_or_origin), context_die);
@@ -15915,7 +19443,9 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
       if (!origin)
         origin = decl_ultimate_origin (decl);
       if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
-       gen_formal_parameter_die (decl, origin, context_die);
+       gen_formal_parameter_die (decl, origin,
+                                 true /* Emit name attribute.  */,
+                                 context_die);
       else
        gen_variable_die (decl, origin, context_die);
       break;
@@ -15937,12 +19467,15 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
        gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
       else
        gen_type_die (TREE_TYPE (decl_or_origin), context_die);
-      gen_formal_parameter_die (decl, origin, context_die);
+      gen_formal_parameter_die (decl, origin,
+                               true /* Emit name attribute.  */,
+                               context_die);
       break;
 
     case NAMESPACE_DECL:
     case IMPORTED_DECL:
-      gen_namespace_die (decl, context_die);
+      if (dwarf_version >= 3 || !dwarf_strict)
+       gen_namespace_die (decl, context_die);
       break;
 
     default:
@@ -16040,9 +19573,14 @@ dwarf2out_imported_module_or_decl_1 (tree decl,
     }
 
   if (TREE_CODE (decl) == NAMESPACE_DECL)
-    imported_die = new_die (DW_TAG_imported_module,
-                           lexical_block_die,
-                           lexical_block);
+    {
+      if (dwarf_version >= 3 || !dwarf_strict)
+       imported_die = new_die (DW_TAG_imported_module,
+                               lexical_block_die,
+                               lexical_block);
+      else
+       return;
+    }
   else
     imported_die = new_die (DW_TAG_imported_declaration,
                            lexical_block_die,
@@ -16083,6 +19621,10 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
       && TYPE_P (context)
       && !should_emit_struct_debug (context, DINFO_USAGE_DIR_USE))
     return;
+
+  if (!(dwarf_version >= 3 || !dwarf_strict))
+    return;
+
   scope_die = get_context_die (context);
 
   if (child)
@@ -16359,30 +19901,207 @@ maybe_emit_file (struct dwarf_file_data * fd)
   return fd->emitted_number;
 }
 
+/* Schedule generation of a DW_AT_const_value attribute to DIE.
+   That generation should happen after function debug info has been
+   generated. The value of the attribute is the constant value of ARG.  */
+
+static void
+append_entry_to_tmpl_value_parm_die_table (dw_die_ref die, tree arg)
+{
+  die_arg_entry entry;
+
+  if (!die || !arg)
+    return;
+
+  if (!tmpl_value_parm_die_table)
+    tmpl_value_parm_die_table
+      = VEC_alloc (die_arg_entry, gc, 32);
+
+  entry.die = die;
+  entry.arg = arg;
+  VEC_safe_push (die_arg_entry, gc,
+                tmpl_value_parm_die_table,
+                &entry);
+}
+
+/* Add a DW_AT_const_value attribute to DIEs that were scheduled
+   by append_entry_to_tmpl_value_parm_die_table. This function must
+   be called after function DIEs have been generated.  */
+
+static void
+gen_remaining_tmpl_value_param_die_attribute (void)
+{
+  if (tmpl_value_parm_die_table)
+    {
+      unsigned i;
+      die_arg_entry *e;
+
+      for (i = 0;
+           VEC_iterate (die_arg_entry, tmpl_value_parm_die_table, i, e);
+           i++)
+       tree_add_const_value_attribute (e->die, e->arg);
+    }
+}
+
+
 /* Replace DW_AT_name for the decl with name.  */
+
 static void
 dwarf2out_set_name (tree decl, tree name)
 {
   dw_die_ref die;
   dw_attr_ref attr;
+  const char *dname;
 
   die = TYPE_SYMTAB_DIE (decl);
   if (!die)
     return;
 
+  dname = dwarf2_name (name, 0);
+  if (!dname)
+    return;
+
   attr = get_AT (die, DW_AT_name);
   if (attr)
     {
       struct indirect_string_node *node;
 
-      node = find_AT_string (dwarf2_name (name, 0));
+      node = find_AT_string (dname);
       /* replace the string.  */
       attr->dw_attr_val.v.val_str = node;
     }
 
   else
-    add_name_attribute (die, dwarf2_name (name, 0));
+    add_name_attribute (die, dname);
+}
+
+/* Called by the final INSN scan whenever we see a direct function call.
+   Make an entry into the direct call table, recording the point of call
+   and a reference to the target function's debug entry.  */
+
+static void
+dwarf2out_direct_call (tree targ)
+{
+  dcall_entry e;
+  tree origin = decl_ultimate_origin (targ);
+
+  /* If this is a clone, use the abstract origin as the target.  */
+  if (origin)
+    targ = origin;
+
+  e.poc_label_num = poc_label_num++;
+  e.poc_decl = current_function_decl;
+  e.targ_die = force_decl_die (targ);
+  VEC_safe_push (dcall_entry, gc, dcall_table, &e);
+
+  /* Drop a label at the return point to mark the point of call.  */
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LPOC", e.poc_label_num);
+}
+
+/* Returns a hash value for X (which really is a struct vcall_insn).  */
+
+static hashval_t
+vcall_insn_table_hash (const void *x)
+{
+  return (hashval_t) ((const struct vcall_insn *) x)->insn_uid;
+}
+
+/* Return nonzero if insn_uid of struct vcall_insn *X is the same as
+   insnd_uid of *Y.  */
+
+static int
+vcall_insn_table_eq (const void *x, const void *y)
+{
+  return (((const struct vcall_insn *) x)->insn_uid
+          == ((const struct vcall_insn *) y)->insn_uid);
+}
+
+/* Associate VTABLE_SLOT with INSN_UID in the VCALL_INSN_TABLE.  */
+
+static void
+store_vcall_insn (unsigned int vtable_slot, int insn_uid)
+{
+  struct vcall_insn *item = GGC_NEW (struct vcall_insn);
+  struct vcall_insn **slot;
+
+  gcc_assert (item);
+  item->insn_uid = insn_uid;
+  item->vtable_slot = vtable_slot;
+  slot = (struct vcall_insn **)
+      htab_find_slot_with_hash (vcall_insn_table, &item,
+                               (hashval_t) insn_uid, INSERT);
+  *slot = item;
+}
+
+/* Return the VTABLE_SLOT associated with INSN_UID.  */
+
+static unsigned int
+lookup_vcall_insn (unsigned int insn_uid)
+{
+  struct vcall_insn item;
+  struct vcall_insn *p;
+
+  item.insn_uid = insn_uid;
+  item.vtable_slot = 0;
+  p = (struct vcall_insn *) htab_find_with_hash (vcall_insn_table,
+                                                 (void *) &item,
+                                                 (hashval_t) insn_uid);
+  if (p == NULL)
+    return (unsigned int) -1;
+  return p->vtable_slot;
+}
+
+
+/* Called when lowering indirect calls to RTL.  We make a note of INSN_UID
+   and the OBJ_TYPE_REF_TOKEN from ADDR.  For C++ virtual calls, the token
+   is the vtable slot index that we will need to put in the virtual call
+   table later.  */
+
+static void
+dwarf2out_virtual_call_token (tree addr, int insn_uid)
+{
+  if (is_cxx() && TREE_CODE (addr) == OBJ_TYPE_REF)
+    {
+      tree token = OBJ_TYPE_REF_TOKEN (addr);
+      if (TREE_CODE (token) == INTEGER_CST)
+        store_vcall_insn (TREE_INT_CST_LOW (token), insn_uid);
+    }
+}
+
+/* Called when scheduling RTL, when a CALL_INSN is split.  Copies the
+   OBJ_TYPE_REF_TOKEN previously associated with OLD_INSN and associates it
+   with NEW_INSN.  */
+
+static void
+dwarf2out_copy_call_info (rtx old_insn, rtx new_insn)
+{
+  unsigned int vtable_slot = lookup_vcall_insn (INSN_UID (old_insn));
+
+  if (vtable_slot != (unsigned int) -1)
+    store_vcall_insn (vtable_slot, INSN_UID (new_insn));
+}
+
+/* Called by the final INSN scan whenever we see a virtual function call.
+   Make an entry into the virtual call table, recording the point of call
+   and the slot index of the vtable entry used to call the virtual member
+   function.  The slot index was associated with the INSN_UID during the
+   lowering to RTL.  */
+
+static void
+dwarf2out_virtual_call (int insn_uid)
+{
+  unsigned int vtable_slot = lookup_vcall_insn (insn_uid);
+  vcall_entry e;
+
+  if (vtable_slot == (unsigned int) -1)
+    return;
+
+  e.poc_label_num = poc_label_num++;
+  e.vtable_slot = vtable_slot;
+  VEC_safe_push (vcall_entry, gc, vcall_table, &e);
+
+  /* Drop a label at the return point to mark the point of call.  */
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LPOC", e.poc_label_num);
 }
 
 /* Called by the final INSN scan whenever we see a var location.  We
@@ -16392,10 +20111,11 @@ dwarf2out_set_name (tree decl, tree name)
 static void
 dwarf2out_var_location (rtx loc_note)
 {
-  char loclabel[MAX_ARTIFICIAL_LABEL_BYTES];
+  char loclabel[MAX_ARTIFICIAL_LABEL_BYTES + 2];
   struct var_loc_node *newloc;
   rtx next_real;
   static const char *last_label;
+  static const char *last_postcall_label;
   static bool last_in_cold_section_p;
   tree decl;
 
@@ -16411,27 +20131,37 @@ dwarf2out_var_location (rtx loc_note)
   newloc = GGC_CNEW (struct var_loc_node);
   /* If there were no real insns between note we processed last time
      and this note, use the label we emitted last time.  */
-  if (last_var_location_insn != NULL_RTX
-      && last_var_location_insn == next_real
-      && last_in_cold_section_p == in_cold_section_p)
-    newloc->label = last_label;
-  else
+  if (last_var_location_insn == NULL_RTX
+      || last_var_location_insn != next_real
+      || last_in_cold_section_p != in_cold_section_p)
     {
       ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num);
       ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num);
       loclabel_num++;
-      newloc->label = ggc_strdup (loclabel);
+      last_label = ggc_strdup (loclabel);
+      last_postcall_label = NULL;
     }
   newloc->var_loc_note = loc_note;
   newloc->next = NULL;
 
+  if (!NOTE_DURING_CALL_P (loc_note))
+    newloc->label = last_label;
+  else
+    {
+      if (!last_postcall_label)
+       {
+         sprintf (loclabel, "%s-1", last_label);
+         last_postcall_label = ggc_strdup (loclabel);
+       }
+      newloc->label = last_postcall_label;
+    }
+
   if (cfun && in_cold_section_p)
     newloc->section_label = crtl->subsections.cold_section_label;
   else
     newloc->section_label = text_section_label;
 
   last_var_location_insn = next_real;
-  last_label = newloc->label;
   last_in_cold_section_p = in_cold_section_p;
   decl = NOTE_VAR_LOCATION_DECL (loc_note);
   add_var_loc_to_decl (decl, newloc);
@@ -16552,7 +20282,7 @@ dwarf2out_source_line (unsigned int line, const char *filename,
 static void
 dwarf2out_start_source_file (unsigned int lineno, const char *filename)
 {
-  if (flag_eliminate_dwarf2_dups)
+  if (flag_eliminate_dwarf2_dups && dwarf_version < 4)
     {
       /* Record the beginning of the file for break_out_includes.  */
       dw_die_ref bincl_die;
@@ -16579,7 +20309,7 @@ dwarf2out_start_source_file (unsigned int lineno, const char *filename)
 static void
 dwarf2out_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED)
 {
-  if (flag_eliminate_dwarf2_dups)
+  if (flag_eliminate_dwarf2_dups && dwarf_version < 4)
     /* Record the end of the file for break_out_includes.  */
     new_die (DW_TAG_GNU_EINCL, comp_unit_die, NULL);
 
@@ -16661,6 +20391,10 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
   pubname_table = VEC_alloc (pubname_entry, gc, 32);
   pubtype_table = VEC_alloc (pubname_entry, gc, 32);
 
+  /* Allocate the table that maps insn UIDs to vtable slot indexes.  */
+  vcall_insn_table = htab_create_ggc (10, vcall_insn_table_hash,
+                                      vcall_insn_table_eq, NULL);
+
   /* Generate the initial DIE for the .debug section.  Note that the (string)
      value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE
      will (typically) be a relative pathname and that this pathname should be
@@ -16689,6 +20423,10 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
                                        SECTION_DEBUG, NULL);
   debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
                                        SECTION_DEBUG, NULL);
+  debug_dcall_section = get_section (DEBUG_DCALL_SECTION,
+                                    SECTION_DEBUG, NULL);
+  debug_vcall_section = get_section (DEBUG_VCALL_SECTION,
+                                    SECTION_DEBUG, NULL);
   debug_str_section = get_section (DEBUG_STR_SECTION,
                                   DEBUG_STR_SECTION_FLAGS, NULL);
   debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
@@ -16733,17 +20471,33 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
       switch_to_section (cold_text_section);
       ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label);
     }
+
+}
+
+/* Called before cgraph_optimize starts outputtting functions, variables
+   and toplevel asms into assembly.  */
+
+static void
+dwarf2out_assembly_start (void)
+{
+  if (HAVE_GAS_CFI_SECTIONS_DIRECTIVE && dwarf2out_do_cfi_asm ())
+    {
+#ifndef TARGET_UNWIND_INFO
+      if (USING_SJLJ_EXCEPTIONS || (!flag_unwind_tables && !flag_exceptions))
+#endif
+       fprintf (asm_out_file, "\t.cfi_sections\t.debug_frame\n");
+    }
 }
 
 /* A helper function for dwarf2out_finish called through
-   ht_forall.  Emit one queued .debug_str string.  */
+   htab_traverse.  Emit one queued .debug_str string.  */
 
 static int
 output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
 {
   struct indirect_string_node *node = (struct indirect_string_node *) *h;
 
-  if (node->form == DW_FORM_strp)
+  if (node->label && node->refcount)
     {
       switch_to_section (debug_str_section);
       ASM_OUTPUT_LABEL (asm_out_file, node->label);
@@ -16793,8 +20547,12 @@ prune_unused_types_walk_attribs (dw_die_ref die)
       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);
+            Make sure that it will get emitted.
+            If it was broken out into a comdat group, don't follow it.  */
+          if (dwarf_version < 4
+              || a->dw_attr == DW_AT_specification
+              || a->dw_attr_val.v.val_die_ref.die->die_id.die_type_node == NULL)
+           prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
        }
       /* Set the string's refcount to 0 so that prune_unused_types_mark
         accounts properly for it.  */
@@ -16838,8 +20596,12 @@ prune_unused_types_mark (dw_die_ref die, int dokids)
       die->die_mark = 2;
 
       /* 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)
+        kids get marked, even if they're types.  If we're
+        breaking out types into comdat sections, do this
+        for all type definitions.  */
+      if (die->die_tag == DW_TAG_array_type
+          || (dwarf_version >= 4
+              && is_type_die (die) && ! is_declaration_die (die)))
        FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1));
       else
        FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
@@ -17021,6 +20783,20 @@ prune_unused_types_prune (dw_die_ref die)
   } while (c != die->die_child);
 }
 
+/* A helper function for dwarf2out_finish called through
+   htab_traverse.  Clear .debug_str strings that we haven't already
+   decided to emit.  */
+
+static int
+prune_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
+{
+  struct indirect_string_node *node = (struct indirect_string_node *) *h;
+
+  if (!node->label || !node->refcount)
+    htab_clear_slot (debug_str_hash, h);
+
+  return 1;
+}
 
 /* Remove dies representing declarations that we never use.  */
 
@@ -17029,19 +20805,31 @@ prune_unused_types (void)
 {
   unsigned int i;
   limbo_die_node *node;
+  comdat_type_node *ctnode;
   pubname_ref pub;
+  dcall_entry *dcall;
 
 #if ENABLE_ASSERT_CHECKING
   /* All the marks should already be clear.  */
   verify_marks_clear (comp_unit_die);
   for (node = limbo_die_list; node; node = node->next)
     verify_marks_clear (node->die);
+  for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+    verify_marks_clear (ctnode->root_die);
 #endif /* ENABLE_ASSERT_CHECKING */
 
+  /* Mark types that are used in global variables.  */
+  premark_types_used_by_global_vars ();
+
   /* 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);
+  for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+    {
+      prune_unused_types_walk (ctnode->root_die);
+      prune_unused_types_mark (ctnode->type_die, 1);
+    }
 
   /* Also set the mark on nodes referenced from the
      pubname_table or arange_table.  */
@@ -17050,17 +20838,27 @@ prune_unused_types (void)
   for (i = 0; i < arange_table_in_use; i++)
     prune_unused_types_mark (arange_table[i], 1);
 
+  /* Mark nodes referenced from the direct call table.  */
+  for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, dcall); i++)
+    prune_unused_types_mark (dcall->targ_die, 1);
+
   /* Get rid of nodes that aren't marked; and update the string counts.  */
-  if (debug_str_hash)
+  if (debug_str_hash && debug_str_hash_forced)
+    htab_traverse (debug_str_hash, prune_indirect_string, NULL);
+  else if (debug_str_hash)
     htab_empty (debug_str_hash);
   prune_unused_types_prune (comp_unit_die);
   for (node = limbo_die_list; node; node = node->next)
     prune_unused_types_prune (node->die);
+  for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+    prune_unused_types_prune (ctnode->root_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);
+  for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+    prune_unmark_dies (ctnode->root_die);
 }
 
 /* Set the parameter to true if there are any relative pathnames in
@@ -17078,6 +20876,28 @@ file_table_relative_p (void ** slot, void *param)
   return 1;
 }
 
+/* Routines to manipulate hash table of comdat type units.  */
+
+static hashval_t
+htab_ct_hash (const void *of)
+{
+  hashval_t h;
+  const comdat_type_node *const type_node = (const comdat_type_node *) of;
+
+  memcpy (&h, type_node->signature, sizeof (h));
+  return h;
+}
+
+static int
+htab_ct_eq (const void *of1, const void *of2)
+{
+  const comdat_type_node *const type_node_1 = (const comdat_type_node *) of1;
+  const comdat_type_node *const type_node_2 = (const comdat_type_node *) of2;
+
+  return (! memcmp (type_node_1->signature, type_node_2->signature,
+                    DWARF_TYPE_SIGNATURE_SIZE));
+}
+
 /* Move a DW_AT_MIPS_linkage_name attribute just added to dw_die_ref
    to the location it would have been added, should we know its
    DECL_ASSEMBLER_NAME when we added other attributes.  This will
@@ -17108,6 +20928,124 @@ move_linkage_attr (dw_die_ref die)
     }
 }
 
+/* Helper function for resolve_addr, attempt to resolve
+   one CONST_STRING, return non-zero if not successful.  Similarly verify that
+   SYMBOL_REFs refer to variables emitted in the current CU.  */
+
+static int
+resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED)
+{
+  rtx rtl = *addr;
+
+  if (GET_CODE (rtl) == CONST_STRING)
+    {
+      size_t len = strlen (XSTR (rtl, 0)) + 1;
+      tree t = build_string (len, XSTR (rtl, 0));
+      tree tlen = build_int_cst (NULL_TREE, len - 1);
+      TREE_TYPE (t)
+       = build_array_type (char_type_node, build_index_type (tlen));
+      rtl = lookup_constant_def (t);
+      if (!rtl || !MEM_P (rtl))
+       return 1;
+      rtl = XEXP (rtl, 0);
+      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+      *addr = rtl;
+      return 0;
+    }
+
+  if (GET_CODE (rtl) == SYMBOL_REF
+      && SYMBOL_REF_DECL (rtl)
+      && TREE_CODE (SYMBOL_REF_DECL (rtl)) == VAR_DECL
+      && !TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl)))
+    return 1;
+
+  if (GET_CODE (rtl) == CONST
+      && for_each_rtx (&XEXP (rtl, 0), resolve_one_addr, NULL))
+    return 1;
+
+  return 0;
+}
+
+/* Helper function for resolve_addr, handle one location
+   expression, return false if at least one CONST_STRING or SYMBOL_REF in
+   the location list couldn't be resolved.  */
+
+static bool
+resolve_addr_in_expr (dw_loc_descr_ref loc)
+{
+  for (; loc; loc = loc->dw_loc_next)
+    if ((loc->dw_loc_opc == DW_OP_addr
+        && resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
+       || (loc->dw_loc_opc == DW_OP_implicit_value
+           && loc->dw_loc_oprnd2.val_class == dw_val_class_addr
+           && resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr, NULL)))
+      return false;
+  return true;
+}
+
+/* Resolve DW_OP_addr and DW_AT_const_value CONST_STRING arguments to
+   an address in .rodata section if the string literal is emitted there,
+   or remove the containing location list or replace DW_AT_const_value
+   with DW_AT_location and empty location expression, if it isn't found
+   in .rodata.  Similarly for SYMBOL_REFs, keep only those that refer
+   to something that has been emitted in the current CU.  */
+
+static void
+resolve_addr (dw_die_ref die)
+{
+  dw_die_ref c;
+  dw_attr_ref a;
+  dw_loc_list_ref *curr;
+  unsigned ix;
+
+  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+    switch (AT_class (a))
+      {
+      case dw_val_class_loc_list:
+       curr = AT_loc_list_ptr (a);
+       while (*curr)
+         {
+           if (!resolve_addr_in_expr ((*curr)->expr))
+             {
+               dw_loc_list_ref next = (*curr)->dw_loc_next;
+               if (next && (*curr)->ll_symbol)
+                 {
+                   gcc_assert (!next->ll_symbol);
+                   next->ll_symbol = (*curr)->ll_symbol;
+                 }
+               *curr = next;
+             }
+           else
+             curr = &(*curr)->dw_loc_next;
+         }
+       if (!AT_loc_list (a))
+         {
+           remove_AT (die, a->dw_attr);
+           ix--;
+         }
+       break;
+      case dw_val_class_loc:
+       if (!resolve_addr_in_expr (AT_loc (a)))
+         {
+           remove_AT (die, a->dw_attr);
+           ix--;
+         }
+       break;
+      case dw_val_class_addr:
+       if (a->dw_attr == DW_AT_const_value
+           && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL))
+         {
+           remove_AT (die, a->dw_attr);
+           ix--;
+         }
+       break;
+      default:
+       break;
+      }
+
+  FOR_EACH_CHILD (die, c, resolve_addr (c));
+}
+
 /* Output stuff that dwarf requires at the end of every file,
    and generate the DWARF-2 debugging info.  */
 
@@ -17115,9 +21053,13 @@ static void
 dwarf2out_finish (const char *filename)
 {
   limbo_die_node *node, *next_node;
+  comdat_type_node *ctnode;
+  htab_t comdat_type_table;
   dw_die_ref die = 0;
   unsigned int i;
 
+  gen_remaining_tmpl_value_param_die_attribute ();
+
   /* Add the name for the main input file now.  We delayed this from
      dwarf2out_init to avoid complications with PCH.  */
   add_name_attribute (comp_unit_die, remap_debug_filename (filename));
@@ -17196,6 +21138,8 @@ dwarf2out_finish (const char *filename)
 
   limbo_die_list = NULL;
 
+  resolve_addr (comp_unit_die);
+
   for (node = deferred_asm_name; node; node = node->next)
     {
       tree decl = node->created_for;
@@ -17218,14 +21162,39 @@ dwarf2out_finish (const char *filename)
 
   /* Generate separate CUs for each of the include files we've seen.
      They will go into limbo_die_list.  */
-  if (flag_eliminate_dwarf2_dups)
+  if (flag_eliminate_dwarf2_dups && dwarf_version < 4)
     break_out_includes (comp_unit_die);
 
+  /* Generate separate COMDAT sections for type DIEs. */
+  if (dwarf_version >= 4)
+    {
+      break_out_comdat_types (comp_unit_die);
+
+      /* Each new type_unit DIE was added to the limbo die list when created.
+         Since these have all been added to comdat_type_list, clear the
+         limbo die list.  */
+      limbo_die_list = NULL;
+
+      /* For each new comdat type unit, copy declarations for incomplete
+         types to make the new unit self-contained (i.e., no direct
+         references to the main compile unit).  */
+      for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
+        copy_decls_for_unworthy_types (ctnode->root_die);
+      copy_decls_for_unworthy_types (comp_unit_die);
+
+      /* In the process of copying declarations from one unit to another,
+         we may have left some declarations behind that are no longer
+         referenced.  Prune them.  */
+      prune_unused_types ();
+    }
+
   /* Traverse the DIE's and add add sibling attributes to those DIE's
      that have children.  */
   add_sibling_attributes (comp_unit_die);
   for (node = limbo_die_list; node; node = node->next)
     add_sibling_attributes (node->die);
+  for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
+    add_sibling_attributes (ctnode->root_die);
 
   /* Output a terminator label for the .text section.  */
   switch_to_section (text_section);
@@ -17238,7 +21207,8 @@ dwarf2out_finish (const char *filename)
 
   /* We can only use the low/high_pc attributes if all of the code was
      in .text.  */
-  if (!have_multiple_function_sections)
+  if (!have_multiple_function_sections
+      || !(dwarf_version >= 3 || !dwarf_strict))
     {
       add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, text_section_label);
       add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);
@@ -17247,6 +21217,7 @@ dwarf2out_finish (const char *filename)
   else
     {
       unsigned fde_idx = 0;
+      bool range_list_added = false;
 
       /* We need to give .debug_loc and .debug_ranges an appropriate
         "base address".  Use zero so that these addresses become
@@ -17256,12 +21227,12 @@ dwarf2out_finish (const char *filename)
       add_AT_addr (comp_unit_die, DW_AT_low_pc, const0_rtx);
       add_AT_addr (comp_unit_die, DW_AT_entry_pc, const0_rtx);
 
-      add_AT_range_list (comp_unit_die, DW_AT_ranges,
-                        add_ranges_by_labels (text_section_label,
-                                              text_end_label));
-      if (flag_reorder_blocks_and_partition)
-       add_ranges_by_labels (cold_text_section_label,
-                             cold_end_label);
+      if (text_section_used)
+       add_ranges_by_labels (comp_unit_die, text_section_label,
+                             text_end_label, &range_list_added);
+      if (flag_reorder_blocks_and_partition && cold_text_section_used)
+       add_ranges_by_labels (comp_unit_die, cold_text_section_label,
+                             cold_end_label, &range_list_added);
 
       for (fde_idx = 0; fde_idx < fde_table_in_use; fde_idx++)
        {
@@ -17270,18 +21241,23 @@ dwarf2out_finish (const char *filename)
          if (fde->dw_fde_switched_sections)
            {
              if (!fde->in_std_section)
-               add_ranges_by_labels (fde->dw_fde_hot_section_label,
-                                     fde->dw_fde_hot_section_end_label);
+               add_ranges_by_labels (comp_unit_die,
+                                     fde->dw_fde_hot_section_label,
+                                     fde->dw_fde_hot_section_end_label,
+                                     &range_list_added);
              if (!fde->cold_in_std_section)
-               add_ranges_by_labels (fde->dw_fde_unlikely_section_label,
-                                     fde->dw_fde_unlikely_section_end_label);
+               add_ranges_by_labels (comp_unit_die,
+                                     fde->dw_fde_unlikely_section_label,
+                                     fde->dw_fde_unlikely_section_end_label,
+                                     &range_list_added);
            }
          else if (!fde->in_std_section)
-           add_ranges_by_labels (fde->dw_fde_begin,
-                                 fde->dw_fde_end);
+           add_ranges_by_labels (comp_unit_die, fde->dw_fde_begin,
+                                 fde->dw_fde_end, &range_list_added);
        }
 
-      add_ranges (NULL);
+      if (range_list_added)
+       add_ranges (NULL);
     }
 
   /* Output location list section if necessary.  */
@@ -17307,6 +21283,27 @@ dwarf2out_finish (const char *filename)
   for (node = limbo_die_list; node; node = node->next)
     output_comp_unit (node->die, 0);
 
+  comdat_type_table = htab_create (100, htab_ct_hash, htab_ct_eq, NULL);
+  for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
+    {
+      void **slot = htab_find_slot (comdat_type_table, ctnode, INSERT);
+
+      /* Don't output duplicate types.  */
+      if (*slot != HTAB_EMPTY_ENTRY)
+        continue;
+
+      /* Add a pointer to the line table for the main compilation unit
+         so that the debugger can make sense of DW_AT_decl_file
+         attributes.  */
+      if (debug_info_level >= DINFO_LEVEL_NORMAL)
+        add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
+                       debug_line_section_label);
+
+      output_comdat_type_unit (ctnode);
+      *slot = ctnode;
+    }
+  htab_delete (comdat_type_table);
+
   /* Output the main compilation unit if non-empty or if .debug_macinfo
      has been emitted.  */
   output_comp_unit (comp_unit_die, debug_info_level >= DINFO_LEVEL_VERBOSE);
@@ -17332,6 +21329,18 @@ dwarf2out_finish (const char *filename)
       output_pubnames (pubtype_table);
     }
 
+  /* Output direct and virtual call tables if necessary.  */
+  if (!VEC_empty (dcall_entry, dcall_table))
+    {
+      switch_to_section (debug_dcall_section);
+      output_dcall_table ();
+    }
+  if (!VEC_empty (vcall_entry, vcall_table))
+    {
+      switch_to_section (debug_vcall_section);
+      output_vcall_table ();
+    }
+
   /* Output the address range information.  We only put functions in the arange
      table, so don't write it out if we don't have any.  */
   if (fde_table_in_use)
@@ -17379,6 +21388,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
 {
   0,           /* init */
   0,           /* finish */
+  0,           /* assembly_start */
   0,           /* define */
   0,           /* undef */
   0,           /* start_source_file */
@@ -17402,6 +21412,10 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   0,           /* handle_pch */
   0,           /* var_location */
   0,           /* switch_text_section */
+  0,           /* direct_call */
+  0,           /* virtual_call_token */
+  0,           /* copy_call_info */
+  0,           /* virtual_call */
   0,           /* set_name */
   0            /* start_end_main_source_file */
 };