OSDN Git Service

Revert "Fix PR debug/49047"
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index 4b4042a..7ec1e93 100644 (file)
@@ -1,6 +1,6 @@
 /* Output Dwarf2 format symbol table information from GCC.
    Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Gary Funck (gary@intrepid.com).
    Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
@@ -92,6 +92,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "tree-pass.h"
 #include "tree-flow.h"
+#include "cfglayout.h"
 
 static void dwarf2out_source_line (unsigned int, const char *, int, bool);
 static rtx last_var_location_insn;
@@ -112,23 +113,18 @@ int vms_file_stats_name (const char *, long long *, long *, char *, int *);
 #define DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET 0
 #endif
 
-#ifndef DWARF2_UNWIND_INFO
-#define DWARF2_UNWIND_INFO 0
+/* ??? Poison these here until it can be done generically.  They've been
+   totally replaced in this file; make sure it stays that way.  */
+#undef DWARF2_UNWIND_INFO
+#undef DWARF2_FRAME_INFO
+#if (GCC_VERSION >= 3000)
+ #pragma GCC poison DWARF2_UNWIND_INFO DWARF2_FRAME_INFO
 #endif
 
 #ifndef INCOMING_RETURN_ADDR_RTX
 #define INCOMING_RETURN_ADDR_RTX  (gcc_unreachable (), NULL_RTX)
 #endif
 
-#ifndef DWARF2_FRAME_INFO
-# ifdef DWARF2_DEBUGGING_INFO
-#  define DWARF2_FRAME_INFO \
-  (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
-# else
-#  define DWARF2_FRAME_INFO 0
-# endif
-#endif
-
 /* Map register numbers held in the call frame info that gcc has
    collected using DWARF_FRAME_REGNUM to those that should be output in
    .debug_frame and .eh_frame.  */
@@ -148,13 +144,20 @@ dwarf2out_do_frame (void)
   /* We want to emit correct CFA location expressions or lists, so we
      have to return true if we're going to output debug info, even if
      we're not going to output frame or unwind info.  */
-  return (write_symbols == DWARF2_DEBUG
-         || write_symbols == VMS_AND_DWARF2_DEBUG
-         || DWARF2_FRAME_INFO || saved_do_cfi_asm
-         || (DWARF2_UNWIND_INFO
-             && (flag_unwind_tables
-                 || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS)))
-         );
+  if (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
+    return true;
+
+  if (saved_do_cfi_asm)
+    return true;
+
+  if (targetm.debug_unwind_info () == UI_DWARF2)
+    return true;
+
+  if ((flag_unwind_tables || flag_exceptions)
+      && targetm.except_unwind_info (&global_options) == UI_DWARF2)
+    return true;
+
+  return false;
 }
 
 /* Decide whether to emit frame unwind via assembler directives.  */
@@ -167,10 +170,10 @@ dwarf2out_do_cfi_asm (void)
 #ifdef MIPS_DEBUGGING_INFO
   return false;
 #endif
-  if (!flag_dwarf2_cfi_asm || !dwarf2out_do_frame ())
-    return false;
   if (saved_do_cfi_asm)
     return true;
+  if (!flag_dwarf2_cfi_asm || !dwarf2out_do_frame ())
+    return false;
   if (!HAVE_GAS_CFI_PERSONALITY_DIRECTIVE)
     return false;
 
@@ -183,15 +186,12 @@ 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
-    }
+  /* If we can't get the assembler to emit only .debug_frame, and we don't need
+     dwarf2 unwind info for exceptions, then emit .debug_frame by hand.  */
+  if (!HAVE_GAS_CFI_SECTIONS_DIRECTIVE
+      && !flag_unwind_tables && !flag_exceptions
+      && targetm.except_unwind_info (&global_options) != UI_DWARF2)
+    return false;
 
   saved_do_cfi_asm = true;
   return true;
@@ -228,8 +228,6 @@ 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;
@@ -269,7 +267,6 @@ typedef union GTY(()) dw_cfi_oprnd_struct {
 dw_cfi_oprnd;
 
 typedef struct GTY(()) dw_cfi_struct {
-  dw_cfi_ref dw_cfi_next;
   enum dwarf_call_frame_info dw_cfi_opc;
   dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd1_desc (%1.dw_cfi_opc)")))
     dw_cfi_oprnd1;
@@ -278,12 +275,18 @@ typedef struct GTY(()) dw_cfi_struct {
 }
 dw_cfi_node;
 
+DEF_VEC_P (dw_cfi_ref);
+DEF_VEC_ALLOC_P (dw_cfi_ref, heap);
+DEF_VEC_ALLOC_P (dw_cfi_ref, gc);
+
+typedef VEC(dw_cfi_ref, gc) *cfi_vec;
+
 /* This is how we define the location of the CFA. We use to handle it
    as REG + OFFSET all the time,  but now it can be more complex.
    It can now be either REG + CFA_OFFSET or *(REG + BASE_OFFSET) + CFA_OFFSET.
    Instead of passing around REG and OFFSET, we pass a copy
    of this structure.  */
-typedef struct GTY(()) cfa_loc {
+typedef struct cfa_loc {
   HOST_WIDE_INT offset;
   HOST_WIDE_INT base_offset;
   unsigned int reg;
@@ -304,12 +307,10 @@ typedef struct GTY(()) dw_fde_struct {
   const char *dw_fde_end;
   const char *dw_fde_vms_end_prologue;
   const char *dw_fde_vms_begin_epilogue;
-  const char *dw_fde_hot_section_label;
-  const char *dw_fde_hot_section_end_label;
-  const char *dw_fde_unlikely_section_label;
-  const char *dw_fde_unlikely_section_end_label;
-  dw_cfi_ref dw_fde_cfi;
-  dw_cfi_ref dw_fde_switch_cfi; /* Last CFI before switching sections.  */
+  const char *dw_fde_second_begin;
+  const char *dw_fde_second_end;
+  cfi_vec dw_fde_cfi;
+  int dw_fde_switch_cfi_index; /* Last CFI before switching sections.  */
   HOST_WIDE_INT stack_realignment;
   unsigned funcdef_number;
   /* Dynamic realign argument pointer register.  */
@@ -326,13 +327,9 @@ typedef struct GTY(()) dw_fde_struct {
   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
+  /* True iff dw_fde_second_begin 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;
+  unsigned second_in_std_section : 1;
 }
 dw_fde_node;
 
@@ -418,8 +415,8 @@ current_fde (void)
   return fde_table_in_use ? &fde_table[fde_table_in_use - 1] : NULL;
 }
 
-/* A list of call frame insns for the CIE.  */
-static GTY(()) dw_cfi_ref cie_cfi_head;
+/* A vector of call frame insns for the CIE.  */
+static GTY(()) cfi_vec cie_cfi_vec;
 
 /* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram
    attribute that accelerates the lookup of the FDE associated
@@ -436,10 +433,6 @@ 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;
 
@@ -459,7 +452,7 @@ static GTY(()) section *cold_text_section;
 static char *stripattributes (const char *);
 static const char *dwarf_cfi_name (unsigned);
 static dw_cfi_ref new_cfi (void);
-static void add_cfi (dw_cfi_ref *, dw_cfi_ref);
+static void add_cfi (cfi_vec *, dw_cfi_ref);
 static void add_fde_cfi (const char *, dw_cfi_ref);
 static void lookup_cfa_1 (dw_cfi_ref, dw_cfa_location *, dw_cfa_location *);
 static void lookup_cfa (dw_cfa_location *);
@@ -471,12 +464,11 @@ 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 flush_queued_reg_saves (void);
 static bool clobbers_queued_reg_save (const_rtx);
 static void dwarf2out_frame_debug_expr (rtx, const char *);
 
 /* Support for complex CFA locations.  */
-static void output_cfa_loc (dw_cfi_ref);
+static void output_cfa_loc (dw_cfi_ref, int);
 static void output_cfa_loc_raw (dw_cfi_ref);
 static void get_cfa_from_loc_descr (dw_cfa_location *,
                                    struct dw_loc_descr_struct *);
@@ -486,7 +478,8 @@ static struct dw_loc_descr_struct *build_cfa_aligned_loc
   (HOST_WIDE_INT, HOST_WIDE_INT);
 static void def_cfa_1 (const char *, dw_cfa_location *);
 static struct dw_loc_descr_struct *mem_loc_descriptor
-  (rtx, enum machine_mode mode, enum var_init_status);
+  (rtx, enum machine_mode mode, enum machine_mode mem_mode,
+   enum var_init_status);
 
 /* How to start an assembler comment.  */
 #ifndef ASM_COMMENT_START
@@ -548,6 +541,89 @@ static struct dw_loc_descr_struct *mem_loc_descriptor
 #define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
 #endif
 \f
+/* Match the base name of a file to the base name of a compilation unit. */
+
+static int
+matches_main_base (const char *path)
+{
+  /* Cache the last query. */
+  static const char *last_path = NULL;
+  static int last_match = 0;
+  if (path != last_path)
+    {
+      const char *base;
+      int length = base_of_path (path, &base);
+      last_path = path;
+      last_match = (length == main_input_baselength
+                    && memcmp (base, main_input_basename, length) == 0);
+    }
+  return last_match;
+}
+
+#ifdef DEBUG_DEBUG_STRUCT
+
+static int
+dump_struct_debug (tree type, enum debug_info_usage usage,
+                  enum debug_struct_file criterion, int generic,
+                  int matches, int result)
+{
+  /* Find the type name. */
+  tree type_decl = TYPE_STUB_DECL (type);
+  tree t = type_decl;
+  const char *name = 0;
+  if (TREE_CODE (t) == TYPE_DECL)
+    t = DECL_NAME (t);
+  if (t)
+    name = IDENTIFIER_POINTER (t);
+
+  fprintf (stderr, "   struct %d %s %s %s %s %d %p %s\n",
+          criterion,
+           DECL_IN_SYSTEM_HEADER (type_decl) ? "sys" : "usr",
+           matches ? "bas" : "hdr",
+           generic ? "gen" : "ord",
+           usage == DINFO_USAGE_DFN ? ";" :
+             usage == DINFO_USAGE_DIR_USE ? "." : "*",
+           result,
+           (void*) type_decl, name);
+  return result;
+}
+#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
+  dump_struct_debug (type, usage, criterion, generic, matches, result)
+
+#else
+
+#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
+  (result)
+
+#endif
+
+static bool
+should_emit_struct_debug (tree type, enum debug_info_usage usage)
+{
+  enum debug_struct_file criterion;
+  tree type_decl;
+  bool generic = lang_hooks.types.generic_p (type);
+
+  if (generic)
+    criterion = debug_struct_generic[usage];
+  else
+    criterion = debug_struct_ordinary[usage];
+
+  if (criterion == DINFO_STRUCT_FILE_NONE)
+    return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
+  if (criterion == DINFO_STRUCT_FILE_ANY)
+    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
+
+  type_decl = TYPE_STUB_DECL (TYPE_MAIN_VARIANT (type));
+
+  if (criterion == DINFO_STRUCT_FILE_SYS && DECL_IN_SYSTEM_HEADER (type_decl))
+    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
+
+  if (matches_main_base (DECL_SOURCE_FILE (type_decl)))
+    return DUMP_GSTRUCT (type, usage, criterion, generic, true, true);
+  return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
+}
+\f
 /* Hook used by __throw.  */
 
 rtx
@@ -733,7 +809,6 @@ new_cfi (void)
 {
   dw_cfi_ref cfi = ggc_alloc_dw_cfi_node ();
 
-  cfi->dw_cfi_next = NULL;
   cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0;
   cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0;
 
@@ -743,9 +818,8 @@ new_cfi (void)
 /* Add a Call Frame Instruction to list of instructions.  */
 
 static inline void
-add_cfi (dw_cfi_ref *list_head, dw_cfi_ref cfi)
+add_cfi (cfi_vec *vec, dw_cfi_ref cfi)
 {
-  dw_cfi_ref *p;
   dw_fde_ref fde = current_fde ();
 
   /* When DRAP is used, CFA is defined with an expression.  Redefine
@@ -767,11 +841,7 @@ add_cfi (dw_cfi_ref *list_head, dw_cfi_ref cfi)
           break;
       }
 
-  /* Find the end of the chain.  */
-  for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next)
-    ;
-
-  *p = cfi;
+  VEC_safe_push (dw_cfi_ref, gc, *vec, cfi);
 }
 
 /* Generate a new label for the CFI info to refer to.  FORCE is true
@@ -791,8 +861,9 @@ dwarf2out_cfi_label (bool force)
     }
   else
     {
-      ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", dwarf2out_cfi_label_num++);
-      ASM_OUTPUT_LABEL (asm_out_file, label);
+      int num = dwarf2out_cfi_label_num++;
+      ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", num);
+      ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LCFI", num);
     }
 
   return label;
@@ -801,13 +872,21 @@ dwarf2out_cfi_label (bool force)
 /* True if remember_state should be emitted before following CFI directive.  */
 static bool emit_cfa_remember;
 
+/* True if any CFI directives were emitted at the current insn.  */
+static bool any_cfis_emitted;
+
 /* 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;
+  cfi_vec *vec;
+
+  if (cie_cfi_vec == NULL)
+    cie_cfi_vec = VEC_alloc (dw_cfi_ref, gc, 20);
+
+  vec = &cie_cfi_vec;
 
   if (emit_cfa_remember)
     {
@@ -820,8 +899,6 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi)
       add_fde_cfi (label, cfi_remember);
     }
 
-  list_head = &cie_cfi_head;
-
   if (dwarf2out_do_cfi_asm ())
     {
       if (label)
@@ -879,7 +956,8 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi)
 
          output_cfi_directive (cfi);
 
-         list_head = &fde->dw_fde_cfi;
+         vec = &fde->dw_fde_cfi;
+         any_cfis_emitted = true;
        }
       /* ??? If this is a CFI for the CIE, we don't emit.  This
         assumes that the standard CIE contents that the assembler
@@ -916,10 +994,11 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi)
          fde->dw_fde_current_label = label;
        }
 
-      list_head = &fde->dw_fde_cfi;
+      vec = &fde->dw_fde_cfi;
+      any_cfis_emitted = true;
     }
 
-  add_cfi (list_head, cfi);
+  add_cfi (vec, cfi);
 }
 
 /* Subroutine of lookup_cfa.  */
@@ -966,6 +1045,7 @@ lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc, dw_cfa_location *remember)
 static void
 lookup_cfa (dw_cfa_location *loc)
 {
+  int ix;
   dw_cfi_ref cfi;
   dw_fde_ref fde;
   dw_cfa_location remember;
@@ -974,12 +1054,12 @@ lookup_cfa (dw_cfa_location *loc)
   loc->reg = INVALID_REGNUM;
   remember = *loc;
 
-  for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
+  FOR_EACH_VEC_ELT (dw_cfi_ref, cie_cfi_vec, ix, cfi)
     lookup_cfa_1 (cfi, loc, &remember);
 
   fde = current_fde ();
   if (fde)
-    for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
+    FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi)
       lookup_cfa_1 (cfi, loc, &remember);
 }
 
@@ -1712,8 +1792,8 @@ queue_reg_save (const char *label, rtx reg, rtx sreg, HOST_WIDE_INT offset)
 
 /* Output all the entries in QUEUED_REG_SAVES.  */
 
-static void
-flush_queued_reg_saves (void)
+void
+dwarf2out_flush_queued_reg_saves (void)
 {
   struct queued_reg_save *q;
 
@@ -1970,6 +2050,17 @@ dwarf2out_frame_debug_cfa_register (rtx set, const char *label)
   reg_save (label, sregno, dregno, 0);
 }
 
+/* Helper function to get mode of MEM's address.  */
+
+static inline enum machine_mode
+get_address_mode (rtx mem)
+{
+  enum machine_mode mode = GET_MODE (XEXP (mem, 0));
+  if (mode != VOIDmode)
+    return mode;
+  return targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem));
+}
+
 /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_EXPRESSION note. */
 
 static void
@@ -1990,8 +2081,8 @@ dwarf2out_frame_debug_cfa_expression (rtx set, const char *label)
   cfi->dw_cfi_opc = DW_CFA_expression;
   cfi->dw_cfi_oprnd1.dw_cfi_reg_num = DWARF_FRAME_REGNUM (REGNO (src));
   cfi->dw_cfi_oprnd2.dw_cfi_loc
-    = mem_loc_descriptor (XEXP (dest, 0), GET_MODE (dest),
-                         VAR_INIT_STATUS_INITIALIZED);
+    = mem_loc_descriptor (XEXP (dest, 0), get_address_mode (dest),
+                         GET_MODE (dest), VAR_INIT_STATUS_INITIALIZED);
 
   /* ??? We'd like to use queue_reg_save, were the interface different,
      and, as above, we could manage flushing for epilogues.  */
@@ -2146,14 +2237,14 @@ dwarf2out_frame_debug_cfa_restore (rtx reg, const char *label)
           cfa_temp.offset = <const_int>
 
   Rule 10:
-  (set (mem (pre_modify sp:cfa_store (???? <reg1> <const_int>))) <reg2>)
+  (set (mem ({pre,post}_modify sp:cfa_store (???? <reg1> <const_int>))) <reg2>)
   effects: cfa_store.offset -= <const_int>
           cfa.offset = cfa_store.offset if cfa.reg == sp
           cfa.reg = sp
           cfa.base_offset = -cfa_store.offset
 
   Rule 11:
-  (set (mem ({pre_inc,pre_dec} sp:cfa_store.reg)) <reg>)
+  (set (mem ({pre_inc,pre_dec,post_dec} sp:cfa_store.reg)) <reg>)
   effects: cfa_store.offset += -/+ mode_size(mem)
           cfa.offset = cfa_store.offset if cfa.reg == sp
           cfa.reg = sp
@@ -2172,7 +2263,7 @@ dwarf2out_frame_debug_cfa_restore (rtx reg, const char *label)
           cfa.base_offset = -{cfa_store,cfa_temp}.offset
 
   Rule 14:
-  (set (mem (postinc <reg1>:cfa_temp <const_int>)) <reg2>)
+  (set (mem (post_inc <reg1>:cfa_temp <const_int>)) <reg2>)
   effects: cfa.reg = <reg1>
           cfa.base_offset = -cfa_temp.offset
           cfa_temp.offset -= mode_size(mem)
@@ -2458,7 +2549,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
             {
              /* We interpret reg_save differently with stack_realign set.
                 Thus we must flush whatever we have queued first.  */
-             flush_queued_reg_saves ();
+             dwarf2out_flush_queued_reg_saves ();
 
               gcc_assert (cfa_store.reg == REGNO (XEXP (src, 0)));
               fde->stack_realign = 1;
@@ -2487,6 +2578,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
          /* Rule 10 */
          /* With a push.  */
        case PRE_MODIFY:
+       case POST_MODIFY:
          /* We can't handle variable size modifications.  */
          gcc_assert (GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
                      == CONST_INT);
@@ -2499,12 +2591,16 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
          if (cfa.reg == STACK_POINTER_REGNUM)
            cfa.offset = cfa_store.offset;
 
-         offset = -cfa_store.offset;
+         if (GET_CODE (XEXP (dest, 0)) == POST_MODIFY)
+           offset -= cfa_store.offset;
+         else
+           offset = -cfa_store.offset;
          break;
 
          /* Rule 11 */
        case PRE_INC:
        case PRE_DEC:
+       case POST_DEC:
          offset = GET_MODE_SIZE (GET_MODE (dest));
          if (GET_CODE (XEXP (dest, 0)) == PRE_INC)
            offset = -offset;
@@ -2529,7 +2625,10 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
          if (cfa.reg == STACK_POINTER_REGNUM)
            cfa.offset = cfa_store.offset;
 
-         offset = -cfa_store.offset;
+         if (GET_CODE (XEXP (dest, 0)) == POST_DEC)
+           offset += -cfa_store.offset;
+         else
+           offset = -cfa_store.offset;
          break;
 
          /* Rule 12 */
@@ -2548,7 +2647,9 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
 
            regno = REGNO (XEXP (XEXP (dest, 0), 0));
 
-           if (cfa_store.reg == (unsigned) regno)
+           if (cfa.reg == (unsigned) regno)
+             offset -= cfa.offset;
+           else if (cfa_store.reg == (unsigned) regno)
              offset -= cfa_store.offset;
            else
              {
@@ -2564,7 +2665,9 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
          {
            int regno = REGNO (XEXP (dest, 0));
 
-           if (cfa_store.reg == (unsigned) regno)
+           if (cfa.reg == (unsigned) regno)
+             offset = -cfa.offset;
+           else if (cfa_store.reg == (unsigned) regno)
              offset = -cfa_store.offset;
            else
              {
@@ -2700,40 +2803,8 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
   rtx note, n;
   bool handled_one = false;
 
-  if (insn == NULL_RTX)
-    {
-      size_t i;
-
-      /* Flush any queued register saves.  */
-      flush_queued_reg_saves ();
-
-      /* Set up state for generating call frame debug info.  */
-      lookup_cfa (&cfa);
-      gcc_assert (cfa.reg
-                 == (unsigned long)DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM));
-
-      cfa.reg = STACK_POINTER_REGNUM;
-      cfa_store = cfa;
-      cfa_temp.reg = -1;
-      cfa_temp.offset = 0;
-
-      for (i = 0; i < num_regs_saved_in_regs; i++)
-       {
-         regs_saved_in_regs[i].orig_reg = NULL_RTX;
-         regs_saved_in_regs[i].saved_in_reg = NULL_RTX;
-       }
-      num_regs_saved_in_regs = 0;
-
-      if (barrier_args_size)
-       {
-         XDELETEVEC (barrier_args_size);
-         barrier_args_size = NULL;
-       }
-      return;
-    }
-
   if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn))
-    flush_queued_reg_saves ();
+    dwarf2out_flush_queued_reg_saves ();
 
   if (!RTX_FRAME_RELATED_P (insn))
     {
@@ -2746,6 +2817,7 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
     }
 
   label = dwarf2out_cfi_label (false);
+  any_cfis_emitted = false;
 
   for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
     switch (REG_NOTE_KIND (note))
@@ -2831,7 +2903,11 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
        break;
       }
   if (handled_one)
-    return;
+    {
+      if (any_cfis_emitted)
+       dwarf2out_flush_queued_reg_saves ();
+      return;
+    }
 
   insn = PATTERN (insn);
  found:
@@ -2840,8 +2916,42 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
   /* Check again.  A parallel can save and update the same register.
      We could probably check just once, here, but this is safer than
      removing the check above.  */
-  if (clobbers_queued_reg_save (insn))
-    flush_queued_reg_saves ();
+  if (any_cfis_emitted || clobbers_queued_reg_save (insn))
+    dwarf2out_flush_queued_reg_saves ();
+}
+
+/* Called once at the start of final to initialize some data for the
+   current function.  */
+void
+dwarf2out_frame_debug_init (void)
+{
+  size_t i;
+
+  /* Flush any queued register saves.  */
+  dwarf2out_flush_queued_reg_saves ();
+
+  /* Set up state for generating call frame debug info.  */
+  lookup_cfa (&cfa);
+  gcc_assert (cfa.reg
+             == (unsigned long)DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM));
+
+  cfa.reg = STACK_POINTER_REGNUM;
+  cfa_store = cfa;
+  cfa_temp.reg = -1;
+  cfa_temp.offset = 0;
+
+  for (i = 0; i < num_regs_saved_in_regs; i++)
+    {
+      regs_saved_in_regs[i].orig_reg = NULL_RTX;
+      regs_saved_in_regs[i].saved_in_reg = NULL_RTX;
+    }
+  num_regs_saved_in_regs = 0;
+
+  if (barrier_args_size)
+    {
+      XDELETEVEC (barrier_args_size);
+      barrier_args_size = NULL;
+    }
 }
 
 /* Determine if we need to save and restore CFI information around this
@@ -3221,7 +3331,7 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
 
        case DW_CFA_def_cfa_expression:
        case DW_CFA_expression:
-         output_cfa_loc (cfi);
+         output_cfa_loc (cfi, for_eh);
          break;
 
        case DW_CFA_GNU_negative_offset_extended:
@@ -3335,169 +3445,183 @@ output_cfi_directive (dw_cfi_ref cfi)
     }
 }
 
-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.  */
+/* Output CFIs from VEC, up to index UPTO, to bring current FDE to the
+   same state as after executing CFIs in CFI chain.  DO_CFI_ASM is
+   true if .cfi_* directives shall be emitted, false otherwise.  If it
+   is false, FDE and FOR_EH are the other arguments to pass to
+   output_cfi.  */
 
 static void
-output_cfis (dw_cfi_ref cfi, bool do_cfi_asm, dw_fde_ref fde, bool for_eh)
+output_cfis (cfi_vec vec, int upto, bool do_cfi_asm,
+            dw_fde_ref fde, bool for_eh)
 {
+  int ix;
   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);
+  VEC(dw_cfi_ref, heap) *regs = VEC_alloc (dw_cfi_ref, heap, 32);
   unsigned int len, idx;
 
-  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:
+  for (ix = 0; ix < upto + 1; ix++)
+    {
+      dw_cfi_ref cfi = ix < upto ? VEC_index (dw_cfi_ref, vec, ix) : NULL;
+      switch (cfi ? cfi->dw_cfi_opc : DW_CFA_nop)
        {
-         dw_cfi_ref args_size = cfi_args_size;
-
-         /* Skip everything between .cfi_remember_state and
-            .cfi_restore_state.  */
-         for (cfi2 = cfi->dw_cfi_next; cfi2; cfi2 = cfi2->dw_cfi_next)
-           if (cfi2->dw_cfi_opc == DW_CFA_restore_state)
-             break;
-           else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size)
-             args_size = cfi2;
-           else
-             gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state);
-
-         if (cfi2 == NULL)
-           goto flush_all;
-         else
-           {
-             cfi = cfi2;
-             cfi_args_size = args_size;
-           }
+       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_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++)
+       case DW_CFA_remember_state:
          {
-           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)
+           dw_cfi_ref args_size = cfi_args_size;
+
+           /* Skip everything between .cfi_remember_state and
+              .cfi_restore_state.  */
+           ix++;
+           if (ix == upto)
+             goto flush_all;
+
+           for (; ix < upto; ix++)
              {
-               if (do_cfi_asm)
-                 output_cfi_directive (cfi2);
+               cfi2 = VEC_index (dw_cfi_ref, vec, ix);
+               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
-                 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 ();
+                 gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state);
              }
-           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;
+
+           cfi_args_size = args_size;
+           break;
          }
-       else if (do_cfi_asm)
-         output_cfi_directive (cfi);
-       else
-         output_cfi (cfi, fde, for_eh);
-       break;
-      default:
-       gcc_unreachable ();
+       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 ();
+       }
     }
 }
 
+/* Like output_cfis, but emit all CFIs in the vector.  */
+static void
+output_all_cfis (cfi_vec vec, bool do_cfi_asm,
+                dw_fde_ref fde, bool for_eh)
+{
+  output_cfis (vec, VEC_length (dw_cfi_ref, vec), do_cfi_asm, fde, for_eh);
+}
+
 /* Output one FDE.  */
 
 static void
@@ -3505,6 +3629,7 @@ 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)
 {
+  int ix;
   const char *begin, *end;
   static unsigned int j;
   char l1[20], l2[20];
@@ -3529,28 +3654,8 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second,
     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;
-    }
+  begin = second ? fde->dw_fde_second_begin : fde->dw_fde_begin;
+  end = second ? fde->dw_fde_second_end : fde->dw_fde_end;
 
   if (for_eh)
     {
@@ -3611,32 +3716,32 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second,
   /* 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)
+  if (fde->dw_fde_second_begin == NULL)
+    FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi)
       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)
+      if (fde->dw_fde_switch_cfi_index > 0)
+       FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi)
          {
-           output_cfi (cfi, fde, for_eh);
-           if (cfi == fde->dw_fde_switch_cfi)
+           if (ix == fde->dw_fde_switch_cfi_index)
              break;
+           output_cfi (cfi, fde, for_eh);
          }
     }
   else
     {
-      dw_cfi_ref cfi_next = fde->dw_fde_cfi;
+      int i, from = 0;
+      int until = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
 
-      if (fde->dw_fde_switch_cfi)
+      if (fde->dw_fde_switch_cfi_index > 0)
        {
-         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;
+         from = fde->dw_fde_switch_cfi_index;
+         output_cfis (fde->dw_fde_cfi, from, false, fde, for_eh);
        }
-      for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next)
-       output_cfi (cfi, fde, for_eh);
+      for (i = from; i < until; i++)
+       output_cfi (VEC_index (dw_cfi_ref, fde->dw_fde_cfi, i),
+                   fde, for_eh);
     }
 
   /* If we are to emit a ref/link from function bodies to their frame tables,
@@ -3872,7 +3977,7 @@ output_call_frame_info (int for_eh)
                             eh_data_format_name (fde_encoding));
     }
 
-  for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
+  FOR_EACH_VEC_ELT (dw_cfi_ref, cie_cfi_vec, i, cfi)
     output_cfi (cfi, NULL, for_eh);
 
   /* Pad the CIE out to an address sized boundary.  */
@@ -3890,7 +3995,7 @@ output_call_frame_info (int for_eh)
       if (for_eh && !fde_needed_for_eh_p (fde))
        continue;
 
-      for (k = 0; k < (fde->dw_fde_switched_sections ? 2 : 1); k++)
+      for (k = 0; k < (fde->dw_fde_second_begin ? 2 : 1); k++)
        output_fde (fde, for_eh, k, section_start_label, fde_encoding,
                    augmentation, any_lsda_needed, lsda_encoding);
     }
@@ -3966,20 +4071,18 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   char * dup_label;
   dw_fde_ref fde;
   section *fnsec;
+  bool do_frame;
 
   current_function_func_begin_label = NULL;
 
-#ifdef TARGET_UNWIND_INFO
-  /* ??? current_function_func_begin_label is also used by except.c
-     for call-site information.  We must emit this label if it might
-     be used.  */
-  if ((! flag_exceptions || USING_SJLJ_EXCEPTIONS)
-      && ! dwarf2out_do_frame ())
-    return;
-#else
-  if (! dwarf2out_do_frame ())
+  do_frame = dwarf2out_do_frame ();
+
+  /* ??? current_function_func_begin_label is also used by except.c for
+     call-site information.  We must emit this label if it might be used.  */
+  if (!do_frame
+      && (!flag_exceptions
+         || targetm.except_unwind_info (&global_options) != UI_TARGET))
     return;
-#endif
 
   fnsec = function_section (current_function_decl);
   switch_to_section (fnsec);
@@ -3990,11 +4093,9 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   dup_label = xstrdup (label);
   current_function_func_begin_label = dup_label;
 
-#ifdef TARGET_UNWIND_INFO
   /* We can elide the fde allocation if we're not emitting debug info.  */
-  if (! dwarf2out_do_frame ())
+  if (!do_frame)
     return;
-#endif
 
   /* Expand the fde table if necessary.  */
   if (fde_table_in_use == fde_table_allocated)
@@ -4012,45 +4113,23 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   fde = &fde_table[fde_table_in_use++];
   fde->decl = current_function_decl;
   fde->dw_fde_begin = dup_label;
-  fde->dw_fde_current_label = dup_label;
-  fde->dw_fde_hot_section_label = NULL;
-  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 = 0;
-  fde->dw_fde_switched_cold_to_hot = 0;
   fde->dw_fde_end = NULL;
+  fde->dw_fde_current_label = dup_label;
+  fde->dw_fde_second_begin = NULL;
+  fde->dw_fde_second_end = NULL;
   fde->dw_fde_vms_end_prologue = NULL;
   fde->dw_fde_vms_begin_epilogue = NULL;
-  fde->dw_fde_cfi = NULL;
-  fde->dw_fde_switch_cfi = NULL;
+  fde->dw_fde_cfi = VEC_alloc (dw_cfi_ref, gc, 20);
+  fde->dw_fde_switch_cfi_index = 0;
   fde->funcdef_number = current_function_funcdef_no;
   fde->all_throwers_are_sibcalls = crtl->all_throwers_are_sibcalls;
   fde->uses_eh_lsda = crtl->uses_eh_lsda;
   fde->nothrow = crtl->nothrow;
   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;
-    }
+  fde->in_std_section = (fnsec == text_section
+                        || (cold_text_section && fnsec == cold_text_section));
+  fde->second_in_std_section = 0;
 
   args_size = old_args_size = 0;
 
@@ -4146,7 +4225,8 @@ dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
   ASM_OUTPUT_LABEL (asm_out_file, label);
   fde = current_fde ();
   gcc_assert (fde != NULL);
-  fde->dw_fde_end = xstrdup (label);
+  if (fde->dw_fde_second_begin == NULL)
+    fde->dw_fde_end = xstrdup (label);
 }
 
 void
@@ -4163,7 +4243,8 @@ dwarf2out_frame_init (void)
   /* On entry, the Canonical Frame Address is at SP.  */
   dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
 
-  if (DWARF2_UNWIND_INFO || DWARF2_FRAME_INFO)
+  if (targetm.debug_unwind_info () == UI_DWARF2
+      || targetm.except_unwind_info (&global_options) == UI_DWARF2)
     initial_return_save (INCOMING_RETURN_ADDR_RTX);
 }
 
@@ -4171,14 +4252,13 @@ void
 dwarf2out_frame_finish (void)
 {
   /* Output call frame information.  */
-  if (DWARF2_FRAME_INFO)
+  if (targetm.debug_unwind_info () == UI_DWARF2)
     output_call_frame_info (0);
 
-#ifndef TARGET_UNWIND_INFO
   /* Output another copy for the unwinder.  */
-  if (! USING_SJLJ_EXCEPTIONS && (flag_unwind_tables || flag_exceptions))
+  if ((flag_unwind_tables || flag_exceptions)
+      && targetm.except_unwind_info (&global_options) == UI_DWARF2)
     output_call_frame_info (1);
-#endif
 }
 
 /* Note that the current function section is being used for code.  */
@@ -4193,20 +4273,29 @@ dwarf2out_note_section_used (void)
     cold_text_section_used = true;
 }
 
