OSDN Git Service

PR debug/42278
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index 0dfe4f6..467bb26 100644 (file)
@@ -1,6 +1,7 @@
 /* Output Dwarf2 format symbol table information from GCC.
    Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
    Contributed by Gary Funck (gary@intrepid.com).
    Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
    Extensively modified by Jason Merrill (jason@cygnus.com).
@@ -78,7 +79,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "dwarf2out.h"
 #include "dwarf2asm.h"
 #include "toplev.h"
-#include "varray.h"
 #include "ggc.h"
 #include "md5.h"
 #include "tm_p.h"
@@ -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);
@@ -163,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;
@@ -177,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;
 }
@@ -212,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 ";#"
@@ -332,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
@@ -407,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;
 
@@ -442,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 *);
@@ -778,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);
     }
@@ -1013,10 +1039,10 @@ def_cfa_1 (const char *label, dw_cfa_location *loc_p)
 
   cfi = new_cfi ();
 
-  if (loc.reg == old_cfa.reg && !loc.indirect)
+  if (loc.reg == old_cfa.reg && !loc.indirect && !old_cfa.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)
@@ -1029,7 +1055,8 @@ def_cfa_1 (const char *label, dw_cfa_location *loc_p)
 #ifndef MIPS_DEBUGGING_INFO  /* SGI dbx thinks this means no offset.  */
   else if (loc.offset == old_cfa.offset
           && old_cfa.reg != INVALID_REGNUM
-          && !loc.indirect)
+          && !loc.indirect
+          && !old_cfa.indirect)
     {
       /* Construct a "DW_CFA_def_cfa_register <register>" instruction,
         indicating the CFA register has changed to <register> but the
@@ -1088,8 +1115,8 @@ reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT
       && sreg == INVALID_REGNUM)
     {
       cfi->dw_cfi_opc = DW_CFA_expression;
-      cfi->dw_cfi_oprnd2.dw_cfi_reg_num = reg;
-      cfi->dw_cfi_oprnd1.dw_cfi_loc
+      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+      cfi->dw_cfi_oprnd2.dw_cfi_loc
        = build_cfa_aligned_loc (offset, fde->stack_realignment);
     }
   else if (sreg == INVALID_REGNUM)
@@ -1129,25 +1156,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.  */
 
@@ -1498,13 +1506,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;
@@ -1588,31 +1641,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
@@ -1857,7 +1886,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))
     {
@@ -2131,15 +2160,7 @@ dwarf2out_frame_debug_cfa_restore (rtx reg, const char *label)
                && cfa.indirect == 0
                && cfa.reg != HARD_FRAME_POINTER_REGNUM
   effects: Use DW_CFA_def_cfa_expression to define cfa
-          cfa.reg == fde->drap_reg
-
-  Rule 20:
-  (set reg fde->drap_reg)
-  constraints: fde->vdrap_reg == INVALID_REGNUM
-  effects: fde->vdrap_reg = reg.
-  (set mem fde->drap_reg)
-  constraints: fde->drap_reg_saved == 1
-  effects: none.  */
+          cfa.reg == fde->drap_reg  */
 
 static void
 dwarf2out_frame_debug_expr (rtx expr, const char *label)
@@ -2190,7 +2211,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;
@@ -2210,24 +2231,6 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
 
   fde = current_fde ();
 
-  if (REG_P (src)
-      && fde
-      && fde->drap_reg == REGNO (src)
-      && (fde->drap_reg_saved
-         || REG_P (dest)))
-    {
-      /* Rule 20 */
-      /* If we are saving dynamic realign argument pointer to a
-        register, the destination is virtual dynamic realign
-        argument pointer.  It may be used to access argument.  */
-      if (REG_P (dest))
-       {
-         gcc_assert (fde->vdrap_reg == INVALID_REGNUM);
-         fde->vdrap_reg = REGNO (dest);
-       }
-      return;
-    }
-
   switch (GET_CODE (dest))
     {
     case REG:
@@ -2683,10 +2686,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;
     }
 
@@ -2749,6 +2755,21 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
        handled_one = true;
        break;
 
+      case REG_CFA_SET_VDRAP:
+       n = XEXP (note, 0);
+       if (REG_P (n))
+         {
+           dw_fde_ref fde = current_fde ();
+           if (fde)
+             {
+               gcc_assert (fde->vdrap_reg == INVALID_REGNUM);
+               if (REG_P (n))
+                 fde->vdrap_reg = REGNO (n);
+             }
+         }
+       handled_one = true;
+       break;
+
       default:
        break;
       }
@@ -2844,7 +2865,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;
@@ -2890,6 +2911,7 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
     case DW_CFA_same_value:
     case DW_CFA_def_cfa_register:
     case DW_CFA_register:
+    case DW_CFA_expression:
       return dw_cfi_oprnd_reg_num;
 
     case DW_CFA_def_cfa_offset:
@@ -2898,7 +2920,6 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
       return dw_cfi_oprnd_offset;
 
     case DW_CFA_def_cfa_expression:
-    case DW_CFA_expression:
       return dw_cfi_oprnd_loc;
 
     default:
@@ -2925,6 +2946,9 @@ dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
     case DW_CFA_register:
       return dw_cfi_oprnd_reg_num;
 
+    case DW_CFA_expression:
+      return dw_cfi_oprnd_loc;
+
     default:
       return dw_cfi_oprnd_unused;
     }
@@ -3027,7 +3051,7 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
     {
       r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
       dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
-                          "DW_CFA_offset, column 0x%lx", r);
+                          "DW_CFA_offset, column %#lx", r);
       off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
       dw2_asm_output_data_uleb128 (off, NULL);
     }
@@ -3035,7 +3059,7 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
     {
       r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
       dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
-                          "DW_CFA_restore, column 0x%lx", r);
+                          "DW_CFA_restore, column %#lx", r);
     }
   else
     {
@@ -3227,7 +3251,7 @@ output_cfi_directive (dw_cfi_ref cfi)
       break;
 
     case DW_CFA_GNU_args_size:
-      fprintf (asm_out_file, "\t.cfi_escape 0x%x,", DW_CFA_GNU_args_size);
+      fprintf (asm_out_file, "\t.cfi_escape %#x,", DW_CFA_GNU_args_size);
       dw2_asm_output_data_uleb128_raw (cfi->dw_cfi_oprnd1.dw_cfi_offset);
       if (flag_debug_asm)
        fprintf (asm_out_file, "\t%s args_size "HOST_WIDE_INT_PRINT_DEC,
@@ -3241,7 +3265,7 @@ output_cfi_directive (dw_cfi_ref cfi)
 
     case DW_CFA_def_cfa_expression:
     case DW_CFA_expression:
-      fprintf (asm_out_file, "\t.cfi_escape 0x%x,", cfi->dw_cfi_opc);
+      fprintf (asm_out_file, "\t.cfi_escape %#x,", cfi->dw_cfi_opc);
       output_cfa_loc_raw (cfi);
       fputc ('\n', asm_out_file);
       break;
@@ -3595,6 +3619,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.  */
@@ -3680,6 +3705,8 @@ output_call_frame_info (int for_eh)
 
   augmentation[0] = 0;
   augmentation_size = 0;
+
+  personality = current_unit_personality;
   if (for_eh)
     {
       char *p;
@@ -3699,11 +3726,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)
        {
@@ -3722,7 +3749,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 */
@@ -3744,6 +3771,11 @@ output_call_frame_info (int for_eh)
     }
 
   dw2_asm_output_nstring (augmentation, -1, "CIE Augmentation");
+  if (dw_cie_version >= 4)
+    {
+      dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "CIE Address Size");
+      dw2_asm_output_data (1, 0, "CIE Segment Size");
+    }
   dw2_asm_output_data_uleb128 (1, "CIE Code Alignment Factor");
   dw2_asm_output_data_sleb128 (DWARF_CIE_DATA_ALIGNMENT,
                               "CIE Data Alignment Factor");
@@ -3756,12 +3788,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);
        }
 
@@ -3820,13 +3852,14 @@ 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
@@ -3835,7 +3868,7 @@ dwarf2out_do_cfi_startproc (bool second)
       if (enc & DW_EH_PE_indirect)
        ref = dw2_force_const_mem (ref, true);
 
-      fprintf (asm_out_file, "\t.cfi_personality 0x%x,", enc);
+      fprintf (asm_out_file, "\t.cfi_personality %#x,", enc);
       output_addr_const (asm_out_file, ref);
       fputc ('\n', asm_out_file);
     }
@@ -3853,7 +3886,7 @@ dwarf2out_do_cfi_startproc (bool second)
       if (enc & DW_EH_PE_indirect)
        ref = dw2_force_const_mem (ref, true);
 
-      fprintf (asm_out_file, "\t.cfi_lsda 0x%x,", enc);
+      fprintf (asm_out_file, "\t.cfi_lsda %#x,", enc);
       output_addr_const (asm_out_file, ref);
       fputc ('\n', asm_out_file);
     }
@@ -3965,6 +3998,20 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
 
   if (dwarf2out_do_cfi_asm ())
     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
@@ -4117,6 +4164,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.  */
@@ -4130,7 +4180,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,
@@ -4139,18 +4189,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 {
@@ -4173,7 +4215,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
        {
@@ -4185,6 +4227,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;
 }
@@ -4528,6 +4571,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:
@@ -4634,6 +4681,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
@@ -4738,6 +4797,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;
     }
@@ -4773,6 +4836,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
@@ -4794,7 +4861,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:
@@ -4808,6 +4875,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:
@@ -4817,6 +4938,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
@@ -4948,6 +5070,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 ();
 
@@ -4974,7 +5097,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;
@@ -5057,7 +5180,7 @@ output_loc_sequence_raw (dw_loc_descr_ref loc)
   while (1)
     {
       /* Output the opcode.  */
-      fprintf (asm_out_file, "0x%x", loc->dw_loc_opc);
+      fprintf (asm_out_file, "%#x", loc->dw_loc_opc);
       output_loc_operands_raw (loc);
 
       if (!loc->dw_loc_next)
@@ -5078,10 +5201,14 @@ output_cfa_loc (dw_cfi_ref cfi)
   unsigned long size;
 
   if (cfi->dw_cfi_opc == DW_CFA_expression)
-    dw2_asm_output_data (1, cfi->dw_cfi_oprnd2.dw_cfi_reg_num, NULL);
+    {
+      dw2_asm_output_data (1, cfi->dw_cfi_oprnd1.dw_cfi_reg_num, NULL);
+      loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
+    }
+  else
+    loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
 
   /* Output the size of the block.  */
-  loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
   size = size_of_locs (loc);
   dw2_asm_output_data_uleb128 (size, NULL);
 
@@ -5098,10 +5225,14 @@ output_cfa_loc_raw (dw_cfi_ref cfi)
   unsigned long size;
 
   if (cfi->dw_cfi_opc == DW_CFA_expression)
-    fprintf (asm_out_file, "0x%x,", cfi->dw_cfi_oprnd2.dw_cfi_reg_num);
+    {
+      fprintf (asm_out_file, "%#x,", cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+      loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
+    }
+  else
+    loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
 
   /* Output the size of the block.  */
-  loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
   size = size_of_locs (loc);
   dw2_asm_output_data_uleb128_raw (size);
   fputc (',', asm_out_file);
@@ -5279,10 +5410,12 @@ 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 *);
 static void dwarf2out_end_source_file (unsigned);
+static void dwarf2out_function_decl (tree);
 static void dwarf2out_begin_block (unsigned, unsigned);
 static void dwarf2out_end_block (unsigned, unsigned);
 static bool dwarf2out_ignore_block (const_tree);
@@ -5293,6 +5426,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);
 
@@ -5302,6 +5439,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
 {
   dwarf2out_init,
   dwarf2out_finish,
+  dwarf2out_assembly_start,
   dwarf2out_define,
   dwarf2out_undef,
   dwarf2out_start_source_file,
@@ -5315,7 +5453,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   dwarf2out_end_epilogue,
   dwarf2out_begin_function,
   debug_nothing_int,           /* end_function */
-  dwarf2out_decl,              /* function_decl */
+  dwarf2out_function_decl,     /* function_decl */
   dwarf2out_global_decl,
   dwarf2out_type_decl,         /* type_decl */
   dwarf2out_imported_module_or_decl,
@@ -5328,6 +5466,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 */
 };
@@ -5355,6 +5497,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
@@ -5395,7 +5538,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;
@@ -5441,6 +5589,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;
@@ -5449,6 +5607,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 ";#"
@@ -5482,6 +5648,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)
 
@@ -5523,6 +5694,11 @@ limbo_die_node;
    is not made available by the GCC front-end.  */
 #define        DWARF_LINE_DEFAULT_IS_STMT_START 1
 
+/* Maximum number of operations per instruction bundle.  */
+#ifndef DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN
+#define DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN 1
+#endif
+
 #ifdef DWARF2_DEBUGGING_INFO
 /* This location is used by calc_die_sizes() to keep track
    the offset of each DIE within the .debug_info section.  */
