OSDN Git Service

* matrix-reorg.c (analyze_matrix_allocation_site): Remove unused
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index dc5ed24..3e3cf31 100644 (file)
@@ -89,9 +89,29 @@ 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);
+static void dwarf2out_source_line (unsigned int, const char *, int, bool);
+
+static rtx last_var_location_insn;
+#endif
+
+#ifdef VMS_DEBUGGING_INFO
+int vms_file_stats_name (const char *, long long *, long *, char *, int *);
+
+/* Define this macro to be a nonzero value if the directory specifications
+    which are output in the debug info should end with a separator.  */
+#define DWARF2_DIR_SHOULD_END_WITH_SEPARATOR 1
+/* Define this macro to evaluate to a nonzero value if GCC should refrain
+   from generating indirect strings in DWARF2 debug information, for instance
+   if your target is stuck with an old version of GDB that is unable to
+   process them properly or uses VMS Debug.  */
+#define DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET 1
+#else
+#define DWARF2_DIR_SHOULD_END_WITH_SEPARATOR 0
+#define DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET 0
 #endif
 
 #ifndef DWARF2_FRAME_INFO
@@ -145,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;
@@ -159,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;
 }
@@ -194,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 ";#"
@@ -266,8 +302,8 @@ typedef struct GTY(()) dw_fde_struct {
   const char *dw_fde_hot_section_end_label;
   const char *dw_fde_unlikely_section_label;
   const char *dw_fde_unlikely_section_end_label;
-  bool dw_fde_switched_sections;
   dw_cfi_ref dw_fde_cfi;
+  dw_cfi_ref dw_fde_switch_cfi; /* Last CFI before switching sections.  */
   unsigned funcdef_number;
   HOST_WIDE_INT stack_realignment;
   /* Dynamic realign argument pointer register.  */
@@ -281,6 +317,15 @@ typedef struct GTY(()) dw_fde_struct {
   unsigned stack_realign : 1;
   /* Whether dynamic realign argument pointer register has been saved.  */
   unsigned drap_reg_saved: 1;
+  /* True iff dw_fde_begin label is in text_section or cold_text_section.  */
+  unsigned in_std_section : 1;
+  /* True iff dw_fde_unlikely_section_label is in text_section or
+     cold_text_section.  */
+  unsigned cold_in_std_section : 1;
+  /* True iff switched sections.  */
+  unsigned dw_fde_switched_sections : 1;
+  /* True iff switching from cold to hot section.  */
+  unsigned dw_fde_switched_cold_to_hot : 1;
 }
 dw_fde_node;
 
@@ -305,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
@@ -317,8 +368,6 @@ dw_fde_node;
 #define DWARF_INITIAL_LENGTH_SIZE (DWARF_OFFSET_SIZE == 4 ? 4 : 12)
 #endif
 
-#define DWARF_VERSION 2
-
 /* Round SIZE up to the nearest BOUNDARY.  */
 #define DWARF_ROUND(SIZE,BOUNDARY) \
   ((((SIZE) + (BOUNDARY) - 1) / (BOUNDARY)) * (BOUNDARY))
@@ -382,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;
 
@@ -417,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 *);
@@ -524,6 +575,25 @@ init_return_column_size (enum machine_mode mode, rtx mem, unsigned int c)
   emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
 }
 
+/* Divide OFF by DWARF_CIE_DATA_ALIGNMENT, asserting no remainder.  */
+
+static inline HOST_WIDE_INT
+div_data_align (HOST_WIDE_INT off)
+{
+  HOST_WIDE_INT r = off / DWARF_CIE_DATA_ALIGNMENT;
+  gcc_assert (r * DWARF_CIE_DATA_ALIGNMENT == off);
+  return r;
+}
+
+/* Return true if we need a signed version of a given opcode
+   (e.g. DW_CFA_offset_extended_sf vs DW_CFA_offset_extended).  */
+
+static inline bool
+need_data_align_sf_opcode (HOST_WIDE_INT off)
+{
+  return DWARF_CIE_DATA_ALIGNMENT < 0 ? off > 0 : off < 0;
+}
+
 /* Generate code to initialize the register size table.  */
 
 void
@@ -717,13 +787,29 @@ dwarf2out_cfi_label (bool force)
   return label;
 }
 
+/* True if remember_state should be emitted before following CFI directive.  */
+static bool emit_cfa_remember;
+
 /* Add CFI to the current fde at the PC value indicated by LABEL if specified,
    or to the CIE if LABEL is NULL.  */
 
 static void
 add_fde_cfi (const char *label, dw_cfi_ref cfi)
 {
-  dw_cfi_ref *list_head = &cie_cfi_head;
+  dw_cfi_ref *list_head;
+
+  if (emit_cfa_remember)
+    {
+      dw_cfi_ref cfi_remember;
+
+      /* Emit the state save.  */
+      emit_cfa_remember = false;
+      cfi_remember = new_cfi ();
+      cfi_remember->dw_cfi_opc = DW_CFA_remember_state;
+      add_fde_cfi (label, cfi_remember);
+    }
+
+  list_head = &cie_cfi_head;
 
   if (dwarf2out_do_cfi_asm ())
     {
@@ -733,50 +819,51 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi)
 
          gcc_assert (fde != NULL);
 
-         /* We still have to add the cfi to the list so that
-            lookup_cfa works later on.  When -g2 and above we
-            even need to force emitting of CFI labels and
-            add to list a DW_CFA_set_loc for convert_cfa_to_fb_loc_list
-            purposes.  */
-         switch (cfi->dw_cfi_opc)
+         /* We still have to add the cfi to the list so that lookup_cfa
+            works later on.  When -g2 and above we even need to force
+            emitting of CFI labels and add to list a DW_CFA_set_loc for
+            convert_cfa_to_fb_loc_list purposes.  If we're generating
+            DWARF3 output we use DW_OP_call_frame_cfa and so don't use
+            convert_cfa_to_fb_loc_list.  */
+         if (dwarf_version == 2
+             && debug_info_level > DINFO_LEVEL_TERSE
+             && (write_symbols == DWARF2_DEBUG
+                 || write_symbols == VMS_AND_DWARF2_DEBUG))
            {
-           case DW_CFA_def_cfa_offset:
-           case DW_CFA_def_cfa_offset_sf:
-           case DW_CFA_def_cfa_register:
-           case DW_CFA_def_cfa:
-           case DW_CFA_def_cfa_sf:
-           case DW_CFA_def_cfa_expression:
-           case DW_CFA_restore_state:
-             if (write_symbols != DWARF2_DEBUG
-                 && write_symbols != VMS_AND_DWARF2_DEBUG)
-               break;
-             if (debug_info_level <= DINFO_LEVEL_TERSE)
-               break;
-
-             if (*label == 0 || strcmp (label, "<do not output>") == 0)
-               label = dwarf2out_cfi_label (true);
-
-             if (fde->dw_fde_current_label == NULL
-                 || strcmp (label, fde->dw_fde_current_label) != 0)
+             switch (cfi->dw_cfi_opc)
                {
-                 dw_cfi_ref xcfi;
-
-                 label = xstrdup (label);
-
-                 /* Set the location counter to the new label.  */
-                 xcfi = new_cfi ();
-                 /* It doesn't metter whether DW_CFA_set_loc
-                    or DW_CFA_advance_loc4 is added here, those aren't
-                    emitted into assembly, only looked up by
-                    convert_cfa_to_fb_loc_list.  */
-                 xcfi->dw_cfi_opc = DW_CFA_set_loc;
-                 xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
-                 add_cfi (&fde->dw_fde_cfi, xcfi);
-                 fde->dw_fde_current_label = label;
-               }
-             break;
-           default:
-             break;
+               case DW_CFA_def_cfa_offset:
+               case DW_CFA_def_cfa_offset_sf:
+               case DW_CFA_def_cfa_register:
+               case DW_CFA_def_cfa:
+               case DW_CFA_def_cfa_sf:
+               case DW_CFA_def_cfa_expression:
+               case DW_CFA_restore_state:
+                 if (*label == 0 || strcmp (label, "<do not output>") == 0)
+                   label = dwarf2out_cfi_label (true);
+
+                 if (fde->dw_fde_current_label == NULL
+                     || strcmp (label, fde->dw_fde_current_label) != 0)
+                   {
+                     dw_cfi_ref xcfi;
+
+                     label = xstrdup (label);
+
+                     /* Set the location counter to the new label.  */
+                     xcfi = new_cfi ();
+                     /* It doesn't metter whether DW_CFA_set_loc
+                        or DW_CFA_advance_loc4 is added here, those aren't
+                        emitted into assembly, only looked up by
+                        convert_cfa_to_fb_loc_list.  */
+                     xcfi->dw_cfi_opc = DW_CFA_set_loc;
+                     xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
+                     add_cfi (&fde->dw_fde_cfi, xcfi);
+                     fde->dw_fde_current_label = label;
+                   }
+                 break;
+               default:
+                 break;
+               }
            }
 
          output_cfi_directive (cfi);
@@ -955,7 +1042,7 @@ def_cfa_1 (const char *label, dw_cfa_location *loc_p)
   if (loc.reg == old_cfa.reg && !loc.indirect)
     {
       /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, indicating
-        the CFA register did not change but the offset did.  The data 
+        the CFA register did not change but the offset did.  The data
         factoring for DW_CFA_def_cfa_offset_sf happens in output_cfi, or
         in the assembler via the .cfi_def_cfa_offset directive.  */
       if (loc.offset < 0)
@@ -1033,7 +1120,7 @@ reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT
     }
   else if (sreg == INVALID_REGNUM)
     {
-      if (offset < 0)
+      if (need_data_align_sf_opcode (offset))
        cfi->dw_cfi_opc = DW_CFA_offset_extended_sf;
       else if (reg & ~0x3f)
        cfi->dw_cfi_opc = DW_CFA_offset_extended;
@@ -1068,25 +1155,6 @@ dwarf2out_window_save (const char *label)
   add_fde_cfi (label, cfi);
 }
 
-/* Add a CFI to update the running total of the size of arguments
-   pushed onto the stack.  */
-
-void
-dwarf2out_args_size (const char *label, HOST_WIDE_INT size)
-{
-  dw_cfi_ref cfi;
-
-  if (size == old_args_size)
-    return;
-
-  old_args_size = size;
-
-  cfi = new_cfi ();
-  cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
-  cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
-  add_fde_cfi (label, cfi);
-}
-
 /* Entry point for saving a register to the stack.  REG is the GCC register
    number.  LABEL and OFFSET are passed to reg_save.  */
 
@@ -1161,7 +1229,7 @@ initial_return_save (rtx rtl)
       /* The return address is at some offset from any value we can
         actually load.  For instance, on the SPARC it is in %i7+8. Just
         ignore the offset for now; it doesn't matter for unwinding frames.  */
-      gcc_assert (GET_CODE (XEXP (rtl, 1)) == CONST_INT);
+      gcc_assert (CONST_INT_P (XEXP (rtl, 1)));
       initial_return_save (XEXP (rtl, 0));
       return;
 
@@ -1203,7 +1271,7 @@ stack_adjust_offset (const_rtx pattern, HOST_WIDE_INT cur_args_size,
 
       if (! (code == PLUS || code == MINUS)
          || XEXP (src, 0) != stack_pointer_rtx
-         || GET_CODE (XEXP (src, 1)) != CONST_INT)
+         || !CONST_INT_P (XEXP (src, 1)))
        return 0;
 
       /* (set (reg sp) (plus (reg sp) (const_int))) */
@@ -1230,7 +1298,7 @@ stack_adjust_offset (const_rtx pattern, HOST_WIDE_INT cur_args_size,
              rtx val = XEXP (XEXP (src, 1), 1);
              /* We handle only adjustments by constant amount.  */
              gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS
-                         && GET_CODE (val) == CONST_INT);
+                         && CONST_INT_P (val));
              offset = -INTVAL (val);
              break;
            }
@@ -1437,13 +1505,58 @@ compute_barrier_args_size (void)
   VEC_free (rtx, heap, next);
 }
 
+/* Add a CFI to update the running total of the size of arguments
+   pushed onto the stack.  */
+
+static void
+dwarf2out_args_size (const char *label, HOST_WIDE_INT size)
+{
+  dw_cfi_ref cfi;
+
+  if (size == old_args_size)
+    return;
+
+  old_args_size = size;
+
+  cfi = new_cfi ();
+  cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
+  cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
+  add_fde_cfi (label, cfi);
+}
+
+/* Record a stack adjustment of OFFSET bytes.  */
+
+static void
+dwarf2out_stack_adjust (HOST_WIDE_INT offset, const char *label)
+{
+  if (cfa.reg == STACK_POINTER_REGNUM)
+    cfa.offset += offset;
+
+  if (cfa_store.reg == STACK_POINTER_REGNUM)
+    cfa_store.offset += offset;
+
+  if (ACCUMULATE_OUTGOING_ARGS)
+    return;
+
+#ifndef STACK_GROWS_DOWNWARD
+  offset = -offset;
+#endif
+
+  args_size += offset;
+  if (args_size < 0)
+    args_size = 0;
+
+  def_cfa_1 (label, &cfa);
+  if (flag_asynchronous_unwind_tables)
+    dwarf2out_args_size (label, args_size);
+}
 
 /* Check INSN to see if it looks like a push or a stack adjustment, and
-   make a note of it if it does.  EH uses this information to find out how
-   much extra space it needs to pop off the stack.  */
+   make a note of it if it does.  EH uses this information to find out
+   how much extra space it needs to pop off the stack.  */
 
 static void
-dwarf2out_stack_adjust (rtx insn, bool after_p)
+dwarf2out_notice_stack_adjust (rtx insn, bool after_p)
 {
   HOST_WIDE_INT offset;
   const char *label;
@@ -1527,31 +1640,7 @@ dwarf2out_stack_adjust (rtx insn, bool after_p)
     return;
 
   label = dwarf2out_cfi_label (false);
-  dwarf2out_args_size_adjust (offset, label);
-}
-
-/* Adjust args_size based on stack adjustment OFFSET.  */
-
-static void
-dwarf2out_args_size_adjust (HOST_WIDE_INT offset, const char *label)
-{
-  if (cfa.reg == STACK_POINTER_REGNUM)
-    cfa.offset += offset;
-
-  if (cfa_store.reg == STACK_POINTER_REGNUM)
-    cfa_store.offset += offset;
-
-#ifndef STACK_GROWS_DOWNWARD
-  offset = -offset;
-#endif
-
-  args_size += offset;
-  if (args_size < 0)
-    args_size = 0;
-
-  def_cfa_1 (label, &cfa);
-  if (flag_asynchronous_unwind_tables)
-    dwarf2out_args_size (label, args_size);
+  dwarf2out_stack_adjust (offset, label);
 }
 
 #endif
@@ -1796,7 +1885,7 @@ dwarf2out_frame_debug_cfa_offset (rtx set, const char *label)
   addr = XEXP (set, 0);
   gcc_assert (MEM_P (addr));
   addr = XEXP (addr, 0);
-  
+
   /* As documented, only consider extremely simple addresses.  */
   switch (GET_CODE (addr))
     {
@@ -2129,7 +2218,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
              HOST_WIDE_INT offset = stack_adjust_offset (elem, args_size, 0);
 
              if (offset != 0)
-               dwarf2out_args_size_adjust (offset, label);
+               dwarf2out_stack_adjust (offset, label);
            }
        }
       return;
@@ -2149,17 +2238,17 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
 
   fde = current_fde ();
 
-  if (GET_CODE (src) == REG
+  if (REG_P (src)
       && fde
       && fde->drap_reg == REGNO (src)
       && (fde->drap_reg_saved
-         || GET_CODE (dest) == REG))
+         || 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 (GET_CODE (dest) == REG)
+      if (REG_P (dest))
        {
          gcc_assert (fde->vdrap_reg == INVALID_REGNUM);
          fde->vdrap_reg = REGNO (dest);
@@ -2260,7 +2349,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
 
              gcc_assert (REG_P (XEXP (src, 0))
                          && (unsigned) REGNO (XEXP (src, 0)) == cfa.reg
-                         && GET_CODE (XEXP (src, 1)) == CONST_INT);
+                         && CONST_INT_P (XEXP (src, 1)));
              offset = INTVAL (XEXP (src, 1));
              if (GET_CODE (src) != MINUS)
                offset = -offset;
@@ -2274,7 +2363,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
              /* Rule 4 */
              if (REG_P (XEXP (src, 0))
                  && REGNO (XEXP (src, 0)) == cfa.reg
-                 && GET_CODE (XEXP (src, 1)) == CONST_INT)
+                 && CONST_INT_P (XEXP (src, 1)))
                {
                  /* Setting a temporary CFA register that will be copied
                     into the FP later on.  */
@@ -2300,7 +2389,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
 
              /* Rule 9 */
              else if (GET_CODE (src) == LO_SUM
-                      && GET_CODE (XEXP (src, 1)) == CONST_INT)
+                      && CONST_INT_P (XEXP (src, 1)))
                {
                  cfa_temp.reg = REGNO (dest);
                  cfa_temp.offset = INTVAL (XEXP (src, 1));
@@ -2320,7 +2409,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
        case IOR:
          gcc_assert (REG_P (XEXP (src, 0))
                      && (unsigned) REGNO (XEXP (src, 0)) == cfa_temp.reg
-                     && GET_CODE (XEXP (src, 1)) == CONST_INT);
+                     && CONST_INT_P (XEXP (src, 1)));
 
          if ((unsigned) REGNO (dest) != cfa_temp.reg)
            cfa_temp.reg = REGNO (dest);
@@ -2427,7 +2516,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
          {
            int regno;
 
-           gcc_assert (GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT
+           gcc_assert (CONST_INT_P (XEXP (XEXP (dest, 0), 1))
                        && REG_P (XEXP (XEXP (dest, 0), 0)));
            offset = INTVAL (XEXP (XEXP (dest, 0), 1));
            if (GET_CODE (XEXP (dest, 0)) == MINUS)
@@ -2622,10 +2711,13 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
   if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn))
     flush_queued_reg_saves ();
 
-  if (! RTX_FRAME_RELATED_P (insn))
+  if (!RTX_FRAME_RELATED_P (insn))
     {
+      /* ??? This should be done unconditionally since stack adjustments
+        matter if the stack pointer is not the CFA register anymore but
+        is still used to save registers.  */
       if (!ACCUMULATE_OUTGOING_ARGS)
-       dwarf2out_stack_adjust (insn, after_p);
+       dwarf2out_notice_stack_adjust (insn, after_p);
       return;
     }
 
@@ -2709,7 +2801,6 @@ dwarf2out_begin_epilogue (rtx insn)
 {
   bool saw_frp = false;
   rtx i;
-  dw_cfi_ref cfi;
 
   /* Scan forward to the return insn, noticing if there are possible
      frame related insns.  */
@@ -2724,6 +2815,22 @@ dwarf2out_begin_epilogue (rtx insn)
       if (CALL_P (i) && SIBLING_CALL_P (i))
        break;
 
+      if (GET_CODE (PATTERN (i)) == SEQUENCE)
+       {
+         int idx;
+         rtx seq = PATTERN (i);
+
+         if (returnjump_p (XVECEXP (seq, 0, 0)))
+           break;
+         if (CALL_P (XVECEXP (seq, 0, 0))
+             && SIBLING_CALL_P (XVECEXP (seq, 0, 0)))
+           break;
+
+         for (idx = 0; idx < XVECLEN (seq, 0); idx++)
+           if (RTX_FRAME_RELATED_P (XVECEXP (seq, 0, idx)))
+             saw_frp = true;
+       }
+
       if (RTX_FRAME_RELATED_P (i))
        saw_frp = true;
     }
@@ -2755,10 +2862,7 @@ dwarf2out_begin_epilogue (rtx insn)
     }
   emit_note_before (NOTE_INSN_CFA_RESTORE_STATE, i);
 
-  /* Emit the state save.  */
-  cfi = new_cfi (); 
-  cfi->dw_cfi_opc = DW_CFA_remember_state;
-  add_fde_cfi (dwarf2out_cfi_label (false), cfi);
+  emit_cfa_remember = true;
 
   /* And emulate the state save.  */
   gcc_assert (!cfa_remember.in_use);
@@ -2771,7 +2875,7 @@ dwarf2out_begin_epilogue (rtx insn)
 void
 dwarf2out_frame_debug_restore_state (void)
 {
-  dw_cfi_ref cfi = new_cfi (); 
+  dw_cfi_ref cfi = new_cfi ();
   const char *label = dwarf2out_cfi_label (false);
 
   cfi->dw_cfi_opc = DW_CFA_restore_state;
@@ -2859,12 +2963,12 @@ dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
 
 #if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
 
-/* Switch to eh_frame_section.  If we don't have an eh_frame_section,
-   switch to the data section instead, and write out a synthetic label
-   for collect2.  */
+/* Switch [BACK] to eh_frame_section.  If we don't have an eh_frame_section,
+   switch to the data section instead, and write out a synthetic start label
+   for collect2 the first time around.  */
 
 static void
-switch_to_eh_frame_section (void)
+switch_to_eh_frame_section (bool back)
 {
   tree label;
 
@@ -2907,22 +3011,33 @@ switch_to_eh_frame_section (void)
       /* We have no special eh_frame section.  Put the information in
         the data section and emit special labels to guide collect2.  */
       switch_to_section (data_section);
-      label = get_file_function_name ("F");
-      ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
-      targetm.asm_out.globalize_label (asm_out_file,
-                                      IDENTIFIER_POINTER (label));
-      ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+
+      if (!back)
+       {
+         label = get_file_function_name ("F");
+         ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+         targetm.asm_out.globalize_label (asm_out_file,
+                                          IDENTIFIER_POINTER (label));
+         ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+       }
     }
 }
 
-/* Divide OFF by DWARF_CIE_DATA_ALIGNMENT, asserting no remainder.  */
+/* Switch [BACK] to the eh or debug frame table section, depending on
+   FOR_EH.  */
 
-static HOST_WIDE_INT
-div_data_align (HOST_WIDE_INT off)
+static void
+switch_to_frame_table_section (int for_eh, bool back)
 {
-  HOST_WIDE_INT r = off / DWARF_CIE_DATA_ALIGNMENT;
-  gcc_assert (r * DWARF_CIE_DATA_ALIGNMENT == off);
-  return r;
+  if (for_eh)
+    switch_to_eh_frame_section (back);
+  else
+    {
+      if (!debug_frame_section)
+       debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+                                          SECTION_DEBUG, NULL);
+      switch_to_section (debug_frame_section);
+    }
 }
 
 /* Output a Call Frame Information opcode and its operand(s).  */
@@ -3167,54 +3282,382 @@ output_cfi_directive (dw_cfi_ref cfi)
     }
 }
 
-/* Output the call frame information used to record information
-   that relates to calculating the frame pointer, and records the
-   location of saved registers.  */
+DEF_VEC_P (dw_cfi_ref);
+DEF_VEC_ALLOC_P (dw_cfi_ref, heap);
+
+/* Output CFIs to bring current FDE to the same state as after executing
+   CFIs in CFI chain.  DO_CFI_ASM is true if .cfi_* directives shall
+   be emitted, false otherwise.  If it is false, FDE and FOR_EH are the
+   other arguments to pass to output_cfi.  */
 
 static void
-output_call_frame_info (int for_eh)
+output_cfis (dw_cfi_ref cfi, bool do_cfi_asm, dw_fde_ref fde, bool for_eh)
 {
-  unsigned int i;
-  dw_fde_ref fde;
-  dw_cfi_ref cfi;
-  char l1[20], l2[20], section_start_label[20];
-  bool any_lsda_needed = false;
-  char augmentation[6];
-  int augmentation_size;
-  int fde_encoding = DW_EH_PE_absptr;
-  int per_encoding = DW_EH_PE_absptr;
-  int lsda_encoding = DW_EH_PE_absptr;
-  int return_reg;
+  struct dw_cfi_struct cfi_buf;
+  dw_cfi_ref cfi2;
+  dw_cfi_ref cfi_args_size = NULL, cfi_cfa = NULL, cfi_cfa_offset = NULL;
+  VEC (dw_cfi_ref, heap) *regs = VEC_alloc (dw_cfi_ref, heap, 32);
+  unsigned int len, idx;
 
-  /* Don't emit a CIE if there won't be any FDEs.  */
-  if (fde_table_in_use == 0)
-    return;
+  for (;; cfi = cfi->dw_cfi_next)
+    switch (cfi ? cfi->dw_cfi_opc : DW_CFA_nop)
+      {
+      case DW_CFA_advance_loc:
+      case DW_CFA_advance_loc1:
+      case DW_CFA_advance_loc2:
+      case DW_CFA_advance_loc4:
+      case DW_CFA_MIPS_advance_loc8:
+      case DW_CFA_set_loc:
+       /* All advances should be ignored.  */
+       break;
+      case DW_CFA_remember_state:
+       {
+         dw_cfi_ref args_size = cfi_args_size;
 
-  /* Nothing to do if the assembler's doing it all.  */
-  if (dwarf2out_do_cfi_asm ())
-    return;
+         /* Skip everything between .cfi_remember_state and
+            .cfi_restore_state.  */
+         for (cfi2 = cfi->dw_cfi_next; cfi2; cfi2 = cfi2->dw_cfi_next)
+           if (cfi2->dw_cfi_opc == DW_CFA_restore_state)
+             break;
+           else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size)
+             args_size = cfi2;
+           else
+             gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state);
 
-  /* If we make FDEs linkonce, we may have to emit an empty label for
-     an FDE that wouldn't otherwise be emitted.  We want to avoid
-     having an FDE kept around when the function it refers to is
-     discarded.  Example where this matters: a primary function
-     template in C++ requires EH information, but an explicit
-     specialization doesn't.  */
-  if (TARGET_USES_WEAK_UNWIND_INFO
-      && ! flag_asynchronous_unwind_tables
-      && flag_exceptions
-      && for_eh)
-    for (i = 0; i < fde_table_in_use; i++)
-      if ((fde_table[i].nothrow || fde_table[i].all_throwers_are_sibcalls)
-         && !fde_table[i].uses_eh_lsda
-         && ! DECL_WEAK (fde_table[i].decl))
-       targetm.asm_out.unwind_label (asm_out_file, fde_table[i].decl,
-                                     for_eh, /* empty */ 1);
+         if (cfi2 == NULL)
+           goto flush_all;
+         else
+           {
+             cfi = cfi2;
+             cfi_args_size = args_size;
+           }
+         break;
+       }
+      case DW_CFA_GNU_args_size:
+       cfi_args_size = cfi;
+       break;
+      case DW_CFA_GNU_window_save:
+       goto flush_all;
+      case DW_CFA_offset:
+      case DW_CFA_offset_extended:
+      case DW_CFA_offset_extended_sf:
+      case DW_CFA_restore:
+      case DW_CFA_restore_extended:
+      case DW_CFA_undefined:
+      case DW_CFA_same_value:
+      case DW_CFA_register:
+      case DW_CFA_val_offset:
+      case DW_CFA_val_offset_sf:
+      case DW_CFA_expression:
+      case DW_CFA_val_expression:
+      case DW_CFA_GNU_negative_offset_extended:
+       if (VEC_length (dw_cfi_ref, regs) <= cfi->dw_cfi_oprnd1.dw_cfi_reg_num)
+         VEC_safe_grow_cleared (dw_cfi_ref, heap, regs,
+                                cfi->dw_cfi_oprnd1.dw_cfi_reg_num + 1);
+       VEC_replace (dw_cfi_ref, regs, cfi->dw_cfi_oprnd1.dw_cfi_reg_num, cfi);
+       break;
+      case DW_CFA_def_cfa:
+      case DW_CFA_def_cfa_sf:
+      case DW_CFA_def_cfa_expression:
+       cfi_cfa = cfi;
+       cfi_cfa_offset = cfi;
+       break;
+      case DW_CFA_def_cfa_register:
+       cfi_cfa = cfi;
+       break;
+      case DW_CFA_def_cfa_offset:
+      case DW_CFA_def_cfa_offset_sf:
+       cfi_cfa_offset = cfi;
+       break;
+      case DW_CFA_nop:
+       gcc_assert (cfi == NULL);
+      flush_all:
+       len = VEC_length (dw_cfi_ref, regs);
+       for (idx = 0; idx < len; idx++)
+         {
+           cfi2 = VEC_replace (dw_cfi_ref, regs, idx, NULL);
+           if (cfi2 != NULL
+               && cfi2->dw_cfi_opc != DW_CFA_restore
+               && cfi2->dw_cfi_opc != DW_CFA_restore_extended)
+             {
+               if (do_cfi_asm)
+                 output_cfi_directive (cfi2);
+               else
+                 output_cfi (cfi2, fde, for_eh);
+             }
+         }
+       if (cfi_cfa && cfi_cfa_offset && cfi_cfa_offset != cfi_cfa)
+         {
+           gcc_assert (cfi_cfa->dw_cfi_opc != DW_CFA_def_cfa_expression);
+           cfi_buf = *cfi_cfa;
+           switch (cfi_cfa_offset->dw_cfi_opc)
+             {
+             case DW_CFA_def_cfa_offset:
+               cfi_buf.dw_cfi_opc = DW_CFA_def_cfa;
+               cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1;
+               break;
+             case DW_CFA_def_cfa_offset_sf:
+               cfi_buf.dw_cfi_opc = DW_CFA_def_cfa_sf;
+               cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1;
+               break;
+             case DW_CFA_def_cfa:
+             case DW_CFA_def_cfa_sf:
+               cfi_buf.dw_cfi_opc = cfi_cfa_offset->dw_cfi_opc;
+               cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd2;
+               break;
+             default:
+               gcc_unreachable ();
+             }
+           cfi_cfa = &cfi_buf;
+         }
+       else if (cfi_cfa_offset)
+         cfi_cfa = cfi_cfa_offset;
+       if (cfi_cfa)
+         {
+           if (do_cfi_asm)
+             output_cfi_directive (cfi_cfa);
+           else
+             output_cfi (cfi_cfa, fde, for_eh);
+         }
+       cfi_cfa = NULL;
+       cfi_cfa_offset = NULL;
+       if (cfi_args_size
+           && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset)
+         {
+           if (do_cfi_asm)
+             output_cfi_directive (cfi_args_size);
+           else
+             output_cfi (cfi_args_size, fde, for_eh);
+         }
+       cfi_args_size = NULL;
+       if (cfi == NULL)
+         {
+           VEC_free (dw_cfi_ref, heap, regs);
+           return;
+         }
+       else if (do_cfi_asm)
+         output_cfi_directive (cfi);
+       else
+         output_cfi (cfi, fde, for_eh);
+       break;
+      default:
+       gcc_unreachable ();
+    }
+}
 