+static void var_location_switch_text_section (void);
+static void set_cur_line_info_table (section *);
+
 void
 dwarf2out_switch_text_section (void)
 {
+  section *sect;
   dw_fde_ref fde = current_fde ();
 
-  gcc_assert (cfun && fde && !fde->dw_fde_switched_sections);
+  gcc_assert (cfun && fde && fde->dw_fde_second_begin == NULL);
 
-  fde->dw_fde_switched_sections = 1;
-  fde->dw_fde_switched_cold_to_hot = !in_cold_section_p;
-
-  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;
-  fde->dw_fde_unlikely_section_end_label = crtl->subsections.cold_section_end_label;
+  if (!in_cold_section_p)
+    {
+      fde->dw_fde_end = crtl->subsections.cold_section_end_label;
+      fde->dw_fde_second_begin = crtl->subsections.hot_section_label;
+      fde->dw_fde_second_end = crtl->subsections.hot_section_end_label;
+    }
+  else
+    {
+      fde->dw_fde_end = crtl->subsections.hot_section_end_label;
+      fde->dw_fde_second_begin = crtl->subsections.cold_section_label;
+      fde->dw_fde_second_end = crtl->subsections.cold_section_end_label;
+    }
   have_multiple_function_sections = true;
 
   /* Reset the current label on switching text sections, so that we
@@ -4221,25 +4310,24 @@ dwarf2out_switch_text_section (void)
     fprintf (asm_out_file, "\t.cfi_endproc\n");
 
   /* Now do the real section switch.  */
-  switch_to_section (current_function_section ());
+  sect = current_function_section ();
+  switch_to_section (sect);
+
+  fde->second_in_std_section
+    = (sect == text_section
+       || (cold_text_section && sect == cold_text_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);
+      output_all_cfis (fde->dw_fde_cfi, true, fde, true);
     }
-  else
-    {
-      dw_cfi_ref cfi = fde->dw_fde_cfi;
+  fde->dw_fde_switch_cfi_index = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
+  var_location_switch_text_section ();
 
-      cfi = fde->dw_fde_cfi;
-      if (cfi)
-       while (cfi->dw_cfi_next != NULL)
-         cfi = cfi->dw_cfi_next;
-      fde->dw_fde_switch_cfi = cfi;
-    }
+  set_cur_line_info_table (sect);
 }
 \f
 /* And now, the subset of the debugging information support code necessary
@@ -4295,6 +4383,7 @@ enum dw_val_class
   dw_val_class_macptr,
   dw_val_class_file,
   dw_val_class_data8,
+  dw_val_class_decl_ref,
   dw_val_class_vms_delta
 };
 
@@ -4333,6 +4422,7 @@ typedef struct GTY(()) dw_val_struct {
       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];
+      tree GTY ((tag ("dw_val_class_decl_ref"))) val_decl_ref;
       struct dw_val_vms_delta_union
        {
          char * lbl1;
@@ -4369,6 +4459,13 @@ typedef struct GTY(()) dw_loc_list_struct {
                      Only on head of list */
   const char *section; /* Section this loclist is relative to */
   dw_loc_descr_ref expr;
+  hashval_t hash;
+  /* True if all addresses in this and subsequent lists are known to be
+     resolved.  */
+  bool resolved_addr;
+  /* True if this list has been replaced by dw_loc_next.  */
+  bool replaced;
+  bool emitted;
 } dw_loc_list_node;
 
 static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
@@ -4696,6 +4793,20 @@ dwarf_stack_op_name (unsigned int op)
       return "DW_OP_GNU_uninit";
     case DW_OP_GNU_encoded_addr:
       return "DW_OP_GNU_encoded_addr";
+    case DW_OP_GNU_implicit_pointer:
+      return "DW_OP_GNU_implicit_pointer";
+    case DW_OP_GNU_entry_value:
+      return "DW_OP_GNU_entry_value";
+    case DW_OP_GNU_const_type:
+      return "DW_OP_GNU_const_type";
+    case DW_OP_GNU_regval_type:
+      return "DW_OP_GNU_regval_type";
+    case DW_OP_GNU_deref_type:
+      return "DW_OP_GNU_deref_type";
+    case DW_OP_GNU_convert:
+      return "DW_OP_GNU_convert";
+    case DW_OP_GNU_reinterpret:
+      return "DW_OP_GNU_reinterpret";
 
     default:
       return "OP_<unknown>";
@@ -4799,6 +4910,12 @@ loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset)
     loc_descr_plus_const (&d->expr, offset);
 }
 
+#define DWARF_REF_SIZE \
+  (dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE)
+
+static unsigned long size_of_locs (dw_loc_descr_ref);
+static unsigned long int get_base_type_offset (dw_die_ref);
+
 /* Return the size of a location descriptor.  */
 
 static unsigned long
@@ -4905,15 +5022,68 @@ size_of_loc_descr (dw_loc_descr_ref loc)
       size += 4;
       break;
     case DW_OP_call_ref:
-      size += DWARF2_ADDR_SIZE;
+      size += DWARF_REF_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:
+    case DW_OP_GNU_implicit_pointer:
+      size += DWARF_REF_SIZE + size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
       break;
-    }
+    case DW_OP_GNU_entry_value:
+      {
+       unsigned long op_size = size_of_locs (loc->dw_loc_oprnd1.v.val_loc);
+       size += size_of_uleb128 (op_size) + op_size;
+       break;
+      }
+    case DW_OP_GNU_const_type:
+      {
+       unsigned long o
+         = get_base_type_offset (loc->dw_loc_oprnd1.v.val_die_ref.die);
+       size += size_of_uleb128 (o) + 1;
+       switch (loc->dw_loc_oprnd2.val_class)
+         {
+         case dw_val_class_vec:
+           size += loc->dw_loc_oprnd2.v.val_vec.length
+                   * loc->dw_loc_oprnd2.v.val_vec.elt_size;
+           break;
+         case dw_val_class_const:
+           size += HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT;
+           break;
+         case dw_val_class_const_double:
+           size += 2 * HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT;
+           break;
+         default:
+           gcc_unreachable ();
+         }
+       break;
+      }
+    case DW_OP_GNU_regval_type:
+      {
+       unsigned long o
+         = get_base_type_offset (loc->dw_loc_oprnd2.v.val_die_ref.die);
+       size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned)
+               + size_of_uleb128 (o);
+      }
+      break;
+    case DW_OP_GNU_deref_type:
+      {
+       unsigned long o
+         = get_base_type_offset (loc->dw_loc_oprnd2.v.val_die_ref.die);
+       size += 1 + size_of_uleb128 (o);
+      }
+      break;
+    case DW_OP_GNU_convert:
+    case DW_OP_GNU_reinterpret:
+      {
+       unsigned long o
+         = get_base_type_offset (loc->dw_loc_oprnd1.v.val_die_ref.die);
+       size += size_of_uleb128 (o);
+      }
+    default:
+      break;
+    }
 
   return size;
 }
@@ -4947,11 +5117,18 @@ size_of_locs (dw_loc_descr_ref loc)
 }
 
 static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
+static void get_ref_die_offset_label (char *, dw_die_ref);
+static void output_loc_sequence (dw_loc_descr_ref, int);
 
-/* Output location description stack opcode's operands (if any).  */
+/* Output location description stack opcode's operands (if any).
+   The for_eh_or_skip parameter controls whether register numbers are
+   converted using DWARF2_FRAME_REG_OUT, which is needed in the case that
+   hard reg numbers have been processed via DWARF_FRAME_REGNUM (i.e. for unwind
+   info).  This should be suppressed for the cases that have not been converted
+   (i.e. symbolic debug info), by setting the parameter < 0.  See PR47324.  */
 
 static void
-output_loc_operands (dw_loc_descr_ref loc)
+output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
 {
   dw_val_ref val1 = &loc->dw_loc_oprnd1;
   dw_val_ref val2 = &loc->dw_loc_oprnd2;
@@ -5122,14 +5299,28 @@ output_loc_operands (dw_loc_descr_ref loc)
       dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
       break;
     case DW_OP_regx:
-      dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+      {
+       unsigned r = val1->v.val_unsigned;
+       if (for_eh_or_skip >= 0)
+         r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
+       gcc_assert (size_of_uleb128 (r) 
+                   == size_of_uleb128 (val1->v.val_unsigned));
+       dw2_asm_output_data_uleb128 (r, NULL);  
+      }
       break;
     case DW_OP_fbreg:
       dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
       break;
     case DW_OP_bregx:
-      dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
-      dw2_asm_output_data_sleb128 (val2->v.val_int, NULL);
+      {
+       unsigned r = val1->v.val_unsigned;
+       if (for_eh_or_skip >= 0)
+         r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
+       gcc_assert (size_of_uleb128 (r) 
+                   == size_of_uleb128 (val1->v.val_unsigned));
+       dw2_asm_output_data_uleb128 (r, NULL);  
+       dw2_asm_output_data_sleb128 (val2->v.val_int, NULL);
+      }
       break;
     case DW_OP_piece:
       dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
@@ -5166,25 +5357,154 @@ output_loc_operands (dw_loc_descr_ref loc)
        }
       break;
 
+    case DW_OP_GNU_implicit_pointer:
+      {
+       char label[MAX_ARTIFICIAL_LABEL_BYTES
+                  + HOST_BITS_PER_WIDE_INT / 2 + 2];
+       gcc_assert (val1->val_class == dw_val_class_die_ref);
+       get_ref_die_offset_label (label, val1->v.val_die_ref.die);
+       dw2_asm_output_offset (DWARF_REF_SIZE, label, debug_info_section, NULL);
+       dw2_asm_output_data_sleb128 (val2->v.val_int, NULL);
+      }
+      break;
+
+    case DW_OP_GNU_entry_value:
+      dw2_asm_output_data_uleb128 (size_of_locs (val1->v.val_loc), NULL);
+      output_loc_sequence (val1->v.val_loc, for_eh_or_skip);
+      break;
+
+    case DW_OP_GNU_const_type:
+      {
+       unsigned long o = get_base_type_offset (val1->v.val_die_ref.die), l;
+       gcc_assert (o);
+       dw2_asm_output_data_uleb128 (o, NULL);
+       switch (val2->val_class)
+         {
+         case dw_val_class_const:
+           l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
+           dw2_asm_output_data (1, l, NULL);
+           dw2_asm_output_data (l, 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;
+
+             l = len * elt_size;
+             dw2_asm_output_data (1, l, NULL);
+             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;
+             l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
+
+             dw2_asm_output_data (1, 2 * l, NULL);
+             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 (l, first, NULL);
+             dw2_asm_output_data (l, second, NULL);
+           }
+           break;
+         default:
+           gcc_unreachable ();
+         }
+      }
+      break;
+    case DW_OP_GNU_regval_type:
+      {
+       unsigned r = val1->v.val_unsigned;
+       unsigned long o = get_base_type_offset (val2->v.val_die_ref.die);
+       gcc_assert (o);
+       if (for_eh_or_skip >= 0)
+         {
+           r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
+           gcc_assert (size_of_uleb128 (r)
+                       == size_of_uleb128 (val1->v.val_unsigned));
+         }
+       dw2_asm_output_data_uleb128 (r, NULL);
+       dw2_asm_output_data_uleb128 (o, NULL);
+      }
+      break;
+    case DW_OP_GNU_deref_type:
+      {
+       unsigned long o = get_base_type_offset (val2->v.val_die_ref.die);
+       gcc_assert (o);
+       dw2_asm_output_data (1, val1->v.val_int, NULL);
+       dw2_asm_output_data_uleb128 (o, NULL);
+      }
+      break;
+    case DW_OP_GNU_convert:
+    case DW_OP_GNU_reinterpret:
+      {
+       unsigned long o = get_base_type_offset (val1->v.val_die_ref.die);
+       gcc_assert (o);
+       dw2_asm_output_data_uleb128 (o, NULL);
+      }
+      break;
+
     default:
       /* Other codes have no operands.  */
       break;
     }
 }
 
-/* Output a sequence of location operations.  */
+/* Output a sequence of location operations.  
+   The for_eh_or_skip parameter controls whether register numbers are
+   converted using DWARF2_FRAME_REG_OUT, which is needed in the case that
+   hard reg numbers have been processed via DWARF_FRAME_REGNUM (i.e. for unwind
+   info).  This should be suppressed for the cases that have not been converted
+   (i.e. symbolic debug info), by setting the parameter < 0.  See PR47324.  */
 
 static void
-output_loc_sequence (dw_loc_descr_ref loc)
+output_loc_sequence (dw_loc_descr_ref loc, int for_eh_or_skip)
 {
   for (; loc != NULL; loc = loc->dw_loc_next)
     {
+      enum dwarf_location_atom opc = loc->dw_loc_opc;
       /* Output the opcode.  */
-      dw2_asm_output_data (1, loc->dw_loc_opc,
-                          "%s", dwarf_stack_op_name (loc->dw_loc_opc));
+      if (for_eh_or_skip >= 0 
+          && opc >= DW_OP_breg0 && opc <= DW_OP_breg31)
+       {
+         unsigned r = (opc - DW_OP_breg0);
+         r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
+         gcc_assert (r <= 31);
+         opc = (enum dwarf_location_atom) (DW_OP_breg0 + r);
+       }
+      else if (for_eh_or_skip >= 0 
+              && opc >= DW_OP_reg0 && opc <= DW_OP_reg31)
+       {
+         unsigned r = (opc - DW_OP_reg0);
+         r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
+         gcc_assert (r <= 31);
+         opc = (enum dwarf_location_atom) (DW_OP_reg0 + r);
+       }
+
+      dw2_asm_output_data (1, opc,
+                            "%s", dwarf_stack_op_name (opc));
 
       /* Output the operand(s) (if any).  */
-      output_loc_operands (loc);
+      output_loc_operands (loc, for_eh_or_skip);
     }
 }
 
@@ -5245,9 +5565,18 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
       }
       break;
 
+    case DW_OP_regx:
+      {
+       unsigned r = DWARF2_FRAME_REG_OUT (val1->v.val_unsigned, 1);
+       gcc_assert (size_of_uleb128 (r) 
+                   == size_of_uleb128 (val1->v.val_unsigned));
+       fputc (',', asm_out_file);
+       dw2_asm_output_data_uleb128_raw (r);
+      }
+      break;
+      
     case DW_OP_constu:
     case DW_OP_plus_uconst:
-    case DW_OP_regx:
     case DW_OP_piece:
       fputc (',', asm_out_file);
       dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
@@ -5298,10 +5627,25 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
       break;
 
     case DW_OP_bregx:
-      fputc (',', asm_out_file);
-      dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
-      fputc (',', asm_out_file);
-      dw2_asm_output_data_sleb128_raw (val2->v.val_int);
+      {
+       unsigned r = DWARF2_FRAME_REG_OUT (val1->v.val_unsigned, 1);
+       gcc_assert (size_of_uleb128 (r) 
+                   == size_of_uleb128 (val1->v.val_unsigned));
+       fputc (',', asm_out_file);
+       dw2_asm_output_data_uleb128_raw (r);
+       fputc (',', asm_out_file);
+       dw2_asm_output_data_sleb128_raw (val2->v.val_int);
+      }
+      break;
+
+    case DW_OP_GNU_implicit_pointer:
+    case DW_OP_GNU_entry_value:
+    case DW_OP_GNU_const_type:
+    case DW_OP_GNU_regval_type:
+    case DW_OP_GNU_deref_type:
+    case DW_OP_GNU_convert:
+    case DW_OP_GNU_reinterpret:
+      gcc_unreachable ();
       break;
 
     default:
@@ -5315,8 +5659,24 @@ output_loc_sequence_raw (dw_loc_descr_ref loc)
 {
   while (1)
     {
+      enum dwarf_location_atom opc = loc->dw_loc_opc;
+      /* Output the opcode.  */
+      if (opc >= DW_OP_breg0 && opc <= DW_OP_breg31)
+       {
+         unsigned r = (opc - DW_OP_breg0);
+         r = DWARF2_FRAME_REG_OUT (r, 1);
+         gcc_assert (r <= 31);
+         opc = (enum dwarf_location_atom) (DW_OP_breg0 + r);
+       }
+      else if (opc >= DW_OP_reg0 && opc <= DW_OP_reg31)
+       {
+         unsigned r = (opc - DW_OP_reg0);
+         r = DWARF2_FRAME_REG_OUT (r, 1);
+         gcc_assert (r <= 31);
+         opc = (enum dwarf_location_atom) (DW_OP_reg0 + r);
+       }
       /* Output the opcode.  */
-      fprintf (asm_out_file, "%#x", loc->dw_loc_opc);
+      fprintf (asm_out_file, "%#x", opc);
       output_loc_operands_raw (loc);
 
       if (!loc->dw_loc_next)
@@ -5331,14 +5691,16 @@ output_loc_sequence_raw (dw_loc_descr_ref loc)
    description based on a cfi entry with a complex address.  */
 
 static void
-output_cfa_loc (dw_cfi_ref cfi)
+output_cfa_loc (dw_cfi_ref cfi, int for_eh)
 {
   dw_loc_descr_ref loc;
   unsigned long size;
 
   if (cfi->dw_cfi_opc == DW_CFA_expression)
     {
-      dw2_asm_output_data (1, cfi->dw_cfi_oprnd1.dw_cfi_reg_num, NULL);
+      unsigned r = 
+       DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+      dw2_asm_output_data (1, r, NULL);
       loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
     }
   else
@@ -5349,7 +5711,7 @@ output_cfa_loc (dw_cfi_ref cfi)
   dw2_asm_output_data_uleb128 (size, NULL);
 
   /* Now output the operations themselves.  */
-  output_loc_sequence (loc);
+  output_loc_sequence (loc, for_eh);
 }
 
 /* Similar, but used for .cfi_escape.  */
@@ -5362,7 +5724,9 @@ output_cfa_loc_raw (dw_cfi_ref cfi)
 
   if (cfi->dw_cfi_opc == DW_CFA_expression)
     {
-      fprintf (asm_out_file, "%#x,", cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+      unsigned r = 
+       DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
+      fprintf (asm_out_file, "%#x,", r);
       loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
     }
   else
@@ -5560,10 +5924,6 @@ 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);
 
@@ -5606,12 +5966,9 @@ 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 */
+  1,                            /* start_end_main_source_file */
+  TYPE_SYMTAB_IS_DIE            /* tree_type_symtab_field */
 };
 \f
 /* NOTE: In the comments in this file, many references are made to
@@ -5623,6 +5980,16 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
    representation is done after the entire program has been compiled.
    The types below are used to describe the internal representation.  */
 
+/* Whether to put type DIEs into their own section .debug_types instead
+   of making them part of the .debug_info section.  Only supported for
+   Dwarf V4 or higher and the user didn't disable them through
+   -fno-debug-types-section.  It is more efficient to put them in a
+   separate comdat sections since the linker will then be able to
+   remove duplicates.  But not all tools support .debug_types sections
+   yet.  */
+
+#define use_debug_types (dwarf_version >= 4 && flag_debug_types_section)
+
 /* Various DIE's use offsets relative to the beginning of the
    .debug_info section to refer to each other.  */
 
@@ -5632,31 +5999,70 @@ typedef long int dw_offset;
 
 typedef struct dw_attr_struct *dw_attr_ref;
 typedef struct dw_line_info_struct *dw_line_info_ref;
-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
-   entry.  The label gives the PC value associated with
-   the line number entry.  */
+/* The entries in the line_info table more-or-less mirror the opcodes
+   that are used in the real dwarf line table.  Arrays of these entries
+   are collected per section when DWARF2_ASM_LINE_DEBUG_INFO is not
+   supported.  */
+
+enum dw_line_info_opcode {
+  /* Emit DW_LNE_set_address; the operand is the label index.  */
+  LI_set_address,
+
+  /* Emit a row to the matrix with the given line.  This may be done
+     via any combination of DW_LNS_copy, DW_LNS_advance_line, and
+     special opcodes.  */
+  LI_set_line,
+
+  /* Emit a DW_LNS_set_file.  */
+  LI_set_file,
+
+  /* Emit a DW_LNS_set_column.  */
+  LI_set_column,
+
+  /* Emit a DW_LNS_negate_stmt; the operand is ignored.  */
+  LI_negate_stmt,
+
+  /* Emit a DW_LNS_set_prologue_end/epilogue_begin; the operand is ignored.  */
+  LI_set_prologue_end,
+  LI_set_epilogue_begin,
+
+  /* Emit a DW_LNE_set_discriminator.  */
+  LI_set_discriminator
+};
 
 typedef struct GTY(()) dw_line_info_struct {
-  unsigned long dw_file_num;
-  unsigned long dw_line_num;
-}
-dw_line_info_entry;
+  enum dw_line_info_opcode opcode;
+  unsigned int val;
+} dw_line_info_entry;
 
-/* Line information for functions in separate sections; each one gets its
-   own sequence.  */
-typedef struct GTY(()) dw_separate_line_info_struct {
-  unsigned long dw_file_num;
-  unsigned long dw_line_num;
-  unsigned long function;
-}
-dw_separate_line_info_entry;
+DEF_VEC_O(dw_line_info_entry);
+DEF_VEC_ALLOC_O(dw_line_info_entry, gc);
+
+typedef struct GTY(()) dw_line_info_table_struct {
+  /* The label that marks the end of this section.  */
+  const char *end_label;
+
+  /* The values for the last row of the matrix, as collected in the table.
+     These are used to minimize the changes to the next row.  */
+  unsigned int file_num;
+  unsigned int line_num;
+  unsigned int column_num;
+  int discrim_num;
+  bool is_stmt;
+  bool in_use;
+
+  VEC(dw_line_info_entry, gc) *entries;
+} dw_line_info_table;
+
+typedef dw_line_info_table *dw_line_info_table_p;
+
+DEF_VEC_P(dw_line_info_table_p);
+DEF_VEC_ALLOC_P(dw_line_info_table_p, gc);
 
 /* Each DIE attribute has a field specifying the attribute kind,
    a link to the next attribute in the chain, and an attribute value.
@@ -5681,7 +6087,7 @@ typedef struct GTY((chain_circular ("%h.die_sib"))) die_struct {
       char * GTY ((tag ("0"))) die_symbol;
       comdat_type_node_ref GTY ((tag ("1"))) die_type_node;
     }
-  GTY ((desc ("dwarf_version >= 4"))) die_id;
+  GTY ((desc ("use_debug_types"))) die_id;
   VEC(dw_attr_node,gc) * die_attr;
   dw_die_ref die_parent;
   dw_die_ref die_child;
@@ -5723,6 +6129,18 @@ struct GTY(()) dw_ranges_struct {
   int num;
 };
 
+/* A structure to hold a macinfo entry.  */
+
+typedef struct GTY(()) macinfo_struct {
+  unsigned HOST_WIDE_INT code;
+  unsigned HOST_WIDE_INT lineno;
+  const char *info;
+}
+macinfo_entry;
+
+DEF_VEC_O(macinfo_entry);
+DEF_VEC_ALLOC_O(macinfo_entry, gc);
+
 struct GTY(()) dw_ranges_by_label_struct {
   const char *begin;
   const char *end;
@@ -5746,7 +6164,7 @@ typedef struct GTY(()) limbo_die_struct {
 }
 limbo_die_node;
 
-typedef struct GTY(()) skeleton_chain_struct
+typedef struct skeleton_chain_struct
 {
   dw_die_ref old_die;
   dw_die_ref new_die;
@@ -5822,7 +6240,7 @@ skeleton_chain_node;
 #define DWARF_LINE_BASE  -10
 
 /* First special line opcode - leave room for the standard opcodes.  */
-#define DWARF_LINE_OPCODE_BASE  10
+#define DWARF_LINE_OPCODE_BASE  ((int)DW_LNS_set_isa + 1)
 
 /* Range of line offsets in a special line info. opcode.  */
 #define DWARF_LINE_RANGE  (254-DWARF_LINE_OPCODE_BASE+1)
@@ -5843,7 +6261,7 @@ skeleton_chain_node;
 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;
+static GTY(()) dw_die_ref single_comp_unit_die;
 
 /* A list of type DIEs that have been separated into comdat sections.  */
 static GTY(()) comdat_type_node *comdat_type_list;
@@ -5901,15 +6319,56 @@ struct GTY (()) var_loc_list_def {
      Do not mark it for GC because it is marked through the chain.  */
   struct var_loc_node * GTY ((skip ("%h"))) last;
 
+  /* Pointer to the last element before section switch,
+     if NULL, either sections weren't switched or first
+     is after section switch.  */
+  struct var_loc_node * GTY ((skip ("%h"))) last_before_switch;
+
   /* DECL_UID of the variable decl.  */
   unsigned int decl_id;
 };
 typedef struct var_loc_list_def var_loc_list;
 
+/* Call argument location list.  */
+struct GTY ((chain_next ("%h.next"))) call_arg_loc_node {
+  rtx GTY (()) call_arg_loc_note;
+  const char * GTY (()) label;
+  tree GTY (()) block;
+  bool tail_call_p;
+  rtx GTY (()) symbol_ref;
+  struct call_arg_loc_node * GTY (()) next;
+};
+
 
 /* Table of decl location linked lists.  */
 static GTY ((param_is (var_loc_list))) htab_t decl_loc_table;
 
+/* Head and tail of call_arg_loc chain.  */
+static GTY (()) struct call_arg_loc_node *call_arg_locations;
+static struct call_arg_loc_node *call_arg_loc_last;
+
+/* Number of call sites in the current function.  */
+static int call_site_count = -1;
+/* Number of tail call sites in the current function.  */
+static int tail_call_site_count = -1;
+
+/* Vector mapping block numbers to DW_TAG_{lexical_block,inlined_subroutine}
+   DIEs.  */
+static VEC (dw_die_ref, heap) *block_map;
+
+/* A cached location list.  */
+struct GTY (()) cached_dw_loc_list_def {
+  /* The DECL_UID of the decl that this entry describes.  */
+  unsigned int decl_id;
+
+  /* The cached location list.  */
+  dw_loc_list_ref loc_list;
+};
+typedef struct cached_dw_loc_list_def cached_dw_loc_list;
+
+/* Table of cached location lists.  */
+static GTY ((param_is (cached_dw_loc_list))) htab_t cached_dw_loc_list_table;
+
 /* A pointer to the base of a list of references to DIE's that
    are uniquely identified by their tag, presence/absence of
    children DIE's, and list of attribute/value pairs.  */
@@ -5926,31 +6385,24 @@ static GTY(()) unsigned abbrev_die_table_in_use;
    abbrev_die_table.  */
 #define ABBREV_DIE_TABLE_INCREMENT 256
 
-/* A pointer to the base of a table that contains line information
-   for each source code line in .text in the compilation unit.  */
-static GTY((length ("line_info_table_allocated")))
-     dw_line_info_ref line_info_table;
+/* A global counter for generating labels for line number data.  */
+static unsigned int line_info_label_num;
 
-/* Number of elements currently allocated for line_info_table.  */
-static GTY(()) unsigned line_info_table_allocated;
+/* The current table to which we should emit line number information
+   for the current function.  This will be set up at the beginning of
+   assembly for the function.  */
+static dw_line_info_table *cur_line_info_table;
 
-/* Number of elements in line_info_table currently in use.  */
-static GTY(()) unsigned line_info_table_in_use;
+/* The two default tables of line number info.  */
+static GTY(()) dw_line_info_table *text_section_line_info;
+static GTY(()) dw_line_info_table *cold_text_section_line_info;
 
-/* A pointer to the base of a table that contains line information
-   for each source code line outside of .text in the compilation unit.  */
-static GTY ((length ("separate_line_info_table_allocated")))
-     dw_separate_line_info_ref separate_line_info_table;
+/* The set of all non-default tables of line number info.  */
+static GTY(()) VEC (dw_line_info_table_p, gc) *separate_line_info;
 
-/* Number of elements currently allocated for separate_line_info_table.  */
-static GTY(()) unsigned separate_line_info_table_allocated;
-
-/* Number of elements in separate_line_info_table currently in use.  */
-static GTY(()) unsigned separate_line_info_table_in_use;
-
-/* Size (in elements) of increments by which we may expand the
-   line_info_table.  */
-#define LINE_INFO_TABLE_INCREMENT 1024
+/* A flag to tell pubnames/types export if there is an info section to
+   refer to.  */
+static bool info_section_emitted;
 
 /* A pointer to the base of a table that contains a list of publicly
    accessible names.  */
@@ -5960,18 +6412,9 @@ static GTY (()) VEC (pubname_entry, gc) *  pubname_table;
    accessible types.  */
 static GTY (()) VEC (pubname_entry, gc) * pubtype_table;
 
-/* Array of dies for which we should generate .debug_arange info.  */
-static GTY((length ("arange_table_allocated"))) dw_die_ref *arange_table;
-
-/* Number of elements currently allocated for arange_table.  */
-static GTY(()) unsigned arange_table_allocated;
-
-/* Number of elements in arange_table currently in use.  */
-static GTY(()) unsigned arange_table_in_use;
-
-/* Size (in elements) of increments by which we may expand the
-   arange_table.  */
-#define ARANGE_TABLE_INCREMENT 64
+/* A pointer to the base of a table that contains a list of macro
+   defines/undefines (and file start/end markers).  */
+static GTY (()) VEC (macinfo_entry, gc) * macinfo_table;
 
 /* Array of dies for which we should generate .debug_ranges info.  */
 static GTY ((length ("ranges_table_allocated"))) dw_ranges_ref ranges_table;
@@ -6005,47 +6448,8 @@ 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;
-
 /* Record whether the function being analyzed contains inlined functions.  */
 static int current_function_has_inlines;
-#if 0 && defined (MIPS_DEBUGGING_INFO)
-static int comp_unit_has_inlines;
-#endif
 
 /* The last file entry emitted by maybe_emit_file().  */
 static GTY(()) struct dwarf_file_data * last_emitted_file;
@@ -6058,10 +6462,18 @@ static GTY(()) struct dwarf_file_data * file_table_last_lookup;
 
 static GTY(()) VEC(die_arg_entry,gc) *tmpl_value_parm_die_table;
 
+/* Instances of generic types for which we need to generate debug
+   info that describe their generic parameters and arguments. That
+   generation needs to happen once all types are properly laid out so
+   we do it at the end of compilation.  */
+static GTY(()) VEC(tree,gc) *generic_type_instances;
+
 /* Offset from the "steady-state frame pointer" to the frame base,
    within the current function.  */
 static HOST_WIDE_INT frame_pointer_fb_offset;
 
+static VEC (dw_die_ref, heap) *base_types;
+
 /* Forward declarations for functions defined in this file.  */
 
 static int is_pseudo_reg (const_rtx);
@@ -6126,6 +6538,8 @@ static void remove_child_TAG (dw_die_ref, enum dwarf_tag);
 static void add_child_die (dw_die_ref, dw_die_ref);
 static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree);
 static dw_die_ref lookup_type_die (tree);
+static dw_die_ref strip_naming_typedef (tree, dw_die_ref);
+static dw_die_ref lookup_type_die_strip_naming_typedef (tree);
 static void equate_type_number_to_die (tree, dw_die_ref);
 static hashval_t decl_die_table_hash (const void *);
 static int decl_die_table_eq (const void *, const void *);
@@ -6139,7 +6553,6 @@ static void equate_decl_number_to_die (tree, dw_die_ref);
 static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *);
 static void print_spaces (FILE *);
 static void print_die (dw_die_ref, FILE *);
-static void print_dwarf_line_table (FILE *);
 static dw_die_ref push_new_compile_unit (dw_die_ref, dw_die_ref);
 static dw_die_ref pop_compile_unit (dw_die_ref);
 static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
@@ -6193,6 +6606,7 @@ static void output_location_lists (dw_die_ref);
 static int constant_size (unsigned HOST_WIDE_INT);
 static unsigned long size_of_die (dw_die_ref);
 static void calc_die_sizes (dw_die_ref);
+static void calc_base_type_die_sizes (void);
 static void mark_dies (dw_die_ref);
 static void unmark_dies (dw_die_ref);
 static void unmark_all_dies (dw_die_ref);
@@ -6211,13 +6625,13 @@ static void add_pubname (tree, dw_die_ref);
 static void add_pubname_string (const char *, dw_die_ref);
 static void add_pubtype (tree, dw_die_ref);
 static void output_pubnames (VEC (pubname_entry,gc) *);
-static void add_arange (tree, dw_die_ref);
-static void output_aranges (void);
+static void output_aranges (unsigned long);
 static unsigned int add_ranges_num (int);
 static unsigned int add_ranges (const_tree);
 static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
                                  bool *);
 static void output_ranges (void);
+static dw_line_info_table *new_line_info_table (void);
 static void output_line_info (void);
 static void output_file_names (void);
 static dw_die_ref base_type_die (tree);
@@ -6258,11 +6672,12 @@ static void insert_int (HOST_WIDE_INT, unsigned, unsigned char *);
 static void insert_double (double_int, unsigned char *);
 static void insert_float (const_rtx, unsigned char *);
 static rtx rtl_for_decl_location (tree);
-static bool add_location_or_const_value_attribute (dw_die_ref, tree,
+static bool add_location_or_const_value_attribute (dw_die_ref, tree, bool,
                                                   enum dwarf_attribute);
 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_gnat_descriptive_type_attribute (dw_die_ref, tree, dw_die_ref);
 static void add_comp_dir_attribute (dw_die_ref);
 static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree);
 static void add_subscript_info (dw_die_ref, tree, bool);
@@ -6315,7 +6730,7 @@ static void gen_typedef_die (tree, dw_die_ref);
 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 int is_redundant_typedef (const_tree);
 static bool is_naming_typedef_decl (const_tree);
 static inline dw_die_ref get_context_die (tree);
 static void gen_namespace_die (tree, dw_die_ref);
@@ -6338,6 +6753,7 @@ static void output_loc_list (dw_loc_list_ref);
 static char *gen_internal_sym (const char *);
 
 static void prune_unmark_dies (dw_die_ref);
+static void prune_unused_types_mark_generic_parms_dies (dw_die_ref);
 static void prune_unused_types_mark (dw_die_ref, int);
 static void prune_unused_types_walk (dw_die_ref);
 static void prune_unused_types_walk_attribs (dw_die_ref);
@@ -6350,6 +6766,9 @@ static inline void add_AT_vms_delta (dw_die_ref, enum dwarf_attribute,
                                     const char *, const char *);
 static void append_entry_to_tmpl_value_parm_die_table (dw_die_ref, tree);
 static void gen_remaining_tmpl_value_param_die_attribute (void);
+static bool generic_type_p (tree);
+static void schedule_generic_params_dies_gen (tree t);
+static void gen_scheduled_generic_parms_dies (void);
 
 /* Section names used to hold DWARF debugging information.  */
 #ifndef DEBUG_INFO_SECTION
@@ -6376,12 +6795,6 @@ static void gen_remaining_tmpl_value_param_die_attribute (void);
 #ifndef DEBUG_PUBTYPES_SECTION
 #define DEBUG_PUBTYPES_SECTION ".debug_pubtypes"
 #endif