@@ -5532,12 +5708,14 @@ 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;
 
 /* A list of DIEs for which we may have to generate
-   DW_AT_MIPS_linkage_name once their DECL_ASSEMBLER_NAMEs are
-   set.  */
+   DW_AT_{,MIPS_}linkage_name once their DECL_ASSEMBLER_NAMEs are set.  */
 static GTY(()) limbo_die_node *deferred_asm_name;
 
 /* Filenames referenced by this compilation unit.  */
@@ -5563,7 +5741,6 @@ DEF_VEC_ALLOC_O(die_arg_entry,gc);
 struct GTY ((chain_next ("%h.next"))) var_loc_node {
   rtx GTY (()) var_loc_note;
   const char * GTY (()) label;
-  const char * GTY (()) section_label;
   struct var_loc_node * GTY (()) next;
 };
 
@@ -5571,8 +5748,12 @@ struct GTY ((chain_next ("%h.next"))) var_loc_node {
 struct GTY (()) var_loc_list_def {
   struct var_loc_node * GTY (()) first;
 
-  /* Do not mark the last element of the chained list because
-     it is marked through the chain.  */
+  /* Pointer to the last but one or last element of the
+     chained list.  If the list is empty, both first and
+     last are NULL, if the list contains just one node
+     or the last node certainly is not redundant, it points
+     to the last node, otherwise points to the last but one.
+     Do not mark it for GC because it is marked through the chain.  */
   struct var_loc_node * GTY ((skip ("%h"))) last;
 
   /* DECL_UID of the variable decl.  */
@@ -5676,6 +5857,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;
@@ -5719,10 +5939,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 *);
@@ -5756,9 +5977,7 @@ static const char *get_AT_string (dw_die_ref, enum dwarf_attribute);
 static int get_AT_flag (dw_die_ref, enum dwarf_attribute);
 static unsigned get_AT_unsigned (dw_die_ref, enum dwarf_attribute);
 static inline dw_die_ref get_AT_ref (dw_die_ref, enum dwarf_attribute);
-static bool is_c_family (void);
 static bool is_cxx (void);
-static bool is_java (void);
 static bool is_fortran (void);
 static bool is_ada (void);
 static void remove_AT (dw_die_ref, enum dwarf_attribute);
@@ -5776,7 +5995,7 @@ static hashval_t decl_loc_table_hash (const void *);
 static int decl_loc_table_eq (const void *, const void *);
 static var_loc_list *lookup_decl_loc (const_tree);
 static void equate_decl_number_to_die (tree, dw_die_ref);
-static void add_var_loc_to_decl (tree, struct var_loc_node *);
+static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *);
 static void print_spaces (FILE *);
 static void print_die (dw_die_ref, FILE *);
 static void print_dwarf_line_table (FILE *);
@@ -5785,6 +6004,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 *);
@@ -5796,6 +6025,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 *);
@@ -5819,6 +6064,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);
@@ -5828,7 +6074,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);
@@ -5836,7 +6083,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, dw_die_ref, int);
+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);
@@ -5848,13 +6096,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);
@@ -5862,17 +6112,17 @@ 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_double (double_int, unsigned char *);
 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 void tree_add_const_value_attribute_for_decl (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);
@@ -5904,7 +6154,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);
@@ -5936,15 +6187,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 tree make_ith_pack_parameter_name (tree, int);
 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 *);
 
@@ -5983,6 +6230,12 @@ static void gen_remaining_tmpl_value_param_die_attribute (void);
 #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
@@ -6029,6 +6282,12 @@ static void gen_remaining_tmpl_value_param_die_attribute (void);
 #define DEBUG_MACINFO_SECTION_LABEL     "Ldebug_macinfo"
 #endif
 
+/* Mangled name attribute to use.  This used to be a vendor extension
+   until DWARF 4 standardized it.  */
+#define AT_linkage_name \
+  (dwarf_version >= 4 ? DW_AT_linkage_name : DW_AT_MIPS_linkage_name)
+
+
 /* Definitions of defaults for formats and names of various special
    (artificial) labels which may be generated within this file (when the -g
    options is used and DWARF2_DEBUGGING_INFO is in effect.
@@ -6241,6 +6500,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:
@@ -6419,6 +6688,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:
@@ -6456,6 +6738,22 @@ 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";
 
@@ -6516,6 +6814,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>";
     }
@@ -6651,15 +6957,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);
 }
 
@@ -6679,6 +6985,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
@@ -6694,6 +7014,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)
 {
@@ -6736,6 +7058,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)
 {
@@ -6751,7 +7104,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);
 
@@ -6774,9 +7126,7 @@ AT_string_form (dw_attr_ref a)
       && (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;
 }
@@ -6881,8 +7231,15 @@ AT_loc_list (dw_attr_ref a)
   return a->dw_attr_val.v.val_loc_list;
 }
 
-/* Add an address constant attribute value to a DIE.  */
-
+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
 add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
 {
@@ -7104,18 +7461,6 @@ get_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind)
   return a ? AT_file (a) : NULL;
 }
 
-/* Return TRUE if the language is C or C++.  */
-
-static inline bool
-is_c_family (void)
-{
-  unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
-
-  return (lang == DW_LANG_C || lang == DW_LANG_C89 || lang == DW_LANG_ObjC
-         || lang == DW_LANG_C99
-         || lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus);
-}
-
 /* Return TRUE if the language is C++.  */
 
 static inline bool
@@ -7138,16 +7483,6 @@ is_fortran (void)
          || lang == DW_LANG_Fortran95);
 }
 
-/* Return TRUE if the language is Java.  */
-
-static inline bool
-is_java (void)
-{
-  unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
-
-  return lang == DW_LANG_Java;
-}
-
 /* Return TRUE if the language is Ada.  */
 
 static inline bool
@@ -7202,6 +7537,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.  */
 
@@ -7366,6 +7738,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));
 }
@@ -7385,12 +7759,13 @@ equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
 
 /* Add a variable location node to the linked list for DECL.  */
 
-static void
-add_var_loc_to_decl (tree decl, struct var_loc_node *loc)
+static struct var_loc_node *
+add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
 {
   unsigned int decl_id = DECL_UID (decl);
   var_loc_list *temp;
   void **slot;
+  struct var_loc_node *loc = NULL;
 
   slot = htab_find_slot_with_hash (decl_loc_table, decl, decl_id, INSERT);
   if (*slot == NULL)
@@ -7404,29 +7779,70 @@ add_var_loc_to_decl (tree decl, struct var_loc_node *loc)
 
   if (temp->last)
     {
+      struct var_loc_node *last = temp->last, *unused = NULL;
+      if (last->next)
+       {
+         last = last->next;
+         gcc_assert (last->next == NULL);
+       }
+      /* TEMP->LAST here is either pointer to the last but one or
+        last element in the chained list, LAST is pointer to the
+        last element.  */
+      /* If the last note doesn't cover any instructions, remove it.  */
+      if (label && strcmp (last->label, label) == 0)
+       {
+         if (temp->last != last)
+           {
+             temp->last->next = NULL;
+             unused = last;
+             last = temp->last;
+             gcc_assert (strcmp (last->label, label) != 0);
+           }
+         else
+           {
+             gcc_assert (temp->first == temp->last);
+             memset (temp->last, '\0', sizeof (*temp->last));
+             return temp->last;
+           }
+       }
       /* If the current location is the same as the end of the list,
         and either both or neither of the locations is uninitialized,
         we have nothing to do.  */
-      if ((!rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->last->var_loc_note),
-                        NOTE_VAR_LOCATION_LOC (loc->var_loc_note)))
-         || ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note)
-              != NOTE_VAR_LOCATION_STATUS (loc->var_loc_note))
-             && ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note)
+      if ((!rtx_equal_p (NOTE_VAR_LOCATION_LOC (last->var_loc_note),
+                        NOTE_VAR_LOCATION_LOC (loc_note)))
+         || ((NOTE_VAR_LOCATION_STATUS (last->var_loc_note)
+              != NOTE_VAR_LOCATION_STATUS (loc_note))
+             && ((NOTE_VAR_LOCATION_STATUS (last->var_loc_note)
                   == VAR_INIT_STATUS_UNINITIALIZED)
-                 || (NOTE_VAR_LOCATION_STATUS (loc->var_loc_note)
+                 || (NOTE_VAR_LOCATION_STATUS (loc_note)
                      == VAR_INIT_STATUS_UNINITIALIZED))))
        {
-         /* Add LOC to the end of list and update LAST.  */
-         temp->last->next = loc;
-         temp->last = loc;
+         /* Add LOC to the end of list and update LAST.  If the last
+            element of the list has been removed above, reuse its
+            memory for the new node, otherwise allocate a new one.  */
+         if (unused)
+           {
+             loc = unused;
+             memset (loc, '\0', sizeof (*loc));
+           }
+         else
+           loc = GGC_CNEW (struct var_loc_node);
+         last->next = loc;
+         /* Ensure TEMP->LAST will point either to the new last but one
+            element of the chain, or to the last element in it.  */
+         if (last != temp->last)
+           temp->last = last;
        }
+      else if (unused)
+       ggc_free (unused);
     }
-  /* Do not add empty location to the beginning of the list.  */
-  else if (NOTE_VAR_LOCATION_LOC (loc->var_loc_note) != NULL_RTX)
+  else
     {
+      loc = GGC_CNEW (struct var_loc_node);
       temp->first = loc;
       temp->last = loc;
     }
+  return loc;
 }
 \f
 /* Keep track of the number of spaces used to indent the
@@ -7442,6 +7858,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.  */
 
@@ -7458,6 +7885,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++)
     {
@@ -7488,10 +7922,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");
@@ -7502,8 +7937,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);
            }
@@ -7525,6 +7967,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;
        }
@@ -7647,8 +8097,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);
@@ -7689,6 +8139,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;
     }
@@ -7722,139 +8176,762 @@ 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.  */
 
-  switch (v1->val_class)
+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_rvalue_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:
-      return v1->v.val_int == v2->v.val_int;
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_SLEB128 (at->dw_attr_val.v.val_int);
+      break;
+
     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;
+      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:
-      if (v1->v.val_vec.length != v2->v.val_vec.length
-         || v1->v.val_vec.elt_size != v2->v.val_vec.elt_size)
-       return 0;
-      if (memcmp (v1->v.val_vec.array, v2->v.val_vec.array,
-                 v1->v.val_vec.length * v1->v.val_vec.elt_size))
-       return 0;
-      return 1;
+      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:
-      return v1->v.val_flag == v2->v.val_flag;
+      CHECKSUM_ULEB128 (DW_FORM_flag);
+      CHECKSUM_ULEB128 (at->dw_attr_val.v.val_flag ? 1 : 0);
+      break;
+
     case dw_val_class_str:
-      return !strcmp(v1->v.val_str->str, v2->v.val_str->str);
+      CHECKSUM_ULEB128 (DW_FORM_string);
+      CHECKSUM_STRING (AT_string (at));
+      break;
 
     case dw_val_class_addr:
-      r1 = v1->v.val_addr;
-      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));
+      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:
-      return v1->v.val_offset == v2->v.val_offset;
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_ULEB128 (at->dw_attr_val.v.val_offset);
+      break;
 
     case dw_val_class_loc:
-      for (loc1 = v1->v.val_loc, loc2 = v2->v.val_loc;
-          loc1 && loc2;
-          loc1 = loc1->dw_loc_next, loc2 = loc2->dw_loc_next)
-       if (!same_loc_p (loc1, loc2, mark))
-         return 0;
-      return !loc1 && !loc2;
-
-    case dw_val_class_die_ref:
-      return same_die_p (v1->v.val_die_ref.die, v2->v.val_die_ref.die, mark);
+      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:
-      return 1;
+      break;
 
     case dw_val_class_file:
-      return v1->v.val_file == v2->v.val_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:
-      return 1;
+      break;
     }
 }
 
-/* Do the attributes look the same?  */
-
-static int
-same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark)
-{
-  if (at1->dw_attr != at2->dw_attr)
-    return 0;
-
-  /* We don't care that this was compiled with a different compiler
-     snapshot; if the output is the same, that's what matters. */
-  if (at1->dw_attr == DW_AT_producer)
-    return 1;
-
-  return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark);
-}
+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;
+};
 
-/* Do the dies look the same?  */
+/* Collect the attributes that we will want to use for the checksum.  */
 