-  /* If we don't have any functions we'll want to unwind out of, don't
-     emit any EH unwind information.  Note that if exceptions aren't
-     enabled, we won't have collected nothrow information, and if we
-     asked for asynchronous tables, we always want this info.  */
+/* Output one FDE.  */
+
+static void
+output_fde (dw_fde_ref fde, bool for_eh, bool second,
+           char *section_start_label, int fde_encoding, char *augmentation,
+           bool any_lsda_needed, int lsda_encoding)
+{
+  const char *begin, *end;
+  static unsigned int j;
+  char l1[20], l2[20];
+  dw_cfi_ref cfi;
+
+  targetm.asm_out.unwind_label (asm_out_file, fde->decl, for_eh,
+                               /* empty */ 0);
+  targetm.asm_out.internal_label (asm_out_file, FDE_LABEL,
+                                 for_eh + j);
+  ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + j);
+  ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + j);
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
+    dw2_asm_output_data (4, 0xffffffff, "Initial length escape value"
+                        " indicating 64-bit DWARF extension");
+  dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
+                       "FDE Length");
+  ASM_OUTPUT_LABEL (asm_out_file, l1);
+
+  if (for_eh)
+    dw2_asm_output_delta (4, l1, section_start_label, "FDE CIE offset");
+  else
+    dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label,
+                          debug_frame_section, "FDE CIE offset");
+
+  if (!fde->dw_fde_switched_sections)
+    {
+      begin = fde->dw_fde_begin;
+      end = fde->dw_fde_end;
+    }
+  else
+    {
+      /* For the first section, prefer dw_fde_begin over
+        dw_fde_{hot,cold}_section_label, as the latter
+        might be separated from the real start of the
+        function by alignment padding.  */
+      if (!second)
+       begin = fde->dw_fde_begin;
+      else if (fde->dw_fde_switched_cold_to_hot)
+       begin = fde->dw_fde_hot_section_label;
+      else
+       begin = fde->dw_fde_unlikely_section_label;
+      if (second ^ fde->dw_fde_switched_cold_to_hot)
+       end = fde->dw_fde_unlikely_section_end_label;
+      else
+       end = fde->dw_fde_hot_section_end_label;
+    }
+
+  if (for_eh)
+    {
+      rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, begin);
+      SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
+      dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref, false,
+                                      "FDE initial location");
+      dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+                           end, begin, "FDE address range");
+    }
+  else
+    {
+      dw2_asm_output_addr (DWARF2_ADDR_SIZE, begin, "FDE initial location");
+      dw2_asm_output_delta (DWARF2_ADDR_SIZE, end, begin, "FDE address range");
+    }
+
+  if (augmentation[0])
+    {
+      if (any_lsda_needed)
+       {
+         int size = size_of_encoded_value (lsda_encoding);
+
+         if (lsda_encoding == DW_EH_PE_aligned)
+           {
+             int offset = (  4         /* Length */
+                           + 4         /* CIE offset */
+                           + 2 * size_of_encoded_value (fde_encoding)
+                           + 1         /* Augmentation size */ );
+             int pad = -offset & (PTR_SIZE - 1);
+
+             size += pad;
+             gcc_assert (size_of_uleb128 (size) == 1);
+           }
+
+         dw2_asm_output_data_uleb128 (size, "Augmentation size");
+
+         if (fde->uses_eh_lsda)
+           {
+             ASM_GENERATE_INTERNAL_LABEL (l1, second ? "LLSDAC" : "LLSDA",
+                                          fde->funcdef_number);
+             dw2_asm_output_encoded_addr_rtx (lsda_encoding,
+                                              gen_rtx_SYMBOL_REF (Pmode, l1),
+                                              false,
+                                              "Language Specific Data Area");
+           }
+         else
+           {
+             if (lsda_encoding == DW_EH_PE_aligned)
+               ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+             dw2_asm_output_data (size_of_encoded_value (lsda_encoding), 0,
+                                  "Language Specific Data Area (none)");
+           }
+       }
+      else
+       dw2_asm_output_data_uleb128 (0, "Augmentation size");
+    }
+
+  /* Loop through the Call Frame Instructions associated with
+     this FDE.  */
+  fde->dw_fde_current_label = begin;
+  if (!fde->dw_fde_switched_sections)
+    for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
+      output_cfi (cfi, fde, for_eh);
+  else if (!second)
+    {
+      if (fde->dw_fde_switch_cfi)
+       for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
+         {
+           output_cfi (cfi, fde, for_eh);
+           if (cfi == fde->dw_fde_switch_cfi)
+             break;
+         }
+    }
+  else
+    {
+      dw_cfi_ref cfi_next = fde->dw_fde_cfi;
+
+      if (fde->dw_fde_switch_cfi)
+       {
+         cfi_next = fde->dw_fde_switch_cfi->dw_cfi_next;
+         fde->dw_fde_switch_cfi->dw_cfi_next = NULL;
+         output_cfis (fde->dw_fde_cfi, false, fde, for_eh);
+         fde->dw_fde_switch_cfi->dw_cfi_next = cfi_next;
+       }
+      for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next)
+       output_cfi (cfi, fde, for_eh);
+    }
+
+  /* If we are to emit a ref/link from function bodies to their frame tables,
+     do it now.  This is typically performed to make sure that tables
+     associated with functions are dragged with them and not discarded in
+     garbage collecting links. We need to do this on a per function basis to
+     cope with -ffunction-sections.  */
+
+#ifdef ASM_OUTPUT_DWARF_TABLE_REF
+  /* Switch to the function section, emit the ref to the tables, and
+     switch *back* into the table section.  */
+  switch_to_section (function_section (fde->decl));
+  ASM_OUTPUT_DWARF_TABLE_REF (section_start_label);
+  switch_to_frame_table_section (for_eh, true);
+#endif
+
+  /* Pad the FDE out to an address sized boundary.  */
+  ASM_OUTPUT_ALIGN (asm_out_file,
+                   floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
+  ASM_OUTPUT_LABEL (asm_out_file, l2);
+
+  j += 2;
+}
+
+/* Output the call frame information used to record information
+   that relates to calculating the frame pointer, and records the
+   location of saved registers.  */
+
+static void
+output_call_frame_info (int for_eh)
+{
+  unsigned int i;
+  dw_fde_ref fde;
+  dw_cfi_ref cfi;
+  char l1[20], l2[20], section_start_label[20];
+  bool any_lsda_needed = false;
+  char augmentation[6];
+  int augmentation_size;
+  int fde_encoding = DW_EH_PE_absptr;
+  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.  */
+  if (fde_table_in_use == 0)
+    return;
+
+  /* Nothing to do if the assembler's doing it all.  */
+  if (dwarf2out_do_cfi_asm ())
+    return;
+
+  /* If we make FDEs linkonce, we may have to emit an empty label for
+     an FDE that wouldn't otherwise be emitted.  We want to avoid
+     having an FDE kept around when the function it refers to is
+     discarded.  Example where this matters: a primary function
+     template in C++ requires EH information, but an explicit
+     specialization doesn't.  */
+  if (TARGET_USES_WEAK_UNWIND_INFO
+      && ! flag_asynchronous_unwind_tables
+      && flag_exceptions
+      && for_eh)
+    for (i = 0; i < fde_table_in_use; i++)
+      if ((fde_table[i].nothrow || fde_table[i].all_throwers_are_sibcalls)
+         && !fde_table[i].uses_eh_lsda
+         && ! DECL_WEAK (fde_table[i].decl))
+       targetm.asm_out.unwind_label (asm_out_file, fde_table[i].decl,
+                                     for_eh, /* empty */ 1);
+
+  /* If we don't have any functions we'll want to unwind out of, don't
+     emit any EH unwind information.  Note that if exceptions aren't
+     enabled, we won't have collected nothrow information, and if we
+     asked for asynchronous tables, we always want this info.  */
   if (for_eh)
     {
       bool any_eh_needed = !flag_exceptions || flag_asynchronous_unwind_tables;
@@ -3236,15 +3679,8 @@ output_call_frame_info (int for_eh)
   if (flag_debug_asm)
     app_enable ();
 
-  if (for_eh)
-    switch_to_eh_frame_section ();
-  else
-    {
-      if (!debug_frame_section)
-       debug_frame_section = get_section (DEBUG_FRAME_SECTION,
-                                          SECTION_DEBUG, NULL);
-      switch_to_section (debug_frame_section);
-    }
+  /* Switch to the proper frame section, first time.  */
+  switch_to_frame_table_section (for_eh, false);
 
   ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
   ASM_OUTPUT_LABEL (asm_out_file, section_start_label);
@@ -3265,10 +3701,19 @@ output_call_frame_info (int for_eh)
                       (for_eh ? 0 : DWARF_CIE_ID),
                       "CIE Identifier Tag");
 
-  dw2_asm_output_data (1, DW_CIE_VERSION, "CIE Version");
+  /* Use the CIE version 3 for DWARF3; allow DWARF2 to continue to
+     use CIE version 1, unless that would produce incorrect results
+     due to overflowing the return register column.  */
+  return_reg = DWARF2_FRAME_REG_OUT (DWARF_FRAME_RETURN_COLUMN, for_eh);
+  dw_cie_version = 1;
+  if (return_reg >= 256 || dwarf_version > 2)
+    dw_cie_version = 3;
+  dw2_asm_output_data (1, dw_cie_version, "CIE Version");
 
   augmentation[0] = 0;
   augmentation_size = 0;
+
+  personality = current_unit_personality;
   if (for_eh)
     {
       char *p;
@@ -3288,11 +3733,11 @@ output_call_frame_info (int for_eh)
       lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
 
       p = augmentation + 1;
-      if (eh_personality_libfunc)
+      if (personality)
        {
          *p++ = 'P';
          augmentation_size += 1 + size_of_encoded_value (per_encoding);
-         assemble_external_libcall (eh_personality_libfunc);
+         assemble_external_libcall (personality);
        }
       if (any_lsda_needed)
        {
@@ -3311,7 +3756,7 @@ output_call_frame_info (int for_eh)
        }
 
       /* Ug.  Some platforms can't do unaligned dynamic relocations at all.  */
-      if (eh_personality_libfunc && per_encoding == DW_EH_PE_aligned)
+      if (personality && per_encoding == DW_EH_PE_aligned)
        {
          int offset = (  4             /* Length */
                        + 4             /* CIE Id */
@@ -3337,8 +3782,7 @@ output_call_frame_info (int for_eh)
   dw2_asm_output_data_sleb128 (DWARF_CIE_DATA_ALIGNMENT,
                               "CIE Data Alignment Factor");
 
-  return_reg = DWARF2_FRAME_REG_OUT (DWARF_FRAME_RETURN_COLUMN, for_eh);
-  if (DW_CIE_VERSION == 1)
+  if (dw_cie_version == 1)
     dw2_asm_output_data (1, return_reg, "CIE RA Column");
   else
     dw2_asm_output_data_uleb128 (return_reg, "CIE RA Column");
@@ -3346,12 +3790,12 @@ output_call_frame_info (int for_eh)
   if (augmentation[0])
     {
       dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size");
-      if (eh_personality_libfunc)
+      if (personality)
        {
          dw2_asm_output_data (1, per_encoding, "Personality (%s)",
                               eh_data_format_name (per_encoding));
          dw2_asm_output_encoded_addr_rtx (per_encoding,
-                                          eh_personality_libfunc,
+                                          personality,
                                           true, NULL);
        }
 
@@ -3375,6 +3819,7 @@ output_call_frame_info (int for_eh)
   /* Loop through all of the FDE's.  */
   for (i = 0; i < fde_table_in_use; i++)
     {
+      unsigned int k;
       fde = &fde_table[i];
 
       /* Don't emit EH unwind info for leaf functions that don't need it.  */
@@ -3384,139 +3829,9 @@ output_call_frame_info (int for_eh)
          && !fde->uses_eh_lsda)
        continue;
 
-      targetm.asm_out.unwind_label (asm_out_file, fde->decl, for_eh, /* empty */ 0);
-      targetm.asm_out.internal_label (asm_out_file, FDE_LABEL, for_eh + i * 2);
-      ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i * 2);
-      ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i * 2);
-      if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
-       dw2_asm_output_data (4, 0xffffffff,
-                            "Initial length escape value indicating 64-bit DWARF extension");
-      dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
-                           "FDE Length");
-      ASM_OUTPUT_LABEL (asm_out_file, l1);
-
-      if (for_eh)
-       dw2_asm_output_delta (4, l1, section_start_label, "FDE CIE offset");
-      else
-       dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label,
-                              debug_frame_section, "FDE CIE offset");
-
-      if (for_eh)
-       {
-         if (fde->dw_fde_switched_sections)
-           {
-             rtx sym_ref2 = gen_rtx_SYMBOL_REF (Pmode,
-                                     fde->dw_fde_unlikely_section_label);
-             rtx sym_ref3= gen_rtx_SYMBOL_REF (Pmode,
-                                     fde->dw_fde_hot_section_label);
-             SYMBOL_REF_FLAGS (sym_ref2) |= SYMBOL_FLAG_LOCAL;
-             SYMBOL_REF_FLAGS (sym_ref3) |= SYMBOL_FLAG_LOCAL;
-             dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref3, false,
-                                              "FDE initial location");
-             dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
-                                   fde->dw_fde_hot_section_end_label,
-                                   fde->dw_fde_hot_section_label,
-                                   "FDE address range");
-             dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref2, false,
-                                              "FDE initial location");
-             dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
-                                   fde->dw_fde_unlikely_section_end_label,
-                                   fde->dw_fde_unlikely_section_label,
-                                   "FDE address range");
-           }
-         else
-           {
-             rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, fde->dw_fde_begin);
-             SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
-             dw2_asm_output_encoded_addr_rtx (fde_encoding,
-                                              sym_ref,
-                                              false,
-                                              "FDE initial location");
-             dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
-                                   fde->dw_fde_end, fde->dw_fde_begin,
-                                   "FDE address range");
-           }
-       }
-      else
-       {
-         if (fde->dw_fde_switched_sections)
-           {
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE,
-                                  fde->dw_fde_hot_section_label,
-                                  "FDE initial location");
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE,
-                                   fde->dw_fde_hot_section_end_label,
-                                   fde->dw_fde_hot_section_label,
-                                   "FDE address range");
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE,
-                                  fde->dw_fde_unlikely_section_label,
-                                  "FDE initial location");
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE,
-                                   fde->dw_fde_unlikely_section_end_label,
-                                   fde->dw_fde_unlikely_section_label,
-                                   "FDE address range");
-           }
-         else
-           {
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin,
-                                  "FDE initial location");
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE,
-                                   fde->dw_fde_end, fde->dw_fde_begin,
-                                   "FDE address range");
-           }
-       }
-
-      if (augmentation[0])
-       {
-         if (any_lsda_needed)
-           {
-             int size = size_of_encoded_value (lsda_encoding);
-
-             if (lsda_encoding == DW_EH_PE_aligned)
-               {
-                 int offset = (  4             /* Length */
-                               + 4             /* CIE offset */
-                               + 2 * size_of_encoded_value (fde_encoding)
-                               + 1             /* Augmentation size */ );
-                 int pad = -offset & (PTR_SIZE - 1);
-
-                 size += pad;
-                 gcc_assert (size_of_uleb128 (size) == 1);
-               }
-
-             dw2_asm_output_data_uleb128 (size, "Augmentation size");
-
-             if (fde->uses_eh_lsda)
-               {
-                 ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
-                                              fde->funcdef_number);
-                 dw2_asm_output_encoded_addr_rtx (
-                       lsda_encoding, gen_rtx_SYMBOL_REF (Pmode, l1),
-                       false, "Language Specific Data Area");
-               }
-             else
-               {
-                 if (lsda_encoding == DW_EH_PE_aligned)
-                   ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
-                 dw2_asm_output_data
-                   (size_of_encoded_value (lsda_encoding), 0,
-                    "Language Specific Data Area (none)");
-               }
-           }
-         else
-           dw2_asm_output_data_uleb128 (0, "Augmentation size");
-       }
-
-      /* Loop through the Call Frame Instructions associated with
-        this FDE.  */
-      fde->dw_fde_current_label = fde->dw_fde_begin;
-      for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
-       output_cfi (cfi, fde, for_eh);
-
-      /* Pad the FDE out to an address sized boundary.  */
-      ASM_OUTPUT_ALIGN (asm_out_file,
-                       floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
-      ASM_OUTPUT_LABEL (asm_out_file, l2);
+      for (k = 0; k < (fde->dw_fde_switched_sections ? 2 : 1); k++)
+       output_fde (fde, for_eh, k, section_start_label, fde_encoding,
+                   augmentation, any_lsda_needed, lsda_encoding);
     }
 
   if (for_eh && targetm.terminate_dw2_eh_frame_info)
@@ -3532,6 +3847,53 @@ output_call_frame_info (int for_eh)
     app_disable ();
 }
 
+/* Emit .cfi_startproc and .cfi_personality/.cfi_lsda if needed.  */
+
+static void
+dwarf2out_do_cfi_startproc (bool second)
+{
+  int enc;
+  rtx ref;
+  rtx personality = get_personality_function (current_function_decl);
+
+  fprintf (asm_out_file, "\t.cfi_startproc\n");
+
+  if (personality)
+    {
+      enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
+      ref = personality;
+
+      /* ??? The GAS support isn't entirely consistent.  We have to
+        handle indirect support ourselves, but PC-relative is done
+        in the assembler.  Further, the assembler can't handle any
+        of the weirder relocation types.  */
+      if (enc & DW_EH_PE_indirect)
+       ref = dw2_force_const_mem (ref, true);
+
+      fprintf (asm_out_file, "\t.cfi_personality 0x%x,", enc);
+      output_addr_const (asm_out_file, ref);
+      fputc ('\n', asm_out_file);
+    }
+
+  if (crtl->uses_eh_lsda)
+    {
+      char lab[20];
+
+      enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
+      ASM_GENERATE_INTERNAL_LABEL (lab, second ? "LLSDAC" : "LLSDA",
+                                  current_function_funcdef_no);
+      ref = gen_rtx_SYMBOL_REF (Pmode, lab);
+      SYMBOL_REF_FLAGS (ref) = SYMBOL_FLAG_LOCAL;
+
+      if (enc & DW_EH_PE_indirect)
+       ref = dw2_force_const_mem (ref, true);
+
+      fprintf (asm_out_file, "\t.cfi_lsda 0x%x,", enc);
+      output_addr_const (asm_out_file, ref);
+      fputc ('\n', asm_out_file);
+    }
+}
+
 /* Output a marker (i.e. a label) for the beginning of a function, before
    the prologue.  */
 
@@ -3542,6 +3904,7 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
   char * dup_label;
   dw_fde_ref fde;
+  section *fnsec;
 
   current_function_func_begin_label = NULL;
 
@@ -3557,7 +3920,8 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
     return;
 #endif
 
-  switch_to_section (function_section (current_function_decl));
+  fnsec = function_section (current_function_decl);
+  switch_to_section (fnsec);
   ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
                               current_function_funcdef_no);
   ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
@@ -3592,15 +3956,38 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   fde->dw_fde_hot_section_end_label = NULL;
   fde->dw_fde_unlikely_section_label = NULL;
   fde->dw_fde_unlikely_section_end_label = NULL;
-  fde->dw_fde_switched_sections = false;
+  fde->dw_fde_switched_sections = 0;
+  fde->dw_fde_switched_cold_to_hot = 0;
   fde->dw_fde_end = NULL;
   fde->dw_fde_cfi = NULL;
+  fde->dw_fde_switch_cfi = NULL;
   fde->funcdef_number = current_function_funcdef_no;
   fde->nothrow = crtl->nothrow;
   fde->uses_eh_lsda = crtl->uses_eh_lsda;
   fde->all_throwers_are_sibcalls = crtl->all_throwers_are_sibcalls;
   fde->drap_reg = INVALID_REGNUM;
   fde->vdrap_reg = INVALID_REGNUM;
+  if (flag_reorder_blocks_and_partition)
+    {
+      section *unlikelysec;
+      if (first_function_block_is_cold)
+       fde->in_std_section = 1;
+      else
+       fde->in_std_section
+         = (fnsec == text_section
+            || (cold_text_section && fnsec == cold_text_section));
+      unlikelysec = unlikely_text_section ();
+      fde->cold_in_std_section
+       = (unlikelysec == text_section
+          || (cold_text_section && unlikelysec == cold_text_section));
+    }
+  else
+    {
+      fde->in_std_section
+       = (fnsec == text_section
+          || (cold_text_section && fnsec == cold_text_section));
+      fde->cold_in_std_section = 0;
+    }
 
   args_size = old_args_size = 0;
 
@@ -3608,50 +3995,24 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
      prologue case, not the eh frame case.  */
 #ifdef DWARF2_DEBUGGING_INFO
   if (file)
-    dwarf2out_source_line (line, file, 0);
+    dwarf2out_source_line (line, file, 0, true);
 #endif
 
   if (dwarf2out_do_cfi_asm ())
+    dwarf2out_do_cfi_startproc (false);
+  else
     {
-      int enc;
-      rtx ref;
-
-      fprintf (asm_out_file, "\t.cfi_startproc\n");
-
-      if (eh_personality_libfunc)
-       {
-         enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1); 
-         ref = eh_personality_libfunc;
-
-         /* ??? The GAS support isn't entirely consistent.  We have to
-            handle indirect support ourselves, but PC-relative is done
-            in the assembler.  Further, the assembler can't handle any
-            of the weirder relocation types.  */
-         if (enc & DW_EH_PE_indirect)
-           ref = dw2_force_const_mem (ref, true);
-
-         fprintf (asm_out_file, "\t.cfi_personality 0x%x,", enc);
-         output_addr_const (asm_out_file, ref);
-         fputc ('\n', asm_out_file);
-       }
-
-      if (crtl->uses_eh_lsda)
-       {
-         char lab[20];
-
-         enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
-         ASM_GENERATE_INTERNAL_LABEL (lab, "LLSDA",
-                                      current_function_funcdef_no);
-         ref = gen_rtx_SYMBOL_REF (Pmode, lab);
-         SYMBOL_REF_FLAGS (ref) = SYMBOL_FLAG_LOCAL;
-
-         if (enc & DW_EH_PE_indirect)
-           ref = dw2_force_const_mem (ref, true);
+      rtx personality = get_personality_function (current_function_decl);
+      if (!current_unit_personality)
+        current_unit_personality = personality;
 
-         fprintf (asm_out_file, "\t.cfi_lsda 0x%x,", enc);
-         output_addr_const (asm_out_file, ref);
-         fputc ('\n', asm_out_file);
-       }
+      /* 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.");
     }
 }
 
@@ -3666,6 +4027,10 @@ dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
   dw_fde_ref fde;
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
+#ifdef DWARF2_DEBUGGING_INFO
+  last_var_location_insn = NULL_RTX;
+#endif
+
   if (dwarf2out_do_cfi_asm ())
     fprintf (asm_out_file, "\t.cfi_endproc\n");
 
@@ -3730,9 +4095,11 @@ dwarf2out_switch_text_section (void)
 {
   dw_fde_ref fde = current_fde ();
 
-  gcc_assert (cfun && fde);
+  gcc_assert (cfun && fde && !fde->dw_fde_switched_sections);
+
+  fde->dw_fde_switched_sections = 1;
+  fde->dw_fde_switched_cold_to_hot = !in_cold_section_p;
 
-  fde->dw_fde_switched_sections = true;
   fde->dw_fde_hot_section_label = crtl->subsections.hot_section_label;
   fde->dw_fde_hot_section_end_label = crtl->subsections.hot_section_end_label;
   fde->dw_fde_unlikely_section_label = crtl->subsections.cold_section_label;
@@ -3746,6 +4113,30 @@ dwarf2out_switch_text_section (void)
   /* There is no need to mark used sections when not debugging.  */
   if (cold_text_section != NULL)
     dwarf2out_note_section_used ();
+
+  if (dwarf2out_do_cfi_asm ())
+    fprintf (asm_out_file, "\t.cfi_endproc\n");
+
+  /* Now do the real section switch.  */
+  switch_to_section (current_function_section ());
+
+  if (dwarf2out_do_cfi_asm ())
+    {
+      dwarf2out_do_cfi_startproc (true);
+      /* As this is a different FDE, insert all current CFI instructions
+        again.  */
+      output_cfis (fde->dw_fde_cfi, true, fde, true);
+    }
+  else
+    {
+      dw_cfi_ref cfi = fde->dw_fde_cfi;
+
+      cfi = fde->dw_fde_cfi;
+      if (cfi)
+       while (cfi->dw_cfi_next != NULL)
+         cfi = cfi->dw_cfi_next;
+      fde->dw_fde_switch_cfi = cfi;
+    }
 }
 #endif
 \f
@@ -3758,11 +4149,6 @@ struct GTY(()) dwarf_file_data {
   int emitted_number;
 };
 
-/* We need some way to distinguish DW_OP_addr with a direct symbol
-   relocation from DW_OP_addr with a dtp-relative symbol relocation.  */
-#define INTERNAL_DW_OP_tls_addr                (0x100 + DW_OP_addr)
-
-
 typedef struct dw_val_struct *dw_val_ref;
 typedef struct die_struct *dw_die_ref;
 typedef const struct die_struct *const_dw_die_ref;
@@ -3780,6 +4166,9 @@ DEF_VEC_ALLOC_O(deferred_locations,gc);
 
 static GTY(()) VEC(deferred_locations, gc) *deferred_locations_list;
 
+DEF_VEC_P(dw_die_ref);
+DEF_VEC_ALLOC_P(dw_die_ref,heap);
+
 /* Each DIE may have a series of attribute/value pairs.  Values
    can take on several forms.  The forms that are used in this
    implementation are listed below.  */
@@ -3793,7 +4182,7 @@ enum dw_val_class
   dw_val_class_range_list,
   dw_val_class_const,
   dw_val_class_unsigned_const,
-  dw_val_class_long_long,
+  dw_val_class_const_double,
   dw_val_class_vec,
   dw_val_class_flag,
   dw_val_class_die_ref,
@@ -3802,18 +4191,10 @@ enum dw_val_class
   dw_val_class_lineptr,
   dw_val_class_str,
   dw_val_class_macptr,
-  dw_val_class_file
+  dw_val_class_file,
+  dw_val_class_data8
 };
 