-#ifndef DEBUG_DCALL_SECTION
-#define DEBUG_DCALL_SECTION    ".debug_dcall"
-#endif
-#ifndef DEBUG_VCALL_SECTION
-#define DEBUG_VCALL_SECTION    ".debug_vcall"
-#endif
 #ifndef DEBUG_STR_SECTION
 #define DEBUG_STR_SECTION      ".debug_str"
 #endif
@@ -6461,11 +6874,17 @@ static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
 #ifndef LINE_CODE_LABEL
 #define LINE_CODE_LABEL                "LM"
 #endif
-#ifndef SEPARATE_LINE_CODE_LABEL
-#define SEPARATE_LINE_CODE_LABEL       "LSM"
-#endif
 
 \f
+/* Return the root of the DIE's built for the current compilation unit.  */
+static dw_die_ref
+comp_unit_die (void)
+{
+  if (!single_comp_unit_die)
+    single_comp_unit_die = gen_compile_unit_die (NULL);
+  return single_comp_unit_die;
+}
+
 /* We allow a language front-end to designate a function that is to be
    called to "demangle" any name before it is put into a DIE.  */
 
@@ -6518,6 +6937,29 @@ is_tagged_type (const_tree type)
          || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
 }
 
+/* Set label to debug_info_section_label + die_offset of a DIE reference.  */
+
+static void
+get_ref_die_offset_label (char *label, dw_die_ref ref)
+{
+  sprintf (label, "%s+%ld", debug_info_section_label, ref->die_offset);
+}
+
+/* Return die_offset of a DIE reference to a base type.  */
+
+static unsigned long int
+get_base_type_offset (dw_die_ref ref)
+{
+  if (ref->die_offset)
+    return ref->die_offset;
+  if (comp_unit_die ()->die_abbrev)
+    {
+      calc_base_type_die_sizes ();
+      gcc_assert (ref->die_offset);
+    }
+  return ref->die_offset;
+}
+
 /* Convert a DIE tag into its string name.  */
 
 static const char *
@@ -6665,6 +7107,10 @@ dwarf_tag_name (unsigned int tag)
       return "DW_TAG_GNU_EINCL";
     case DW_TAG_GNU_template_template_param:
       return "DW_TAG_GNU_template_template_param";
+    case DW_TAG_GNU_call_site:
+      return "DW_TAG_GNU_call_site";
+    case DW_TAG_GNU_call_site_parameter:
+      return "DW_TAG_GNU_call_site_parameter";
     default:
       return "DW_TAG_<unknown>";
     }
@@ -6889,6 +7335,7 @@ dwarf_attr_name (unsigned int attr)
       return "DW_AT_body_begin";
     case DW_AT_body_end:
       return "DW_AT_body_end";
+
     case DW_AT_GNU_vector:
       return "DW_AT_GNU_vector";
     case DW_AT_GNU_guarded_by:
@@ -6909,6 +7356,25 @@ dwarf_attr_name (unsigned int attr)
       return "DW_AT_GNU_odr_signature";
     case DW_AT_GNU_template_name:
       return "DW_AT_GNU_template_name";
+    case DW_AT_GNU_call_site_value:
+      return "DW_AT_GNU_call_site_value";
+    case DW_AT_GNU_call_site_data_value:
+      return "DW_AT_GNU_call_site_data_value";
+    case DW_AT_GNU_call_site_target:
+      return "DW_AT_GNU_call_site_target";
+    case DW_AT_GNU_call_site_target_clobbered:
+      return "DW_AT_GNU_call_site_target_clobbered";
+    case DW_AT_GNU_tail_call:
+      return "DW_AT_GNU_tail_call";
+    case DW_AT_GNU_all_tail_call_sites:
+      return "DW_AT_GNU_all_tail_call_sites";
+    case DW_AT_GNU_all_call_sites:
+      return "DW_AT_GNU_all_call_sites";
+    case DW_AT_GNU_all_source_call_sites:
+      return "DW_AT_GNU_all_source_call_sites";
+
+    case DW_AT_GNAT_descriptive_type:
+      return "DW_AT_GNAT_descriptive_type";
 
     case DW_AT_VMS_rtnbeg_pd_address:
       return "DW_AT_VMS_rtnbeg_pd_address";
@@ -7210,37 +7676,6 @@ 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)
 {
@@ -7256,6 +7691,7 @@ 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);
 
@@ -7278,7 +7714,9 @@ AT_string_form (dw_attr_ref a)
       && (len - DWARF_OFFSET_SIZE) * node->refcount <= len))
     return node->form = DW_FORM_string;
 
-  gen_label_for_indirect_string (node);
+  ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+  ++dw2_string_counter;
+  node->label = xstrdup (label);
 
   return node->form = DW_FORM_strp;
 }
@@ -7290,6 +7728,15 @@ add_AT_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind, dw_die_ref targ_
 {
   dw_attr_node attr;
 
+#ifdef ENABLE_CHECKING
+  gcc_assert (targ_die != NULL);
+#else
+  /* With LTO we can end up trying to reference something we didn't create
+     a DIE for.  Avoid crashing later on a NULL referenced DIE.  */
+  if (targ_die == NULL)
+    return;
+#endif
+
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_die_ref;
   attr.dw_attr_val.v.val_die_ref.die = targ_die;
@@ -7560,7 +8007,7 @@ get_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
   if (! die)
     return NULL;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     if (a->dw_attr == attr_kind)
       return a;
     else if (a->dw_attr == DW_AT_specification
@@ -7651,7 +8098,7 @@ get_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind)
 static inline bool
 is_cxx (void)
 {
-  unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+  unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
 
   return lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus;
 }
@@ -7661,7 +8108,7 @@ is_cxx (void)
 static inline bool
 is_fortran (void)
 {
-  unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+  unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
 
   return (lang == DW_LANG_Fortran77
          || lang == DW_LANG_Fortran90
@@ -7673,7 +8120,7 @@ is_fortran (void)
 static inline bool
 is_ada (void)
 {
-  unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+  unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
 
   return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
 }
@@ -7689,7 +8136,7 @@ remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
   if (! die)
     return;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     if (a->dw_attr == attr_kind)
       {
        if (AT_class (a) == dw_val_class_str)
@@ -7869,6 +8316,39 @@ lookup_type_die (tree type)
   return TYPE_SYMTAB_DIE (type);
 }
 
+/* Given a TYPE_DIE representing the type TYPE, if TYPE is an
+   anonymous type named by the typedef TYPE_DIE, return the DIE of the
+   anonymous type instead the one of the naming typedef.  */
+
+static inline dw_die_ref
+strip_naming_typedef (tree type, dw_die_ref type_die)
+{
+  if (type
+      && TREE_CODE (type) == RECORD_TYPE
+      && type_die
+      && type_die->die_tag == DW_TAG_typedef
+      && is_naming_typedef_decl (TYPE_NAME (type)))
+    type_die = get_AT_ref (type_die, DW_AT_type);
+  return type_die;
+}
+
+/* Like lookup_type_die, but if type is an anonymous type named by a
+   typedef[1], return the DIE of the anonymous type instead the one of
+   the naming typedef.  This is because in gen_typedef_die, we did
+   equate the anonymous struct named by the typedef with the DIE of
+   the naming typedef. So by default, lookup_type_die on an anonymous
+   struct yields the DIE of the naming typedef.
+
+   [1]: Read the comment of is_naming_typedef_decl to learn about what
+   a naming typedef is.  */
+
+static inline dw_die_ref
+lookup_type_die_strip_naming_typedef (tree type)
+{
+  dw_die_ref die = lookup_type_die (type);
+  return strip_naming_typedef (type, die);
+}
+
 /* Equate a DIE to a given type specifier.  */
 
 static inline void
@@ -7929,6 +8409,24 @@ lookup_decl_loc (const_tree decl)
     htab_find_with_hash (decl_loc_table, decl, DECL_UID (decl));
 }
 
+/* Returns a hash value for X (which really is a cached_dw_loc_list_list).  */
+
+static hashval_t
+cached_dw_loc_list_table_hash (const void *x)
+{
+  return (hashval_t) ((const cached_dw_loc_list *) x)->decl_id;
+}
+
+/* Return nonzero if decl_id of cached_dw_loc_list X is the same as
+   UID of decl *Y.  */
+
+static int
+cached_dw_loc_list_table_eq (const void *x, const void *y)
+{
+  return (((const cached_dw_loc_list *) x)->decl_id
+         == DECL_UID ((const_tree) y));
+}
+
 /* Equate a DIE to a particular declaration.  */
 
 static void
@@ -8264,12 +8762,15 @@ print_die (dw_die_ref die, FILE *outfile)
   unsigned ix;
 
   print_spaces (outfile);
-  fprintf (outfile, "DIE %4ld: %s\n",
-          die->die_offset, dwarf_tag_name (die->die_tag));
+  fprintf (outfile, "DIE %4ld: %s (%p)\n",
+          die->die_offset, dwarf_tag_name (die->die_tag),
+          (void*) die);
   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)
+  fprintf (outfile, " offset: %ld", die->die_offset);
+  fprintf (outfile, " mark: %d\n", die->die_mark);
+
+  if (use_debug_types && die->die_id.die_type_node)
     {
       print_spaces (outfile);
       fprintf (outfile, "  signature: ");
@@ -8277,7 +8778,7 @@ print_die (dw_die_ref die, FILE *outfile)
       fprintf (outfile, "\n");
     }
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     {
       print_spaces (outfile);
       fprintf (outfile, "  %s: ", dwarf_attr_name (a->dw_attr));
@@ -8321,17 +8822,18 @@ print_die (dw_die_ref die, FILE *outfile)
        case dw_val_class_die_ref:
          if (AT_ref (a) != NULL)
            {
-             if (dwarf_version >= 4 && AT_ref (a)->die_id.die_type_node)
+             if (use_debug_types && 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)
+             else if (! use_debug_types && 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);
+             fprintf (outfile, " (%p)", (void *) AT_ref (a));
            }
          else
            fprintf (outfile, "die -> <null>");
@@ -8380,27 +8882,6 @@ print_die (dw_die_ref die, FILE *outfile)
     fprintf (outfile, "\n");
 }
 
-/* Print the contents of the source code line number correspondence table.
-   This routine is a debugging aid only.  */
-
-static void
-print_dwarf_line_table (FILE *outfile)
-{
-  unsigned i;
-  dw_line_info_ref line_info;
-
-  fprintf (outfile, "\n\nDWARF source line information\n");
-  for (i = 1; i < line_info_table_in_use; i++)
-    {
-      line_info = &line_info_table[i];
-      fprintf (outfile, "%5d: %4ld %6ld\n", i,
-              line_info->dw_file_num,
-              line_info->dw_line_num);
-    }
-
-  fprintf (outfile, "\n\n");
-}
-
 /* Print the information collected for a given DIE.  */
 
 DEBUG_FUNCTION void
@@ -8416,9 +8897,7 @@ DEBUG_FUNCTION void
 debug_dwarf (void)
 {
   print_indent = 0;
-  print_die (comp_unit_die, stderr);
-  if (! DWARF2_ASM_LINE_DEBUG_INFO)
-    print_dwarf_line_table (stderr);
+  print_die (comp_unit_die (), stderr);
 }
 \f
 /* Start a new compilation unit DIE for an include file.  OLD_UNIT is the CU
@@ -8556,7 +9035,7 @@ die_checksum (dw_die_ref die, struct md5_ctx *ctx, int *mark)
 
   CHECKSUM (die->die_tag);
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     attr_checksum (a, ctx, mark);
 
   FOR_EACH_CHILD (die, c, die_checksum (c, ctx, mark));
@@ -8869,7 +9348,7 @@ collect_checksum_attributes (struct checksum_attributes *attrs, dw_die_ref die)
   dw_attr_ref a;
   unsigned ix;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     {
       switch (a->dw_attr)
         {
@@ -9303,7 +9782,7 @@ same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
       != VEC_length (dw_attr_node, die2->die_attr))
     return 0;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die1->die_attr, ix, a1)
     if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark))
       return 0;
 
@@ -9466,6 +9945,14 @@ is_symbol_die (dw_die_ref c)
          || c->die_tag == DW_TAG_module);
 }
 
+/* Returns true iff C is a compile-unit DIE.  */
+
+static inline bool
+is_cu_die (dw_die_ref c)
+{
+  return c && c->die_tag == DW_TAG_compile_unit;
+}
+
 static char *
 gen_internal_sym (const char *prefix)
 {
@@ -9664,7 +10151,7 @@ is_declaration_die (dw_die_ref die)
   dw_attr_ref a;
   unsigned ix;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     if (a->dw_attr == DW_AT_declaration)
       return 1;
 
@@ -9683,6 +10170,20 @@ is_nested_in_subprogram (dw_die_ref die)
   return local_scope_p (decl);
 }
 
+/* Return non-zero if this DIE contains a defining declaration of a
+   subprogram.  */
+
+static int
+contains_subprogram_definition (dw_die_ref die)
+{
+  dw_die_ref c;
+
+  if (die->die_tag == DW_TAG_subprogram && ! is_declaration_die (die))
+    return 1;
+  FOR_EACH_CHILD (die, c, if (contains_subprogram_definition(c)) return 1);
+  return 0;
+}
+
 /* Return non-zero if this is a type DIE that should be moved to a
    COMDAT .debug_types section.  */
 
@@ -9701,6 +10202,8 @@ should_move_die_to_comdat (dw_die_ref die)
           || get_AT (die, DW_AT_abstract_origin)
           || is_nested_in_subprogram (die))
         return 0;
+      /* A type definition should never contain a subprogram definition.  */
+      gcc_assert (!contains_subprogram_definition (die));
       return 1;
     case DW_TAG_array_type:
     case DW_TAG_interface_type:
@@ -9735,7 +10238,7 @@ clone_die (dw_die_ref die)
   clone = ggc_alloc_cleared_die_node ();
   clone->die_tag = die->die_tag;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     add_dwarf_attr (clone, a);
 
   return clone;
@@ -9776,7 +10279,7 @@ clone_as_declaration (dw_die_ref die)
   clone = ggc_alloc_cleared_die_node ();
   clone->die_tag = die->die_tag;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     {
       /* We don't want to copy over all attributes.
          For example we don't want DW_AT_byte_size because otherwise we will no
@@ -9833,7 +10336,7 @@ copy_declaration_context (dw_die_ref unit, dw_die_ref die)
 
       remove_AT (die, DW_AT_specification);
 
-      for (ix = 0; VEC_iterate (dw_attr_node, decl->die_attr, ix, a); ix++)
+      FOR_EACH_VEC_ELT (dw_attr_node, decl->die_attr, ix, a)
         {
           if (a->dw_attr != DW_AT_name
               && a->dw_attr != DW_AT_declaration
@@ -9991,7 +10494,7 @@ break_out_comdat_types (dw_die_ref die)
            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));
+                         get_AT_unsigned (comp_unit_die (), DW_AT_language));
         type_node = ggc_alloc_cleared_comdat_type_node ();
         type_node->root_die = unit;
         type_node->next = comdat_type_list;
@@ -10129,7 +10632,7 @@ copy_decls_walk (dw_die_ref unit, dw_die_ref die, htab_t decl_table)
   dw_attr_ref a;
   unsigned ix;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     {
       if (AT_class (a) == dw_val_class_die_ref)
         {
@@ -10248,7 +10751,7 @@ output_location_lists (dw_die_ref die)
   dw_attr_ref a;
   unsigned ix;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     if (AT_class (a) == dw_val_class_loc_list)
       output_loc_list (AT_loc_list (a));
 
@@ -10271,11 +10774,11 @@ build_abbrev_table (dw_die_ref die)
 
   /* 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++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     if (AT_class (a) == dw_val_class_die_ref
        && AT_ref (a)->die_mark == 0)
       {
-       gcc_assert (dwarf_version >= 4 || AT_ref (a)->die_id.die_symbol);
+       gcc_assert (use_debug_types || AT_ref (a)->die_id.die_symbol);
        set_AT_ref_external (a, 1);
       }
 
@@ -10295,7 +10798,7 @@ build_abbrev_table (dw_die_ref die)
          != VEC_length (dw_attr_node, die->die_attr))
        continue;
 
-      for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, die_a); ix++)
+      FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, die_a)
        {
          abbrev_a = VEC_index (dw_attr_node, abbrev->die_attr, ix);
          if ((abbrev_a->dw_attr != die_a->dw_attr)
@@ -10359,7 +10862,7 @@ size_of_die (dw_die_ref die)
   unsigned ix;
 
   size += size_of_uleb128 (die->die_abbrev);
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     {
       switch (AT_class (a))
        {
@@ -10419,11 +10922,11 @@ size_of_die (dw_die_ref die)
        case dw_val_class_die_ref:
          if (AT_ref_external (a))
            {
-             /* In DWARF4, we use DW_FORM_sig8; for earlier versions
+             /* In DWARF4, we use DW_FORM_ref_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)
+             if (use_debug_types)
                size += DWARF_TYPE_SIGNATURE_SIZE;
              else if (dwarf_version == 2)
                size += DWARF2_ADDR_SIZE;
@@ -10476,6 +10979,8 @@ calc_die_sizes (dw_die_ref die)
 {
   dw_die_ref c;
 
+  gcc_assert (die->die_offset == 0
+             || (unsigned long int) die->die_offset == next_die_offset);
   die->die_offset = next_die_offset;
   next_die_offset += size_of_die (die);
 
@@ -10486,17 +10991,47 @@ calc_die_sizes (dw_die_ref die)
     next_die_offset += 1;
 }
 
-/* Set the marks for a die and its children.  We do this so
-   that we know whether or not a reference needs to use FORM_ref_addr; only
-   DIEs in the same CU will be marked.  We used to clear out the offset
-   and use that as the flag, but ran into ordering problems.  */
+/* Size just the base type children at the start of the CU.
+   This is needed because build_abbrev needs to size locs
+   and sizing of type based stack ops needs to know die_offset
+   values for the base types.  */
 
 static void
-mark_dies (dw_die_ref die)
+calc_base_type_die_sizes (void)
 {
-  dw_die_ref c;
-
-  gcc_assert (!die->die_mark);
+  unsigned long die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
+  unsigned int i;
+  dw_die_ref base_type;
+#if ENABLE_ASSERT_CHECKING
+  dw_die_ref prev = comp_unit_die ()->die_child;
+#endif
+
+  die_offset += size_of_die (comp_unit_die ());
+  for (i = 0; VEC_iterate (dw_die_ref, base_types, i, base_type); i++)
+    {
+#if ENABLE_ASSERT_CHECKING
+      gcc_assert (base_type->die_offset == 0
+                 && prev->die_sib == base_type
+                 && base_type->die_child == NULL
+                 && base_type->die_abbrev);
+      prev = base_type;
+#endif
+      base_type->die_offset = die_offset;
+      die_offset += size_of_die (base_type);
+    }
+}
+
+/* Set the marks for a die and its children.  We do this so
+   that we know whether or not a reference needs to use FORM_ref_addr; only
+   DIEs in the same CU will be marked.  We used to clear out the offset
+   and use that as the flag, but ran into ordering problems.  */
+
+static void
+mark_dies (dw_die_ref die)
+{
+  dw_die_ref c;
+
+  gcc_assert (!die->die_mark);
 
   die->die_mark = 1;
   FOR_EACH_CHILD (die, c, mark_dies (c));
@@ -10509,7 +11044,7 @@ unmark_dies (dw_die_ref die)
 {
   dw_die_ref c;
 
-  if (dwarf_version < 4)
+  if (! use_debug_types)
     gcc_assert (die->die_mark);
 
   die->die_mark = 0;
@@ -10531,7 +11066,7 @@ unmark_all_dies (dw_die_ref die)
 
   FOR_EACH_CHILD (die, c, unmark_all_dies (c));
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     if (AT_class (a) == dw_val_class_die_ref)
       unmark_all_dies (AT_ref (a));
 }
@@ -10547,7 +11082,7 @@ size_of_pubnames (VEC (pubname_entry, gc) * names)
   pubname_ref p;
 
   size = DWARF_PUBNAMES_HEADER_SIZE;
-  for (i = 0; VEC_iterate (pubname_entry, names, i, p); i++)
+  FOR_EACH_VEC_ELT (pubname_entry, names, i, p)
     if (names != pubtype_table
        || p->die->die_offset != 0
        || !flag_eliminate_unused_debug_types)
@@ -10571,7 +11106,20 @@ size_of_aranges (void)
     size += 2 * DWARF2_ADDR_SIZE;
   if (cold_text_section_used)
     size += 2 * DWARF2_ADDR_SIZE;
-  size += 2 * DWARF2_ADDR_SIZE * arange_table_in_use;
+  if (have_multiple_function_sections)
+    {
+      unsigned fde_idx = 0;
+
+      for (fde_idx = 0; fde_idx < fde_table_in_use; fde_idx++)
+       {
+         dw_fde_ref fde = &fde_table[fde_idx];
+
+         if (!fde->in_std_section)
+           size += 2 * DWARF2_ADDR_SIZE;
+         if (fde->dw_fde_second_begin && !fde->second_in_std_section)
+           size += 2 * DWARF2_ADDR_SIZE;
+       }
+    }
 
   /* Count the two zero words used to terminated the address range table.  */
   size += 2 * DWARF2_ADDR_SIZE;
@@ -10695,7 +11243,7 @@ value_format (dw_attr_ref a)
       return DW_FORM_flag;
     case dw_val_class_die_ref:
       if (AT_ref_external (a))
-       return dwarf_version >= 4 ? DW_FORM_sig8 : DW_FORM_ref_addr;
+       return use_debug_types ? DW_FORM_ref_sig8 : DW_FORM_ref_addr;
       else
        return DW_FORM_ref;
     case dw_val_class_fde_ref:
@@ -10746,6 +11294,9 @@ output_abbrev_section (void)
 {
   unsigned long abbrev_id;
 
+  if (abbrev_die_table_in_use == 1)
+    return;
+
   for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
     {
       dw_die_ref abbrev = abbrev_die_table[abbrev_id];
@@ -10830,6 +11381,10 @@ output_loc_list (dw_loc_list_ref list_head)
 {
   dw_loc_list_ref curr = list_head;
 
+  if (list_head->emitted)
+    return;
+  list_head->emitted = true;
+
   ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
 
   /* Walk the location list, and output each range + expression.  */
@@ -10863,7 +11418,7 @@ output_loc_list (dw_loc_list_ref list_head)
       gcc_assert (size <= 0xffff);
       dw2_asm_output_data (2, size, "%s", "Location expression size");
 
-      output_loc_sequence (curr->expr);
+      output_loc_sequence (curr->expr, -1);
     }
 
   dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
@@ -10898,14 +11453,14 @@ 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 (dwarf_version < 4 && die->die_id.die_symbol)
+  if (! use_debug_types && die->die_id.die_symbol)
     output_die_symbol (die);
 
   dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
                               (unsigned long)die->die_offset,
                               dwarf_tag_name (die->die_tag));
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     {
       const char *name = dwarf_attr_name (a->dw_attr);
 
@@ -10941,7 +11496,7 @@ output_die (dw_die_ref die)
          else
            dw2_asm_output_data (constant_size (size), size, "%s", name);
 
-         output_loc_sequence (AT_loc (a));
+         output_loc_sequence (AT_loc (a), -1);
          break;
 
        case dw_val_class_const:
@@ -11037,7 +11592,7 @@ output_die (dw_die_ref die)
        case dw_val_class_die_ref:
          if (AT_ref_external (a))
            {
-             if (dwarf_version >= 4)
+             if (use_debug_types)
                {
                  comdat_type_node_ref type_node =
                    AT_ref (a)->die_id.die_type_node;
@@ -11200,7 +11755,11 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
       switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
     }
   else
-    switch_to_section (debug_info_section);
+    {
+      switch_to_section (debug_info_section);
+      ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label);
+      info_section_emitted = true;
+    }
 
   /* Output debugging information.  */
   output_compilation_unit_header ();
@@ -11313,7 +11872,7 @@ add_pubtype (tree decl, dw_die_ref die)
 
   e.name = NULL;
   if ((TREE_PUBLIC (decl)
-       || die->die_parent == comp_unit_die)
+       || is_cu_die (die->die_parent))
       && (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl)))
     {
       e.die = die;
@@ -11371,7 +11930,7 @@ output_pubnames (VEC (pubname_entry, gc) * names)
   dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
                       "Compilation Unit Length");
 
-  for (i = 0; VEC_iterate (pubname_entry, names, i, pub); i++)
+  FOR_EACH_VEC_ELT (pubname_entry, names, i, pub)
     {
       /* We shouldn't see pubnames for DIEs outside of the main CU.  */
       if (names == pubname_table)
@@ -11391,35 +11950,14 @@ output_pubnames (VEC (pubname_entry, gc) * names)
   dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL);
 }
 
-/* Add a new entry to .debug_aranges if appropriate.  */
-
-static void
-add_arange (tree decl, dw_die_ref die)
-{
-  if (! DECL_SECTION_NAME (decl))
-    return;
-
-  if (arange_table_in_use == arange_table_allocated)
-    {
-      arange_table_allocated += ARANGE_TABLE_INCREMENT;
-      arange_table = GGC_RESIZEVEC (dw_die_ref, arange_table,
-                                   arange_table_allocated);
-      memset (arange_table + arange_table_in_use, 0,
-             ARANGE_TABLE_INCREMENT * sizeof (dw_die_ref));
-    }
-
-  arange_table[arange_table_in_use++] = die;
-}
-
 /* Output the information that goes into the .debug_aranges table.
    Namely, define the beginning and ending address range of the
    text section generated for this compilation unit.  */
 
 static void
-output_aranges (void)
+output_aranges (unsigned long aranges_length)
 {
   unsigned i;
-  unsigned long aranges_length = size_of_aranges ();
 
   if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
     dw2_asm_output_data (4, 0xffffffff,
@@ -11464,38 +12002,28 @@ output_aranges (void)
                            cold_text_section_label, "Length");
     }
 
-  for (i = 0; i < arange_table_in_use; i++)
+  if (have_multiple_function_sections)
     {
-      dw_die_ref die = arange_table[i];
-
-      /* We shouldn't see aranges for DIEs outside of the main CU.  */
-      gcc_assert (die->die_mark);
+      unsigned fde_idx = 0;
 
-      if (die->die_tag == DW_TAG_subprogram)
-       {
-         dw2_asm_output_addr (DWARF2_ADDR_SIZE, get_AT_low_pc (die),
-                              "Address");
-         dw2_asm_output_delta (DWARF2_ADDR_SIZE, get_AT_hi_pc (die),
-                               get_AT_low_pc (die), "Length");
-       }
-      else
+      for (fde_idx = 0; fde_idx < fde_table_in_use; fde_idx++)
        {
-         /* A static variable; extract the symbol from DW_AT_location.
-            Note that this code isn't currently hit, as we only emit
-            aranges for functions (jason 9/23/99).  */
-         dw_attr_ref a = get_AT (die, DW_AT_location);
-         dw_loc_descr_ref loc;
-
-         gcc_assert (a && AT_class (a) == dw_val_class_loc);
-
-         loc = AT_loc (a);
-         gcc_assert (loc->dw_loc_opc == DW_OP_addr);
-
-         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE,
-                                  loc->dw_loc_oprnd1.v.val_addr, "Address");
-         dw2_asm_output_data (DWARF2_ADDR_SIZE,
-                              get_AT_unsigned (die, DW_AT_byte_size),
-                              "Length");
+         dw_fde_ref fde = &fde_table[fde_idx];
+
+         if (!fde->in_std_section)
+           {
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin,
+                                  "Address");
+             dw2_asm_output_delta (DWARF2_ADDR_SIZE, fde->dw_fde_end,
+                                   fde->dw_fde_begin, "Length");
+           }
+         if (fde->dw_fde_second_begin && !fde->second_in_std_section)
+           {
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_second_begin,
+                                  "Address");
+             dw2_asm_output_delta (DWARF2_ADDR_SIZE, fde->dw_fde_second_end,
+                                   fde->dw_fde_second_begin, "Length");
+           }
        }
     }
 
@@ -11986,6 +12514,117 @@ output_file_names (void)
 }
 
 
+/* Output one line number table into the .debug_line section.  */
+
+static void
+output_one_line_info_table (dw_line_info_table *table)
+{
+  char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
+  unsigned int current_line = 1;
+  bool current_is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
+  dw_line_info_entry *ent;
+  size_t i;
+
+  FOR_EACH_VEC_ELT (dw_line_info_entry, table->entries, i, ent)
+    {
+      switch (ent->opcode)
+       {
+       case LI_set_address:
+         /* ??? Unfortunately, we have little choice here currently, and
+            must always use the most general form.  GCC does not know the
+            address delta itself, so we can't use DW_LNS_advance_pc.  Many
+            ports do have length attributes which will give an upper bound
+            on the address range.  We could perhaps use length attributes
+            to determine when it is safe to use DW_LNS_fixed_advance_pc.  */
+         ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val);
+
+         /* This can handle any delta.  This takes
+            4+DWARF2_ADDR_SIZE bytes.  */
+         dw2_asm_output_data (1, 0, "set address %s", line_label);
+         dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+         dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+         break;
+
+       case LI_set_line:
+         if (ent->val == current_line)
+           {
+             /* We still need to start a new row, so output a copy insn.  */
+             dw2_asm_output_data (1, DW_LNS_copy,
+                                  "copy line %u", current_line);
+           }
+         else
+           {
+             int line_offset = ent->val - current_line;
+             int line_delta = line_offset - DWARF_LINE_BASE;
+
+             current_line = ent->val;
+             if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
+               {
+                 /* This can handle deltas from -10 to 234, using the current
+                    definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE.
+                    This takes 1 byte.  */
+                 dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
+                                      "line %u", current_line);
+               }
+             else
+               {
+                 /* This can handle any delta.  This takes at least 4 bytes,
+                    depending on the value being encoded.  */
+                 dw2_asm_output_data (1, DW_LNS_advance_line,
+                                      "advance to line %u", current_line);
+                 dw2_asm_output_data_sleb128 (line_offset, NULL);
+                 dw2_asm_output_data (1, DW_LNS_copy, NULL);
+               }
+           }
+         break;
+
+       case LI_set_file:
+         dw2_asm_output_data (1, DW_LNS_set_file, "set file %u", ent->val);
+         dw2_asm_output_data_uleb128 (ent->val, "%u", ent->val);
+         break;
+
+       case LI_set_column:
+         dw2_asm_output_data (1, DW_LNS_set_column, "column %u", ent->val);
+         dw2_asm_output_data_uleb128 (ent->val, "%u", ent->val);
+         break;
+
+       case LI_negate_stmt:
+         current_is_stmt = !current_is_stmt;
+         dw2_asm_output_data (1, DW_LNS_negate_stmt,
+                              "is_stmt %d", current_is_stmt);
+         break;
+
+       case LI_set_prologue_end:
+         dw2_asm_output_data (1, DW_LNS_set_prologue_end,
+                              "set prologue end");
+         break;
+         
+       case LI_set_epilogue_begin:
+         dw2_asm_output_data (1, DW_LNS_set_epilogue_begin,
+                              "set epilogue begin");
+         break;
+
+       case LI_set_discriminator:
+         dw2_asm_output_data (1, 0, "discriminator %u", ent->val);
+         dw2_asm_output_data_uleb128 (1 + size_of_uleb128 (ent->val), NULL);
+         dw2_asm_output_data (1, DW_LNE_set_discriminator, NULL);
+         dw2_asm_output_data_uleb128 (ent->val, NULL);
+         break;
+       }
+    }
+
+  /* Emit debug info for the address of the end of the table.  */
+  dw2_asm_output_data (1, 0, "set address %s", table->end_label);
+  dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+  dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+  dw2_asm_output_addr (DWARF2_ADDR_SIZE, table->end_label, NULL);
+
+  dw2_asm_output_data (1, 0, "end sequence");
+  dw2_asm_output_data_uleb128 (1, NULL);
+  dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
+}
+
 /* Output the source line number correspondence information.  This
    information goes into the .debug_line section.  */
 
@@ -11993,17 +12632,9 @@ static void
 output_line_info (void)
 {
   char l1[20], l2[20], p1[20], p2[20];
-  char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
-  char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES];
-  unsigned opc;
-  unsigned n_op_args;
-  unsigned long lt_index;
-  unsigned long current_line;
-  long line_offset;
-  long line_delta;
-  unsigned long current_file;
-  unsigned long function;
   int ver = dwarf_version;
+  bool saw_one = false;
+  int opc;
 
   ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
@@ -12021,16 +12652,15 @@ output_line_info (void)
   dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
   ASM_OUTPUT_LABEL (asm_out_file, p1);
 