-static int
-same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
+static void
+collect_checksum_attributes (struct checksum_attributes *attrs, dw_die_ref die)
 {
-  dw_die_ref c1, c2;
-  dw_attr_ref a1;
+  dw_attr_ref a;
   unsigned ix;
 
-  /* To avoid infinite recursion.  */
-  if (die1->die_mark)
-    return die1->die_mark == die2->die_mark;
-  die1->die_mark = die2->die_mark = ++(*mark);
-
-  if (die1->die_tag != die2->die_tag)
-    return 0;
-
-  if (VEC_length (dw_attr_node, die1->die_attr)
-      != VEC_length (dw_attr_node, die2->die_attr))
-    return 0;
-
-  for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++)
-    if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark))
-      return 0;
-
-  c1 = die1->die_child;
-  c2 = die2->die_child;
-  if (! c1)
+  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
     {
-      if (c2)
-       return 0;
-    }
-  else
-    for (;;)
-      {
-       if (!same_die_p (c1, c2, mark))
-         return 0;
-       c1 = c1->die_sib;
-       c2 = c2->die_sib;
-       if (c1 == die1->die_child)
+      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)
+    {
+    case dw_val_class_const:
+      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_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)
+       return 0;
+      if (memcmp (v1->v.val_vec.array, v2->v.val_vec.array,
+                 v1->v.val_vec.length * v1->v.val_vec.elt_size))
+       return 0;
+      return 1;
+    case dw_val_class_flag:
+      return v1->v.val_flag == v2->v.val_flag;
+    case dw_val_class_str:
+      return !strcmp(v1->v.val_str->str, v2->v.val_str->str);
+
+    case dw_val_class_addr:
+      r1 = v1->v.val_addr;
+      r2 = v2->v.val_addr;
+      if (GET_CODE (r1) != GET_CODE (r2))
+       return 0;
+      return !rtx_equal_p (r1, r2);
+
+    case dw_val_class_offset:
+      return v1->v.val_offset == v2->v.val_offset;
+
+    case dw_val_class_loc:
+      for (loc1 = v1->v.val_loc, loc2 = v2->v.val_loc;
+          loc1 && loc2;
+          loc1 = loc1->dw_loc_next, loc2 = loc2->dw_loc_next)
+       if (!same_loc_p (loc1, loc2, mark))
+         return 0;
+      return !loc1 && !loc2;
+
+    case dw_val_class_die_ref:
+      return same_die_p (v1->v.val_die_ref.die, v2->v.val_die_ref.die, mark);
+
+    case dw_val_class_fde_ref:
+    case dw_val_class_lbl_id:
+    case dw_val_class_lineptr:
+    case dw_val_class_macptr:
+      return 1;
+
+    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;
+    }
+}
+
+/* Do the attributes look the same?  */
+
+static int
+same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark)
+{
+  if (at1->dw_attr != at2->dw_attr)
+    return 0;
+
+  /* We don't care that this was compiled with a different compiler
+     snapshot; if the output is the same, that's what matters. */
+  if (at1->dw_attr == DW_AT_producer)
+    return 1;
+
+  return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark);
+}
+
+/* Do the dies look the same?  */
+
+static int
+same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
+{
+  dw_die_ref c1, c2;
+  dw_attr_ref a1;
+  unsigned ix;
+
+  /* To avoid infinite recursion.  */
+  if (die1->die_mark)
+    return die1->die_mark == die2->die_mark;
+  die1->die_mark = die2->die_mark = ++(*mark);
+
+  if (die1->die_tag != die2->die_tag)
+    return 0;
+
+  if (VEC_length (dw_attr_node, die1->die_attr)
+      != VEC_length (dw_attr_node, die2->die_attr))
+    return 0;
+
+  for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++)
+    if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark))
+      return 0;
+
+  c1 = die1->die_child;
+  c2 = die2->die_child;
+  if (! c1)
+    {
+      if (c2)
+       return 0;
+    }
+  else
+    for (;;)
+      {
+       if (!same_die_p (c1, c2, mark))
+         return 0;
+       c1 = c1->die_sib;
+       c2 = c2->die_sib;
+       if (c1 == die1->die_child)
          {
            if (c2 == die2->die_child)
              break;
@@ -7920,7 +8997,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;
 }
 
@@ -7937,6 +9014,7 @@ is_type_die (dw_die_ref die)
     case DW_TAG_enumeration_type:
     case DW_TAG_pointer_type:
     case DW_TAG_reference_type:
+    case DW_TAG_rvalue_reference_type:
     case DW_TAG_string_type:
     case DW_TAG_structure_type:
     case DW_TAG_subroutine_type:
@@ -7974,6 +9052,7 @@ is_comdat_die (dw_die_ref c)
 
   if (c->die_tag == DW_TAG_pointer_type
       || c->die_tag == DW_TAG_reference_type
+      || c->die_tag == DW_TAG_rvalue_reference_type
       || c->die_tag == DW_TAG_const_type
       || c->die_tag == DW_TAG_volatile_type)
     {
@@ -7992,8 +9071,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);
 }
@@ -8022,10 +9100,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));
@@ -8045,7 +9123,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
@@ -8055,7 +9133,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
@@ -8083,7 +9161,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;
 
@@ -8115,7 +9193,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;
 
@@ -8188,42 +9266,583 @@ 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
+/* Return non-zero if this is a type DIE that should be moved to a
+   COMDAT .debug_types section.  */
+
+static int
+should_move_die_to_comdat (dw_die_ref die)
+{
+  switch (die->die_tag)
+    {
+    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_rvalue_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;
+    }
+}
+
+/* Make a clone of DIE.  */
+
+static dw_die_ref
+clone_die (dw_die_ref die)
+{
+  dw_die_ref clone;
+  dw_attr_ref a;
+  unsigned ix;
+
+  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++)
+    add_dwarf_attr (clone, a);
+
+  return clone;
+}
+
+/* Make a clone of the tree rooted at DIE.  */
+
+static dw_die_ref
+clone_tree (dw_die_ref die)
+{
+  dw_die_ref c;
+  dw_die_ref clone = clone_die (die);
+
+  FOR_EACH_CHILD (die, c, add_child_die (clone, clone_tree(c)));
+
+  return clone;
+}
+
+/* Make a clone of DIE as a declaration.  */
+
+static dw_die_ref
+clone_as_declaration (dw_die_ref die)
+{
+  dw_die_ref clone;
+  dw_die_ref decl;
+  dw_attr_ref a;
+  unsigned ix;
+
+  /* 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++)
+    {
+      /* 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.  */
+
+      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_linkage_name:
+        case DW_AT_MIPS_linkage_name:
+          add_dwarf_attr (clone, a);
+          break;
+        case DW_AT_byte_size:
+        default:
+          break;
+        }
+    }
+
+  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;
+}
+
+/* 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
+copy_declaration_context (dw_die_ref unit, dw_die_ref die)
+{
+  dw_die_ref decl;
+  dw_die_ref new_decl;
+
+  decl = get_AT_ref (die, DW_AT_specification);
+  if (decl == NULL)
+    decl = die;
+  else
+    {
+      unsigned ix;
+      dw_die_ref c;
+      dw_attr_ref a;
+
+      /* 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;
+
+      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);
+        }
+    }
+}
+
+/* Generate the skeleton ancestor tree for the given NODE, then clone
+   the DIE and add the clone into the tree.  */
+
+static void
+generate_skeleton_ancestor_tree (skeleton_chain_node *node)
+{
+  if (node->new_die != NULL)
+    return;
+
+  node->new_die = clone_as_declaration (node->old_die);
+
+  if (node->parent != NULL)
+    {
+      generate_skeleton_ancestor_tree (node->parent);
+      add_child_die (node->parent->new_die, node->new_die);
+    }
+}
+
+/* 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
+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;
+
+  node.parent = parent;
+
+  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);
+}
+
+/* Wrapper function for generate_skeleton_bottom_up.  */
+
+static dw_die_ref
+generate_skeleton (dw_die_ref die)
+{
+  skeleton_chain_node node;
+
+  node.old_die = die;
+  node.new_die = NULL;
+  node.parent = NULL;
+
+  /* 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);
+
+  generate_skeleton_bottom_up (&node);
+  return node.new_die;
+}
+
+/* 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 dw_die_ref
+remove_child_or_replace_with_skeleton (dw_die_ref child, dw_die_ref prev)
+{
+  dw_die_ref skeleton;
+
+  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);
+    }
+
+  return skeleton;
+}
+
+/* Traverse the DIE and set up additional .debug_types sections for each
+   type worthy of being placed in a COMDAT section.  */
+
+static void
+break_out_comdat_types (dw_die_ref die)
+{
+  dw_die_ref c;
+  dw_die_ref first;
+  dw_die_ref prev = NULL;
+  dw_die_ref next = NULL;
+  dw_die_ref unit = NULL;
+
+  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;
+
+        /* 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;
+
+        /* 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);
+}
+
+/* Structure to map a DIE in one CU to its copy in a comdat type unit.  */
+
+struct decl_table_entry
+{
+  dw_die_ref orig;
+  dw_die_ref copy;
+};
+
+/* 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);
+}
+
+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
+htab_decl_del (void *what)
+{
+  struct decl_table_entry *entry = (struct decl_table_entry *) what;
+
+  free (entry);
+}
+
+/* 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 dw_die_ref
+copy_ancestor_tree (dw_die_ref unit, dw_die_ref die, htab_t decl_table)
+{
+  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;
+
+  if (decl_table)
+    {
+      /* 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;
+        }
+
+      /* 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 (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);
+    }
+
+  copy = clone_as_declaration (die);
+  add_child_die (new_parent, copy);
+
+  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;
+    }
+
+  return copy;
+}
+
+/* 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 void
+copy_decls_walk (dw_die_ref unit, dw_die_ref die, htab_t decl_table)
+{
+  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_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 (targ->die_mark != 0 || type_node != NULL)
+            continue;
+
+          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));
+}
+
+/* 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 void
+copy_decls_for_unworthy_types (dw_die_ref unit)
+{
+  htab_t decl_table;
+
+  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);
+}
+
+/* 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.  */
+
+static void
+output_location_lists (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));
+
+  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.  */
 
@@ -8242,7 +9861,7 @@ build_abbrev_table (dw_die_ref die)
     if (AT_class (a) == dw_val_class_die_ref
        && AT_ref (a)->die_mark == 0)
       {
-       gcc_assert (AT_ref (a)->die_symbol);
+       gcc_assert (dwarf_version >= 4 || AT_ref (a)->die_id.die_symbol);
        set_AT_ref_external (a, 1);
       }
 
@@ -8341,7 +9960,10 @@ size_of_die (dw_die_ref die)
            unsigned long lsize = size_of_locs (AT_loc (a));
 
            /* Block length.  */
-           size += constant_size (lsize);
+           if (dwarf_version >= 4)
+             size += size_of_uleb128 (lsize);
+           else
+             size += constant_size (lsize);
            size += lsize;
          }
          break;
@@ -8357,8 +9979,10 @@ size_of_die (dw_die_ref die)
        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 */
+       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:
          size += constant_size (a->dw_attr_val.v.val_vec.length
@@ -8367,13 +9991,31 @@ size_of_die (dw_die_ref die)
                    * a->dw_attr_val.v.val_vec.elt_size; /* block */
          break;
        case dw_val_class_flag:
-         size += 1;
+         if (dwarf_version >= 4)
+           /* Currently all add_AT_flag calls pass in 1 as last argument,
+              so DW_FORM_flag_present can be used.  If that ever changes,
+              we'll need to use DW_FORM_flag and have some optimization
+              in build_abbrev_table that will change those to
+              DW_FORM_flag_present if it is set to 1 in all DIEs using
+              the same abbrev entry.  */
+           gcc_assert (a->dw_attr_val.v.val_flag == 1);
+         else
+           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;
+         if (AT_ref_external (a))
+           {
+             /* 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;
+           }
          else
            size += DWARF_OFFSET_SIZE;
          break;
@@ -8396,6 +10038,9 @@ size_of_die (dw_die_ref die)
        case dw_val_class_file:
          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 ();
        }
@@ -8447,7 +10092,8 @@ unmark_dies (dw_die_ref die)
 {
   dw_die_ref c;
 
-  gcc_assert (die->die_mark);
+  if (dwarf_version < 4)
+    gcc_assert (die->die_mark);
 
   die->die_mark = 0;
   FOR_EACH_CHILD (die, c, unmark_dies (c));
@@ -8523,10 +10169,36 @@ value_format (dw_attr_ref a)
   switch (a->dw_attr_val.val_class)
     {
     case dw_val_class_addr:
-      return DW_FORM_addr;
+      /* Only very few attributes allow DW_FORM_addr.  */
+      switch (a->dw_attr)
+       {
+       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:
+      if (dwarf_version >= 4)
+       return DW_FORM_sec_offset;
+      /* FALLTHRU */
+    case dw_val_class_offset:
       switch (DWARF_OFFSET_SIZE)
        {
        case 4:
@@ -8537,6 +10209,8 @@ value_format (dw_attr_ref a)
          gcc_unreachable ();
        }
     case dw_val_class_loc:
+      if (dwarf_version >= 4)
+       return DW_FORM_exprloc;
       switch (constant_size (size_of_locs (AT_loc (a))))
        {
        case 1:
@@ -8562,8 +10236,19 @@ value_format (dw_attr_ref a)
        default:
          gcc_unreachable ();
        }
-    case dw_val_class_long_long:
-      return DW_FORM_block1;
+    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))
@@ -8578,10 +10263,21 @@ value_format (dw_attr_ref a)
          gcc_unreachable ();
        }
     case dw_val_class_flag:
+      if (dwarf_version >= 4)
+       {
+         /* Currently all add_AT_flag calls pass in 1 as last argument,
+            so DW_FORM_flag_present can be used.  If that ever changes,
+            we'll need to use DW_FORM_flag and have some optimization
+            in build_abbrev_table that will change those to
+            DW_FORM_flag_present if it is set to 1 in all DIEs using
+            the same abbrev entry.  */
+         gcc_assert (a->dw_attr_val.v.val_flag == 1);
+         return DW_FORM_flag_present;
+       }
       return DW_FORM_flag;
     case dw_val_class_die_ref:
       if (AT_ref_external (a))
-       return DW_FORM_ref_addr;
+       return dwarf_version >= 4 ? DW_FORM_sig8 : DW_FORM_ref_addr;
       else
        return DW_FORM_ref;
     case dw_val_class_fde_ref:
@@ -8590,7 +10286,7 @@ value_format (dw_attr_ref a)
       return DW_FORM_addr;
     case dw_val_class_lineptr:
     case dw_val_class_macptr:
-      return DW_FORM_data;
+      return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
     case dw_val_class_str:
       return AT_string_form (a);
     case dw_val_class_file:
@@ -8606,6 +10302,9 @@ value_format (dw_attr_ref a)
          gcc_unreachable ();
        }
 
+    case dw_val_class_data8:
+      return DW_FORM_data8;
+
     default:
       gcc_unreachable ();
     }
@@ -8665,7 +10364,7 @@ output_abbrev_section (void)
 static inline void
 output_die_symbol (dw_die_ref die)
 {
-  char *sym = die->die_symbol;
+  char *sym = die->die_id.die_symbol;
 
   if (sym == 0)
     return;
@@ -8680,12 +10379,11 @@ output_die_symbol (dw_die_ref die)
 }
 
 /* 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.  */
+   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 int gensym)
+             const char *section)
 {
   dw_loc_list_ref retlist = GGC_CNEW (dw_loc_list_node);
 
@@ -8693,27 +10391,18 @@ new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
   retlist->end = end;
   retlist->expr = expr;
   retlist->section = section;
-  if (gensym)
-    retlist->ll_symbol = gen_internal_sym ("LLST");
 
   return retlist;
 }
 
-/* Add a location description expression to a location list.  */
+/* Generate a new internal symbol for this location list node, if it
+   hasn't got one yet.  */
 
 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)
+gen_llsym (dw_loc_list_ref list)
 {
-  dw_loc_list_ref *d;
-
-  /* Find the end of the chain.  */
-  for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
-    ;
-
-  /* Add a new location list node to the list.  */
-  *d = new_loc_list (descr, begin, end, section, 0);
+  gcc_assert (!list->ll_symbol);
+  list->ll_symbol = gen_internal_sym ("LLST");
 }
 
 /* Output the location list given to us.  */
@@ -8767,6 +10456,17 @@ output_loc_list (dw_loc_list_ref list_head)
                       list_head->ll_symbol);
 }
 
+/* Output a type signature.  */
+
+static inline void
+output_signature (const char *sig, const char *name)
+{
+  int i;
+
+  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+    dw2_asm_output_data (1, sig[i], i == 0 ? "%s" : NULL, name);
+}
+
 /* Output the DIE and its attributes.  Called recursively to generate
    the definitions of each child DIE.  */
 
@@ -8780,10 +10480,10 @@ output_die (dw_die_ref die)
 
   /* If someone in another CU might refer to us, set up a symbol for
      them to point to.  */
-  if (die->die_symbol)
+  if (dwarf_version < 4 && die->die_id.die_symbol)
     output_die_symbol (die);
 
-  dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (0x%lx) %s)",
+  dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
                               (unsigned long)die->die_offset,
                               dwarf_tag_name (die->die_tag));
 
@@ -8818,7 +10518,10 @@ output_die (dw_die_ref die)
          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);
+         if (dwarf_version >= 4)
+           dw2_asm_output_data_uleb128 (size, "%s", name);
+         else
+           dw2_asm_output_data (constant_size (size), size, "%s", name);
 
          output_loc_sequence (AT_loc (a));
          break;
@@ -8835,28 +10538,30 @@ output_die (dw_die_ref die)
                               AT_unsigned (a), "%s", name);
          break;
 
-       case dw_val_class_long_long:
+       case dw_val_class_const_double:
          {
            unsigned HOST_WIDE_INT first, second;
 
-           dw2_asm_output_data (1,
-                                2 * HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
-                                "%s", name);
+           if (HOST_BITS_PER_WIDE_INT >= 64)
+             dw2_asm_output_data (1,
+                                  2 * HOST_BITS_PER_WIDE_INT
+                                  / HOST_BITS_PER_CHAR,
+                                  NULL);
 
            if (WORDS_BIG_ENDIAN)
              {
-               first = a->dw_attr_val.v.val_long_long.hi;
-               second = a->dw_attr_val.v.val_long_long.low;
+               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_long_long.low;
-               second = a->dw_attr_val.v.val_long_long.hi;
+               first = a->dw_attr_val.v.val_double.low;
+               second = a->dw_attr_val.v.val_double.high;
              }
 
-           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,
+           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;
@@ -8884,6 +10589,20 @@ output_die (dw_die_ref die)
          }
 
        case dw_val_class_flag:
+         if (dwarf_version >= 4)
+           {
+             /* Currently all add_AT_flag calls pass in 1 as last argument,
+                so DW_FORM_flag_present can be used.  If that ever changes,
+                we'll need to use DW_FORM_flag and have some optimization
+                in build_abbrev_table that will change those to
+                DW_FORM_flag_present if it is set to 1 in all DIEs using
+                the same abbrev entry.  */
+             gcc_assert (AT_flag (a) == 1);
+             if (flag_debug_asm)
+               fprintf (asm_out_file, "\t\t\t%s %s\n",
+                        ASM_COMMENT_START, name);
+             break;
+           }
          dw2_asm_output_data (1, AT_flag (a), "%s", name);
          break;
 
@@ -8900,18 +10619,30 @@ output_die (dw_die_ref die)
        case dw_val_class_die_ref:
          if (AT_ref_external (a))
            {
-             char *sym = AT_ref (a)->die_symbol;
-             int size;
-
-             gcc_assert (sym);
+             if (dwarf_version >= 4)
+               {
+                 comdat_type_node_ref type_node =
+                   AT_ref (a)->die_id.die_type_node;
 
-             /* 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;
+                 gcc_assert (type_node);
+                 output_signature (type_node->signature, name);
+               }
              else
-               size = DWARF_OFFSET_SIZE;
-             dw2_asm_output_offset (size, sym, debug_info_section, "%s", name);
+               {
+                 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
            {
@@ -8965,6 +10696,16 @@ output_die (dw_die_ref die)
            break;
          }
 
+       case dw_val_class_data8:
+         {
+           int i;
+
+           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;
+         }
+
        default:
          gcc_unreachable ();
        }
@@ -8974,7 +10715,7 @@ output_die (dw_die_ref die)
 
   /* 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",
+    dw2_asm_output_data (1, 0, "end of children of DIE %#lx",
                         (unsigned long) die->die_offset);
 }
 
@@ -8984,13 +10725,15 @@ output_die (dw_die_ref die)
 static void
 output_compilation_unit_header (void)
 {
+  int ver = dwarf_version;
+
   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_data (2, ver, "DWARF version number");
   dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
                         debug_abbrev_section,
                         "Offset Into Abbrev. Section");
@@ -9022,14 +10765,14 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
   next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
   calc_die_sizes (die);
 
-  oldsym = die->die_symbol;
+  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_symbol = NULL;
+      die->die_id.die_symbol = NULL;
       switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
     }
   else
@@ -9044,10 +10787,60 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
   if (oldsym)
     {
       unmark_dies (die);
-      die->die_symbol = oldsym;
+      die->die_id.die_symbol = oldsym;
     }
 }
 
+/* Output a comdat type unit DIE and its children.  */
+
+static void
+output_comdat_type_unit (comdat_type_node *node)
+{
+  const char *secname;
+  char *tmp;
+  int i;
+#if defined (OBJECT_FORMAT_ELF)
+  tree comdat_key;
+#endif
+
+  /* First mark all the DIEs in this CU so we know which get local refs.  */
+  mark_dies (node->root_die);
+
+  build_abbrev_table (node->root_die);
+
+  /* Initialize the beginning DIE offset - and calculate sizes/offsets.  */
+  next_die_offset = DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE;
+  calc_die_sizes (node->root_die);
+
+#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
+
+  /* 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);
+
+  unmark_dies (node->root_die);
+}
+
 /* Return the DWARF2/3 pubname associated with a decl.  */
 
 static const char *
@@ -9072,7 +10865,11 @@ static void
 add_pubname (tree decl, dw_die_ref die)
 {
   if (TREE_PUBLIC (decl))
-    add_pubname_string (dwarf2_name (decl, 1), die);
+    {
+      const char *name = dwarf2_name (decl, 1);
+      if (name)
+       add_pubname_string (name, die);
+    }
 }
 
 /* Add a new entry to .debug_pubtypes if appropriate.  */
@@ -9102,7 +10899,11 @@ add_pubtype (tree decl, dw_die_ref die)
            }
        }
       else
-       e.name = xstrdup (dwarf2_name (decl, 1));
+       {
+         e.name = dwarf2_name (decl, 1);
+         if (e.name)
+           e.name = xstrdup (e.name);
+       }
 
       /* If we don't have a name for the type, there's no point in adding
         it to the table.  */
@@ -9306,10 +11107,12 @@ add_ranges (const_tree block)
 /* Add a new entry to .debug_ranges corresponding to a pair of
    labels.  */
 
-static unsigned int
-add_ranges_by_labels (const char *begin, const char *end)
+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)
     {
@@ -9326,14 +11129,19 @@ add_ranges_by_labels (const char *begin, const char *end)
   ranges_by_label[in_use].end = end;
   ranges_by_label_in_use = in_use + 1;
 
-  return add_ranges_num (-(int)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";
+  static const char *const start_fmt = "Offset %#x";
   const char *fmt = start_fmt;
 
   for (i = 0; i < ranges_table_in_use; i++)
@@ -9544,7 +11352,6 @@ output_file_names (void)
   int ndirs;
   int idx_offset;
   int i;
-  int idx;
 
   if (!last_emitted_file)
     {
@@ -9671,13 +11478,12 @@ output_file_names (void)
     }
 
   /* 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
                             - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
-                           "Directory Entry: 0x%x", i + idx_offset);
+                           "Directory Entry: %#x", i + idx_offset);
 
   dw2_asm_output_data (1, 0, "End directory table");
 
@@ -9713,7 +11519,7 @@ output_file_names (void)
                files[file_idx].path + dirs[dir_idx].length, ver);
 
       dw2_asm_output_nstring
-       (filebuf, -1, "File Entry: 0x%x", (unsigned) i + 1);
+       (filebuf, -1, "File Entry: %#x", (unsigned) i + 1);
 
       /* Include directory index.  */
       dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
@@ -9731,7 +11537,7 @@ output_file_names (void)
         NULL);
 #else
       dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
-                             "File Entry: 0x%x", (unsigned) i + 1);
+                             "File Entry: %#x", (unsigned) i + 1);
 
       /* Include directory index.  */
       dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
@@ -9765,6 +11571,7 @@ output_line_info (void)
   long line_delta;
   unsigned long current_file;
   unsigned long function;
+  int ver = dwarf_version;
 
   ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
@@ -9778,7 +11585,7 @@ output_line_info (void)
                        "Length of Source Line Info");
   ASM_OUTPUT_LABEL (asm_out_file, l1);
 
-  dw2_asm_output_data (2, dwarf_version, "DWARF Version");
+  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);
 
@@ -9793,6 +11600,9 @@ output_line_info (void)
   dw2_asm_output_data (1, 1,
                       "Minimum Instruction Length");
 
+  if (ver >= 4)
+    dw2_asm_output_data (1, DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN,
+                        "Maximum Operations Per Instruction");
   dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START,
                       "Default is_stmt_start flag");
   dw2_asm_output_data (1, DWARF_LINE_BASE,
@@ -9818,7 +11628,7 @@ output_line_info (void)
          break;
        }
 
-      dw2_asm_output_data (1, n_op_args, "opcode: 0x%x has %d args",
+      dw2_asm_output_data (1, n_op_args, "opcode: %#x has %d args",
                           opc, n_op_args);
     }
 