-/* Describe a double word constant value.  */
-/* ??? Every instance of long_long in the code really means CONST_DOUBLE.  */
-
-typedef struct GTY(()) dw_long_long_struct {
-  unsigned long hi;
-  unsigned long low;
-}
-dw_long_long_const;
-
 /* Describe a floating point constant value, or a vector constant value.  */
 
 typedef struct GTY(()) dw_vec_struct {
@@ -3836,7 +4217,7 @@ typedef struct GTY(()) dw_val_struct {
       dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
       HOST_WIDE_INT GTY ((default)) val_int;
       unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
-      dw_long_long_const GTY ((tag ("dw_val_class_long_long"))) val_long_long;
+      double_int GTY ((tag ("dw_val_class_const_double"))) val_double;
       dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
       struct dw_val_die_union
        {
@@ -3848,6 +4229,7 @@ typedef struct GTY(()) dw_val_struct {
       char * GTY ((tag ("dw_val_class_lbl_id"))) val_lbl_id;
       unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag;
       struct dwarf_file_data * GTY ((tag ("dw_val_class_file"))) val_file;
+      unsigned char GTY ((tag ("dw_val_class_data8"))) val_data8[8];
     }
   GTY ((desc ("%1.val_class"))) v;
 }
@@ -3858,7 +4240,10 @@ dw_val_node;
 
 typedef struct GTY(()) dw_loc_descr_struct {
   dw_loc_descr_ref dw_loc_next;
-  enum dwarf_location_atom dw_loc_opc;
+  ENUM_BITFIELD (dwarf_location_atom) dw_loc_opc : 8;
+  /* Used to distinguish DW_OP_addr with a direct symbol relocation
+     from DW_OP_addr with a dtp-relative symbol relocation.  */
+  unsigned int dtprel : 1;
   int dw_loc_addr;
   dw_val_node dw_loc_oprnd1;
   dw_val_node dw_loc_oprnd2;
@@ -3890,7 +4275,6 @@ dwarf_stack_op_name (unsigned int op)
   switch (op)
     {
     case DW_OP_addr:
-    case INTERNAL_DW_OP_tls_addr:
       return "DW_OP_addr";
     case DW_OP_deref:
       return "DW_OP_deref";
@@ -4180,6 +4564,7 @@ dwarf_stack_op_name (unsigned int op)
       return "DW_OP_xderef_size";
     case DW_OP_nop:
       return "DW_OP_nop";
+
     case DW_OP_push_object_address:
       return "DW_OP_push_object_address";
     case DW_OP_call2:
@@ -4188,10 +4573,24 @@ 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:
+      return "DW_OP_call_frame_cfa";
+    case DW_OP_bit_piece:
+      return "DW_OP_bit_piece";
+
     case DW_OP_GNU_push_tls_address:
       return "DW_OP_GNU_push_tls_address";
     case DW_OP_GNU_uninit:
       return "DW_OP_GNU_uninit";
+    case DW_OP_GNU_encoded_addr:
+      return "DW_OP_GNU_encoded_addr";
+
     default:
       return "OP_<unknown>";
     }
@@ -4284,6 +4683,18 @@ loc_descr_plus_const (dw_loc_descr_ref *list_head, HOST_WIDE_INT offset)
     }
 }
 
+#ifdef DWARF2_DEBUGGING_INFO
+/* Add a constant OFFSET to a location list.  */
+
+static void
+loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset)
+{
+  dw_loc_list_ref d;
+  for (d = list_head; d != NULL; d = d->dw_loc_next)
+    loc_descr_plus_const (&d->expr, offset);
+}
+#endif
+
 /* Return the size of a location descriptor.  */
 
 static unsigned long
@@ -4294,7 +4705,6 @@ size_of_loc_descr (dw_loc_descr_ref loc)
   switch (loc->dw_loc_opc)
     {
     case DW_OP_addr:
-    case INTERNAL_DW_OP_tls_addr:
       size += DWARF2_ADDR_SIZE;
       break;
     case DW_OP_const1u:
@@ -4389,6 +4799,10 @@ size_of_loc_descr (dw_loc_descr_ref loc)
     case DW_OP_call_ref:
       size += DWARF2_ADDR_SIZE;
       break;
+    case DW_OP_implicit_value:
+      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned)
+             + loc->dw_loc_oprnd1.v.val_unsigned;
+      break;
     default:
       break;
     }
@@ -4424,6 +4838,10 @@ size_of_locs (dw_loc_descr_ref loc)
   return size;
 }
 
+#ifdef DWARF2_DEBUGGING_INFO
+static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
+#endif
+
 /* Output location description stack opcode's operands (if any).  */
 
 static void
@@ -4435,9 +4853,6 @@ output_loc_operands (dw_loc_descr_ref loc)
   switch (loc->dw_loc_opc)
     {
 #ifdef DWARF2_DEBUGGING_INFO
-    case DW_OP_addr:
-      dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val1->v.val_addr, NULL);
-      break;
     case DW_OP_const2u:
     case DW_OP_const2s:
       dw2_asm_output_data (2, val1->v.val_int, NULL);
@@ -4448,7 +4863,7 @@ output_loc_operands (dw_loc_descr_ref loc)
       break;
     case DW_OP_const8u:
     case DW_OP_const8s:
-      gcc_assert (HOST_BITS_PER_LONG >= 64);
+      gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
       dw2_asm_output_data (8, val1->v.val_int, NULL);
       break;
     case DW_OP_skip:
@@ -4462,16 +4877,70 @@ output_loc_operands (dw_loc_descr_ref loc)
        dw2_asm_output_data (2, offset, NULL);
       }
       break;
-#else
-    case DW_OP_addr:
-    case DW_OP_const2u:
-    case DW_OP_const2s:
+    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:
     case DW_OP_const4u:
     case DW_OP_const4s:
     case DW_OP_const8u:
     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
@@ -4546,16 +5015,27 @@ output_loc_operands (dw_loc_descr_ref loc)
       dw2_asm_output_data (1, val1->v.val_int, NULL);
       break;
 
-    case INTERNAL_DW_OP_tls_addr:
-      if (targetm.asm_out.output_dwarf_dtprel)
+    case DW_OP_addr:
+      if (loc->dtprel)
        {
-         targetm.asm_out.output_dwarf_dtprel (asm_out_file,
-                                              DWARF2_ADDR_SIZE,
-                                              val1->v.val_addr);
-         fputc ('\n', asm_out_file);
+         if (targetm.asm_out.output_dwarf_dtprel)
+           {
+             targetm.asm_out.output_dwarf_dtprel (asm_out_file,
+                                                  DWARF2_ADDR_SIZE,
+                                                  val1->v.val_addr);
+             fputc ('\n', asm_out_file);
+           }
+         else
+           gcc_unreachable ();
        }
       else
-       gcc_unreachable ();
+       {
+#ifdef DWARF2_DEBUGGING_INFO
+         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val1->v.val_addr, NULL);
+#else
+         gcc_unreachable ();
+#endif
+       }
       break;
 
     default:
@@ -4592,6 +5072,7 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
   switch (loc->dw_loc_opc)
     {
     case DW_OP_addr:
+    case DW_OP_implicit_value:
       /* We cannot output addresses in .cfi_escape, only bytes.  */
       gcc_unreachable ();
 
@@ -4618,7 +5099,7 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
 
     case DW_OP_const8u:
     case DW_OP_const8s:
-      gcc_assert (HOST_BITS_PER_LONG >= 64);
+      gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
       fputc (',', asm_out_file);
       dw2_asm_output_data_raw (8, val1->v.val_int);
       break;
@@ -4689,9 +5170,6 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
       dw2_asm_output_data_sleb128_raw (val2->v.val_int);
       break;
 
-    case INTERNAL_DW_OP_tls_addr:
-      gcc_unreachable ();
-
     default:
       /* Other codes have no operands.  */
       break;
@@ -4926,6 +5404,7 @@ static int output_indirect_string (void **, void *);
 
 static void dwarf2out_init (const char *);
 static void dwarf2out_finish (const char *);
+static void dwarf2out_assembly_start (void);
 static void dwarf2out_define (unsigned int, const char *);
 static void dwarf2out_undef (unsigned int, const char *);
 static void dwarf2out_start_source_file (unsigned, const char *);
@@ -4940,6 +5419,10 @@ static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
                                                 dw_die_ref);
 static void dwarf2out_abstract_function (tree);
 static void dwarf2out_var_location (rtx);
+static void dwarf2out_direct_call (tree);
+static void dwarf2out_virtual_call_token (tree, int);
+static void dwarf2out_copy_call_info (rtx, rtx);
+static void dwarf2out_virtual_call (int);
 static void dwarf2out_begin_function (tree);
 static void dwarf2out_set_name (tree, tree);
 
@@ -4949,6 +5432,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
 {
   dwarf2out_init,
   dwarf2out_finish,
+  dwarf2out_assembly_start,
   dwarf2out_define,
   dwarf2out_undef,
   dwarf2out_start_source_file,
@@ -4975,6 +5459,10 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   debug_nothing_int,           /* handle_pch */
   dwarf2out_var_location,
   dwarf2out_switch_text_section,
+  dwarf2out_direct_call,
+  dwarf2out_virtual_call_token,
+  dwarf2out_copy_call_info,
+  dwarf2out_virtual_call,
   dwarf2out_set_name,
   1                             /* start_end_main_source_file */
 };
@@ -5002,6 +5490,7 @@ typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref;
 typedef struct pubname_struct *pubname_ref;
 typedef struct dw_ranges_struct *dw_ranges_ref;
 typedef struct dw_ranges_by_label_struct *dw_ranges_by_label_ref;
+typedef struct comdat_type_struct *comdat_type_node_ref;
 
 /* Each entry in the line_info_table maintains the file and
    line number associated with the label generated for that
@@ -5042,7 +5531,12 @@ DEF_VEC_ALLOC_O(dw_attr_node,gc);
 
 typedef struct GTY((chain_circular ("%h.die_sib"))) die_struct {
   enum dwarf_tag die_tag;
-  char *die_symbol;
+  union die_symbol_or_type_node
+    {
+      char * GTY ((tag ("0"))) die_symbol;
+      comdat_type_node_ref GTY ((tag ("1"))) die_type_node;
+    }
+  GTY ((desc ("dwarf_version >= 4"))) die_id;
   VEC(dw_attr_node,gc) * die_attr;
   dw_die_ref die_parent;
   dw_die_ref die_child;
@@ -5088,6 +5582,16 @@ struct GTY(()) dw_ranges_by_label_struct {
   const char *end;
 };
 
+/* The comdat type node structure.  */
+typedef struct GTY(()) comdat_type_struct
+{
+  dw_die_ref root_die;
+  dw_die_ref type_die;
+  char signature[DWARF_TYPE_SIGNATURE_SIZE];
+  struct comdat_type_struct *next;
+}
+comdat_type_node;
+
 /* The limbo die list structure.  */
 typedef struct GTY(()) limbo_die_struct {
   dw_die_ref die;
@@ -5096,6 +5600,14 @@ typedef struct GTY(()) limbo_die_struct {
 }
 limbo_die_node;
 
+typedef struct GTY(()) skeleton_chain_struct
+{
+  dw_die_ref old_die;
+  dw_die_ref new_die;
+  struct skeleton_chain_struct *parent;
+}
+skeleton_chain_node;
+
 /* How to start an assembler comment.  */
 #ifndef ASM_COMMENT_START
 #define ASM_COMMENT_START ";#"
@@ -5129,6 +5641,11 @@ limbo_die_node;
 #define DWARF_COMPILE_UNIT_HEADER_SIZE \
   (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 3)
 
+/* Fixed size portion of the DWARF comdat type unit header.  */
+#define DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE \
+  (DWARF_COMPILE_UNIT_HEADER_SIZE + DWARF_TYPE_SIGNATURE_SIZE \
+   + DWARF_OFFSET_SIZE)
+
 /* Fixed size portion of public names info.  */
 #define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
 
@@ -5179,6 +5696,9 @@ static unsigned long next_die_offset;
 /* Record the root of the DIE's built for the current compilation unit.  */
 static GTY(()) dw_die_ref comp_unit_die;
 
+/* A list of type DIEs that have been separated into comdat sections.  */
+static GTY(()) comdat_type_node *comdat_type_list;
+
 /* A list of DIEs with a NULL parent waiting to be relocated.  */
 static GTY(()) limbo_die_node *limbo_die_list;
 
@@ -5198,6 +5718,14 @@ static GTY ((param_is (struct die_struct))) htab_t decl_die_table;
    The key is DECL_UID() ^ die_parent.  */
 static GTY ((param_is (struct die_struct))) htab_t common_block_die_table;
 
+typedef struct GTY(()) die_arg_entry_struct {
+    dw_die_ref die;
+    tree arg;
+} die_arg_entry;
+
+DEF_VEC_O(die_arg_entry);
+DEF_VEC_ALLOC_O(die_arg_entry,gc);
+
 /* Node of the variable location list.  */
 struct GTY ((chain_next ("%h.next"))) var_loc_node {
   rtx GTY (()) var_loc_note;
@@ -5315,6 +5843,45 @@ static GTY(()) bool have_location_lists;
 /* Unique label counter.  */
 static GTY(()) unsigned int loclabel_num;
 
+/* Unique label counter for point-of-call tables.  */
+static GTY(()) unsigned int poc_label_num;
+
+/* The direct call table structure.  */
+
+typedef struct GTY(()) dcall_struct {
+  unsigned int poc_label_num;
+  tree poc_decl;
+  dw_die_ref targ_die;
+}
+dcall_entry;
+
+DEF_VEC_O(dcall_entry);
+DEF_VEC_ALLOC_O(dcall_entry, gc);
+
+/* The virtual call table structure.  */
+
+typedef struct GTY(()) vcall_struct {
+  unsigned int poc_label_num;
+  unsigned int vtable_slot;
+}
+vcall_entry;
+
+DEF_VEC_O(vcall_entry);
+DEF_VEC_ALLOC_O(vcall_entry, gc);
+
+/* Pointers to the direct and virtual call tables.  */
+static GTY (()) VEC (dcall_entry, gc) * dcall_table = NULL;
+static GTY (()) VEC (vcall_entry, gc) * vcall_table = NULL;
+
+/* A hash table to map INSN_UIDs to vtable slot indexes.  */
+
+struct GTY (()) vcall_insn {
+  int insn_uid;
+  unsigned int vtable_slot;
+};
+
+static GTY ((param_is (struct vcall_insn))) htab_t vcall_insn_table;
+
 #ifdef DWARF2_DEBUGGING_INFO
 /* Record whether the function being analyzed contains inlined functions.  */
 static int current_function_has_inlines;
@@ -5332,6 +5899,8 @@ static GTY(()) int label_num;
 /* Cached result of previous call to lookup_filename.  */
 static GTY(()) struct dwarf_file_data * file_table_last_lookup;
 
+static GTY(()) VEC(die_arg_entry,gc) *tmpl_value_parm_die_table;
+
 #ifdef DWARF2_DEBUGGING_INFO
 
 /* Offset from the "steady-state frame pointer" to the frame base,
@@ -5356,10 +5925,11 @@ static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
 static inline HOST_WIDE_INT AT_int (dw_attr_ref);
 static void add_AT_unsigned (dw_die_ref, enum dwarf_attribute, unsigned HOST_WIDE_INT);
 static inline unsigned HOST_WIDE_INT AT_unsigned (dw_attr_ref);
-static void add_AT_long_long (dw_die_ref, enum dwarf_attribute, unsigned long,
-                             unsigned long);
+static void add_AT_double (dw_die_ref, enum dwarf_attribute,
+                          HOST_WIDE_INT, unsigned HOST_WIDE_INT);
 static inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int,
                               unsigned int, unsigned char *);
+static void add_AT_data8 (dw_die_ref, enum dwarf_attribute, unsigned char *);
 static hashval_t debug_str_do_hash (const void *);
 static int debug_str_eq (const void *, const void *);
 static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *);
@@ -5422,6 +5992,16 @@ static dw_die_ref pop_compile_unit (dw_die_ref);
 static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
 static void attr_checksum (dw_attr_ref, struct md5_ctx *, int *);
 static void die_checksum (dw_die_ref, struct md5_ctx *, int *);
+static void checksum_sleb128 (HOST_WIDE_INT, struct md5_ctx *);
+static void checksum_uleb128 (unsigned HOST_WIDE_INT, struct md5_ctx *);
+static void loc_checksum_ordered (dw_loc_descr_ref, struct md5_ctx *);
+static void attr_checksum_ordered (enum dwarf_tag, dw_attr_ref,
+                                  struct md5_ctx *, int *);
+struct checksum_attributes;
+static void collect_checksum_attributes (struct checksum_attributes *, dw_die_ref);
+static void die_checksum_ordered (dw_die_ref, struct md5_ctx *, int *);
+static void checksum_die_context (dw_die_ref, struct md5_ctx *);
+static void generate_type_signature (dw_die_ref, comdat_type_node *);
 static int same_loc_p (dw_loc_descr_ref, dw_loc_descr_ref, int *);
 static int same_dw_val_p (const dw_val_node *, const dw_val_node *, int *);
 static int same_attr_p (dw_attr_ref, dw_attr_ref, int *);
@@ -5433,6 +6013,22 @@ static int is_comdat_die (dw_die_ref);
 static int is_symbol_die (dw_die_ref);
 static void assign_symbol_names (dw_die_ref);
 static void break_out_includes (dw_die_ref);
+static int is_declaration_die (dw_die_ref);
+static int should_move_die_to_comdat (dw_die_ref);
+static dw_die_ref clone_as_declaration (dw_die_ref);
+static dw_die_ref clone_die (dw_die_ref);
+static dw_die_ref clone_tree (dw_die_ref);
+static void copy_declaration_context (dw_die_ref, dw_die_ref);
+static void generate_skeleton_ancestor_tree (skeleton_chain_node *);
+static void generate_skeleton_bottom_up (skeleton_chain_node *);
+static dw_die_ref generate_skeleton (dw_die_ref);
+static dw_die_ref remove_child_or_replace_with_skeleton (dw_die_ref,
+                                                         dw_die_ref);
+static void break_out_comdat_types (dw_die_ref);
+static dw_die_ref copy_ancestor_tree (dw_die_ref, dw_die_ref, htab_t);
+static void copy_decls_walk (dw_die_ref, dw_die_ref, htab_t);
+static void copy_decls_for_unworthy_types (dw_die_ref);
+
 static hashval_t htab_cu_hash (const void *);
 static int htab_cu_eq (const void *, const void *);
 static void htab_cu_del (void *);
@@ -5456,6 +6052,7 @@ static void output_die_symbol (dw_die_ref);
 static void output_die (dw_die_ref);
 static void output_compilation_unit_header (void);
 static void output_comp_unit (dw_die_ref, int);
+static void output_comdat_type_unit (comdat_type_node *);
 static const char *dwarf2_name (tree, int);
 static void add_pubname (tree, dw_die_ref);
 static void add_pubname_string (const char *, dw_die_ref);
@@ -5473,6 +6070,8 @@ static dw_die_ref base_type_die (tree);
 static int is_base_type (tree);
 static dw_die_ref subrange_type_die (tree, tree, tree, dw_die_ref);
 static dw_die_ref modified_type_die (tree, int, int, dw_die_ref);
+static dw_die_ref generic_parameter_die (tree, tree, bool, dw_die_ref);
+static dw_die_ref template_parameter_pack_die (tree, tree, dw_die_ref);
 static int type_is_enum (const_tree);
 static unsigned int dbx_reg_number (const_rtx);
 static void add_loc_descr_op_piece (dw_loc_descr_ref *, int);
@@ -5484,13 +6083,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);
@@ -5498,16 +6099,16 @@ static unsigned int simple_decl_align_in_bits (const_tree);
 static unsigned HOST_WIDE_INT simple_type_size_in_bits (const_tree);
 static HOST_WIDE_INT field_byte_offset (const_tree);
 static void add_AT_location_description        (dw_die_ref, enum dwarf_attribute,
-                                        dw_loc_descr_ref);
+                                        dw_loc_list_ref);
 static void add_data_member_location_attribute (dw_die_ref, tree);
-static void add_const_value_attribute (dw_die_ref, rtx);
+static bool add_const_value_attribute (dw_die_ref, rtx);
 static void insert_int (HOST_WIDE_INT, unsigned, unsigned char *);
-static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
 static void insert_float (const_rtx, unsigned char *);
 static rtx rtl_for_decl_location (tree);
-static void add_location_or_const_value_attribute (dw_die_ref, tree,
+static bool add_location_or_const_value_attribute (dw_die_ref, tree,
                                                   enum dwarf_attribute);
-static void tree_add_const_value_attribute (dw_die_ref, tree);
+static bool tree_add_const_value_attribute (dw_die_ref, tree);
+static bool tree_add_const_value_attribute_for_decl (dw_die_ref, tree);
 static void add_name_attribute (dw_die_ref, const char *);
 static void add_comp_dir_attribute (dw_die_ref);
 static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree);
@@ -5539,7 +6140,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);
@@ -5561,6 +6163,7 @@ static void gen_type_die (tree, dw_die_ref);
 static void gen_block_die (tree, dw_die_ref, int);
 static void decls_for_scope (tree, dw_die_ref, int);
 static int is_redundant_typedef (const_tree);
+static inline dw_die_ref get_context_die (tree);
 static void gen_namespace_die (tree, dw_die_ref);
 static void gen_decl_die (tree, tree, dw_die_ref);
 static dw_die_ref force_decl_die (tree);
@@ -5570,6 +6173,7 @@ static dw_die_ref declare_in_namespace (tree, dw_die_ref);
 static struct dwarf_file_data * lookup_filename (const char *);
 static void retry_incomplete_types (void);
 static void gen_type_die_for_member (tree, tree, dw_die_ref);
+static void gen_generic_params_dies (tree);
 static void splice_child_die (dw_die_ref, dw_die_ref);
 static int file_info_cmp (const void *, const void *);
 static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
@@ -5587,6 +6191,8 @@ static void prune_unused_types_walk_attribs (dw_die_ref);
 static void prune_unused_types_prune (dw_die_ref);
 static void prune_unused_types (void);
 static int maybe_emit_file (struct dwarf_file_data *fd);
+static void append_entry_to_tmpl_value_parm_die_table (dw_die_ref, tree);
+static void gen_remaining_tmpl_value_param_die_attribute (void);
 
 /* Section names used to hold DWARF debugging information.  */
 #ifndef DEBUG_INFO_SECTION
@@ -5610,6 +6216,15 @@ static int maybe_emit_file (struct dwarf_file_data *fd);
 #ifndef DEBUG_PUBNAMES_SECTION
 #define DEBUG_PUBNAMES_SECTION ".debug_pubnames"
 #endif
+#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
@@ -5868,6 +6483,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:
@@ -5880,6 +6505,8 @@ dwarf_tag_name (unsigned int tag)
       return "DW_TAG_GNU_BINCL";
     case DW_TAG_GNU_EINCL:
       return "DW_TAG_GNU_EINCL";
+    case DW_TAG_GNU_template_template_param:
+      return "DW_TAG_GNU_template_template_param";
     default:
       return "DW_TAG_<unknown>";
     }
@@ -6044,6 +6671,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:
@@ -6081,6 +6721,24 @@ dwarf_attr_name (unsigned int attr)
       return "DW_AT_body_end";
     case DW_AT_GNU_vector:
       return "DW_AT_GNU_vector";
+    case DW_AT_GNU_guarded_by:
+      return "DW_AT_GNU_guarded_by";
+    case DW_AT_GNU_pt_guarded_by:
+      return "DW_AT_GNU_pt_guarded_by";
+    case DW_AT_GNU_guarded:
+      return "DW_AT_GNU_guarded";
+    case DW_AT_GNU_pt_guarded:
+      return "DW_AT_GNU_pt_guarded";
+    case DW_AT_GNU_locks_excluded:
+      return "DW_AT_GNU_locks_excluded";
+    case DW_AT_GNU_exclusive_locks_required:
+      return "DW_AT_GNU_exclusive_locks_required";
+    case DW_AT_GNU_shared_locks_required:
+      return "DW_AT_GNU_shared_locks_required";
+    case DW_AT_GNU_odr_signature:
+      return "DW_AT_GNU_odr_signature";
+    case DW_AT_GNU_template_name:
+      return "DW_AT_GNU_template_name";
 
     case DW_AT_VMS_rtnbeg_pd_address:
       return "DW_AT_VMS_rtnbeg_pd_address";
@@ -6139,6 +6797,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>";
     }
@@ -6274,15 +6940,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);
 }
 
@@ -6302,6 +6968,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
@@ -6317,6 +6997,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)
 {
@@ -6359,6 +7041,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)
 {
@@ -6374,7 +7087,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);
 
@@ -6392,13 +7104,12 @@ AT_string_form (dw_attr_ref a)
   /* If we cannot expect the linker to merge strings in .debug_str
      section, only put it into .debug_str if it is worth even in this
      single module.  */
-  if ((debug_str_section->common.flags & SECTION_MERGE) == 0
-      && (len - DWARF_OFFSET_SIZE) * node->refcount <= len)
+  if (DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
+      || ((debug_str_section->common.flags & SECTION_MERGE) == 0
+      && (len - DWARF_OFFSET_SIZE) * node->refcount <= len))
     return node->form = DW_FORM_string;
 
-  ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
-  ++dw2_string_counter;
-  node->label = xstrdup (label);
+  gen_label_for_indirect_string (node);
 
   return node->form = DW_FORM_strp;
 }
@@ -6824,6 +7535,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.  */
 
@@ -6988,6 +7736,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));
 }
@@ -7064,6 +7814,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.  */
 
@@ -7080,6 +7841,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++)
     {
@@ -7110,10 +7878,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");
@@ -7124,8 +7893,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);
            }
@@ -7147,6 +7923,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;
        }
@@ -7238,7 +8022,10 @@ pop_compile_unit (dw_die_ref old_unit)
 static inline void
 loc_checksum (dw_loc_descr_ref loc, struct md5_ctx *ctx)
 {
-  CHECKSUM (loc->dw_loc_opc);
+  int tem;
+
+  tem = (loc->dtprel << 8) | ((unsigned int) loc->dw_loc_opc);
+  CHECKSUM (tem);
   CHECKSUM (loc->dw_loc_oprnd1);
   CHECKSUM (loc->dw_loc_oprnd2);
 }
@@ -7266,8 +8053,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);
@@ -7308,6 +8095,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;
     }
@@ -7341,221 +8132,843 @@ 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)
-    {
-    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_long_long:
-      return v1->v.val_long_long.hi == v2->v.val_long_long.hi
-            && v1->v.val_long_long.low == v2->v.val_long_long.low;
-    case dw_val_class_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);
+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;
 
-    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));
+  if (tag != DW_TAG_namespace
+      && tag != DW_TAG_structure_type
+      && tag != DW_TAG_class_type)
+    return;
 
-    case dw_val_class_offset:
-      return v1->v.val_offset == v2->v.val_offset;
+  name = get_AT_string (die, DW_AT_name);
 
-    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;
+  spec = get_AT_ref (die, DW_AT_specification);
+  if (spec != NULL)
+    die = spec;
 
-    case dw_val_class_die_ref:
-      return same_die_p (v1->v.val_die_ref.die, v2->v.val_die_ref.die, mark);
+  if (die->die_parent != NULL)
+    checksum_die_context (die->die_parent, ctx);
 
-    case dw_val_class_fde_ref:
-    case dw_val_class_lbl_id:
-    case dw_val_class_lineptr:
-    case dw_val_class_macptr:
-      return 1;
+  CHECKSUM_ULEB128 ('C');
+  CHECKSUM_ULEB128 (tag);
+  if (name != NULL)
+    CHECKSUM_STRING (name);
+}
 
-    case dw_val_class_file:
-      return v1->v.val_file == v2->v.val_file;
+/* Calculate the checksum of a location expression.  */
 
-    default:
-      return 1;
+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;
     }
 }
 
-/* Do the attributes look the same?  */
+/* Calculate the checksum of an attribute.  */
 
-static int
-same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark)
+static void
+attr_checksum_ordered (enum dwarf_tag tag, dw_attr_ref at,
+                      struct md5_ctx *ctx, 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;
+  dw_loc_descr_ref loc;
+  rtx r;
 
-  return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark);
-}
+  if (AT_class (at) == dw_val_class_die_ref)
+    {
+      dw_die_ref target_die = AT_ref (at);
+
+      /* For pointer and reference types, we checksum only the (qualified)
+        name of the target type (if there is a name).  For friend entries,
+        we checksum only the (qualified) name of the target type or function.
+        This allows the checksum to remain the same whether the target type
+        is complete or not.  */
+      if ((at->dw_attr == DW_AT_type
+          && (tag == DW_TAG_pointer_type
+              || tag == DW_TAG_reference_type
+              || tag == DW_TAG_ptr_to_member_type))
+         || (at->dw_attr == DW_AT_friend
+             && tag == DW_TAG_friend))
+       {
+         dw_attr_ref name_attr = get_AT (target_die, DW_AT_name);
 
-/* Do the dies look the same?  */
+         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;
+           }
+       }
 
-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;
+      /* 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;
+    }
 
-  /* To avoid infinite recursion.  */
-  if (die1->die_mark)
-    return die1->die_mark == die2->die_mark;
-  die1->die_mark = die2->die_mark = ++(*mark);
+  CHECKSUM_ULEB128 ('A');
+  CHECKSUM_ULEB128 (at->dw_attr);
 
-  if (die1->die_tag != die2->die_tag)
-    return 0;
+  switch (AT_class (at))
+    {
+    case dw_val_class_const:
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_SLEB128 (at->dw_attr_val.v.val_int);
+      break;
 
-  if (VEC_length (dw_attr_node, die1->die_attr)
-      != VEC_length (dw_attr_node, die2->die_attr))
-    return 0;
+    case dw_val_class_unsigned_const:
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_SLEB128 ((int) at->dw_attr_val.v.val_unsigned);
+      break;
 
-  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;
+    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;
 
-  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;
-           else
-             return 0;
-         }
-    }
+    case dw_val_class_vec:
+      CHECKSUM_ULEB128 (DW_FORM_block);
+      CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_vec));
+      CHECKSUM (at->dw_attr_val.v.val_vec);
+      break;
 