-  /* Define the architecture-dependent minimum instruction length (in
-   bytes).  In this implementation of DWARF, this field is used for
-   information purposes only.  Since GCC generates assembly language,
-   we have no a priori knowledge of how many instruction bytes are
-   generated for each source line, and therefore can use only the
-   DW_LNE_set_address and DW_LNS_fixed_advance_pc line information
-   commands.  Accordingly, we fix this as `1', which is "correct
-   enough" for all architectures, and don't let the target override.  */
-  dw2_asm_output_data (1, 1,
-                      "Minimum Instruction Length");
+  /* Define the architecture-dependent minimum instruction length (in bytes).
+     In this implementation of DWARF, this field is used for information
+     purposes only.  Since GCC generates assembly language, we have no
+     a priori knowledge of how many instruction bytes are generated for each
+     source line, and therefore can use only the DW_LNE_set_address and
+     DW_LNS_fixed_advance_pc line information commands.  Accordingly, we fix
+     this as '1', which is "correct enough" for all architectures,
+     and don't let the target override.  */
+  dw2_asm_output_data (1, 1, "Minimum Instruction Length");
 
   if (ver >= 4)
     dw2_asm_output_data (1, DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN,
@@ -12046,6 +12676,7 @@ output_line_info (void)
 
   for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; opc++)
     {
+      int n_op_args;
       switch (opc)
        {
        case DW_LNS_advance_pc:
@@ -12053,6 +12684,7 @@ output_line_info (void)
        case DW_LNS_set_file:
        case DW_LNS_set_column:
        case DW_LNS_fixed_advance_pc:
+       case DW_LNS_set_isa:
          n_op_args = 1;
          break;
        default:
@@ -12068,364 +12700,35 @@ output_line_info (void)
   output_file_names ();
   ASM_OUTPUT_LABEL (asm_out_file, p2);
 
-  /* We used to set the address register to the first location in the text
-     section here, but that didn't accomplish anything since we already
-     have a line note for the opening brace of the first function.  */
-
-  /* Generate the line number to PC correspondence table, encoded as
-     a series of state machine operations.  */
-  current_file = 1;
-  current_line = 1;
-
-  if (cfun && in_cold_section_p)
-    strcpy (prev_line_label, crtl->subsections.cold_section_label);
-  else
-    strcpy (prev_line_label, text_section_label);
-  for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
+  if (separate_line_info)
     {
-      dw_line_info_ref line_info = &line_info_table[lt_index];
-
-#if 0
-      /* Disable this optimization for now; GDB wants to see two line notes
-        at the beginning of a function so it can find the end of the
-        prologue.  */
-
-      /* Don't emit anything for redundant notes.  Just updating the
-        address doesn't accomplish anything, because we already assume
-        that anything after the last address is this line.  */
-      if (line_info->dw_line_num == current_line
-         && line_info->dw_file_num == current_file)
-       continue;
-#endif
-
-      /* Emit debug info for the address of the current line.
-
-        Unfortunately, we have little choice here currently, and must always
-        use the most general form.  GCC does not know the address delta
-        itself, so we can't use DW_LNS_advance_pc.  Many ports do have length
-        attributes which will give an upper bound on the address range.  We
-        could perhaps use length attributes to determine when it is safe to
-        use DW_LNS_fixed_advance_pc.  */
-
-      ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index);
-      if (0)
-       {
-         /* This can handle deltas up to 0xffff.  This takes 3 bytes.  */
-         dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-                              "DW_LNS_fixed_advance_pc");
-         dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
-       }
-      else
-       {
-         /* This can handle any delta.  This takes
-            4+DWARF2_ADDR_SIZE bytes.  */
-         dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-         dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-         dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-         dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
-       }
-
-      strcpy (prev_line_label, line_label);
-
-      /* Emit debug info for the source file of the current line, if
-        different from the previous line.  */
-      if (line_info->dw_file_num != current_file)
-       {
-         current_file = line_info->dw_file_num;
-         dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
-         dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
-       }
-
-      /* Emit debug info for the current line number, choosing the encoding
-        that uses the least amount of space.  */
-      if (line_info->dw_line_num != current_line)
-       {
-         line_offset = line_info->dw_line_num - current_line;
-         line_delta = line_offset - DWARF_LINE_BASE;
-         current_line = line_info->dw_line_num;
-         if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
-           /* This can handle deltas from -10 to 234, using the current
-              definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE.  This
-              takes 1 byte.  */
-           dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
-                                "line %lu", current_line);
-         else
-           {
-             /* This can handle any delta.  This takes at least 4 bytes,
-                depending on the value being encoded.  */
-             dw2_asm_output_data (1, DW_LNS_advance_line,
-                                  "advance to line %lu", current_line);
-             dw2_asm_output_data_sleb128 (line_offset, NULL);
-             dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
-           }
-       }
-      else
-       /* We still need to start a new row, so output a copy insn.  */
-       dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
-    }
+      dw_line_info_table *table;
+      size_t i;
 
-  /* Emit debug info for the address of the end of the function.  */
-  if (0)
-    {
-      dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-                          "DW_LNS_fixed_advance_pc");
-      dw2_asm_output_delta (2, text_end_label, prev_line_label, NULL);
+      FOR_EACH_VEC_ELT (dw_line_info_table_p, separate_line_info, i, table)
+       if (table->in_use)
+         {
+           output_one_line_info_table (table);
+           saw_one = true;
+         }
     }
-  else
+  if (cold_text_section_line_info && cold_text_section_line_info->in_use)
     {
-      dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-      dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-      dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-      dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_end_label, NULL);
+      output_one_line_info_table (cold_text_section_line_info);
+      saw_one = true;
     }
 
-  dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
-  dw2_asm_output_data_uleb128 (1, NULL);
-  dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
-
-  function = 0;
-  current_file = 1;
-  current_line = 1;
-  for (lt_index = 0; lt_index < separate_line_info_table_in_use;)
-    {
-      dw_separate_line_info_ref line_info
-       = &separate_line_info_table[lt_index];
-
-#if 0
-      /* Don't emit anything for redundant notes.  */
-      if (line_info->dw_line_num == current_line
-         && line_info->dw_file_num == current_file
-         && line_info->function == function)
-       goto cont;
-#endif
-
-      /* Emit debug info for the address of the current line.  If this is
-        a new function, or the first line of a function, then we need
-        to handle it differently.  */
-      ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL,
-                                  lt_index);
-      if (function != line_info->function)
-       {
-         function = line_info->function;
-
-         /* Set the address register to the first line in the function.  */
-         dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-         dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-         dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-         dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
-       }
-      else
-       {
-         /* ??? See the DW_LNS_advance_pc comment above.  */
-         if (0)
-           {
-             dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-                                  "DW_LNS_fixed_advance_pc");
-             dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
-           }
-         else
-           {
-             dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-             dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-             dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
-           }
-       }
-
-      strcpy (prev_line_label, line_label);
-
-      /* Emit debug info for the source file of the current line, if
-        different from the previous line.  */
-      if (line_info->dw_file_num != current_file)
-       {
-         current_file = line_info->dw_file_num;
-         dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
-         dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
-       }
-
-      /* Emit debug info for the current line number, choosing the encoding
-        that uses the least amount of space.  */
-      if (line_info->dw_line_num != current_line)
-       {
-         line_offset = line_info->dw_line_num - current_line;
-         line_delta = line_offset - DWARF_LINE_BASE;
-         current_line = line_info->dw_line_num;
-         if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
-           dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
-                                "line %lu", current_line);
-         else
-           {
-             dw2_asm_output_data (1, DW_LNS_advance_line,
-                                  "advance to line %lu", current_line);
-             dw2_asm_output_data_sleb128 (line_offset, NULL);
-             dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
-           }
-       }
-      else
-       dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
-
-#if 0
-    cont:
-#endif
-
-      lt_index++;
-
-      /* If we're done with a function, end its sequence.  */
-      if (lt_index == separate_line_info_table_in_use
-         || separate_line_info_table[lt_index].function != function)
-       {
-         current_file = 1;
-         current_line = 1;
-
-         /* Emit debug info for the address of the end of the function.  */
-         ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function);
-         if (0)
-           {
-             dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-                                  "DW_LNS_fixed_advance_pc");
-             dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
-           }
-         else
-           {
-             dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-             dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-             dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
-           }
-
-         /* Output the marker for the end of this sequence.  */
-         dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
-         dw2_asm_output_data_uleb128 (1, NULL);
-         dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
-       }
-    }
+  /* ??? Some Darwin linkers crash on a .debug_line section with no
+     sequences.  Further, merely a DW_LNE_end_sequence entry is not
+     sufficient -- the address column must also be initialized.
+     Make sure to output at least one set_address/end_sequence pair,
+     choosing .text since that section is always present.  */
+  if (text_section_line_info->in_use || !saw_one)
+    output_one_line_info_table (text_section_line_info);
 
   /* 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.
@@ -12517,7 +12820,7 @@ base_type_die (tree type)
       gcc_unreachable ();
     }
 
-  base_type_result = new_die (DW_TAG_base_type, comp_unit_die, type);
+  base_type_result = new_die (DW_TAG_base_type, comp_unit_die (), type);
 
   add_AT_unsigned (base_type_result, DW_AT_byte_size,
                   int_size_in_bytes (type));
@@ -12552,6 +12855,7 @@ is_base_type (tree type)
     case METHOD_TYPE:
     case POINTER_TYPE:
     case REFERENCE_TYPE:
+    case NULLPTR_TYPE:
     case OFFSET_TYPE:
     case LANG_TYPE:
     case VECTOR_TYPE:
@@ -12608,7 +12912,7 @@ subrange_type_die (tree type, tree low, tree high, dw_die_ref context_die)
   const HOST_WIDE_INT size_in_bytes = int_size_in_bytes (type);
 
   if (context_die == NULL)
-    context_die = comp_unit_die;
+    context_die = comp_unit_die ();
 
   subrange_die = new_die (DW_TAG_subrange_type, context_die, type);
 
@@ -12655,15 +12959,14 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
       && TYPE_NAME (qualified_type)
       && TREE_CODE (TYPE_NAME (qualified_type)) == TYPE_DECL)
     {
-#ifdef ENABLE_CHECKING
-      gcc_assert (TREE_CODE (TREE_TYPE (TYPE_NAME (qualified_type)))
-                 == INTEGER_TYPE
-                 && TYPE_PRECISION (TREE_TYPE (TYPE_NAME (qualified_type)))
-                    == TYPE_PRECISION (qualified_type)
-                 && TYPE_UNSIGNED (TREE_TYPE (TYPE_NAME (qualified_type)))
-                    == TYPE_UNSIGNED (qualified_type));
-#endif
-      qualified_type = TREE_TYPE (TYPE_NAME (qualified_type));
+      tree t = TREE_TYPE (TYPE_NAME (qualified_type));
+
+      gcc_checking_assert (TREE_CODE (t) == INTEGER_TYPE
+                          && TYPE_PRECISION (t)
+                          == TYPE_PRECISION (qualified_type)
+                          && TYPE_UNSIGNED (t)
+                          == TYPE_UNSIGNED (qualified_type));
+      qualified_type = t;
     }
 
   /* If we do, then we can just use its DIE, if it exists.  */
@@ -12701,19 +13004,24 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
       /* Else cv-qualified version of named type; fall through.  */
     }
 
-  if (is_const_type)
+  if (is_const_type
+      /* If both is_const_type and is_volatile_type, prefer the path
+        which leads to a qualified type.  */
+      && (!is_volatile_type
+         || get_qualified_type (type, TYPE_QUAL_CONST) == NULL_TREE
+         || get_qualified_type (type, TYPE_QUAL_VOLATILE) != NULL_TREE))
     {
-      mod_type_die = new_die (DW_TAG_const_type, comp_unit_die, type);
+      mod_type_die = new_die (DW_TAG_const_type, comp_unit_die (), type);
       sub_die = modified_type_die (type, 0, is_volatile_type, context_die);
     }
   else if (is_volatile_type)
     {
-      mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die, type);
-      sub_die = modified_type_die (type, 0, 0, context_die);
+      mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die (), type);
+      sub_die = modified_type_die (type, is_const_type, 0, context_die);
     }
   else if (code == POINTER_TYPE)
     {
-      mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die, type);
+      mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die (), type);
       add_AT_unsigned (mod_type_die, DW_AT_byte_size,
                       simple_type_size_in_bits (type) / BITS_PER_UNIT);
       item_type = TREE_TYPE (type);
@@ -12724,10 +13032,10 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
   else if (code == REFERENCE_TYPE)
     {
       if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4)
-       mod_type_die = new_die (DW_TAG_rvalue_reference_type, comp_unit_die,
+       mod_type_die = new_die (DW_TAG_rvalue_reference_type, comp_unit_die (),
                                type);
       else
-       mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die, type);
+       mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die (), type);
       add_AT_unsigned (mod_type_die, DW_AT_byte_size,
                       simple_type_size_in_bits (type) / BITS_PER_UNIT);
       item_type = TREE_TYPE (type);
@@ -12781,6 +13089,7 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
           useful source coordinates anyway.  */
        name = DECL_NAME (name);
       add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
+      add_gnat_descriptive_type_attribute (mod_type_die, type, context_die);
     }
   /* This probably indicates a bug.  */
   else if (mod_type_die && mod_type_die->die_tag == DW_TAG_base_type)
@@ -13059,7 +13368,8 @@ reg_loc_descriptor (rtx rtl, enum var_init_status initialized)
 
       if (dwarf_version >= 4 || !dwarf_strict)
        {
-         result = mem_loc_descriptor (rtl, VOIDmode, initialized);
+         result = mem_loc_descriptor (rtl, GET_MODE (rtl), VOIDmode,
+                                      initialized);
          if (result)
            add_loc_descr (&result,
                           new_loc_descr (DW_OP_stack_value, 0, 0));
@@ -13299,7 +13609,7 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset,
              int base_reg
                = DWARF_FRAME_REGNUM ((fde && fde->drap_reg != INVALID_REGNUM)
                                      ? HARD_FRAME_POINTER_REGNUM
-                                     : STACK_POINTER_REGNUM);
+                                     : REGNO (elim));
              return new_reg_loc_descr (base_reg, offset);
            }
 
@@ -13406,11 +13716,25 @@ const_ok_for_output_1 (rtx *rtlp, void *data ATTRIBUTE_UNUSED)
       /* If delegitimize_address couldn't do anything with the UNSPEC, assume
         we can't express it in the debug info.  */
 #ifdef ENABLE_CHECKING
-      inform (current_function_decl
-             ? DECL_SOURCE_LOCATION (current_function_decl)
-             : UNKNOWN_LOCATION,
-             "non-delegitimized UNSPEC %d found in variable location",
-             XINT (rtl, 1));
+      /* Don't complain about TLS UNSPECs, those are just too hard to
+        delegitimize.  */
+      if (XVECLEN (rtl, 0) != 1
+         || GET_CODE (XVECEXP (rtl, 0, 0)) != SYMBOL_REF
+         || SYMBOL_REF_DECL (XVECEXP (rtl, 0, 0)) == NULL
+         || TREE_CODE (SYMBOL_REF_DECL (XVECEXP (rtl, 0, 0))) != VAR_DECL
+         || !DECL_THREAD_LOCAL_P (SYMBOL_REF_DECL (XVECEXP (rtl, 0, 0))))
+       inform (current_function_decl
+               ? DECL_SOURCE_LOCATION (current_function_decl)
+               : UNKNOWN_LOCATION,
+#if NUM_UNSPEC_VALUES > 0
+               "non-delegitimized UNSPEC %s (%d) found in variable location",
+               ((XINT (rtl, 1) >= 0 && XINT (rtl, 1) < NUM_UNSPEC_VALUES)
+                ? unspec_strings[XINT (rtl, 1)] : "unknown"),
+               XINT (rtl, 1));
+#else
+               "non-delegitimized UNSPEC %d found in variable location",
+               XINT (rtl, 1));
+#endif
 #endif
       expansion_failed (NULL_TREE, rtl,
                        "UNSPEC hasn't been delegitimized.\n");
@@ -13473,6 +13797,33 @@ const_ok_for_output (rtx rtl)
   return true;
 }
 
+/* Return a reference to DW_TAG_base_type corresponding to MODE and UNSIGNEDP
+   if possible, NULL otherwise.  */
+
+static dw_die_ref
+base_type_for_mode (enum machine_mode mode, bool unsignedp)
+{
+  dw_die_ref type_die;
+  tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
+
+  if (type == NULL)
+    return NULL;
+  switch (TREE_CODE (type))
+    {
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+      break;
+    default:
+      return NULL;
+    }
+  type_die = lookup_type_die (type);
+  if (!type_die)
+    type_die = modified_type_die (type, false, false, comp_unit_die ());
+  if (type_die == NULL || type_die->die_tag != DW_TAG_base_type)
+    return NULL;
+  return type_die;
+}
+
 /* 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
@@ -13483,22 +13834,25 @@ const_ok_for_output (rtx rtl)
    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.
+   MODE is the mode that should be assumed for the rtl if it is VOIDmode.
 
-   CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the
-   location list for RTL.
+   MEM_MODE is the mode of the memory reference, needed to handle some
+   autoincrement addressing modes.
 
    Return 0 if we can't represent the location.  */
 
 static dw_loc_descr_ref
 mem_loc_descriptor (rtx rtl, enum machine_mode mode,
+                   enum machine_mode mem_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;
 
+  if (mode == VOIDmode)
+    mode = GET_MODE (rtl);
+
   /* 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
@@ -13506,12 +13860,15 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
 
   rtl = targetm.delegitimize_address (rtl);
 
+  if (mode != GET_MODE (rtl) && GET_MODE (rtl) != VOIDmode)
+    return NULL;
+
   switch (GET_CODE (rtl))
     {
     case POST_INC:
     case POST_DEC:
     case POST_MODIFY:
-      return mem_loc_descriptor (XEXP (rtl, 0), mode, initialized);
+      return mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, initialized);
 
     case SUBREG:
       /* The case of a subreg may arise when we have a local (register)
@@ -13521,15 +13878,80 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
         contains the given subreg.  */
       if (!subreg_lowpart_p (rtl))
        break;
-      rtl = SUBREG_REG (rtl);
-      if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE)
+      if (GET_MODE_CLASS (mode) == MODE_INT
+         && GET_MODE_CLASS (GET_MODE (SUBREG_REG (rtl))) == MODE_INT
+         && (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE
+#ifdef POINTERS_EXTEND_UNSIGNED
+             || (mode == Pmode && mem_mode != VOIDmode)
+#endif
+            )
+         && GET_MODE_SIZE (GET_MODE (SUBREG_REG (rtl))) <= DWARF2_ADDR_SIZE)
+       {
+         mem_loc_result = mem_loc_descriptor (SUBREG_REG (rtl),
+                                              GET_MODE (SUBREG_REG (rtl)),
+                                              mem_mode, initialized);
+         break;
+       }
+      if (dwarf_strict)
+       break;
+      if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (rtl))))
        break;
-      if (GET_MODE_CLASS (GET_MODE (rtl)) != MODE_INT)
+      if (GET_MODE_SIZE (mode) != GET_MODE_SIZE (GET_MODE (SUBREG_REG (rtl)))
+         && (GET_MODE_CLASS (mode) != MODE_INT
+             || GET_MODE_CLASS (GET_MODE (SUBREG_REG (rtl))) != MODE_INT))
        break;
-      mem_loc_result = mem_loc_descriptor (rtl, mode, initialized);
+      else
+       {
+         dw_die_ref type_die;
+         dw_loc_descr_ref cvt;
+
+         mem_loc_result = mem_loc_descriptor (SUBREG_REG (rtl),
+                                              GET_MODE (SUBREG_REG (rtl)),
+                                              mem_mode, initialized);
+         if (mem_loc_result == NULL)
+           break;
+         type_die = base_type_for_mode (mode, 0);
+         if (type_die == NULL)
+           {
+             mem_loc_result = NULL;
+             break;
+           }
+         if (GET_MODE_SIZE (mode)
+             != GET_MODE_SIZE (GET_MODE (SUBREG_REG (rtl))))
+           cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+         else
+           cvt = new_loc_descr (DW_OP_GNU_reinterpret, 0, 0);
+         cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+         cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+         cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+         add_loc_descr (&mem_loc_result, cvt);
+       }
       break;
 
     case REG:
+      if (GET_MODE_CLASS (mode) != MODE_INT
+         || (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE
+#ifdef POINTERS_EXTEND_UNSIGNED
+             && (mode != Pmode || mem_mode == VOIDmode)
+#endif
+             ))
+       {
+         dw_die_ref type_die;
+
+         if (dwarf_strict)
+           break;
+         if (REGNO (rtl) > FIRST_PSEUDO_REGISTER)
+           break;
+         type_die = base_type_for_mode (mode, 0);
+         if (type_die == NULL)
+           break;
+         mem_loc_result = new_loc_descr (DW_OP_GNU_regval_type,
+                                         dbx_reg_number (rtl), 0);
+         mem_loc_result->dw_loc_oprnd2.val_class = dw_val_class_die_ref;
+         mem_loc_result->dw_loc_oprnd2.v.val_die_ref.die = type_die;
+         mem_loc_result->dw_loc_oprnd2.v.val_die_ref.external = 0;
+         break;
+       }
       /* 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
@@ -13559,11 +13981,12 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
 
     case SIGN_EXTEND:
     case ZERO_EXTEND:
-      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
+      gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (XEXP (rtl, 0)),
+                               mem_mode, VAR_INIT_STATUS_INITIALIZED);
       if (op0 == 0)
        break;
-      else
+      else if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE)
        {
          int shift = DWARF2_ADDR_SIZE
                      - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
@@ -13578,39 +14001,75 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
          add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
          add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
        }
+      else if (!dwarf_strict)
+       {
+         dw_die_ref type_die1, type_die2;
+         dw_loc_descr_ref cvt;
+
+         type_die1 = base_type_for_mode (GET_MODE (XEXP (rtl, 0)),
+                                         GET_CODE (rtl) == ZERO_EXTEND);
+         if (type_die1 == NULL)
+           break;
+         type_die2 = base_type_for_mode (mode, 0);
+         if (type_die2 == NULL)
+           break;
+         mem_loc_result = op0;
+         cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+         cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+         cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die1;
+         cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+         add_loc_descr (&mem_loc_result, cvt);
+         cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+         cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+         cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die2;
+         cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+         add_loc_descr (&mem_loc_result, cvt);
+       }
       break;
 
     case MEM:
-      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0),
+                                          get_address_mode (rtl), mode,
                                           VAR_INIT_STATUS_INITIALIZED);
       if (mem_loc_result == NULL)
        mem_loc_result = tls_mem_loc_descriptor (rtl);
       if (mem_loc_result != 0)
        {
-         if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE)
+         if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE
+             || GET_MODE_CLASS (mode) != MODE_INT)
            {
-             expansion_failed (NULL_TREE, rtl, "DWARF address size mismatch");
-             return 0;
+             dw_die_ref type_die;
+             dw_loc_descr_ref deref;
+
+             if (dwarf_strict)
+               return NULL;
+             type_die = base_type_for_mode (mode, 0);
+             if (type_die == NULL)
+               return NULL;
+             deref = new_loc_descr (DW_OP_GNU_deref_type,
+                                    GET_MODE_SIZE (mode), 0);
+             deref->dw_loc_oprnd2.val_class = dw_val_class_die_ref;
+             deref->dw_loc_oprnd2.v.val_die_ref.die = type_die;
+             deref->dw_loc_oprnd2.v.val_die_ref.external = 0;
+             add_loc_descr (&mem_loc_result, deref);
            }
-         else if (GET_MODE_SIZE (GET_MODE (rtl)) == DWARF2_ADDR_SIZE)
+         else if (GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE)
            add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
          else
            add_loc_descr (&mem_loc_result,
                           new_loc_descr (DW_OP_deref_size,
-                                         GET_MODE_SIZE (GET_MODE (rtl)), 0));
+                                         GET_MODE_SIZE (mode), 0));
        }
       else
        {
          rtx new_rtl = avoid_constant_pool_reference (rtl);
          if (new_rtl != rtl)
-           return mem_loc_descriptor (new_rtl, mode, initialized);
+           return mem_loc_descriptor (new_rtl, mode, mem_mode, initialized);
        }
       break;
 
     case LO_SUM:
-        rtl = XEXP (rtl, 1);
-
-      /* ... fall through ...  */
+      return mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, initialized);
 
     case LABEL_REF:
       /* Some ports can transform a symbol ref into a label ref, because
@@ -13618,6 +14077,13 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
         pool.  */
     case CONST:
     case SYMBOL_REF:
+      if (GET_MODE_CLASS (mode) != MODE_INT
+         || (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE
+#ifdef POINTERS_EXTEND_UNSIGNED
+             && (mode != Pmode || mem_mode == VOIDmode)
+#endif
+             ))
+       break;
       if (GET_CODE (rtl) == SYMBOL_REF
          && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
        {
@@ -13655,10 +14121,42 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
     case CONCAT:
     case CONCATN:
     case VAR_LOCATION:
+    case DEBUG_IMPLICIT_PTR:
       expansion_failed (NULL_TREE, rtl,
                        "CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor");
       return 0;
 
+    case ENTRY_VALUE:
+      if (dwarf_strict)
+       return NULL;
+      if (REG_P (ENTRY_VALUE_EXP (rtl)))
+       {
+         if (GET_MODE_CLASS (mode) != MODE_INT
+             || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE)
+           op0 = mem_loc_descriptor (ENTRY_VALUE_EXP (rtl), mode,
+                                     VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+         else
+           op0
+             = one_reg_loc_descriptor (dbx_reg_number (ENTRY_VALUE_EXP (rtl)),
+                                       VAR_INIT_STATUS_INITIALIZED);
+       }
+      else if (MEM_P (ENTRY_VALUE_EXP (rtl))
+              && REG_P (XEXP (ENTRY_VALUE_EXP (rtl), 0)))
+       {
+         op0 = mem_loc_descriptor (ENTRY_VALUE_EXP (rtl), mode,
+                                   VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+         if (op0 && op0->dw_loc_opc == DW_OP_fbreg)
+           return NULL;
+       }
+      else
+       gcc_unreachable ();
+      if (op0 == NULL)
+       return NULL;
+      mem_loc_result = new_loc_descr (DW_OP_GNU_entry_value, 0, 0);
+      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_loc;
+      mem_loc_result->dw_loc_oprnd1.v.val_loc = op0;
+      return mem_loc_result;
+
     case PRE_MODIFY:
       /* Extract the PLUS expression nested inside and fall into
         PLUS code below.  */
@@ -13669,32 +14167,35 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
     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),
+      rtl = gen_rtx_PLUS (mode, XEXP (rtl, 0),
                          GEN_INT (GET_CODE (rtl) == PRE_INC
-                                  ? GET_MODE_UNIT_SIZE (mode)
-                                  : -GET_MODE_UNIT_SIZE (mode)));
+                                  ? GET_MODE_UNIT_SIZE (mem_mode)
+                                  : -GET_MODE_UNIT_SIZE (mem_mode)));
 
       /* ... fall through ...  */
 
     case PLUS:
     plus:
-      if (is_based_loc (rtl))
+      if (is_based_loc (rtl)
+         && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE
+         && GET_MODE_CLASS (mode) == MODE_INT)
        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,
+         mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
                                               VAR_INIT_STATUS_INITIALIZED);
          if (mem_loc_result == 0)
            break;
 
-         if (CONST_INT_P (XEXP (rtl, 1)))
+         if (CONST_INT_P (XEXP (rtl, 1))
+             && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE)
            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,
+               = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
                                      VAR_INIT_STATUS_INITIALIZED);
              if (mem_loc_result2 == 0)
                break;
@@ -13725,15 +14226,31 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
 
     case ASHIFT:
       op = DW_OP_shl;
-      goto do_binop;
+      goto do_shift;
 
     case ASHIFTRT:
       op = DW_OP_shra;
-      goto do_binop;
+      goto do_shift;
 
     case LSHIFTRT:
       op = DW_OP_shr;
-      goto do_binop;
+      goto do_shift;
+
+    do_shift:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1),
+                               GET_MODE (XEXP (rtl, 1)) == VOIDmode
+                               ? mode : GET_MODE (XEXP (rtl, 1)), mem_mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+
+      if (op0 == 0 || op1 == 0)
+       break;
+
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      break;
 
     case AND:
       op = DW_OP_and;
@@ -13748,9 +14265,9 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       goto do_binop;
 
     do_binop:
-      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
                                VAR_INIT_STATUS_INITIALIZED);
-      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
                                VAR_INIT_STATUS_INITIALIZED);
 
       if (op0 == 0 || op1 == 0)
@@ -13762,9 +14279,9 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       break;
 
     case MOD:
-      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
                                VAR_INIT_STATUS_INITIALIZED);
-      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
                                VAR_INIT_STATUS_INITIALIZED);
 
       if (op0 == 0 || op1 == 0)
@@ -13792,7 +14309,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       goto do_unop;
 
     do_unop:
-      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
                                VAR_INIT_STATUS_INITIALIZED);
 
       if (op0 == 0)
@@ -13803,7 +14320,81 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       break;
 
     case CONST_INT:
-      mem_loc_result = int_loc_descriptor (INTVAL (rtl));
+      if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE
+#ifdef POINTERS_EXTEND_UNSIGNED
+         || (mode == Pmode
+             && mem_mode != VOIDmode
+             && trunc_int_for_mode (INTVAL (rtl), ptr_mode) == INTVAL (rtl))
+#endif
+         )
+       {
+         mem_loc_result = int_loc_descriptor (INTVAL (rtl));
+         break;
+       }
+      if (!dwarf_strict
+         && (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT
+             || GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT))
+       {
+         dw_die_ref type_die = base_type_for_mode (mode, 0);
+         if (type_die == NULL)
+           return NULL;
+         mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0,
+                                         INTVAL (rtl));
+         mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+         mem_loc_result->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+         mem_loc_result->dw_loc_oprnd1.v.val_die_ref.external = 0;
+         if (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT)
+           mem_loc_result->dw_loc_oprnd2.val_class = dw_val_class_const;
+         else
+           {
+             mem_loc_result->dw_loc_oprnd2.val_class
+               = dw_val_class_const_double;
+             mem_loc_result->dw_loc_oprnd2.v.val_double
+               = shwi_to_double_int (INTVAL (rtl));
+           }
+       }
+      break;
+
+    case CONST_DOUBLE:
+      if (!dwarf_strict)
+       {
+         dw_die_ref type_die;
+
+         /* 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 (mode == VOIDmode
+             || (GET_MODE (rtl) == VOIDmode
+                 && GET_MODE_BITSIZE (mode) != 2 * HOST_BITS_PER_WIDE_INT))
+           break;
+         type_die = base_type_for_mode (mode, 0);
+         if (type_die == NULL)
+           return NULL;
+         mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0, 0);
+         mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+         mem_loc_result->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+         mem_loc_result->dw_loc_oprnd1.v.val_die_ref.external = 0;
+         if (SCALAR_FLOAT_MODE_P (mode))
+           {
+             unsigned int length = GET_MODE_SIZE (mode);
+             unsigned char *array
+                 = (unsigned char*) ggc_alloc_atomic (length);
+
+             insert_float (rtl, array);
+             mem_loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+             mem_loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4;
+             mem_loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
+             mem_loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+           }
+         else
+           {
+             mem_loc_result->dw_loc_oprnd2.val_class
+               = dw_val_class_const_double;
+             mem_loc_result->dw_loc_oprnd2.v.val_double
+               = rtx_to_double_int (rtl);
+           }
+       }
       break;
 
     case EQ:
@@ -13831,74 +14422,75 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       goto do_scompare;
 
     do_scompare:
-      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
-         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 1))) > DWARF2_ADDR_SIZE)
-       break;
-      else
-       {
-         enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
+      {
+       enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
 
-         if (op_mode == VOIDmode)
-           op_mode = GET_MODE (XEXP (rtl, 1));
-         if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT)
-           break;
+       if (op_mode == VOIDmode)
+         op_mode = GET_MODE (XEXP (rtl, 1));
+       if (op_mode == VOIDmode)
+         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 (dwarf_strict
+           && (GET_MODE_CLASS (op_mode) != MODE_INT
+               || GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE))
+         break;
 
-         if (op0 == 0 || op1 == 0)
-           break;
+       op0 = mem_loc_descriptor (XEXP (rtl, 0), op_mode, mem_mode,
+                                 VAR_INIT_STATUS_INITIALIZED);
+       op1 = mem_loc_descriptor (XEXP (rtl, 1), op_mode, mem_mode,
+                                 VAR_INIT_STATUS_INITIALIZED);
 
-         if (op_mode != VOIDmode
-             && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
-           {
-             int shift = DWARF2_ADDR_SIZE - GET_MODE_SIZE (op_mode);
-             shift *= BITS_PER_UNIT;
-             /* For eq/ne, if the operands are known to be zero-extended,
-                there is no need to do the fancy shifting up.  */
-             if (op == DW_OP_eq || op == DW_OP_ne)
-               {
-                 dw_loc_descr_ref last0, last1;
-                 for (last0 = op0;
-                      last0->dw_loc_next != NULL;
-                      last0 = last0->dw_loc_next)
-                   ;
-                 for (last1 = op1;
-                      last1->dw_loc_next != NULL;
-                      last1 = last1->dw_loc_next)
-                   ;
-                 /* deref_size zero extends, and for constants we can check
-                    whether they are zero extended or not.  */
-                 if (((last0->dw_loc_opc == DW_OP_deref_size
-                       && last0->dw_loc_oprnd1.v.val_int
-                          <= GET_MODE_SIZE (op_mode))
-                      || (CONST_INT_P (XEXP (rtl, 0))
-                           && (unsigned HOST_WIDE_INT) INTVAL (XEXP (rtl, 0))
-                              == (INTVAL (XEXP (rtl, 0))
-                                  & GET_MODE_MASK (op_mode))))
-                     && ((last1->dw_loc_opc == DW_OP_deref_size
-                          && last1->dw_loc_oprnd1.v.val_int
-                             <= GET_MODE_SIZE (op_mode))
-                         || (CONST_INT_P (XEXP (rtl, 1))
-                             && (unsigned HOST_WIDE_INT)
-                                INTVAL (XEXP (rtl, 1))
-                                == (INTVAL (XEXP (rtl, 1))
-                                    & GET_MODE_MASK (op_mode)))))
-                   goto do_compare;
-               }
-             add_loc_descr (&op0, int_loc_descriptor (shift));
-             add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
-             if (CONST_INT_P (XEXP (rtl, 1)))
-               op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift);
-             else
-               {
-                 add_loc_descr (&op1, int_loc_descriptor (shift));
-                 add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
-               }
-           }
-       }
+       if (op0 == 0 || op1 == 0)
+         break;
+
+       if (GET_MODE_CLASS (op_mode) == MODE_INT
+           && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
+         {
+           int shift = DWARF2_ADDR_SIZE - GET_MODE_SIZE (op_mode);
+           shift *= BITS_PER_UNIT;
+           /* For eq/ne, if the operands are known to be zero-extended,
+              there is no need to do the fancy shifting up.  */
+           if (op == DW_OP_eq || op == DW_OP_ne)
+             {
+               dw_loc_descr_ref last0, last1;
+               for (last0 = op0;
+                    last0->dw_loc_next != NULL;
+                    last0 = last0->dw_loc_next)
+                 ;
+               for (last1 = op1;
+                    last1->dw_loc_next != NULL;
+                    last1 = last1->dw_loc_next)
+                 ;
+               /* deref_size zero extends, and for constants we can check
+                  whether they are zero extended or not.  */
+               if (((last0->dw_loc_opc == DW_OP_deref_size
+                     && last0->dw_loc_oprnd1.v.val_int
+                        <= GET_MODE_SIZE (op_mode))
+                    || (CONST_INT_P (XEXP (rtl, 0))
+                        && (unsigned HOST_WIDE_INT) INTVAL (XEXP (rtl, 0))
+                            == (INTVAL (XEXP (rtl, 0))
+                                & GET_MODE_MASK (op_mode))))
+                   && ((last1->dw_loc_opc == DW_OP_deref_size
+                        && last1->dw_loc_oprnd1.v.val_int
+                           <= GET_MODE_SIZE (op_mode))
+                       || (CONST_INT_P (XEXP (rtl, 1))
+                           && (unsigned HOST_WIDE_INT)
+                              INTVAL (XEXP (rtl, 1))
+                              == (INTVAL (XEXP (rtl, 1))
+                                  & GET_MODE_MASK (op_mode)))))
+                 goto do_compare;
+             }
+           add_loc_descr (&op0, int_loc_descriptor (shift));
+           add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+           if (CONST_INT_P (XEXP (rtl, 1)))
+             op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift);
+           else
+             {
+               add_loc_descr (&op1, int_loc_descriptor (shift));
+               add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+             }
+         }
+      }
 
     do_compare:
       mem_loc_result = op0;