@@ -10061,6 +11871,129 @@ output_line_info (void)
   /* 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.
@@ -10100,13 +12033,20 @@ base_type_die (tree type)
 
     case REAL_TYPE:
       if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))
-       encoding = DW_ATE_decimal_float;
+       {
+         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 (TYPE_UNSIGNED (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;
@@ -10133,10 +12073,6 @@ base_type_die (tree type)
 
   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);
@@ -10168,6 +12104,7 @@ is_base_type (tree type)
     case ENUMERAL_TYPE:
     case FUNCTION_TYPE:
     case METHOD_TYPE:
+    case NULLPTR_TYPE:
     case POINTER_TYPE:
     case REFERENCE_TYPE:
     case OFFSET_TYPE:
@@ -10254,6 +12191,21 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
                          ((is_const_type ? TYPE_QUAL_CONST : 0)
                           | (is_volatile_type ? TYPE_QUAL_VOLATILE : 0)));
 
+  if (qualified_type == sizetype
+      && TYPE_NAME (qualified_type)
+      && TREE_CODE (TYPE_NAME (qualified_type)) == TYPE_DECL)
+    {
+#ifdef ENABLE_CHECKING
+      gcc_assert (TREE_CODE (TREE_TYPE (TYPE_NAME (qualified_type)))
+                 == INTEGER_TYPE
+                 && TYPE_PRECISION (TREE_TYPE (TYPE_NAME (qualified_type)))
+                    == TYPE_PRECISION (qualified_type)
+                 && TYPE_UNSIGNED (TREE_TYPE (TYPE_NAME (qualified_type)))
+                    == TYPE_UNSIGNED (qualified_type));
+#endif
+      qualified_type = TREE_TYPE (TYPE_NAME (qualified_type));
+    }
+
   /* If we do, then we can just use its DIE, if it exists.  */
   if (qualified_type)
     {
@@ -10265,7 +12217,8 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
   name = qualified_type ? TYPE_NAME (qualified_type) : NULL;
 
   /* Handle C typedef types.  */
-  if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name))
+  if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name)
+      && !DECL_ARTIFICIAL (name))
     {
       tree dtype = TREE_TYPE (name);
 
@@ -10304,13 +12257,23 @@ modified_type_die (tree type, int is_const_type, int is_volatile_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);
+      if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4)
+       mod_type_die = new_die (DW_TAG_rvalue_reference_type, comp_unit_die,
+                               type);
+      else
+       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
@@ -10341,10 +12304,16 @@ modified_type_die (tree type, int is_const_type, int is_volatile_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.  */
+     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
-         || (TREE_TYPE (name) == qualified_type && DECL_NAME (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,
@@ -10353,6 +12322,9 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
        name = DECL_NAME (name);
       add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
     }
+  /* This probably indicates a bug.  */
+  else if (mod_type_die->die_tag == DW_TAG_base_type)
+    add_name_attribute (mod_type_die, "__unknown__");
 
   if (qualified_type)
     equate_type_number_to_die (qualified_type, mod_type_die);
@@ -10373,27 +12345,6 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
   return mod_type_die;
 }
 
-/* Generate a new name for the parameter pack name NAME (an
-   IDENTIFIER_NODE) that incorporates its */
-
-static tree
-make_ith_pack_parameter_name (tree name, int i)
-{
-  /* Munge the name to include the parameter index.  */
-#define NUMBUF_LEN 128
-  char numbuf[NUMBUF_LEN];
-  char* newname;
-  int newname_len;
-
-  snprintf (numbuf, NUMBUF_LEN, "%i", i);
-  newname_len = IDENTIFIER_LENGTH (name)
-               + strlen (numbuf) + 2;
-  newname = (char*) alloca (newname_len);
-  snprintf (newname, newname_len,
-           "%s#%i", IDENTIFIER_POINTER (name), i);
-  return get_identifier (newname);
-}
-
 /* 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.  */
@@ -10425,30 +12376,27 @@ gen_generic_params_dies (tree t)
   args = lang_hooks.get_innermost_generic_args (t);
   for (i = 0; i < parms_num; i++)
     {
-      tree parm, arg;
+      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)
        {
-         tree pack_elems =
-           lang_hooks.types.get_argument_pack_elems (arg);
-         if (pack_elems)
-           {
-             /* So ARG is an argument pack and the elements of that pack
-                are stored in PACK_ELEMS.  */
-             int i, len;
-
-             len = TREE_VEC_LENGTH (pack_elems);
-             for (i = 0; i < len; i++)
-               generic_parameter_die (TREE_VALUE (parm),
-                                      TREE_VEC_ELT (pack_elems, i),
-                                      die, i);
-           }
-         else /* Arg is not an argument pack.  */
-           generic_parameter_die (TREE_VALUE (parm),
-                                  arg, die,
-                                  -1/* Not a param pack.  */);
+         /* 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);
        }
     }
 }
@@ -10457,15 +12405,15 @@ gen_generic_params_dies (tree t)
    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.
-   PACK_ELEM_INDEX is >= 0 if PARM is a generic parameter pack, and if ARG
-   is one of the unpacked elements of the parameter PACK. In that case,
-   PACK_ELEM_INDEX is the index of ARG in the parameter pack.  */
+   as a child node.  */
 
 static dw_die_ref
-generic_parameter_die (tree parm, tree arg, dw_die_ref parent_die,
-                      int pack_elem_index)
+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;
@@ -10498,20 +12446,17 @@ generic_parameter_die (tree parm, tree arg, dw_die_ref parent_die,
     {
       tree tmpl_type;
 
-      if (pack_elem_index >= 0)
+      /* 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)
        {
-         /* PARM is an element of a parameter pack.
-            Generate a name for it.  */
-         tree identifier = make_ith_pack_parameter_name (DECL_NAME (parm),
-                                                         pack_elem_index);
-         if (identifier)
-           name = IDENTIFIER_POINTER (identifier);
+         name = IDENTIFIER_POINTER (DECL_NAME (parm));
+         gcc_assert (name);
+         add_AT_string (tmpl_die, DW_AT_name, name);
        }
-      else
-       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))
        {
@@ -10534,7 +12479,8 @@ generic_parameter_die (tree parm, tree arg, dw_die_ref parent_die,
          /* 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);
-         add_AT_string (tmpl_die, DW_AT_GNU_template_name, name);
+         if (name)
+           add_AT_string (tmpl_die, DW_AT_GNU_template_name, name);
        }
 
       if (TREE_CODE (parm) == PARM_DECL)
@@ -10556,6 +12502,30 @@ generic_parameter_die (tree parm, tree arg, dw_die_ref parent_die,
   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.  */
 
@@ -10755,6 +12725,63 @@ int_loc_descriptor (HOST_WIDE_INT i)
 #endif
 
 #ifdef DWARF2_DEBUGGING_INFO
+/* Return loc description representing "address" of integer value.
+   This can appear only as toplevel expression.  */
+
+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;
+
+  if (!(dwarf_version >= 4 || !dwarf_strict))
+    return 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;
+    }
+
+  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;
+}
 
 /* Return a location descriptor that designates a base+offset location.  */
 
@@ -10806,13 +12833,17 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset,
          return new_loc_descr (DW_OP_fbreg, offset, 0);
        }
     }
-  else if (fde
-          && fde->drap_reg != INVALID_REGNUM
+  else if (!optimize
+          && fde
           && (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.  */
+        on the stack when drap is used to align stack.
+        Only do this when not optimizing, for optimized code var-tracking
+        is supposed to track where the arguments live and the register
+        used as vdrap or drap in some spot might be used for something
+        else in other part of the routine.  */
       return new_loc_descr (DW_OP_fbreg, offset, 0);
     }
 
@@ -10840,36 +12871,6 @@ is_based_loc (const_rtx rtl)
               && CONST_INT_P (XEXP (rtl, 1)))));
 }
 
-/* Return a descriptor that describes the concatenation of N locations
-   used to form the address of a memory location.  */
-
-static dw_loc_descr_ref
-concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode,
-                           enum var_init_status initialized)
-{
-  unsigned int i;
-  dw_loc_descr_ref cc_loc_result = NULL;
-  unsigned int n = XVECLEN (concatn, 0);
-
-  for (i = 0; i < n; ++i)
-    {
-      dw_loc_descr_ref ref;
-      rtx x = XVECEXP (concatn, 0, i);
-
-      ref = mem_loc_descriptor (x, mode, VAR_INIT_STATUS_INITIALIZED);
-      if (ref == NULL)
-       return NULL;
-
-      add_loc_descr (&cc_loc_result, ref);
-      add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
-    }
-
-  if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
-
-  return cc_loc_result;
-}
-
 /* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0)
    failed.  */
 
@@ -10888,7 +12889,7 @@ tls_mem_loc_descriptor (rtx mem)
       || !DECL_THREAD_LOCAL_P (base))
     return NULL;
 
-  loc_result = loc_descriptor_from_tree_1 (MEM_EXPR (mem), 2);
+  loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1);
   if (loc_result == NULL)
     return NULL;
 