-  return 1;
+    case dw_val_class_flag:
+      CHECKSUM_ULEB128 (DW_FORM_flag);
+      CHECKSUM_ULEB128 (at->dw_attr_val.v.val_flag ? 1 : 0);
+      break;
+
+    case dw_val_class_str:
+      CHECKSUM_ULEB128 (DW_FORM_string);
+      CHECKSUM_STRING (AT_string (at));
+      break;
+
+    case dw_val_class_addr:
+      r = AT_addr (at);
+      gcc_assert (GET_CODE (r) == SYMBOL_REF);
+      CHECKSUM_ULEB128 (DW_FORM_string);
+      CHECKSUM_STRING (XSTR (r, 0));
+      break;
+
+    case dw_val_class_offset:
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_ULEB128 (at->dw_attr_val.v.val_offset);
+      break;
+
+    case dw_val_class_loc:
+      for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
+       loc_checksum_ordered (loc, ctx);
+      break;
+
+    case dw_val_class_fde_ref:
+    case dw_val_class_lbl_id:
+    case dw_val_class_lineptr:
+    case dw_val_class_macptr:
+      break;
+
+    case dw_val_class_file:
+      CHECKSUM_ULEB128 (DW_FORM_string);
+      CHECKSUM_STRING (AT_file (at)->filename);
+      break;
+
+    case dw_val_class_data8:
+      CHECKSUM (at->dw_attr_val.v.val_data8);
+      break;
+
+    default:
+      break;
+    }
 }
 
-/* Do the dies look the same?  Wrapper around same_die_p.  */
+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;
+};
 
-static int
-same_die_p_wrap (dw_die_ref die1, dw_die_ref die2)
-{
-  int mark = 0;
-  int ret = same_die_p (die1, die2, &mark);
+/* Collect the attributes that we will want to use for the checksum.  */
 
-  unmark_all_dies (die1);
-  unmark_all_dies (die2);
+static void
+collect_checksum_attributes (struct checksum_attributes *attrs, dw_die_ref die)
+{
+  dw_attr_ref a;
+  unsigned ix;
 
-  return ret;
+  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+    {
+      switch (a->dw_attr)
+        {
+        case DW_AT_name:
+          attrs->at_name = a;
+          break;
+        case DW_AT_type:
+          attrs->at_type = a;
+          break;
+        case DW_AT_friend:
+          attrs->at_friend = a;
+          break;
+        case DW_AT_accessibility:
+          attrs->at_accessibility = a;
+          break;
+        case DW_AT_address_class:
+          attrs->at_address_class = a;
+          break;
+        case DW_AT_allocated:
+          attrs->at_allocated = a;
+          break;
+        case DW_AT_artificial:
+          attrs->at_artificial = a;
+          break;
+        case DW_AT_associated:
+          attrs->at_associated = a;
+          break;
+        case DW_AT_binary_scale:
+          attrs->at_binary_scale = a;
+          break;
+        case DW_AT_bit_offset:
+          attrs->at_bit_offset = a;
+          break;
+        case DW_AT_bit_size:
+          attrs->at_bit_size = a;
+          break;
+        case DW_AT_bit_stride:
+          attrs->at_bit_stride = a;
+          break;
+        case DW_AT_byte_size:
+          attrs->at_byte_size = a;
+          break;
+        case DW_AT_byte_stride:
+          attrs->at_byte_stride = a;
+          break;
+        case DW_AT_const_value:
+          attrs->at_const_value = a;
+          break;
+        case DW_AT_containing_type:
+          attrs->at_containing_type = a;
+          break;
+        case DW_AT_count:
+          attrs->at_count = a;
+          break;
+        case DW_AT_data_location:
+          attrs->at_data_location = a;
+          break;
+        case DW_AT_data_member_location:
+          attrs->at_data_member_location = a;
+          break;
+        case DW_AT_decimal_scale:
+          attrs->at_decimal_scale = a;
+          break;
+        case DW_AT_decimal_sign:
+          attrs->at_decimal_sign = a;
+          break;
+        case DW_AT_default_value:
+          attrs->at_default_value = a;
+          break;
+        case DW_AT_digit_count:
+          attrs->at_digit_count = a;
+          break;
+        case DW_AT_discr:
+          attrs->at_discr = a;
+          break;
+        case DW_AT_discr_list:
+          attrs->at_discr_list = a;
+          break;
+        case DW_AT_discr_value:
+          attrs->at_discr_value = a;
+          break;
+        case DW_AT_encoding:
+          attrs->at_encoding = a;
+          break;
+        case DW_AT_endianity:
+          attrs->at_endianity = a;
+          break;
+        case DW_AT_explicit:
+          attrs->at_explicit = a;
+          break;
+        case DW_AT_is_optional:
+          attrs->at_is_optional = a;
+          break;
+        case DW_AT_location:
+          attrs->at_location = a;
+          break;
+        case DW_AT_lower_bound:
+          attrs->at_lower_bound = a;
+          break;
+        case DW_AT_mutable:
+          attrs->at_mutable = a;
+          break;
+        case DW_AT_ordering:
+          attrs->at_ordering = a;
+          break;
+        case DW_AT_picture_string:
+          attrs->at_picture_string = a;
+          break;
+        case DW_AT_prototyped:
+          attrs->at_prototyped = a;
+          break;
+        case DW_AT_small:
+          attrs->at_small = a;
+          break;
+        case DW_AT_segment:
+          attrs->at_segment = a;
+          break;
+        case DW_AT_string_length:
+          attrs->at_string_length = a;
+          break;
+        case DW_AT_threads_scaled:
+          attrs->at_threads_scaled = a;
+          break;
+        case DW_AT_upper_bound:
+          attrs->at_upper_bound = a;
+          break;
+        case DW_AT_use_location:
+          attrs->at_use_location = a;
+          break;
+        case DW_AT_use_UTF8:
+          attrs->at_use_UTF8 = a;
+          break;
+        case DW_AT_variable_parameter:
+          attrs->at_variable_parameter = a;
+          break;
+        case DW_AT_virtuality:
+          attrs->at_virtuality = a;
+          break;
+        case DW_AT_visibility:
+          attrs->at_visibility = a;
+          break;
+        case DW_AT_vtable_elem_location:
+          attrs->at_vtable_elem_location = a;
+          break;
+        default:
+          break;
+        }
+    }
 }
 
-/* The prefix to attach to symbols on DIEs in the current comdat debug
-   info section.  */
-static char *comdat_symbol_id;
+/* Calculate the checksum of a DIE, using an ordered subset of attributes.  */
 
-/* The index of the current symbol within the current comdat CU.  */
-static unsigned int comdat_symbol_number;
+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;
 
-/* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its
-   children, and set comdat_symbol_id accordingly.  */
+    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
-compute_section_prefix (dw_die_ref unit_die)
+generate_type_signature (dw_die_ref die, comdat_type_node *type_node)
 {
-  const char *die_name = get_AT_string (unit_die, DW_AT_name);
-  const char *base = die_name ? lbasename (die_name) : "anonymous";
-  char *name = XALLOCAVEC (char, strlen (base) + 64);
-  char *p;
-  int i, mark;
+  int mark;
+  const char *name;
   unsigned char checksum[16];
   struct md5_ctx ctx;
+  dw_die_ref decl;
 
-  /* Compute the checksum of the DIE, then append part of it as hex digits to
-     the name filename of the unit.  */
-
-  md5_init_ctx (&ctx);
-  mark = 0;
-  die_checksum (unit_die, &ctx, &mark);
-  unmark_all_dies (unit_die);
-  md5_finish_ctx (&ctx, checksum);
+  name = get_AT_string (die, DW_AT_name);
+  decl = get_AT_ref (die, DW_AT_specification);
 
-  sprintf (name, "%s.", base);
-  clean_symbol_name (name);
+  /* 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.  */
 
-  p = name + strlen (name);
-  for (i = 0; i < 4; i++)
+  if (is_cxx() && name != NULL)
     {
-      sprintf (p, "%.2x", checksum[i]);
-      p += 2;
+      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]);
     }
 
-  comdat_symbol_id = unit_die->die_symbol = xstrdup (name);
-  comdat_symbol_number = 0;
+  /* 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;
 }
 
-/* Returns nonzero if DIE represents a type, in the sense of TYPE_P.  */
+/* 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
-is_type_die (dw_die_ref die)
+same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
 {
-  switch (die->die_tag)
+  dw_loc_descr_ref loc1, loc2;
+  rtx r1, r2;
+
+  if (v1->val_class != v2->val_class)
+    return 0;
+
+  switch (v1->val_class)
     {
-    case DW_TAG_array_type:
-    case DW_TAG_class_type:
-    case DW_TAG_interface_type:
-    case DW_TAG_enumeration_type:
-    case DW_TAG_pointer_type:
-    case DW_TAG_reference_type:
+    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;
+           else
+             return 0;
+         }
+    }
+
+  return 1;
+}
+
+/* Do the dies look the same?  Wrapper around same_die_p.  */
+
+static int
+same_die_p_wrap (dw_die_ref die1, dw_die_ref die2)
+{
+  int mark = 0;
+  int ret = same_die_p (die1, die2, &mark);
+
+  unmark_all_dies (die1);
+  unmark_all_dies (die2);
+
+  return ret;
+}
+
+/* The prefix to attach to symbols on DIEs in the current comdat debug
+   info section.  */
+static char *comdat_symbol_id;
+
+/* The index of the current symbol within the current comdat CU.  */
+static unsigned int comdat_symbol_number;
+
+/* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its
+   children, and set comdat_symbol_id accordingly.  */
+
+static void
+compute_section_prefix (dw_die_ref unit_die)
+{
+  const char *die_name = get_AT_string (unit_die, DW_AT_name);
+  const char *base = die_name ? lbasename (die_name) : "anonymous";
+  char *name = XALLOCAVEC (char, strlen (base) + 64);
+  char *p;
+  int i, mark;
+  unsigned char checksum[16];
+  struct md5_ctx ctx;
+
+  /* Compute the checksum of the DIE, then append part of it as hex digits to
+     the name filename of the unit.  */
+
+  md5_init_ctx (&ctx);
+  mark = 0;
+  die_checksum (unit_die, &ctx, &mark);
+  unmark_all_dies (unit_die);
+  md5_finish_ctx (&ctx, checksum);
+
+  sprintf (name, "%s.", base);
+  clean_symbol_name (name);
+
+  p = name + strlen (name);
+  for (i = 0; i < 4; i++)
+    {
+      sprintf (p, "%.2x", checksum[i]);
+      p += 2;
+    }
+
+  comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
+  comdat_symbol_number = 0;
+}
+
+/* Returns nonzero if DIE represents a type, in the sense of TYPE_P.  */
+
+static int
+is_type_die (dw_die_ref die)
+{
+  switch (die->die_tag)
+    {
+    case DW_TAG_array_type:
+    case DW_TAG_class_type:
+    case DW_TAG_interface_type:
+    case DW_TAG_enumeration_type:
+    case DW_TAG_pointer_type:
+    case DW_TAG_reference_type:
     case DW_TAG_string_type:
     case DW_TAG_structure_type:
     case DW_TAG_subroutine_type:
@@ -7611,8 +9024,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);
 }
@@ -7641,10 +9053,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));
@@ -7664,7 +9076,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
@@ -7674,7 +9086,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
@@ -7702,7 +9114,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;
 
@@ -7734,7 +9146,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;
 
@@ -7807,62 +9219,600 @@ 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.  */
+/* Return non-zero if this DIE is a declaration.  */
 
-static void
-add_sibling_attributes (dw_die_ref die)
+static int
+is_declaration_die (dw_die_ref die)
 {
-  dw_die_ref c;
+  dw_attr_ref a;
+  unsigned ix;
 
-  if (! die->die_child)
-    return;
+  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+    if (a->dw_attr == DW_AT_declaration)
+      return 1;
 
-  if (die->die_parent && die != die->die_parent->die_child)
-    add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
+  return 0;
+}
 
-  FOR_EACH_CHILD (die, c, add_sibling_attributes (c));
+/* 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_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;
+    }
 }
 
-/* Output all location lists for the DIE and its children.  */
+/* Make a clone of DIE.  */
 
-static void
-output_location_lists (dw_die_ref die)
+static dw_die_ref
+clone_die (dw_die_ref die)
 {
-  dw_die_ref c;
+  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++)
-    if (AT_class (a) == dw_val_class_loc_list)
-      output_loc_list (AT_loc_list (a));
+    add_dwarf_attr (clone, a);
 
-  FOR_EACH_CHILD (die, c, output_location_lists (c));
+  return clone;
 }
 
-/* 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.  */
+/* Make a clone of the tree rooted at DIE.  */
 
-static void
-build_abbrev_table (dw_die_ref die)
+static dw_die_ref
+clone_tree (dw_die_ref die)
 {
-  unsigned long abbrev_id;
-  unsigned int n_alloc;
   dw_die_ref c;
-  dw_attr_ref a;
-  unsigned ix;
+  dw_die_ref clone = clone_die (die);
 
-  /* Scan the DIE references, and mark as external any that refer to
+  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_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.  */
+
+static void
+build_abbrev_table (dw_die_ref die)
+{
+  unsigned long abbrev_id;
+  unsigned int n_alloc;
+  dw_die_ref c;
+  dw_attr_ref a;
+  unsigned ix;
+
+  /* Scan the DIE references, and mark as external any that refer to
      DIEs from other CUs (i.e. those which are not marked).  */
   for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
     if (AT_class (a) == dw_val_class_die_ref
        && AT_ref (a)->die_mark == 0)
       {
-       gcc_assert (AT_ref (a)->die_symbol);
-
+       gcc_assert (dwarf_version >= 4 || AT_ref (a)->die_id.die_symbol);
        set_AT_ref_external (a, 1);
       }
 
@@ -7977,8 +9927,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
@@ -7991,7 +9943,18 @@ size_of_die (dw_die_ref die)
          break;
        case dw_val_class_die_ref:
          if (AT_ref_external (a))
-           size += DWARF2_ADDR_SIZE;
+           {
+             /* In DWARF4, we use DW_FORM_sig8; for earlier versions
+                we use DW_FORM_ref_addr.  In DWARF2, DW_FORM_ref_addr
+                is sized by target address length, whereas in DWARF3
+                it's always sized as an offset.  */
+             if (dwarf_version >= 4)
+               size += DWARF_TYPE_SIGNATURE_SIZE;
+             else if (dwarf_version == 2)
+               size += DWARF2_ADDR_SIZE;
+             else
+               size += DWARF_OFFSET_SIZE;
+           }
          else
            size += DWARF_OFFSET_SIZE;
          break;
@@ -8014,6 +9977,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 ();
        }
@@ -8065,7 +10031,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));
@@ -8141,7 +10108,30 @@ 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:
@@ -8180,8 +10170,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))
@@ -8199,7 +10200,7 @@ value_format (dw_attr_ref a)
       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:
@@ -8224,6 +10225,9 @@ value_format (dw_attr_ref a)
          gcc_unreachable ();
        }
 
+    case dw_val_class_data8:
+      return DW_FORM_data8;
+
     default:
       gcc_unreachable ();
     }
@@ -8283,7 +10287,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;
@@ -8385,8 +10389,19 @@ output_loc_list (dw_loc_list_ref list_head)
                       list_head->ll_symbol);
 }
 
-/* Output the DIE and its attributes.  Called recursively to generate
-   the definitions of each child DIE.  */
+/* 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.  */
 
 static void
 output_die (dw_die_ref die)
@@ -8398,7 +10413,7 @@ 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)",
@@ -8453,28 +10468,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;
@@ -8518,11 +10535,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;
-
-             gcc_assert (sym);
-             dw2_asm_output_offset (DWARF2_ADDR_SIZE, sym, debug_info_section,
-                                    "%s", name);
+             if (dwarf_version >= 4)
+               {
+                 comdat_type_node_ref type_node =
+                   AT_ref (a)->die_id.die_type_node;
+
+                 gcc_assert (type_node);
+                 output_signature (type_node->signature, name);
+               }
+             else
+               {
+                 char *sym = AT_ref (a)->die_id.die_symbol;
+                 int size;
+
+                 gcc_assert (sym);
+                 /* In DWARF2, DW_FORM_ref_addr is sized by target address
+                    length, whereas in DWARF3 it's always sized as an
+                    offset.  */
+                 if (dwarf_version == 2)
+                   size = DWARF2_ADDR_SIZE;
+                 else
+                   size = DWARF_OFFSET_SIZE;
+                 dw2_asm_output_offset (size, sym, debug_info_section, "%s",
+                                        name);
+               }
            }
          else
            {
@@ -8576,6 +10612,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 ();
        }
@@ -8595,13 +10641,20 @@ output_die (dw_die_ref die)
 static void
 output_compilation_unit_header (void)
 {
+  int ver = dwarf_version;
+
+  /* Don't mark the output as DWARF-4 until we make full use of the
+     version 4 extensions, and gdb supports them.  For now, -gdwarf-4
+     selects only a few extensions from the DWARF-4 spec.  */
+  if (ver > 3)
+    ver = 3;
   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");
@@ -8633,14 +10686,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
@@ -8655,10 +10708,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 *
@@ -8682,9 +10785,12 @@ add_pubname_string (const char *str, dw_die_ref die)
 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.  */
@@ -8714,7 +10820,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.  */
@@ -8742,7 +10852,8 @@ output_pubnames (VEC (pubname_entry, gc) * names)
   else
     dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
                         "Length of Public Type Names Info");
-  dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
+  /* Version number for pubnames/pubtypes is still 2, even in DWARF3.  */
+  dw2_asm_output_data (2, 2, "DWARF Version");
   dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
                         debug_info_section,
                         "Offset of Compilation Unit Info");
@@ -8804,7 +10915,8 @@ output_aranges (void)
       "Initial length escape value indicating 64-bit DWARF extension");
   dw2_asm_output_data (DWARF_OFFSET_SIZE, aranges_length,
                       "Length of Address Ranges Info");
-  dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
+  /* Version number for aranges is still 2, even in DWARF3.  */
+  dw2_asm_output_data (2, 2, "DWARF Version");
   dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
                         debug_info_section,
                         "Offset of Compilation Unit Info");
@@ -9154,7 +11266,6 @@ output_file_names (void)
   int ndirs;
   int idx_offset;
   int i;
-  int idx;
 
   if (!last_emitted_file)
     {
@@ -9281,10 +11392,11 @@ 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 - 1,
+    dw2_asm_output_nstring (dirs[i].path,
+                           dirs[i].length
+                            - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
                            "Directory Entry: 0x%x", i + idx_offset);
 
   dw2_asm_output_data (1, 0, "End directory table");
@@ -9302,6 +11414,42 @@ output_file_names (void)
       int file_idx = backmap[i];
       int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
 
+#ifdef VMS_DEBUGGING_INFO
+#define MAX_VMS_VERSION_LEN 6 /* ";32768" */
+
+      /* Setting these fields can lead to debugger miscomparisons,
+         but VMS Debug requires them to be set correctly.  */
+
+      int ver;
+      long long cdt;
+      long siz;
+      int maxfilelen = strlen (files[file_idx].path)
+                              + dirs[dir_idx].length
+                              + MAX_VMS_VERSION_LEN + 1;
+      char *filebuf = XALLOCAVEC (char, maxfilelen);
+
+      vms_file_stats_name (files[file_idx].path, 0, 0, 0, &ver);
+      snprintf (filebuf, maxfilelen, "%s;%d",
+               files[file_idx].path + dirs[dir_idx].length, ver);
+
+      dw2_asm_output_nstring
+       (filebuf, -1, "File Entry: 0x%x", (unsigned) i + 1);
+
+      /* Include directory index.  */
+      dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+
+      /* Modification time.  */
+      dw2_asm_output_data_uleb128
+        ((vms_file_stats_name (files[file_idx].path, &cdt, 0, 0, 0) == 0)
+         ? cdt : 0,
+        NULL);
+
+      /* File length in bytes.  */
+      dw2_asm_output_data_uleb128
+        ((vms_file_stats_name (files[file_idx].path, 0, &siz, 0, 0) == 0)
+         ? siz : 0,
+        NULL);
+#else
       dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
                              "File Entry: 0x%x", (unsigned) i + 1);
 
@@ -9313,6 +11461,7 @@ output_file_names (void)
 
       /* File length in bytes.  */
       dw2_asm_output_data_uleb128 (0, NULL);
+#endif
     }
 
   dw2_asm_output_data (1, 0, "End file name table");
@@ -9336,6 +11485,13 @@ output_line_info (void)
   long line_delta;
   unsigned long current_file;
   unsigned long function;
+  int ver = dwarf_version;
+
+  /* Don't mark the output as DWARF-4 until we make full use of the
+     version 4 extensions, and gdb supports them.  For now, -gdwarf-4
+     selects only a few extensions from the DWARF-4 spec.  */
+  if (ver > 3)
+    ver = 3;
 
   ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
@@ -9349,7 +11505,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);
 