@@ -13929,87 +14521,111 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       goto do_ucompare;
 
     do_ucompare:
-      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
-         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 1))) > DWARF2_ADDR_SIZE)
-       break;
-      else
-       {
-         enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
+      {
+       enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
 
-         if (op_mode == VOIDmode)
-           op_mode = GET_MODE (XEXP (rtl, 1));
-         if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT)
-           break;
+       if (op_mode == VOIDmode)
+         op_mode = GET_MODE (XEXP (rtl, 1));
+       if (op_mode == VOIDmode)
+         break;
+       if (GET_MODE_CLASS (op_mode) != MODE_INT)
+         break;
 
-         op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                                   VAR_INIT_STATUS_INITIALIZED);
-         op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                                   VAR_INIT_STATUS_INITIALIZED);
+       if (dwarf_strict && GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE)
+         break;
 
-         if (op0 == 0 || op1 == 0)
+       if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT)
            break;
 
-         if (op_mode != VOIDmode
-             && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
-           {
-             HOST_WIDE_INT mask = GET_MODE_MASK (op_mode);
-             dw_loc_descr_ref last0, last1;
-             for (last0 = op0;
-                  last0->dw_loc_next != NULL;
-                  last0 = last0->dw_loc_next)
-               ;
-             for (last1 = op1;
-                  last1->dw_loc_next != NULL;
-                  last1 = last1->dw_loc_next)
-               ;
-             if (CONST_INT_P (XEXP (rtl, 0)))
-               op0 = int_loc_descriptor (INTVAL (XEXP (rtl, 0)) & mask);
-             /* deref_size zero extends, so no need to mask it again.  */
-             else if (last0->dw_loc_opc != DW_OP_deref_size
-                      || last0->dw_loc_oprnd1.v.val_int
-                         > GET_MODE_SIZE (op_mode))
-               {
-                 add_loc_descr (&op0, int_loc_descriptor (mask));
-                 add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
-               }
-             if (CONST_INT_P (XEXP (rtl, 1)))
-               op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask);
-             /* deref_size zero extends, so no need to mask it again.  */
-             else if (last1->dw_loc_opc != DW_OP_deref_size
-                      || last1->dw_loc_oprnd1.v.val_int
-                         > GET_MODE_SIZE (op_mode))
-               {
-                 add_loc_descr (&op1, int_loc_descriptor (mask));
-                 add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
-               }
-           }
-         else
-           {
-             HOST_WIDE_INT bias = 1;
-             bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
-             add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
-             if (CONST_INT_P (XEXP (rtl, 1)))
-               op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias
-                                         + INTVAL (XEXP (rtl, 1)));
-             else
-               add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst,
-                                                   bias, 0));
-           }
-       }
+       op0 = mem_loc_descriptor (XEXP (rtl, 0), op_mode, mem_mode,
+                                 VAR_INIT_STATUS_INITIALIZED);
+       op1 = mem_loc_descriptor (XEXP (rtl, 1), op_mode, mem_mode,
+                                 VAR_INIT_STATUS_INITIALIZED);
+
+       if (op0 == 0 || op1 == 0)
+         break;
+
+       if (GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
+         {
+           HOST_WIDE_INT mask = GET_MODE_MASK (op_mode);
+           dw_loc_descr_ref last0, last1;
+           for (last0 = op0;
+                last0->dw_loc_next != NULL;
+                last0 = last0->dw_loc_next)
+             ;
+           for (last1 = op1;
+                last1->dw_loc_next != NULL;
+                last1 = last1->dw_loc_next)
+             ;
+           if (CONST_INT_P (XEXP (rtl, 0)))
+             op0 = int_loc_descriptor (INTVAL (XEXP (rtl, 0)) & mask);
+           /* deref_size zero extends, so no need to mask it again.  */
+           else if (last0->dw_loc_opc != DW_OP_deref_size
+                    || last0->dw_loc_oprnd1.v.val_int
+                       > GET_MODE_SIZE (op_mode))
+             {
+               add_loc_descr (&op0, int_loc_descriptor (mask));
+               add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+             }
+           if (CONST_INT_P (XEXP (rtl, 1)))
+             op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask);
+           /* deref_size zero extends, so no need to mask it again.  */
+           else if (last1->dw_loc_opc != DW_OP_deref_size
+                    || last1->dw_loc_oprnd1.v.val_int
+                       > GET_MODE_SIZE (op_mode))
+             {
+               add_loc_descr (&op1, int_loc_descriptor (mask));
+               add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
+             }
+         }
+       else if (GET_MODE_SIZE (op_mode) == DWARF2_ADDR_SIZE)
+         {
+           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));
+         }
+       else
+         {
+           dw_die_ref type_die = base_type_for_mode (mode, 1);
+           dw_loc_descr_ref cvt;
+
+           if (type_die == NULL)
+             break;
+           cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+           cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+           cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+           cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+           add_loc_descr (&op0, cvt);
+           cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+           cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+           cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+           cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+           add_loc_descr (&op1, cvt);
+         }
+      }
       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)))
+      if (GET_MODE_CLASS (mode) != MODE_INT)
+       break;
+      /* FALLTHRU */
+    case SMIN:
+    case SMAX:
+      if (dwarf_strict
+         && (GET_MODE_CLASS (mode) != MODE_INT
+             || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE))
        break;
 
-      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
                                VAR_INIT_STATUS_INITIALIZED);
-      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
                                VAR_INIT_STATUS_INITIALIZED);
 
       if (op0 == 0 || op1 == 0)
@@ -14020,26 +14636,44 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       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)
+         if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
            {
-             HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0)));
+             HOST_WIDE_INT mask = GET_MODE_MASK (mode);
              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
+         else if (GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE)
            {
              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
+           {
+             dw_die_ref type_die = base_type_for_mode (mode, 1);
+             dw_loc_descr_ref cvt;
+
+             if (type_die == NULL)
+               break;
+             cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+             cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+             cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+             cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+             add_loc_descr (&op0, cvt);
+             cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+             cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+             cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+             cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+             add_loc_descr (&op1, cvt);
+           }
        }
-      else if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+      else if (GET_MODE_CLASS (mode) == MODE_INT
+              && GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
        {
-         int shift = DWARF2_ADDR_SIZE
-                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+         int shift = DWARF2_ADDR_SIZE - GET_MODE_SIZE (mode);
          shift *= BITS_PER_UNIT;
          add_loc_descr (&op0, int_loc_descriptor (shift));
          add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
@@ -14073,13 +14707,14 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
          && 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)
+             <= GET_MODE_BITSIZE (mode))
+         && GET_MODE_CLASS (mode) == MODE_INT
+         && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE
+         && GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) <= DWARF2_ADDR_SIZE)
        {
          int shift, size;
-         op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                                   VAR_INIT_STATUS_INITIALIZED);
+         op0 = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (XEXP (rtl, 0)),
+                                   mem_mode, VAR_INIT_STATUS_INITIALIZED);
          if (op0 == 0)
            break;
          if (GET_CODE (rtl) == SIGN_EXTRACT)
@@ -14108,8 +14743,98 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
        }
       break;
 
-    case COMPARE:
     case IF_THEN_ELSE:
+      {
+       dw_loc_descr_ref op2, bra_node, drop_node;
+       op0 = mem_loc_descriptor (XEXP (rtl, 0),
+                                 GET_MODE (XEXP (rtl, 0)) == VOIDmode
+                                 ? word_mode : GET_MODE (XEXP (rtl, 0)),
+                                 mem_mode, VAR_INIT_STATUS_INITIALIZED);
+       op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
+                                 VAR_INIT_STATUS_INITIALIZED);
+       op2 = mem_loc_descriptor (XEXP (rtl, 2), mode, mem_mode,
+                                 VAR_INIT_STATUS_INITIALIZED);
+       if (op0 == NULL || op1 == NULL || op2 == NULL)
+         break;
+
+       mem_loc_result = op1;
+       add_loc_descr (&mem_loc_result, op2);
+       add_loc_descr (&mem_loc_result, op0);
+       bra_node = new_loc_descr (DW_OP_bra, 0, 0);
+       add_loc_descr (&mem_loc_result, bra_node);
+       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_swap, 0, 0));
+       drop_node = new_loc_descr (DW_OP_drop, 0, 0);
+       add_loc_descr (&mem_loc_result, drop_node);
+       bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+       bra_node->dw_loc_oprnd1.v.val_loc = drop_node;
+      }
+      break;
+
+    case FLOAT_EXTEND:
+    case FLOAT_TRUNCATE:
+    case FLOAT:
+    case UNSIGNED_FLOAT:
+    case FIX:
+    case UNSIGNED_FIX:
+      if (!dwarf_strict)
+       {
+         dw_die_ref type_die;
+         dw_loc_descr_ref cvt;
+
+         op0 = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (XEXP (rtl, 0)),
+                                   mem_mode, VAR_INIT_STATUS_INITIALIZED);
+         if (op0 == NULL)
+           break;
+         if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) == MODE_INT
+             && (GET_CODE (rtl) == UNSIGNED_FLOAT
+                 || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)))
+                    <= DWARF2_ADDR_SIZE))
+           {
+             type_die = base_type_for_mode (GET_MODE (XEXP (rtl, 0)),
+                                            GET_CODE (rtl) == UNSIGNED_FLOAT);
+             if (type_die == NULL)
+               break;
+             cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+             cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+             cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+             cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+             add_loc_descr (&op0, cvt);
+           }
+         type_die = base_type_for_mode (mode, GET_CODE (rtl) == UNSIGNED_FIX);
+         if (type_die == NULL)
+           break;
+         cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+         cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+         cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+         cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+         add_loc_descr (&op0, cvt);
+         if (GET_MODE_CLASS (mode) == MODE_INT
+             && (GET_CODE (rtl) == UNSIGNED_FIX
+                 || GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE))
+           {
+             enum machine_mode outer_mode = mode;
+             if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
+               {
+                 outer_mode = mode_for_size (DWARF2_ADDR_SIZE * BITS_PER_UNIT,
+                                             MODE_INT, 0);
+                 if (outer_mode == BLKmode
+                     || GET_MODE_SIZE (outer_mode) != DWARF2_ADDR_SIZE)
+                   break;
+               }
+             type_die = base_type_for_mode (outer_mode, 0);
+             if (type_die == NULL)
+               break;
+             cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+             cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+             cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+             cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+             add_loc_descr (&op0, cvt);
+           }
+         mem_loc_result = op0;
+       }
+      break;
+
+    case COMPARE:
     case ROTATE:
     case ROTATERT:
     case TRUNCATE:
@@ -14140,12 +14865,6 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
     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:
@@ -14164,6 +14883,10 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
     case VEC_DUPLICATE:
     case UNSPEC:
     case HIGH:
+    case FMA:
+    case STRICT_LOW_PART:
+    case CONST_VECTOR:
+    case CONST_FIXED:
       /* 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.  */
@@ -14244,9 +14967,40 @@ concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
   return cc_loc_result;
 }
 
-/* Output a proper Dwarf location descriptor for a variable or parameter
-   which is either allocated in a register or in a memory location.  For a
-   register, we just generate an OP_REG and the register number.  For a
+/* Helper function for loc_descriptor.  Return DW_OP_GNU_implicit_pointer
+   for DEBUG_IMPLICIT_PTR RTL.  */
+
+static dw_loc_descr_ref
+implicit_ptr_descriptor (rtx rtl, HOST_WIDE_INT offset)
+{
+  dw_loc_descr_ref ret;
+  dw_die_ref ref;
+
+  if (dwarf_strict)
+    return NULL;
+  gcc_assert (TREE_CODE (DEBUG_IMPLICIT_PTR_DECL (rtl)) == VAR_DECL
+             || TREE_CODE (DEBUG_IMPLICIT_PTR_DECL (rtl)) == PARM_DECL
+             || TREE_CODE (DEBUG_IMPLICIT_PTR_DECL (rtl)) == RESULT_DECL);
+  ref = lookup_decl_die (DEBUG_IMPLICIT_PTR_DECL (rtl));
+  ret = new_loc_descr (DW_OP_GNU_implicit_pointer, 0, offset);
+  ret->dw_loc_oprnd2.val_class = dw_val_class_const;
+  if (ref)
+    {
+      ret->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+      ret->dw_loc_oprnd1.v.val_die_ref.die = ref;
+      ret->dw_loc_oprnd1.v.val_die_ref.external = 0;
+    }
+  else
+    {
+      ret->dw_loc_oprnd1.val_class = dw_val_class_decl_ref;
+      ret->dw_loc_oprnd1.v.val_decl_ref = DEBUG_IMPLICIT_PTR_DECL (rtl);
+    }
+  return ret;
+}
+
+/* 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.
 
@@ -14270,7 +15024,10 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
         up an entire register.  For now, just assume that it is
         legitimate to make the Dwarf info refer to the whole register which
         contains the given subreg.  */
-      loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized);
+      if (REG_P (SUBREG_REG (rtl)) && subreg_lowpart_p (rtl))
+       loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized);
+      else
+       goto do_default;
       break;
 
     case REG:
@@ -14278,8 +15035,8 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
       break;
 
     case MEM:
-      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
-                                      initialized);
+      loc_result = mem_loc_descriptor (XEXP (rtl, 0), get_address_mode (rtl),
+                                      GET_MODE (rtl), initialized);
       if (loc_result == NULL)
        loc_result = tls_mem_loc_descriptor (rtl);
       if (loc_result == NULL)
@@ -14461,13 +15218,28 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
        }
       break;
 
+    case DEBUG_IMPLICIT_PTR:
+      loc_result = implicit_ptr_descriptor (rtl, 0);
+      break;
+
+    case PLUS:
+      if (GET_CODE (XEXP (rtl, 0)) == DEBUG_IMPLICIT_PTR
+         && CONST_INT_P (XEXP (rtl, 1)))
+       {
+         loc_result
+           = implicit_ptr_descriptor (XEXP (rtl, 0), INTVAL (XEXP (rtl, 1)));
+         break;
+       }
+      /* FALLTHRU */
+    do_default:
     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))
+      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 && mode != VOIDmode && mode != BLKmode))
        {
          /* Value expression.  */
-         loc_result = mem_loc_descriptor (rtl, VOIDmode, initialized);
+         loc_result = mem_loc_descriptor (rtl, mode, VOIDmode, initialized);
          if (loc_result)
            add_loc_descr (&loc_result,
                           new_loc_descr (DW_OP_stack_value, 0, 0));
@@ -14542,18 +15314,20 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address,
          if (MEM_P (varloc))
            {
              rtx addr = XEXP (varloc, 0);
-             descr = mem_loc_descriptor (addr, mode, initialized);
+             descr = mem_loc_descriptor (addr, get_address_mode (varloc),
+                                         mode, initialized);
              if (descr)
                have_address = 1;
              else
                {
                  rtx x = avoid_constant_pool_reference (varloc);
                  if (x != varloc)
-                   descr = mem_loc_descriptor (x, mode, initialized);
+                   descr = mem_loc_descriptor (x, mode, VOIDmode,
+                                               initialized);
                }
            }
          else
-           descr = mem_loc_descriptor (varloc, mode, initialized);
+           descr = mem_loc_descriptor (varloc, mode, VOIDmode, initialized);
        }
       else
        return 0;
@@ -14824,9 +15598,23 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
          }
        if (descr)
          {
+           bool range_across_switch = false;
+           /* If section switch happens in between node->label
+              and node->next->label (or end of function) and
+              we can't emit it as a single entry list,
+              emit two ranges, first one ending at the end
+              of first partition and second one starting at the
+              beginning of second partition.  */
+           if (node == loc_list->last_before_switch
+               && (node != loc_list->first || loc_list->first->next)
+               && current_function_decl)
+             {
+               endname = current_fde ()->dw_fde_end;
+               range_across_switch = true;
+             }
            /* The variable has a location between NODE->LABEL and
               NODE->NEXT->LABEL.  */
-           if (node->next)
+           else if (node->next)
              endname = node->next->label;
            /* If the variable has a location at the last label
               it keeps its location until the end of function.  */
@@ -14841,6 +15629,30 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
 
            *listp = new_loc_list (descr, node->label, endname, secname);
            listp = &(*listp)->dw_loc_next;
+
+           if (range_across_switch)
+             {
+               if (GET_CODE (node->loc) == EXPR_LIST)
+                 descr = dw_sra_loc_expr (decl, node->loc);
+               else
+                 {
+                   initialized = NOTE_VAR_LOCATION_STATUS (node->loc);
+                   varloc = NOTE_VAR_LOCATION (node->loc);
+                   descr = dw_loc_list_1 (decl, varloc, want_address,
+                                          initialized);
+                 }
+               gcc_assert (descr);
+               /* The variable has a location between NODE->LABEL and
+                  NODE->NEXT->LABEL.  */
+               if (node->next)
+                 endname = node->next->label;
+               else
+                 endname = current_fde ()->dw_fde_second_end;
+               *listp = new_loc_list (descr,
+                                      current_fde ()->dw_fde_second_begin,
+                                      endname, secname);
+               listp = &(*listp)->dw_loc_next;
+             }
          }
       }
 
@@ -14937,7 +15749,6 @@ 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;
 
   if (!rtl || !MEM_P (rtl))
     {
@@ -14955,9 +15766,8 @@ cst_pool_loc_descr (tree loc)
                        "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);
+  return mem_loc_descriptor (XEXP (rtl, 0), get_address_mode (rtl),
+                            GET_MODE (rtl), VAR_INIT_STATUS_INITIALIZED);
 }
 
 /* Return dw_loc_list representing address of addr_expr LOC
@@ -15159,12 +15969,12 @@ loc_list_from_tree (tree loc, int want_address)
       /* FALLTHRU */
 
     case PARM_DECL:
+    case RESULT_DECL:
       if (DECL_HAS_VALUE_EXPR_P (loc))
        return loc_list_from_tree (DECL_VALUE_EXPR (loc),
                                   want_address);
       /* FALLTHRU */
 
-    case RESULT_DECL:
     case FUNCTION_DECL:
       {
        rtx rtl;
@@ -15202,7 +16012,7 @@ loc_list_from_tree (tree loc, int want_address)
          }
        else
          {
-           enum machine_mode mode;
+           enum machine_mode mode, mem_mode;
 
            /* Certain constructs can only be represented at top-level.  */
            if (want_address == 2)
@@ -15214,12 +16024,16 @@ loc_list_from_tree (tree loc, int want_address)
            else
              {
                mode = GET_MODE (rtl);
+               mem_mode = VOIDmode;
                if (MEM_P (rtl))
                  {
+                   mem_mode = mode;
+                   mode = get_address_mode (rtl);
                    rtl = XEXP (rtl, 0);
                    have_address = 1;
                  }
-               ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
+               ret = mem_loc_descriptor (rtl, mode, mem_mode,
+                                         VAR_INIT_STATUS_INITIALIZED);
              }
            if (!ret)
              expansion_failed (loc, rtl,
@@ -15234,7 +16048,6 @@ loc_list_from_tree (tree loc, int want_address)
        return 0;
       /* Fallthru.  */
     case INDIRECT_REF:
-    case MISALIGNED_INDIRECT_REF:
       list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
       have_address = 1;
       break;
@@ -15847,10 +16660,22 @@ add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
 static void
 add_accessibility_attribute (dw_die_ref die, tree decl)
 {
+  /* In DWARF3+ the default is DW_ACCESS_private only in DW_TAG_class_type
+     children, otherwise the default is DW_ACCESS_public.  In DWARF2
+     the default has always been DW_ACCESS_public.  */
   if (TREE_PROTECTED (decl))
     add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected);
   else if (TREE_PRIVATE (decl))
-    add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_private);
+    {
+      if (dwarf_version == 2
+         || die->die_parent == NULL
+         || die->die_parent->die_tag != DW_TAG_class_type)
+       add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_private);
+    }
+  else if (dwarf_version > 2
+          && die->die_parent
+          && die->die_parent->die_tag == DW_TAG_class_type)
+    add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
 }
 
 /* Attach the specialized form of location attribute used for data members of
@@ -16228,6 +17053,8 @@ rtl_for_decl_init (tree init, tree type)
 {
   rtx rtl = NULL_RTX;
 
+  STRIP_NOPS (init);
+
   /* If a variable is initialized with a string constant without embedded
      zeros, build CONST_STRING.  */
   if (TREE_CODE (init) == STRING_CST && TREE_CODE (type) == ARRAY_TYPE)
@@ -16252,11 +17079,15 @@ rtl_for_decl_init (tree init, tree type)
     }
   /* Other aggregates, and complex values, could be represented using
      CONCAT: FIXME!  */
-  else if (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
+  else if (AGGREGATE_TYPE_P (type)
+          || (TREE_CODE (init) == VIEW_CONVERT_EXPR
+              && AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (init, 0))))
+          || TREE_CODE (type) == COMPLEX_TYPE)
     ;
   /* Vectors only work if their mode is supported by the target.
      FIXME: generic vectors ought to work too.  */
-  else if (TREE_CODE (type) == VECTOR_TYPE && TYPE_MODE (type) == BLKmode)
+  else if (TREE_CODE (type) == VECTOR_TYPE
+          && !VECTOR_MODE_P (TYPE_MODE (type)))
     ;
   /* If the initializer is something that we know will expand into an
      immediate RTL constant, expand it now.  We must be careful not to
@@ -16410,7 +17241,13 @@ rtl_for_decl_location (tree decl)
     }
   else if (TREE_CODE (decl) == PARM_DECL)
     {
-      if (rtl == NULL_RTX || is_pseudo_reg (rtl))
+      if (rtl == NULL_RTX
+         || is_pseudo_reg (rtl)
+         || (MEM_P (rtl)
+             && is_pseudo_reg (XEXP (rtl, 0))
+             && DECL_INCOMING_RTL (decl)
+             && MEM_P (DECL_INCOMING_RTL (decl))
+             && GET_MODE (rtl) == GET_MODE (DECL_INCOMING_RTL (decl))))
        {
          tree declared_type = TREE_TYPE (decl);
          tree passed_type = DECL_ARG_TYPE (decl);
@@ -16422,7 +17259,8 @@ rtl_for_decl_location (tree decl)
             all cases where (rtl == NULL_RTX) just below.  */
          if (dmode == pmode)
            rtl = DECL_INCOMING_RTL (decl);
-         else if (SCALAR_INT_MODE_P (dmode)
+         else if ((rtl == NULL_RTX || is_pseudo_reg (rtl))
+                  && SCALAR_INT_MODE_P (dmode)
                   && GET_MODE_SIZE (dmode) <= GET_MODE_SIZE (pmode)
                   && DECL_INCOMING_RTL (decl))
            {
@@ -16457,7 +17295,7 @@ rtl_for_decl_location (tree decl)
               && (!REG_P (XEXP (rtl, 0))
                   || REGNO (XEXP (rtl, 0)) == HARD_FRAME_POINTER_REGNUM
                   || REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM
-#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_ARG_POINTER
                   || REGNO (XEXP (rtl, 0)) == ARG_POINTER_REGNUM
 #endif
                     )
@@ -16588,15 +17426,22 @@ fortran_common (tree decl, HOST_WIDE_INT *value)
    these things can crop up in other ways also.)  Note that one type of
    constant value which can be passed into an inlined function is a constant
    pointer.  This can happen for example if an actual argument in an inlined
-   function call evaluates to a compile-time constant address.  */
+   function call evaluates to a compile-time constant address.
+
+   CACHE_P is true if it is worth caching the location list for DECL,
+   so that future calls can reuse it rather than regenerate it from scratch.
+   This is true for BLOCK_NONLOCALIZED_VARS in inlined subroutines,
+   since we will need to refer to them each time the function is inlined.  */
 
 static bool
-add_location_or_const_value_attribute (dw_die_ref die, tree decl,
+add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p,
                                       enum dwarf_attribute attr)
 {
   rtx rtl;
   dw_loc_list_ref list;
   var_loc_list *loc_list;
+  cached_dw_loc_list *cache;
+  void **slot;
 
   if (TREE_CODE (decl) == ERROR_MARK)
     return false;
@@ -16633,7 +17478,33 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
          && add_const_value_attribute (die, rtl))
         return true;
     }
-  list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2);
+  /* If this decl is from BLOCK_NONLOCALIZED_VARS, we might need its
+     list several times.  See if we've already cached the contents.  */
+  list = NULL;
+  if (loc_list == NULL || cached_dw_loc_list_table == NULL)
+    cache_p = false;
+  if (cache_p)
+    {
+      cache = (cached_dw_loc_list *)
+       htab_find_with_hash (cached_dw_loc_list_table, decl, DECL_UID (decl));
+      if (cache)
+       list = cache->loc_list;
+    }
+  if (list == NULL)
+    {
+      list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2);
+      /* It is usually worth caching this result if the decl is from
+        BLOCK_NONLOCALIZED_VARS and if the list has at least two elements.  */
+      if (cache_p && list && list->dw_loc_next)
+       {
+         slot = htab_find_slot_with_hash (cached_dw_loc_list_table, decl,
+                                          DECL_UID (decl), INSERT);
+         cache = ggc_alloc_cleared_cached_dw_loc_list ();
+         cache->decl_id = DECL_UID (decl);
+         cache->loc_list = list;
+         *slot = cache;
+       }
+    }
   if (list)
     {
       add_AT_location_description (die, attr, list);
@@ -16713,9 +17584,7 @@ native_encode_initializer (tree init, unsigned char *array, int size)
 
          min_index = tree_low_cst (TYPE_MIN_VALUE (TYPE_DOMAIN (type)), 0);
          memset (array, '\0', size);
-         for (cnt = 0;
-              VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (init), cnt, ce);
-              cnt++)
+         FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (init), cnt, ce)
            {
              tree val = ce->value;
              tree index = ce->index;
@@ -16761,9 +17630,7 @@ native_encode_initializer (tree init, unsigned char *array, int size)
          if (TREE_CODE (type) == RECORD_TYPE)
            field = TYPE_FIELDS (type);
 
-         for (cnt = 0;
-              VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (init), cnt, ce);
-              cnt++, field = field ? DECL_CHAIN (field) : 0)
+         FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (init), cnt, ce)
            {
              tree val = ce->value;
              int pos, fieldsize;
@@ -16852,7 +17719,9 @@ 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))
+         && TREE_CODE (decl) != CONST_DECL)
+      || (TREE_CODE (decl) == VAR_DECL
+         && !TREE_STATIC (decl)))
     return false;
 
     if (TREE_READONLY (decl)
@@ -16878,6 +17747,7 @@ tree_add_const_value_attribute_for_decl (dw_die_ref var_die, tree decl)
 static dw_loc_list_ref
 convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
 {
+  int ix;
   dw_fde_ref fde;
   dw_loc_list_ref list, *list_tail;
   dw_cfi_ref cfi;
@@ -16900,39 +17770,67 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
 
   /* ??? Bald assumption that the CIE opcode list does not contain
      advance opcodes.  */
-  for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
+  FOR_EACH_VEC_ELT (dw_cfi_ref, cie_cfi_vec, ix, cfi)
     lookup_cfa_1 (cfi, &next_cfa, &remember);
 
   last_cfa = next_cfa;
   last_label = start_label;
 
-  for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
-    switch (cfi->dw_cfi_opc)
-      {
-      case DW_CFA_set_loc:
-      case DW_CFA_advance_loc1:
-      case DW_CFA_advance_loc2:
-      case DW_CFA_advance_loc4:
-       if (!cfa_equal_p (&last_cfa, &next_cfa))
-         {
-           *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
-                                      start_label, last_label, section);
+  if (fde->dw_fde_second_begin && fde->dw_fde_switch_cfi_index == 0)
+    {
+      /* If the first partition contained no CFI adjustments, the
+        CIE opcodes apply to the whole first partition.  */
+      *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
+                                fde->dw_fde_begin, fde->dw_fde_end, section);
+      list_tail =&(*list_tail)->dw_loc_next;
+      start_label = last_label = fde->dw_fde_second_begin;
+    }
 
-           list_tail = &(*list_tail)->dw_loc_next;
-           last_cfa = next_cfa;
-           start_label = last_label;
-         }
-       last_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
-       break;
+  FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi)
+    {
+      switch (cfi->dw_cfi_opc)
+       {
+       case DW_CFA_set_loc:
+       case DW_CFA_advance_loc1:
+       case DW_CFA_advance_loc2:
+       case DW_CFA_advance_loc4:
+         if (!cfa_equal_p (&last_cfa, &next_cfa))
+           {
+             *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
+                                        start_label, last_label, section);
 
-      case DW_CFA_advance_loc:
-       /* The encoding is complex enough that we should never emit this.  */
-       gcc_unreachable ();
+             list_tail = &(*list_tail)->dw_loc_next;
+             last_cfa = next_cfa;
+             start_label = last_label;
+           }
+         last_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+         break;
 
-      default:
-       lookup_cfa_1 (cfi, &next_cfa, &remember);
-       break;
-      }
+       case DW_CFA_advance_loc:
+         /* The encoding is complex enough that we should never emit this.  */
+         gcc_unreachable ();
+
+       default:
+         lookup_cfa_1 (cfi, &next_cfa, &remember);
+         break;
+       }
+      if (ix + 1 == fde->dw_fde_switch_cfi_index)
+       {
+         if (!cfa_equal_p (&last_cfa, &next_cfa))
+           {
+             *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
+                                        start_label, last_label, section);
+
+             list_tail = &(*list_tail)->dw_loc_next;
+             last_cfa = next_cfa;
+             start_label = last_label;
+           }
+         *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
+                                    start_label, fde->dw_fde_end, section);
+         list_tail = &(*list_tail)->dw_loc_next;
+         start_label = last_label = fde->dw_fde_second_begin;
+       }
+    }
 
   if (!cfa_equal_p (&last_cfa, &next_cfa))
     {
@@ -16943,7 +17841,10 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
     }
 
   *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
-                            start_label, fde->dw_fde_end, section);
+                            start_label,
+                            fde->dw_fde_second_begin
+                            ? fde->dw_fde_second_end : fde->dw_fde_end,
+                            section);
 
   if (list && list->dw_loc_next)
     gen_llsym (list);
@@ -17001,6 +17902,38 @@ add_name_attribute (dw_die_ref die, const char *name_string)
     }
 }
 
+/* Retrieve the descriptive type of TYPE, if any, make sure it has a
+   DIE and attach a DW_AT_GNAT_descriptive_type attribute to the DIE
+   of TYPE accordingly.
+
+   ??? This is a temporary measure until after we're able to generate
+   regular DWARF for the complex Ada type system.  */
+
+static void 
+add_gnat_descriptive_type_attribute (dw_die_ref die, tree type,
+                                    dw_die_ref context_die)
+{
+  tree dtype;
+  dw_die_ref dtype_die;
+
+  if (!lang_hooks.types.descriptive_type)
+    return;
+
+  dtype = lang_hooks.types.descriptive_type (type);
+  if (!dtype)
+    return;
+
+  dtype_die = lookup_type_die (dtype);
+  if (!dtype_die)
+    {
+      gen_type_die (dtype, context_die);
+      dtype_die = lookup_type_die (dtype);
+      gcc_assert (dtype_die);
+    }
+
+  add_AT_die_ref (die, DW_AT_GNAT_descriptive_type, dtype_die);
+}
+
 /* Generate a DW_AT_comp_dir attribute for DIE.  */
 
 static void
@@ -17033,7 +17966,7 @@ add_comp_dir_attribute (dw_die_ref die)
 static int
 lower_bound_default (void)
 {
-  switch (get_AT_unsigned (comp_unit_die, DW_AT_language))
+  switch (get_AT_unsigned (comp_unit_die (), DW_AT_language))
     {
     case DW_LANG_C:
     case DW_LANG_C89:
@@ -17162,7 +18095,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
          break;
 
        if (current_function_decl == 0)
-         ctx = comp_unit_die;
+         ctx = comp_unit_die ();
        else
          ctx = lookup_decl_die (current_function_decl);
 
@@ -17299,7 +18232,7 @@ add_bit_offset_attribute (dw_die_ref die, tree decl)
   HOST_WIDE_INT bitpos_int;
   HOST_WIDE_INT highest_order_object_bit_offset;
   HOST_WIDE_INT highest_order_field_bit_offset;
-  HOST_WIDE_INT unsigned bit_offset;
+  HOST_WIDE_INT bit_offset;
 
   /* Must be a field and a bit field.  */
   gcc_assert (type && TREE_CODE (decl) == FIELD_DECL);
@@ -17332,7 +18265,10 @@ add_bit_offset_attribute (dw_die_ref die, tree decl)
        ? highest_order_object_bit_offset - highest_order_field_bit_offset
        : highest_order_field_bit_offset - highest_order_object_bit_offset);
 
-  add_AT_unsigned (die, DW_AT_bit_offset, bit_offset);
+  if (bit_offset < 0)
+    add_AT_int (die, DW_AT_bit_offset, bit_offset);
+  else
+    add_AT_unsigned (die, DW_AT_bit_offset, (unsigned HOST_WIDE_INT) bit_offset);
 }
 
 /* For a FIELD_DECL node which represents a bit field, output an attribute
@@ -17355,8 +18291,8 @@ add_bit_size_attribute (dw_die_ref die, tree decl)
 static inline void
 add_prototyped_attribute (dw_die_ref die, tree func_type)
 {
-  if (get_AT_unsigned (comp_unit_die, DW_AT_language) == DW_LANG_C89
-      && TYPE_ARG_TYPES (func_type) != NULL)
+  if (get_AT_unsigned (comp_unit_die (), DW_AT_language) == DW_LANG_C89
+      && prototype_p (func_type))
     add_AT_flag (die, DW_AT_prototyped, 1);
 }
 
@@ -17453,8 +18389,11 @@ add_linkage_attr (dw_die_ref die, tree decl)
 static void
 add_src_coords_attributes (dw_die_ref die, tree decl)
 {
-  expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+  expanded_location s;
 
+  if (DECL_SOURCE_LOCATION (decl) == UNKNOWN_LOCATION)
+    return;
+  s = expand_location (DECL_SOURCE_LOCATION (decl));
   add_AT_file (die, DW_AT_decl_file, lookup_filename (s.file));
   add_AT_unsigned (die, DW_AT_decl_line, s.line);
 }
@@ -17535,17 +18474,17 @@ dwarf2out_vms_debug_main_pointer (void)
                               current_function_funcdef_no);
   add_AT_lbl_id (die, DW_AT_entry_pc, label);
 
-  /* Make it the first child of comp_unit_die.  */
-  die->die_parent = comp_unit_die;
-  if (comp_unit_die->die_child)
+  /* Make it the first child of comp_unit_die ().  */
+  die->die_parent = comp_unit_die ();
+  if (comp_unit_die ()->die_child)
     {
-      die->die_sib = comp_unit_die->die_child->die_sib;
-      comp_unit_die->die_child->die_sib = die;
+      die->die_sib = comp_unit_die ()->die_child->die_sib;
+      comp_unit_die ()->die_child->die_sib = die;
     }
   else
     {
       die->die_sib = die;
-      comp_unit_die->die_child = die;
+      comp_unit_die ()->die_child = die;
     }
 }
 #endif /* VMS_DEBUGGING_INFO */