@@ -10898,20 +12899,120 @@ tls_mem_loc_descriptor (rtx 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.
+/* Output debug info about reason why we failed to expand expression as dwarf
+   expression.  */
 
-   CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the
+static void
+expansion_failed (tree expr, rtx rtl, char const *reason)
+{
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      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);
+    }
+}
+
+/* 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) == UNSPEC)
+    {
+      /* If delegitimize_address couldn't do anything with the UNSPEC, assume
+        we can't express it in the debug info.  */
+#ifdef ENABLE_CHECKING
+      inform (current_function_decl
+             ? DECL_SOURCE_LOCATION (current_function_decl)
+             : UNKNOWN_LOCATION,
+             "non-delegitimized UNSPEC %d found in variable location",
+             XINT (rtl, 1));
+#endif
+      expansion_failed (NULL_TREE, rtl,
+                       "UNSPEC hasn't been delegitimized.\n");
+      return 1;
+    }
+
+  if (GET_CODE (rtl) != SYMBOL_REF)
+    return 0;
+
+  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;
+}
+
+/* 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 bool
+const_ok_for_output (rtx rtl)
+{
+  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;
+}
+
+/* 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.  */
@@ -10922,6 +13023,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
 {
   dw_loc_descr_ref mem_loc_result = NULL;
   enum dwarf_location_atom op;
+  dw_loc_descr_ref op0, op1;
 
   /* Note that for a dynamically sized array, the location we will generate a
      description of here will be the lowest numbered location which is
@@ -10935,10 +13037,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
     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 ...  */
+      return mem_loc_descriptor (XEXP (rtl, 0), mode, initialized);
 
     case SUBREG:
       /* The case of a subreg may arise when we have a local (register)
@@ -10946,9 +13045,15 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
         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 ...  */
+      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;
 
     case REG:
       /* Whenever a register number forms a part of the description of the
@@ -10978,13 +13083,54 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
        }
       break;
 
+    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;
+
     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));
+       {
+         if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE)
+           {
+             expansion_failed (NULL_TREE, rtl, "DWARF address size mismatch");
+             return 0;
+           }
+         else if (GET_MODE_SIZE (GET_MODE (rtl)) == DWARF2_ADDR_SIZE)
+           add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
+         else
+           add_loc_descr (&mem_loc_result,
+                          new_loc_descr (DW_OP_deref_size,
+                                         GET_MODE_SIZE (GET_MODE (rtl)), 0));
+       }
+      else
+       {
+         rtx new_rtl = avoid_constant_pool_reference (rtl);
+         if (new_rtl != rtl)
+           return mem_loc_descriptor (new_rtl, mode, initialized);
+       }
       break;
 
     case LO_SUM:
@@ -10998,36 +13144,43 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
         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))
+      if (GET_CODE (rtl) == SYMBOL_REF
+         && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
        {
-         bool marked;
-         rtx tmp = get_pool_constant_mark (rtl, &marked);
+         dw_loc_descr_ref temp;
 
-         if (GET_CODE (tmp) == SYMBOL_REF)
-           {
-             rtl = tmp;
-             if (CONSTANT_POOL_ADDRESS_P (tmp))
-               get_pool_constant_mark (tmp, &marked);
-             else
-               marked = true;
-           }
+         /* If this is not defined, we have no way to emit the data.  */
+         if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
+           break;
 
-         /* 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;
+         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;
        }
 
+      if (!const_ok_for_output (rtl))
+       break;
+
+    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;
 
+    case CONCAT:
+    case CONCATN:
+    case VAR_LOCATION:
+      expansion_failed (NULL_TREE, rtl,
+                       "CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor");
+      return 0;
+
     case PRE_MODIFY:
       /* Extract the PLUS expression nested inside and fall into
         PLUS code below.  */
@@ -11076,10 +13229,22 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
 
     /* 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;
+
     case MULT:
       op = DW_OP_mul;
       goto do_binop;
 
+    case DIV:
+      op = DW_OP_div;
+      goto do_binop;
+
+    case UMOD:
+      op = DW_OP_mod;
+      goto do_binop;
+
     case ASHIFT:
       op = DW_OP_shl;
       goto do_binop;
@@ -11092,203 +13257,1144 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       op = DW_OP_shr;
       goto do_binop;
 
+    case AND:
+      op = DW_OP_and;
+      goto do_binop;
+
+    case IOR:
+      op = DW_OP_or;
+      goto do_binop;
+
+    case XOR:
+      op = DW_OP_xor;
+      goto do_binop;
+
     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);
+      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 (op0 == 0 || op1 == 0)
+       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 MOD:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-       mem_loc_result = op0;
-       add_loc_descr (&mem_loc_result, op1);
-       add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      if (op0 == 0 || op1 == 0)
        break;
-      }
+
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_over, 0, 0));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_over, 0, 0));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_div, 0, 0));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_minus, 0, 0));
+      break;
+
+    case NOT:
+      op = DW_OP_not;
+      goto do_unop;
+
+    case ABS:
+      op = DW_OP_abs;
+      goto do_unop;
+
+    case NEG:
+      op = DW_OP_neg;
+      goto do_unop;
+
+    do_unop:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+
+      if (op0 == 0)
+       break;
+
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      break;
 
     case CONST_INT:
       mem_loc_result = int_loc_descriptor (INTVAL (rtl));
       break;
 
-    case CONCATN:
-      mem_loc_result = concatn_mem_loc_descriptor (rtl, mode,
-                                                  VAR_INIT_STATUS_INITIALIZED);
+    case EQ:
+      op = DW_OP_eq;
+      goto do_scompare;
+
+    case GE:
+      op = DW_OP_ge;
+      goto do_scompare;
+
+    case GT:
+      op = DW_OP_gt;
+      goto do_scompare;
+
+    case LE:
+      op = DW_OP_le;
+      goto do_scompare;
+
+    case LT:
+      op = DW_OP_lt;
+      goto do_scompare;
+
+    case NE:
+      op = DW_OP_ne;
+      goto do_scompare;
+
+    do_scompare:
+      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 1))) > DWARF2_ADDR_SIZE)
+       break;
+      else
+       {
+         enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
+
+         if (op_mode == VOIDmode)
+           op_mode = GET_MODE (XEXP (rtl, 1));
+         if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT)
+           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 (op_mode != VOIDmode
+             && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
+           {
+             int shift = DWARF2_ADDR_SIZE - GET_MODE_SIZE (op_mode);
+             shift *= BITS_PER_UNIT;
+             /* For eq/ne, if the operands are known to be zero-extended,
+                there is no need to do the fancy shifting up.  */
+             if (op == DW_OP_eq || op == DW_OP_ne)
+               {
+                 dw_loc_descr_ref last0, last1;
+                 for (last0 = op0;
+                      last0->dw_loc_next != NULL;
+                      last0 = last0->dw_loc_next)
+                   ;
+                 for (last1 = op1;
+                      last1->dw_loc_next != NULL;
+                      last1 = last1->dw_loc_next)
+                   ;
+                 /* deref_size zero extends, and for constants we can check
+                    whether they are zero extended or not.  */
+                 if (((last0->dw_loc_opc == DW_OP_deref_size
+                       && last0->dw_loc_oprnd1.v.val_int
+                          <= GET_MODE_SIZE (op_mode))
+                      || (CONST_INT_P (XEXP (rtl, 0))
+                           && (unsigned HOST_WIDE_INT) INTVAL (XEXP (rtl, 0))
+                              == (INTVAL (XEXP (rtl, 0))
+                                  & GET_MODE_MASK (op_mode))))
+                     && ((last1->dw_loc_opc == DW_OP_deref_size
+                          && last1->dw_loc_oprnd1.v.val_int
+                             <= GET_MODE_SIZE (op_mode))
+                         || (CONST_INT_P (XEXP (rtl, 1))
+                             && (unsigned HOST_WIDE_INT)
+                                INTVAL (XEXP (rtl, 1))
+                                == (INTVAL (XEXP (rtl, 1))
+                                    & GET_MODE_MASK (op_mode)))))
+                   goto do_compare;
+               }
+             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));
+               }
+           }
+       }
+
+    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;
+
+    case GEU:
+      op = DW_OP_ge;
+      goto do_ucompare;
+
+    case GTU:
+      op = DW_OP_gt;
+      goto do_ucompare;
+
+    case LEU:
+      op = DW_OP_le;
+      goto do_ucompare;
+
+    case LTU:
+      op = DW_OP_lt;
+      goto do_ucompare;
+
+    do_ucompare:
+      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 1))) > DWARF2_ADDR_SIZE)
+       break;
+      else
+       {
+         enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
+
+         if (op_mode == VOIDmode)
+           op_mode = GET_MODE (XEXP (rtl, 1));
+         if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT)
+           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 (op_mode != VOIDmode
+             && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
+           {
+             HOST_WIDE_INT mask = GET_MODE_MASK (op_mode);
+             dw_loc_descr_ref last0, last1;
+             for (last0 = op0;
+                  last0->dw_loc_next != NULL;
+                  last0 = last0->dw_loc_next)
+               ;
+             for (last1 = op1;
+                  last1->dw_loc_next != NULL;
+                  last1 = last1->dw_loc_next)
+               ;
+             if (CONST_INT_P (XEXP (rtl, 0)))
+               op0 = int_loc_descriptor (INTVAL (XEXP (rtl, 0)) & mask);
+             /* deref_size zero extends, so no need to mask it again.  */
+             else if (last0->dw_loc_opc != DW_OP_deref_size
+                      || last0->dw_loc_oprnd1.v.val_int
+                         > GET_MODE_SIZE (op_mode))
+               {
+                 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);
+             /* deref_size zero extends, so no need to mask it again.  */
+             else if (last1->dw_loc_opc != DW_OP_deref_size
+                      || last1->dw_loc_oprnd1.v.val_int
+                         > GET_MODE_SIZE (op_mode))
+               {
+                 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));
+             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;
+
+      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;
+
+      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));
+       }
+
+      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;
+
+       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;
+
+    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)
+       {
+         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)
+           {
+             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));
+           }
+         if (size != (int) DWARF2_ADDR_SIZE)
+           {
+             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));
+           }
+       }
       break;
 
+    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 SS_PLUS:
+    case US_PLUS:
+    case SS_MINUS:
+    case US_MINUS:
+    case SS_NEG:
+    case US_NEG:
+    case SS_ABS:
+    case SS_ASHIFT:
+    case US_ASHIFT:
+    case SS_TRUNCATE:
+    case US_TRUNCATE:
+    case UDIV:
+    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 VEC_MERGE:
+    case VEC_SELECT:
+    case VEC_CONCAT:
+    case VEC_DUPLICATE:
     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;
 
-    default:
-      gcc_unreachable ();
+    case CONST_STRING:
+      resolve_one_addr (&rtl, NULL);
+      goto symref;
+
+    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 a descriptor that describes the concatenation of two locations.
+   This is typically a complex variable.  */
+
+static dw_loc_descr_ref
+concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
+{
+  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.  */
+
+static dw_loc_descr_ref
+concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
+{
+  unsigned int i;
+  dw_loc_descr_ref cc_loc_result = NULL;
+  unsigned int n = XVECLEN (concatn, 0);
+
+  for (i = 0; i < n; ++i)
+    {
+      dw_loc_descr_ref ref;
+      rtx x = XVECEXP (concatn, 0, i);
+
+      ref = loc_descriptor (x, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+      if (ref == NULL)
+       return NULL;
+
+      add_loc_descr (&cc_loc_result, ref);
+      add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
+    }
+
+  if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
+  return cc_loc_result;
+}
+
+/* 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.
+
+   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.
+
+   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 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.  */
+      loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized);
+      break;
+
+    case REG:
+      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:
+      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+                                      initialized);
+      if (loc_result == NULL)
+       loc_result = tls_mem_loc_descriptor (rtl);
+      if (loc_result == NULL)
+       {
+         rtx new_rtl = avoid_constant_pool_reference (rtl);
+         if (new_rtl != rtl)
+           loc_result = loc_descriptor (new_rtl, mode, initialized);
+       }
+      break;
+
+    case CONCAT:
+      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1),
+                                         initialized);
+      break;
+
+    case CONCATN:
+      loc_result = concatn_loc_descriptor (rtl, initialized);
+      break;
+
+    case VAR_LOCATION:
+      /* Single part.  */
+      if (GET_CODE (PAT_VAR_LOCATION_LOC (rtl)) != PARALLEL)
+       {
+         rtx loc = PAT_VAR_LOCATION_LOC (rtl);
+         if (GET_CODE (loc) == EXPR_LIST)
+           loc = XEXP (loc, 0);
+         loc_result = loc_descriptor (loc, mode, initialized);
+         break;
+       }
+
+      rtl = XEXP (rtl, 1);
+      /* FALLTHRU */
+
+    case PARALLEL:
+      {
+       rtvec par_elems = XVEC (rtl, 0);
+       int num_elem = GET_NUM_ELEM (par_elems);
+       enum machine_mode mode;
+       int i;
+
+       /* 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;
+
+           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 CONST_INT:
+      if (mode != VOIDmode && mode != BLKmode)
+       loc_result = address_of_int_loc_descriptor (GET_MODE_SIZE (mode),
+                                                   INTVAL (rtl));
+      break;
+
+    case CONST_DOUBLE:
+      if (mode == VOIDmode)
+       mode = GET_MODE (rtl);
+
+      if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
+       {
+         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
+           {
+             loc_result->dw_loc_oprnd2.val_class = dw_val_class_const_double;
+             loc_result->dw_loc_oprnd2.v.val_double
+               = rtx_to_double_int (rtl);
+           }
+       }
+      break;
+
+    case CONST_VECTOR:
+      if (mode == VOIDmode)
+       mode = GET_MODE (rtl);
+
+      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);
+                 double_int val = rtx_to_double_int (elt);
+
+                 if (elt_size <= sizeof (HOST_WIDE_INT))
+                   insert_int (double_int_to_shwi (val), elt_size, p);
+                 else
+                   {
+                     gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
+                     insert_double (val, p);
+                   }
+               }
+             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;
+
+           default:
+             gcc_unreachable ();
+           }
+
+         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 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:
+      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;
+
+  return secname;
+}
+
+/* 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));
+}
+
+/* Helper function for dw_loc_list.  Compute proper Dwarf location descriptor
+   for VARLOC.  */
+
+static dw_loc_descr_ref
+dw_loc_list_1 (tree loc, rtx varloc, int want_address,
+              enum var_init_status initialized)
+{
+  int have_address = 0;
+  dw_loc_descr_ref descr;
+  enum machine_mode mode;
+
+  if (want_address != 2)
+    {
+      gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
+      /* Single part.  */
+      if (GET_CODE (PAT_VAR_LOCATION_LOC (varloc)) != PARALLEL)
+       {
+         varloc = PAT_VAR_LOCATION_LOC (varloc);
+         if (GET_CODE (varloc) == EXPR_LIST)
+           varloc = XEXP (varloc, 0);
+         mode = GET_MODE (varloc);
+         if (MEM_P (varloc))
+           {
+             rtx addr = XEXP (varloc, 0);
+             descr = mem_loc_descriptor (addr, mode, initialized);
+             if (descr)
+               have_address = 1;
+             else
+               {
+                 rtx x = avoid_constant_pool_reference (varloc);
+                 if (x != varloc)
+                   descr = mem_loc_descriptor (x, mode, initialized);
+               }
+           }
+         else
+           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;
+
+  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;
+    }
+
+  /* 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 (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;
+
+      add_loc_descr (&descr, new_loc_descr (op, size, 0));
     }
 
-  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 descr;
 }
 
-/* Return a descriptor that describes the concatenation of two locations.
-   This is typically a complex variable.  */
+/* 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
-concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
+static dw_loc_list_ref
+dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
 {
-  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);
-
-  if (x0_ref == 0 || x1_ref == 0)
-    return 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;
+         }
+      }
 
-  cc_loc_result = x0_ref;
-  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x0)));
+  /* 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)
+    {
+      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, x1_ref);
-  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1)));
+         *listp = new_loc_list (descr, node->label, endname, secname);
+         listp = &(*listp)->dw_loc_next;
+       }
+    }
 
-  if (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;
 }
 
-/* Return a descriptor that describes the concatenation of N
-   locations.  */
+/* Return if the loc_list has only single element and thus can be represented
+   as location description.   */
 
-static dw_loc_descr_ref
-concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
+static bool
+single_element_loc_list_p (dw_loc_list_ref list)
 {
-  unsigned int i;
-  dw_loc_descr_ref cc_loc_result = NULL;
-  unsigned int n = XVECLEN (concatn, 0);
-
-  for (i = 0; i < n; ++i)
-    {
-      dw_loc_descr_ref ref;
-      rtx x = XVECEXP (concatn, 0, i);
+  gcc_assert (!list->dw_loc_next || list->ll_symbol);
+  return !list->ll_symbol;
+}
 
-      ref = loc_descriptor (x, VAR_INIT_STATUS_INITIALIZED);
-      if (ref == NULL)
-       return NULL;
+/* To each location in list LIST add loc descr REF.  */
 
-      add_loc_descr (&cc_loc_result, ref);
-      add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
+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;
     }
+}
 
-  if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+/* 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.
 
-  return cc_loc_result;
-}
+   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.  */
 
-/* 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.
+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;
+}
 
-   If we don't know how to describe it, return 0.  */
+/* LOC is constant expression.  Try a luck, look it up in constant
+   pool and return its loc_descr of its address.  */
 
 static dw_loc_descr_ref
-loc_descriptor (rtx rtl, enum var_init_status initialized)
+cst_pool_loc_descr (tree loc)
 {
-  dw_loc_descr_ref loc_result = NULL;
+  /* Get an RTL for this, if something has been emitted.  */
+  rtx rtl = lookup_constant_def (loc);
+  enum machine_mode mode;
 
-  switch (GET_CODE (rtl))
+  if (!rtl || !MEM_P (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);
-
-      /* ... fall through ...  */
-
-    case REG:
-      loc_result = reg_loc_descriptor (rtl, initialized);
-      break;
+      gcc_assert (!rtl);
+      return 0;
+    }
+  gcc_assert (GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF);
 
-    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 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);
+}
 
-    case CONCAT:
-      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1),
-                                         initialized);
-      break;
+/* Return dw_loc_list representing address of addr_expr LOC
+   by looking for innder INDIRECT_REF expression and turing it
+   into simple arithmetics.  */
 