@@ -9632,6 +11788,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.
@@ -9671,13 +11950,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;
@@ -9875,6 +12161,9 @@ 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)
     {
@@ -9882,6 +12171,9 @@ 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 == INTEGER_TYPE
           && TREE_TYPE (type) != NULL_TREE
@@ -9896,345 +12188,1345 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
     {
       gen_type_die (type, context_die);
 
-      /* We have to get the type_main_variant here (and pass that to the
-        `lookup_type_die' routine) because the ..._TYPE node we have
-        might simply be a *copy* of some original type node (where the
-        copy was created to help us keep track of typedef names) and
-        that copy might have a different TYPE_UID from the original
-        ..._TYPE node.  */
-      if (TREE_CODE (type) != VECTOR_TYPE)
-       return lookup_type_die (type_main_variant (type));
-      else
-       /* Vectors have the debugging information in the type,
-          not the main variant.  */
-       return lookup_type_die (type);
-    }
+      /* We have to get the type_main_variant here (and pass that to the
+        `lookup_type_die' routine) because the ..._TYPE node we have
+        might simply be a *copy* of some original type node (where the
+        copy was created to help us keep track of typedef names) and
+        that copy might have a different TYPE_UID from the original
+        ..._TYPE node.  */
+      if (TREE_CODE (type) != VECTOR_TYPE)
+       return lookup_type_die (type_main_variant (type));
+      else
+       /* Vectors have the debugging information in the type,
+          not the main variant.  */
+       return lookup_type_die (type);
+    }
+
+  /* Builtin types don't have a DECL_ORIGINAL_TYPE.  For those,
+     don't output a DW_TAG_typedef, since there isn't one in the
+     user's program; just attach a DW_AT_name to the type.
+     Don't attach a DW_AT_name to DW_TAG_const_type or DW_TAG_volatile_type
+     if the base type already has the same name.  */
+  if (name
+      && ((TREE_CODE (name) != TYPE_DECL
+          && (qualified_type == TYPE_MAIN_VARIANT (type)
+              || (!is_const_type && !is_volatile_type)))
+         || (TREE_CODE (name) == TYPE_DECL
+             && TREE_TYPE (name) == qualified_type
+             && DECL_NAME (name))))
+    {
+      if (TREE_CODE (name) == TYPE_DECL)
+       /* Could just call add_name_and_src_coords_attributes here,
+          but since this is a builtin type it doesn't have any
+          useful source coordinates anyway.  */
+       name = DECL_NAME (name);
+      add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
+    }
+
+  if (qualified_type)
+    equate_type_number_to_die (qualified_type, mod_type_die);
+
+  if (item_type)
+    /* We must do this after the equate_type_number_to_die call, in case
+       this is a recursive type.  This ensures that the modified_type_die
+       recursion will terminate even if the type is recursive.  Recursive
+       types are possible in Ada.  */
+    sub_die = modified_type_die (item_type,
+                                TYPE_READONLY (item_type),
+                                TYPE_VOLATILE (item_type),
+                                context_die);
+
+  if (sub_die != NULL)
+    add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
+
+  return mod_type_die;
+}
+
+/* Generate DIEs for the generic parameters of T.
+   T must be either a generic type or a generic function.
+   See http://gcc.gnu.org/wiki/TemplateParmsDwarf for more.  */
+
+static void
+gen_generic_params_dies (tree t)
+{
+  tree parms, args;
+  int parms_num, i;
+  dw_die_ref die = NULL;
+
+  if (!t || (TYPE_P (t) && !COMPLETE_TYPE_P (t)))
+    return;
+
+  if (TYPE_P (t))
+    die = lookup_type_die (t);
+  else if (DECL_P (t))
+    die = lookup_decl_die (t);
+
+  gcc_assert (die);
+
+  parms = lang_hooks.get_innermost_generic_parms (t);
+  if (!parms)
+    /* T has no generic parameter. It means T is neither a generic type
+       or function. End of story.  */
+    return;
+
+  parms_num = TREE_VEC_LENGTH (parms);
+  args = lang_hooks.get_innermost_generic_args (t);
+  for (i = 0; i < parms_num; i++)
+    {
+      tree parm, arg, arg_pack_elems;
+
+      parm = TREE_VEC_ELT (parms, i);
+      arg = TREE_VEC_ELT (args, i);
+      arg_pack_elems = lang_hooks.types.get_argument_pack_elems (arg);
+      gcc_assert (parm && TREE_VALUE (parm) && arg);
+
+      if (parm && TREE_VALUE (parm) && arg)
+       {
+         /* If PARM represents a template parameter pack,
+            emit a DW_TAG_GNU_template_parameter_pack DIE, followed
+            by DW_TAG_template_*_parameter DIEs for the argument
+            pack elements of ARG. Note that ARG would then be
+            an argument pack.  */
+         if (arg_pack_elems)
+           template_parameter_pack_die (TREE_VALUE (parm),
+                                        arg_pack_elems,
+                                        die);
+         else
+           generic_parameter_die (TREE_VALUE (parm), arg,
+                                  true /* Emit DW_AT_name */, die);
+       }
+    }
+}
+
+/* Create and return a DIE for PARM which should be
+   the representation of a generic type parameter.
+   For instance, in the C++ front end, PARM would be a template parameter.
+   ARG is the argument to PARM.
+   EMIT_NAME_P if tree, the DIE will have DW_AT_name attribute set to the
+   name of the PARM.
+   PARENT_DIE is the parent DIE which the new created DIE should be added to,
+   as a child node.  */
+
+static dw_die_ref
+generic_parameter_die (tree parm, tree arg,
+                      bool emit_name_p,
+                      dw_die_ref parent_die)
+{
+  dw_die_ref tmpl_die = NULL;
+  const char *name = NULL;
+
+  if (!parm || !DECL_NAME (parm) || !arg)
+    return NULL;
+
+  /* We support non-type generic parameters and arguments,
+     type generic parameters and arguments, as well as
+     generic generic parameters (a.k.a. template template parameters in C++)
+     and arguments.  */
+  if (TREE_CODE (parm) == PARM_DECL)
+    /* PARM is a nontype generic parameter  */
+    tmpl_die = new_die (DW_TAG_template_value_param, parent_die, parm);
+  else if (TREE_CODE (parm) == TYPE_DECL)
+    /* PARM is a type generic parameter.  */
+    tmpl_die = new_die (DW_TAG_template_type_param, parent_die, parm);
+  else if (lang_hooks.decls.generic_generic_parameter_decl_p (parm))
+    /* PARM is a generic generic parameter.
+       Its DIE is a GNU extension. It shall have a
+       DW_AT_name attribute to represent the name of the template template
+       parameter, and a DW_AT_GNU_template_name attribute to represent the
+       name of the template template argument.  */
+    tmpl_die = new_die (DW_TAG_GNU_template_template_param,
+                       parent_die, parm);
+  else
+    gcc_unreachable ();
+
+  if (tmpl_die)
+    {
+      tree tmpl_type;
+
+      /* If PARM is a generic parameter pack, it means we are
+         emitting debug info for a template argument pack element.
+        In other terms, ARG is a template argument pack element.
+        In that case, we don't emit any DW_AT_name attribute for
+        the die.  */
+      if (emit_name_p)
+       {
+         name = IDENTIFIER_POINTER (DECL_NAME (parm));
+         gcc_assert (name);
+         add_AT_string (tmpl_die, DW_AT_name, name);
+       }
+
+      if (!lang_hooks.decls.generic_generic_parameter_decl_p (parm))
+       {
+         /* DWARF3, 5.6.8 says if PARM is a non-type generic parameter
+            TMPL_DIE should have a child DW_AT_type attribute that is set
+            to the type of the argument to PARM, which is ARG.
+            If PARM is a type generic parameter, TMPL_DIE should have a
+            child DW_AT_type that is set to ARG.  */
+         tmpl_type = TYPE_P (arg) ? arg : TREE_TYPE (arg);
+         add_type_attribute (tmpl_die, tmpl_type, 0,
+                             TREE_THIS_VOLATILE (tmpl_type),
+                             parent_die);
+       }
+      else
+       {
+         /* So TMPL_DIE is a DIE representing a
+            a generic generic template parameter, a.k.a template template
+            parameter in C++ and arg is a template.  */
+
+         /* The DW_AT_GNU_template_name attribute of the DIE must be set
+            to the name of the argument.  */
+         name = dwarf2_name (TYPE_P (arg) ? TYPE_NAME (arg) : arg, 1);
+         if (name)
+           add_AT_string (tmpl_die, DW_AT_GNU_template_name, name);
+       }
+
+      if (TREE_CODE (parm) == PARM_DECL)
+       /* So PARM is a non-type generic parameter.
+          DWARF3 5.6.8 says we must set a DW_AT_const_value child
+          attribute of TMPL_DIE which value represents the value
+          of ARG.
+          We must be careful here:
+          The value of ARG might reference some function decls.
+          We might currently be emitting debug info for a generic
+          type and types are emitted before function decls, we don't
+          know if the function decls referenced by ARG will actually be
+          emitted after cgraph computations.
+          So must defer the generation of the DW_AT_const_value to
+          after cgraph is ready.  */
+       append_entry_to_tmpl_value_parm_die_table (tmpl_die, arg);
+    }
+
+  return tmpl_die;
+}
+
+/* Generate and return a  DW_TAG_GNU_template_parameter_pack DIE representing.
+   PARM_PACK must be a template parameter pack. The returned DIE
+   will be child DIE of PARENT_DIE.  */
+
+static dw_die_ref
+template_parameter_pack_die (tree parm_pack,
+                            tree parm_pack_args,
+                            dw_die_ref parent_die)
+{
+  dw_die_ref die;
+  int j;
+
+  gcc_assert (parent_die && parm_pack);
+
+  die = new_die (DW_TAG_GNU_template_parameter_pack, parent_die, parm_pack);
+  add_name_and_src_coords_attributes (die, parm_pack);
+  for (j = 0; j < TREE_VEC_LENGTH (parm_pack_args); j++)
+    generic_parameter_die (parm_pack,
+                          TREE_VEC_ELT (parm_pack_args, j),
+                          false /* Don't emit DW_AT_name */,
+                          die);
+  return die;
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
+   an enumerated type.  */
+
+static inline int
+type_is_enum (const_tree type)
+{
+  return TREE_CODE (type) == ENUMERAL_TYPE;
+}
+
+/* Return the DBX register number described by a given RTL node.  */
+
+static unsigned int
+dbx_reg_number (const_rtx rtl)
+{
+  unsigned regno = REGNO (rtl);
+
+  gcc_assert (regno < FIRST_PSEUDO_REGISTER);
+
+#ifdef LEAF_REG_REMAP
+  if (current_function_uses_only_leaf_regs)
+    {
+      int leaf_reg = LEAF_REG_REMAP (regno);
+      if (leaf_reg != -1)
+       regno = (unsigned) leaf_reg;
+    }
+#endif
+
+  return DBX_REGISTER_NUMBER (regno);
+}
+
+/* Optionally add a DW_OP_piece term to a location description expression.
+   DW_OP_piece is only added if the location description expression already
+   doesn't end with DW_OP_piece.  */
+
+static void
+add_loc_descr_op_piece (dw_loc_descr_ref *list_head, int size)
+{
+  dw_loc_descr_ref loc;
+
+  if (*list_head != NULL)
+    {
+      /* Find the end of the chain.  */
+      for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
+       ;
+
+      if (loc->dw_loc_opc != DW_OP_piece)
+       loc->dw_loc_next = new_loc_descr (DW_OP_piece, size, 0);
+    }
+}
+
+/* Return a location descriptor that designates a machine register or
+   zero if there is none.  */
+
+static dw_loc_descr_ref
+reg_loc_descriptor (rtx rtl, enum var_init_status initialized)
+{
+  rtx regs;
+
+  if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
+    return 0;
+
+  regs = targetm.dwarf_register_span (rtl);
+
+  if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
+    return multiple_reg_loc_descriptor (rtl, regs, initialized);
+  else
+    return one_reg_loc_descriptor (dbx_reg_number (rtl), initialized);
+}
+
+/* Return a location descriptor that designates a machine register for
+   a given hard register number.  */
+
+static dw_loc_descr_ref
+one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized)
+{
+  dw_loc_descr_ref reg_loc_descr;
+
+  if (regno <= 31)
+    reg_loc_descr
+      = new_loc_descr ((enum dwarf_location_atom) (DW_OP_reg0 + regno), 0, 0);
+  else
+    reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0);
+
+  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&reg_loc_descr, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
+  return reg_loc_descr;
+}
+
+/* Given an RTL of a register, return a location descriptor that
+   designates a value that spans more than one register.  */
+
+static dw_loc_descr_ref
+multiple_reg_loc_descriptor (rtx rtl, rtx regs,
+                            enum var_init_status initialized)
+{
+  int nregs, size, i;
+  unsigned reg;
+  dw_loc_descr_ref loc_result = NULL;
+
+  reg = REGNO (rtl);
+#ifdef LEAF_REG_REMAP
+  if (current_function_uses_only_leaf_regs)
+    {
+      int leaf_reg = LEAF_REG_REMAP (reg);
+      if (leaf_reg != -1)
+       reg = (unsigned) leaf_reg;
+    }
+#endif
+  gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
+  nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
+
+  /* Simple, contiguous registers.  */
+  if (regs == NULL_RTX)
+    {
+      size = GET_MODE_SIZE (GET_MODE (rtl)) / nregs;
+
+      loc_result = NULL;
+      while (nregs--)
+       {
+         dw_loc_descr_ref t;
+
+         t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg),
+                                     VAR_INIT_STATUS_INITIALIZED);
+         add_loc_descr (&loc_result, t);
+         add_loc_descr_op_piece (&loc_result, size);
+         ++reg;
+       }
+      return loc_result;
+    }
+
+  /* Now onto stupid register sets in non contiguous locations.  */
+
+  gcc_assert (GET_CODE (regs) == PARALLEL);
+
+  size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
+  loc_result = NULL;
+
+  for (i = 0; i < XVECLEN (regs, 0); ++i)
+    {
+      dw_loc_descr_ref t;
+
+      t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)),
+                                 VAR_INIT_STATUS_INITIALIZED);
+      add_loc_descr (&loc_result, t);
+      size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
+      add_loc_descr_op_piece (&loc_result, size);
+    }
+
+  if (loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+  return loc_result;
+}
+
+#endif /* DWARF2_DEBUGGING_INFO */
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+
+/* Return a location descriptor that designates a constant.  */
+
+static dw_loc_descr_ref
+int_loc_descriptor (HOST_WIDE_INT i)
+{
+  enum dwarf_location_atom op;
+
+  /* Pick the smallest representation of a constant, rather than just
+     defaulting to the LEB encoding.  */
+  if (i >= 0)
+    {
+      if (i <= 31)
+       op = (enum dwarf_location_atom) (DW_OP_lit0 + i);
+      else if (i <= 0xff)
+       op = DW_OP_const1u;
+      else if (i <= 0xffff)
+       op = DW_OP_const2u;
+      else if (HOST_BITS_PER_WIDE_INT == 32
+              || i <= 0xffffffff)
+       op = DW_OP_const4u;
+      else
+       op = DW_OP_constu;
+    }
+  else
+    {
+      if (i >= -0x80)
+       op = DW_OP_const1s;
+      else if (i >= -0x8000)
+       op = DW_OP_const2s;
+      else if (HOST_BITS_PER_WIDE_INT == 32
+              || i >= -0x80000000)
+       op = DW_OP_const4s;
+      else
+       op = DW_OP_consts;
+    }
+
+  return new_loc_descr (op, i, 0);
+}
+#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.  */
+
+static dw_loc_descr_ref
+based_loc_descr (rtx reg, HOST_WIDE_INT offset,
+                enum var_init_status initialized)
+{
+  unsigned int regno;
+  dw_loc_descr_ref result;
+  dw_fde_ref fde = current_fde ();
+
+  /* We only use "frame base" when we're sure we're talking about the
+     post-prologue local stack frame.  We do this by *not* running
+     register elimination until this point, and recognizing the special
+     argument pointer and soft frame pointer rtx's.  */
+  if (reg == arg_pointer_rtx || reg == frame_pointer_rtx)
+    {
+      rtx elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+
+      if (elim != reg)
+       {
+         if (GET_CODE (elim) == PLUS)
+           {
+             offset += INTVAL (XEXP (elim, 1));
+             elim = XEXP (elim, 0);
+           }
+         gcc_assert ((SUPPORTS_STACK_ALIGNMENT
+                      && (elim == hard_frame_pointer_rtx
+                          || elim == stack_pointer_rtx))
+                     || elim == (frame_pointer_needed
+                                 ? hard_frame_pointer_rtx
+                                 : stack_pointer_rtx));
+
+         /* If drap register is used to align stack, use frame
+            pointer + offset to access stack variables.  If stack
+            is aligned without drap, use stack pointer + offset to
+            access stack variables.  */
+         if (crtl->stack_realign_tried
+             && reg == frame_pointer_rtx)
+           {
+             int base_reg
+               = DWARF_FRAME_REGNUM ((fde && fde->drap_reg != INVALID_REGNUM)
+                                     ? HARD_FRAME_POINTER_REGNUM
+                                     : STACK_POINTER_REGNUM);
+             return new_reg_loc_descr (base_reg, offset);
+           }
+
+         offset += frame_pointer_fb_offset;
+         return new_loc_descr (DW_OP_fbreg, offset, 0);
+       }
+    }
+  else if (fde
+          && fde->drap_reg != INVALID_REGNUM
+          && (fde->drap_reg == REGNO (reg)
+              || fde->vdrap_reg == REGNO (reg)))
+    {
+      /* Use cfa+offset to represent the location of arguments passed
+        on stack when drap is used to align stack.  */
+      return new_loc_descr (DW_OP_fbreg, offset, 0);
+    }
+
+  regno = dbx_reg_number (reg);
+  if (regno <= 31)
+    result = new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + regno),
+                           offset, 0);
+  else
+    result = new_loc_descr (DW_OP_bregx, regno, offset);
+
+  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
+  return result;
+}
+
+/* Return true if this RTL expression describes a base+offset calculation.  */
+
+static inline int
+is_based_loc (const_rtx rtl)
+{
+  return (GET_CODE (rtl) == PLUS
+         && ((REG_P (XEXP (rtl, 0))
+              && REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
+              && CONST_INT_P (XEXP (rtl, 1)))));
+}
+
+/* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0)
+   failed.  */
+
+static dw_loc_descr_ref
+tls_mem_loc_descriptor (rtx mem)
+{
+  tree base;
+  dw_loc_descr_ref loc_result;
+
+  if (MEM_EXPR (mem) == NULL_TREE || MEM_OFFSET (mem) == NULL_RTX)
+    return NULL;
+
+  base = get_base_address (MEM_EXPR (mem));
+  if (base == NULL
+      || TREE_CODE (base) != VAR_DECL
+      || !DECL_THREAD_LOCAL_P (base))
+    return NULL;
+
+  loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1);
+  if (loc_result == NULL)
+    return NULL;
+
+  if (INTVAL (MEM_OFFSET (mem)))
+    loc_descr_plus_const (&loc_result, INTVAL (MEM_OFFSET (mem)));
+
+  return loc_result;
+}
+
+/* Output debug info about reason why we failed to expand expression as dwarf
+   expression.  */
+
+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) != 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.  */
+
+static dw_loc_descr_ref
+mem_loc_descriptor (rtx rtl, enum machine_mode mode,
+                   enum var_init_status initialized)
+{
+  dw_loc_descr_ref mem_loc_result = NULL;
+  enum dwarf_location_atom op;
+  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
+     actually within the array.  That's *not* necessarily the same as the
+     zeroth element of the array.  */
+
+  rtl = targetm.delegitimize_address (rtl);
+
+  switch (GET_CODE (rtl))
+    {
+    case POST_INC:
+    case POST_DEC:
+    case POST_MODIFY:
+      return mem_loc_descriptor (XEXP (rtl, 0), mode, initialized);
+
+    case SUBREG:
+      /* The case of a subreg may arise when we have a local (register)
+        variable or a formal (register) parameter which doesn't quite fill
+        up an entire register.  For now, just assume that it is
+        legitimate to make the Dwarf info refer to the whole register which
+        contains the given subreg.  */
+      if (!subreg_lowpart_p (rtl))
+       break;
+      rtl = SUBREG_REG (rtl);
+      if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE)
+       break;
+      if (GET_MODE_CLASS (GET_MODE (rtl)) != MODE_INT)
+       break;
+      mem_loc_result = mem_loc_descriptor (rtl, mode, initialized);
+      break;
+
+    case REG:
+      /* Whenever a register number forms a part of the description of the
+        method for calculating the (dynamic) address of a memory resident
+        object, DWARF rules require the register number be referred to as
+        a "base register".  This distinction is not based in any way upon
+        what category of register the hardware believes the given register
+        belongs to.  This is strictly DWARF terminology we're dealing with
+        here. Note that in cases where the location of a memory-resident
+        data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
+        OP_CONST (0)) the actual DWARF location descriptor that we generate
+        may just be OP_BASEREG (basereg).  This may look deceptively like
+        the object in question was allocated to a register (rather than in
+        memory) so DWARF consumers need to be aware of the subtle
+        distinction between OP_REG and OP_BASEREG.  */
+      if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
+       mem_loc_result = based_loc_descr (rtl, 0, VAR_INIT_STATUS_INITIALIZED);
+      else if (stack_realign_drap
+              && crtl->drap_reg
+              && crtl->args.internal_arg_pointer == rtl
+              && REGNO (crtl->drap_reg) < FIRST_PSEUDO_REGISTER)
+       {
+         /* If RTL is internal_arg_pointer, which has been optimized
+            out, use DRAP instead.  */
+         mem_loc_result = based_loc_descr (crtl->drap_reg, 0,
+                                           VAR_INIT_STATUS_INITIALIZED);
+       }
+      break;
+
+    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));
+      break;
+
+    case LO_SUM:
+        rtl = XEXP (rtl, 1);
+
+      /* ... fall through ...  */
+
+    case LABEL_REF:
+      /* Some ports can transform a symbol ref into a label ref, because
+        the symbol ref is too far away and has to be dumped into a constant
+        pool.  */
+    case CONST:
+    case SYMBOL_REF:
+      /* Alternatively, the symbol in the constant pool might be referenced
+        by a different symbol.  */
+      if (GET_CODE (rtl) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (rtl))
+       {
+         bool marked;
+         rtx tmp = get_pool_constant_mark (rtl, &marked);
+
+         if (GET_CODE (tmp) == SYMBOL_REF)
+           {
+             rtl = tmp;
+             if (CONSTANT_POOL_ADDRESS_P (tmp))
+               get_pool_constant_mark (tmp, &marked);
+             else
+               marked = true;
+           }
+
+         /* If all references to this pool constant were optimized away,
+            it was not output and thus we can't represent it.
+            FIXME: might try to use DW_OP_const_value here, though
+            DW_OP_piece complicates it.  */
+         if (!marked)
+           {
+             expansion_failed (NULL_TREE, rtl,
+                               "Constant was removed from constant pool.\n");
+             return 0;
+           }
+       }
+
+      if (GET_CODE (rtl) == SYMBOL_REF
+         && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
+       {
+         dw_loc_descr_ref temp;
+
+         /* If this is not defined, we have no way to emit the data.  */
+         if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
+           break;
+
+         temp = new_loc_descr (DW_OP_addr, 0, 0);
+         temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
+         temp->dw_loc_oprnd1.v.val_addr = rtl;
+         temp->dtprel = true;
+
+         mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
+         add_loc_descr (&mem_loc_result, temp);
 
-  /* Builtin types don't have a DECL_ORIGINAL_TYPE.  For those,
-     don't output a DW_TAG_typedef, since there isn't one in the
-     user's program; just attach a DW_AT_name to the type.  */
-  if (name
-      && (TREE_CODE (name) != TYPE_DECL
-         || (TREE_TYPE (name) == qualified_type && DECL_NAME (name))))
-    {
-      if (TREE_CODE (name) == TYPE_DECL)
-       /* Could just call add_name_and_src_coords_attributes here,
-          but since this is a builtin type it doesn't have any
-          useful source coordinates anyway.  */
-       name = DECL_NAME (name);
-      add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
-    }
+         break;
+       }
 
-  if (qualified_type)
-    equate_type_number_to_die (qualified_type, mod_type_die);
+      if (!const_ok_for_output (rtl))
+       break;
 
-  if (item_type)
-    /* We must do this after the equate_type_number_to_die call, in case
-       this is a recursive type.  This ensures that the modified_type_die
-       recursion will terminate even if the type is recursive.  Recursive
-       types are possible in Ada.  */
-    sub_die = modified_type_die (item_type,
-                                TYPE_READONLY (item_type),
-                                TYPE_VOLATILE (item_type),
-                                context_die);
+    symref:
+      mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
+      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
+      mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+      break;
 
-  if (sub_die != NULL)
-    add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
+    case CONCAT:
+    case CONCATN:
+    case VAR_LOCATION:
+      expansion_failed (NULL_TREE, rtl,
+                       "CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor");
+      return 0;
 
-  return mod_type_die;
-}
+    case PRE_MODIFY:
+      /* Extract the PLUS expression nested inside and fall into
+        PLUS code below.  */
+      rtl = XEXP (rtl, 1);
+      goto plus;
 
-/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
-   an enumerated type.  */
+    case PRE_INC:
+    case PRE_DEC:
+      /* Turn these into a PLUS expression and fall into the PLUS code
+        below.  */
+      rtl = gen_rtx_PLUS (word_mode, XEXP (rtl, 0),
+                         GEN_INT (GET_CODE (rtl) == PRE_INC
+                                  ? GET_MODE_UNIT_SIZE (mode)
+                                  : -GET_MODE_UNIT_SIZE (mode)));
 
-static inline int
-type_is_enum (const_tree type)
-{
-  return TREE_CODE (type) == ENUMERAL_TYPE;
-}
+      /* ... fall through ...  */
 
-/* Return the DBX register number described by a given RTL node.  */
+    case PLUS:
+    plus:
+      if (is_based_loc (rtl))
+       mem_loc_result = based_loc_descr (XEXP (rtl, 0),
+                                         INTVAL (XEXP (rtl, 1)),
+                                         VAR_INIT_STATUS_INITIALIZED);
+      else
+       {
+         mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                                              VAR_INIT_STATUS_INITIALIZED);
+         if (mem_loc_result == 0)
+           break;
 
-static unsigned int
-dbx_reg_number (const_rtx rtl)
-{
-  unsigned regno = REGNO (rtl);
+         if (CONST_INT_P (XEXP (rtl, 1)))
+           loc_descr_plus_const (&mem_loc_result, INTVAL (XEXP (rtl, 1)));
+         else
+           {
+             dw_loc_descr_ref mem_loc_result2
+               = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                                     VAR_INIT_STATUS_INITIALIZED);
+             if (mem_loc_result2 == 0)
+               break;
+             add_loc_descr (&mem_loc_result, mem_loc_result2);
+             add_loc_descr (&mem_loc_result,
+                            new_loc_descr (DW_OP_plus, 0, 0));
+           }
+       }
+      break;
 
-  gcc_assert (regno < FIRST_PSEUDO_REGISTER);
+    /* 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;
 
-#ifdef LEAF_REG_REMAP
-  if (current_function_uses_only_leaf_regs)
-    {
-      int leaf_reg = LEAF_REG_REMAP (regno);
-      if (leaf_reg != -1)
-       regno = (unsigned) leaf_reg;
-    }
-#endif
+    case MULT:
+      op = DW_OP_mul;
+      goto do_binop;
 
-  return DBX_REGISTER_NUMBER (regno);
-}
+    case DIV:
+      op = DW_OP_div;
+      goto do_binop;
 
-/* Optionally add a DW_OP_piece term to a location description expression.
-   DW_OP_piece is only added if the location description expression already
-   doesn't end with DW_OP_piece.  */
+    case MOD:
+      op = DW_OP_mod;
+      goto do_binop;
 
-static void
-add_loc_descr_op_piece (dw_loc_descr_ref *list_head, int size)
-{
-  dw_loc_descr_ref loc;
+    case ASHIFT:
+      op = DW_OP_shl;
+      goto do_binop;
 
-  if (*list_head != NULL)
-    {
-      /* Find the end of the chain.  */
-      for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
-       ;
+    case ASHIFTRT:
+      op = DW_OP_shra;
+      goto do_binop;
 
-      if (loc->dw_loc_opc != DW_OP_piece)
-       loc->dw_loc_next = new_loc_descr (DW_OP_piece, size, 0);
-    }
-}
+    case LSHIFTRT:
+      op = DW_OP_shr;
+      goto do_binop;
 
-/* Return a location descriptor that designates a machine register or
-   zero if there is none.  */
+    case AND:
+      op = DW_OP_and;
+      goto do_binop;
 
-static dw_loc_descr_ref
-reg_loc_descriptor (rtx rtl, enum var_init_status initialized)
-{
-  rtx regs;
+    case IOR:
+      op = DW_OP_or;
+      goto do_binop;
 
-  if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
-    return 0;
+    case XOR:
+      op = DW_OP_xor;
+      goto do_binop;
 
-  regs = targetm.dwarf_register_span (rtl);
+    do_binop:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-  if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
-    return multiple_reg_loc_descriptor (rtl, regs, initialized);
-  else
-    return one_reg_loc_descriptor (dbx_reg_number (rtl), initialized);
-}
+      if (op0 == 0 || op1 == 0)
+       break;
 
-/* Return a location descriptor that designates a machine register for
-   a given hard register number.  */
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      break;
 
-static dw_loc_descr_ref
-one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized)
-{
-  dw_loc_descr_ref reg_loc_descr;
+    case NOT:
+      op = DW_OP_not;
+      goto do_unop;
 
-  if (regno <= 31)
-    reg_loc_descr
-      = new_loc_descr ((enum dwarf_location_atom) (DW_OP_reg0 + regno), 0, 0);
-  else
-    reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0);
+    case ABS:
+      op = DW_OP_abs;
+      goto do_unop;
 
-  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&reg_loc_descr, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+    case NEG:
+      op = DW_OP_neg;
+      goto do_unop;
 
-  return reg_loc_descr;
-}
+    do_unop:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-/* Given an RTL of a register, return a location descriptor that
-   designates a value that spans more than one register.  */
+      if (op0 == 0)
+       break;
 
-static dw_loc_descr_ref
-multiple_reg_loc_descriptor (rtx rtl, rtx regs,
-                            enum var_init_status initialized)
-{
-  int nregs, size, i;
-  unsigned reg;
-  dw_loc_descr_ref loc_result = NULL;
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      break;
 
-  reg = REGNO (rtl);
-#ifdef LEAF_REG_REMAP
-  if (current_function_uses_only_leaf_regs)
-    {
-      int leaf_reg = LEAF_REG_REMAP (reg);
-      if (leaf_reg != -1)
-       reg = (unsigned) leaf_reg;
-    }
-#endif
-  gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
-  nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
+    case CONST_INT:
+      mem_loc_result = int_loc_descriptor (INTVAL (rtl));
+      break;
 
-  /* Simple, contiguous registers.  */
-  if (regs == NULL_RTX)
-    {
-      size = GET_MODE_SIZE (GET_MODE (rtl)) / nregs;
+    case EQ:
+      op = DW_OP_eq;
+      goto do_scompare;
 
-      loc_result = NULL;
-      while (nregs--)
-       {
-         dw_loc_descr_ref t;
+    case GE:
+      op = DW_OP_ge;
+      goto do_scompare;
 
-         t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg),
-                                     VAR_INIT_STATUS_INITIALIZED);
-         add_loc_descr (&loc_result, t);
-         add_loc_descr_op_piece (&loc_result, size);
-         ++reg;
-       }
-      return loc_result;
-    }
+    case GT:
+      op = DW_OP_gt;
+      goto do_scompare;
 
-  /* Now onto stupid register sets in non contiguous locations.  */
+    case LE:
+      op = DW_OP_le;
+      goto do_scompare;
 
-  gcc_assert (GET_CODE (regs) == PARALLEL);
+    case LT:
+      op = DW_OP_lt;
+      goto do_scompare;
+
+    case NE:
+      op = DW_OP_ne;
+      goto do_scompare;
+
+    do_scompare:
+      if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
+         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+         || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+       break;
+
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+
+      if (op0 == 0 || op1 == 0)
+       break;
+
+      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+       {
+         int shift = DWARF2_ADDR_SIZE
+                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+         shift *= BITS_PER_UNIT;
+         add_loc_descr (&op0, int_loc_descriptor (shift));
+         add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+         if (CONST_INT_P (XEXP (rtl, 1)))
+           op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift);
+         else
+           {
+             add_loc_descr (&op1, int_loc_descriptor (shift));
+             add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+           }
+       }
 
-  size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
-  loc_result = NULL;
+    do_compare:
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      if (STORE_FLAG_VALUE != 1)
+       {
+         add_loc_descr (&mem_loc_result,
+                        int_loc_descriptor (STORE_FLAG_VALUE));
+         add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
+       }
+      break;
 
-  for (i = 0; i < XVECLEN (regs, 0); ++i)
-    {
-      dw_loc_descr_ref t;
+    case GEU:
+      op = DW_OP_ge;
+      goto do_ucompare;
 
-      t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)),
-                                 VAR_INIT_STATUS_INITIALIZED);
-      add_loc_descr (&loc_result, t);
-      size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
-      add_loc_descr_op_piece (&loc_result, size);
-    }
+    case GTU:
+      op = DW_OP_gt;
+      goto do_ucompare;
 
-  if (loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
-  return loc_result;
-}
+    case LEU:
+      op = DW_OP_le;
+      goto do_ucompare;
 
-#endif /* DWARF2_DEBUGGING_INFO */
+    case LTU:
+      op = DW_OP_lt;
+      goto do_ucompare;
 
-#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+    do_ucompare:
+      if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
+         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+         || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+       break;
 
-/* Return a location descriptor that designates a constant.  */
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-static dw_loc_descr_ref
-int_loc_descriptor (HOST_WIDE_INT i)
-{
-  enum dwarf_location_atom op;
+      if (op0 == 0 || op1 == 0)
+       break;
 
-  /* Pick the smallest representation of a constant, rather than just
-     defaulting to the LEB encoding.  */
-  if (i >= 0)
-    {
-      if (i <= 31)
-       op = (enum dwarf_location_atom) (DW_OP_lit0 + i);
-      else if (i <= 0xff)
-       op = DW_OP_const1u;
-      else if (i <= 0xffff)
-       op = DW_OP_const2u;
-      else if (HOST_BITS_PER_WIDE_INT == 32
-              || i <= 0xffffffff)
-       op = DW_OP_const4u;
-      else
-       op = DW_OP_constu;
-    }
-  else
-    {
-      if (i >= -0x80)
-       op = DW_OP_const1s;
-      else if (i >= -0x8000)
-       op = DW_OP_const2s;
-      else if (HOST_BITS_PER_WIDE_INT == 32
-              || i >= -0x80000000)
-       op = DW_OP_const4s;
+      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+       {
+         HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0)));
+         add_loc_descr (&op0, int_loc_descriptor (mask));
+         add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+         if (CONST_INT_P (XEXP (rtl, 1)))
+           op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask);
+         else
+           {
+             add_loc_descr (&op1, int_loc_descriptor (mask));
+             add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
+           }
+       }
       else
-       op = DW_OP_consts;
-    }
+       {
+         HOST_WIDE_INT bias = 1;
+         bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
+         add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+         if (CONST_INT_P (XEXP (rtl, 1)))
+           op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias
+                                     + INTVAL (XEXP (rtl, 1)));
+         else
+           add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+       }
+      goto do_compare;
+
+    case SMIN:
+    case SMAX:
+    case UMIN:
+    case UMAX:
+      if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
+         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+         || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+       break;
 
-  return new_loc_descr (op, i, 0);
-}
-#endif
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-#ifdef DWARF2_DEBUGGING_INFO
+      if (op0 == 0 || op1 == 0)
+       break;
 
-/* Return a location descriptor that designates a base+offset location.  */
+      add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
+      add_loc_descr (&op1, new_loc_descr (DW_OP_swap, 0, 0));
+      add_loc_descr (&op1, new_loc_descr (DW_OP_over, 0, 0));
+      if (GET_CODE (rtl) == UMIN || GET_CODE (rtl) == UMAX)
+       {
+         if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+           {
+             HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0)));
+             add_loc_descr (&op0, int_loc_descriptor (mask));
+             add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+             add_loc_descr (&op1, int_loc_descriptor (mask));
+             add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
+           }
+         else
+           {
+             HOST_WIDE_INT bias = 1;
+             bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
+             add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+             add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+           }
+       }
+      else if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+       {
+         int shift = DWARF2_ADDR_SIZE
+                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+         shift *= BITS_PER_UNIT;
+         add_loc_descr (&op0, int_loc_descriptor (shift));
+         add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+         add_loc_descr (&op1, int_loc_descriptor (shift));
+         add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+       }
 