@@ -17599,8 +18538,8 @@ scope_die_for (tree t, dw_die_ref context_die)
   if (containing_scope && TREE_CODE (containing_scope) == FUNCTION_TYPE)
     containing_scope = NULL_TREE;
 
-  if (containing_scope == NULL_TREE)
-    scope_die = comp_unit_die;
+  if (SCOPE_FILE_SCOPE_P (containing_scope))
+    scope_die = comp_unit_die ();
   else if (TYPE_P (containing_scope))
     {
       /* For types, we can just look up the appropriate DIE.  But
@@ -17620,10 +18559,10 @@ scope_die_for (tree t, dw_die_ref context_die)
 
          /* If none of the current dies are suitable, we get file scope.  */
          if (scope_die == NULL)
-           scope_die = comp_unit_die;
+           scope_die = comp_unit_die ();
        }
       else
-       scope_die = lookup_type_die (containing_scope);
+       scope_die = lookup_type_die_strip_naming_typedef (containing_scope);
     }
   else
     scope_die = context_die;
@@ -17711,14 +18650,21 @@ add_calling_convention_attribute (dw_die_ref subr_die, tree decl)
   value = ((enum dwarf_calling_convention)
           targetm.dwarf_calling_convention (TREE_TYPE (decl)));
 
-  /* DWARF doesn't provide a way to identify a program's source-level
-     entry point.  DW_AT_calling_convention attributes are only meant
-     to describe functions' calling conventions.  However, lacking a
-     better way to signal the Fortran main program, we use this for the
-     time being, following existing custom.  */
   if (is_fortran ()
       && !strcmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), "MAIN__"))
-    value = DW_CC_program;
+    {
+      /* DWARF 2 doesn't provide a way to identify a program's source-level
+       entry point.  DW_AT_calling_convention attributes are only meant
+       to describe functions' calling conventions.  However, lacking a
+       better way to signal the Fortran main program, we used this for 
+       a long time, following existing custom.  Now, DWARF 4 has 
+       DW_AT_main_subprogram, which we add below, but some tools still
+       rely on the old way, which we thus keep.  */
+      value = DW_CC_program;
+
+      if (dwarf_version >= 4 || !dwarf_strict)
+       add_AT_flag (subr_die, DW_AT_main_subprogram, 1);
+    }
 
   /* Only add the attribute if the backend requests it, and
      is not DW_CC_normal.  */
@@ -17867,15 +18813,11 @@ gen_array_type_die (tree type, dw_die_ref context_die)
 
   array_die = new_die (DW_TAG_array_type, scope_die, type);
   add_name_attribute (array_die, type_tag (type));
+  add_gnat_descriptive_type_attribute (array_die, type, context_die);
   equate_type_number_to_die (type, array_die);
 
   if (TREE_CODE (type) == VECTOR_TYPE)
-    {
-      /* The frontend feeds us a representation for the vector as a struct
-        containing an array.  Pull out the array type.  */
-      type = TREE_TYPE (TYPE_FIELDS (TYPE_DEBUG_REPRESENTATION_TYPE (type)));
-      add_AT_flag (array_die, DW_AT_GNU_vector, 1);
-    }
+    add_AT_flag (array_die, DW_AT_GNU_vector, 1);
 
   /* For Fortran multidimensional arrays use DW_ORD_col_major ordering.  */
   if (is_fortran ()
@@ -17898,10 +18840,20 @@ gen_array_type_die (tree type, dw_die_ref context_die)
 #ifdef MIPS_DEBUGGING_INFO
   /* The SGI compilers handle arrays of unknown bound by setting
      AT_declaration and not emitting any subrange DIEs.  */
-  if (! TYPE_DOMAIN (type))
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && ! TYPE_DOMAIN (type))
     add_AT_flag (array_die, DW_AT_declaration, 1);
   else
 #endif
+  if (TREE_CODE (type) == VECTOR_TYPE)
+    {
+      /* For VECTOR_TYPEs we use an array die with appropriate bounds.  */
+      dw_die_ref subrange_die = new_die (DW_TAG_subrange_type, array_die, NULL);
+      add_bound_info (subrange_die, DW_AT_lower_bound, size_zero_node);
+      add_bound_info (subrange_die, DW_AT_upper_bound,
+                     size_int (TYPE_VECTOR_SUBPARTS (type) - 1));
+    }
+  else
     add_subscript_info (array_die, type, collapse_nested_arrays);
 
   /* Add representation of the type of the elements of this array type and
@@ -18119,7 +19071,7 @@ retry_incomplete_types (void)
   for (i = VEC_length (tree, incomplete_types) - 1; i >= 0; i--)
     if (should_emit_struct_debug (VEC_index (tree, incomplete_types, i),
                                  DINFO_USAGE_DIR_USE))
-      gen_type_die (VEC_index (tree, incomplete_types, i), comp_unit_die);
+      gen_type_die (VEC_index (tree, incomplete_types, i), comp_unit_die ());
 }
 
 /* Determine what tag to use for a record type.  */
@@ -18164,9 +19116,14 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die)
                          scope_die_for (type, context_die), type);
       equate_type_number_to_die (type, type_die);
       add_name_attribute (type_die, type_tag (type));
-      if ((dwarf_version >= 4 || !dwarf_strict)
-         && ENUM_IS_SCOPED (type))
-       add_AT_flag (type_die, DW_AT_enum_class, 1);
+      add_gnat_descriptive_type_attribute (type_die, type, context_die);
+      if (dwarf_version >= 4 || !dwarf_strict)
+       {
+         if (ENUM_IS_SCOPED (type))
+           add_AT_flag (type_die, DW_AT_enum_class, 1);
+         if (ENUM_IS_OPAQUE (type))
+           add_AT_flag (type_die, DW_AT_declaration, 1);
+       }
     }
   else if (! TYPE_SIZE (type))
     return type_die;
@@ -18282,7 +19239,7 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
         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,
-                                              DW_AT_location);
+                                              node == NULL, DW_AT_location);
 
       break;
 
@@ -18434,7 +19391,7 @@ gen_type_die_for_member (tree type, tree member, dw_die_ref context_die)
       gcc_assert (!decl_ultimate_origin (member));
 
       push_decl_scope (type);
-      type_die = lookup_type_die (type);
+      type_die = lookup_type_die_strip_naming_typedef (type);
       if (TREE_CODE (member) == FUNCTION_DECL)
        gen_subprogram_die (member, type_die);
       else if (TREE_CODE (member) == FIELD_DECL)
@@ -18467,6 +19424,9 @@ dwarf2out_abstract_function (tree decl)
   tree context;
   int was_abstract;
   htab_t old_decl_loc_table;
+  htab_t old_cached_dw_loc_list_table;
+  int old_call_site_count, old_tail_call_site_count;
+  struct call_arg_loc_node *old_call_arg_locations;
 
   /* Make sure we have the actual abstract inline, not a clone.  */
   decl = DECL_ORIGIN (decl);
@@ -18481,6 +19441,14 @@ dwarf2out_abstract_function (tree decl)
      get locations in abstract instantces.  */
   old_decl_loc_table = decl_loc_table;
   decl_loc_table = NULL;
+  old_cached_dw_loc_list_table = cached_dw_loc_list_table;
+  cached_dw_loc_list_table = NULL;
+  old_call_arg_locations = call_arg_locations;
+  call_arg_locations = NULL;
+  old_call_site_count = call_site_count;
+  call_site_count = -1;
+  old_tail_call_site_count = tail_call_site_count;
+  tail_call_site_count = -1;
 
   /* Be sure we've emitted the in-class declaration DIE (if any) first, so
      we don't get confused by DECL_ABSTRACT.  */
@@ -18489,7 +19457,7 @@ dwarf2out_abstract_function (tree decl)
       context = decl_class_context (decl);
       if (context)
        gen_type_die_for_member
-         (context, decl, decl_function_context (decl) ? NULL : comp_unit_die);
+         (context, decl, decl_function_context (decl) ? NULL : comp_unit_die ());
     }
 
   /* Pretend we've just finished compiling this function.  */
@@ -18505,6 +19473,10 @@ dwarf2out_abstract_function (tree decl)
 
   current_function_decl = save_fn;
   decl_loc_table = old_decl_loc_table;
+  cached_dw_loc_list_table = old_cached_dw_loc_list_table;
+  call_arg_locations = old_call_arg_locations;
+  call_site_count = old_call_site_count;
+  tail_call_site_count = old_tail_call_site_count;
   pop_cfun ();
 }
 
@@ -18580,16 +19552,51 @@ premark_types_used_by_global_vars (void)
                   premark_types_used_by_global_vars_helper, NULL);
 }
 
+/* Generate a DW_TAG_GNU_call_site DIE in function DECL under SUBR_DIE
+   for CA_LOC call arg loc node.  */
+
+static dw_die_ref
+gen_call_site_die (tree decl, dw_die_ref subr_die,
+                  struct call_arg_loc_node *ca_loc)
+{
+  dw_die_ref stmt_die = NULL, die;
+  tree block = ca_loc->block;
+
+  while (block
+        && block != DECL_INITIAL (decl)
+        && TREE_CODE (block) == BLOCK)
+    {
+      if (VEC_length (dw_die_ref, block_map) > BLOCK_NUMBER (block))
+       stmt_die = VEC_index (dw_die_ref, block_map, BLOCK_NUMBER (block));
+      if (stmt_die)
+       break;
+      block = BLOCK_SUPERCONTEXT (block);
+    }
+  if (stmt_die == NULL)
+    stmt_die = subr_die;
+  die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE);
+  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label);
+  if (ca_loc->tail_call_p)
+    add_AT_flag (die, DW_AT_GNU_tail_call, 1);
+  if (ca_loc->symbol_ref)
+    {
+      dw_die_ref tdie = lookup_decl_die (SYMBOL_REF_DECL (ca_loc->symbol_ref));
+      if (tdie)
+       add_AT_die_ref (die, DW_AT_abstract_origin, tdie);
+      else
+       add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref);
+    }
+  return die;
+}
+
 /* Generate a DIE to represent a declared function (either file-scope or
    block-local).  */
 
 static void
 gen_subprogram_die (tree decl, dw_die_ref context_die)
 {
-  char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
   tree origin = decl_ultimate_origin (decl);
   dw_die_ref subr_die;
-  tree fn_arg_types;
   tree outer_scope;
   dw_die_ref old_die = lookup_decl_die (decl);
   int declaration = (current_function_decl != decl
@@ -18653,7 +19660,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
         instances of inlines, since the spec requires the out-of-line copy
         to have the same parent.  For local class methods, this doesn't
         apply; we just use the old DIE.  */
-      if ((old_die->die_parent == comp_unit_die || context_die == NULL)
+      if ((is_cu_die (old_die->die_parent) || context_die == NULL)
          && (DECL_ARTIFICIAL (decl)
              || (get_AT_file (old_die, DW_AT_decl_file) == file_index
                  && (get_AT_unsigned (old_die, DW_AT_decl_line)
@@ -18756,12 +19763,24 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 
       if (!flag_reorder_blocks_and_partition)
        {
-         ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
-                                      current_function_funcdef_no);
-         add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
-         ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
-                                      current_function_funcdef_no);
-         add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
+         dw_fde_ref fde = &fde_table[current_funcdef_fde];
+         if (fde->dw_fde_begin)
+           {
+             /* We have already generated the labels.  */
+             add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin);
+             add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end);
+           }
+         else
+           {
+             /* Create start/end labels and add the range.  */
+             char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
+             ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
+                                          current_function_funcdef_no);
+             add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
+             ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+                                          current_function_funcdef_no);
+             add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
+           }
 
 #if VMS_DEBUGGING_INFO
       /* HP OpenVMS Industry Standard 64: DWARF Extensions
@@ -18777,8 +19796,6 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
         attributes allow a compiler to communicate the location(s) to use.  */
 
       {
-        dw_fde_ref fde = &fde_table[current_funcdef_fde];
-
         if (fde->dw_fde_vms_end_prologue)
           add_AT_vms_delta (subr_die, DW_AT_HP_prologue,
            fde->dw_fde_begin, fde->dw_fde_vms_end_prologue);
@@ -18790,22 +19807,87 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 #endif
 
          add_pubname (decl, subr_die);
-         add_arange (decl, subr_die);
        }
       else
-       {  /* Do nothing for now; maybe need to duplicate die, one for
-             hot section and one for cold section, then use the hot/cold
-             section begin/end labels to generate the aranges...  */
-         /*
-           add_AT_lbl_id (subr_die, DW_AT_low_pc, hot_section_label);
-           add_AT_lbl_id (subr_die, DW_AT_high_pc, hot_section_end_label);
-           add_AT_lbl_id (subr_die, DW_AT_lo_user, unlikely_section_label);
-           add_AT_lbl_id (subr_die, DW_AT_hi_user, cold_section_end_label);
-
-           add_pubname (decl, subr_die);
-           add_arange (decl, subr_die);
-           add_arange (decl, subr_die);
-          */
+       {  /* Generate pubnames entries for the split function code
+             ranges.  */
+         dw_fde_ref fde = &fde_table[current_funcdef_fde];
+
+         if (fde->dw_fde_second_begin)
+           {
+             if (dwarf_version >= 3 || !dwarf_strict)
+               {
+                 /* We should use ranges for non-contiguous code section 
+                    addresses.  Use the actual code range for the initial
+                    section, since the HOT/COLD labels might precede an 
+                    alignment offset.  */
+                 bool range_list_added = false;
+                 add_ranges_by_labels (subr_die, fde->dw_fde_begin,
+                                       fde->dw_fde_end, &range_list_added);
+                 add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
+                                       fde->dw_fde_second_end,
+                                       &range_list_added);
+                 add_pubname (decl, subr_die);
+                 if (range_list_added)
+                   add_ranges (NULL);
+               }
+             else
+               {
+                 /* There is no real support in DW2 for this .. so we make
+                    a work-around.  First, emit the pub name for the segment
+                    containing the function label.  Then make and emit a
+                    simplified subprogram DIE for the second segment with the
+                    name pre-fixed by __hot/cold_sect_of_.  We use the same
+                    linkage name for the second die so that gdb will find both
+                    sections when given "b foo".  */
+                 const char *name = NULL;
+                 tree decl_name = DECL_NAME (decl);
+                 dw_die_ref seg_die;
+
+                 /* Do the 'primary' section.   */
+                 add_AT_lbl_id (subr_die, DW_AT_low_pc,
+                                fde->dw_fde_begin);
+                 add_AT_lbl_id (subr_die, DW_AT_high_pc,
+                                fde->dw_fde_end);
+                 /* Add it.   */
+                 add_pubname (decl, subr_die);
+
+                 /* Build a minimal DIE for the secondary section.  */
+                 seg_die = new_die (DW_TAG_subprogram,
+                                    subr_die->die_parent, decl);
+
+                 if (TREE_PUBLIC (decl))
+                   add_AT_flag (seg_die, DW_AT_external, 1);
+
+                 if (decl_name != NULL 
+                     && IDENTIFIER_POINTER (decl_name) != NULL)
+                   {
+                     name = dwarf2_name (decl, 1);
+                     if (! DECL_ARTIFICIAL (decl))
+                       add_src_coords_attributes (seg_die, decl);
+
+                     add_linkage_name (seg_die, decl);
+                   }
+                 gcc_assert (name != NULL);
+                 add_pure_or_virtual_attribute (seg_die, decl);
+                 if (DECL_ARTIFICIAL (decl))
+                   add_AT_flag (seg_die, DW_AT_artificial, 1);
+
+                 name = concat ("__second_sect_of_", name, NULL); 
+                 add_AT_lbl_id (seg_die, DW_AT_low_pc,
+                                fde->dw_fde_second_begin);
+                 add_AT_lbl_id (seg_die, DW_AT_high_pc,
+                                fde->dw_fde_second_end);
+                 add_name_attribute (seg_die, name);
+                 add_pubname_string (name, seg_die);
+               }
+           }
+         else
+           {
+             add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin);
+             add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end);
+             add_pubname (decl, subr_die);
+           }
        }
 
 #ifdef MIPS_DEBUGGING_INFO
@@ -18927,8 +20009,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
         void_type_node 2) an unprototyped function declaration (not a
         definition).  This just means that we have no info about the
         parameters at all.  */
-      fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
-      if (fn_arg_types != NULL)
+      if (prototype_p (TREE_TYPE (decl)))
        {
          /* This is the prototyped case, check for....  */
          if (stdarg_p (TREE_TYPE (decl)))
@@ -18958,6 +20039,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
      constructor function.  */
   if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK)
     {
+      int call_site_note_count = 0;
+      int tail_call_site_note_count = 0;
+
       /* Emit a DW_TAG_variable DIE for a named return value.  */
       if (DECL_NAME (DECL_RESULT (decl)))
        gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
@@ -18965,17 +20049,139 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       current_function_has_inlines = 0;
       decls_for_scope (outer_scope, subr_die, 0);
 
-#if 0 && defined (MIPS_DEBUGGING_INFO)
-      if (current_function_has_inlines)
+      if (call_arg_locations && !dwarf_strict)
        {
-         add_AT_flag (subr_die, DW_AT_MIPS_has_inlines, 1);
-         if (! comp_unit_has_inlines)
+         struct call_arg_loc_node *ca_loc;
+         for (ca_loc = call_arg_locations; ca_loc; ca_loc = ca_loc->next)
            {
-             add_AT_flag (comp_unit_die, DW_AT_MIPS_has_inlines, 1);
-             comp_unit_has_inlines = 1;
+             dw_die_ref die = NULL;
+             rtx tloc = NULL_RTX, tlocc = NULL_RTX;
+             rtx arg, next_arg;
+
+             for (arg = NOTE_VAR_LOCATION (ca_loc->call_arg_loc_note);
+                  arg; arg = next_arg)
+               {
+                 dw_loc_descr_ref reg, val;
+                 enum machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1));
+                 dw_die_ref cdie;
+
+                 next_arg = XEXP (arg, 1);
+                 if (REG_P (XEXP (XEXP (arg, 0), 0))
+                     && next_arg
+                     && MEM_P (XEXP (XEXP (next_arg, 0), 0))
+                     && REG_P (XEXP (XEXP (XEXP (next_arg, 0), 0), 0))
+                     && REGNO (XEXP (XEXP (arg, 0), 0))
+                        == REGNO (XEXP (XEXP (XEXP (next_arg, 0), 0), 0)))
+                   next_arg = XEXP (next_arg, 1);
+                 if (mode == VOIDmode)
+                   {
+                     mode = GET_MODE (XEXP (XEXP (arg, 0), 0));
+                     if (mode == VOIDmode)
+                       mode = GET_MODE (XEXP (arg, 0));
+                   }
+                 if (mode == VOIDmode || mode == BLKmode)
+                   continue;
+                 if (XEXP (XEXP (arg, 0), 0) == pc_rtx)
+                   {
+                     gcc_assert (ca_loc->symbol_ref == NULL_RTX);
+                     tloc = XEXP (XEXP (arg, 0), 1);
+                     continue;
+                   }
+                 else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) == CLOBBER
+                          && XEXP (XEXP (XEXP (arg, 0), 0), 0) == pc_rtx)
+                   {
+                     gcc_assert (ca_loc->symbol_ref == NULL_RTX);
+                     tlocc = XEXP (XEXP (arg, 0), 1);
+                     continue;
+                   }
+                 if (REG_P (XEXP (XEXP (arg, 0), 0)))
+                   reg = reg_loc_descriptor (XEXP (XEXP (arg, 0), 0),
+                                             VAR_INIT_STATUS_INITIALIZED);
+                 else if (MEM_P (XEXP (XEXP (arg, 0), 0)))
+                   {
+                     rtx mem = XEXP (XEXP (arg, 0), 0);
+                     reg = mem_loc_descriptor (XEXP (mem, 0),
+                                               get_address_mode (mem),
+                                               GET_MODE (mem),
+                                               VAR_INIT_STATUS_INITIALIZED);
+                   }
+                 else
+                   continue;
+                 if (reg == NULL)
+                   continue;
+                 val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), mode,
+                                           VOIDmode,
+                                           VAR_INIT_STATUS_INITIALIZED);
+                 if (val == NULL)
+                   continue;
+                 if (die == NULL)
+                   die = gen_call_site_die (decl, subr_die, ca_loc);
+                 cdie = new_die (DW_TAG_GNU_call_site_parameter, die,
+                                 NULL_TREE);           
+                 add_AT_loc (cdie, DW_AT_location, reg);
+                 add_AT_loc (cdie, DW_AT_GNU_call_site_value, val);
+                 if (next_arg != XEXP (arg, 1))
+                   {
+                     mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 1));
+                     if (mode == VOIDmode)
+                       mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 0));
+                     val = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 1),
+                                                           0), 1),
+                                               mode, VOIDmode,
+                                               VAR_INIT_STATUS_INITIALIZED);
+                     if (val != NULL)
+                       add_AT_loc (cdie, DW_AT_GNU_call_site_data_value, val);
+                   }
+               }
+             if (die == NULL
+                 && (ca_loc->symbol_ref || tloc))
+               die = gen_call_site_die (decl, subr_die, ca_loc);
+             if (die != NULL && (tloc != NULL_RTX || tlocc != NULL_RTX))
+               {
+                 dw_loc_descr_ref tval = NULL;
+
+                 if (tloc != NULL_RTX)
+                   tval = mem_loc_descriptor (tloc,
+                                              GET_MODE (tloc) == VOIDmode
+                                              ? Pmode : GET_MODE (tloc),
+                                              VOIDmode,
+                                              VAR_INIT_STATUS_INITIALIZED);
+                 if (tval)
+                   add_AT_loc (die, DW_AT_GNU_call_site_target, tval);
+                 else if (tlocc != NULL_RTX)
+                   {
+                     tval = mem_loc_descriptor (tlocc,
+                                                GET_MODE (tlocc) == VOIDmode
+                                                ? Pmode : GET_MODE (tlocc),
+                                                VOIDmode,
+                                                VAR_INIT_STATUS_INITIALIZED);
+                     if (tval)
+                       add_AT_loc (die, DW_AT_GNU_call_site_target_clobbered,
+                                   tval);
+                   }
+               }
+             if (die != NULL)
+               {
+                 call_site_note_count++;
+                 if (ca_loc->tail_call_p)
+                   tail_call_site_note_count++;
+               }
            }
        }
-#endif
+      call_arg_locations = NULL;
+      call_arg_loc_last = NULL;
+      if (tail_call_site_count >= 0
+         && tail_call_site_count == tail_call_site_note_count
+         && !dwarf_strict)
+       {
+         if (call_site_count >= 0
+             && call_site_count == call_site_note_count)
+           add_AT_flag (subr_die, DW_AT_GNU_all_call_sites, 1);
+         else
+           add_AT_flag (subr_die, DW_AT_GNU_all_tail_call_sites, 1);
+       }
+      call_site_count = -1;
+      tail_call_site_count = -1;
     }
   /* Add the calling convention attribute if requested.  */
   add_calling_convention_attribute (subr_die, decl);
@@ -19210,7 +20416,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   if (declaration)
     add_AT_flag (var_die, DW_AT_declaration, 1);
 
-  if (decl && (DECL_ABSTRACT (decl) || declaration))
+  if (decl && (DECL_ABSTRACT (decl) || declaration || old_die == NULL))
     equate_decl_number_to_die (decl, var_die);
 
   if (! declaration
@@ -19229,9 +20435,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
           && !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl_or_origin)))
        defer_location (decl_or_origin, var_die);
       else
-        add_location_or_const_value_attribute (var_die,
-                                              decl_or_origin,
-                                              DW_AT_location);
+        add_location_or_const_value_attribute (var_die, decl_or_origin,
+                                              decl == NULL, DW_AT_location);
       add_pubname (decl_or_origin, var_die);
     }
   else
@@ -19364,6 +20569,14 @@ gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth)
 {
   dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
 
+  if (call_arg_locations)
+    {
+      if (VEC_length (dw_die_ref, block_map) <= BLOCK_NUMBER (stmt))
+       VEC_safe_grow_cleared (dw_die_ref, heap, block_map,
+                              BLOCK_NUMBER (stmt) + 1);
+      VEC_replace (dw_die_ref, block_map, BLOCK_NUMBER (stmt), stmt_die);
+    }
+
   if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
     add_high_low_attributes (stmt, stmt_die);
 
@@ -19394,6 +20607,13 @@ gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die, int depth)
       dw_die_ref subr_die
        = new_die (DW_TAG_inlined_subroutine, context_die, stmt);
 
+      if (call_arg_locations)
+       {
+         if (VEC_length (dw_die_ref, block_map) <= BLOCK_NUMBER (stmt))
+           VEC_safe_grow_cleared (dw_die_ref, heap, block_map,
+                                  BLOCK_NUMBER (stmt) + 1);
+         VEC_replace (dw_die_ref, block_map, BLOCK_NUMBER (stmt), subr_die);
+       }
       add_abstract_origin_attribute (subr_die, decl);
       if (TREE_ASM_WRITTEN (stmt))
         add_high_low_attributes (stmt, subr_die);
@@ -19527,6 +20747,38 @@ gen_compile_unit_die (const char *filename)
 
   add_AT_string (die, DW_AT_producer, producer);
 
+  /* If our producer is LTO try to figure out a common language to use
+     from the global list of translation units.  */
+  if (strcmp (language_string, "GNU GIMPLE") == 0)
+    {
+      unsigned i;
+      tree t;
+      const char *common_lang = NULL;
+
+      FOR_EACH_VEC_ELT (tree, all_translation_units, i, t)
+       {
+         if (!TRANSLATION_UNIT_LANGUAGE (t))
+           continue;
+         if (!common_lang)
+           common_lang = TRANSLATION_UNIT_LANGUAGE (t);
+         else if (strcmp (common_lang, TRANSLATION_UNIT_LANGUAGE (t)) == 0)
+           ;
+         else if (strncmp (common_lang, "GNU C", 5) == 0
+                  && strncmp (TRANSLATION_UNIT_LANGUAGE (t), "GNU C", 5) == 0)
+           /* Mixing C and C++ is ok, use C++ in that case.  */
+           common_lang = "GNU C++";
+         else
+           {
+             /* Fall back to C.  */
+             common_lang = NULL;
+             break;
+           }
+       }
+
+      if (common_lang)
+       language_string = common_lang;
+    }
+
   language = DW_LANG_C89;
   if (strcmp (language_string, "GNU C++") == 0)
     language = DW_LANG_C_plus_plus;
@@ -19579,10 +20831,20 @@ gen_inheritance_die (tree binfo, tree access, dw_die_ref context_die)
   if (BINFO_VIRTUAL_P (binfo))
     add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
 
+  /* In DWARF3+ the default is DW_ACCESS_private only in DW_TAG_class_type
+     children, otherwise the default is DW_ACCESS_public.  In DWARF2
+     the default has always been DW_ACCESS_private.  */
   if (access == access_public_node)
-    add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
+    {
+      if (dwarf_version == 2
+         || context_die->die_tag == DW_TAG_class_type)
+      add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
+    }
   else if (access == access_protected_node)
     add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected);
+  else if (dwarf_version > 2
+          && context_die->die_tag != DW_TAG_class_type)
+    add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_private);
 }
 
 /* Generate a DIE for a class member.  */
@@ -19676,7 +20938,7 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
 
   scope_die = scope_die_for (type, context_die);
 
-  if (! type_die || (nested && scope_die == comp_unit_die))
+  if (! type_die || (nested && is_cu_die (scope_die)))
     /* First occurrence of type or toplevel definition of nested class.  */
     {
       dw_die_ref old_die = type_die;
@@ -19688,7 +20950,10 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
       if (old_die)
        add_AT_specification (type_die, old_die);
       else
-       add_name_attribute (type_die, type_tag (type));
+       {
+         add_name_attribute (type_die, type_tag (type));
+         add_gnat_descriptive_type_attribute (type_die, type, context_die);
+       }
     }
   else
     remove_AT (type_die, DW_AT_declaration);
@@ -19696,7 +20961,7 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
   /* Generate child dies for template paramaters.  */
   if (debug_info_level > DINFO_LEVEL_TERSE
       && COMPLETE_TYPE_P (type))
-    gen_generic_params_dies (type);
+    schedule_generic_params_dies_gen (type);
 
   /* If this type has been completed, then give it a byte_size attribute and
      then give a list of members.  */
@@ -19814,6 +21079,14 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
                 anonymous struct DIE.  */
              if (!TREE_ASM_WRITTEN (type))
                gen_tagged_type_die (type, context_die, DINFO_USAGE_DIR_USE);
+
+             /* This is a GNU Extension.  We are adding a
+                DW_AT_linkage_name attribute to the DIE of the
+                anonymous struct TYPE.  The value of that attribute
+                is the name of the typedef decl naming the anonymous
+                struct.  This greatly eases the work of consumers of
+                this debug info.  */
+             add_linkage_attr (lookup_type_die (type), decl);
            }
        }
 
@@ -19876,6 +21149,10 @@ gen_tagged_type_die (tree type,
         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));
+      /* A declaration DIE doesn't count; nested types need to go in the
+        specification.  */
+      if (context_die && is_declaration_die (context_die))
+       context_die = NULL;
       need_pop = 0;
     }
   else