-    case CONCATN:
-      loc_result = concatn_loc_descriptor (rtl, initialized);
-      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;
 
-    case VAR_LOCATION:
-      /* Single part.  */
-      if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
+  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;
+    }
+  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)
        {
-         loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), initialized);
-         break;
+         /* 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));
        }
-
-      rtl = XEXP (rtl, 1);
-      /* FALLTHRU */
-
-    case PARALLEL:
-      {
-       rtvec par_elems = XVEC (rtl, 0);
-       int num_elem = GET_NUM_ELEM (par_elems);
-       enum machine_mode mode;
-       int i;
-
-       /* 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;
-
-           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;
-
-    default:
-      gcc_unreachable ();
+      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 loc_result;
+  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;
 
@@ -11299,6 +14405,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:
@@ -11306,25 +14413,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))
@@ -11337,7 +14464,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;
 
@@ -11352,7 +14479,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;
@@ -11384,17 +14512,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);
@@ -11403,8 +14542,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;
@@ -11416,37 +14558,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);
+               ret = loc_descriptor (rtl, VOIDmode,
+                                     VAR_INIT_STATUS_INITIALIZED);
                have_address = 1;
              }
-           ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
+           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);
+             }
+           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;
@@ -11457,52 +14612,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:
@@ -11525,6 +14703,8 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
     case CEIL_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case TRUNC_DIV_EXPR:
+      if (TYPE_UNSIGNED (TREE_TYPE (loc)))
+       return 0;
       op = DW_OP_div;
       goto do_binop;
 
@@ -11536,8 +14716,25 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
     case CEIL_MOD_EXPR:
     case ROUND_MOD_EXPR:
     case TRUNC_MOD_EXPR:
-      op = DW_OP_mod;
-      goto do_binop;
+      if (TYPE_UNSIGNED (TREE_TYPE (loc)))
+       {
+         op = DW_OP_mod;
+         goto do_binop;
+       }
+      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_list (&list_ret, list_ret1);
+      if (list_ret == 0)
+       return 0;
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_over, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_over, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_div, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_mul, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_minus, 0, 0));
+      break;
 
     case MULT_EXPR:
       op = DW_OP_mul;
@@ -11556,11 +14753,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;
        }
 
@@ -11604,13 +14801,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:
@@ -11627,11 +14826,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:
@@ -11651,29 +14850,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;
       }
@@ -11687,7 +14886,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
@@ -11699,33 +14902,77 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
       return NULL;
 #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'
@@ -11835,9 +15082,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))
@@ -11932,10 +15179,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
@@ -12021,11 +15272,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
@@ -12034,7 +15285,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);
        }
     }
@@ -12072,6 +15323,24 @@ extract_int (const unsigned char *src, unsigned int size)
   return val;
 }
 
+/* Writes double_int values to dw_vec_const array.  */
+
+static void
+insert_double (double_int val, unsigned char *dest)
+{
+  unsigned char *p0 = dest;
+  unsigned char *p1 = dest + sizeof (HOST_WIDE_INT);
+
+  if (WORDS_BIG_ENDIAN)
+    {
+      p0 = p1;
+      p1 = dest;
+    }
+
+  insert_int ((HOST_WIDE_INT) val.low, sizeof (HOST_WIDE_INT), p0);
+  insert_int ((HOST_WIDE_INT) val.high, sizeof (HOST_WIDE_INT), p1);
+}
+
 /* Writes floating point values to dw_vec_const array.  */
 
 static void
@@ -12098,7 +15367,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))
@@ -12112,13 +15381,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);
 
@@ -12131,15 +15400,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:
       {
@@ -12156,39 +15420,14 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
            for (i = 0, p = array; i < length; i++, p += elt_size)
              {
                rtx elt = CONST_VECTOR_ELT (rtl, i);
-               HOST_WIDE_INT lo, hi;
-
-               switch (GET_CODE (elt))
-                 {
-                 case CONST_INT:
-                   lo = INTVAL (elt);
-                   hi = -(lo < 0);
-                   break;
-
-                 case CONST_DOUBLE:
-                   lo = CONST_DOUBLE_LOW (elt);
-                   hi = CONST_DOUBLE_HIGH (elt);
-                   break;
-
-                 default:
-                   gcc_unreachable ();
-                 }
+               double_int val = rtx_to_double_int (elt);
 
                if (elt_size <= sizeof (HOST_WIDE_INT))
-                 insert_int (lo, elt_size, p);
+                 insert_int (double_int_to_shwi (val), 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);
+                   insert_double (val, p);
                  }
              }
            break;
@@ -12207,18 +15446,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
@@ -12232,13 +15488,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
@@ -12305,8 +15575,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!  */
@@ -12567,37 +15841,25 @@ 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))
+  /* 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)
     {
-      tree sectree = DECL_SECTION_NAME (current_function_decl);
-      secname = TREE_STRING_POINTER (sectree);
+      rtl = make_decl_rtl_for_debug (decl);
+      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
@@ -12613,12 +15875,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 ())
@@ -12650,60 +15911,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
@@ -12715,137 +15922,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->next == NULL
+      && 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) == EXPR_LIST)
+       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_for_decl (die, decl);
+  return tree_add_const_value_attribute_for_decl (die, decl);
 }
 
 /* Add VARIABLE and DIE into deferred locations list.  */
@@ -13009,7 +16136,7 @@ native_encode_initializer (tree init, unsigned char *array, int size)
 /* Attach a DW_AT_const_value attribute to DIE. The value of the
    attribute is the const value T.  */
 
-static void
+static bool
 tree_add_const_value_attribute (dw_die_ref die, tree t)
 {
   tree init;
@@ -13017,14 +16144,14 @@ tree_add_const_value_attribute (dw_die_ref die, tree t)
   rtx rtl;
 
   if (!t || !TREE_TYPE (t) || TREE_TYPE (t) == error_mark_node)
-    return;
+    return false;
 
   init = t;
   gcc_assert (!DECL_P (init));
 
   rtl = rtl_for_decl_init (init, type);
   if (rtl)
-    add_const_value_attribute (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))
@@ -13035,9 +16162,13 @@ tree_add_const_value_attribute (dw_die_ref die, tree t)
          unsigned char *array = GGC_CNEWVEC (unsigned char, size);
 
          if (native_encode_initializer (init, array, size))
-           add_AT_vec (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
@@ -13045,23 +16176,27 @@ tree_add_const_value_attribute (dw_die_ref die, tree t)
    variable with static storage duration
    (so it can't be a PARM_DECL or a RESULT_DECL).  */
 
-static void
+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;
+    return false;
 
     if (TREE_READONLY (decl)
        && ! TREE_THIS_VOLATILE (decl)
        && DECL_INITIAL (decl))
       /* OK */;
     else
-      return;
+      return false;
 
-    tree_add_const_value_attribute (var_die, DECL_INITIAL (decl));
+  /* 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
@@ -13111,8 +16246,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;
@@ -13133,14 +16267,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;
 }
@@ -13221,6 +16357,43 @@ add_comp_dir_attribute (dw_die_ref die)
     add_AT_string (die, DW_AT_comp_dir, remap_debug_filename (wd));
 }
 
+/* Return the default for DW_AT_lower_bound, or -1 if there is not any
+   default.  */
+
+static int
+lower_bound_default (void)
+{
+  switch (get_AT_unsigned (comp_unit_die, DW_AT_language))
+    {
+    case DW_LANG_C:
+    case DW_LANG_C89:
+    case DW_LANG_C99:
+    case DW_LANG_C_plus_plus:
+    case DW_LANG_ObjC:
+    case DW_LANG_ObjC_plus_plus:
+    case DW_LANG_Java:
+      return 0;
+    case DW_LANG_Fortran77:
+    case DW_LANG_Fortran90:
+    case DW_LANG_Fortran95:
+      return 1;
+    case DW_LANG_UPC:
+    case DW_LANG_D:
+    case DW_LANG_Python:
+      return dwarf_version >= 4 ? 0 : -1;
+    case DW_LANG_Ada95:
+    case DW_LANG_Ada83:
+    case DW_LANG_Cobol74:
+    case DW_LANG_Cobol85:
+    case DW_LANG_Pascal83:
+    case DW_LANG_Modula2:
+    case DW_LANG_PLI:
+      return dwarf_version >= 4 ? 1 : -1;
+    default:
+      return -1;
+    }
+}
+
 /* Given a tree node describing an array bound (either lower or upper) output
    a representation for that bound.  */
 
@@ -13234,14 +16407,35 @@ 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));
+       int dflt;
+
+       /* Use the default if possible.  */
+       if (bound_attr == DW_AT_lower_bound
+           && host_integerp (bound, 0)
+           && (dflt = lower_bound_default ()) != -1
+           && tree_low_cst (bound, 0) == dflt)
+         ;
+
+       /* 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:
@@ -13257,7 +16451,6 @@ 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;
 
        /* ??? Can this happen, or should the variable have been bound
           first?  Probably it can, since I imagine that we try to create
@@ -13265,14 +16458,12 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
           the list, and won't have created a forward reference to a
           later parameter.  */
        if (decl_die != NULL)
-         add_AT_die_ref (subrange_die, bound_attr, decl_die);
-       else
          {
-           loc = loc_descriptor_from_tree_1 (bound, 0);
-           add_AT_location_description (subrange_die, bound_attr, loc);
+           add_AT_die_ref (subrange_die, bound_attr, decl_die);
+           break;
          }
-       break;
       }
+      /* FALLTHRU */
 
     default:
       {
@@ -13280,10 +16471,24 @@ 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 || single_element_loc_list_p (list))
+         {
+           /* If DW_AT_*bound is not a reference nor constant, it is
+              a DWARF expression rather than location description.
+              For that loc_list_from_tree (bound, 0) is needed.
+              If that fails to give a single element list,
+              fall back to outputting this as a reference anyway.  */
+           dw_loc_list_ref list2 = loc_list_from_tree (bound, 0);
+           if (list2 && single_element_loc_list_p (list2))
+             {
+               add_AT_loc (subrange_die, bound_attr, list2->expr);
+               break;
+             }
+         }
+       if (list == NULL)
          break;
 
        if (current_function_decl == 0)
@@ -13294,8 +16499,7 @@ 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);
-
+       add_AT_location_description (decl_die, DW_AT_location, list);
        add_AT_die_ref (subrange_die, bound_attr, decl_die);
        break;
       }
@@ -13548,7 +16752,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)));
     }
@@ -13576,15 +16781,16 @@ 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);
 
       if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
          && TREE_PUBLIC (decl)
          && !DECL_ABSTRACT (decl)
-         && !(TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl))
-         && !is_fortran ())
+         && !(TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl)))
        {
          /* Defer until we have an assembler name set.  */
          if (!DECL_ASSEMBLER_NAME_SET_P (decl))
@@ -13598,7 +16804,7 @@ add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
              deferred_asm_name = asm_name;
            }
          else if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
-           add_AT_string (die, DW_AT_MIPS_linkage_name,
+           add_AT_string (die, AT_linkage_name,
                           IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
        }
     }
@@ -13900,12 +17106,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);
            }
@@ -13964,7 +17170,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)
@@ -13999,7 +17205,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));
@@ -14116,11 +17322,11 @@ gen_descr_array_type_die (tree type, struct array_descr_info *info,
       if (info->dimen[dim].lower_bound)
        {
          /* If it is the default value, omit it.  */
-         if ((is_c_family () || is_java ())
-             && integer_zerop (info->dimen[dim].lower_bound))
-           ;
-         else if (is_fortran ()
-                  && integer_onep (info->dimen[dim].lower_bound))
+         int dflt;
+
+         if (host_integerp (info->dimen[dim].lower_bound, 0)
+             && (dflt = lower_bound_default ()) != -1
+             && tree_low_cst (info->dimen[dim].lower_bound, 0) == dflt)
            ;
          else
            add_descr_info_field (subrange_die, DW_AT_lower_bound,
@@ -14176,7 +17382,9 @@ retry_incomplete_types (void)
   int i;
 
   for (i = VEC_length (tree, incomplete_types) - 1; i >= 0; i--)
-    gen_type_die (VEC_index (tree, incomplete_types, i), comp_unit_die);
+    if (should_emit_struct_debug (VEC_index (tree, incomplete_types, i),
+                                 DINFO_USAGE_DIR_USE))
+      gen_type_die (VEC_index (tree, incomplete_types, i), comp_unit_die);
 }
 
 /* Determine what tag to use for a record type.  */
@@ -14196,7 +17404,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 ();
@@ -14219,6 +17429,9 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die)
                          scope_die_for (type, context_die), type);
       equate_type_number_to_die (type, type_die);
       add_name_attribute (type_die, type_tag (type));