-static dw_loc_descr_ref
-based_loc_descr (rtx reg, HOST_WIDE_INT offset,
-                enum var_init_status initialized)
-{
-  unsigned int regno;
-  dw_loc_descr_ref result;
-  dw_fde_ref fde = current_fde ();
+      if (GET_CODE (rtl) == SMIN || GET_CODE (rtl) == UMIN)
+       op = DW_OP_lt;
+      else
+       op = DW_OP_gt;
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      {
+       dw_loc_descr_ref bra_node, drop_node;
 
-  /* We only use "frame base" when we're sure we're talking about the
-     post-prologue local stack frame.  We do this by *not* running
-     register elimination until this point, and recognizing the special
-     argument pointer and soft frame pointer rtx's.  */
-  if (reg == arg_pointer_rtx || reg == frame_pointer_rtx)
-    {
-      rtx elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+       bra_node = new_loc_descr (DW_OP_bra, 0, 0);
+       add_loc_descr (&mem_loc_result, bra_node);
+       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_swap, 0, 0));
+       drop_node = new_loc_descr (DW_OP_drop, 0, 0);
+       add_loc_descr (&mem_loc_result, drop_node);
+       bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+       bra_node->dw_loc_oprnd1.v.val_loc = drop_node;
+      }
+      break;
 
-      if (elim != reg)
+    case ZERO_EXTRACT:
+    case SIGN_EXTRACT:
+      if (CONST_INT_P (XEXP (rtl, 1))
+         && CONST_INT_P (XEXP (rtl, 2))
+         && ((unsigned) INTVAL (XEXP (rtl, 1))
+             + (unsigned) INTVAL (XEXP (rtl, 2))
+             <= GET_MODE_BITSIZE (GET_MODE (rtl)))
+         && GET_MODE_BITSIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE
+         && GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0))) <= DWARF2_ADDR_SIZE)
        {
-         if (GET_CODE (elim) == PLUS)
+         int shift, size;
+         op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                                   VAR_INIT_STATUS_INITIALIZED);
+         if (op0 == 0)
+           break;
+         if (GET_CODE (rtl) == SIGN_EXTRACT)
+           op = DW_OP_shra;
+         else
+           op = DW_OP_shr;
+         mem_loc_result = op0;
+         size = INTVAL (XEXP (rtl, 1));
+         shift = INTVAL (XEXP (rtl, 2));
+         if (BITS_BIG_ENDIAN)
+           shift = GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0)))
+                   - shift - size;
+         if (shift + size != (int) DWARF2_ADDR_SIZE)
            {
-             offset += INTVAL (XEXP (elim, 1));
-             elim = XEXP (elim, 0);
+             add_loc_descr (&mem_loc_result,
+                            int_loc_descriptor (DWARF2_ADDR_SIZE
+                                                - shift - size));
+             add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
            }
-         gcc_assert ((SUPPORTS_STACK_ALIGNMENT
-                      && (elim == hard_frame_pointer_rtx
-                          || elim == stack_pointer_rtx))
-                     || elim == (frame_pointer_needed
-                                 ? hard_frame_pointer_rtx
-                                 : stack_pointer_rtx));
-
-         /* If drap register is used to align stack, use frame
-            pointer + offset to access stack variables.  If stack
-            is aligned without drap, use stack pointer + offset to
-            access stack variables.  */
-         if (crtl->stack_realign_tried
-             && cfa.reg == HARD_FRAME_POINTER_REGNUM
-             && reg == frame_pointer_rtx)
+         if (size != (int) DWARF2_ADDR_SIZE)
            {
-             int base_reg
-               = DWARF_FRAME_REGNUM (cfa.indirect
-                                     ? HARD_FRAME_POINTER_REGNUM
-                                     : STACK_POINTER_REGNUM);
-             return new_reg_loc_descr (base_reg, offset);
+             add_loc_descr (&mem_loc_result,
+                            int_loc_descriptor (DWARF2_ADDR_SIZE - size));
+             add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
            }
-
-         offset += frame_pointer_fb_offset;
-         return new_loc_descr (DW_OP_fbreg, offset, 0);
        }
-    }
-  else if (fde
-          && fde->drap_reg != INVALID_REGNUM
-          && (fde->drap_reg == REGNO (reg)
-              || fde->vdrap_reg == REGNO (reg)))
-    {
-      /* Use cfa+offset to represent the location of arguments passed
-        on stack when drap is used to align stack.  */
-      return new_loc_descr (DW_OP_fbreg, offset, 0);
-    }
+      break;
 
-  regno = dbx_reg_number (reg);
-  if (regno <= 31)
-    result = new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + regno),
-                           offset, 0);
-  else
-    result = new_loc_descr (DW_OP_bregx, regno, offset);
+    case COMPARE:
+    case IF_THEN_ELSE:
+    case ROTATE:
+    case ROTATERT:
+    case TRUNCATE:
+      /* In theory, we could implement the above.  */
+      /* DWARF cannot represent the unsigned compare operations
+        natively.  */
+    case SS_MULT:
+    case US_MULT:
+    case SS_DIV:
+    case US_DIV:
+    case UDIV:
+    case UMOD:
+    case UNORDERED:
+    case ORDERED:
+    case UNEQ:
+    case UNGE:
+    case UNGT:
+    case UNLE:
+    case UNLT:
+    case LTGT:
+    case FLOAT_EXTEND:
+    case FLOAT_TRUNCATE:
+    case FLOAT:
+    case UNSIGNED_FLOAT:
+    case FIX:
+    case UNSIGNED_FIX:
+    case FRACT_CONVERT:
+    case UNSIGNED_FRACT_CONVERT:
+    case SAT_FRACT:
+    case UNSIGNED_SAT_FRACT:
+    case SQRT:
+    case BSWAP:
+    case FFS:
+    case CLZ:
+    case CTZ:
+    case POPCOUNT:
+    case PARITY:
+    case ASM_OPERANDS:
+    case UNSPEC:
+    case HIGH:
+      /* If delegitimize_address couldn't do anything with the UNSPEC, we
+        can't express it in the debug info.  This can happen e.g. with some
+        TLS UNSPECs.  */
+      break;
 
-  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+    case CONST_STRING:
+      resolve_one_addr (&rtl, NULL);
+      goto symref;
 
-  return result;
+    default:
+#ifdef ENABLE_CHECKING
+      print_rtl (stderr, rtl);
+      gcc_unreachable ();
+#else
+      break;
+#endif
+    }
+
+  if (mem_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
+  return mem_loc_result;
 }
 
-/* Return true if this RTL expression describes a base+offset calculation.  */
+/* Return a descriptor that describes the concatenation of two locations.
+   This is typically a complex variable.  */
 
-static inline int
-is_based_loc (const_rtx rtl)
+static dw_loc_descr_ref
+concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
 {
-  return (GET_CODE (rtl) == PLUS
-         && ((REG_P (XEXP (rtl, 0))
-              && REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
-              && GET_CODE (XEXP (rtl, 1)) == CONST_INT)));
+  dw_loc_descr_ref cc_loc_result = NULL;
+  dw_loc_descr_ref x0_ref
+    = loc_descriptor (x0, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+  dw_loc_descr_ref x1_ref
+    = loc_descriptor (x1, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+
+  if (x0_ref == 0 || x1_ref == 0)
+    return 0;
+
+  cc_loc_result = x0_ref;
+  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x0)));
+
+  add_loc_descr (&cc_loc_result, x1_ref);
+  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1)));
+
+  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
+  return cc_loc_result;
 }
 
-/* Return a descriptor that describes the concatenation of N locations
-   used to form the address of a memory location.  */
+/* Return a descriptor that describes the concatenation of N
+   locations.  */
 
 static dw_loc_descr_ref
-concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode,
-                           enum var_init_status initialized)
+concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
 {
   unsigned int i;
   dw_loc_descr_ref cc_loc_result = NULL;
@@ -10245,7 +13537,7 @@ concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode,
       dw_loc_descr_ref ref;
       rtx x = XVECEXP (concatn, 0, i);
 
-      ref = mem_loc_descriptor (x, mode, VAR_INIT_STATUS_INITIALIZED);
+      ref = loc_descriptor (x, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
       if (ref == NULL)
        return NULL;
 
@@ -10259,425 +13551,643 @@ concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode,
   return cc_loc_result;
 }
 
-/* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0)
-   failed.  */
-
-static dw_loc_descr_ref
-tls_mem_loc_descriptor (rtx mem)
-{
-  tree base;
-  dw_loc_descr_ref loc_result;
-
-  if (MEM_EXPR (mem) == NULL_TREE || MEM_OFFSET (mem) == NULL_RTX)
-    return NULL;
-
-  base = get_base_address (MEM_EXPR (mem));
-  if (base == NULL
-      || TREE_CODE (base) != VAR_DECL
-      || !DECL_THREAD_LOCAL_P (base))
-    return NULL;
-
-  loc_result = loc_descriptor_from_tree_1 (MEM_EXPR (mem), 2);
-  if (loc_result == NULL)
-    return NULL;
-
-  if (INTVAL (MEM_OFFSET (mem)))
-    loc_descr_plus_const (&loc_result, INTVAL (MEM_OFFSET (mem)));
-
-  return loc_result;
-}
-
-/* The following routine converts the RTL for a variable or parameter
-   (resident in memory) into an equivalent Dwarf representation of a
-   mechanism for getting the address of that same variable onto the top of a
-   hypothetical "address evaluation" stack.
-
-   When creating memory location descriptors, we are effectively transforming
-   the RTL for a memory-resident object into its Dwarf postfix expression
-   equivalent.  This routine recursively descends an RTL tree, turning
-   it into Dwarf postfix code as it goes.
-
-   MODE is the mode of the memory reference, needed to handle some
-   autoincrement addressing modes.
-
-   CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the
-   location list for RTL.
-
-   Return 0 if we can't represent the location.  */
-
-static dw_loc_descr_ref
-mem_loc_descriptor (rtx rtl, enum machine_mode mode,
-                   enum var_init_status initialized)
-{
-  dw_loc_descr_ref mem_loc_result = NULL;
-  enum dwarf_location_atom op;
+/* Output a proper Dwarf location descriptor for a variable or parameter
+   which is either allocated in a register or in a memory location.  For a
+   register, we just generate an OP_REG and the register number.  For a
+   memory location we provide a Dwarf postfix expression describing how to
+   generate the (dynamic) address of the object onto the address stack.
 
-  /* Note that for a dynamically sized array, the location we will generate a
-     description of here will be the lowest numbered location which is
-     actually within the array.  That's *not* necessarily the same as the
-     zeroth element of the array.  */
+   MODE is mode of the decl if this loc_descriptor is going to be used in
+   .debug_loc section where DW_OP_stack_value and DW_OP_implicit_value are
+   allowed, VOIDmode otherwise.
 
-  rtl = targetm.delegitimize_address (rtl);
+   If we don't know how to describe it, return 0.  */
+
+static dw_loc_descr_ref
+loc_descriptor (rtx rtl, enum machine_mode mode,
+               enum var_init_status initialized)
+{
+  dw_loc_descr_ref loc_result = NULL;
 
   switch (GET_CODE (rtl))
     {
-    case POST_INC:
-    case POST_DEC:
-    case POST_MODIFY:
-      /* POST_INC and POST_DEC can be handled just like a SUBREG.  So we
-        just fall into the SUBREG code.  */
-
-      /* ... fall through ...  */
-
     case SUBREG:
       /* The case of a subreg may arise when we have a local (register)
         variable or a formal (register) parameter which doesn't quite fill
         up an entire register.  For now, just assume that it is
         legitimate to make the Dwarf info refer to the whole register which
         contains the given subreg.  */
-      rtl = XEXP (rtl, 0);
-
-      /* ... fall through ...  */
+      loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized);
+      break;
 
     case REG:
-      /* Whenever a register number forms a part of the description of the
-        method for calculating the (dynamic) address of a memory resident
-        object, DWARF rules require the register number be referred to as
-        a "base register".  This distinction is not based in any way upon
-        what category of register the hardware believes the given register
-        belongs to.  This is strictly DWARF terminology we're dealing with
-        here. Note that in cases where the location of a memory-resident
-        data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
-        OP_CONST (0)) the actual DWARF location descriptor that we generate
-        may just be OP_BASEREG (basereg).  This may look deceptively like
-        the object in question was allocated to a register (rather than in
-        memory) so DWARF consumers need to be aware of the subtle
-        distinction between OP_REG and OP_BASEREG.  */
-      if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
-       mem_loc_result = based_loc_descr (rtl, 0, VAR_INIT_STATUS_INITIALIZED);
-      else if (stack_realign_drap
-              && crtl->drap_reg
-              && crtl->args.internal_arg_pointer == rtl
-              && REGNO (crtl->drap_reg) < FIRST_PSEUDO_REGISTER)
-       {
-         /* If RTL is internal_arg_pointer, which has been optimized
-            out, use DRAP instead.  */
-         mem_loc_result = based_loc_descr (crtl->drap_reg, 0,
-                                           VAR_INIT_STATUS_INITIALIZED);
-       }
+      loc_result = reg_loc_descriptor (rtl, initialized);
+      break;
+
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
+      loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
       break;
 
     case MEM:
-      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
-                                          VAR_INIT_STATUS_INITIALIZED);
-      if (mem_loc_result == NULL)
-       mem_loc_result = tls_mem_loc_descriptor (rtl);
-      if (mem_loc_result != 0)
-       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
+      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+                                      initialized);
+      if (loc_result == NULL)
+       loc_result = tls_mem_loc_descriptor (rtl);
       break;
 
-    case LO_SUM:
-        rtl = XEXP (rtl, 1);
+    case CONCAT:
+      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1),
+                                         initialized);
+      break;
 
-      /* ... fall through ...  */
+    case CONCATN:
+      loc_result = concatn_loc_descriptor (rtl, initialized);
+      break;
 
-    case LABEL_REF:
-      /* Some ports can transform a symbol ref into a label ref, because
-        the symbol ref is too far away and has to be dumped into a constant
-        pool.  */
-    case CONST:
-    case SYMBOL_REF:
-      /* Alternatively, the symbol in the constant pool might be referenced
-        by a different symbol.  */
-      if (GET_CODE (rtl) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (rtl))
+    case VAR_LOCATION:
+      /* Single part.  */
+      if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
        {
-         bool marked;
-         rtx tmp = get_pool_constant_mark (rtl, &marked);
-
-         if (GET_CODE (tmp) == SYMBOL_REF)
-           {
-             rtl = tmp;
-             if (CONSTANT_POOL_ADDRESS_P (tmp))
-               get_pool_constant_mark (tmp, &marked);
-             else
-               marked = true;
-           }
-
-         /* 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;
+         loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), mode,
+                                      initialized);
+         break;
        }
 
-      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 PRE_MODIFY:
-      /* Extract the PLUS expression nested inside and fall into
-        PLUS code below.  */
       rtl = XEXP (rtl, 1);
-      goto plus;
+      /* FALLTHRU */
 
-    case PRE_INC:
-    case PRE_DEC:
-      /* Turn these into a PLUS expression and fall into the PLUS code
-        below.  */
-      rtl = gen_rtx_PLUS (word_mode, XEXP (rtl, 0),
-                         GEN_INT (GET_CODE (rtl) == PRE_INC
-                                  ? GET_MODE_UNIT_SIZE (mode)
-                                  : -GET_MODE_UNIT_SIZE (mode)));
+    case PARALLEL:
+      {
+       rtvec par_elems = XVEC (rtl, 0);
+       int num_elem = GET_NUM_ELEM (par_elems);
+       enum machine_mode mode;
+       int i;
 
-      /* ... fall through ...  */
+       /* Create the first one, so we have something to add to.  */
+       loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
+                                    VOIDmode, initialized);
+       if (loc_result == NULL)
+         return NULL;
+       mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
+       add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+       for (i = 1; i < num_elem; i++)
+         {
+           dw_loc_descr_ref temp;
 
-    case PLUS:
-    plus:
-      if (is_based_loc (rtl))
-       mem_loc_result = based_loc_descr (XEXP (rtl, 0),
-                                         INTVAL (XEXP (rtl, 1)),
-                                         VAR_INIT_STATUS_INITIALIZED);
-      else
+           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 && (dwarf_version >= 4 || !dwarf_strict))
        {
-         mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                                              VAR_INIT_STATUS_INITIALIZED);
-         if (mem_loc_result == 0)
-           break;
+         /* 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.  */
+         if (GET_MODE (rtl) != VOIDmode)
+           mode = GET_MODE (rtl);
 
-         if (GET_CODE (XEXP (rtl, 1)) == CONST_INT)
-           loc_descr_plus_const (&mem_loc_result, INTVAL (XEXP (rtl, 1)));
+         loc_result = new_loc_descr (DW_OP_implicit_value,
+                                     GET_MODE_SIZE (mode), 0);
+         if (SCALAR_FLOAT_MODE_P (mode))
+           {
+             unsigned int length = GET_MODE_SIZE (mode);
+             unsigned char *array = GGC_NEWVEC (unsigned char, length);
+
+             insert_float (rtl, array);
+             loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+             loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4;
+             loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
+             loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+           }
          else
            {
-             dw_loc_descr_ref mem_loc_result2
-               = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                                     VAR_INIT_STATUS_INITIALIZED);
-             if (mem_loc_result2 == 0)
-               break;
-             add_loc_descr (&mem_loc_result, mem_loc_result2);
-             add_loc_descr (&mem_loc_result,
-                            new_loc_descr (DW_OP_plus, 0, 0));
+             loc_result->dw_loc_oprnd2.val_class = dw_val_class_const_double;
+             loc_result->dw_loc_oprnd2.v.val_double.high
+               = CONST_DOUBLE_HIGH (rtl);
+             loc_result->dw_loc_oprnd2.v.val_double.low
+               = CONST_DOUBLE_LOW (rtl);
            }
        }
       break;
 
-    /* If a pseudo-reg is optimized away, it is possible for it to
-       be replaced with a MEM containing a multiply or shift.  */
-    case MULT:
-      op = DW_OP_mul;
-      goto do_binop;
+    case CONST_VECTOR:
+      if (mode != VOIDmode && (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;
+
+         mode = GET_MODE (rtl);
+         switch (GET_MODE_CLASS (mode))
+           {
+           case MODE_VECTOR_INT:
+             for (i = 0, p = array; i < length; i++, p += elt_size)
+               {
+                 rtx elt = CONST_VECTOR_ELT (rtl, i);
+                 HOST_WIDE_INT lo, hi;
 
-    case ASHIFT:
-      op = DW_OP_shl;
-      goto do_binop;
+                 switch (GET_CODE (elt))
+                   {
+                   case CONST_INT:
+                     lo = INTVAL (elt);
+                     hi = -(lo < 0);
+                     break;
 
-    case ASHIFTRT:
-      op = DW_OP_shra;
-      goto do_binop;
+                   case CONST_DOUBLE:
+                     lo = CONST_DOUBLE_LOW (elt);
+                     hi = CONST_DOUBLE_HIGH (elt);
+                     break;
 
-    case LSHIFTRT:
-      op = DW_OP_shr;
-      goto do_binop;
+                   default:
+                     gcc_unreachable ();
+                   }
 
-    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);
+                 if (elt_size <= sizeof (HOST_WIDE_INT))
+                   insert_int (lo, elt_size, p);
+                 else
+                   {
+                     unsigned char *p0 = p;
+                     unsigned char *p1 = p + sizeof (HOST_WIDE_INT);
+
+                     gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
+                     if (WORDS_BIG_ENDIAN)
+                       {
+                         p0 = p1;
+                         p1 = p;
+                       }
+                     insert_int (lo, sizeof (HOST_WIDE_INT), p0);
+                     insert_int (hi, sizeof (HOST_WIDE_INT), p1);
+                   }
+               }
+             break;
 
-       if (op0 == 0 || op1 == 0)
-         break;
+           case MODE_VECTOR_FLOAT:
+             for (i = 0, p = array; i < length; i++, p += elt_size)
+               {
+                 rtx elt = CONST_VECTOR_ELT (rtl, i);
+                 insert_float (elt, p);
+               }
+             break;
 
-       mem_loc_result = op0;
-       add_loc_descr (&mem_loc_result, op1);
-       add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
-       break;
-      }
+           default:
+             gcc_unreachable ();
+           }
 
-    case CONST_INT:
-      mem_loc_result = int_loc_descriptor (INTVAL (rtl));
+         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 CONCATN:
-      mem_loc_result = concatn_mem_loc_descriptor (rtl, mode,
-                                                  VAR_INIT_STATUS_INITIALIZED);
+    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_implicit_value,
+                                     DWARF2_ADDR_SIZE, 0);
+         loc_result->dw_loc_oprnd2.val_class = dw_val_class_addr;
+         loc_result->dw_loc_oprnd2.v.val_addr = rtl;
+         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;
+}
 
-    case UNSPEC:
-      /* If delegitimize_address couldn't do anything with the UNSPEC, we
-        can't express it in the debug info.  This can happen e.g. with some
-        TLS UNSPECs.  */
-      break;
+/* Return true when DECL_BY_REFERENCE is defined and set for DECL.  */
 
-    default:
-      gcc_unreachable ();
-    }
+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));
+}
 
-  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 single element location list containing loc descr REF.  */
 
-  return mem_loc_result;
+static dw_loc_list_ref
+single_element_loc_list (dw_loc_descr_ref ref)
+{
+  return new_loc_list (ref, NULL, NULL, NULL, 0);
 }
 
-/* Return a descriptor that describes the concatenation of two locations.
-   This is typically a complex variable.  */
+/* Helper function for dw_loc_list.  Compute proper Dwarf location descriptor
+   for VARLOC.  */
 
 static dw_loc_descr_ref
-concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
+dw_loc_list_1 (tree loc, rtx varloc, int want_address,
+              enum var_init_status initialized)
 {
-  dw_loc_descr_ref cc_loc_result = NULL;
-  dw_loc_descr_ref x0_ref = loc_descriptor (x0, VAR_INIT_STATUS_INITIALIZED);
-  dw_loc_descr_ref x1_ref = loc_descriptor (x1, VAR_INIT_STATUS_INITIALIZED);
+  int have_address = 0;
+  dw_loc_descr_ref descr;
+  enum machine_mode mode;
 
-  if (x0_ref == 0 || x1_ref == 0)
+  if (want_address != 2)
+    {
+      gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
+      /* Single part.  */
+      if (GET_CODE (XEXP (varloc, 1)) != PARALLEL)
+       {
+         varloc = XEXP (XEXP (varloc, 1), 0);
+         mode = GET_MODE (varloc);
+         if (MEM_P (varloc))
+           {
+             varloc = XEXP (varloc, 0);
+             have_address = 1;
+           }
+         descr = mem_loc_descriptor (varloc, mode, initialized);
+       }
+      else
+       return 0;
+    }
+  else
+    {
+      descr = loc_descriptor (varloc, DECL_MODE (loc), initialized);
+      have_address = 1;
+    }
+
+  if (!descr)
     return 0;
 
-  cc_loc_result = x0_ref;
-  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x0)));
+  if (want_address == 2 && !have_address
+      && (dwarf_version >= 4 || !dwarf_strict))
+    {
+      if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE)
+       {
+         expansion_failed (loc, NULL_RTX,
+                           "DWARF address size mismatch");
+         return 0;
+       }
+      add_loc_descr (&descr, new_loc_descr (DW_OP_stack_value, 0, 0));
+      have_address = 1;
+    }
+  /* Show if we can't fill the request for an address.  */
+  if (want_address && !have_address)
+    {
+      expansion_failed (loc, NULL_RTX,
+                       "Want address and only have value");
+      return 0;
+    }
 
-  add_loc_descr (&cc_loc_result, x1_ref);
-  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1)));
+  /* If we've got an address and don't want one, dereference.  */
+  if (!want_address && have_address)
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
+      enum dwarf_location_atom op;
 
-  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+      if (size > DWARF2_ADDR_SIZE || size == -1)
+       {
+         expansion_failed (loc, NULL_RTX,
+                           "DWARF address size mismatch");
+         return 0;
+       }
+      else if (size == DWARF2_ADDR_SIZE)
+       op = DW_OP_deref;
+      else
+       op = DW_OP_deref_size;
 
-  return cc_loc_result;
+      add_loc_descr (&descr, new_loc_descr (op, size, 0));
+    }
+
+  return descr;
 }
 
-/* Return a descriptor that describes the concatenation of N
-   locations.  */
+/* Return dwarf representation of location list representing for
+   LOC_LIST of DECL.  WANT_ADDRESS has the same meaning as in
+   loc_list_from_tree function.  */
 
-static dw_loc_descr_ref
-concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
+static dw_loc_list_ref
+dw_loc_list (var_loc_list * loc_list, tree decl, int want_address)
 {
-  unsigned int i;
-  dw_loc_descr_ref cc_loc_result = NULL;
-  unsigned int n = XVECLEN (concatn, 0);
+  const char *endname, *secname;
+  dw_loc_list_ref list;
+  rtx varloc;
+  enum var_init_status initialized;
+  struct var_loc_node *node;
+  dw_loc_descr_ref descr;
+  char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
 
-  for (i = 0; i < n; ++i)
-    {
-      dw_loc_descr_ref ref;
-      rtx x = XVECEXP (concatn, 0, i);
+  /* 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;
+  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;
+  varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+  descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
 
-      ref = loc_descriptor (x, VAR_INIT_STATUS_INITIALIZED);
-      if (ref == NULL)
-       return NULL;
+  if (loc_list && loc_list->first != loc_list->last)
+    list = new_loc_list (descr, node->label, node->next->label, secname, 1);
+  else
+    return single_element_loc_list (descr);
+  node = node->next;
 
-      add_loc_descr (&cc_loc_result, ref);
-      add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
-    }
+  if (!node)
+    return NULL;
 
-  if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+  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.  */
+       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);
+       add_loc_descr_to_loc_list (&list, descr,
+                                  node->label, node->next->label, secname);
+      }
 
-  return cc_loc_result;
-}
+  /* 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)
+    {
+      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);
+       }
 
-/* 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.
+      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);
+      add_loc_descr_to_loc_list (&list, descr, node->label, endname, secname);
+    }
+  return list;
+}
 
-   If we don't know how to describe it, return 0.  */
+/* Return if the loc_list has only single element and thus can be represented
+   as location description.   */
 
-static dw_loc_descr_ref
-loc_descriptor (rtx rtl, enum var_init_status initialized)
+static bool
+single_element_loc_list_p (dw_loc_list_ref list)
 {
-  dw_loc_descr_ref loc_result = NULL;
+  return (!list->dw_loc_next && !list->begin && !list->end);
+}
 
-  switch (GET_CODE (rtl))
-    {
-    case SUBREG:
-      /* The case of a subreg may arise when we have a local (register)
-        variable or a formal (register) parameter which doesn't quite fill
-        up an entire register.  For now, just assume that it is
-        legitimate to make the Dwarf info refer to the whole register which
-        contains the given subreg.  */
-      rtl = SUBREG_REG (rtl);
+/* To each location in list LIST add loc descr REF.  */
 
-      /* ... fall through ...  */
+static void
+add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref)
+{
+  dw_loc_descr_ref copy;
+  add_loc_descr (&list->expr, ref);
+  list = list->dw_loc_next;
+  while (list)
+    {
+      copy = GGC_CNEW (dw_loc_descr_node);
+      memcpy (copy, ref, sizeof (dw_loc_descr_node));
+      add_loc_descr (&list->expr, copy);
+      while (copy->dw_loc_next)
+       {
+         dw_loc_descr_ref new_copy = GGC_CNEW (dw_loc_descr_node);
+         memcpy (new_copy, copy->dw_loc_next, sizeof (dw_loc_descr_node));
+         copy->dw_loc_next = new_copy;
+         copy = new_copy;
+       }
+      list = list->dw_loc_next;
+    }
+}
 
-    case REG:
-      loc_result = reg_loc_descriptor (rtl, initialized);
-      break;
+/* Given two lists RET and LIST
+   produce location list that is result of adding expression in LIST
+   to expression in RET on each possition in program.
+   Might be destructive on both RET and LIST.
 
-    case MEM:
-      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
-                                      initialized);
-      if (loc_result == NULL)
-       loc_result = tls_mem_loc_descriptor (rtl);
-      break;
+   TODO: We handle only simple cases of RET or LIST having at most one
+   element. General case would inolve sorting the lists in program order
+   and merging them that will need some additional work.
+   Adding that will improve quality of debug info especially for SRA-ed
+   structures.  */
 