@@ -19906,13 +21183,23 @@ gen_tagged_type_die (tree type,
 
 static void
 gen_type_die_with_usage (tree type, dw_die_ref context_die,
-                               enum debug_info_usage usage)
+                        enum debug_info_usage usage)
 {
   struct array_descr_info info;
 
   if (type == NULL_TREE || type == error_mark_node)
     return;
 
+  if (TYPE_NAME (type) != NULL_TREE
+      && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+      && is_redundant_typedef (TYPE_NAME (type))
+      && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+    /* The DECL of this type is a typedef we don't want to emit debug
+       info for but we want debug info for its underlying typedef.
+       This can happen for e.g, the injected-class-name of a C++
+       type.  */
+    type = DECL_ORIGINAL_TYPE (TYPE_NAME (type));
+
   /* If TYPE is a typedef type variant, let's generate debug info
      for the parent typedef which TYPE is a type of.  */
   if (typedef_variant_p (type))
@@ -20044,6 +21331,7 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
       /* No DIEs needed for fundamental types.  */
       break;
 
+    case NULLPTR_TYPE:
     case LANG_TYPE:
       /* Just use DW_TAG_unspecified_type.  */
       {
@@ -20053,7 +21341,7 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
            tree name = TYPE_NAME (type);
            if (TREE_CODE (name) == TYPE_DECL)
              name = DECL_NAME (name);
-            type_die = new_die (DW_TAG_unspecified_type, comp_unit_die, type);
+            type_die = new_die (DW_TAG_unspecified_type, comp_unit_die (), type);
             add_name_attribute (type_die, IDENTIFIER_POINTER (name));
             equate_type_number_to_die (type, type_die);
           }
@@ -20279,11 +21567,14 @@ get_context_die (tree context)
     {
       /* Find die that represents this context.  */
       if (TYPE_P (context))
-       return force_type_die (TYPE_MAIN_VARIANT (context));
+       {
+         context = TYPE_MAIN_VARIANT (context);
+         return strip_naming_typedef (context, force_type_die (context));
+       }
       else
        return force_decl_die (context);
     }
-  return comp_unit_die;
+  return comp_unit_die ();
 }
 
 /* Returns the DIE for decl.  A DIE will always be returned.  */
@@ -20329,7 +21620,11 @@ force_decl_die (tree decl)
            dwarf2out_decl (decl);
          else
            /* DWARF2 has neither DW_TAG_module, nor DW_TAG_namespace.  */
-           decl_die = comp_unit_die;
+           decl_die = comp_unit_die ();
+         break;
+
+       case TRANSLATION_UNIT_DECL:
+         decl_die = comp_unit_die ();
          break;
 
        default:
@@ -20426,7 +21721,7 @@ gen_namespace_die (tree decl, dw_die_ref context_die)
   if (DECL_ABSTRACT_ORIGIN (decl) == NULL)
     {
       /* Output a real namespace or module.  */
-      context_die = setup_namespace_context (decl, comp_unit_die);
+      context_die = setup_namespace_context (decl, comp_unit_die ());
       namespace_die = new_die (is_fortran ()
                               ? DW_TAG_module : DW_TAG_namespace,
                               context_die, decl);
@@ -20451,9 +21746,9 @@ gen_namespace_die (tree decl, dw_die_ref context_die)
       dw_die_ref origin_die
        = force_decl_die (DECL_ABSTRACT_ORIGIN (decl));
 
-      if (DECL_CONTEXT (decl) == NULL_TREE
+      if (DECL_FILE_SCOPE_P (decl)
          || TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL)
-       context_die = setup_namespace_context (decl, comp_unit_die);
+       context_die = setup_namespace_context (decl, comp_unit_die ());
       /* Now create the namespace alias DIE.  */
       namespace_die = new_die (DW_TAG_imported_declaration, context_die, decl);
       add_name_and_src_coords_attributes (namespace_die, decl);
@@ -20481,7 +21776,7 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
       break;
 
     case CONST_DECL:
-      if (!is_fortran ())
+      if (!is_fortran () && !is_ada ())
        {
          /* The individual enumerators of an enum type get output when we output
             the Dwarf representation of the relevant enum type itself.  */
@@ -20501,7 +21796,7 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
       /* Don't output any DIEs to represent mere function declarations,
         unless they are class members or explicit block externs.  */
       if (DECL_INITIAL (decl_or_origin) == NULL_TREE
-          && DECL_CONTEXT (decl_or_origin) == NULL_TREE
+          && DECL_FILE_SCOPE_P (decl_or_origin)
          && (current_function_decl == NULL_TREE
              || DECL_ARTIFICIAL (decl_or_origin)))
        break;
@@ -20538,16 +21833,20 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
       else if (debug_info_level > DINFO_LEVEL_TERSE)
        {
          /* Before we describe the FUNCTION_DECL itself, make sure that we
-            have described its return type.  */
+            have its containing type.  */
+         if (!origin)
+           origin = decl_class_context (decl);
+         if (origin != NULL_TREE)
+           gen_type_die (origin, context_die);
+
+         /* And its return type.  */
          gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die);
 
          /* And its virtual context.  */
          if (DECL_VINDEX (decl) != NULL_TREE)
            gen_type_die (DECL_CONTEXT (decl), context_die);
 
-         /* And its containing type.  */
-         if (!origin)
-           origin = decl_class_context (decl);
+         /* Make sure we have a member DIE for decl.  */
          if (origin != NULL_TREE)
            gen_type_die_for_member (origin, decl, context_die);
 
@@ -20820,7 +22119,7 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
 void
 dwarf2out_decl (tree decl)
 {
-  dw_die_ref context_die = comp_unit_die;
+  dw_die_ref context_die = comp_unit_die ();
 
   switch (TREE_CODE (decl))
     {
@@ -20892,7 +22191,7 @@ dwarf2out_decl (tree decl)
     case CONST_DECL:
       if (debug_info_level <= DINFO_LEVEL_TERSE)
        return;
-      if (!is_fortran ())
+      if (!is_fortran () && !is_ada ())
        return;
       if (TREE_STATIC (decl) && decl_function_context (decl))
        context_die = lookup_decl_die (DECL_CONTEXT (decl));
@@ -20914,16 +22213,7 @@ dwarf2out_decl (tree decl)
       /* Don't bother trying to generate any DIEs to represent any of the
         normal built-in types for the language we are compiling.  */
       if (DECL_IS_BUILTIN (decl))
-       {
-         /* OK, we need to generate one for `bool' so GDB knows what type
-            comparisons have.  */
-         if (is_cxx ()
-             && TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE
-             && ! DECL_IGNORED_P (decl))
-           modified_type_die (TREE_TYPE (decl), 0, 0, NULL);
-
-         return;
-       }
+       return;
 
       /* If we are in terse mode, don't generate any DIEs for types.  */
       if (debug_info_level <= DINFO_LEVEL_TERSE)
@@ -20949,8 +22239,13 @@ static void
 dwarf2out_function_decl (tree decl)
 {
   dwarf2out_decl (decl);
-
+  call_arg_locations = NULL;
+  call_arg_loc_last = NULL;
+  call_site_count = -1;
+  tail_call_site_count = -1;
+  VEC_free (dw_die_ref, heap, block_map);
   htab_empty (decl_loc_table);
+  htab_empty (cached_dw_loc_list_table);
 }
 
 /* Output a marker (i.e. a label) for the beginning of the generated code for
@@ -21010,7 +22305,7 @@ file_table_eq (const void *p1_p, const void *p2_p)
   const struct dwarf_file_data *const p1 =
     (const struct dwarf_file_data *) p1_p;
   const char *const p2 = (const char *) p2_p;
-  return strcmp (p1->filename, p2) == 0;
+  return filename_cmp (p1->filename, p2) == 0;
 }
 
 static hashval_t
@@ -21041,7 +22336,7 @@ lookup_filename (const char *file_name)
      call matches this file name.  If so, return the index.  */
   if (file_table_last_lookup
       && (file_name == file_table_last_lookup->filename
-         || strcmp (file_table_last_lookup->filename, file_name) == 0))
+         || filename_cmp (file_table_last_lookup->filename, file_name) == 0))
     return file_table_last_lookup;
 
   /* Didn't match the previous lookup, search the table.  */
@@ -21109,6 +22404,33 @@ append_entry_to_tmpl_value_parm_die_table (dw_die_ref die, tree arg)
                 &entry);
 }
 
+/* Return TRUE if T is an instance of generic type, FALSE
+   otherwise.  */
+
+static bool
+generic_type_p (tree t)
+{
+  if (t == NULL_TREE || !TYPE_P (t))
+    return false;
+  return lang_hooks.get_innermost_generic_parms (t) != NULL_TREE;
+}
+
+/* Schedule the generation of the generic parameter dies for the
+  instance of generic type T. The proper generation itself is later
+  done by gen_scheduled_generic_parms_dies. */
+
+static void
+schedule_generic_params_dies_gen (tree t)
+{
+  if (!generic_type_p (t))
+    return;
+
+  if (generic_type_instances == NULL)
+    generic_type_instances = VEC_alloc (tree, gc, 256);
+
+  VEC_safe_push (tree, gc, generic_type_instances, t);
+}
+
 /* 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.  */
@@ -21121,13 +22443,29 @@ gen_remaining_tmpl_value_param_die_attribute (void)
       unsigned i;
       die_arg_entry *e;
 
-      for (i = 0;
-           VEC_iterate (die_arg_entry, tmpl_value_parm_die_table, i, e);
-           i++)
+      FOR_EACH_VEC_ELT (die_arg_entry, tmpl_value_parm_die_table, i, e)
        tree_add_const_value_attribute (e->die, e->arg);
     }
 }
 
+/* Generate generic parameters DIEs for instances of generic types
+   that have been previously scheduled by
+   schedule_generic_params_dies_gen. This function must be called
+   after all the types of the CU have been laid out.  */
+
+static void
+gen_scheduled_generic_parms_dies (void)
+{
+  unsigned i;
+  tree t;
+
+  if (generic_type_instances == NULL)
+    return;
+  
+  FOR_EACH_VEC_ELT (tree, generic_type_instances, i, t)
+    gen_generic_params_dies (t);
+}
+
 
 /* Replace DW_AT_name for the decl with name.  */
 
@@ -21160,141 +22498,12 @@ dwarf2out_set_name (tree decl, tree name)
     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.  */
+/* 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.  */
 
 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_alloc_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.  */
-
-static void
-dwarf2out_var_location (rtx loc_note)
+dwarf2out_var_location (rtx loc_note)
 {
   char loclabel[MAX_ARTIFICIAL_LABEL_BYTES + 2];
   struct var_loc_node *newloc;
@@ -21303,16 +22512,35 @@ dwarf2out_var_location (rtx loc_note)
   static const char *last_postcall_label;
   static bool last_in_cold_section_p;
   tree decl;
+  bool var_loc_p;
+
+  if (!NOTE_P (loc_note))
+    {
+      if (CALL_P (loc_note))
+       {
+         call_site_count++;
+         if (SIBLING_CALL_P (loc_note))
+           tail_call_site_count++;
+       }
+      return;
+    }
 
-  if (!DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
+  var_loc_p = NOTE_KIND (loc_note) == NOTE_INSN_VAR_LOCATION;
+  if (var_loc_p && !DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
     return;
 
   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 && !NOTE_DURING_CALL_P (loc_note))
+  if (var_loc_p
+      && next_real == NULL_RTX
+      && !NOTE_DURING_CALL_P (loc_note))
     return;
 
+  if (next_real == NULL_RTX)
+    next_real = get_last_insn ();
+
   /* If there were any real insns between note we processed last time
      and this note (or if it is the first note), clear
      last_{,postcall_}label so that they are not reused this time.  */
@@ -21324,12 +22552,20 @@ dwarf2out_var_location (rtx loc_note)
       last_postcall_label = NULL;
     }
 
-  decl = NOTE_VAR_LOCATION_DECL (loc_note);
-  newloc = add_var_loc_to_decl (decl, loc_note,
-                               NOTE_DURING_CALL_P (loc_note)
-                               ? last_postcall_label : last_label);
-  if (newloc == NULL)
-    return;
+  if (var_loc_p)
+    {
+      decl = NOTE_VAR_LOCATION_DECL (loc_note);
+      newloc = add_var_loc_to_decl (decl, loc_note,
+                                   NOTE_DURING_CALL_P (loc_note)
+                                   ? last_postcall_label : last_label);
+      if (newloc == NULL)
+       return;
+    }
+  else
+    {
+      decl = NULL_TREE;
+      newloc = NULL;
+    }
 
   /* If there were no real insns between note we processed last time
      and this note, use the label we emitted last time.  Otherwise
@@ -21342,7 +22578,43 @@ dwarf2out_var_location (rtx loc_note)
       last_label = ggc_strdup (loclabel);
     }
 
-  if (!NOTE_DURING_CALL_P (loc_note))
+  if (!var_loc_p)
+    {
+      struct call_arg_loc_node *ca_loc
+       = ggc_alloc_cleared_call_arg_loc_node ();
+      rtx prev = prev_real_insn (loc_note), x;
+      ca_loc->call_arg_loc_note = loc_note;
+      ca_loc->next = NULL;
+      ca_loc->label = last_label;
+      gcc_assert (prev
+                 && (CALL_P (prev)
+                     || (NONJUMP_INSN_P (prev)
+                         && GET_CODE (PATTERN (prev)) == SEQUENCE
+                         && CALL_P (XVECEXP (PATTERN (prev), 0, 0)))));
+      if (!CALL_P (prev))
+       prev = XVECEXP (PATTERN (prev), 0, 0);
+      ca_loc->tail_call_p = SIBLING_CALL_P (prev);
+      x = PATTERN (prev);
+      if (GET_CODE (x) == PARALLEL)
+       x = XVECEXP (x, 0, 0);
+      if (GET_CODE (x) == SET)
+       x = SET_SRC (x);
+      if (GET_CODE (x) == CALL && MEM_P (XEXP (x, 0)))
+       {
+         x = XEXP (XEXP (x, 0), 0);
+         if (GET_CODE (x) == SYMBOL_REF
+             && SYMBOL_REF_DECL (x)
+             && TREE_CODE (SYMBOL_REF_DECL (x)) == FUNCTION_DECL)
+           ca_loc->symbol_ref = x;
+       }
+      ca_loc->block = insn_scope (prev);
+      if (call_arg_locations)
+       call_arg_loc_last->next = ca_loc;
+      else
+       call_arg_locations = ca_loc;
+      call_arg_loc_last = ca_loc;
+    }
+  else if (!NOTE_DURING_CALL_P (loc_note))
     newloc->label = last_label;
   else
     {
@@ -21358,6 +22630,92 @@ dwarf2out_var_location (rtx loc_note)
   last_in_cold_section_p = in_cold_section_p;
 }
 
+/* Note in one location list that text section has changed.  */
+
+static int
+var_location_switch_text_section_1 (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+  var_loc_list *list = (var_loc_list *) *slot;
+  if (list->first)
+    list->last_before_switch
+      = list->last->next ? list->last->next : list->last;
+  return 1;
+}
+
+/* Note in all location lists that text section has changed.  */
+
+static void
+var_location_switch_text_section (void)
+{
+  if (decl_loc_table == NULL)
+    return;
+
+  htab_traverse (decl_loc_table, var_location_switch_text_section_1, NULL);
+}
+
+/* Create a new line number table.  */
+
+static dw_line_info_table *
+new_line_info_table (void)
+{
+  dw_line_info_table *table;
+
+  table = ggc_alloc_cleared_dw_line_info_table_struct ();
+  table->file_num = 1;
+  table->line_num = 1;
+  table->is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
+
+  return table;
+}
+
+/* Lookup the "current" table into which we emit line info, so
+   that we don't have to do it for every source line.  */
+
+static void
+set_cur_line_info_table (section *sec)
+{
+  dw_line_info_table *table;
+
+  if (sec == text_section)
+    table = text_section_line_info;
+  else if (sec == cold_text_section)
+    {
+      table = cold_text_section_line_info;
+      if (!table)
+       {
+         cold_text_section_line_info = table = new_line_info_table ();
+         table->end_label = cold_end_label;
+       }
+    }
+  else
+    {
+      const char *end_label;
+
+      if (flag_reorder_blocks_and_partition)
+       {
+         if (in_cold_section_p)
+           end_label = crtl->subsections.cold_section_end_label;
+         else
+           end_label = crtl->subsections.hot_section_end_label;
+       }
+      else
+       {
+         char label[MAX_ARTIFICIAL_LABEL_BYTES];
+         ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL,
+                                      current_function_funcdef_no);
+         end_label = ggc_strdup (label);
+       }
+
+      table = new_line_info_table ();
+      table->end_label = end_label;
+
+      VEC_safe_push (dw_line_info_table_p, gc, separate_line_info, table);
+    }
+
+  cur_line_info_table = table;
+}
+
+
 /* We need to reset the locations at the beginning of each
    function. We can't do this in the end_function hook, because the
    declarations that use the locations won't have been output when
@@ -21366,104 +22724,119 @@ dwarf2out_var_location (rtx loc_note)
 static void
 dwarf2out_begin_function (tree fun)
 {
-  if (function_section (fun) != text_section)
+  section *sec = function_section (fun);
+
+  if (sec != text_section)
     have_multiple_function_sections = true;
 
+  if (flag_reorder_blocks_and_partition && !cold_text_section)
+    {
+      gcc_assert (current_function_decl == fun);
+      cold_text_section = unlikely_text_section ();
+      switch_to_section (cold_text_section);
+      ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label);
+      switch_to_section (sec);
+    }
+
   dwarf2out_note_section_used ();
+  call_site_count = 0;
+  tail_call_site_count = 0;
+
+  set_cur_line_info_table (sec);
+}
+
+/* Add OPCODE+VAL as an entry at the end of the opcode array in TABLE.  */
+
+static void
+push_dw_line_info_entry (dw_line_info_table *table,
+                        enum dw_line_info_opcode opcode, unsigned int val)
+{
+  dw_line_info_entry e;
+  e.opcode = opcode;
+  e.val = val;
+  VEC_safe_push (dw_line_info_entry, gc, table->entries, &e);
 }
 
 /* Output a label to mark the beginning of a source code line entry
    and record information relating to this source line, in
    'line_info_table' for later output of the .debug_line section.  */
+/* ??? The discriminator parameter ought to be unsigned.  */
 
 static void
 dwarf2out_source_line (unsigned int line, const char *filename,
                        int discriminator, bool is_stmt)
 {
-  static bool last_is_stmt = true;
-
-  if (debug_info_level >= DINFO_LEVEL_NORMAL
-      && line != 0)
-    {
-      int file_num = maybe_emit_file (lookup_filename (filename));
-
-      switch_to_section (current_function_section ());
+  unsigned int file_num;
+  dw_line_info_table *table;
 
-      /* If requested, emit something human-readable.  */
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START,
-                filename, line);
+  if (debug_info_level < DINFO_LEVEL_NORMAL || line == 0)
+    return;
 
-      if (DWARF2_ASM_LINE_DEBUG_INFO)
-       {
-         /* Emit the .loc directive understood by GNU as.  */
-         fprintf (asm_out_file, "\t.loc %d %d 0", file_num, line);
-         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);
-         fputc ('\n', asm_out_file);
+  /* The discriminator column was added in dwarf4.  Simplify the below
+     by simply removing it if we're not supposed to output it.  */
+  if (dwarf_version < 4 && dwarf_strict)
+    discriminator = 0;
+
+  table = cur_line_info_table;
+  file_num = maybe_emit_file (lookup_filename (filename));
+
+  /* ??? TODO: Elide duplicate line number entries.  Traditionally,
+     the debugger has used the second (possibly duplicate) line number
+     at the beginning of the function to mark the end of the prologue.
+     We could eliminate any other duplicates within the function.  For
+     Dwarf3, we ought to include the DW_LNS_set_prologue_end mark in
+     that second line number entry.  */
+  /* Recall that this end-of-prologue indication is *not* the same thing
+     as the end_prologue debug hook.  The NOTE_INSN_PROLOGUE_END note,
+     to which the hook corresponds, follows the last insn that was 
+     emitted by gen_prologue.  What we need is to preceed the first insn
+     that had been emitted after NOTE_INSN_FUNCTION_BEG, i.e. the first
+     insn that corresponds to something the user wrote.  These may be
+     very different locations once scheduling is enabled.  */
+
+  if (0 && file_num == table->file_num
+      && line == table->line_num
+      && discriminator == table->discrim_num
+      && is_stmt == table->is_stmt)
+    return;
 
-         /* Indicate that line number info exists.  */
-         line_info_table_in_use++;
-       }
-      else if (function_section (current_function_decl) != text_section)
-       {
-         dw_separate_line_info_ref line_info;
-         targetm.asm_out.internal_label (asm_out_file,
-                                         SEPARATE_LINE_CODE_LABEL,
-                                         separate_line_info_table_in_use);
-
-         /* Expand the line info table if necessary.  */
-         if (separate_line_info_table_in_use
-             == separate_line_info_table_allocated)
-           {
-             separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
-             separate_line_info_table
-               = GGC_RESIZEVEC (dw_separate_line_info_entry,
-                                separate_line_info_table,
-                                separate_line_info_table_allocated);
-             memset (separate_line_info_table
-                      + separate_line_info_table_in_use,
-                     0,
-                     (LINE_INFO_TABLE_INCREMENT
-                      * sizeof (dw_separate_line_info_entry)));
-           }
+  switch_to_section (current_function_section ());
 
-         /* Add the new entry at the end of the line_info_table.  */
-         line_info
-           = &separate_line_info_table[separate_line_info_table_in_use++];
-         line_info->dw_file_num = file_num;
-         line_info->dw_line_num = line;
-         line_info->function = current_function_funcdef_no;
-       }
-      else
-       {
-         dw_line_info_ref line_info;
+  /* If requested, emit something human-readable.  */
+  if (flag_debug_asm)
+    fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START, filename, line);
 
-         targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL,
-                                    line_info_table_in_use);
+  if (DWARF2_ASM_LINE_DEBUG_INFO)
+    {
+      /* Emit the .loc directive understood by GNU as.  */
+      fprintf (asm_out_file, "\t.loc %d %d 0", file_num, line);
+      if (is_stmt != table->is_stmt)
+       fprintf (asm_out_file, " is_stmt %d", is_stmt ? 1 : 0);
+      if (SUPPORTS_DISCRIMINATOR && discriminator != 0)
+       fprintf (asm_out_file, " discriminator %d", discriminator);
+      fputc ('\n', asm_out_file);
+    }
+  else
+    {
+      unsigned int label_num = ++line_info_label_num;
 
-         /* Expand the line info table if necessary.  */
-         if (line_info_table_in_use == line_info_table_allocated)
-           {
-             line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
-             line_info_table
-               = GGC_RESIZEVEC (dw_line_info_entry, line_info_table,
-                                line_info_table_allocated);
-             memset (line_info_table + line_info_table_in_use, 0,
-                     LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry));
-           }
+      targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num);
 
-         /* Add the new entry at the end of the line_info_table.  */
-         line_info = &line_info_table[line_info_table_in_use++];
-         line_info->dw_file_num = file_num;
-         line_info->dw_line_num = line;
-       }
+      push_dw_line_info_entry (table, LI_set_address, label_num);
+      if (file_num != table->file_num)
+       push_dw_line_info_entry (table, LI_set_file, file_num);
+      if (discriminator != table->discrim_num)
+       push_dw_line_info_entry (table, LI_set_discriminator, discriminator);
+      if (is_stmt != table->is_stmt)
+       push_dw_line_info_entry (table, LI_negate_stmt, 0);
+      push_dw_line_info_entry (table, LI_set_line, line);
     }
+
+  table->file_num = file_num;
+  table->line_num = line;
+  table->discrim_num = discriminator;
+  table->is_stmt = is_stmt;
+  table->in_use = true;
 }
 
 /* Record the beginning of a new source file.  */
@@ -21471,25 +22844,22 @@ 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 && dwarf_version < 4)
+  if (flag_eliminate_dwarf2_dups && ! use_debug_types)
     {
       /* Record the beginning of the file for break_out_includes.  */
       dw_die_ref bincl_die;
 
-      bincl_die = new_die (DW_TAG_GNU_BINCL, comp_unit_die, NULL);
+      bincl_die = new_die (DW_TAG_GNU_BINCL, comp_unit_die (), NULL);
       add_AT_string (bincl_die, DW_AT_name, remap_debug_filename (filename));
     }
 
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
     {
-      int file_num = maybe_emit_file (lookup_filename (filename));
-
-      switch_to_section (debug_macinfo_section);
-      dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
-      dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
-                                  lineno);
-
-      dw2_asm_output_data_uleb128 (file_num, "file %s", filename);
+      macinfo_entry e;
+      e.code = DW_MACINFO_start_file;
+      e.lineno = lineno;
+      e.info = xstrdup (filename);
+      VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
     }
 }
 
@@ -21498,14 +22868,17 @@ 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 && dwarf_version < 4)
+  if (flag_eliminate_dwarf2_dups && ! use_debug_types)
     /* Record the end of the file for break_out_includes.  */
-    new_die (DW_TAG_GNU_EINCL, comp_unit_die, NULL);
+    new_die (DW_TAG_GNU_EINCL, comp_unit_die (), NULL);
 
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
     {
-      switch_to_section (debug_macinfo_section);
-      dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
+      macinfo_entry e;
+      e.code = DW_MACINFO_end_file;
+      e.lineno = lineno;
+      e.info = NULL;
+      VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
     }
 }
 
@@ -21519,10 +22892,11 @@ dwarf2out_define (unsigned int lineno ATTRIBUTE_UNUSED,
 {
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
     {
-      switch_to_section (debug_macinfo_section);
-      dw2_asm_output_data (1, DW_MACINFO_define, "Define macro");
-      dw2_asm_output_data_uleb128 (lineno, "At line number %d", lineno);
-      dw2_asm_output_nstring (buffer, -1, "The macro");
+      macinfo_entry e;
+      e.code = DW_MACINFO_define;
+      e.lineno = lineno;
+      e.info = xstrdup (buffer);;
+      VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
     }
 }
 
@@ -21536,10 +22910,58 @@ dwarf2out_undef (unsigned int lineno ATTRIBUTE_UNUSED,
 {
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
     {
-      switch_to_section (debug_macinfo_section);
-      dw2_asm_output_data (1, DW_MACINFO_undef, "Undefine macro");
-      dw2_asm_output_data_uleb128 (lineno, "At line number %d", lineno);
-      dw2_asm_output_nstring (buffer, -1, "The macro");
+      macinfo_entry e;
+      e.code = DW_MACINFO_undef;
+      e.lineno = lineno;
+      e.info = xstrdup (buffer);;
+      VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
+    }
+}
+
+static void
+output_macinfo (void)
+{
+  unsigned i;
+  unsigned long length = VEC_length (macinfo_entry, macinfo_table);
+  macinfo_entry *ref;
+
+  if (! length)
+    return;
+
+  for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++)
+    {
+      switch (ref->code)
+       {
+         case DW_MACINFO_start_file:
+           {
+             int file_num = maybe_emit_file (lookup_filename (ref->info));
+             dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
+             dw2_asm_output_data_uleb128 
+                       (ref->lineno, "Included from line number %lu", 
+                                               (unsigned long)ref->lineno);
+             dw2_asm_output_data_uleb128 (file_num, "file %s", ref->info);
+           }
+           break;
+         case DW_MACINFO_end_file:
+           dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
+           break;
+         case DW_MACINFO_define:
+           dw2_asm_output_data (1, DW_MACINFO_define, "Define macro");
+           dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu", 
+                                               (unsigned long)ref->lineno);
+           dw2_asm_output_nstring (ref->info, -1, "The macro");
+           break;
+         case DW_MACINFO_undef:
+           dw2_asm_output_data (1, DW_MACINFO_undef, "Undefine macro");
+           dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
+                                               (unsigned long)ref->lineno);
+           dw2_asm_output_nstring (ref->info, -1, "The macro");
+           break;
+         default:
+          fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n",
+            ASM_COMMENT_START, (unsigned long)ref->code);
+         break;
+       }
     }
 }
 
@@ -21560,6 +22982,11 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
   decl_loc_table = htab_create_ggc (10, decl_loc_table_hash,
                                    decl_loc_table_eq, NULL);
 
+  /* Allocate the cached_dw_loc_list_table.  */
+  cached_dw_loc_list_table
+    = htab_create_ggc (10, cached_dw_loc_list_table_hash,
+                      cached_dw_loc_list_table_eq, NULL);
+
   /* Allocate the initial hunk of the decl_scope_table.  */
   decl_scope_table = VEC_alloc (tree, gc, 256);
 
@@ -21570,30 +22997,10 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
   /* Zero-th entry is allocated, but unused.  */
   abbrev_die_table_in_use = 1;
 
-  /* Allocate the initial hunk of the line_info_table.  */
-  line_info_table = ggc_alloc_cleared_vec_dw_line_info_entry
-    (LINE_INFO_TABLE_INCREMENT);
-  line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
-
-  /* Zero-th entry is allocated, but unused.  */
-  line_info_table_in_use = 1;
-
   /* Allocate the pubtypes and pubnames vectors.  */
   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
-     taken as being relative to the directory from which the compiler was
-     invoked when the given (base) source file was compiled.  We will fill
-     in this value in dwarf2out_finish.  */
-  comp_unit_die = gen_compile_unit_die (NULL);
-
   incomplete_types = VEC_alloc (tree, gc, 64);
 
   used_rtx_array = VEC_alloc (rtx, gc, 32);
@@ -21614,10 +23021,6 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
                                        SECTION_DEBUG, NULL);
   debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
                                        SECTION_DEBUG, NULL);
-  debug_dcall_section = get_section (DEBUG_DCALL_SECTION,
-                                    SECTION_DEBUG, NULL);
-  debug_vcall_section = get_section (DEBUG_VCALL_SECTION,
-                                    SECTION_DEBUG, NULL);
   debug_str_section = get_section (DEBUG_STR_SECTION,
                                   DEBUG_STR_SECTION_FLAGS, NULL);
   debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
@@ -21639,30 +23042,18 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
                               DEBUG_LINE_SECTION_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
                               DEBUG_RANGES_SECTION_LABEL, 0);
-  switch_to_section (debug_abbrev_section);
-  ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
-  switch_to_section (debug_info_section);
-  ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label);
-  switch_to_section (debug_line_section);
-  ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
+  ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
+                              DEBUG_MACINFO_SECTION_LABEL, 0);
 
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
-    {
-      switch_to_section (debug_macinfo_section);
-      ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
-                                  DEBUG_MACINFO_SECTION_LABEL, 0);
-      ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
-    }
+    macinfo_table = VEC_alloc (macinfo_entry, gc, 64);
 
   switch_to_section (text_section);
   ASM_OUTPUT_LABEL (asm_out_file, text_section_label);
-  if (flag_reorder_blocks_and_partition)
-    {
-      cold_text_section = unlikely_text_section ();
-      switch_to_section (cold_text_section);
-      ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label);
-    }
 
+  /* Make sure the line number table for .text always exists.  */
+  text_section_line_info = new_line_info_table ();
+  text_section_line_info->end_label = text_end_label;
 }
 
 /* Called before cgraph_optimize starts outputtting functions, variables
@@ -21671,13 +23062,11 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
 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");
-    }
+  if (HAVE_GAS_CFI_SECTIONS_DIRECTIVE
+      && dwarf2out_do_cfi_asm ()
+      && (!(flag_unwind_tables || flag_exceptions)
+         || targetm.except_unwind_info (&global_options) != UI_DWARF2))
+    fprintf (asm_out_file, "\t.cfi_sections\t.debug_frame\n");
 }
 
 /* A helper function for dwarf2out_finish called through
@@ -21688,7 +23077,7 @@ output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
 {
   struct indirect_string_node *node = (struct indirect_string_node *) *h;
 
-  if (node->label && node->refcount)
+  if (node->form == DW_FORM_strp)
     {
       switch_to_section (debug_str_section);
       ASM_OUTPUT_LABEL (asm_out_file, node->label);
@@ -21733,14 +23122,14 @@ prune_unused_types_walk_attribs (dw_die_ref die)
   dw_attr_ref a;
   unsigned ix;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     {
       if (a->dw_attr_val.val_class == dw_val_class_die_ref)
        {
          /* A reference to another DIE.
             Make sure that it will get emitted.
             If it was broken out into a comdat group, don't follow it.  */
-          if (dwarf_version < 4
+          if (! use_debug_types
               || 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);
@@ -21752,6 +23141,32 @@ prune_unused_types_walk_attribs (dw_die_ref die)
     }
 }
 
+/* Mark the generic parameters and arguments children DIEs of DIE.  */
+
+static void
+prune_unused_types_mark_generic_parms_dies (dw_die_ref die)
+{
+  dw_die_ref c;
+
+  if (die == NULL || die->die_child == NULL)
+    return;
+  c = die->die_child;
+  do
+    {
+      switch (c->die_tag)
+       {
+       case DW_TAG_template_type_param:
+       case DW_TAG_template_value_param:
+       case DW_TAG_GNU_template_template_param:
+       case DW_TAG_GNU_template_parameter_pack:
+         prune_unused_types_mark (c, 1);
+         break;
+       default:
+         break;
+       }
+      c = c->die_sib;
+    } while (c && c != die->die_child);
+}
 
 /* Mark DIE as being used.  If DOKIDS is true, then walk down
    to DIE's children.  */
@@ -21765,6 +23180,10 @@ prune_unused_types_mark (dw_die_ref die, int dokids)
     {
       /* We haven't done this node yet.  Mark it as used.  */
       die->die_mark = 1;
+      /* If this is the DIE of a generic type instantiation,
+        mark the children DIEs that describe its generic parms and
+        args.  */
+      prune_unused_types_mark_generic_parms_dies (die);
 
       /* We also have to mark its parents as used.
         (But we don't want to mark our parents' kids due to this.)  */
@@ -21791,7 +23210,7 @@ prune_unused_types_mark (dw_die_ref die, int dokids)
         breaking out types into comdat sections, do this
         for all type definitions.  */
       if (die->die_tag == DW_TAG_array_type
-          || (dwarf_version >= 4
+          || (use_debug_types
               && is_type_die (die) && ! is_declaration_die (die)))
        FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1));
       else
@@ -21918,7 +23337,7 @@ prune_unused_types_update_strings (dw_die_ref die)
   dw_attr_ref a;
   unsigned ix;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     if (AT_class (a) == dw_val_class_str)
       {
        struct indirect_string_node *s = a->dw_attr_val.v.val_str;
@@ -21975,21 +23394,6 @@ 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.  */
 
 static void
@@ -21999,11 +23403,11 @@ prune_unused_types (void)
   limbo_die_node *node;
   comdat_type_node *ctnode;
   pubname_ref pub;
-  dcall_entry *dcall;
+  dw_die_ref base_type;
 
 #if ENABLE_ASSERT_CHECKING
   /* All the marks should already be clear.  */
-  verify_marks_clear (comp_unit_die);
+  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)
@@ -22014,7 +23418,7 @@ prune_unused_types (void)
   premark_types_used_by_global_vars ();
 
   /* Set the mark on nodes that are actually used.  */
-  prune_unused_types_walk (comp_unit_die);
+  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)
@@ -22024,29 +23428,22 @@ prune_unused_types (void)
     }
 
   /* Also set the mark on nodes referenced from the
-     pubname_table or arange_table.  */
-  for (i = 0; VEC_iterate (pubname_entry, pubname_table, i, pub); i++)
+     pubname_table.  */
+  FOR_EACH_VEC_ELT (pubname_entry, pubname_table, i, pub)
     prune_unused_types_mark (pub->die, 1);
-  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);
+  for (i = 0; VEC_iterate (dw_die_ref, base_types, i, base_type); i++)
+    prune_unused_types_mark (base_type, 1);
 
-  /* Get rid of nodes that aren't marked; and update the string counts.  */
-  if (debug_str_hash && debug_str_hash_forced)
-    htab_traverse (debug_str_hash, prune_indirect_string, NULL);
-  else if (debug_str_hash)
+  if (debug_str_hash)
     htab_empty (debug_str_hash);
-  prune_unused_types_prune (comp_unit_die);
+  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);
+  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)
@@ -22121,35 +23518,153 @@ 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.  */
+/* Helper function for resolve_addr, mark DW_TAG_base_type nodes
+   referenced from typed stack ops and count how often they are used.  */
 