+      if ((dwarf_version >= 4 || !dwarf_strict)
+         && ENUM_IS_SCOPED (type))
+       add_AT_flag (type_die, DW_AT_enum_class, 1);
     }
   else if (! TYPE_SIZE (type))
     return type_die;
@@ -14285,27 +17498,33 @@ 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;
+  tree ultimate_origin;
   dw_die_ref parm_die
     = new_die (DW_TAG_formal_parameter, context_die, node);
 
   switch (TREE_CODE_CLASS (TREE_CODE (node_or_origin)))
     {
     case tcc_declaration:
-      if (!origin)
-        origin = decl_ultimate_origin (node);
+      ultimate_origin = decl_ultimate_origin (node_or_origin);
+      if (node || ultimate_origin)
+       origin = ultimate_origin;
       if (origin != NULL)
        add_abstract_origin_attribute (parm_die, origin);
       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
@@ -14337,6 +17556,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.  */
 
@@ -14380,7 +17640,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)))
@@ -14417,7 +17679,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;
@@ -14455,17 +17718,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)
@@ -14481,34 +17750,72 @@ 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)
+{
+  tree type;
+  dw_die_ref die;
+
+  type = (tree) *slot;
+  die = lookup_type_die (type);
+  if (die != NULL)
+    die->die_perennial_p = 1;
+  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.  */
+   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_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
+premark_types_used_by_global_vars_helper (void **slot,
+                                         void *data ATTRIBUTE_UNUSED)
 {
-  tree type;
+  struct types_used_by_vars_entry *entry;
   dw_die_ref die;
 
-  type = (tree) *slot;
-  die = lookup_type_die (type);
-  if (die != NULL)
-    die->die_perennial_p = 1;
+  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)
 {
@@ -14516,6 +17823,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).  */
 
@@ -14648,7 +17965,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
@@ -14757,7 +18075,7 @@ 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.  */
@@ -14784,21 +18102,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 -
@@ -14890,44 +18233,24 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   HOST_WIDE_INT off;
   tree com_decl;
   tree decl_or_origin = decl ? decl : origin;
+  tree ultimate_origin;
   dw_die_ref var_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)
-    origin = decl_ultimate_origin (decl);
-
+  ultimate_origin = decl_ultimate_origin (decl_or_origin);
+  if (decl || ultimate_origin)
+    origin = ultimate_origin;
   com_decl = fortran_common (decl_or_origin, &off);
 
   /* Symbol in common gets emitted as a child of the common block, in the form
      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);
@@ -14935,22 +18258,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);
                }
            }
@@ -14962,11 +18286,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
@@ -14977,10 +18300,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);
@@ -14991,8 +18314,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);
@@ -15005,15 +18328,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);
@@ -15023,10 +18347,9 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 
   /* If the compiler emitted a definition for the DECL declaration
      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)
+     DIE for it again. Allow re-declarations of DECLs that are
+     inside functions, though.  */
+  if (old_die && declaration && !local_scope_p (context_die))
     return;
 
   /* For static data members, the declaration in the class is supposed
@@ -15076,10 +18399,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),
@@ -15197,8 +18517,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);
+    }
 }
 
 
@@ -15210,7 +18533,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;
 
@@ -15353,8 +18677,12 @@ gen_pointer_type_die (tree type, dw_die_ref context_die)
 static void
 gen_reference_type_die (tree type, dw_die_ref context_die)
 {
-  dw_die_ref ref_die
-    = new_die (DW_TAG_reference_type, scope_die_for (type, context_die), type);
+  dw_die_ref ref_die, scope_die = scope_die_for (type, context_die);
+
+  if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4)
+    ref_die = new_die (DW_TAG_rvalue_reference_type, scope_die, type);
+  else
+    ref_die = new_die (DW_TAG_reference_type, scope_die, type);
 
   equate_type_number_to_die (type, ref_die);
   add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die);
@@ -15412,26 +18740,42 @@ 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);
+
+  switch (language)
+    {
+    case DW_LANG_Fortran77:
+    case DW_LANG_Fortran90:
+    case DW_LANG_Fortran95:
+      /* Fortran has case insensitive identifiers and the front-end
+        lowercases everything.  */
+      add_AT_unsigned (die, DW_AT_identifier_case, DW_ID_down_case);
+      break;
+    default:
+      /* The default DW_ID_case_sensitive doesn't need to be specified.  */
+      break;
+    }
   return die;
 }
 
@@ -15709,7 +19053,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;
@@ -15841,6 +19186,18 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
         when appropriate.  */
       return;
 
+    case NULLPTR_TYPE:
+      {
+        dw_die_ref type_die = lookup_type_die (type);
+        if (type_die == NULL)
+          {
+            type_die = new_die (DW_TAG_unspecified_type, comp_unit_die, type);
+            add_name_attribute (type_die, "decltype(nullptr)");
+            equate_type_number_to_die (type, type_die);
+          }
+      }
+      return;
+
     case VOID_TYPE:
     case INTEGER_TYPE:
     case REAL_TYPE:
@@ -15961,10 +19318,6 @@ process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
 {
   dw_die_ref die;
   tree decl_or_origin = decl ? decl : origin;
-  tree ultimate_origin = origin ? decl_ultimate_origin (origin) : NULL;
-
-  if (ultimate_origin)
-    origin = ultimate_origin;
 
   if (TREE_CODE (decl_or_origin) == FUNCTION_DECL)
     die = lookup_decl_die (decl_or_origin);
@@ -16047,7 +19400,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);
     }
@@ -16093,7 +19446,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:
@@ -16196,7 +19553,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))
@@ -16228,7 +19589,7 @@ static void
 gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
 {
   tree decl_or_origin = decl ? decl : origin;
-  tree class_origin = NULL;
+  tree class_origin = NULL, ultimate_origin;
 
   if (DECL_P (decl_or_origin) && DECL_IGNORED_P (decl_or_origin))
     return;
@@ -16274,7 +19635,9 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
 
       /* If we're emitting a clone, emit info for the abstract instance.  */
       if (origin || DECL_ORIGIN (decl) != decl)
-       dwarf2out_abstract_function (origin ? origin : DECL_ABSTRACT_ORIGIN (decl));
+       dwarf2out_abstract_function (origin
+                                    ? DECL_ORIGIN (origin)
+                                    : DECL_ABSTRACT_ORIGIN (decl));
 
       /* If we're emitting an out-of-line copy of an inline function,
         emit info for the abstract instance and set up to refer to it.  */
@@ -16356,9 +19719,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);
@@ -16375,10 +19736,12 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
         complicated because of the possibility that the VAR_DECL really
         represents an inlined instance of a formal parameter for an inline
         function.  */
-      if (!origin)
-        origin = decl_ultimate_origin (decl);
-      if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
-       gen_formal_parameter_die (decl, origin, context_die);
+      ultimate_origin = decl_ultimate_origin (decl_or_origin);
+      if (ultimate_origin != NULL_TREE
+         && TREE_CODE (ultimate_origin) == PARM_DECL)
+       gen_formal_parameter_die (decl, origin,
+                                 true /* Emit name attribute.  */,
+                                 context_die);
       else
        gen_variable_die (decl, origin, context_die);
       break;
@@ -16400,12 +19763,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:
@@ -16464,10 +19830,7 @@ dwarf2out_imported_module_or_decl_1 (tree decl,
 
   if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
     {
-      if (is_base_type (TREE_TYPE (decl)))
-       at_import_die = base_type_die (TREE_TYPE (decl));
-      else
-       at_import_die = force_type_die (TREE_TYPE (decl));
+      at_import_die = force_type_die (TREE_TYPE (decl));
       /* For namespace N { typedef void T; } using N::T; base_type_die
         returns NULL, but DW_TAG_imported_declaration requires
         the DW_AT_import tag.  Force creation of DW_TAG_typedef.  */
@@ -16503,9 +19866,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,
@@ -16546,6 +19914,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)
@@ -16689,6 +20061,16 @@ dwarf2out_decl (tree decl)
   gen_decl_die (decl, NULL, context_die);
 }
 
+/* Write the debugging output for DECL.  */
+
+static void
+dwarf2out_function_decl (tree decl)
+{
+  dwarf2out_decl (decl);
+
+  htab_empty (decl_loc_table);
+}
+
 /* Output a marker (i.e. a label) for the beginning of the generated code for
    a lexical block.  */
 
@@ -16866,29 +20248,163 @@ gen_remaining_tmpl_value_param_die_attribute (void)
 
 
 /* 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
@@ -16898,10 +20414,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;
 
@@ -16914,33 +20431,51 @@ dwarf2out_var_location (rtx loc_note)
   if (next_real == NULL_RTX)
     return;
 
-  newloc = GGC_CNEW (struct var_loc_node);
+  /* If there were any real insns between note we processed last time
+     and this note (or if it is the first note), clear
+     last_{,postcall_}label so that they are not reused this time.  */
+  if (last_var_location_insn == NULL_RTX
+      || last_var_location_insn != next_real
+      || last_in_cold_section_p != in_cold_section_p)
+    {
+      last_label = NULL;
+      last_postcall_label = NULL;
+    }
+
+  decl = NOTE_VAR_LOCATION_DECL (loc_note);
+  newloc = add_var_loc_to_decl (decl, loc_note,
+                               NOTE_DURING_CALL_P (loc_note)
+                               ? last_postcall_label : last_label);
+  if (newloc == NULL)
+    return;
+
   /* 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
+     and this note, use the label we emitted last time.  Otherwise
+     create a new label and emit it.  */
+  if (last_label == NULL)
     {
       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);
     }
   newloc->var_loc_note = loc_note;
   newloc->next = NULL;
 
-  if (cfun && in_cold_section_p)
-    newloc->section_label = crtl->subsections.cold_section_label;
+  if (!NOTE_DURING_CALL_P (loc_note))
+    newloc->label = last_label;
   else
-    newloc->section_label = text_section_label;
+    {
+      if (!last_postcall_label)
+       {
+         sprintf (loclabel, "%s-1", last_label);
+         last_postcall_label = ggc_strdup (loclabel);
+       }
+      newloc->label = last_postcall_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);
 }
 
 /* We need to reset the locations at the beginning of each
@@ -16951,8 +20486,6 @@ dwarf2out_var_location (rtx loc_note)
 static void
 dwarf2out_begin_function (tree fun)
 {
-  htab_empty (decl_loc_table);
-
   if (function_section (fun) != text_section)
     have_multiple_function_sections = true;
 
@@ -17058,7 +20591,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;
@@ -17085,7 +20618,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);
 
@@ -17167,6 +20700,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
@@ -17195,6 +20732,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,
@@ -17239,17 +20780,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);
@@ -17299,8 +20856,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.  */
@@ -17344,8 +20905,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));
@@ -17423,6 +20988,7 @@ prune_unused_types_walk (dw_die_ref die)
     case DW_TAG_packed_type:
     case DW_TAG_pointer_type:
     case DW_TAG_reference_type:
+    case DW_TAG_rvalue_reference_type:
     case DW_TAG_volatile_type:
     case DW_TAG_typedef:
     case DW_TAG_array_type:
@@ -17527,6 +21093,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.  */
 
@@ -17535,19 +21115,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.  */
@@ -17556,17 +21148,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
@@ -17584,7 +21186,29 @@ file_table_relative_p (void ** slot, void *param)
   return 1;
 }
 
-/* Move a DW_AT_MIPS_linkage_name attribute just added to dw_die_ref
+/* 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
    probably improve compactness of debug info, removing equivalent
@@ -17597,7 +21221,7 @@ move_linkage_attr (dw_die_ref die)
   unsigned ix = VEC_length (dw_attr_node, die->die_attr);
   dw_attr_node linkage = *VEC_index (dw_attr_node, die->die_attr, ix - 1);
 
-  gcc_assert (linkage.dw_attr == DW_AT_MIPS_linkage_name);
+  gcc_assert (linkage.dw_attr == AT_linkage_name);
 
   while (--ix > 0)
     {
@@ -17614,6 +21238,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.  */
 
@@ -17621,6 +21363,8 @@ 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;
 
@@ -17704,12 +21448,14 @@ 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;
       if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
        {
-         add_AT_string (node->die, DW_AT_MIPS_linkage_name,
+         add_AT_string (node->die, AT_linkage_name,
                         IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
          move_linkage_attr (node->die);
        }
@@ -17726,14 +21472,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);
@@ -17746,7 +21517,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);
@@ -17755,6 +21527,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
@@ -17764,12 +21537,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++)
        {
@@ -17778,18 +21551,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.  */
@@ -17815,6 +21593,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);
@@ -17840,6 +21639,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)
@@ -17887,6 +21698,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
 {
   0,           /* init */
   0,           /* finish */
+  0,           /* assembly_start */
   0,           /* define */
   0,           /* undef */
   0,           /* start_source_file */
@@ -17910,6 +21722,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 */
 };