-    case CONCAT:
-      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1),
-                                         initialized);
-      break;
+static void
+add_loc_list (dw_loc_list_ref *ret, dw_loc_list_ref list)
+{
+  if (!list)
+    return;
+  if (!*ret)
+    {
+      *ret = list;
+      return;
+    }
+  if (!list->dw_loc_next)
+    {
+      add_loc_descr_to_each (*ret, list->expr);
+      return;
+    }
+  if (!(*ret)->dw_loc_next)
+    {
+      add_loc_descr_to_each (list, (*ret)->expr);
+      *ret = list;
+      return;
+    }
+  expansion_failed (NULL_TREE, NULL_RTX,
+                   "Don't know how to merge two non-trivial"
+                   " location lists.\n");
+  *ret = NULL;
+  return;
+}
 
-    case CONCATN:
-      loc_result = concatn_loc_descriptor (rtl, initialized);
-      break;
+/* LOC is constant expression.  Try a luck, look it up in constant
+   pool and return its loc_descr of its address.  */
 
-    case VAR_LOCATION:
-      /* Single part.  */
-      if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
-       {
-         loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), initialized);
-         break;
-       }
+static dw_loc_descr_ref
+cst_pool_loc_descr (tree loc)
+{
+  /* Get an RTL for this, if something has been emitted.  */
+  rtx rtl = lookup_constant_def (loc);
+  enum machine_mode mode;
 
-      rtl = XEXP (rtl, 1);
-      /* FALLTHRU */
+  if (!rtl || !MEM_P (rtl))
+    {
+      gcc_assert (!rtl);
+      return 0;
+    }
+  gcc_assert (GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF);
 
-    case PARALLEL:
-      {
-       rtvec par_elems = XVEC (rtl, 0);
-       int num_elem = GET_NUM_ELEM (par_elems);
-       enum machine_mode mode;
-       int i;
+  /* TODO: We might get more coverage if we was actually delaying expansion
+     of all expressions till end of compilation when constant pools are fully
+     populated.  */
+  if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (XEXP (rtl, 0))))
+    {
+      expansion_failed (loc, NULL_RTX,
+                       "CST value in contant pool but not marked.");
+      return 0;
+    }
+  mode = GET_MODE (rtl);
+  rtl = XEXP (rtl, 0);
+  return mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
+}
 
-       /* Create the first one, so we have something to add to.  */
-       loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
-                                    initialized);
-       if (loc_result == NULL)
-         return NULL;
-       mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
-       add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
-       for (i = 1; i < num_elem; i++)
-         {
-           dw_loc_descr_ref temp;
+/* Return dw_loc_list representing address of addr_expr LOC
+   by looking for innder INDIRECT_REF expression and turing it
+   into simple arithmetics.  */
 
-           temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
-                                  initialized);
-           if (temp == NULL)
-             return NULL;
-           add_loc_descr (&loc_result, temp);
-           mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
-           add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
-         }
-      }
-      break;
+static dw_loc_list_ref
+loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev)
+{
+  tree obj, offset;
+  HOST_WIDE_INT bitsize, bitpos, bytepos;
+  enum machine_mode mode;
+  int volatilep;
+  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
+  dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
 
-    default:
-      gcc_unreachable ();
+  obj = get_inner_reference (TREE_OPERAND (loc, 0),
+                            &bitsize, &bitpos, &offset, &mode,
+                            &unsignedp, &volatilep, false);
+  STRIP_NOPS (obj);
+  if (bitpos % BITS_PER_UNIT)
+    {
+      expansion_failed (loc, NULL_RTX, "bitfield access");
+      return 0;
     }
-
-  return loc_result;
+  if (!INDIRECT_REF_P (obj))
+    {
+      expansion_failed (obj,
+                       NULL_RTX, "no indirect ref in inner refrence");
+      return 0;
+    }
+  if (!offset && !bitpos)
+    list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1);
+  else if (toplev
+          && int_size_in_bytes (TREE_TYPE (loc)) <= DWARF2_ADDR_SIZE
+          && (dwarf_version >= 4 || !dwarf_strict))
+    {
+      list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0);
+      if (!list_ret)
+       return 0;
+      if (offset)
+       {
+         /* Variable offset.  */
+         list_ret1 = loc_list_from_tree (offset, 0);
+         if (list_ret1 == 0)
+           return 0;
+         add_loc_list (&list_ret, list_ret1);
+         if (!list_ret)
+           return 0;
+         add_loc_descr_to_each (list_ret,
+                                new_loc_descr (DW_OP_plus, 0, 0));
+       }
+      bytepos = bitpos / BITS_PER_UNIT;
+      if (bytepos > 0)
+       add_loc_descr_to_each (list_ret,
+                              new_loc_descr (DW_OP_plus_uconst,
+                                             bytepos, 0));
+      else if (bytepos < 0)
+       loc_list_plus_const (list_ret, bytepos);
+      add_loc_descr_to_each (list_ret,
+                            new_loc_descr (DW_OP_stack_value, 0, 0));
+    }
+  return list_ret;
 }
 
-/* Similar, but generate the descriptor from trees instead of rtl.  This comes
-   up particularly with variable length arrays.  WANT_ADDRESS is 2 if this is
-   a top-level invocation of loc_descriptor_from_tree; is 1 if this is not a
-   top-level invocation, and we require the address of LOC; is 0 if we require
-   the value of LOC.  */
 
-static dw_loc_descr_ref
-loc_descriptor_from_tree_1 (tree loc, int want_address)
+/* Generate Dwarf location list representing LOC.
+   If WANT_ADDRESS is false, expression computing LOC will be computed
+   If WANT_ADDRESS is 1, expression computing address of LOC will be returned
+   if WANT_ADDRESS is 2, expression computing address useable in location
+     will be returned (i.e. DW_OP_reg can be used
+     to refer to register values).  */
+
+static dw_loc_list_ref
+loc_list_from_tree (tree loc, int want_address)
 {
-  dw_loc_descr_ref ret, ret1;
+  dw_loc_descr_ref ret = NULL, ret1 = NULL;
+  dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
   int have_address = 0;
   enum dwarf_location_atom op;
 
@@ -10688,6 +14198,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:
@@ -10695,25 +14206,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))
@@ -10721,11 +14252,12 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
          rtx rtl;
          enum dwarf_location_atom first_op;
          enum dwarf_location_atom second_op;
+         bool dtprel = false;
 
          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;
 
@@ -10734,12 +14266,14 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
                  module.  */
              if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
                return 0;
-             first_op = (enum dwarf_location_atom) INTERNAL_DW_OP_tls_addr;
+             first_op = DW_OP_addr;
+             dtprel = true;
              second_op = DW_OP_GNU_push_tls_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;
@@ -10759,6 +14293,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
          ret = new_loc_descr (first_op, 0, 0);
          ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
          ret->dw_loc_oprnd1.v.val_addr = rtl;
+         ret->dtprel = dtprel;
 
          ret1 = new_loc_descr (second_op, 0, 0);
          add_loc_descr (&ret, ret1);
@@ -10770,18 +14305,29 @@ 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;
-       else if (GET_CODE (rtl) == CONST_INT)
+         {
+           expansion_failed (loc, NULL_RTX, "DECL has no RTL");
+           return 0;
+         }
+       else if (CONST_INT_P (rtl))
          {
            HOST_WIDE_INT val = INTVAL (rtl);
            if (TYPE_UNSIGNED (TREE_TYPE (loc)))
@@ -10789,8 +14335,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;
@@ -10802,37 +14351,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;
@@ -10843,52 +14405,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:
@@ -10942,11 +14527,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;
        }
 
@@ -10990,13 +14575,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:
@@ -11013,11 +14600,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:
@@ -11037,29 +14624,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;
       }
@@ -11073,7 +14660,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
@@ -11086,32 +14677,76 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
 #endif
     }
 
+  if (!ret && !list_ret)
+    return 0;
+
+  if (want_address == 2 && !have_address
+      && (dwarf_version >= 4 || !dwarf_strict))
+    {
+      if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE)
+       {
+         expansion_failed (loc, NULL_RTX,
+                           "DWARF address size mismatch");
+         return 0;
+       }
+      if (ret)
+       add_loc_descr (&ret, new_loc_descr (DW_OP_stack_value, 0, 0));
+      else
+       add_loc_descr_to_each (list_ret,
+                              new_loc_descr (DW_OP_stack_value, 0, 0));
+      have_address = 1;
+    }
   /* Show if we can't fill the request for an address.  */
   if (want_address && !have_address)
-    return 0;
+    {
+      expansion_failed (loc, NULL_RTX,
+                       "Want address and only have value");
+      return 0;
+    }
+
+  gcc_assert (!ret || !list_ret);
 
   /* If we've got an address and don't want one, dereference.  */
-  if (!want_address && have_address && ret)
+  if (!want_address && have_address)
     {
       HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
 
       if (size > DWARF2_ADDR_SIZE || size == -1)
-       return 0;
+       {
+         expansion_failed (loc, NULL_RTX,
+                           "DWARF address size mismatch");
+         return 0;
+       }
       else if (size == DWARF2_ADDR_SIZE)
        op = DW_OP_deref;
       else
        op = DW_OP_deref_size;
 
-      add_loc_descr (&ret, new_loc_descr (op, size, 0));
+      if (ret)
+       add_loc_descr (&ret, new_loc_descr (op, size, 0));
+      else
+       add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0));
     }
+  if (ret)
+    list_ret = single_element_loc_list (ret);
 
-  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'
@@ -11221,9 +14856,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))
@@ -11318,10 +14953,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
@@ -11398,22 +15037,31 @@ add_data_member_location_attribute (dw_die_ref die, tree decl)
 
   if (! loc_descr)
     {
-      enum dwarf_location_atom op;
+      if (dwarf_version > 2)
+       {
+         /* Don't need to output a location expression, just the constant. */
+         add_AT_int (die, DW_AT_data_member_location, offset);
+         return;
+       }
+      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.  */
+         /* 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
-        stack.  */
-      op = DW_OP_constu;
+         /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst
+            operator correctly.  It works only if we leave the offset on the
+            stack.  */
+         op = DW_OP_constu;
 #else
-      op = DW_OP_plus_uconst;
+         op = DW_OP_plus_uconst;
 #endif
 
-      loc_descr = new_loc_descr (op, offset, 0);
+         loc_descr = new_loc_descr (op, offset, 0);
+       }
     }
 
   add_AT_loc (die, DW_AT_data_member_location, loc_descr);
@@ -11475,7 +15123,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))
@@ -11489,13 +15137,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);
 
@@ -11508,15 +15156,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:
       {
@@ -11584,18 +15227,25 @@ 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;
+      resolve_one_addr (&rtl, NULL);
+      add_AT_addr (die, DW_AT_const_value, rtl);
+      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+      return true;
 
+    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;
+      return true;
 
     case PLUS:
       /* In cases where an inlined instance of an inline function is passed
@@ -11609,13 +15259,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
@@ -11637,17 +15301,20 @@ reference_to_unused (tree * tp, int * walk_subtrees,
   else if (!cgraph_global_info_ready
           && (TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == FUNCTION_DECL))
     return *tp;
-  else if (DECL_P (*tp) && TREE_CODE (*tp) == VAR_DECL)
+  else if (TREE_CODE (*tp) == VAR_DECL)
     {
       struct varpool_node *node = varpool_node (*tp);
       if (!node->needed)
        return *tp;
     }
-  else if (DECL_P (*tp) && TREE_CODE (*tp) == FUNCTION_DECL
+  else if (TREE_CODE (*tp) == FUNCTION_DECL
           && (!DECL_EXTERNAL (*tp) || DECL_DECLARED_INLINE_P (*tp)))
     {
-      struct cgraph_node *node = cgraph_node (*tp);
-      if (node->process || TREE_ASM_WRITTEN (*tp))
+      /* The call graph machinery must have finished analyzing,
+         optimizing and gimplifying the CU by now.
+        So if *TP has no call graph node associated
+        to it, it means *TP will not be emitted.  */
+      if (!cgraph_get_node (*tp))
        return *tp;
     }
   else if (TREE_CODE (*tp) == STRING_CST && !TREE_ASM_WRITTEN (*tp))
@@ -11679,8 +15346,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!  */
@@ -11941,37 +15612,28 @@ rtl_for_decl_location (tree decl)
   if (rtl)
     rtl = avoid_constant_pool_reference (rtl);
 
-  return rtl;
-}
-
-/* We need to figure out what section we should use as the base for the
-   address ranges where a given location is valid.
-   1. If this particular DECL has a section associated with it, use that.
-   2. If this function has a section associated with it, use that.
-   3. Otherwise, use the text section.
-   XXX: If you split a variable across multiple sections, we won't notice.  */
-
-static const char *
-secname_for_decl (const_tree decl)
-{
-  const char *secname;
-
-  if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl))
-    {
-      tree sectree = DECL_SECTION_NAME (decl);
-      secname = TREE_STRING_POINTER (sectree);
-    }
-  else if (current_function_decl && DECL_SECTION_NAME (current_function_decl))
-    {
-      tree sectree = DECL_SECTION_NAME (current_function_decl);
-      secname = TREE_STRING_POINTER (sectree);
+  /* Try harder to get a rtl.  If this symbol ends up not being emitted
+     in the current CU, resolve_addr will remove the expression referencing
+     it.  */
+  if (rtl == NULL_RTX
+      && TREE_CODE (decl) == VAR_DECL
+      && !DECL_EXTERNAL (decl)
+      && TREE_STATIC (decl)
+      && DECL_NAME (decl)
+      && !DECL_HARD_REGISTER (decl)
+      && DECL_MODE (decl) != VOIDmode)
+    {
+      rtl = DECL_RTL (decl);
+      /* Reset DECL_RTL back, as various parts of the compiler expects
+        DECL_RTL set meaning it is actually going to be output.  */
+      SET_DECL_RTL (decl, NULL);
+      if (!MEM_P (rtl)
+         || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF
+         || SYMBOL_REF_DECL (XEXP (rtl, 0)) != decl)
+       rtl = NULL_RTX;
     }
-  else if (cfun && in_cold_section_p)
-    secname = crtl->subsections.cold_section_label;
-  else
-    secname = text_section_label;
 
-  return secname;
+  return rtl;
 }
 
 /* Check whether decl is a Fortran COMMON symbol.  If not, NULL_TREE is
@@ -11987,12 +15649,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 ())
@@ -12024,60 +15685,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
@@ -12089,137 +15696,54 @@ loc_by_reference (dw_loc_descr_ref loc, tree decl)
    pointer.  This can happen for example if an actual argument in an inlined
    function call evaluates to a compile-time constant address.  */
 
-static void
+static bool
 add_location_or_const_value_attribute (dw_die_ref die, tree decl,
                                       enum dwarf_attribute attr)
 {
   rtx rtl;
-  dw_loc_descr_ref descr;
+  dw_loc_list_ref list;
   var_loc_list *loc_list;
-  struct var_loc_node *node;
+
   if (TREE_CODE (decl) == ERROR_MARK)
-    return;
+    return false;
 
   gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
              || TREE_CODE (decl) == RESULT_DECL);
 
-  /* See if we possibly have multiple locations for this variable.  */
-  loc_list = lookup_decl_loc (decl);
-
-  /* If it truly has multiple locations, the first and last node will
-     differ.  */
-  if (loc_list && loc_list->first != loc_list->last)
-    {
-      const char *endname, *secname;
-      dw_loc_list_ref list;
-      rtx varloc;
-      enum var_init_status initialized;
-
-      /* Now that we know what section we are using for a base,
-        actually construct the list of locations.
-        The first location information is what is passed to the
-        function that creates the location list, and the remaining
-        locations just get added on to that list.
-        Note that we only know the start address for a location
-        (IE location changes), so to build the range, we use
-        the range [current location start, next location start].
-        This means we have to special case the last node, and generate
-        a range of [last location start, end of function label].  */
-
-      node = loc_list->first;
-      varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-      secname = secname_for_decl (decl);
-
-      if (NOTE_VAR_LOCATION_LOC (node->var_loc_note))
-       initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-      else
-       initialized = VAR_INIT_STATUS_INITIALIZED;
-
-      descr = loc_by_reference (loc_descriptor (varloc, initialized), decl);
-      list = new_loc_list (descr, node->label, node->next->label, secname, 1);
-      node = node->next;
-
-      for (; node->next; node = node->next)
-       if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
-         {
-           /* The variable has a location between NODE->LABEL and
-              NODE->NEXT->LABEL.  */
-           enum var_init_status initialized =
-             NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-           varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-           descr = loc_by_reference (loc_descriptor (varloc, initialized),
-                                     decl);
-           add_loc_descr_to_loc_list (&list, descr,
-                                      node->label, node->next->label, secname);
-         }
-
-      /* If the variable has a location at the last label
-        it keeps its location until the end of function.  */
-      if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
-       {
-         char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
-         enum var_init_status initialized =
-           NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-
-         varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-         if (!current_function_decl)
-           endname = text_end_label;
-         else
-           {
-             ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
-                                          current_function_funcdef_no);
-             endname = ggc_strdup (label_id);
-           }
-         descr = loc_by_reference (loc_descriptor (varloc, initialized),
-                                   decl);
-         add_loc_descr_to_loc_list (&list, descr,
-                                    node->label, endname, secname);
-       }
-
-      /* Finally, add the location list to the DIE, and we are done.  */
-      add_AT_loc_list (die, attr, list);
-      return;
-    }
-
   /* Try to get some constant RTL for this decl, and use that as the value of
      the location.  */
 
   rtl = rtl_for_decl_location (decl);
-  if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING))
-    {
-      add_const_value_attribute (die, rtl);
-      return;
-    }
+  if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
+      && add_const_value_attribute (die, rtl))
+    return true;
 
-  /* If we have tried to generate the location otherwise, and it
-     didn't work out (we wouldn't be here if we did), and we have a one entry
-     location list, try generating a location from that.  */
-  if (loc_list && loc_list->first)
+  /* See if we have single element location list that is equivalent to
+     a constant value.  That way we are better to use add_const_value_attribute
+     rather than expanding constant value equivalent.  */
+  loc_list = lookup_decl_loc (decl);
+  if (loc_list && loc_list->first && loc_list->first == loc_list->last)
     {
-      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 (node->var_loc_note);
+      if (GET_CODE (rtl) == VAR_LOCATION
+         && GET_CODE (XEXP (rtl, 1)) != PARALLEL)
+       rtl = XEXP (XEXP (rtl, 1), 0);
+      if ((CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
+         && add_const_value_attribute (die, rtl))
+        return true;
     }
-
-  /* We couldn't get any rtl, so try directly generating the location
-     description from the tree.  */
-  descr = loc_descriptor_from_tree (decl);
-  if (descr)
+  list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2);
+  if (list)
     {
-      descr = loc_by_reference (descr, decl);
-      add_AT_location_description (die, attr, descr);
-      return;
+      add_AT_location_description (die, attr, list);
+      return true;
     }
   /* None of that worked, so it must not really have a location;
      try adding a constant value attribute from the DECL_INITIAL.  */
-  tree_add_const_value_attribute (die, decl);
+  return tree_add_const_value_attribute_for_decl (die, decl);
 }
 
 /* Add VARIABLE and DIE into deferred locations list.  */
@@ -12380,29 +15904,25 @@ native_encode_initializer (tree init, unsigned char *array, int size)
     }
 }
 
-/* If we don't have a copy of this variable in memory for some reason (such
-   as a C++ member constant that doesn't have an out-of-line definition),
-   we should tell the debugger about the constant value.  */
+/* Attach a DW_AT_const_value attribute to DIE. The value of the
+   attribute is the const value T.  */
 
-static void
-tree_add_const_value_attribute (dw_die_ref var_die, tree decl)
+static bool
+tree_add_const_value_attribute (dw_die_ref die, tree t)
 {
   tree init;
-  tree type = TREE_TYPE (decl);
+  tree type = TREE_TYPE (t);
   rtx rtl;
 
-  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL)
-    return;
+  if (!t || !TREE_TYPE (t) || TREE_TYPE (t) == error_mark_node)
+    return false;
 
-  init = DECL_INITIAL (decl);
-  if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init)
-    /* OK */;
-  else
-    return;
+  init = t;
+  gcc_assert (!DECL_P (init));
 
   rtl = rtl_for_decl_init (init, type);
   if (rtl)
-    add_const_value_attribute (var_die, rtl);
+    return add_const_value_attribute (die, rtl);
   /* If the host and target are sane, try harder.  */
   else if (CHAR_BIT == 8 && BITS_PER_UNIT == 8
           && initializer_constant_valid_p (init, type))
@@ -12413,9 +15933,41 @@ tree_add_const_value_attribute (dw_die_ref var_die, tree decl)
          unsigned char *array = GGC_CNEWVEC (unsigned char, size);
 
          if (native_encode_initializer (init, array, size))
-           add_AT_vec (var_die, DW_AT_const_value, size, 1, array);
+           {
+             add_AT_vec (die, DW_AT_const_value, size, 1, array);
+             return true;
+           }
        }
     }
+  return false;
+}
+
+/* Attach a DW_AT_const_value attribute to VAR_DIE. The value of the
+   attribute is the const value of T, where T is an integral constant
+   variable with static storage duration
+   (so it can't be a PARM_DECL or a RESULT_DECL).  */
+
+static bool
+tree_add_const_value_attribute_for_decl (dw_die_ref var_die, tree decl)
+{
+
+  if (!decl
+      || (TREE_CODE (decl) != VAR_DECL
+         && TREE_CODE (decl) != CONST_DECL))
+    return false;
+
+    if (TREE_READONLY (decl)
+       && ! TREE_THIS_VOLATILE (decl)
+       && DECL_INITIAL (decl))
+      /* OK */;
+    else
+      return false;
+
+  /* Don't add DW_AT_const_value if abstract origin already has one.  */
+  if (get_AT (var_die, DW_AT_const_value))
+    return false;
+
+  return tree_add_const_value_attribute (var_die, DECL_INITIAL (decl));
 }
 
 /* Convert the CFI instructions for the current function into a
@@ -12555,7 +16107,23 @@ static void
 add_comp_dir_attribute (dw_die_ref die)
 {
   const char *wd = get_src_pwd ();
-  if (wd != NULL)
+  char *wd1;
+
+  if (wd == NULL)
+    return;
+
+  if (DWARF2_DIR_SHOULD_END_WITH_SEPARATOR)
+    {
+      int wdlen;
+
+      wdlen = strlen (wd);
+      wd1 = GGC_NEWVEC (char, wdlen + 2);
+      strcpy (wd1, wd);
+      wd1 [wdlen] = DIR_SEPARATOR;
+      wd1 [wdlen + 1] = 0;
+      wd = wd1;
+    }
+
     add_AT_string (die, DW_AT_comp_dir, remap_debug_filename (wd));
 }
 
@@ -12572,14 +16140,33 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
 
     /* All fixed-bounds are represented by INTEGER_CST nodes.  */
     case INTEGER_CST:
-      if (! host_integerp (bound, 0)
-         || (bound_attr == DW_AT_lower_bound
-             && (((is_c_family () || is_java ()) &&  integer_zerop (bound))
-                 || (is_fortran () && integer_onep (bound)))))
-       /* Use the default.  */
-       ;
-      else
-       add_AT_unsigned (subrange_die, bound_attr, tree_low_cst (bound, 0));
+      {
+       unsigned int prec = simple_type_size_in_bits (TREE_TYPE (bound));
+
+       /* Use the default if possible.  */
+       if (bound_attr == DW_AT_lower_bound
+           && (((is_c_family () || is_java ()) && integer_zerop (bound))
+               || (is_fortran () && integer_onep (bound))))
+         ;
+
+       /* Otherwise represent the bound as an unsigned value with the
+          precision of its type.  The precision and signedness of the
+          type will be necessary to re-interpret it unambiguously.  */
+       else if (prec < HOST_BITS_PER_WIDE_INT)
+         {
+           unsigned HOST_WIDE_INT mask
+             = ((unsigned HOST_WIDE_INT) 1 << prec) - 1;
+           add_AT_unsigned (subrange_die, bound_attr,
+                            TREE_INT_CST_LOW (bound) & mask);
+         }
+       else if (prec == HOST_BITS_PER_WIDE_INT
+                || TREE_INT_CST_HIGH (bound) == 0)
+         add_AT_unsigned (subrange_die, bound_attr,
+                          TREE_INT_CST_LOW (bound));
+       else
+         add_AT_double (subrange_die, bound_attr, TREE_INT_CST_HIGH (bound),
+                        TREE_INT_CST_LOW (bound));
+      }
       break;
 
     CASE_CONVERT:
@@ -12595,7 +16182,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
     case RESULT_DECL:
       {
        dw_die_ref decl_die = lookup_decl_die (bound);
-       dw_loc_descr_ref loc;
+       dw_loc_list_ref loc;
 
        /* ??? Can this happen, or should the variable have been bound
           first?  Probably it can, since I imagine that we try to create
@@ -12606,7 +16193,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
          add_AT_die_ref (subrange_die, bound_attr, decl_die);
        else
          {
-           loc = loc_descriptor_from_tree_1 (bound, 0);
+           loc = loc_list_from_tree (bound, 0);
            add_AT_location_description (subrange_die, bound_attr, loc);
          }
        break;
@@ -12618,10 +16205,10 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
           evaluate the value of the array bound.  */
 
        dw_die_ref ctx, decl_die;
-       dw_loc_descr_ref loc;
+       dw_loc_list_ref list;
 
-       loc = loc_descriptor_from_tree (bound);
-       if (loc == NULL)
+       list = loc_list_from_tree (bound, 2);
+       if (list == NULL)
          break;
 
        if (current_function_decl == 0)
@@ -12632,7 +16219,10 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
        decl_die = new_die (DW_TAG_variable, ctx, bound);
        add_AT_flag (decl_die, DW_AT_artificial, 1);
        add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
-       add_AT_loc (decl_die, DW_AT_location, loc);
+       if (list->dw_loc_next)
+         add_AT_loc_list (decl_die, DW_AT_location, list);
+       else
+         add_AT_loc (decl_die, DW_AT_location, list->expr);
 
        add_AT_die_ref (subrange_die, bound_attr, decl_die);
        break;
@@ -12914,7 +16504,9 @@ add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
   decl_name = DECL_NAME (decl);
   if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL)
     {
-      add_name_attribute (die, dwarf2_name (decl, 0));
+      const char *name = dwarf2_name (decl, 0);
+      if (name)
+       add_name_attribute (die, name);
       if (! DECL_ARTIFICIAL (decl))
        add_src_coords_attributes (die, decl);
 
@@ -12948,7 +16540,7 @@ add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
     {
       add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
                   XEXP (DECL_RTL (decl), 0));
-      VEC_safe_push (tree, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
+      VEC_safe_push (rtx, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
     }
 #endif
 }
@@ -13238,12 +16830,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);
            }
@@ -13302,7 +16894,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)
@@ -13337,7 +16929,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));
@@ -13534,7 +17126,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 ();
@@ -13623,10 +17217,13 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die)
    DIE to represent a formal parameter object (or some inlining thereof).  If
    it's the latter, then this function is only being called to output a
    DW_TAG_formal_parameter DIE to stand as a placeholder for some formal
-   argument type of some subprogram type.  */
+   argument type of some subprogram type.
+   If EMIT_NAME_P is true, name and source coordinate attributes
+   are emitted.  */
 
 static dw_die_ref
-gen_formal_parameter_die (tree node, tree origin, dw_die_ref context_die)
+gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
+                         dw_die_ref context_die)
 {
   tree node_or_origin = node ? node : origin;
   dw_die_ref parm_die
@@ -13642,8 +17239,9 @@ gen_formal_parameter_die (tree node, tree origin, dw_die_ref context_die)
       else
        {
          tree type = TREE_TYPE (node);
-         add_name_and_src_coords_attributes (parm_die, node);
-         if (DECL_BY_REFERENCE (node))
+         if (emit_name_p)
+           add_name_and_src_coords_attributes (parm_die, node);
+         if (decl_by_reference_p (node))
            add_type_attribute (parm_die, TREE_TYPE (type), 0, 0,
                                context_die);
          else
@@ -13655,7 +17253,7 @@ gen_formal_parameter_die (tree node, tree origin, dw_die_ref context_die)
            add_AT_flag (parm_die, DW_AT_artificial, 1);
        }
 
-      if (node)
+      if (node && node != origin)
         equate_decl_number_to_die (node, parm_die);
       if (! DECL_ABSTRACT (node_or_origin))
        add_location_or_const_value_attribute (parm_die, node_or_origin,
@@ -13675,6 +17273,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.  */
 
@@ -13718,7 +17357,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)))
@@ -13794,6 +17435,7 @@ dwarf2out_abstract_function (tree decl)
   tree save_fn;
   tree context;
   int was_abstract = DECL_ABSTRACT (decl);
+  htab_t old_decl_loc_table;
 
   /* Make sure we have the actual abstract inline, not a clone.  */
   decl = DECL_ORIGIN (decl);