-static int
-resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED)
+static void
+mark_base_types (dw_loc_descr_ref loc)
 {
-  rtx rtl = *addr;
+  dw_die_ref base_type = NULL;
 
-  if (GET_CODE (rtl) == CONST_STRING)
+  for (; loc; loc = loc->dw_loc_next)
     {
-      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;
+      switch (loc->dw_loc_opc)
+       {
+       case DW_OP_GNU_regval_type:
+       case DW_OP_GNU_deref_type:
+         base_type = loc->dw_loc_oprnd2.v.val_die_ref.die;
+         break;
+       case DW_OP_GNU_const_type:
+       case DW_OP_GNU_convert:
+       case DW_OP_GNU_reinterpret:
+         base_type = loc->dw_loc_oprnd1.v.val_die_ref.die;
+         break;
+       case DW_OP_GNU_entry_value:
+         mark_base_types (loc->dw_loc_oprnd1.v.val_loc);
+         continue;
+       default:
+         continue;
+       }
+      gcc_assert (base_type->die_parent == comp_unit_die ());
+      if (base_type->die_mark)
+       base_type->die_mark++;
+      else
+       {
+         VEC_safe_push (dw_die_ref, heap, base_types, base_type);
+         base_type->die_mark = 1;
+       }
+    }
+}
+
+/* Comparison function for sorting marked base types.  */
+
+static int
+base_type_cmp (const void *x, const void *y)
+{
+  dw_die_ref dx = *(const dw_die_ref *) x;
+  dw_die_ref dy = *(const dw_die_ref *) y;
+  unsigned int byte_size1, byte_size2;
+  unsigned int encoding1, encoding2;
+  if (dx->die_mark > dy->die_mark)
+    return -1;
+  if (dx->die_mark < dy->die_mark)
+    return 1;
+  byte_size1 = get_AT_unsigned (dx, DW_AT_byte_size);
+  byte_size2 = get_AT_unsigned (dy, DW_AT_byte_size);
+  if (byte_size1 < byte_size2)
+    return 1;
+  if (byte_size1 > byte_size2)
+    return -1;
+  encoding1 = get_AT_unsigned (dx, DW_AT_encoding);
+  encoding2 = get_AT_unsigned (dy, DW_AT_encoding);
+  if (encoding1 < encoding2)
+    return 1;
+  if (encoding1 > encoding2)
+    return -1;
+  return 0;
+}
+
+/* Move base types marked by mark_base_types as early as possible
+   in the CU, sorted by decreasing usage count both to make the
+   uleb128 references as small as possible and to make sure they
+   will have die_offset already computed by calc_die_sizes when
+   sizes of typed stack loc ops is computed.  */
+
+static void
+move_marked_base_types (void)
+{
+  unsigned int i;
+  dw_die_ref base_type, die, c;
+
+  if (VEC_empty (dw_die_ref, base_types))
+    return;
+
+  /* Sort by decreasing usage count, they will be added again in that
+     order later on.  */
+  VEC_qsort (dw_die_ref, base_types, base_type_cmp);
+  die = comp_unit_die ();
+  c = die->die_child;
+  do
+    {
+      dw_die_ref prev = c;
+      c = c->die_sib;
+      while (c->die_mark)
+       {
+         remove_child_with_prev (c, prev);
+         /* As base types got marked, there must be at least
+            one node other than DW_TAG_base_type.  */
+         gcc_assert (c != c->die_sib);
+         c = c->die_sib;
+       }
+    }
+  while (c != die->die_child);
+  gcc_assert (die->die_child);
+  c = die->die_child;
+  for (i = 0; VEC_iterate (dw_die_ref, base_types, i, base_type); i++)
+    {
+      base_type->die_mark = 0;
+      base_type->die_sib = c->die_sib;
+      c->die_sib = base_type;
+      c = base_type;
+    }
+}
+
+/* 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 = size_int (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_ASM_WRITTEN (SYMBOL_REF_DECL (rtl)))
-    return 1;
+      && SYMBOL_REF_DECL (rtl))
+    {
+      if (TREE_CONSTANT_POOL_ADDRESS_P (rtl))
+       {
+         if (!TREE_ASM_WRITTEN (DECL_INITIAL (SYMBOL_REF_DECL (rtl))))
+           return 1;
+       }
+      else if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl)))
+       return 1;
+    }
 
   if (GET_CODE (rtl) == CONST
       && for_each_rtx (&XEXP (rtl, 0), resolve_one_addr, NULL))
@@ -22172,6 +23687,17 @@ resolve_addr_in_expr (dw_loc_descr_ref loc)
            && loc->dw_loc_oprnd2.val_class == dw_val_class_addr
            && resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr, NULL)))
       return false;
+    else if (loc->dw_loc_opc == DW_OP_GNU_implicit_pointer
+            && loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref)
+      {
+       dw_die_ref ref
+         = lookup_decl_die (loc->dw_loc_oprnd1.v.val_decl_ref);
+       if (ref == NULL)
+         return false;
+       loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+       loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
+       loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
+      }
   return true;
 }
 
@@ -22187,30 +23713,56 @@ resolve_addr (dw_die_ref die)
 {
   dw_die_ref c;
   dw_attr_ref a;
-  dw_loc_list_ref *curr;
+  dw_loc_list_ref *curr, *start, loc;
   unsigned ix;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     switch (AT_class (a))
       {
       case dw_val_class_loc_list:
-       curr = AT_loc_list_ptr (a);
-       while (*curr)
+       start = curr = AT_loc_list_ptr (a);
+       loc = *curr;
+       gcc_assert (loc);
+       /* The same list can be referenced more than once.  See if we have
+          already recorded the result from a previous pass.  */
+       if (loc->replaced)
+         *curr = loc->dw_loc_next;
+       else if (!loc->resolved_addr)
          {
-           if (!resolve_addr_in_expr ((*curr)->expr))
+           /* As things stand, we do not expect or allow one die to
+              reference a suffix of another die's location list chain.
+              References must be identical or completely separate.
+              There is therefore no need to cache the result of this
+              pass on any list other than the first; doing so
+              would lead to unnecessary writes.  */
+           while (*curr)
              {
-               dw_loc_list_ref next = (*curr)->dw_loc_next;
-               if (next && (*curr)->ll_symbol)
+               gcc_assert (!(*curr)->replaced && !(*curr)->resolved_addr);
+               if (!resolve_addr_in_expr ((*curr)->expr))
+                 {
+                   dw_loc_list_ref next = (*curr)->dw_loc_next;
+                   if (next && (*curr)->ll_symbol)
+                     {
+                       gcc_assert (!next->ll_symbol);
+                       next->ll_symbol = (*curr)->ll_symbol;
+                     }
+                   *curr = next;
+                 }
+               else
                  {
-                   gcc_assert (!next->ll_symbol);
-                   next->ll_symbol = (*curr)->ll_symbol;
+                   mark_base_types ((*curr)->expr);
+                   curr = &(*curr)->dw_loc_next;
                  }
-               *curr = next;
              }
+           if (loc == *start)
+             loc->resolved_addr = 1;
            else
-             curr = &(*curr)->dw_loc_next;
+             {
+               loc->replaced = 1;
+               loc->dw_loc_next = *start;
+             }
          }
-       if (!AT_loc_list (a))
+       if (!*start)
          {
            remove_AT (die, a->dw_attr);
            ix--;
@@ -22222,6 +23774,8 @@ resolve_addr (dw_die_ref die)
            remove_AT (die, a->dw_attr);
            ix--;
          }
+       else
+         mark_base_types (AT_loc (a));
        break;
       case dw_val_class_addr:
        if (a->dw_attr == DW_AT_const_value
@@ -22230,6 +23784,30 @@ resolve_addr (dw_die_ref die)
            remove_AT (die, a->dw_attr);
            ix--;
          }
+       if (die->die_tag == DW_TAG_GNU_call_site
+           && a->dw_attr == DW_AT_abstract_origin)
+         {
+           tree tdecl = SYMBOL_REF_DECL (a->dw_attr_val.v.val_addr);
+           dw_die_ref tdie = lookup_decl_die (tdecl);
+           if (tdie == NULL
+               && DECL_EXTERNAL (tdecl)
+               && DECL_ABSTRACT_ORIGIN (tdecl) == NULL_TREE)
+             {
+               force_decl_die (tdecl);
+               tdie = lookup_decl_die (tdecl);
+             }
+           if (tdie)
+             {
+               a->dw_attr_val.val_class = dw_val_class_die_ref;
+               a->dw_attr_val.v.val_die_ref.die = tdie;
+               a->dw_attr_val.v.val_die_ref.external = 0;
+             }
+           else
+             {
+               remove_AT (die, a->dw_attr);
+               ix--;
+             }
+         }
        break;
       default:
        break;
@@ -22237,7 +23815,458 @@ resolve_addr (dw_die_ref die)
 
   FOR_EACH_CHILD (die, c, resolve_addr (c));
 }
+\f
+/* Helper routines for optimize_location_lists.
+   This pass tries to share identical local lists in .debug_loc
+   section.  */
+
+/* Iteratively hash operands of LOC opcode.  */
+
+static inline hashval_t
+hash_loc_operands (dw_loc_descr_ref loc, hashval_t hash)
+{
+  dw_val_ref val1 = &loc->dw_loc_oprnd1;
+  dw_val_ref val2 = &loc->dw_loc_oprnd2;
+
+  switch (loc->dw_loc_opc)
+    {
+    case DW_OP_const4u:
+    case DW_OP_const8u:
+      if (loc->dtprel)
+       goto hash_addr;
+      /* FALLTHRU */
+    case DW_OP_const1u:
+    case DW_OP_const1s:
+    case DW_OP_const2u:
+    case DW_OP_const2s:
+    case DW_OP_const4s:
+    case DW_OP_const8s:
+    case DW_OP_constu:
+    case DW_OP_consts:
+    case DW_OP_pick:
+    case DW_OP_plus_uconst:
+    case DW_OP_breg0:
+    case DW_OP_breg1:
+    case DW_OP_breg2:
+    case DW_OP_breg3:
+    case DW_OP_breg4:
+    case DW_OP_breg5:
+    case DW_OP_breg6:
+    case DW_OP_breg7:
+    case DW_OP_breg8:
+    case DW_OP_breg9:
+    case DW_OP_breg10:
+    case DW_OP_breg11:
+    case DW_OP_breg12:
+    case DW_OP_breg13:
+    case DW_OP_breg14:
+    case DW_OP_breg15:
+    case DW_OP_breg16:
+    case DW_OP_breg17:
+    case DW_OP_breg18:
+    case DW_OP_breg19:
+    case DW_OP_breg20:
+    case DW_OP_breg21:
+    case DW_OP_breg22:
+    case DW_OP_breg23:
+    case DW_OP_breg24:
+    case DW_OP_breg25:
+    case DW_OP_breg26:
+    case DW_OP_breg27:
+    case DW_OP_breg28:
+    case DW_OP_breg29:
+    case DW_OP_breg30:
+    case DW_OP_breg31:
+    case DW_OP_regx:
+    case DW_OP_fbreg:
+    case DW_OP_piece:
+    case DW_OP_deref_size:
+    case DW_OP_xderef_size:
+      hash = iterative_hash_object (val1->v.val_int, hash);
+      break;
+    case DW_OP_skip:
+    case DW_OP_bra:
+      {
+       int offset;
 
+       gcc_assert (val1->val_class == dw_val_class_loc);
+       offset = val1->v.val_loc->dw_loc_addr - (loc->dw_loc_addr + 3);
+       hash = iterative_hash_object (offset, hash);
+      }
+      break;
+    case DW_OP_implicit_value:
+      hash = iterative_hash_object (val1->v.val_unsigned, hash);
+      switch (val2->val_class)
+       {
+       case dw_val_class_const:
+         hash = iterative_hash_object (val2->v.val_int, hash);
+         break;
+       case dw_val_class_vec:
+         {
+           unsigned int elt_size = val2->v.val_vec.elt_size;
+           unsigned int len = val2->v.val_vec.length;
+
+           hash = iterative_hash_object (elt_size, hash);
+           hash = iterative_hash_object (len, hash);
+           hash = iterative_hash (val2->v.val_vec.array,
+                                  len * elt_size, hash);
+         }
+         break;
+       case dw_val_class_const_double:
+         hash = iterative_hash_object (val2->v.val_double.low, hash);
+         hash = iterative_hash_object (val2->v.val_double.high, hash);
+         break;
+       case dw_val_class_addr:
+         hash = iterative_hash_rtx (val2->v.val_addr, hash);
+         break;
+       default:
+         gcc_unreachable ();
+       }
+      break;
+    case DW_OP_bregx:
+    case DW_OP_bit_piece:
+      hash = iterative_hash_object (val1->v.val_int, hash);
+      hash = iterative_hash_object (val2->v.val_int, hash);
+      break;
+    case DW_OP_addr:
+    hash_addr:
+      if (loc->dtprel)
+       {
+         unsigned char dtprel = 0xd1;
+         hash = iterative_hash_object (dtprel, hash);
+       }
+      hash = iterative_hash_rtx (val1->v.val_addr, hash);
+      break;
+    case DW_OP_GNU_implicit_pointer:
+      hash = iterative_hash_object (val2->v.val_int, hash);
+      break;
+    case DW_OP_GNU_entry_value:
+      hash = hash_loc_operands (val1->v.val_loc, hash);
+      break;
+    case DW_OP_GNU_regval_type:
+    case DW_OP_GNU_deref_type:
+      {
+       unsigned int byte_size
+         = get_AT_unsigned (val2->v.val_die_ref.die, DW_AT_byte_size);
+       unsigned int encoding
+         = get_AT_unsigned (val2->v.val_die_ref.die, DW_AT_encoding);
+       hash = iterative_hash_object (val1->v.val_int, hash);
+       hash = iterative_hash_object (byte_size, hash);
+       hash = iterative_hash_object (encoding, hash);
+      }
+      break;
+    case DW_OP_GNU_convert:
+    case DW_OP_GNU_reinterpret:
+    case DW_OP_GNU_const_type:
+      {
+       unsigned int byte_size
+         = get_AT_unsigned (val1->v.val_die_ref.die, DW_AT_byte_size);
+       unsigned int encoding
+         = get_AT_unsigned (val1->v.val_die_ref.die, DW_AT_encoding);
+       hash = iterative_hash_object (byte_size, hash);
+       hash = iterative_hash_object (encoding, hash);
+       if (loc->dw_loc_opc != DW_OP_GNU_const_type)
+         break;
+       hash = iterative_hash_object (val2->val_class, hash);
+       switch (val2->val_class)
+         {
+         case dw_val_class_const:
+           hash = iterative_hash_object (val2->v.val_int, hash);
+           break;
+         case dw_val_class_vec:
+           {
+             unsigned int elt_size = val2->v.val_vec.elt_size;
+             unsigned int len = val2->v.val_vec.length;
+
+             hash = iterative_hash_object (elt_size, hash);
+             hash = iterative_hash_object (len, hash);
+             hash = iterative_hash (val2->v.val_vec.array,
+                                    len * elt_size, hash);
+           }
+           break;
+         case dw_val_class_const_double:
+           hash = iterative_hash_object (val2->v.val_double.low, hash);
+           hash = iterative_hash_object (val2->v.val_double.high, hash);
+           break;
+         default:
+           gcc_unreachable ();
+         }
+      }
+      break;
+
+    default:
+      /* Other codes have no operands.  */
+      break;
+    }
+  return hash;
+}
+
+/* Iteratively hash the whole DWARF location expression LOC.  */
+
+static inline hashval_t
+hash_locs (dw_loc_descr_ref loc, hashval_t hash)
+{
+  dw_loc_descr_ref l;
+  bool sizes_computed = false;
+  /* Compute sizes, so that DW_OP_skip/DW_OP_bra can be checksummed.  */
+  size_of_locs (loc);
+
+  for (l = loc; l != NULL; l = l->dw_loc_next)
+    {
+      enum dwarf_location_atom opc = l->dw_loc_opc;
+      hash = iterative_hash_object (opc, hash);
+      if ((opc == DW_OP_skip || opc == DW_OP_bra) && !sizes_computed)
+       {
+         size_of_locs (loc);
+         sizes_computed = true;
+       }
+      hash = hash_loc_operands (l, hash);
+    }
+  return hash;
+}
+
+/* Compute hash of the whole location list LIST_HEAD.  */
+
+static inline void
+hash_loc_list (dw_loc_list_ref list_head)
+{
+  dw_loc_list_ref curr = list_head;
+  hashval_t hash = 0;
+
+  for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
+    {
+      hash = iterative_hash (curr->begin, strlen (curr->begin) + 1, hash);
+      hash = iterative_hash (curr->end, strlen (curr->end) + 1, hash);
+      if (curr->section)
+       hash = iterative_hash (curr->section, strlen (curr->section) + 1,
+                              hash);
+      hash = hash_locs (curr->expr, hash);
+    }
+  list_head->hash = hash;
+}
+
+/* Return true if X and Y opcodes have the same operands.  */
+
+static inline bool
+compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y)
+{
+  dw_val_ref valx1 = &x->dw_loc_oprnd1;
+  dw_val_ref valx2 = &x->dw_loc_oprnd2;
+  dw_val_ref valy1 = &y->dw_loc_oprnd1;
+  dw_val_ref valy2 = &y->dw_loc_oprnd2;
+
+  switch (x->dw_loc_opc)
+    {
+    case DW_OP_const4u:
+    case DW_OP_const8u:
+      if (x->dtprel)
+       goto hash_addr;
+      /* FALLTHRU */
+    case DW_OP_const1u:
+    case DW_OP_const1s:
+    case DW_OP_const2u:
+    case DW_OP_const2s:
+    case DW_OP_const4s:
+    case DW_OP_const8s:
+    case DW_OP_constu:
+    case DW_OP_consts:
+    case DW_OP_pick:
+    case DW_OP_plus_uconst:
+    case DW_OP_breg0:
+    case DW_OP_breg1:
+    case DW_OP_breg2:
+    case DW_OP_breg3:
+    case DW_OP_breg4:
+    case DW_OP_breg5:
+    case DW_OP_breg6:
+    case DW_OP_breg7:
+    case DW_OP_breg8:
+    case DW_OP_breg9:
+    case DW_OP_breg10:
+    case DW_OP_breg11:
+    case DW_OP_breg12:
+    case DW_OP_breg13:
+    case DW_OP_breg14:
+    case DW_OP_breg15:
+    case DW_OP_breg16:
+    case DW_OP_breg17:
+    case DW_OP_breg18:
+    case DW_OP_breg19:
+    case DW_OP_breg20:
+    case DW_OP_breg21:
+    case DW_OP_breg22:
+    case DW_OP_breg23:
+    case DW_OP_breg24:
+    case DW_OP_breg25:
+    case DW_OP_breg26:
+    case DW_OP_breg27:
+    case DW_OP_breg28:
+    case DW_OP_breg29:
+    case DW_OP_breg30:
+    case DW_OP_breg31:
+    case DW_OP_regx:
+    case DW_OP_fbreg:
+    case DW_OP_piece:
+    case DW_OP_deref_size:
+    case DW_OP_xderef_size:
+      return valx1->v.val_int == valy1->v.val_int;
+    case DW_OP_skip:
+    case DW_OP_bra:
+      gcc_assert (valx1->val_class == dw_val_class_loc
+                 && valy1->val_class == dw_val_class_loc
+                 && x->dw_loc_addr == y->dw_loc_addr);
+      return valx1->v.val_loc->dw_loc_addr == valy1->v.val_loc->dw_loc_addr;
+    case DW_OP_implicit_value:
+      if (valx1->v.val_unsigned != valy1->v.val_unsigned
+         || valx2->val_class != valy2->val_class)
+       return false;
+      switch (valx2->val_class)
+       {
+       case dw_val_class_const:
+         return valx2->v.val_int == valy2->v.val_int;
+       case dw_val_class_vec:
+         return valx2->v.val_vec.elt_size == valy2->v.val_vec.elt_size
+                && valx2->v.val_vec.length == valy2->v.val_vec.length
+                && memcmp (valx2->v.val_vec.array, valy2->v.val_vec.array,
+                           valx2->v.val_vec.elt_size
+                           * valx2->v.val_vec.length) == 0;
+       case dw_val_class_const_double:
+         return valx2->v.val_double.low == valy2->v.val_double.low
+                && valx2->v.val_double.high == valy2->v.val_double.high;
+       case dw_val_class_addr:
+         return rtx_equal_p (valx2->v.val_addr, valy2->v.val_addr);
+       default:
+         gcc_unreachable ();
+       }
+    case DW_OP_bregx:
+    case DW_OP_bit_piece:
+      return valx1->v.val_int == valy1->v.val_int
+            && valx2->v.val_int == valy2->v.val_int;
+    case DW_OP_addr:
+    hash_addr:
+      return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr);
+    case DW_OP_GNU_implicit_pointer:
+      return valx1->val_class == dw_val_class_die_ref
+            && valx1->val_class == valy1->val_class
+            && valx1->v.val_die_ref.die == valy1->v.val_die_ref.die
+            && valx2->v.val_int == valy2->v.val_int;
+    case DW_OP_GNU_entry_value:
+      return compare_loc_operands (valx1->v.val_loc, valy1->v.val_loc);
+    case DW_OP_GNU_const_type:
+      if (valx1->v.val_die_ref.die != valy1->v.val_die_ref.die
+         || valx2->val_class != valy2->val_class)
+       return false;
+      switch (valx2->val_class)
+       {
+       case dw_val_class_const:
+         return valx2->v.val_int == valy2->v.val_int;
+       case dw_val_class_vec:
+         return valx2->v.val_vec.elt_size == valy2->v.val_vec.elt_size
+                && valx2->v.val_vec.length == valy2->v.val_vec.length
+                && memcmp (valx2->v.val_vec.array, valy2->v.val_vec.array,
+                           valx2->v.val_vec.elt_size
+                           * valx2->v.val_vec.length) == 0;
+       case dw_val_class_const_double:
+         return valx2->v.val_double.low == valy2->v.val_double.low
+                && valx2->v.val_double.high == valy2->v.val_double.high;
+       default:
+         gcc_unreachable ();
+       }
+    case DW_OP_GNU_regval_type:
+    case DW_OP_GNU_deref_type:
+      return valx1->v.val_int == valy1->v.val_int
+            && valx2->v.val_die_ref.die == valy2->v.val_die_ref.die;
+    case DW_OP_GNU_convert:
+    case DW_OP_GNU_reinterpret:
+      return valx1->v.val_die_ref.die == valy1->v.val_die_ref.die;
+    default:
+      /* Other codes have no operands.  */
+      return true;
+    }
+}
+
+/* Return true if DWARF location expressions X and Y are the same.  */
+
+static inline bool
+compare_locs (dw_loc_descr_ref x, dw_loc_descr_ref y)
+{
+  for (; x != NULL && y != NULL; x = x->dw_loc_next, y = y->dw_loc_next)
+    if (x->dw_loc_opc != y->dw_loc_opc
+       || x->dtprel != y->dtprel
+       || !compare_loc_operands (x, y))
+      break;
+  return x == NULL && y == NULL;
+}
+
+/* Return precomputed hash of location list X.  */
+
+static hashval_t
+loc_list_hash (const void *x)
+{
+  return ((const struct dw_loc_list_struct *) x)->hash;
+}
+
+/* Return 1 if location lists X and Y are the same.  */
+
+static int
+loc_list_eq (const void *x, const void *y)
+{
+  const struct dw_loc_list_struct *a = (const struct dw_loc_list_struct *) x;
+  const struct dw_loc_list_struct *b = (const struct dw_loc_list_struct *) y;
+  if (a == b)
+    return 1;
+  if (a->hash != b->hash)
+    return 0;
+  for (; a != NULL && b != NULL; a = a->dw_loc_next, b = b->dw_loc_next)
+    if (strcmp (a->begin, b->begin) != 0
+       || strcmp (a->end, b->end) != 0
+       || (a->section == NULL) != (b->section == NULL)
+       || (a->section && strcmp (a->section, b->section) != 0)
+       || !compare_locs (a->expr, b->expr))
+      break;
+  return a == NULL && b == NULL;
+}
+
+/* Recursively optimize location lists referenced from DIE
+   children and share them whenever possible.  */
+
+static void
+optimize_location_lists_1 (dw_die_ref die, htab_t htab)
+{
+  dw_die_ref c;
+  dw_attr_ref a;
+  unsigned ix;
+  void **slot;
+
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
+    if (AT_class (a) == dw_val_class_loc_list)
+      {
+       dw_loc_list_ref list = AT_loc_list (a);
+       /* TODO: perform some optimizations here, before hashing
+          it and storing into the hash table.  */
+       hash_loc_list (list);
+       slot = htab_find_slot_with_hash (htab, list, list->hash,
+                                        INSERT);
+       if (*slot == NULL)
+         *slot = (void *) list;
+       else
+         a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
+      }
+
+  FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab));
+}
+
+/* Optimize location lists referenced from DIE
+   children and share them whenever possible.  */
+
+static void
+optimize_location_lists (dw_die_ref die)
+{
+  htab_t htab = htab_create (500, loc_list_hash, loc_list_eq, NULL);
+  optimize_location_lists_1 (die, htab);
+  htab_delete (htab);
+}
+\f
 /* Output stuff that dwarf requires at the end of every file,
    and generate the DWARF-2 debugging info.  */
 
@@ -22247,22 +24276,22 @@ 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_scheduled_generic_parms_dies ();
   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));
+  add_name_attribute (comp_unit_die (), remap_debug_filename (filename));
   if (!IS_ABSOLUTE_PATH (filename))
-    add_comp_dir_attribute (comp_unit_die);
-  else if (get_AT (comp_unit_die, DW_AT_comp_dir) == NULL)
+    add_comp_dir_attribute (comp_unit_die ());
+  else if (get_AT (comp_unit_die (), DW_AT_comp_dir) == NULL)
     {
       bool p = false;
       htab_traverse (file_table, file_table_relative_p, &p);
       if (p)
-       add_comp_dir_attribute (comp_unit_die);
+       add_comp_dir_attribute (comp_unit_die ());
     }
 
   for (i = 0; i < VEC_length (deferred_locations, deferred_locations_list); i++)
@@ -22270,6 +24299,7 @@ dwarf2out_finish (const char *filename)
       add_location_or_const_value_attribute (
         VEC_index (deferred_locations, deferred_locations_list, i)->die,
         VEC_index (deferred_locations, deferred_locations_list, i)->variable,
+       false,
        DW_AT_location);
     }
 
@@ -22280,8 +24310,8 @@ dwarf2out_finish (const char *filename)
      instance.  */
   for (node = limbo_die_list; node; node = next_node)
     {
+      dw_die_ref die = node->die;
       next_node = node->next;
-      die = node->die;
 
       if (die->die_parent == NULL)
        {
@@ -22289,11 +24319,11 @@ dwarf2out_finish (const char *filename)
 
          if (origin)
            add_child_die (origin->die_parent, die);
-         else if (die == comp_unit_die)
+         else if (is_cu_die (die))
            ;
          else if (seen_error ())
            /* It's OK to be confused by errors in the input.  */
-           add_child_die (comp_unit_die, die);
+           add_child_die (comp_unit_die (), die);
          else
            {
              /* In certain situations, the lexical block containing a
@@ -22323,14 +24353,21 @@ dwarf2out_finish (const char *filename)
              if (origin)
                add_child_die (origin, die);
              else
-               add_child_die (comp_unit_die, die);
+               add_child_die (comp_unit_die (), die);
            }
        }
     }
 
   limbo_die_list = NULL;
 
-  resolve_addr (comp_unit_die);
+#if ENABLE_ASSERT_CHECKING
+  {
+    dw_die_ref die = comp_unit_die (), c;
+    FOR_EACH_CHILD (die, c, gcc_assert (! c->die_mark));
+  }
+#endif
+  resolve_addr (comp_unit_die ());
+  move_marked_base_types ();
 
   for (node = deferred_asm_name; node; node = node->next)
     {
@@ -22353,13 +24390,13 @@ 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 && dwarf_version < 4)
-    break_out_includes (comp_unit_die);
+  if (flag_eliminate_dwarf2_dups && ! use_debug_types)
+    break_out_includes (comp_unit_die ());
 
   /* Generate separate COMDAT sections for type DIEs. */
-  if (dwarf_version >= 4)
+  if (use_debug_types)
     {
-      break_out_comdat_types (comp_unit_die);
+      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
@@ -22371,7 +24408,7 @@ dwarf2out_finish (const char *filename)
          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);
+      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
@@ -22381,7 +24418,7 @@ dwarf2out_finish (const char *filename)
 
   /* Traverse the DIE's and add add sibling attributes to those DIE's
      that have children.  */
-  add_sibling_attributes (comp_unit_die);
+  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)
@@ -22390,84 +24427,72 @@ dwarf2out_finish (const char *filename)
   /* Output a terminator label for the .text section.  */
   switch_to_section (text_section);
   targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
-  if (flag_reorder_blocks_and_partition)
+  if (cold_text_section)
     {
-      switch_to_section (unlikely_text_section ());
+      switch_to_section (cold_text_section);
       targetm.asm_out.internal_label (asm_out_file, COLD_END_LABEL, 0);
     }
 
   /* We can only use the low/high_pc attributes if all of the code was
      in .text.  */
-  if (!have_multiple_function_sections
-      || !(dwarf_version >= 3 || !dwarf_strict))
+  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);
+      /* Don't add if the CU has no associated code.  */
+      if (text_section_used)
+       {
+         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);
+       }
     }
-
   else
     {
       unsigned fde_idx = 0;
       bool range_list_added = false;
 
-      /* We need to give .debug_loc and .debug_ranges an appropriate
-        "base address".  Use zero so that these addresses become
-        absolute.  Historically, we've emitted the unexpected
-        DW_AT_entry_pc instead of DW_AT_low_pc for this purpose.
-        Emit both to give time for other tools to adapt.  */
-      add_AT_addr (comp_unit_die, DW_AT_low_pc, const0_rtx);
-      add_AT_addr (comp_unit_die, DW_AT_entry_pc, const0_rtx);
-
       if (text_section_used)
-       add_ranges_by_labels (comp_unit_die, text_section_label,
+       add_ranges_by_labels (comp_unit_die (), text_section_label,
                              text_end_label, &range_list_added);
-      if (flag_reorder_blocks_and_partition && cold_text_section_used)
-       add_ranges_by_labels (comp_unit_die, cold_text_section_label,
+      if (cold_text_section_used)
+       add_ranges_by_labels (comp_unit_die (), cold_text_section_label,
                              cold_end_label, &range_list_added);
 
       for (fde_idx = 0; fde_idx < fde_table_in_use; fde_idx++)
        {
          dw_fde_ref fde = &fde_table[fde_idx];
 
-         if (fde->dw_fde_switched_sections)
-           {
-             if (!fde->in_std_section)
-               add_ranges_by_labels (comp_unit_die,
-                                     fde->dw_fde_hot_section_label,
-                                     fde->dw_fde_hot_section_end_label,
-                                     &range_list_added);
-             if (!fde->cold_in_std_section)
-               add_ranges_by_labels (comp_unit_die,
-                                     fde->dw_fde_unlikely_section_label,
-                                     fde->dw_fde_unlikely_section_end_label,
-                                     &range_list_added);
-           }
-         else if (!fde->in_std_section)
-           add_ranges_by_labels (comp_unit_die, fde->dw_fde_begin,
+         if (!fde->in_std_section)
+           add_ranges_by_labels (comp_unit_die (), fde->dw_fde_begin,
                                  fde->dw_fde_end, &range_list_added);
+         if (fde->dw_fde_second_begin && !fde->second_in_std_section)
+           add_ranges_by_labels (comp_unit_die (), fde->dw_fde_second_begin,
+                                 fde->dw_fde_second_end, &range_list_added);
        }
 
       if (range_list_added)
-       add_ranges (NULL);
-    }
-
-  /* Output location list section if necessary.  */
-  if (have_location_lists)
-    {
-      /* Output the location lists info.  */
-      switch_to_section (debug_loc_section);
-      ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
-                                  DEBUG_LOC_SECTION_LABEL, 0);
-      ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
-      output_location_lists (die);
+       {
+         /* We need to give .debug_loc and .debug_ranges an appropriate
+            "base address".  Use zero so that these addresses become
+            absolute.  Historically, we've emitted the unexpected
+            DW_AT_entry_pc instead of DW_AT_low_pc for this purpose.
+            Emit both to give time for other tools to adapt.  */
+         add_AT_addr (comp_unit_die (), DW_AT_low_pc, const0_rtx);
+         if (! dwarf_strict && dwarf_version < 4)
+           add_AT_addr (comp_unit_die (), DW_AT_entry_pc, const0_rtx);
+
+         add_ranges (NULL);
+       }
     }
 
   if (debug_info_level >= DINFO_LEVEL_NORMAL)
-    add_AT_lineptr (comp_unit_die, DW_AT_stmt_list,
+    add_AT_lineptr (comp_unit_die (), DW_AT_stmt_list,
                    debug_line_section_label);
 
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
-    add_AT_macptr (comp_unit_die, DW_AT_macro_info, macinfo_section_label);
+    add_AT_macptr (comp_unit_die (), DW_AT_macro_info, macinfo_section_label);
+
+  if (have_location_lists)
+    optimize_location_lists (comp_unit_die ());
 
   /* Output all of the compilation units.  We put the main one last so that
      the offsets are available to output_pubnames.  */
@@ -22496,16 +24521,29 @@ dwarf2out_finish (const char *filename)
   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);
+     will be emitted.  */
+  output_comp_unit (comp_unit_die (), debug_info_level >= DINFO_LEVEL_VERBOSE);
 
   /* Output the abbreviation table.  */
   switch_to_section (debug_abbrev_section);
+  ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
   output_abbrev_section ();
 
+  /* Output location list section if necessary.  */
+  if (have_location_lists)
+    {
+      /* Output the location lists info.  */
+      switch_to_section (debug_loc_section);
+      ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
+                                  DEBUG_LOC_SECTION_LABEL, 0);
+      ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
+      output_location_lists (comp_unit_die ());
+    }
+
   /* Output public names table if necessary.  */
   if (!VEC_empty (pubname_entry, pubname_table))
     {
+      gcc_assert (info_section_emitted);
       switch_to_section (debug_pubnames_section);
       output_pubnames (pubname_table);
     }
@@ -22516,28 +24554,40 @@ dwarf2out_finish (const char *filename)
      simply won't look for the section.  */
   if (!VEC_empty (pubname_entry, pubtype_table))
     {
-      switch_to_section (debug_pubtypes_section);
-      output_pubnames (pubtype_table);
+      bool empty = false;
+      
+      if (flag_eliminate_unused_debug_types)
+       {
+         /* The pubtypes table might be emptied by pruning unused items.  */
+         unsigned i;
+         pubname_ref p;
+         empty = true;
+         FOR_EACH_VEC_ELT (pubname_entry, pubtype_table, i, p)
+           if (p->die->die_offset != 0)
+             {
+               empty = false;
+               break;
+             }
+       }
+      if (!empty)
+       {
+         gcc_assert (info_section_emitted);
+         switch_to_section (debug_pubtypes_section);
+         output_pubnames (pubtype_table);
+       }
     }
 
-  /* Output direct and virtual call tables if necessary.  */
-  if (!VEC_empty (dcall_entry, dcall_table))
+  /* Output the address range information if a CU (.debug_info section)
+     was emitted.  We output an empty table even if we had no functions
+     to put in it.  This because the consumer has no way to tell the
+     difference between an empty table that we omitted and failure to
+     generate a table that would have contained data.  */
+  if (info_section_emitted)
     {
-      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 ();
-    }
+      unsigned long aranges_length = size_of_aranges ();
 
-  /* Output the address range information.  We only put functions in the arange
-     table, so don't write it out if we don't have any.  */
-  if (fde_table_in_use)
-    {
       switch_to_section (debug_aranges_section);
-      output_aranges ();
+      output_aranges (aranges_length);
     }
 
   /* Output ranges section if necessary.  */
@@ -22554,16 +24604,18 @@ dwarf2out_finish (const char *filename)
      .debug_info section.  IRIX 6.5 `nm' will then complain when
      examining the file.  This is done late so that any filenames
      used by the debug_info section are marked as 'used'.  */
+  switch_to_section (debug_line_section);
+  ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
   if (! DWARF2_ASM_LINE_DEBUG_INFO)
-    {
-      switch_to_section (debug_line_section);
-      output_line_info ();
-    }
+    output_line_info ();
 
   /* Have to end the macro section.  */
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
     {
       switch_to_section (debug_macinfo_section);
+      ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
+      if (!VEC_empty (macinfo_entry, macinfo_table))
+        output_macinfo ();
       dw2_asm_output_data (1, 0, "End compilation unit");
     }