@@ -13803,6 +17445,12 @@ dwarf2out_abstract_function (tree decl)
     /* 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)
@@ -13824,14 +17472,16 @@ dwarf2out_abstract_function (tree decl)
     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)
 {
@@ -13845,7 +17495,42 @@ premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
   return 1;
 }
 
+/* Helper function of premark_types_used_by_global_vars which gets called
+   through htab_traverse.
+
+   Marks the DIE of a given type in *SLOT as perennial, so it never gets
+   marked as unused by prune_unused_types. The DIE of the type is marked
+   only if the global variable using the type will actually be emitted.  */
+
+static int
+premark_types_used_by_global_vars_helper (void **slot,
+                                         void *data ATTRIBUTE_UNUSED)
+{
+  struct types_used_by_vars_entry *entry;
+  dw_die_ref die;
+
+  entry = (struct types_used_by_vars_entry *) *slot;
+  gcc_assert (entry->type != NULL
+             && entry->var_decl != NULL);
+  die = lookup_type_die (entry->type);
+  if (die)
+    {
+      /* Ask cgraph if the global variable really is to be emitted.
+         If yes, then we'll keep the DIE of ENTRY->TYPE.  */
+      struct varpool_node *node = varpool_node (entry->var_decl);
+      if (node->needed)
+       {
+         die->die_perennial_p = 1;
+         /* Keep the parent DIEs as well.  */
+         while ((die = die->die_parent) && die->die_perennial_p == 0)
+           die->die_perennial_p = 1;
+       }
+    }
+  return 1;
+}
+
 /* Mark all members of used_types_hash as perennial.  */
+
 static void
 premark_used_types (void)
 {
@@ -13853,6 +17538,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).  */
 
@@ -13985,7 +17680,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
@@ -14071,17 +17767,19 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
         (3) We can at least reuse the code inspection and interpretation
         code that determines the CFA position at various points in the
         function.  */
-      /* ??? Use some command-line or configury switch to enable the use
-        of dwarf3 DW_OP_call_frame_cfa.  At present there are no dwarf
-        consumers that understand it; fall back to "pure" dwarf2 and
-        convert the CFA data into a location list.  */
-      {
-       dw_loc_list_ref list = convert_cfa_to_fb_loc_list (cfa_fb_offset);
-       if (list->dw_loc_next)
-         add_AT_loc_list (subr_die, DW_AT_frame_base, list);
-       else
-         add_AT_loc (subr_die, DW_AT_frame_base, list->expr);
-      }
+      if (dwarf_version >= 3)
+       {
+         dw_loc_descr_ref op = new_loc_descr (DW_OP_call_frame_cfa, 0, 0);
+         add_AT_loc (subr_die, DW_AT_frame_base, op);
+       }
+      else
+       {
+         dw_loc_list_ref list = convert_cfa_to_fb_loc_list (cfa_fb_offset);
+         if (list->dw_loc_next)
+           add_AT_loc_list (subr_die, DW_AT_frame_base, list);
+         else
+           add_AT_loc (subr_die, DW_AT_frame_base, list->expr);
+       }
 
       /* Compute a displacement from the "steady-state frame pointer" to
         the CFA.  The former is what all stack slots and argument slots
@@ -14092,9 +17790,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 
       if (cfun->static_chain_decl)
        add_AT_location_description (subr_die, DW_AT_static_link,
-                loc_descriptor_from_tree (cfun->static_chain_decl));
+                loc_list_from_tree (cfun->static_chain_decl, 2));
     }
 
+  /* Generate child dies for template paramaters.  */
+  if (debug_info_level > DINFO_LEVEL_TERSE)
+    gen_generic_params_dies (decl);
+
   /* Now output descriptions of the arguments for this function. This gets
      (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list
      for a FUNCTION_DECL doesn't indicate cases where there was a trailing
@@ -14115,21 +17817,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 -
@@ -14225,26 +17952,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL;
   dw_die_ref origin_die;
   int declaration = (DECL_EXTERNAL (decl_or_origin)
-                    /* If DECL is COMDAT and has not actually been
-                       emitted, we cannot take its address; there
-                       might end up being no definition anywhere in
-                       the program.  For example, consider the C++
-                       test case:
-
-                         template <class T>
-                         struct S { static const int i = 7; };
-
-                         template <class T>
-                         const int S<T>::i;
-
-                         int f() { return S<int>::i; }
-
-                       Here, S<int>::i is not DECL_EXTERNAL, but no
-                       definition is required, so the compiler will
-                       not emit a definition.  */
-                    || (TREE_CODE (decl_or_origin) == VAR_DECL
-                        && DECL_COMDAT (decl_or_origin)
-                        && !TREE_ASM_WRITTEN (decl_or_origin))
                     || class_or_namespace_scope_p (context_die));
 
   if (!origin)
@@ -14256,9 +17963,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
      of a data member.  */
   if (com_decl)
     {
-      tree field;
       dw_die_ref com_die;
-      dw_loc_descr_ref loc;
+      dw_loc_list_ref loc;
       die_node com_die_arg;
 
       var_die = lookup_decl_die (decl_or_origin);
@@ -14266,22 +17972,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);
                }
            }
@@ -14293,11 +18000,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
@@ -14308,10 +18014,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);
@@ -14322,8 +18028,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);
@@ -14336,15 +18042,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);
@@ -14356,8 +18063,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
      and if we already emitted a DIE for it, don't emit a second
      DIE for it again.  */
   if (old_die
-      && declaration
-      && old_die->die_parent == context_die)
+      && declaration)
     return;
 
   /* For static data members, the declaration in the class is supposed
@@ -14407,10 +18113,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),
@@ -14456,7 +18159,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
       add_pubname (decl_or_origin, var_die);
     }
   else
-    tree_add_const_value_attribute (var_die, decl_or_origin);
+    tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
 }
 
 /* Generate a DIE to represent a named constant.  */
@@ -14474,7 +18177,7 @@ gen_const_die (tree decl, dw_die_ref context_die)
     add_AT_flag (const_die, DW_AT_external, 1);
   if (DECL_ARTIFICIAL (decl))
     add_AT_flag (const_die, DW_AT_artificial, 1);
-  tree_add_const_value_attribute (const_die, decl);
+  tree_add_const_value_attribute_for_decl (const_die, decl);
 }
 
 /* Generate a DIE to represent a label identifier.  */
@@ -14528,8 +18231,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);
+    }
 }
 
 
@@ -14541,7 +18247,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;
 
@@ -14592,7 +18299,13 @@ gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth)
 static void
 gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die, int depth)
 {
-  tree decl = block_ultimate_origin (stmt);
+  tree decl;
+
+  /* The instance of function that is effectively being inlined shall not
+     be abstract.  */
+  gcc_assert (! BLOCK_ABSTRACT (stmt));
+
+  decl = block_ultimate_origin (stmt);
 
   /* Emit info for the abstract instance first, if we haven't yet.  We
      must emit this even if the block is abstract, otherwise when we
@@ -14613,20 +18326,6 @@ gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die, int depth)
       decls_for_scope (stmt, subr_die, depth);
       current_function_has_inlines = 1;
     }
-  else
-    /* We may get here if we're the outer block of function A that was
-       inlined into function B that was inlined into function C.  When
-       generating debugging info for C, dwarf2out_abstract_function(B)
-       would mark all inlined blocks as abstract, including this one.
-       So, we wouldn't (and shouldn't) expect labels to be generated
-       for this one.  Instead, just emit debugging info for
-       declarations within the block.  This is particularly important
-       in the case of initializers of arguments passed from B to us:
-       if they're statement expressions containing declarations, we
-       wouldn't generate dies for their abstract variables, and then,
-       when generating dies for the real variables, we'd die (pun
-       intended :-)  */
-    gen_lexical_block_die (stmt, context_die, depth);
 }
 
 /* Generate a DIE for a field in a record, or structure.  */
@@ -14751,24 +18450,26 @@ gen_compile_unit_die (const char *filename)
 
   add_AT_string (die, DW_AT_producer, producer);
 
+  language = DW_LANG_C89;
   if (strcmp (language_string, "GNU C++") == 0)
     language = DW_LANG_C_plus_plus;
-  else if (strcmp (language_string, "GNU Ada") == 0)
-    language = DW_LANG_Ada95;
   else if (strcmp (language_string, "GNU F77") == 0)
     language = DW_LANG_Fortran77;
-  else if (strcmp (language_string, "GNU Fortran") == 0)
-    language = DW_LANG_Fortran95;
   else if (strcmp (language_string, "GNU Pascal") == 0)
     language = DW_LANG_Pascal83;
-  else if (strcmp (language_string, "GNU Java") == 0)
-    language = DW_LANG_Java;
-  else if (strcmp (language_string, "GNU Objective-C") == 0)
-    language = DW_LANG_ObjC;
-  else if (strcmp (language_string, "GNU Objective-C++") == 0)
-    language = DW_LANG_ObjC_plus_plus;
-  else
-    language = DW_LANG_C89;
+  else if (dwarf_version >= 3 || !dwarf_strict)
+    {
+      if (strcmp (language_string, "GNU Ada") == 0)
+       language = DW_LANG_Ada95;
+      else if (strcmp (language_string, "GNU Fortran") == 0)
+       language = DW_LANG_Fortran95;
+      else if (strcmp (language_string, "GNU Java") == 0)
+       language = DW_LANG_Java;
+      else if (strcmp (language_string, "GNU Objective-C") == 0)
+       language = DW_LANG_ObjC;
+      else if (strcmp (language_string, "GNU Objective-C++") == 0)
+       language = DW_LANG_ObjC_plus_plus;
+    }
 
   add_AT_unsigned (die, DW_AT_language, language);
   return die;
@@ -14901,6 +18602,11 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
   else
     remove_AT (type_die, DW_AT_declaration);
 
+  /* Generate child dies for template paramaters.  */
+  if (debug_info_level > DINFO_LEVEL_TERSE
+      && COMPLETE_TYPE_P (type))
+    gen_generic_params_dies (type);
+
   /* If this type has been completed, then give it a byte_size attribute and
      then give a list of members.  */
   if (complete && !ns_decl)
@@ -15018,6 +18724,8 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
   if (type == NULL_TREE || type == error_mark_node)
     return;
 
+  /* If TYPE is a typedef type variant, let's generate debug info
+     for the parent typedef which TYPE is a type of.  */
   if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
       && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
     {
@@ -15031,7 +18739,7 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
          the type description DIE we want to generate.  */
       if (DECL_CONTEXT (TYPE_NAME (type))
          && TREE_CODE (DECL_CONTEXT (TYPE_NAME (type))) == NAMESPACE_DECL)
-       context_die = lookup_decl_die (DECL_CONTEXT (TYPE_NAME (type)));
+       context_die = get_context_die (DECL_CONTEXT (TYPE_NAME (type)));
 
       TREE_ASM_WRITTEN (type) = 1;
       gen_decl_die (TYPE_NAME (type), NULL, context_die);
@@ -15041,7 +18749,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;
@@ -15140,6 +18849,15 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
          context_die = lookup_type_die (TYPE_CONTEXT (type));
          need_pop = 1;
        }
+      else if (TYPE_CONTEXT (type) != NULL_TREE
+              && (TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL))
+       {
+         /* If this type is local to a function that hasn't been written
+            out yet, use a NULL context for now; it will be fixed up in
+            decls_for_scope.  */
+         context_die = lookup_decl_die (TYPE_CONTEXT (type));
+         need_pop = 0;
+       }
       else
        {
          context_die = declare_in_namespace (type, context_die);
@@ -15253,7 +18971,23 @@ gen_block_die (tree stmt, dw_die_ref context_die, int depth)
   if (must_output_die)
     {
       if (inlined_func)
-       gen_inlined_subroutine_die (stmt, context_die, depth);
+       {
+         /* If STMT block is abstract, that means we have been called
+            indirectly from dwarf2out_abstract_function.
+            That function rightfully marks the descendent blocks (of
+            the abstract function it is dealing with) as being abstract,
+            precisely to prevent us from emitting any
+            DW_TAG_inlined_subroutine DIE as a descendent
+            of an abstract function instance. So in that case, we should
+            not call gen_inlined_subroutine_die.
+
+            Later though, when cgraph asks dwarf2out to emit info
+            for the concrete instance of the function decl into which
+            the concrete instance of STMT got inlined, the later will lead
+            to the generation of a DW_TAG_inlined_subroutine DIE.  */
+         if (! BLOCK_ABSTRACT (stmt))
+           gen_inlined_subroutine_die (stmt, context_die, depth);
+       }
       else
        gen_lexical_block_die (stmt, context_die, depth);
     }
@@ -15354,7 +19088,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);
     }
@@ -15400,7 +19134,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:
@@ -15503,7 +19241,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))
@@ -15663,9 +19405,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);
@@ -15685,7 +19425,9 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
       if (!origin)
         origin = decl_ultimate_origin (decl);
       if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
-       gen_formal_parameter_die (decl, origin, context_die);
+       gen_formal_parameter_die (decl, origin,
+                                 true /* Emit name attribute.  */,
+                                 context_die);
       else
        gen_variable_die (decl, origin, context_die);
       break;
@@ -15707,12 +19449,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:
@@ -15810,9 +19555,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,
@@ -15853,6 +19603,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)
@@ -16129,31 +19883,209 @@ maybe_emit_file (struct dwarf_file_data * fd)
   return fd->emitted_number;
 }
 
+/* Schedule generation of a DW_AT_const_value attribute to DIE.
+   That generation should happen after function debug info has been
+   generated. The value of the attribute is the constant value of ARG.  */
+
+static void
+append_entry_to_tmpl_value_parm_die_table (dw_die_ref die, tree arg)
+{
+  die_arg_entry entry;
+
+  if (!die || !arg)
+    return;
+
+  if (!tmpl_value_parm_die_table)
+    tmpl_value_parm_die_table
+      = VEC_alloc (die_arg_entry, gc, 32);
+
+  entry.die = die;
+  entry.arg = arg;
+  VEC_safe_push (die_arg_entry, gc,
+                tmpl_value_parm_die_table,
+                &entry);
+}
+
+/* Add a DW_AT_const_value attribute to DIEs that were scheduled
+   by append_entry_to_tmpl_value_parm_die_table. This function must
+   be called after function DIEs have been generated.  */
+
+static void
+gen_remaining_tmpl_value_param_die_attribute (void)
+{
+  if (tmpl_value_parm_die_table)
+    {
+      unsigned i;
+      die_arg_entry *e;
+
+      for (i = 0;
+           VEC_iterate (die_arg_entry, tmpl_value_parm_die_table, i, e);
+           i++)
+       tree_add_const_value_attribute (e->die, e->arg);
+    }
+}
+
+
 /* Replace DW_AT_name for the decl with name.  */
+
 static void
 dwarf2out_set_name (tree decl, tree name)
 {
   dw_die_ref die;
   dw_attr_ref attr;
+  const char *dname;
 
   die = TYPE_SYMTAB_DIE (decl);
   if (!die)
     return;
 
+  dname = dwarf2_name (name, 0);
+  if (!dname)
+    return;
+
   attr = get_AT (die, DW_AT_name);
   if (attr)
     {
       struct indirect_string_node *node;
 
-      node = find_AT_string (dwarf2_name (name, 0));
+      node = find_AT_string (dname);
       /* replace the string.  */
       attr->dw_attr_val.v.val_str = node;
     }
 
   else
-    add_name_attribute (die, dwarf2_name (name, 0));
+    add_name_attribute (die, dname);
+}
+
+/* Called by the final INSN scan whenever we see a direct function call.
+   Make an entry into the direct call table, recording the point of call
+   and a reference to the target function's debug entry.  */
+
+static void
+dwarf2out_direct_call (tree targ)
+{
+  dcall_entry e;
+  tree origin = decl_ultimate_origin (targ);
+
+  /* If this is a clone, use the abstract origin as the target.  */
+  if (origin)
+    targ = origin;
+
+  e.poc_label_num = poc_label_num++;
+  e.poc_decl = current_function_decl;
+  e.targ_die = force_decl_die (targ);
+  VEC_safe_push (dcall_entry, gc, dcall_table, &e);
+
+  /* Drop a label at the return point to mark the point of call.  */
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LPOC", e.poc_label_num);
+}
+
+/* Returns a hash value for X (which really is a struct vcall_insn).  */
+
+static hashval_t
+vcall_insn_table_hash (const void *x)
+{
+  return (hashval_t) ((const struct vcall_insn *) x)->insn_uid;
+}
+
+/* Return nonzero if insn_uid of struct vcall_insn *X is the same as
+   insnd_uid of *Y.  */
+
+static int
+vcall_insn_table_eq (const void *x, const void *y)
+{
+  return (((const struct vcall_insn *) x)->insn_uid
+          == ((const struct vcall_insn *) y)->insn_uid);
+}
+
+/* Associate VTABLE_SLOT with INSN_UID in the VCALL_INSN_TABLE.  */
+
+static void
+store_vcall_insn (unsigned int vtable_slot, int insn_uid)
+{
+  struct vcall_insn *item = GGC_NEW (struct vcall_insn);
+  struct vcall_insn **slot;
+
+  gcc_assert (item);
+  item->insn_uid = insn_uid;
+  item->vtable_slot = vtable_slot;
+  slot = (struct vcall_insn **)
+      htab_find_slot_with_hash (vcall_insn_table, &item,
+                               (hashval_t) insn_uid, INSERT);
+  *slot = item;
+}
+
+/* Return the VTABLE_SLOT associated with INSN_UID.  */
+
+static unsigned int
+lookup_vcall_insn (unsigned int insn_uid)
+{
+  struct vcall_insn item;
+  struct vcall_insn *p;
+
+  item.insn_uid = insn_uid;
+  item.vtable_slot = 0;
+  p = (struct vcall_insn *) htab_find_with_hash (vcall_insn_table,
+                                                 (void *) &item,
+                                                 (hashval_t) insn_uid);
+  if (p == NULL)
+    return (unsigned int) -1;
+  return p->vtable_slot;
+}
+
+
+/* Called when lowering indirect calls to RTL.  We make a note of INSN_UID
+   and the OBJ_TYPE_REF_TOKEN from ADDR.  For C++ virtual calls, the token
+   is the vtable slot index that we will need to put in the virtual call
+   table later.  */
+
+static void
+dwarf2out_virtual_call_token (tree addr, int insn_uid)
+{
+  if (is_cxx() && TREE_CODE (addr) == OBJ_TYPE_REF)
+    {
+      tree token = OBJ_TYPE_REF_TOKEN (addr);
+      if (TREE_CODE (token) == INTEGER_CST)
+        store_vcall_insn (TREE_INT_CST_LOW (token), insn_uid);
+    }
+}
+
+/* Called when scheduling RTL, when a CALL_INSN is split.  Copies the
+   OBJ_TYPE_REF_TOKEN previously associated with OLD_INSN and associates it
+   with NEW_INSN.  */
+
+static void
+dwarf2out_copy_call_info (rtx old_insn, rtx new_insn)
+{
+  unsigned int vtable_slot = lookup_vcall_insn (INSN_UID (old_insn));
+
+  if (vtable_slot != (unsigned int) -1)
+    store_vcall_insn (vtable_slot, INSN_UID (new_insn));
+}
+
+/* Called by the final INSN scan whenever we see a virtual function call.
+   Make an entry into the virtual call table, recording the point of call
+   and the slot index of the vtable entry used to call the virtual member
+   function.  The slot index was associated with the INSN_UID during the
+   lowering to RTL.  */
+
+static void
+dwarf2out_virtual_call (int insn_uid)
+{
+  unsigned int vtable_slot = lookup_vcall_insn (insn_uid);
+  vcall_entry e;
+
+  if (vtable_slot == (unsigned int) -1)
+    return;
+
+  e.poc_label_num = poc_label_num++;
+  e.vtable_slot = vtable_slot;
+  VEC_safe_push (vcall_entry, gc, vcall_table, &e);
+
+  /* Drop a label at the return point to mark the point of call.  */
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LPOC", e.poc_label_num);
 }
+
 /* Called by the final INSN scan whenever we see a var location.  We
    use it to drop labels in the right places, and throw the location in
    our lookup table.  */
@@ -16161,45 +20093,58 @@ 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 prev_insn;
-  static rtx last_insn;
+  rtx next_real;
   static const char *last_label;
+  static const char *last_postcall_label;
+  static bool last_in_cold_section_p;
   tree decl;
 
   if (!DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
     return;
-  prev_insn = PREV_INSN (loc_note);
+
+  next_real = next_real_insn (loc_note);
+  /* If there are no instructions which would be affected by this note,
+     don't do anything.  */
+  if (next_real == NULL_RTX)
+    return;
 
   newloc = GGC_CNEW (struct var_loc_node);
-  /* If the insn we processed last time is the previous insn
-     and it is also a var location note, use the label we emitted
-     last time.  */
-  if (last_insn != NULL_RTX
-      && last_insn == prev_insn
-      && NOTE_P (prev_insn)
-      && NOTE_KIND (prev_insn) == NOTE_INSN_VAR_LOCATION)
-    {
-      newloc->label = last_label;
-    }
-  else
+  /* 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)
     {
       ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num);
       ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num);
       loclabel_num++;
-      newloc->label = ggc_strdup (loclabel);
+      last_label = ggc_strdup (loclabel);
+      last_postcall_label = NULL;
     }
   newloc->var_loc_note = loc_note;
   newloc->next = NULL;
 
+  if (!NOTE_DURING_CALL_P (loc_note))
+    newloc->label = last_label;
+  else
+    {
+      if (!last_postcall_label)
+       {
+         sprintf (loclabel, "%s-1", last_label);
+         last_postcall_label = ggc_strdup (loclabel);
+       }
+      newloc->label = last_postcall_label;
+    }
+
   if (cfun && in_cold_section_p)
     newloc->section_label = crtl->subsections.cold_section_label;
   else
     newloc->section_label = text_section_label;
 
-  last_insn = loc_note;
-  last_label = newloc->label;
+  last_var_location_insn = next_real;
+  last_in_cold_section_p = in_cold_section_p;
   decl = NOTE_VAR_LOCATION_DECL (loc_note);
   add_var_loc_to_decl (decl, newloc);
 }
@@ -16226,8 +20171,10 @@ dwarf2out_begin_function (tree fun)
 
 static void
 dwarf2out_source_line (unsigned int line, const char *filename,
-                       int discriminator)
+                       int discriminator, bool is_stmt)
 {
+  static bool last_is_stmt = true;
+
   if (debug_info_level >= DINFO_LEVEL_NORMAL
       && line != 0)
     {
@@ -16244,10 +20191,13 @@ dwarf2out_source_line (unsigned int line, const char *filename,
        {
          /* Emit the .loc directive understood by GNU as.  */
          fprintf (asm_out_file, "\t.loc %d %d 0", file_num, line);
-#ifdef HAVE_GAS_DISCRIMINATOR
-         if (discriminator != 0)
+         if (is_stmt != last_is_stmt)
+           {
+             fprintf (asm_out_file, " is_stmt %d", is_stmt ? 1 : 0);
+             last_is_stmt = is_stmt;
+           }
+         if (SUPPORTS_DISCRIMINATOR && discriminator != 0)
            fprintf (asm_out_file, " discriminator %d", discriminator);
-#endif /* HAVE_GAS_DISCRIMINATOR */
          fputc ('\n', asm_out_file);
 
          /* Indicate that line number info exists.  */
@@ -16314,7 +20264,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;
@@ -16341,7 +20291,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);
 
@@ -16423,6 +20373,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
@@ -16449,10 +20403,12 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
                                   SECTION_DEBUG, NULL);
   debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
                                        SECTION_DEBUG, NULL);
-#ifdef DEBUG_PUBTYPES_SECTION
   debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
                                        SECTION_DEBUG, NULL);
-#endif
+  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,
@@ -16497,17 +20453,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);
@@ -16557,8 +20529,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.  */
@@ -16602,8 +20578,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));
@@ -16785,6 +20765,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.  */
 
@@ -16793,19 +20787,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.  */
@@ -16814,17 +20820,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
@@ -16842,6 +20858,28 @@ file_table_relative_p (void ** slot, void *param)
   return 1;
 }
 
+/* Routines to manipulate hash table of comdat type units.  */
+
+static hashval_t
+htab_ct_hash (const void *of)
+{
+  hashval_t h;
+  const comdat_type_node *const type_node = (const comdat_type_node *) of;
+
+  memcpy (&h, type_node->signature, sizeof (h));
+  return h;
+}
+
+static int
+htab_ct_eq (const void *of1, const void *of2)
+{
+  const comdat_type_node *const type_node_1 = (const comdat_type_node *) of1;
+  const comdat_type_node *const type_node_2 = (const comdat_type_node *) of2;
+
+  return (! memcmp (type_node_1->signature, type_node_2->signature,
+                    DWARF_TYPE_SIGNATURE_SIZE));
+}
+
 /* Move a DW_AT_MIPS_linkage_name attribute just added to dw_die_ref
    to the location it would have been added, should we know its
    DECL_ASSEMBLER_NAME when we added other attributes.  This will
@@ -16872,6 +20910,104 @@ 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:
+       for (curr = AT_loc_list (a); curr != NULL; curr = curr->dw_loc_next)
+         if (!resolve_addr_in_expr (curr->expr))
+           curr->expr = NULL;
+       break;
+      case dw_val_class_loc:
+       if (!resolve_addr_in_expr (AT_loc (a)))
+         a->dw_attr_val.v.val_loc = NULL;
+       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))
+         {
+           a->dw_attr = DW_AT_location;
+           a->dw_attr_val.val_class = dw_val_class_loc;
+           a->dw_attr_val.v.val_loc = NULL;
+         }
+       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.  */
 
@@ -16879,9 +21015,13 @@ static void
 dwarf2out_finish (const char *filename)
 {
   limbo_die_node *node, *next_node;
+  comdat_type_node *ctnode;
+  htab_t comdat_type_table;
   dw_die_ref die = 0;
   unsigned int i;
 
+  gen_remaining_tmpl_value_param_die_attribute ();
+
   /* Add the name for the main input file now.  We delayed this from
      dwarf2out_init to avoid complications with PCH.  */
   add_name_attribute (comp_unit_die, remap_debug_filename (filename));
@@ -16960,6 +21100,8 @@ dwarf2out_finish (const char *filename)
 
   limbo_die_list = NULL;
 
+  resolve_addr (comp_unit_die);
+
   for (node = deferred_asm_name; node; node = node->next)
     {
       tree decl = node->created_for;
@@ -16982,14 +21124,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);
@@ -17002,7 +21169,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);
@@ -17033,12 +21201,14 @@ dwarf2out_finish (const char *filename)
 
          if (fde->dw_fde_switched_sections)
            {
-             add_ranges_by_labels (fde->dw_fde_hot_section_label,
-                                   fde->dw_fde_hot_section_end_label);
-             add_ranges_by_labels (fde->dw_fde_unlikely_section_label,
-                                   fde->dw_fde_unlikely_section_end_label);
+             if (!fde->in_std_section)
+               add_ranges_by_labels (fde->dw_fde_hot_section_label,
+                                     fde->dw_fde_hot_section_end_label);
+             if (!fde->cold_in_std_section)
+               add_ranges_by_labels (fde->dw_fde_unlikely_section_label,
+                                     fde->dw_fde_unlikely_section_end_label);
            }
-         else
+         else if (!fde->in_std_section)
            add_ranges_by_labels (fde->dw_fde_begin,
                                  fde->dw_fde_end);
        }
@@ -17069,6 +21239,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);
@@ -17084,14 +21275,27 @@ dwarf2out_finish (const char *filename)
       output_pubnames (pubname_table);
     }
 
-#ifdef DEBUG_PUBTYPES_SECTION
   /* Output public types table if necessary.  */
+  /* ??? Only defined by DWARF3, but emitted by Darwin for DWARF2.
+     It shouldn't hurt to emit it always, since pure DWARF2 consumers
+     simply won't look for the section.  */
   if (!VEC_empty (pubname_entry, pubtype_table))
     {
       switch_to_section (debug_pubtypes_section);
       output_pubnames (pubtype_table);
     }
-#endif
+
+  /* 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.  */
@@ -17136,7 +21340,41 @@ dwarf2out_finish (const char *filename)
 #else
 
 /* This should never be used, but its address is needed for comparisons.  */
-const struct gcc_debug_hooks dwarf2_debug_hooks;
+const struct gcc_debug_hooks dwarf2_debug_hooks =
+{
+  0,           /* init */
+  0,           /* finish */
+  0,           /* assembly_start */
+  0,           /* define */
+  0,           /* undef */
+  0,           /* start_source_file */
+  0,           /* end_source_file */
+  0,           /* begin_block */
+  0,           /* end_block */
+  0,           /* ignore_block */
+  0,           /* source_line */
+  0,           /* begin_prologue */
+  0,           /* end_prologue */
+  0,           /* end_epilogue */
+  0,           /* begin_function */
+  0,           /* end_function */
+  0,           /* function_decl */
+  0,           /* global_decl */
+  0,           /* type_decl */
+  0,           /* imported_module_or_decl */
+  0,           /* deferred_inline_function */
+  0,           /* outlining_inline_function */
+  0,           /* label */
+  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 */
+};
 
 #endif /* DWARF2_DEBUGGING_INFO */