OSDN Git Service

* dwarf2out.c (gen_compile_unit_die): Use DW_LANG_Go for Go.
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index df9ccce..850eb55 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).
@@ -82,8 +82,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "md5.h"
 #include "tm_p.h"
 #include "diagnostic.h"
+#include "tree-pretty-print.h"
 #include "debug.h"
 #include "target.h"
+#include "common/common-target.h"
 #include "langhooks.h"
 #include "hashtab.h"
 #include "cgraph.h"
@@ -91,12 +93,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "tree-pass.h"
 #include "tree-flow.h"
+#include "cfglayout.h"
+#include "opts.h"
 
-#ifdef DWARF2_DEBUGGING_INFO
 static void dwarf2out_source_line (unsigned int, const char *, int, bool);
-
 static rtx last_var_location_insn;
-#endif
+static rtx cached_next_real_insn;
 
 #ifdef VMS_DEBUGGING_INFO
 int vms_file_stats_name (const char *, long long *, long *, char *, int *);
@@ -114,84 +116,13 @@ int vms_file_stats_name (const char *, long long *, long *, char *, int *);
 #define DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET 0
 #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.  */
-#ifndef DWARF2_FRAME_REG_OUT
-#define DWARF2_FRAME_REG_OUT(REGNO, FOR_EH) (REGNO)
-#endif
-
-/* Save the result of dwarf2out_do_frame across PCH.  */
-static GTY(()) bool saved_do_cfi_asm = 0;
-
-/* Decide whether we want to emit frame unwind information for the current
-   translation unit.  */
-
-int
-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
-#ifdef DWARF2_UNWIND_INFO
-         || (DWARF2_UNWIND_INFO
-             && (flag_unwind_tables
-                 || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS)))
-#endif
-         );
-}
-
-/* Decide whether to emit frame unwind via assembler directives.  */
-
-int
-dwarf2out_do_cfi_asm (void)
-{
-  int enc;
-
-#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 (!HAVE_GAS_CFI_PERSONALITY_DIRECTIVE)
-    return false;
-
-  /* Make sure the personality encoding is one the assembler can support.
-     In particular, aligned addresses can't be handled.  */
-  enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2,/*global=*/1);
-  if ((enc & 0x70) != 0 && (enc & 0x70) != DW_EH_PE_pcrel)
-    return false;
-  enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0,/*global=*/0);
-  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;
+/* ??? 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
-    }
-
-  saved_do_cfi_asm = true;
-  return true;
-}
 
 /* The size of the target's pointer type.  */
 #ifndef PTR_SIZE
@@ -224,138 +155,13 @@ static GTY(()) section *debug_line_section;
 static GTY(()) section *debug_loc_section;
 static GTY(()) section *debug_pubnames_section;
 static GTY(()) section *debug_pubtypes_section;
-static GTY(()) section *debug_dcall_section;
-static GTY(()) section *debug_vcall_section;
 static GTY(()) section *debug_str_section;
 static GTY(()) section *debug_ranges_section;
 static GTY(()) section *debug_frame_section;
 
-/* Personality decl of current unit.  Used only when assembler does not support
-   personality CFI.  */
-static GTY(()) rtx current_unit_personality;
-
-/* How to start an assembler comment.  */
-#ifndef ASM_COMMENT_START
-#define ASM_COMMENT_START ";#"
-#endif
-
-typedef struct dw_cfi_struct *dw_cfi_ref;
-typedef struct dw_fde_struct *dw_fde_ref;
-typedef union  dw_cfi_oprnd_struct *dw_cfi_oprnd_ref;
-
-/* Call frames are described using a sequence of Call Frame
-   Information instructions.  The register number, offset
-   and address fields are provided as possible operands;
-   their use is selected by the opcode field.  */
-
-enum dw_cfi_oprnd_type {
-  dw_cfi_oprnd_unused,
-  dw_cfi_oprnd_reg_num,
-  dw_cfi_oprnd_offset,
-  dw_cfi_oprnd_addr,
-  dw_cfi_oprnd_loc
-};
-
-typedef union GTY(()) dw_cfi_oprnd_struct {
-  unsigned int GTY ((tag ("dw_cfi_oprnd_reg_num"))) dw_cfi_reg_num;
-  HOST_WIDE_INT GTY ((tag ("dw_cfi_oprnd_offset"))) dw_cfi_offset;
-  const char * GTY ((tag ("dw_cfi_oprnd_addr"))) dw_cfi_addr;
-  struct dw_loc_descr_struct * GTY ((tag ("dw_cfi_oprnd_loc"))) dw_cfi_loc;
-}
-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;
-  dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd2_desc (%1.dw_cfi_opc)")))
-    dw_cfi_oprnd2;
-}
-dw_cfi_node;
-
-/* 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 {
-  HOST_WIDE_INT offset;
-  HOST_WIDE_INT base_offset;
-  unsigned int reg;
-  BOOL_BITFIELD indirect : 1;  /* 1 if CFA is accessed via a dereference.  */
-  BOOL_BITFIELD in_use : 1;    /* 1 if a saved cfa is stored here.  */
-} dw_cfa_location;
-
-/* All call frame descriptions (FDE's) in the GCC generated DWARF
-   refer to a single Common Information Entry (CIE), defined at
-   the beginning of the .debug_frame section.  This use of a single
-   CIE obviates the need to keep track of multiple CIE's
-   in the DWARF generation routines below.  */
-
-typedef struct GTY(()) dw_fde_struct {
-  tree decl;
-  const char *dw_fde_begin;
-  const char *dw_fde_current_label;
-  const char *dw_fde_end;
-  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.  */
-  unsigned funcdef_number;
-  HOST_WIDE_INT stack_realignment;
-  /* Dynamic realign argument pointer register.  */
-  unsigned int drap_reg;
-  /* Virtual dynamic realign argument pointer register.  */
-  unsigned int vdrap_reg;
-  unsigned all_throwers_are_sibcalls : 1;
-  unsigned nothrow : 1;
-  unsigned uses_eh_lsda : 1;
-  /* Whether we did stack realign in this call frame.  */
-  unsigned stack_realign : 1;
-  /* Whether dynamic realign argument pointer register has been saved.  */
-  unsigned drap_reg_saved: 1;
-  /* True iff dw_fde_begin label is in text_section or cold_text_section.  */
-  unsigned in_std_section : 1;
-  /* True iff dw_fde_unlikely_section_label is in text_section or
-     cold_text_section.  */
-  unsigned cold_in_std_section : 1;
-  /* True iff switched sections.  */
-  unsigned dw_fde_switched_sections : 1;
-  /* True iff switching from cold to hot section.  */
-  unsigned dw_fde_switched_cold_to_hot : 1;
-}
-dw_fde_node;
-
 /* Maximum size (in bytes) of an artificially generated label.  */
 #define MAX_ARTIFICIAL_LABEL_BYTES     30
 
-/* The size of addresses as they appear in the Dwarf 2 data.
-   Some architectures use word addresses to refer to code locations,
-   but Dwarf 2 info always uses byte addresses.  On such machines,
-   Dwarf 2 addresses need to be larger than the architecture's
-   pointers.  */
-#ifndef DWARF2_ADDR_SIZE
-#define DWARF2_ADDR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
-#endif
-
-/* The size in bytes of a DWARF field indicating an offset or length
-   relative to a debug info section, specified to be 4 bytes in the
-   DWARF-2 specification.  The SGI/MIPS ABI defines it to be the same
-   as PTR_SIZE.  */
-
-#ifndef DWARF_OFFSET_SIZE
-#define DWARF_OFFSET_SIZE 4
-#endif
-
-/* The size in bytes of a DWARF 4 type signature.  */
-
-#ifndef DWARF_TYPE_SIGNATURE_SIZE
-#define DWARF_TYPE_SIGNATURE_SIZE 8
-#endif
-
 /* According to the (draft) DWARF 3 specification, the initial length
    should either be 4 or 12 bytes.  When it's 12 bytes, the first 4
    bytes are 0xffffffff, followed by the length stored in the next 8
@@ -372,15 +178,6 @@ dw_fde_node;
 #define DWARF_ROUND(SIZE,BOUNDARY) \
   ((((SIZE) + (BOUNDARY) - 1) / (BOUNDARY)) * (BOUNDARY))
 
-/* Offsets recorded in opcodes are a multiple of this alignment factor.  */
-#ifndef DWARF_CIE_DATA_ALIGNMENT
-#ifdef STACK_GROWS_DOWNWARD
-#define DWARF_CIE_DATA_ALIGNMENT (-((int) UNITS_PER_WORD))
-#else
-#define DWARF_CIE_DATA_ALIGNMENT ((int) UNITS_PER_WORD)
-#endif
-#endif
-
 /* CIE identifier.  */
 #if HOST_BITS_PER_WIDE_INT >= 64
 #define DWARF_CIE_ID \
@@ -389,38 +186,12 @@ dw_fde_node;
 #define DWARF_CIE_ID DW_CIE_ID
 #endif
 
-/* A pointer to the base of a table that contains frame description
-   information for each routine.  */
-static GTY((length ("fde_table_allocated"))) dw_fde_ref fde_table;
-
-/* Number of elements currently allocated for fde_table.  */
-static GTY(()) unsigned fde_table_allocated;
-
-/* Number of elements in fde_table currently in use.  */
-static GTY(()) unsigned fde_table_in_use;
-
-/* Size (in elements) of increments by which we may expand the
-   fde_table.  */
-#define FDE_TABLE_INCREMENT 256
-
-/* Get the current fde_table entry we should use.  */
-
-static inline dw_fde_ref
-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;
+DEF_VEC_P (dw_fde_ref);
+DEF_VEC_ALLOC_P (dw_fde_ref, gc);
 
-#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
-/* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram
-   attribute that accelerates the lookup of the FDE associated
-   with the subprogram.  This variable holds the table index of the FDE
-   associated with the current function (body) definition.  */
-static unsigned current_funcdef_fde;
-#endif
+/* A vector for a table that contains frame description
+   information for each routine.  */
+static GTY(()) VEC(dw_fde_ref, gc) *fde_vec;
 
 struct GTY(()) indirect_string_node {
   const char *str;
@@ -431,12 +202,7 @@ 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;
 
 /* True if the compilation unit places functions in more than one section.  */
 static GTY(()) bool have_multiple_function_sections = false;
@@ -449,46 +215,15 @@ static GTY(()) bool cold_text_section_used = false;
 /* The default cold text section.  */
 static GTY(()) section *cold_text_section;
 
-#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
-
 /* Forward declarations for functions defined in this file.  */
 
 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_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 *);
-static void reg_save (const char *, unsigned, unsigned, HOST_WIDE_INT);
-#ifdef DWARF2_UNWIND_INFO
-static void initial_return_save (rtx);
-#endif
-static HOST_WIDE_INT stack_adjust_offset (const_rtx, HOST_WIDE_INT,
-                                         HOST_WIDE_INT);
-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_raw (dw_cfi_ref);
-static void get_cfa_from_loc_descr (dw_cfa_location *,
-                                   struct dw_loc_descr_struct *);
-static struct dw_loc_descr_struct *build_cfa_loc
-  (dw_cfa_location *, HOST_WIDE_INT);
-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 *);
-
-/* How to start an assembler comment.  */
-#ifndef ASM_COMMENT_START
-#define ASM_COMMENT_START ";#"
-#endif
+
+/* Personality decl of current unit.  Used only when assembler does not support
+   personality CFI.  */
+static GTY(()) rtx current_unit_personality;
 
 /* Data and reference forms for relocatable data.  */
 #define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4)
@@ -506,6 +241,14 @@ static void def_cfa_1 (const char *, dw_cfa_location *);
 #define FUNC_END_LABEL         "LFE"
 #endif
 
+#ifndef PROLOGUE_END_LABEL
+#define PROLOGUE_END_LABEL     "LPE"
+#endif
+
+#ifndef EPILOGUE_BEGIN_LABEL
+#define EPILOGUE_BEGIN_LABEL   "LEB"
+#endif
+
 #ifndef FRAME_BEGIN_LABEL
 #define FRAME_BEGIN_LABEL      "Lframe"
 #endif
@@ -519,33 +262,90 @@ static void def_cfa_1 (const char *, dw_cfa_location *);
 #define LN_PROLOG_AS_LABEL     "LASLTP"
 #define LN_PROLOG_END_LABEL    "LELTP"
 #define DIE_LABEL_PREFIX       "DW"
+\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)
 
-/* The DWARF 2 CFA column which tracks the return address.  Normally this
-   is the column for PC, or the first column after all of the hard
-   registers.  */
-#ifndef DWARF_FRAME_RETURN_COLUMN
-#ifdef PC_REGNUM
-#define DWARF_FRAME_RETURN_COLUMN      DWARF_FRAME_REGNUM (PC_REGNUM)
 #else
-#define DWARF_FRAME_RETURN_COLUMN      DWARF_FRAME_REGISTERS
-#endif
-#endif
 
-/* The mapping from gcc register number to DWARF 2 CFA column number.  By
-   default, we just provide columns for all registers.  */
-#ifndef DWARF_FRAME_REGNUM
-#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
+#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
+  (result)
+
 #endif
-\f
-/* Hook used by __throw.  */
 
-rtx
-expand_builtin_dwarf_sp_column (void)
+static bool
+should_emit_struct_debug (tree type, enum debug_info_usage usage)
 {
-  unsigned int dwarf_regnum = DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM);
-  return GEN_INT (DWARF2_FRAME_REG_OUT (dwarf_regnum, 1));
-}
+  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
 /* Return a pointer to a copy of the section string name S with all
    attributes stripped off, and an asterisk prepended (for assemble_name).  */
 
@@ -564,3689 +364,844 @@ stripattributes (const char *s)
   return stripped;
 }
 
-/* MEM is a memory reference for the register size table, each element of
-   which has mode MODE.  Initialize column C as a return address column.  */
+/* Switch [BACK] to eh_frame_section.  If we don't have an eh_frame_section,
+   switch to the data section instead, and write out a synthetic start label
+   for collect2 the first time around.  */
 
 static void
-init_return_column_size (enum machine_mode mode, rtx mem, unsigned int c)
-{
-  HOST_WIDE_INT offset = c * GET_MODE_SIZE (mode);
-  HOST_WIDE_INT size = GET_MODE_SIZE (Pmode);
-  emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
-}
-
-/* Divide OFF by DWARF_CIE_DATA_ALIGNMENT, asserting no remainder.  */
-
-static inline HOST_WIDE_INT
-div_data_align (HOST_WIDE_INT off)
+switch_to_eh_frame_section (bool back)
 {
-  HOST_WIDE_INT r = off / DWARF_CIE_DATA_ALIGNMENT;
-  gcc_assert (r * DWARF_CIE_DATA_ALIGNMENT == off);
-  return r;
-}
-
-/* Return true if we need a signed version of a given opcode
-   (e.g. DW_CFA_offset_extended_sf vs DW_CFA_offset_extended).  */
+  tree label;
 
-static inline bool
-need_data_align_sf_opcode (HOST_WIDE_INT off)
-{
-  return DWARF_CIE_DATA_ALIGNMENT < 0 ? off > 0 : off < 0;
-}
+#ifdef EH_FRAME_SECTION_NAME
+  if (eh_frame_section == 0)
+    {
+      int flags;
 
-/* Generate code to initialize the register size table.  */
+      if (EH_TABLES_CAN_BE_READ_ONLY)
+       {
+         int fde_encoding;
+         int per_encoding;
+         int lsda_encoding;
 
-void
-expand_builtin_init_dwarf_reg_sizes (tree address)
-{
-  unsigned int i;
-  enum machine_mode mode = TYPE_MODE (char_type_node);
-  rtx addr = expand_normal (address);
-  rtx mem = gen_rtx_MEM (BLKmode, addr);
-  bool wrote_return_column = false;
+         fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1,
+                                                      /*global=*/0);
+         per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2,
+                                                      /*global=*/1);
+         lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0,
+                                                       /*global=*/0);
+         flags = ((! flag_pic
+                   || ((fde_encoding & 0x70) != DW_EH_PE_absptr
+                       && (fde_encoding & 0x70) != DW_EH_PE_aligned
+                       && (per_encoding & 0x70) != DW_EH_PE_absptr
+                       && (per_encoding & 0x70) != DW_EH_PE_aligned
+                       && (lsda_encoding & 0x70) != DW_EH_PE_absptr
+                       && (lsda_encoding & 0x70) != DW_EH_PE_aligned))
+                  ? 0 : SECTION_WRITE);
+       }
+      else
+       flags = SECTION_WRITE;
+      eh_frame_section = get_section (EH_FRAME_SECTION_NAME, flags, NULL);
+    }
+#endif /* EH_FRAME_SECTION_NAME */
 
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+  if (eh_frame_section)
+    switch_to_section (eh_frame_section);
+  else
     {
-      int rnum = DWARF2_FRAME_REG_OUT (DWARF_FRAME_REGNUM (i), 1);
+      /* We have no special eh_frame section.  Put the information in
+        the data section and emit special labels to guide collect2.  */
+      switch_to_section (data_section);
 
-      if (rnum < DWARF_FRAME_REGISTERS)
+      if (!back)
        {
-         HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (mode);
-         enum machine_mode save_mode = reg_raw_mode[i];
-         HOST_WIDE_INT size;
-
-         if (HARD_REGNO_CALL_PART_CLOBBERED (i, save_mode))
-           save_mode = choose_hard_reg_mode (i, 1, true);
-         if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN)
-           {
-             if (save_mode == VOIDmode)
-               continue;
-             wrote_return_column = true;
-           }
-         size = GET_MODE_SIZE (save_mode);
-         if (offset < 0)
-           continue;
-
-         emit_move_insn (adjust_address (mem, mode, offset),
-                         gen_int_mode (size, mode));
+         label = get_file_function_name ("F");
+         ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+         targetm.asm_out.globalize_label (asm_out_file,
+                                          IDENTIFIER_POINTER (label));
+         ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
        }
     }
+}
 
-  if (!wrote_return_column)
-    init_return_column_size (mode, mem, DWARF_FRAME_RETURN_COLUMN);
-
-#ifdef DWARF_ALT_FRAME_RETURN_COLUMN
-  init_return_column_size (mode, mem, DWARF_ALT_FRAME_RETURN_COLUMN);
-#endif
+/* Switch [BACK] to the eh or debug frame table section, depending on
+   FOR_EH.  */
 
-  targetm.init_dwarf_reg_sizes_extra (address);
+static void
+switch_to_frame_table_section (int for_eh, bool back)
+{
+  if (for_eh)
+    switch_to_eh_frame_section (back);
+  else
+    {
+      if (!debug_frame_section)
+       debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+                                          SECTION_DEBUG, NULL);
+      switch_to_section (debug_frame_section);
+    }
 }
 
-/* Convert a DWARF call frame info. operation to its string name */
+/* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used.  */
 
-static const char *
-dwarf_cfi_name (unsigned int cfi_opc)
+enum dw_cfi_oprnd_type
+dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
 {
-  switch (cfi_opc)
+  switch (cfi)
     {
-    case DW_CFA_advance_loc:
-      return "DW_CFA_advance_loc";
-    case DW_CFA_offset:
-      return "DW_CFA_offset";
-    case DW_CFA_restore:
-      return "DW_CFA_restore";
     case DW_CFA_nop:
-      return "DW_CFA_nop";
+    case DW_CFA_GNU_window_save:
+    case DW_CFA_remember_state:
+    case DW_CFA_restore_state:
+      return dw_cfi_oprnd_unused;
+
     case DW_CFA_set_loc:
-      return "DW_CFA_set_loc";
     case DW_CFA_advance_loc1:
-      return "DW_CFA_advance_loc1";
     case DW_CFA_advance_loc2:
-      return "DW_CFA_advance_loc2";
     case DW_CFA_advance_loc4:
-      return "DW_CFA_advance_loc4";
+    case DW_CFA_MIPS_advance_loc8:
+      return dw_cfi_oprnd_addr;
+
+    case DW_CFA_offset:
     case DW_CFA_offset_extended:
-      return "DW_CFA_offset_extended";
+    case DW_CFA_def_cfa:
+    case DW_CFA_offset_extended_sf:
+    case DW_CFA_def_cfa_sf:
+    case DW_CFA_restore:
     case DW_CFA_restore_extended:
-      return "DW_CFA_restore_extended";
     case DW_CFA_undefined:
-      return "DW_CFA_undefined";
     case DW_CFA_same_value:
-      return "DW_CFA_same_value";
-    case DW_CFA_register:
-      return "DW_CFA_register";
-    case DW_CFA_remember_state:
-      return "DW_CFA_remember_state";
-    case DW_CFA_restore_state:
-      return "DW_CFA_restore_state";
-    case DW_CFA_def_cfa:
-      return "DW_CFA_def_cfa";
     case DW_CFA_def_cfa_register:
-      return "DW_CFA_def_cfa_register";
-    case DW_CFA_def_cfa_offset:
-      return "DW_CFA_def_cfa_offset";
-
-    /* DWARF 3 */
-    case DW_CFA_def_cfa_expression:
-      return "DW_CFA_def_cfa_expression";
+    case DW_CFA_register:
     case DW_CFA_expression:
-      return "DW_CFA_expression";
-    case DW_CFA_offset_extended_sf:
-      return "DW_CFA_offset_extended_sf";
-    case DW_CFA_def_cfa_sf:
-      return "DW_CFA_def_cfa_sf";
-    case DW_CFA_def_cfa_offset_sf:
-      return "DW_CFA_def_cfa_offset_sf";
-
-    /* SGI/MIPS specific */
-    case DW_CFA_MIPS_advance_loc8:
-      return "DW_CFA_MIPS_advance_loc8";
+      return dw_cfi_oprnd_reg_num;
 
-    /* GNU extensions */
-    case DW_CFA_GNU_window_save:
-      return "DW_CFA_GNU_window_save";
+    case DW_CFA_def_cfa_offset:
     case DW_CFA_GNU_args_size:
-      return "DW_CFA_GNU_args_size";
-    case DW_CFA_GNU_negative_offset_extended:
-      return "DW_CFA_GNU_negative_offset_extended";
+    case DW_CFA_def_cfa_offset_sf:
+      return dw_cfi_oprnd_offset;
+
+    case DW_CFA_def_cfa_expression:
+      return dw_cfi_oprnd_loc;
 
     default:
-      return "DW_CFA_<unknown>";
+      gcc_unreachable ();
     }
 }
 
-/* Return a pointer to a newly allocated Call Frame Instruction.  */
+/* Describe for the GTY machinery what parts of dw_cfi_oprnd2 are used.  */
 
-static inline dw_cfi_ref
-new_cfi (void)
+enum dw_cfi_oprnd_type
+dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
 {
-  dw_cfi_ref cfi = GGC_NEW (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;
+  switch (cfi)
+    {
+    case DW_CFA_def_cfa:
+    case DW_CFA_def_cfa_sf:
+    case DW_CFA_offset:
+    case DW_CFA_offset_extended_sf:
+    case DW_CFA_offset_extended:
+      return dw_cfi_oprnd_offset;
 
-  return cfi;
-}
+    case DW_CFA_register:
+      return dw_cfi_oprnd_reg_num;
 
-/* Add a Call Frame Instruction to list of instructions.  */
+    case DW_CFA_expression:
+      return dw_cfi_oprnd_loc;
 
-static inline void
-add_cfi (dw_cfi_ref *list_head, 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
-     CFA may lead to a different CFA value.   */
-  /* ??? Of course, this heuristic fails when we're annotating epilogues,
-     because of course we'll always want to redefine the CFA back to the
-     stack pointer on the way out.  Where should we move this check?  */
-  if (0 && fde && fde->drap_reg != INVALID_REGNUM)
-    switch (cfi->dw_cfi_opc)
-      {
-        case DW_CFA_def_cfa_register:
-        case DW_CFA_def_cfa_offset:
-        case DW_CFA_def_cfa_offset_sf:
-        case DW_CFA_def_cfa:
-        case DW_CFA_def_cfa_sf:
-         gcc_unreachable ();
+    default:
+      return dw_cfi_oprnd_unused;
+    }
+}
 
-        default:
-          break;
-      }
+/* Output one FDE.  */
 
-  /* Find the end of the chain.  */
-  for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next)
-    ;
+static void
+output_fde (dw_fde_ref fde, bool for_eh, bool second,
+           char *section_start_label, int fde_encoding, char *augmentation,
+           bool any_lsda_needed, int lsda_encoding)
+{
+  const char *begin, *end;
+  static unsigned int j;
+  char l1[20], l2[20];
 
-  *p = cfi;
-}
+  targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, for_eh,
+                                    /* empty */ 0);
+  targetm.asm_out.internal_label (asm_out_file, FDE_LABEL,
+                                 for_eh + j);
+  ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + j);
+  ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + j);
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
+    dw2_asm_output_data (4, 0xffffffff, "Initial length escape value"
+                        " indicating 64-bit DWARF extension");
+  dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
+                       "FDE Length");
+  ASM_OUTPUT_LABEL (asm_out_file, l1);
 
-/* Generate a new label for the CFI info to refer to.  FORCE is true
-   if a label needs to be output even when using .cfi_* directives.  */
+  if (for_eh)
+    dw2_asm_output_delta (4, l1, section_start_label, "FDE CIE offset");
+  else
+    dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label,
+                          debug_frame_section, "FDE CIE offset");
 
-char *
-dwarf2out_cfi_label (bool force)
-{
-  static char label[20];
+  begin = second ? fde->dw_fde_second_begin : fde->dw_fde_begin;
+  end = second ? fde->dw_fde_second_end : fde->dw_fde_end;
 
-  if (!force && dwarf2out_do_cfi_asm ())
+  if (for_eh)
     {
-      /* In this case, we will be emitting the asm directive instead of
-        the label, so just return a placeholder to keep the rest of the
-        interfaces happy.  */
-      strcpy (label, "<do not output>");
+      rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, begin);
+      SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
+      dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref, false,
+                                      "FDE initial location");
+      dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+                           end, begin, "FDE address range");
     }
   else
     {
-      ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", dwarf2out_cfi_label_num++);
-      ASM_OUTPUT_LABEL (asm_out_file, label);
-    }
-
-  return label;
-}
-
-/* True if remember_state should be emitted before following CFI directive.  */
-static bool emit_cfa_remember;
-
-/* Add CFI to the current fde at the PC value indicated by LABEL if specified,
-   or to the CIE if LABEL is NULL.  */
-
-static void
-add_fde_cfi (const char *label, dw_cfi_ref cfi)
-{
-  dw_cfi_ref *list_head;
-
-  if (emit_cfa_remember)
-    {
-      dw_cfi_ref cfi_remember;
-
-      /* Emit the state save.  */
-      emit_cfa_remember = false;
-      cfi_remember = new_cfi ();
-      cfi_remember->dw_cfi_opc = DW_CFA_remember_state;
-      add_fde_cfi (label, cfi_remember);
+      dw2_asm_output_addr (DWARF2_ADDR_SIZE, begin, "FDE initial location");
+      dw2_asm_output_delta (DWARF2_ADDR_SIZE, end, begin, "FDE address range");
     }
 
-  list_head = &cie_cfi_head;
-
-  if (dwarf2out_do_cfi_asm ())
+  if (augmentation[0])
     {
-      if (label)
+      if (any_lsda_needed)
        {
-         dw_fde_ref fde = current_fde ();
-
-         gcc_assert (fde != NULL);
-
-         /* We still have to add the cfi to the list so that lookup_cfa
-            works later on.  When -g2 and above we even need to force
-            emitting of CFI labels and add to list a DW_CFA_set_loc for
-            convert_cfa_to_fb_loc_list purposes.  If we're generating
-            DWARF3 output we use DW_OP_call_frame_cfa and so don't use
-            convert_cfa_to_fb_loc_list.  */
-         if (dwarf_version == 2
-             && debug_info_level > DINFO_LEVEL_TERSE
-             && (write_symbols == DWARF2_DEBUG
-                 || write_symbols == VMS_AND_DWARF2_DEBUG))
+         int size = size_of_encoded_value (lsda_encoding);
+
+         if (lsda_encoding == DW_EH_PE_aligned)
            {
-             switch (cfi->dw_cfi_opc)
-               {
-               case DW_CFA_def_cfa_offset:
-               case DW_CFA_def_cfa_offset_sf:
-               case DW_CFA_def_cfa_register:
-               case DW_CFA_def_cfa:
-               case DW_CFA_def_cfa_sf:
-               case DW_CFA_def_cfa_expression:
-               case DW_CFA_restore_state:
-                 if (*label == 0 || strcmp (label, "<do not output>") == 0)
-                   label = dwarf2out_cfi_label (true);
-
-                 if (fde->dw_fde_current_label == NULL
-                     || strcmp (label, fde->dw_fde_current_label) != 0)
-                   {
-                     dw_cfi_ref xcfi;
-
-                     label = xstrdup (label);
-
-                     /* Set the location counter to the new label.  */
-                     xcfi = new_cfi ();
-                     /* It doesn't metter whether DW_CFA_set_loc
-                        or DW_CFA_advance_loc4 is added here, those aren't
-                        emitted into assembly, only looked up by
-                        convert_cfa_to_fb_loc_list.  */
-                     xcfi->dw_cfi_opc = DW_CFA_set_loc;
-                     xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
-                     add_cfi (&fde->dw_fde_cfi, xcfi);
-                     fde->dw_fde_current_label = label;
-                   }
-                 break;
-               default:
-                 break;
-               }
+             int offset = (  4         /* Length */
+                           + 4         /* CIE offset */
+                           + 2 * size_of_encoded_value (fde_encoding)
+                           + 1         /* Augmentation size */ );
+             int pad = -offset & (PTR_SIZE - 1);
+
+             size += pad;
+             gcc_assert (size_of_uleb128 (size) == 1);
            }
 
-         output_cfi_directive (cfi);
+         dw2_asm_output_data_uleb128 (size, "Augmentation size");
 
-         list_head = &fde->dw_fde_cfi;
+         if (fde->uses_eh_lsda)
+           {
+             ASM_GENERATE_INTERNAL_LABEL (l1, second ? "LLSDAC" : "LLSDA",
+                                          fde->funcdef_number);
+             dw2_asm_output_encoded_addr_rtx (lsda_encoding,
+                                              gen_rtx_SYMBOL_REF (Pmode, l1),
+                                              false,
+                                              "Language Specific Data Area");
+           }
+         else
+           {
+             if (lsda_encoding == DW_EH_PE_aligned)
+               ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+             dw2_asm_output_data (size_of_encoded_value (lsda_encoding), 0,
+                                  "Language Specific Data Area (none)");
+           }
        }
-      /* ??? If this is a CFI for the CIE, we don't emit.  This
-        assumes that the standard CIE contents that the assembler
-        uses matches the standard CIE contents that the compiler
-        uses.  This is probably a bad assumption.  I'm not quite
-        sure how to address this for now.  */
+      else
+       dw2_asm_output_data_uleb128 (0, "Augmentation size");
     }
-  else if (label)
-    {
-      dw_fde_ref fde = current_fde ();
-
-      gcc_assert (fde != NULL);
-
-      if (*label == 0)
-       label = dwarf2out_cfi_label (false);
 
-      if (fde->dw_fde_current_label == NULL
-         || strcmp (label, fde->dw_fde_current_label) != 0)
-       {
-         dw_cfi_ref xcfi;
-
-         label = xstrdup (label);
-
-         /* Set the location counter to the new label.  */
-         xcfi = new_cfi ();
-         /* If we have a current label, advance from there, otherwise
-            set the location directly using set_loc.  */
-         xcfi->dw_cfi_opc = fde->dw_fde_current_label
-                            ? DW_CFA_advance_loc4
-                            : DW_CFA_set_loc;
-         xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
-         add_cfi (&fde->dw_fde_cfi, xcfi);
+  /* Loop through the Call Frame Instructions associated with this FDE.  */
+  fde->dw_fde_current_label = begin;
+  {
+    size_t from, until, i;
 
-         fde->dw_fde_current_label = label;
-       }
+    from = 0;
+    until = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
 
-      list_head = &fde->dw_fde_cfi;
-    }
+    if (fde->dw_fde_second_begin == NULL)
+      ;
+    else if (!second)
+      until = fde->dw_fde_switch_cfi_index;
+    else
+      from = fde->dw_fde_switch_cfi_index;
 
-  add_cfi (list_head, cfi);
-}
+    for (i = from; i < until; i++)
+      output_cfi (VEC_index (dw_cfi_ref, fde->dw_fde_cfi, i), fde, for_eh);
+  }
 
-/* Subroutine of lookup_cfa.  */
+  /* If we are to emit a ref/link from function bodies to their frame tables,
+     do it now.  This is typically performed to make sure that tables
+     associated with functions are dragged with them and not discarded in
+     garbage collecting links. We need to do this on a per function basis to
+     cope with -ffunction-sections.  */
 
-static void
-lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc, dw_cfa_location *remember)
-{
-  switch (cfi->dw_cfi_opc)
-    {
-    case DW_CFA_def_cfa_offset:
-    case DW_CFA_def_cfa_offset_sf:
-      loc->offset = cfi->dw_cfi_oprnd1.dw_cfi_offset;
-      break;
-    case DW_CFA_def_cfa_register:
-      loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
-      break;
-    case DW_CFA_def_cfa:
-    case DW_CFA_def_cfa_sf:
-      loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
-      loc->offset = cfi->dw_cfi_oprnd2.dw_cfi_offset;
-      break;
-    case DW_CFA_def_cfa_expression:
-      get_cfa_from_loc_descr (loc, cfi->dw_cfi_oprnd1.dw_cfi_loc);
-      break;
+#ifdef ASM_OUTPUT_DWARF_TABLE_REF
+  /* Switch to the function section, emit the ref to the tables, and
+     switch *back* into the table section.  */
+  switch_to_section (function_section (fde->decl));
+  ASM_OUTPUT_DWARF_TABLE_REF (section_start_label);
+  switch_to_frame_table_section (for_eh, true);
+#endif
 
-    case DW_CFA_remember_state:
-      gcc_assert (!remember->in_use);
-      *remember = *loc;
-      remember->in_use = 1;
-      break;
-    case DW_CFA_restore_state:
-      gcc_assert (remember->in_use);
-      *loc = *remember;
-      remember->in_use = 0;
-      break;
+  /* Pad the FDE out to an address sized boundary.  */
+  ASM_OUTPUT_ALIGN (asm_out_file,
+                   floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
+  ASM_OUTPUT_LABEL (asm_out_file, l2);
 
-    default:
-      break;
-    }
+  j += 2;
 }
 
-/* Find the previous value for the CFA.  */
+/* Return true if frame description entry FDE is needed for EH.  */
 
-static void
-lookup_cfa (dw_cfa_location *loc)
+static bool
+fde_needed_for_eh_p (dw_fde_ref fde)
 {
-  dw_cfi_ref cfi;
-  dw_fde_ref fde;
-  dw_cfa_location remember;
-
-  memset (loc, 0, sizeof (*loc));
-  loc->reg = INVALID_REGNUM;
-  remember = *loc;
-
-  for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
-    lookup_cfa_1 (cfi, loc, &remember);
-
-  fde = current_fde ();
-  if (fde)
-    for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
-      lookup_cfa_1 (cfi, loc, &remember);
-}
-
-/* The current rule for calculating the DWARF2 canonical frame address.  */
-static dw_cfa_location cfa;
-
-/* The register used for saving registers to the stack, and its offset
-   from the CFA.  */
-static dw_cfa_location cfa_store;
-
-/* The current save location around an epilogue.  */
-static dw_cfa_location cfa_remember;
-
-/* The running total of the size of arguments pushed onto the stack.  */
-static HOST_WIDE_INT args_size;
-
-/* The last args_size we actually output.  */
-static HOST_WIDE_INT old_args_size;
+  if (flag_asynchronous_unwind_tables)
+    return true;
 
-/* Entry point to update the canonical frame address (CFA).
-   LABEL is passed to add_fde_cfi.  The value of CFA is now to be
-   calculated from REG+OFFSET.  */
+  if (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde->decl))
+    return true;
 
-void
-dwarf2out_def_cfa (const char *label, unsigned int reg, HOST_WIDE_INT offset)
-{
-  dw_cfa_location loc;
-  loc.indirect = 0;
-  loc.base_offset = 0;
-  loc.reg = reg;
-  loc.offset = offset;
-  def_cfa_1 (label, &loc);
-}
+  if (fde->uses_eh_lsda)
+    return true;
 
-/* Determine if two dw_cfa_location structures define the same data.  */
+  /* If exceptions are enabled, we have collected nothrow info.  */
+  if (flag_exceptions && (fde->all_throwers_are_sibcalls || fde->nothrow))
+    return false;
 
-static bool
-cfa_equal_p (const dw_cfa_location *loc1, const dw_cfa_location *loc2)
-{
-  return (loc1->reg == loc2->reg
-         && loc1->offset == loc2->offset
-         && loc1->indirect == loc2->indirect
-         && (loc1->indirect == 0
-             || loc1->base_offset == loc2->base_offset));
+  return true;
 }
 
-/* This routine does the actual work.  The CFA is now calculated from
-   the dw_cfa_location structure.  */
+/* Output the call frame information used to record information
+   that relates to calculating the frame pointer, and records the
+   location of saved registers.  */
 
 static void
-def_cfa_1 (const char *label, dw_cfa_location *loc_p)
+output_call_frame_info (int for_eh)
 {
+  unsigned int i;
+  dw_fde_ref fde;
   dw_cfi_ref cfi;
-  dw_cfa_location old_cfa, loc;
-
-  cfa = *loc_p;
-  loc = *loc_p;
-
-  if (cfa_store.reg == loc.reg && loc.indirect == 0)
-    cfa_store.offset = loc.offset;
-
-  loc.reg = DWARF_FRAME_REGNUM (loc.reg);
-  lookup_cfa (&old_cfa);
+  char l1[20], l2[20], section_start_label[20];
+  bool any_lsda_needed = false;
+  char augmentation[6];
+  int augmentation_size;
+  int fde_encoding = DW_EH_PE_absptr;
+  int per_encoding = DW_EH_PE_absptr;
+  int lsda_encoding = DW_EH_PE_absptr;
+  int return_reg;
+  rtx personality = NULL;
+  int dw_cie_version;
 
-  /* If nothing changed, no need to issue any call frame instructions.  */
-  if (cfa_equal_p (&loc, &old_cfa))
+  /* Don't emit a CIE if there won't be any FDEs.  */
+  if (fde_vec == NULL)
     return;
 
-  cfi = new_cfi ();
+  /* Nothing to do if the assembler's doing it all.  */
+  if (dwarf2out_do_cfi_asm ())
+    return;
 
-  if (loc.reg == old_cfa.reg && !loc.indirect && !old_cfa.indirect)
+  /* If we don't have any functions we'll want to unwind out of, don't emit
+     any EH unwind information.  If we make FDEs linkonce, we may have to
+     emit an empty label for an FDE that wouldn't otherwise be emitted.  We
+     want to avoid having an FDE kept around when the function it refers to
+     is discarded.  Example where this matters: a primary function template
+     in C++ requires EH information, an explicit specialization doesn't.  */
+  if (for_eh)
     {
-      /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, indicating
-        the CFA register did not change but the offset did.  The data
-        factoring for DW_CFA_def_cfa_offset_sf happens in output_cfi, or
-        in the assembler via the .cfi_def_cfa_offset directive.  */
-      if (loc.offset < 0)
-       cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf;
-      else
-       cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
-      cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset;
-    }
+      bool any_eh_needed = false;
 
-#ifndef MIPS_DEBUGGING_INFO  /* SGI dbx thinks this means no offset.  */
-  else if (loc.offset == old_cfa.offset
-          && old_cfa.reg != INVALID_REGNUM
-          && !loc.indirect
-          && !old_cfa.indirect)
-    {
-      /* Construct a "DW_CFA_def_cfa_register <register>" instruction,
-        indicating the CFA register has changed to <register> but the
-        offset has not changed.  */
-      cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
-      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
-    }
-#endif
+      FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, i, fde)
+       {
+         if (fde->uses_eh_lsda)
+           any_eh_needed = any_lsda_needed = true;
+         else if (fde_needed_for_eh_p (fde))
+           any_eh_needed = true;
+         else if (TARGET_USES_WEAK_UNWIND_INFO)
+           targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, 1, 1);
+       }
 
-  else if (loc.indirect == 0)
-    {
-      /* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
-        indicating the CFA register has changed to <register> with
-        the specified offset.  The data factoring for DW_CFA_def_cfa_sf
-        happens in output_cfi, or in the assembler via the .cfi_def_cfa
-        directive.  */
-      if (loc.offset < 0)
-       cfi->dw_cfi_opc = DW_CFA_def_cfa_sf;
-      else
-       cfi->dw_cfi_opc = DW_CFA_def_cfa;
-      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
-      cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset;
+      if (!any_eh_needed)
+       return;
     }
-  else
-    {
-      /* Construct a DW_CFA_def_cfa_expression instruction to
-        calculate the CFA using a full location expression since no
-        register-offset pair is available.  */
-      struct dw_loc_descr_struct *loc_list;
 
-      cfi->dw_cfi_opc = DW_CFA_def_cfa_expression;
-      loc_list = build_cfa_loc (&loc, 0);
-      cfi->dw_cfi_oprnd1.dw_cfi_loc = loc_list;
-    }
+  /* We're going to be generating comments, so turn on app.  */
+  if (flag_debug_asm)
+    app_enable ();
 
-  add_fde_cfi (label, cfi);
-}
+  /* Switch to the proper frame section, first time.  */
+  switch_to_frame_table_section (for_eh, false);
 
-/* Add the CFI for saving a register.  REG is the CFA column number.
-   LABEL is passed to add_fde_cfi.
-   If SREG is -1, the register is saved at OFFSET from the CFA;
-   otherwise it is saved in SREG.  */
+  ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
+  ASM_OUTPUT_LABEL (asm_out_file, section_start_label);
 
-static void
-reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
-{
-  dw_cfi_ref cfi = new_cfi ();
-  dw_fde_ref fde = current_fde ();
+  /* Output the CIE.  */
+  ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
+  ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
+    dw2_asm_output_data (4, 0xffffffff,
+      "Initial length escape value indicating 64-bit DWARF extension");
+  dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
+                       "Length of Common Information Entry");
+  ASM_OUTPUT_LABEL (asm_out_file, l1);
 
-  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+  /* Now that the CIE pointer is PC-relative for EH,
+     use 0 to identify the CIE.  */
+  dw2_asm_output_data ((for_eh ? 4 : DWARF_OFFSET_SIZE),
+                      (for_eh ? 0 : DWARF_CIE_ID),
+                      "CIE Identifier Tag");
 
-  /* When stack is aligned, store REG using DW_CFA_expression with
-     FP.  */
-  if (fde
-      && fde->stack_realign
-      && sreg == INVALID_REGNUM)
-    {
-      cfi->dw_cfi_opc = DW_CFA_expression;
-      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
-      cfi->dw_cfi_oprnd2.dw_cfi_loc
-       = build_cfa_aligned_loc (offset, fde->stack_realignment);
-    }
-  else if (sreg == INVALID_REGNUM)
-    {
-      if (need_data_align_sf_opcode (offset))
-       cfi->dw_cfi_opc = DW_CFA_offset_extended_sf;
-      else if (reg & ~0x3f)
-       cfi->dw_cfi_opc = DW_CFA_offset_extended;
-      else
-       cfi->dw_cfi_opc = DW_CFA_offset;
-      cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
-    }
-  else if (sreg == reg)
-    cfi->dw_cfi_opc = DW_CFA_same_value;
-  else
-    {
-      cfi->dw_cfi_opc = DW_CFA_register;
-      cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
-    }
+  /* Use the CIE version 3 for DWARF3; allow DWARF2 to continue to
+     use CIE version 1, unless that would produce incorrect results
+     due to overflowing the return register column.  */
+  return_reg = DWARF2_FRAME_REG_OUT (DWARF_FRAME_RETURN_COLUMN, for_eh);
+  dw_cie_version = 1;
+  if (return_reg >= 256 || dwarf_version > 2)
+    dw_cie_version = 3;
+  dw2_asm_output_data (1, dw_cie_version, "CIE Version");
 
-  add_fde_cfi (label, cfi);
-}
+  augmentation[0] = 0;
+  augmentation_size = 0;
 
-/* Add the CFI for saving a register window.  LABEL is passed to reg_save.
-   This CFI tells the unwinder that it needs to restore the window registers
-   from the previous frame's window save area.
+  personality = current_unit_personality;
+  if (for_eh)
+    {
+      char *p;
 
-   ??? Perhaps we should note in the CIE where windows are saved (instead of
-   assuming 0(cfa)) and what registers are in the window.  */
+      /* Augmentation:
+        z      Indicates that a uleb128 is present to size the
+               augmentation section.
+        L      Indicates the encoding (and thus presence) of
+               an LSDA pointer in the FDE augmentation.
+        R      Indicates a non-default pointer encoding for
+               FDE code pointers.
+        P      Indicates the presence of an encoding + language
+               personality routine in the CIE augmentation.  */
 
-void
-dwarf2out_window_save (const char *label)
-{
-  dw_cfi_ref cfi = new_cfi ();
-
-  cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
-  add_fde_cfi (label, cfi);
-}
-
-/* Entry point for saving a register to the stack.  REG is the GCC register
-   number.  LABEL and OFFSET are passed to reg_save.  */
-
-void
-dwarf2out_reg_save (const char *label, unsigned int reg, HOST_WIDE_INT offset)
-{
-  reg_save (label, DWARF_FRAME_REGNUM (reg), INVALID_REGNUM, offset);
-}
-
-/* Entry point for saving the return address in the stack.
-   LABEL and OFFSET are passed to reg_save.  */
-
-void
-dwarf2out_return_save (const char *label, HOST_WIDE_INT offset)
-{
-  reg_save (label, DWARF_FRAME_RETURN_COLUMN, INVALID_REGNUM, offset);
-}
-
-/* Entry point for saving the return address in a register.
-   LABEL and SREG are passed to reg_save.  */
-
-void
-dwarf2out_return_reg (const char *label, unsigned int sreg)
-{
-  reg_save (label, DWARF_FRAME_RETURN_COLUMN, DWARF_FRAME_REGNUM (sreg), 0);
-}
-
-#ifdef DWARF2_UNWIND_INFO
-/* Record the initial position of the return address.  RTL is
-   INCOMING_RETURN_ADDR_RTX.  */
-
-static void
-initial_return_save (rtx rtl)
-{
-  unsigned int reg = INVALID_REGNUM;
-  HOST_WIDE_INT offset = 0;
-
-  switch (GET_CODE (rtl))
-    {
-    case REG:
-      /* RA is in a register.  */
-      reg = DWARF_FRAME_REGNUM (REGNO (rtl));
-      break;
+      fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0);
+      per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
+      lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
 
-    case MEM:
-      /* RA is on the stack.  */
-      rtl = XEXP (rtl, 0);
-      switch (GET_CODE (rtl))
+      p = augmentation + 1;
+      if (personality)
        {
-       case REG:
-         gcc_assert (REGNO (rtl) == STACK_POINTER_REGNUM);
-         offset = 0;
-         break;
-
-       case PLUS:
-         gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM);
-         offset = INTVAL (XEXP (rtl, 1));
-         break;
-
-       case MINUS:
-         gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM);
-         offset = -INTVAL (XEXP (rtl, 1));
-         break;
-
-       default:
-         gcc_unreachable ();
+         *p++ = 'P';
+         augmentation_size += 1 + size_of_encoded_value (per_encoding);
+         assemble_external_libcall (personality);
        }
-
-      break;
-
-    case PLUS:
-      /* The return address is at some offset from any value we can
-        actually load.  For instance, on the SPARC it is in %i7+8. Just
-        ignore the offset for now; it doesn't matter for unwinding frames.  */
-      gcc_assert (CONST_INT_P (XEXP (rtl, 1)));
-      initial_return_save (XEXP (rtl, 0));
-      return;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  if (reg != DWARF_FRAME_RETURN_COLUMN)
-    reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset);
-}
-#endif
-
-/* Given a SET, calculate the amount of stack adjustment it
-   contains.  */
-
-static HOST_WIDE_INT
-stack_adjust_offset (const_rtx pattern, HOST_WIDE_INT cur_args_size,
-                    HOST_WIDE_INT cur_offset)
-{
-  const_rtx src = SET_SRC (pattern);
-  const_rtx dest = SET_DEST (pattern);
-  HOST_WIDE_INT offset = 0;
-  enum rtx_code code;
-
-  if (dest == stack_pointer_rtx)
-    {
-      code = GET_CODE (src);
-
-      /* Assume (set (reg sp) (reg whatever)) sets args_size
-        level to 0.  */
-      if (code == REG && src != stack_pointer_rtx)
+      if (any_lsda_needed)
        {
-         offset = -cur_args_size;
-#ifndef STACK_GROWS_DOWNWARD
-         offset = -offset;
-#endif
-         return offset - cur_offset;
+         *p++ = 'L';
+         augmentation_size += 1;
        }
-
-      if (! (code == PLUS || code == MINUS)
-         || XEXP (src, 0) != stack_pointer_rtx
-         || !CONST_INT_P (XEXP (src, 1)))
-       return 0;
-
-      /* (set (reg sp) (plus (reg sp) (const_int))) */
-      offset = INTVAL (XEXP (src, 1));
-      if (code == PLUS)
-       offset = -offset;
-      return offset;
-    }
-
-  if (MEM_P (src) && !MEM_P (dest))
-    dest = src;
-  if (MEM_P (dest))
-    {
-      /* (set (mem (pre_dec (reg sp))) (foo)) */
-      src = XEXP (dest, 0);
-      code = GET_CODE (src);
-
-      switch (code)
+      if (fde_encoding != DW_EH_PE_absptr)
        {
-       case PRE_MODIFY:
-       case POST_MODIFY:
-         if (XEXP (src, 0) == stack_pointer_rtx)
-           {
-             rtx val = XEXP (XEXP (src, 1), 1);
-             /* We handle only adjustments by constant amount.  */
-             gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS
-                         && CONST_INT_P (val));
-             offset = -INTVAL (val);
-             break;
-           }
-         return 0;
+         *p++ = 'R';
+         augmentation_size += 1;
+       }
+      if (p > augmentation + 1)
+       {
+         augmentation[0] = 'z';
+         *p = '\0';
+       }
 
-       case PRE_DEC:
-       case POST_DEC:
-         if (XEXP (src, 0) == stack_pointer_rtx)
-           {
-             offset = GET_MODE_SIZE (GET_MODE (dest));
-             break;
-           }
-         return 0;
+      /* Ug.  Some platforms can't do unaligned dynamic relocations at all.  */
+      if (personality && per_encoding == DW_EH_PE_aligned)
+       {
+         int offset = (  4             /* Length */
+                       + 4             /* CIE Id */
+                       + 1             /* CIE version */
+                       + strlen (augmentation) + 1     /* Augmentation */
+                       + size_of_uleb128 (1)           /* Code alignment */
+                       + size_of_sleb128 (DWARF_CIE_DATA_ALIGNMENT)
+                       + 1             /* RA column */
+                       + 1             /* Augmentation size */
+                       + 1             /* Personality encoding */ );
+         int pad = -offset & (PTR_SIZE - 1);
 
-       case PRE_INC:
-       case POST_INC:
-         if (XEXP (src, 0) == stack_pointer_rtx)
-           {
-             offset = -GET_MODE_SIZE (GET_MODE (dest));
-             break;
-           }
-         return 0;
+         augmentation_size += pad;
 
-       default:
-         return 0;
+         /* Augmentations should be small, so there's scarce need to
+            iterate for a solution.  Die if we exceed one uleb128 byte.  */
+         gcc_assert (size_of_uleb128 (augmentation_size) == 1);
        }
     }
-  else
-    return 0;
-
-  return offset;
-}
-
-/* Precomputed args_size for CODE_LABELs and BARRIERs preceeding them,
-   indexed by INSN_UID.  */
-
-static HOST_WIDE_INT *barrier_args_size;
 
-/* Helper function for compute_barrier_args_size.  Handle one insn.  */
+  dw2_asm_output_nstring (augmentation, -1, "CIE Augmentation");
+  if (dw_cie_version >= 4)
+    {
+      dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "CIE Address Size");
+      dw2_asm_output_data (1, 0, "CIE Segment Size");
+    }
+  dw2_asm_output_data_uleb128 (1, "CIE Code Alignment Factor");
+  dw2_asm_output_data_sleb128 (DWARF_CIE_DATA_ALIGNMENT,
+                              "CIE Data Alignment Factor");
 
-static HOST_WIDE_INT
-compute_barrier_args_size_1 (rtx insn, HOST_WIDE_INT cur_args_size,
-                            VEC (rtx, heap) **next)
-{
-  HOST_WIDE_INT offset = 0;
-  int i;
+  if (dw_cie_version == 1)
+    dw2_asm_output_data (1, return_reg, "CIE RA Column");
+  else
+    dw2_asm_output_data_uleb128 (return_reg, "CIE RA Column");
 
-  if (! RTX_FRAME_RELATED_P (insn))
+  if (augmentation[0])
     {
-      if (prologue_epilogue_contains (insn))
-       /* Nothing */;
-      else if (GET_CODE (PATTERN (insn)) == SET)
-       offset = stack_adjust_offset (PATTERN (insn), cur_args_size, 0);
-      else if (GET_CODE (PATTERN (insn)) == PARALLEL
-              || GET_CODE (PATTERN (insn)) == SEQUENCE)
+      dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size");
+      if (personality)
        {
-         /* There may be stack adjustments inside compound insns.  Search
-            for them.  */
-         for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
-           if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
-             offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i),
-                                            cur_args_size, offset);
+         dw2_asm_output_data (1, per_encoding, "Personality (%s)",
+                              eh_data_format_name (per_encoding));
+         dw2_asm_output_encoded_addr_rtx (per_encoding,
+                                          personality,
+                                          true, NULL);
        }
-    }
-  else
-    {
-      rtx expr = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
 
-      if (expr)
-       {
-         expr = XEXP (expr, 0);
-         if (GET_CODE (expr) == PARALLEL
-             || GET_CODE (expr) == SEQUENCE)
-           for (i = 1; i < XVECLEN (expr, 0); i++)
-             {
-               rtx elem = XVECEXP (expr, 0, i);
+      if (any_lsda_needed)
+       dw2_asm_output_data (1, lsda_encoding, "LSDA Encoding (%s)",
+                            eh_data_format_name (lsda_encoding));
 
-               if (GET_CODE (elem) == SET && !RTX_FRAME_RELATED_P (elem))
-                 offset += stack_adjust_offset (elem, cur_args_size, offset);
-             }
-       }
+      if (fde_encoding != DW_EH_PE_absptr)
+       dw2_asm_output_data (1, fde_encoding, "FDE Encoding (%s)",
+                            eh_data_format_name (fde_encoding));
     }
 
-#ifndef STACK_GROWS_DOWNWARD
-  offset = -offset;
-#endif
+  FOR_EACH_VEC_ELT (dw_cfi_ref, cie_cfi_vec, i, cfi)
+    output_cfi (cfi, NULL, for_eh);
 
-  cur_args_size += offset;
-  if (cur_args_size < 0)
-    cur_args_size = 0;
+  /* Pad the CIE out to an address sized boundary.  */
+  ASM_OUTPUT_ALIGN (asm_out_file,
+                   floor_log2 (for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE));
+  ASM_OUTPUT_LABEL (asm_out_file, l2);
 
-  if (JUMP_P (insn))
+  /* Loop through all of the FDE's.  */
+  FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, i, fde)
     {
-      rtx dest = JUMP_LABEL (insn);
+      unsigned int k;
 
-      if (dest)
-       {
-         if (barrier_args_size [INSN_UID (dest)] < 0)
-           {
-             barrier_args_size [INSN_UID (dest)] = cur_args_size;
-             VEC_safe_push (rtx, heap, *next, dest);
-           }
-       }
+      /* Don't emit EH unwind info for leaf functions that don't need it.  */
+      if (for_eh && !fde_needed_for_eh_p (fde))
+       continue;
+
+      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);
     }
 
-  return cur_args_size;
+  if (for_eh && targetm.terminate_dw2_eh_frame_info)
+    dw2_asm_output_data (4, 0, "End of Table");
+#ifdef MIPS_DEBUGGING_INFO
+  /* Work around Irix 6 assembler bug whereby labels at the end of a section
+     get a value of 0.  Putting .align 0 after the label fixes it.  */
+  ASM_OUTPUT_ALIGN (asm_out_file, 0);
+#endif
+
+  /* Turn off app to make assembly quicker.  */
+  if (flag_debug_asm)
+    app_disable ();
 }
 
-/* Walk the whole function and compute args_size on BARRIERs.  */
+/* Emit .cfi_startproc and .cfi_personality/.cfi_lsda if needed.  */
 
 static void
-compute_barrier_args_size (void)
+dwarf2out_do_cfi_startproc (bool second)
 {
-  int max_uid = get_max_uid (), i;
-  rtx insn;
-  VEC (rtx, heap) *worklist, *next, *tmp;
+  int enc;
+  rtx ref;
+  rtx personality = get_personality_function (current_function_decl);
 
-  barrier_args_size = XNEWVEC (HOST_WIDE_INT, max_uid);
-  for (i = 0; i < max_uid; i++)
-    barrier_args_size[i] = -1;
+  fprintf (asm_out_file, "\t.cfi_startproc\n");
 
-  worklist = VEC_alloc (rtx, heap, 20);
-  next = VEC_alloc (rtx, heap, 20);
-  insn = get_insns ();
-  barrier_args_size[INSN_UID (insn)] = 0;
-  VEC_quick_push (rtx, worklist, insn);
-  for (;;)
+  if (personality)
     {
-      while (!VEC_empty (rtx, worklist))
-       {
-         rtx prev, body, first_insn;
-         HOST_WIDE_INT cur_args_size;
+      enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
+      ref = personality;
 
-         first_insn = insn = VEC_pop (rtx, worklist);
-         cur_args_size = barrier_args_size[INSN_UID (insn)];
-         prev = prev_nonnote_insn (insn);
-         if (prev && BARRIER_P (prev))
-           barrier_args_size[INSN_UID (prev)] = cur_args_size;
+      /* ??? The GAS support isn't entirely consistent.  We have to
+        handle indirect support ourselves, but PC-relative is done
+        in the assembler.  Further, the assembler can't handle any
+        of the weirder relocation types.  */
+      if (enc & DW_EH_PE_indirect)
+       ref = dw2_force_const_mem (ref, true);
 
-         for (; insn; insn = NEXT_INSN (insn))
-           {
-             if (INSN_DELETED_P (insn) || NOTE_P (insn))
-               continue;
-             if (BARRIER_P (insn))
-               break;
+      fprintf (asm_out_file, "\t.cfi_personality %#x,", enc);
+      output_addr_const (asm_out_file, ref);
+      fputc ('\n', asm_out_file);
+    }
 
-             if (LABEL_P (insn))
-               {
-                 if (insn == first_insn)
-                   continue;
-                 else if (barrier_args_size[INSN_UID (insn)] < 0)
-                   {
-                     barrier_args_size[INSN_UID (insn)] = cur_args_size;
-                     continue;
-                   }
-                 else
-                   {
-                     /* The insns starting with this label have been
-                        already scanned or are in the worklist.  */
-                     break;
-                   }
-               }
+  if (crtl->uses_eh_lsda)
+    {
+      char lab[20];
 
-             body = PATTERN (insn);
-             if (GET_CODE (body) == SEQUENCE)
-               {
-                 HOST_WIDE_INT dest_args_size = cur_args_size;
-                 for (i = 1; i < XVECLEN (body, 0); i++)
-                   if (INSN_ANNULLED_BRANCH_P (XVECEXP (body, 0, 0))
-                       && INSN_FROM_TARGET_P (XVECEXP (body, 0, i)))
-                     dest_args_size
-                       = compute_barrier_args_size_1 (XVECEXP (body, 0, i),
-                                                      dest_args_size, &next);
-                   else
-                     cur_args_size
-                       = compute_barrier_args_size_1 (XVECEXP (body, 0, i),
-                                                      cur_args_size, &next);
-
-                 if (INSN_ANNULLED_BRANCH_P (XVECEXP (body, 0, 0)))
-                   compute_barrier_args_size_1 (XVECEXP (body, 0, 0),
-                                                dest_args_size, &next);
-                 else
-                   cur_args_size
-                     = compute_barrier_args_size_1 (XVECEXP (body, 0, 0),
-                                                    cur_args_size, &next);
-               }
-             else
-               cur_args_size
-                 = compute_barrier_args_size_1 (insn, cur_args_size, &next);
-           }
-       }
+      enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
+      ASM_GENERATE_INTERNAL_LABEL (lab, second ? "LLSDAC" : "LLSDA",
+                                  current_function_funcdef_no);
+      ref = gen_rtx_SYMBOL_REF (Pmode, lab);
+      SYMBOL_REF_FLAGS (ref) = SYMBOL_FLAG_LOCAL;
 
-      if (VEC_empty (rtx, next))
-       break;
+      if (enc & DW_EH_PE_indirect)
+       ref = dw2_force_const_mem (ref, true);
 
-      /* Swap WORKLIST with NEXT and truncate NEXT for next iteration.  */
-      tmp = next;
-      next = worklist;
-      worklist = tmp;
-      VEC_truncate (rtx, next, 0);
+      fprintf (asm_out_file, "\t.cfi_lsda %#x,", enc);
+      output_addr_const (asm_out_file, ref);
+      fputc ('\n', asm_out_file);
     }
-
-  VEC_free (rtx, heap, worklist);
-  VEC_free (rtx, heap, next);
 }
 
-/* Add a CFI to update the running total of the size of arguments
-   pushed onto the stack.  */
+/* Allocate CURRENT_FDE.  Immediately initialize all we can, noting that
+   this allocation may be done before pass_final.  */
 
-static void
-dwarf2out_args_size (const char *label, HOST_WIDE_INT size)
+dw_fde_ref
+dwarf2out_alloc_current_fde (void)
 {
-  dw_cfi_ref cfi;
+  dw_fde_ref fde;
 
-  if (size == old_args_size)
-    return;
+  fde = ggc_alloc_cleared_dw_fde_node ();
+  fde->decl = current_function_decl;
+  fde->funcdef_number = current_function_funcdef_no;
+  fde->fde_index = VEC_length (dw_fde_ref, fde_vec);
+  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;
 
-  old_args_size = size;
+  /* Record the FDE associated with this function.  */
+  cfun->fde = fde;
+  VEC_safe_push (dw_fde_ref, gc, fde_vec, fde);
 
-  cfi = new_cfi ();
-  cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
-  cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
-  add_fde_cfi (label, cfi);
+  return fde;
 }
 
-/* Record a stack adjustment of OFFSET bytes.  */
+/* Output a marker (i.e. a label) for the beginning of a function, before
+   the prologue.  */
 
-static void
-dwarf2out_stack_adjust (HOST_WIDE_INT offset, const char *label)
+void
+dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
+                         const char *file ATTRIBUTE_UNUSED)
 {
-  if (cfa.reg == STACK_POINTER_REGNUM)
-    cfa.offset += offset;
-
-  if (cfa_store.reg == STACK_POINTER_REGNUM)
-    cfa_store.offset += offset;
-
-  if (ACCUMULATE_OUTGOING_ARGS)
-    return;
-
-#ifndef STACK_GROWS_DOWNWARD
-  offset = -offset;
-#endif
-
-  args_size += offset;
-  if (args_size < 0)
-    args_size = 0;
-
-  def_cfa_1 (label, &cfa);
-  if (flag_asynchronous_unwind_tables)
-    dwarf2out_args_size (label, args_size);
-}
-
-/* Check INSN to see if it looks like a push or a stack adjustment, and
-   make a note of it if it does.  EH uses this information to find out
-   how much extra space it needs to pop off the stack.  */
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+  char * dup_label;
+  dw_fde_ref fde;
+  section *fnsec;
+  bool do_frame;
 
-static void
-dwarf2out_notice_stack_adjust (rtx insn, bool after_p)
-{
-  HOST_WIDE_INT offset;
-  const char *label;
-  int i;
+  current_function_func_begin_label = NULL;
 
-  /* Don't handle epilogues at all.  Certainly it would be wrong to do so
-     with this function.  Proper support would require all frame-related
-     insns to be marked, and to be able to handle saving state around
-     epilogues textually in the middle of the function.  */
-  if (prologue_epilogue_contains (insn))
-    return;
+  do_frame = dwarf2out_do_frame ();
 
-  /* If INSN is an instruction from target of an annulled branch, the
-     effects are for the target only and so current argument size
-     shouldn't change at all.  */
-  if (final_sequence
-      && INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))
-      && INSN_FROM_TARGET_P (insn))
+  /* ??? 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_common.except_unwind_info (&global_options) != UI_TARGET))
     return;
 
-  /* If only calls can throw, and we have a frame pointer,
-     save up adjustments until we see the CALL_INSN.  */
-  if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM)
-    {
-      if (CALL_P (insn) && !after_p)
-       {
-         /* Extract the size of the args from the CALL rtx itself.  */
-         insn = PATTERN (insn);
-         if (GET_CODE (insn) == PARALLEL)
-           insn = XVECEXP (insn, 0, 0);
-         if (GET_CODE (insn) == SET)
-           insn = SET_SRC (insn);
-         gcc_assert (GET_CODE (insn) == CALL);
-         dwarf2out_args_size ("", INTVAL (XEXP (insn, 1)));
-       }
-      return;
-    }
-
-  if (CALL_P (insn) && !after_p)
-    {
-      if (!flag_asynchronous_unwind_tables)
-       dwarf2out_args_size ("", args_size);
-      return;
-    }
-  else if (BARRIER_P (insn))
-    {
-      /* Don't call compute_barrier_args_size () if the only
-        BARRIER is at the end of function.  */
-      if (barrier_args_size == NULL && next_nonnote_insn (insn))
-       compute_barrier_args_size ();
-      if (barrier_args_size == NULL)
-       offset = 0;
-      else
-       {
-         offset = barrier_args_size[INSN_UID (insn)];
-         if (offset < 0)
-           offset = 0;
-       }
+  fnsec = function_section (current_function_decl);
+  switch_to_section (fnsec);
+  ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
+                              current_function_funcdef_no);
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
+                         current_function_funcdef_no);
+  dup_label = xstrdup (label);
+  current_function_func_begin_label = dup_label;
 
-      offset -= args_size;
-#ifndef STACK_GROWS_DOWNWARD
-      offset = -offset;
-#endif
-    }
-  else if (GET_CODE (PATTERN (insn)) == SET)
-    offset = stack_adjust_offset (PATTERN (insn), args_size, 0);
-  else if (GET_CODE (PATTERN (insn)) == PARALLEL
-          || GET_CODE (PATTERN (insn)) == SEQUENCE)
-    {
-      /* There may be stack adjustments inside compound insns.  Search
-        for them.  */
-      for (offset = 0, i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
-       if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
-         offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i),
-                                        args_size, offset);
-    }
-  else
+  /* We can elide the fde allocation if we're not emitting debug info.  */
+  if (!do_frame)
     return;
 
-  if (offset == 0)
-    return;
+  /* Cater to the various TARGET_ASM_OUTPUT_MI_THUNK implementations that
+     emit insns as rtx but bypass the bulk of rest_of_compilation, which
+     would include pass_dwarf2_frame.  If we've not created the FDE yet,
+     do so now.  */
+  fde = cfun->fde;
+  if (fde == NULL)
+    fde = dwarf2out_alloc_current_fde ();
 
-  label = dwarf2out_cfi_label (false);
-  dwarf2out_stack_adjust (offset, label);
-}
+  /* Initialize the bits of CURRENT_FDE that were not available earlier.  */
+  fde->dw_fde_begin = dup_label;
+  fde->dw_fde_current_label = dup_label;
+  fde->in_std_section = (fnsec == text_section
+                        || (cold_text_section && fnsec == cold_text_section));
 
+  /* We only want to output line number information for the genuine dwarf2
+     prologue case, not the eh frame case.  */
+#ifdef DWARF2_DEBUGGING_INFO
+  if (file)
+    dwarf2out_source_line (line, file, 0, true);
 #endif
 
-/* We delay emitting a register save until either (a) we reach the end
-   of the prologue or (b) the register is clobbered.  This clusters
-   register saves so that there are fewer pc advances.  */
-
-struct GTY(()) queued_reg_save {
-  struct queued_reg_save *next;
-  rtx reg;
-  HOST_WIDE_INT cfa_offset;
-  rtx saved_reg;
-};
-
-static GTY(()) struct queued_reg_save *queued_reg_saves;
-
-/* The caller's ORIG_REG is saved in SAVED_IN_REG.  */
-struct GTY(()) reg_saved_in_data {
-  rtx orig_reg;
-  rtx saved_in_reg;
-};
-
-/* A list of registers saved in other registers.
-   The list intentionally has a small maximum capacity of 4; if your
-   port needs more than that, you might consider implementing a
-   more efficient data structure.  */
-static GTY(()) struct reg_saved_in_data regs_saved_in_regs[4];
-static GTY(()) size_t num_regs_saved_in_regs;
-
-#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
-static const char *last_reg_save_label;
-
-/* Add an entry to QUEUED_REG_SAVES saying that REG is now saved at
-   SREG, or if SREG is NULL then it is saved at OFFSET to the CFA.  */
-
-static void
-queue_reg_save (const char *label, rtx reg, rtx sreg, HOST_WIDE_INT offset)
-{
-  struct queued_reg_save *q;
-
-  /* Duplicates waste space, but it's also necessary to remove them
-     for correctness, since the queue gets output in reverse
-     order.  */
-  for (q = queued_reg_saves; q != NULL; q = q->next)
-    if (REGNO (q->reg) == REGNO (reg))
-      break;
-
-  if (q == NULL)
-    {
-      q = GGC_NEW (struct queued_reg_save);
-      q->next = queued_reg_saves;
-      queued_reg_saves = q;
-    }
-
-  q->reg = reg;
-  q->cfa_offset = offset;
-  q->saved_reg = sreg;
-
-  last_reg_save_label = label;
-}
-
-/* Output all the entries in QUEUED_REG_SAVES.  */
-
-static void
-flush_queued_reg_saves (void)
-{
-  struct queued_reg_save *q;
-
-  for (q = queued_reg_saves; q; q = q->next)
+  if (dwarf2out_do_cfi_asm ())
+    dwarf2out_do_cfi_startproc (false);
+  else
     {
-      size_t i;
-      unsigned int reg, sreg;
-
-      for (i = 0; i < num_regs_saved_in_regs; i++)
-       if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (q->reg))
-         break;
-      if (q->saved_reg && i == num_regs_saved_in_regs)
-       {
-         gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
-         num_regs_saved_in_regs++;
-       }
-      if (i != num_regs_saved_in_regs)
-       {
-         regs_saved_in_regs[i].orig_reg = q->reg;
-         regs_saved_in_regs[i].saved_in_reg = q->saved_reg;
-       }
+      rtx personality = get_personality_function (current_function_decl);
+      if (!current_unit_personality)
+        current_unit_personality = personality;
 
-      reg = DWARF_FRAME_REGNUM (REGNO (q->reg));
-      if (q->saved_reg)
-       sreg = DWARF_FRAME_REGNUM (REGNO (q->saved_reg));
-      else
-       sreg = INVALID_REGNUM;
-      reg_save (last_reg_save_label, reg, sreg, q->cfa_offset);
+      /* We cannot keep a current personality per function as without CFI
+        asm, at the point where we emit the CFI data, there is no current
+        function anymore.  */
+      if (personality && current_unit_personality != personality)
+       sorry ("multiple EH personalities are supported only with assemblers "
+              "supporting .cfi_personality directive");
     }
-
-  queued_reg_saves = NULL;
-  last_reg_save_label = NULL;
 }
 
-/* Does INSN clobber any register which QUEUED_REG_SAVES lists a saved
-   location for?  Or, does it clobber a register which we've previously
-   said that some other register is saved in, and for which we now
-   have a new location for?  */
+/* Output a marker (i.e. a label) for the end of the generated code
+   for a function prologue.  This gets called *after* the prologue code has
+   been generated.  */
 
-static bool
-clobbers_queued_reg_save (const_rtx insn)
+void
+dwarf2out_vms_end_prologue (unsigned int line ATTRIBUTE_UNUSED,
+                       const char *file ATTRIBUTE_UNUSED)
 {
-  struct queued_reg_save *q;
-
-  for (q = queued_reg_saves; q; q = q->next)
-    {
-      size_t i;
-      if (modified_in_p (q->reg, insn))
-       return true;
-      for (i = 0; i < num_regs_saved_in_regs; i++)
-       if (REGNO (q->reg) == REGNO (regs_saved_in_regs[i].orig_reg)
-           && modified_in_p (regs_saved_in_regs[i].saved_in_reg, insn))
-         return true;
-    }
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
-  return false;
+  /* Output a label to mark the endpoint of the code generated for this
+     function.  */
+  ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL,
+                              current_function_funcdef_no);
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, PROLOGUE_END_LABEL,
+                         current_function_funcdef_no);
+  cfun->fde->dw_fde_vms_end_prologue = xstrdup (label);
 }
 
-/* Entry point for saving the first register into the second.  */
+/* Output a marker (i.e. a label) for the beginning of the generated code
+   for a function epilogue.  This gets called *before* the prologue code has
+   been generated.  */
 
 void
-dwarf2out_reg_save_reg (const char *label, rtx reg, rtx sreg)
+dwarf2out_vms_begin_epilogue (unsigned int line ATTRIBUTE_UNUSED,
+                         const char *file ATTRIBUTE_UNUSED)
 {
-  size_t i;
-  unsigned int regno, sregno;
+  dw_fde_ref fde = cfun->fde;
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
-  for (i = 0; i < num_regs_saved_in_regs; i++)
-    if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (reg))
-      break;
-  if (i == num_regs_saved_in_regs)
-    {
-      gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
-      num_regs_saved_in_regs++;
-    }
-  regs_saved_in_regs[i].orig_reg = reg;
-  regs_saved_in_regs[i].saved_in_reg = sreg;
+  if (fde->dw_fde_vms_begin_epilogue)
+    return;
 
-  regno = DWARF_FRAME_REGNUM (REGNO (reg));
-  sregno = DWARF_FRAME_REGNUM (REGNO (sreg));
-  reg_save (label, regno, sregno, 0);
+  /* Output a label to mark the endpoint of the code generated for this
+     function.  */
+  ASM_GENERATE_INTERNAL_LABEL (label, EPILOGUE_BEGIN_LABEL,
+                              current_function_funcdef_no);
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, EPILOGUE_BEGIN_LABEL,
+                         current_function_funcdef_no);
+  fde->dw_fde_vms_begin_epilogue = xstrdup (label);
 }
 
-/* What register, if any, is currently saved in REG?  */
+/* Output a marker (i.e. a label) for the absolute end of the generated code
+   for a function definition.  This gets called *after* the epilogue code has
+   been generated.  */
 
-static rtx
-reg_saved_in (rtx reg)
+void
+dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
+                       const char *file ATTRIBUTE_UNUSED)
 {
-  unsigned int regn = REGNO (reg);
-  size_t i;
-  struct queued_reg_save *q;
+  dw_fde_ref fde;
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
-  for (q = queued_reg_saves; q; q = q->next)
-    if (q->saved_reg && regn == REGNO (q->saved_reg))
-      return q->reg;
+  last_var_location_insn = NULL_RTX;
+  cached_next_real_insn = NULL_RTX;
 
-  for (i = 0; i < num_regs_saved_in_regs; i++)
-    if (regs_saved_in_regs[i].saved_in_reg
-       && regn == REGNO (regs_saved_in_regs[i].saved_in_reg))
-      return regs_saved_in_regs[i].orig_reg;
+  if (dwarf2out_do_cfi_asm ())
+    fprintf (asm_out_file, "\t.cfi_endproc\n");
 
-  return NULL_RTX;
+  /* Output a label to mark the endpoint of the code generated for this
+     function.  */
+  ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL,
+                              current_function_funcdef_no);
+  ASM_OUTPUT_LABEL (asm_out_file, label);
+  fde = cfun->fde;
+  gcc_assert (fde != NULL);
+  if (fde->dw_fde_second_begin == NULL)
+    fde->dw_fde_end = xstrdup (label);
 }
 
-
-/* A temporary register holding an integral value used in adjusting SP
-   or setting up the store_reg.  The "offset" field holds the integer
-   value, not an offset.  */
-static dw_cfa_location cfa_temp;
-
-/* A subroutine of dwarf2out_frame_debug, process a REG_DEF_CFA note.  */
-
-static void
-dwarf2out_frame_debug_def_cfa (rtx pat, const char *label)
+void
+dwarf2out_frame_finish (void)
 {
-  memset (&cfa, 0, sizeof (cfa));
-
-  switch (GET_CODE (pat))
-    {
-    case PLUS:
-      cfa.reg = REGNO (XEXP (pat, 0));
-      cfa.offset = INTVAL (XEXP (pat, 1));
-      break;
-
-    case REG:
-      cfa.reg = REGNO (pat);
-      break;
-
-    default:
-      /* Recurse and define an expression.  */
-      gcc_unreachable ();
-    }
+  /* Output call frame information.  */
+  if (targetm.debug_unwind_info () == UI_DWARF2)
+    output_call_frame_info (0);
 
-  def_cfa_1 (label, &cfa);
+  /* Output another copy for the unwinder.  */
+  if ((flag_unwind_tables || flag_exceptions)
+      && targetm_common.except_unwind_info (&global_options) == UI_DWARF2)
+    output_call_frame_info (1);
 }
 
-/* A subroutine of dwarf2out_frame_debug, process a REG_ADJUST_CFA note.  */
+/* Note that the current function section is being used for code.  */
 
 static void
-dwarf2out_frame_debug_adjust_cfa (rtx pat, const char *label)
+dwarf2out_note_section_used (void)
 {
-  rtx src, dest;
-
-  gcc_assert (GET_CODE (pat) == SET);
-  dest = XEXP (pat, 0);
-  src = XEXP (pat, 1);
-
-  switch (GET_CODE (src))
-    {
-    case PLUS:
-      gcc_assert (REGNO (XEXP (src, 0)) == cfa.reg);
-      cfa.offset -= INTVAL (XEXP (src, 1));
-      break;
-
-    case REG:
-       break;
-
-    default:
-       gcc_unreachable ();
-    }
-
-  cfa.reg = REGNO (dest);
-  gcc_assert (cfa.indirect == 0);
-
-  def_cfa_1 (label, &cfa);
+  section *sec = current_function_section ();
+  if (sec == text_section)
+    text_section_used = true;
+  else if (sec == cold_text_section)
+    cold_text_section_used = true;
 }
 
-/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_OFFSET note.  */
+static void var_location_switch_text_section (void);
+static void set_cur_line_info_table (section *);
 
-static void
-dwarf2out_frame_debug_cfa_offset (rtx set, const char *label)
+void
+dwarf2out_switch_text_section (void)
 {
-  HOST_WIDE_INT offset;
-  rtx src, addr, span;
+  section *sect;
+  dw_fde_ref fde = cfun->fde;
 
-  src = XEXP (set, 1);
-  addr = XEXP (set, 0);
-  gcc_assert (MEM_P (addr));
-  addr = XEXP (addr, 0);
+  gcc_assert (cfun && fde && fde->dw_fde_second_begin == NULL);
 
-  /* As documented, only consider extremely simple addresses.  */
-  switch (GET_CODE (addr))
+  if (!in_cold_section_p)
     {
-    case REG:
-      gcc_assert (REGNO (addr) == cfa.reg);
-      offset = -cfa.offset;
-      break;
-    case PLUS:
-      gcc_assert (REGNO (XEXP (addr, 0)) == cfa.reg);
-      offset = INTVAL (XEXP (addr, 1)) - cfa.offset;
-      break;
-    default:
-      gcc_unreachable ();
+      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;
     }
-
-  span = targetm.dwarf_register_span (src);
-
-  /* ??? We'd like to use queue_reg_save, but we need to come up with
-     a different flushing heuristic for epilogues.  */
-  if (!span)
-    reg_save (label, DWARF_FRAME_REGNUM (REGNO (src)), INVALID_REGNUM, offset);
   else
     {
-      /* We have a PARALLEL describing where the contents of SRC live.
-        Queue register saves for each piece of the PARALLEL.  */
-      int par_index;
-      int limit;
-      HOST_WIDE_INT span_offset = offset;
-
-      gcc_assert (GET_CODE (span) == PARALLEL);
-
-      limit = XVECLEN (span, 0);
-      for (par_index = 0; par_index < limit; par_index++)
-       {
-         rtx elem = XVECEXP (span, 0, par_index);
-
-         reg_save (label, DWARF_FRAME_REGNUM (REGNO (elem)),
-                   INVALID_REGNUM, span_offset);
-         span_offset += GET_MODE_SIZE (GET_MODE (elem));
-       }
+      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;
 
-/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_REGISTER note.  */
+  /* There is no need to mark used sections when not debugging.  */
+  if (cold_text_section != NULL)
+    dwarf2out_note_section_used ();
 
-static void
-dwarf2out_frame_debug_cfa_register (rtx set, const char *label)
-{
-  rtx src, dest;
-  unsigned sregno, dregno;
+  if (dwarf2out_do_cfi_asm ())
+    fprintf (asm_out_file, "\t.cfi_endproc\n");
+
+  /* Now do the real section switch.  */
+  sect = current_function_section ();
+  switch_to_section (sect);
 
-  src = XEXP (set, 1);
-  dest = XEXP (set, 0);
+  fde->second_in_std_section
+    = (sect == text_section
+       || (cold_text_section && sect == cold_text_section));
 
-  if (src == pc_rtx)
-    sregno = DWARF_FRAME_RETURN_COLUMN;
-  else
-    sregno = DWARF_FRAME_REGNUM (REGNO (src));
+  if (dwarf2out_do_cfi_asm ())
+    dwarf2out_do_cfi_startproc (true);
 
-  dregno = DWARF_FRAME_REGNUM (REGNO (dest));
+  var_location_switch_text_section ();
 
-  /* ??? We'd like to use queue_reg_save, but we need to come up with
-     a different flushing heuristic for epilogues.  */
-  reg_save (label, sregno, dregno, 0);
+  set_cur_line_info_table (sect);
 }
+\f
+/* And now, the subset of the debugging information support code necessary
+   for emitting location expressions.  */
 
-/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE note.  */
-
-static void
-dwarf2out_frame_debug_cfa_restore (rtx reg, const char *label)
-{
-  dw_cfi_ref cfi = new_cfi ();
-  unsigned int regno = DWARF_FRAME_REGNUM (REGNO (reg));
-
-  cfi->dw_cfi_opc = (regno & ~0x3f ? DW_CFA_restore_extended : DW_CFA_restore);
-  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = regno;
-
-  add_fde_cfi (label, cfi);
-}
-
-/* Record call frame debugging information for an expression EXPR,
-   which either sets SP or FP (adjusting how we calculate the frame
-   address) or saves a register to the stack or another register.
-   LABEL indicates the address of EXPR.
-
-   This function encodes a state machine mapping rtxes to actions on
-   cfa, cfa_store, and cfa_temp.reg.  We describe these rules so
-   users need not read the source code.
-
-  The High-Level Picture
-
-  Changes in the register we use to calculate the CFA: Currently we
-  assume that if you copy the CFA register into another register, we
-  should take the other one as the new CFA register; this seems to
-  work pretty well.  If it's wrong for some target, it's simple
-  enough not to set RTX_FRAME_RELATED_P on the insn in question.
-
-  Changes in the register we use for saving registers to the stack:
-  This is usually SP, but not always.  Again, we deduce that if you
-  copy SP into another register (and SP is not the CFA register),
-  then the new register is the one we will be using for register
-  saves.  This also seems to work.
-
-  Register saves: There's not much guesswork about this one; if
-  RTX_FRAME_RELATED_P is set on an insn which modifies memory, it's a
-  register save, and the register used to calculate the destination
-  had better be the one we think we're using for this purpose.
-  It's also assumed that a copy from a call-saved register to another
-  register is saving that register if RTX_FRAME_RELATED_P is set on
-  that instruction.  If the copy is from a call-saved register to
-  the *same* register, that means that the register is now the same
-  value as in the caller.
-
-  Except: If the register being saved is the CFA register, and the
-  offset is nonzero, we are saving the CFA, so we assume we have to
-  use DW_CFA_def_cfa_expression.  If the offset is 0, we assume that
-  the intent is to save the value of SP from the previous frame.
-
-  In addition, if a register has previously been saved to a different
-  register,
-
-  Invariants / Summaries of Rules
-
-  cfa         current rule for calculating the CFA.  It usually
-              consists of a register and an offset.
-  cfa_store    register used by prologue code to save things to the stack
-              cfa_store.offset is the offset from the value of
-              cfa_store.reg to the actual CFA
-  cfa_temp     register holding an integral value.  cfa_temp.offset
-              stores the value, which will be used to adjust the
-              stack pointer.  cfa_temp is also used like cfa_store,
-              to track stores to the stack via fp or a temp reg.
-
-  Rules  1- 4: Setting a register's value to cfa.reg or an expression
-              with cfa.reg as the first operand changes the cfa.reg and its
-              cfa.offset.  Rule 1 and 4 also set cfa_temp.reg and
-              cfa_temp.offset.
-
-  Rules  6- 9: Set a non-cfa.reg register value to a constant or an
-              expression yielding a constant.  This sets cfa_temp.reg
-              and cfa_temp.offset.
-
-  Rule 5:      Create a new register cfa_store used to save items to the
-              stack.
-
-  Rules 10-14: Save a register to the stack.  Define offset as the
-              difference of the original location and cfa_store's
-              location (or cfa_temp's location if cfa_temp is used).
-
-  Rules 16-20: If AND operation happens on sp in prologue, we assume
-              stack is realigned.  We will use a group of DW_OP_XXX
-              expressions to represent the location of the stored
-              register instead of CFA+offset.
-
-  The Rules
-
-  "{a,b}" indicates a choice of a xor b.
-  "<reg>:cfa.reg" indicates that <reg> must equal cfa.reg.
-
-  Rule 1:
-  (set <reg1> <reg2>:cfa.reg)
-  effects: cfa.reg = <reg1>
-          cfa.offset unchanged
-          cfa_temp.reg = <reg1>
-          cfa_temp.offset = cfa.offset
-
-  Rule 2:
-  (set sp ({minus,plus,losum} {sp,fp}:cfa.reg
-                             {<const_int>,<reg>:cfa_temp.reg}))
-  effects: cfa.reg = sp if fp used
-          cfa.offset += {+/- <const_int>, cfa_temp.offset} if cfa.reg==sp
-          cfa_store.offset += {+/- <const_int>, cfa_temp.offset}
-            if cfa_store.reg==sp
-
-  Rule 3:
-  (set fp ({minus,plus,losum} <reg>:cfa.reg <const_int>))
-  effects: cfa.reg = fp
-          cfa_offset += +/- <const_int>
-
-  Rule 4:
-  (set <reg1> ({plus,losum} <reg2>:cfa.reg <const_int>))
-  constraints: <reg1> != fp
-              <reg1> != sp
-  effects: cfa.reg = <reg1>
-          cfa_temp.reg = <reg1>
-          cfa_temp.offset = cfa.offset
-
-  Rule 5:
-  (set <reg1> (plus <reg2>:cfa_temp.reg sp:cfa.reg))
-  constraints: <reg1> != fp
-              <reg1> != sp
-  effects: cfa_store.reg = <reg1>
-          cfa_store.offset = cfa.offset - cfa_temp.offset
-
-  Rule 6:
-  (set <reg> <const_int>)
-  effects: cfa_temp.reg = <reg>
-          cfa_temp.offset = <const_int>
-
-  Rule 7:
-  (set <reg1>:cfa_temp.reg (ior <reg2>:cfa_temp.reg <const_int>))
-  effects: cfa_temp.reg = <reg1>
-          cfa_temp.offset |= <const_int>
-
-  Rule 8:
-  (set <reg> (high <exp>))
-  effects: none
-
-  Rule 9:
-  (set <reg> (lo_sum <exp> <const_int>))
-  effects: cfa_temp.reg = <reg>
-          cfa_temp.offset = <const_int>
-
-  Rule 10:
-  (set (mem (pre_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>)
-  effects: cfa_store.offset += -/+ mode_size(mem)
-          cfa.offset = cfa_store.offset if cfa.reg == sp
-          cfa.reg = sp
-          cfa.base_offset = -cfa_store.offset
-
-  Rule 12:
-  (set (mem ({minus,plus,losum} <reg1>:{cfa_store,cfa_temp} <const_int>))
-
-       <reg2>)
-  effects: cfa.reg = <reg1>
-          cfa.base_offset = -/+ <const_int> - {cfa_store,cfa_temp}.offset
-
-  Rule 13:
-  (set (mem <reg1>:{cfa_store,cfa_temp}) <reg2>)
-  effects: cfa.reg = <reg1>
-          cfa.base_offset = -{cfa_store,cfa_temp}.offset
-
-  Rule 14:
-  (set (mem (postinc <reg1>:cfa_temp <const_int>)) <reg2>)
-  effects: cfa.reg = <reg1>
-          cfa.base_offset = -cfa_temp.offset
-          cfa_temp.offset -= mode_size(mem)
-
-  Rule 15:
-  (set <reg> {unspec, unspec_volatile})
-  effects: target-dependent
-
-  Rule 16:
-  (set sp (and: sp <const_int>))
-  constraints: cfa_store.reg == sp
-  effects: current_fde.stack_realign = 1
-           cfa_store.offset = 0
-          fde->drap_reg = cfa.reg if cfa.reg != sp and cfa.reg != fp
-
-  Rule 17:
-  (set (mem ({pre_inc, pre_dec} sp)) (mem (plus (cfa.reg) (const_int))))
-  effects: cfa_store.offset += -/+ mode_size(mem)
-
-  Rule 18:
-  (set (mem ({pre_inc, pre_dec} sp)) fp)
-  constraints: fde->stack_realign == 1
-  effects: cfa_store.offset = 0
-          cfa.reg != HARD_FRAME_POINTER_REGNUM
-
-  Rule 19:
-  (set (mem ({pre_inc, pre_dec} sp)) cfa.reg)
-  constraints: fde->stack_realign == 1
-               && cfa.offset == 0
-               && cfa.indirect == 0
-               && cfa.reg != HARD_FRAME_POINTER_REGNUM
-  effects: Use DW_CFA_def_cfa_expression to define cfa
-          cfa.reg == fde->drap_reg  */
+/* Data about a single source file.  */
+struct GTY(()) dwarf_file_data {
+  const char * filename;
+  int emitted_number;
+};
 
-static void
-dwarf2out_frame_debug_expr (rtx expr, const char *label)
+typedef struct GTY(()) deferred_locations_struct
 {
-  rtx src, dest, span;
-  HOST_WIDE_INT offset;
-  dw_fde_ref fde;
-
-  /* If RTX_FRAME_RELATED_P is set on a PARALLEL, process each member of
-     the PARALLEL independently. The first element is always processed if
-     it is a SET. This is for backward compatibility.   Other elements
-     are processed only if they are SETs and the RTX_FRAME_RELATED_P
-     flag is set in them.  */
-  if (GET_CODE (expr) == PARALLEL || GET_CODE (expr) == SEQUENCE)
-    {
-      int par_index;
-      int limit = XVECLEN (expr, 0);
-      rtx elem;
-
-      /* PARALLELs have strict read-modify-write semantics, so we
-        ought to evaluate every rvalue before changing any lvalue.
-        It's cumbersome to do that in general, but there's an
-        easy approximation that is enough for all current users:
-        handle register saves before register assignments.  */
-      if (GET_CODE (expr) == PARALLEL)
-       for (par_index = 0; par_index < limit; par_index++)
-         {
-           elem = XVECEXP (expr, 0, par_index);
-           if (GET_CODE (elem) == SET
-               && MEM_P (SET_DEST (elem))
-               && (RTX_FRAME_RELATED_P (elem) || par_index == 0))
-             dwarf2out_frame_debug_expr (elem, label);
-         }
-
-      for (par_index = 0; par_index < limit; par_index++)
-       {
-         elem = XVECEXP (expr, 0, par_index);
-         if (GET_CODE (elem) == SET
-             && (!MEM_P (SET_DEST (elem)) || GET_CODE (expr) == SEQUENCE)
-             && (RTX_FRAME_RELATED_P (elem) || par_index == 0))
-           dwarf2out_frame_debug_expr (elem, label);
-         else if (GET_CODE (elem) == SET
-                  && par_index != 0
-                  && !RTX_FRAME_RELATED_P (elem))
-           {
-             /* Stack adjustment combining might combine some post-prologue
-                stack adjustment into a prologue stack adjustment.  */
-             HOST_WIDE_INT offset = stack_adjust_offset (elem, args_size, 0);
-
-             if (offset != 0)
-               dwarf2out_stack_adjust (offset, label);
-           }
-       }
-      return;
-    }
+  tree variable;
+  dw_die_ref die;
+} deferred_locations;
 
-  gcc_assert (GET_CODE (expr) == SET);
+DEF_VEC_O(deferred_locations);
+DEF_VEC_ALLOC_O(deferred_locations,gc);
 
-  src = SET_SRC (expr);
-  dest = SET_DEST (expr);
+static GTY(()) VEC(deferred_locations, gc) *deferred_locations_list;
 
-  if (REG_P (src))
-    {
-      rtx rsi = reg_saved_in (src);
-      if (rsi)
-       src = rsi;
-    }
-
-  fde = current_fde ();
-
-  switch (GET_CODE (dest))
-    {
-    case REG:
-      switch (GET_CODE (src))
-       {
-         /* Setting FP from SP.  */
-       case REG:
-         if (cfa.reg == (unsigned) REGNO (src))
-           {
-             /* Rule 1 */
-             /* Update the CFA rule wrt SP or FP.  Make sure src is
-                relative to the current CFA register.
-
-                We used to require that dest be either SP or FP, but the
-                ARM copies SP to a temporary register, and from there to
-                FP.  So we just rely on the backends to only set
-                RTX_FRAME_RELATED_P on appropriate insns.  */
-             cfa.reg = REGNO (dest);
-             cfa_temp.reg = cfa.reg;
-             cfa_temp.offset = cfa.offset;
-           }
-         else
-           {
-             /* Saving a register in a register.  */
-             gcc_assert (!fixed_regs [REGNO (dest)]
-                         /* For the SPARC and its register window.  */
-                         || (DWARF_FRAME_REGNUM (REGNO (src))
-                             == DWARF_FRAME_RETURN_COLUMN));
-
-              /* After stack is aligned, we can only save SP in FP
-                if drap register is used.  In this case, we have
-                to restore stack pointer with the CFA value and we
-                don't generate this DWARF information.  */
-             if (fde
-                 && fde->stack_realign
-                 && REGNO (src) == STACK_POINTER_REGNUM)
-               gcc_assert (REGNO (dest) == HARD_FRAME_POINTER_REGNUM
-                           && fde->drap_reg != INVALID_REGNUM
-                           && cfa.reg != REGNO (src));
-             else
-               queue_reg_save (label, src, dest, 0);
-           }
-         break;
-
-       case PLUS:
-       case MINUS:
-       case LO_SUM:
-         if (dest == stack_pointer_rtx)
-           {
-             /* Rule 2 */
-             /* Adjusting SP.  */
-             switch (GET_CODE (XEXP (src, 1)))
-               {
-               case CONST_INT:
-                 offset = INTVAL (XEXP (src, 1));
-                 break;
-               case REG:
-                 gcc_assert ((unsigned) REGNO (XEXP (src, 1))
-                             == cfa_temp.reg);
-                 offset = cfa_temp.offset;
-                 break;
-               default:
-                 gcc_unreachable ();
-               }
-
-             if (XEXP (src, 0) == hard_frame_pointer_rtx)
-               {
-                 /* Restoring SP from FP in the epilogue.  */
-                 gcc_assert (cfa.reg == (unsigned) HARD_FRAME_POINTER_REGNUM);
-                 cfa.reg = STACK_POINTER_REGNUM;
-               }
-             else if (GET_CODE (src) == LO_SUM)
-               /* Assume we've set the source reg of the LO_SUM from sp.  */
-               ;
-             else
-               gcc_assert (XEXP (src, 0) == stack_pointer_rtx);
-
-             if (GET_CODE (src) != MINUS)
-               offset = -offset;
-             if (cfa.reg == STACK_POINTER_REGNUM)
-               cfa.offset += offset;
-             if (cfa_store.reg == STACK_POINTER_REGNUM)
-               cfa_store.offset += offset;
-           }
-         else if (dest == hard_frame_pointer_rtx)
-           {
-             /* Rule 3 */
-             /* Either setting the FP from an offset of the SP,
-                or adjusting the FP */
-             gcc_assert (frame_pointer_needed);
-
-             gcc_assert (REG_P (XEXP (src, 0))
-                         && (unsigned) REGNO (XEXP (src, 0)) == cfa.reg
-                         && CONST_INT_P (XEXP (src, 1)));
-             offset = INTVAL (XEXP (src, 1));
-             if (GET_CODE (src) != MINUS)
-               offset = -offset;
-             cfa.offset += offset;
-             cfa.reg = HARD_FRAME_POINTER_REGNUM;
-           }
-         else
-           {
-             gcc_assert (GET_CODE (src) != MINUS);
-
-             /* Rule 4 */
-             if (REG_P (XEXP (src, 0))
-                 && REGNO (XEXP (src, 0)) == cfa.reg
-                 && CONST_INT_P (XEXP (src, 1)))
-               {
-                 /* Setting a temporary CFA register that will be copied
-                    into the FP later on.  */
-                 offset = - INTVAL (XEXP (src, 1));
-                 cfa.offset += offset;
-                 cfa.reg = REGNO (dest);
-                 /* Or used to save regs to the stack.  */
-                 cfa_temp.reg = cfa.reg;
-                 cfa_temp.offset = cfa.offset;
-               }
-
-             /* Rule 5 */
-             else if (REG_P (XEXP (src, 0))
-                      && REGNO (XEXP (src, 0)) == cfa_temp.reg
-                      && XEXP (src, 1) == stack_pointer_rtx)
-               {
-                 /* Setting a scratch register that we will use instead
-                    of SP for saving registers to the stack.  */
-                 gcc_assert (cfa.reg == STACK_POINTER_REGNUM);
-                 cfa_store.reg = REGNO (dest);
-                 cfa_store.offset = cfa.offset - cfa_temp.offset;
-               }
-
-             /* Rule 9 */
-             else if (GET_CODE (src) == LO_SUM
-                      && CONST_INT_P (XEXP (src, 1)))
-               {
-                 cfa_temp.reg = REGNO (dest);
-                 cfa_temp.offset = INTVAL (XEXP (src, 1));
-               }
-             else
-               gcc_unreachable ();
-           }
-         break;
-
-         /* Rule 6 */
-       case CONST_INT:
-         cfa_temp.reg = REGNO (dest);
-         cfa_temp.offset = INTVAL (src);
-         break;
-
-         /* Rule 7 */
-       case IOR:
-         gcc_assert (REG_P (XEXP (src, 0))
-                     && (unsigned) REGNO (XEXP (src, 0)) == cfa_temp.reg
-                     && CONST_INT_P (XEXP (src, 1)));
-
-         if ((unsigned) REGNO (dest) != cfa_temp.reg)
-           cfa_temp.reg = REGNO (dest);
-         cfa_temp.offset |= INTVAL (XEXP (src, 1));
-         break;
-
-         /* Skip over HIGH, assuming it will be followed by a LO_SUM,
-            which will fill in all of the bits.  */
-         /* Rule 8 */
-       case HIGH:
-         break;
-
-         /* Rule 15 */
-       case UNSPEC:
-       case UNSPEC_VOLATILE:
-         gcc_assert (targetm.dwarf_handle_frame_unspec);
-         targetm.dwarf_handle_frame_unspec (label, expr, XINT (src, 1));
-         return;
-
-         /* Rule 16 */
-       case AND:
-          /* If this AND operation happens on stack pointer in prologue,
-            we assume the stack is realigned and we extract the
-            alignment.  */
-          if (fde && XEXP (src, 0) == stack_pointer_rtx)
-            {
-              gcc_assert (cfa_store.reg == REGNO (XEXP (src, 0)));
-              fde->stack_realign = 1;
-              fde->stack_realignment = INTVAL (XEXP (src, 1));
-              cfa_store.offset = 0;
-
-             if (cfa.reg != STACK_POINTER_REGNUM
-                 && cfa.reg != HARD_FRAME_POINTER_REGNUM)
-               fde->drap_reg = cfa.reg;
-            }
-          return;
-
-       default:
-         gcc_unreachable ();
-       }
-
-      def_cfa_1 (label, &cfa);
-      break;
-
-    case MEM:
-
-      /* Saving a register to the stack.  Make sure dest is relative to the
-        CFA register.  */
-      switch (GET_CODE (XEXP (dest, 0)))
-       {
-         /* Rule 10 */
-         /* With a push.  */
-       case PRE_MODIFY:
-         /* We can't handle variable size modifications.  */
-         gcc_assert (GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
-                     == CONST_INT);
-         offset = -INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1));
-
-         gcc_assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM
-                     && cfa_store.reg == STACK_POINTER_REGNUM);
-
-         cfa_store.offset += offset;
-         if (cfa.reg == STACK_POINTER_REGNUM)
-           cfa.offset = cfa_store.offset;
-
-         offset = -cfa_store.offset;
-         break;
-
-         /* Rule 11 */
-       case PRE_INC:
-       case PRE_DEC:
-         offset = GET_MODE_SIZE (GET_MODE (dest));
-         if (GET_CODE (XEXP (dest, 0)) == PRE_INC)
-           offset = -offset;
-
-         gcc_assert ((REGNO (XEXP (XEXP (dest, 0), 0))
-                      == STACK_POINTER_REGNUM)
-                     && cfa_store.reg == STACK_POINTER_REGNUM);
-
-         cfa_store.offset += offset;
-
-          /* Rule 18: If stack is aligned, we will use FP as a
-            reference to represent the address of the stored
-            regiser.  */
-          if (fde
-              && fde->stack_realign
-              && src == hard_frame_pointer_rtx)
-           {
-             gcc_assert (cfa.reg != HARD_FRAME_POINTER_REGNUM);
-             cfa_store.offset = 0;
-           }
-
-         if (cfa.reg == STACK_POINTER_REGNUM)
-           cfa.offset = cfa_store.offset;
-
-         offset = -cfa_store.offset;
-         break;
-
-         /* Rule 12 */
-         /* With an offset.  */
-       case PLUS:
-       case MINUS:
-       case LO_SUM:
-         {
-           int regno;
-
-           gcc_assert (CONST_INT_P (XEXP (XEXP (dest, 0), 1))
-                       && REG_P (XEXP (XEXP (dest, 0), 0)));
-           offset = INTVAL (XEXP (XEXP (dest, 0), 1));
-           if (GET_CODE (XEXP (dest, 0)) == MINUS)
-             offset = -offset;
-
-           regno = REGNO (XEXP (XEXP (dest, 0), 0));
-
-           if (cfa_store.reg == (unsigned) regno)
-             offset -= cfa_store.offset;
-           else
-             {
-               gcc_assert (cfa_temp.reg == (unsigned) regno);
-               offset -= cfa_temp.offset;
-             }
-         }
-         break;
-
-         /* Rule 13 */
-         /* Without an offset.  */
-       case REG:
-         {
-           int regno = REGNO (XEXP (dest, 0));
-
-           if (cfa_store.reg == (unsigned) regno)
-             offset = -cfa_store.offset;
-           else
-             {
-               gcc_assert (cfa_temp.reg == (unsigned) regno);
-               offset = -cfa_temp.offset;
-             }
-         }
-         break;
-
-         /* Rule 14 */
-       case POST_INC:
-         gcc_assert (cfa_temp.reg
-                     == (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)));
-         offset = -cfa_temp.offset;
-         cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest));
-         break;
-
-       default:
-         gcc_unreachable ();
-       }
-
-        /* Rule 17 */
-        /* If the source operand of this MEM operation is not a
-          register, basically the source is return address.  Here
-          we only care how much stack grew and we don't save it.  */
-      if (!REG_P (src))
-        break;
-
-      if (REGNO (src) != STACK_POINTER_REGNUM
-         && REGNO (src) != HARD_FRAME_POINTER_REGNUM
-         && (unsigned) REGNO (src) == cfa.reg)
-       {
-         /* We're storing the current CFA reg into the stack.  */
-
-         if (cfa.offset == 0)
-           {
-              /* Rule 19 */
-              /* If stack is aligned, putting CFA reg into stack means
-                we can no longer use reg + offset to represent CFA.
-                Here we use DW_CFA_def_cfa_expression instead.  The
-                result of this expression equals to the original CFA
-                value.  */
-              if (fde
-                  && fde->stack_realign
-                  && cfa.indirect == 0
-                  && cfa.reg != HARD_FRAME_POINTER_REGNUM)
-                {
-                 dw_cfa_location cfa_exp;
-
-                 gcc_assert (fde->drap_reg == cfa.reg);
-
-                 cfa_exp.indirect = 1;
-                 cfa_exp.reg = HARD_FRAME_POINTER_REGNUM;
-                 cfa_exp.base_offset = offset;
-                 cfa_exp.offset = 0;
-
-                 fde->drap_reg_saved = 1;
-
-                 def_cfa_1 (label, &cfa_exp);
-                 break;
-                }
-
-             /* If the source register is exactly the CFA, assume
-                we're saving SP like any other register; this happens
-                on the ARM.  */
-             def_cfa_1 (label, &cfa);
-             queue_reg_save (label, stack_pointer_rtx, NULL_RTX, offset);
-             break;
-           }
-         else
-           {
-             /* Otherwise, we'll need to look in the stack to
-                calculate the CFA.  */
-             rtx x = XEXP (dest, 0);
-
-             if (!REG_P (x))
-               x = XEXP (x, 0);
-             gcc_assert (REG_P (x));
-
-             cfa.reg = REGNO (x);
-             cfa.base_offset = offset;
-             cfa.indirect = 1;
-             def_cfa_1 (label, &cfa);
-             break;
-           }
-       }
-
-      def_cfa_1 (label, &cfa);
-      {
-       span = targetm.dwarf_register_span (src);
-
-       if (!span)
-         queue_reg_save (label, src, NULL_RTX, offset);
-       else
-         {
-           /* We have a PARALLEL describing where the contents of SRC
-              live.  Queue register saves for each piece of the
-              PARALLEL.  */
-           int par_index;
-           int limit;
-           HOST_WIDE_INT span_offset = offset;
-
-           gcc_assert (GET_CODE (span) == PARALLEL);
-
-           limit = XVECLEN (span, 0);
-           for (par_index = 0; par_index < limit; par_index++)
-             {
-               rtx elem = XVECEXP (span, 0, par_index);
-
-               queue_reg_save (label, elem, NULL_RTX, span_offset);
-               span_offset += GET_MODE_SIZE (GET_MODE (elem));
-             }
-         }
-      }
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-}
-
-/* Record call frame debugging information for INSN, which either
-   sets SP or FP (adjusting how we calculate the frame address) or saves a
-   register to the stack.  If INSN is NULL_RTX, initialize our state.
-
-   If AFTER_P is false, we're being called before the insn is emitted,
-   otherwise after.  Call instructions get invoked twice.  */
-
-void
-dwarf2out_frame_debug (rtx insn, bool after_p)
-{
-  const char *label;
-  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 ();
-
-  if (!RTX_FRAME_RELATED_P (insn))
-    {
-      /* ??? This should be done unconditionally since stack adjustments
-        matter if the stack pointer is not the CFA register anymore but
-        is still used to save registers.  */
-      if (!ACCUMULATE_OUTGOING_ARGS)
-       dwarf2out_notice_stack_adjust (insn, after_p);
-      return;
-    }
-
-  label = dwarf2out_cfi_label (false);
-
-  for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
-    switch (REG_NOTE_KIND (note))
-      {
-      case REG_FRAME_RELATED_EXPR:
-       insn = XEXP (note, 0);
-       goto found;
-
-      case REG_CFA_DEF_CFA:
-       dwarf2out_frame_debug_def_cfa (XEXP (note, 0), label);
-       handled_one = true;
-       break;
-
-      case REG_CFA_ADJUST_CFA:
-       n = XEXP (note, 0);
-       if (n == NULL)
-         {
-           n = PATTERN (insn);
-           if (GET_CODE (n) == PARALLEL)
-             n = XVECEXP (n, 0, 0);
-         }
-       dwarf2out_frame_debug_adjust_cfa (n, label);
-       handled_one = true;
-       break;
-
-      case REG_CFA_OFFSET:
-       n = XEXP (note, 0);
-       if (n == NULL)
-         n = single_set (insn);
-       dwarf2out_frame_debug_cfa_offset (n, label);
-       handled_one = true;
-       break;
-
-      case REG_CFA_REGISTER:
-       n = XEXP (note, 0);
-       if (n == NULL)
-         {
-           n = PATTERN (insn);
-           if (GET_CODE (n) == PARALLEL)
-             n = XVECEXP (n, 0, 0);
-         }
-       dwarf2out_frame_debug_cfa_register (n, label);
-       handled_one = true;
-       break;
-
-      case REG_CFA_RESTORE:
-       n = XEXP (note, 0);
-       if (n == NULL)
-         {
-           n = PATTERN (insn);
-           if (GET_CODE (n) == PARALLEL)
-             n = XVECEXP (n, 0, 0);
-           n = XEXP (n, 0);
-         }
-       dwarf2out_frame_debug_cfa_restore (n, label);
-       handled_one = true;
-       break;
-
-      case REG_CFA_SET_VDRAP:
-       n = XEXP (note, 0);
-       if (REG_P (n))
-         {
-           dw_fde_ref fde = current_fde ();
-           if (fde)
-             {
-               gcc_assert (fde->vdrap_reg == INVALID_REGNUM);
-               if (REG_P (n))
-                 fde->vdrap_reg = REGNO (n);
-             }
-         }
-       handled_one = true;
-       break;
-
-      default:
-       break;
-      }
-  if (handled_one)
-    return;
-
-  insn = PATTERN (insn);
- found:
-  dwarf2out_frame_debug_expr (insn, label);
-}
-
-/* Determine if we need to save and restore CFI information around this
-   epilogue.  If SIBCALL is true, then this is a sibcall epilogue.  If
-   we do need to save/restore, then emit the save now, and insert a
-   NOTE_INSN_CFA_RESTORE_STATE at the appropriate place in the stream.  */
-
-void
-dwarf2out_begin_epilogue (rtx insn)
-{
-  bool saw_frp = false;
-  rtx i;
-
-  /* Scan forward to the return insn, noticing if there are possible
-     frame related insns.  */
-  for (i = NEXT_INSN (insn); i ; i = NEXT_INSN (i))
-    {
-      if (!INSN_P (i))
-       continue;
-
-      /* Look for both regular and sibcalls to end the block.  */
-      if (returnjump_p (i))
-       break;
-      if (CALL_P (i) && SIBLING_CALL_P (i))
-       break;
-
-      if (GET_CODE (PATTERN (i)) == SEQUENCE)
-       {
-         int idx;
-         rtx seq = PATTERN (i);
-
-         if (returnjump_p (XVECEXP (seq, 0, 0)))
-           break;
-         if (CALL_P (XVECEXP (seq, 0, 0))
-             && SIBLING_CALL_P (XVECEXP (seq, 0, 0)))
-           break;
-
-         for (idx = 0; idx < XVECLEN (seq, 0); idx++)
-           if (RTX_FRAME_RELATED_P (XVECEXP (seq, 0, idx)))
-             saw_frp = true;
-       }
-
-      if (RTX_FRAME_RELATED_P (i))
-       saw_frp = true;
-    }
-
-  /* If the port doesn't emit epilogue unwind info, we don't need a
-     save/restore pair.  */
-  if (!saw_frp)
-    return;
-
-  /* Otherwise, search forward to see if the return insn was the last
-     basic block of the function.  If so, we don't need save/restore.  */
-  gcc_assert (i != NULL);
-  i = next_real_insn (i);
-  if (i == NULL)
-    return;
-
-  /* Insert the restore before that next real insn in the stream, and before
-     a potential NOTE_INSN_EPILOGUE_BEG -- we do need these notes to be
-     properly nested.  This should be after any label or alignment.  This
-     will be pushed into the CFI stream by the function below.  */
-  while (1)
-    {
-      rtx p = PREV_INSN (i);
-      if (!NOTE_P (p))
-       break;
-      if (NOTE_KIND (p) == NOTE_INSN_BASIC_BLOCK)
-       break;
-      i = p;
-    }
-  emit_note_before (NOTE_INSN_CFA_RESTORE_STATE, i);
-
-  emit_cfa_remember = true;
-
-  /* And emulate the state save.  */
-  gcc_assert (!cfa_remember.in_use);
-  cfa_remember = cfa;
-  cfa_remember.in_use = 1;
-}
-
-/* A "subroutine" of dwarf2out_begin_epilogue.  Emit the restore required.  */
-
-void
-dwarf2out_frame_debug_restore_state (void)
-{
-  dw_cfi_ref cfi = new_cfi ();
-  const char *label = dwarf2out_cfi_label (false);
-
-  cfi->dw_cfi_opc = DW_CFA_restore_state;
-  add_fde_cfi (label, cfi);
-
-  gcc_assert (cfa_remember.in_use);
-  cfa = cfa_remember;
-  cfa_remember.in_use = 0;
-}
-
-#endif
-
-/* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used.  */
-static enum dw_cfi_oprnd_type dw_cfi_oprnd1_desc
- (enum dwarf_call_frame_info cfi);
-
-static enum dw_cfi_oprnd_type
-dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
-{
-  switch (cfi)
-    {
-    case DW_CFA_nop:
-    case DW_CFA_GNU_window_save:
-    case DW_CFA_remember_state:
-    case DW_CFA_restore_state:
-      return dw_cfi_oprnd_unused;
-
-    case DW_CFA_set_loc:
-    case DW_CFA_advance_loc1:
-    case DW_CFA_advance_loc2:
-    case DW_CFA_advance_loc4:
-    case DW_CFA_MIPS_advance_loc8:
-      return dw_cfi_oprnd_addr;
-
-    case DW_CFA_offset:
-    case DW_CFA_offset_extended:
-    case DW_CFA_def_cfa:
-    case DW_CFA_offset_extended_sf:
-    case DW_CFA_def_cfa_sf:
-    case DW_CFA_restore:
-    case DW_CFA_restore_extended:
-    case DW_CFA_undefined:
-    case DW_CFA_same_value:
-    case DW_CFA_def_cfa_register:
-    case DW_CFA_register:
-    case DW_CFA_expression:
-      return dw_cfi_oprnd_reg_num;
-
-    case DW_CFA_def_cfa_offset:
-    case DW_CFA_GNU_args_size:
-    case DW_CFA_def_cfa_offset_sf:
-      return dw_cfi_oprnd_offset;
-
-    case DW_CFA_def_cfa_expression:
-      return dw_cfi_oprnd_loc;
-
-    default:
-      gcc_unreachable ();
-    }
-}
-
-/* Describe for the GTY machinery what parts of dw_cfi_oprnd2 are used.  */
-static enum dw_cfi_oprnd_type dw_cfi_oprnd2_desc
- (enum dwarf_call_frame_info cfi);
-
-static enum dw_cfi_oprnd_type
-dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
-{
-  switch (cfi)
-    {
-    case DW_CFA_def_cfa:
-    case DW_CFA_def_cfa_sf:
-    case DW_CFA_offset:
-    case DW_CFA_offset_extended_sf:
-    case DW_CFA_offset_extended:
-      return dw_cfi_oprnd_offset;
-
-    case DW_CFA_register:
-      return dw_cfi_oprnd_reg_num;
-
-    case DW_CFA_expression:
-      return dw_cfi_oprnd_loc;
-
-    default:
-      return dw_cfi_oprnd_unused;
-    }
-}
-
-#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
-
-/* Switch [BACK] to eh_frame_section.  If we don't have an eh_frame_section,
-   switch to the data section instead, and write out a synthetic start label
-   for collect2 the first time around.  */
-
-static void
-switch_to_eh_frame_section (bool back)
-{
-  tree label;
-
-#ifdef EH_FRAME_SECTION_NAME
-  if (eh_frame_section == 0)
-    {
-      int flags;
-
-      if (EH_TABLES_CAN_BE_READ_ONLY)
-       {
-         int fde_encoding;
-         int per_encoding;
-         int lsda_encoding;
-
-         fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1,
-                                                      /*global=*/0);
-         per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2,
-                                                      /*global=*/1);
-         lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0,
-                                                       /*global=*/0);
-         flags = ((! flag_pic
-                   || ((fde_encoding & 0x70) != DW_EH_PE_absptr
-                       && (fde_encoding & 0x70) != DW_EH_PE_aligned
-                       && (per_encoding & 0x70) != DW_EH_PE_absptr
-                       && (per_encoding & 0x70) != DW_EH_PE_aligned
-                       && (lsda_encoding & 0x70) != DW_EH_PE_absptr
-                       && (lsda_encoding & 0x70) != DW_EH_PE_aligned))
-                  ? 0 : SECTION_WRITE);
-       }
-      else
-       flags = SECTION_WRITE;
-      eh_frame_section = get_section (EH_FRAME_SECTION_NAME, flags, NULL);
-    }
-#endif
-
-  if (eh_frame_section)
-    switch_to_section (eh_frame_section);
-  else
-    {
-      /* We have no special eh_frame section.  Put the information in
-        the data section and emit special labels to guide collect2.  */
-      switch_to_section (data_section);
-
-      if (!back)
-       {
-         label = get_file_function_name ("F");
-         ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
-         targetm.asm_out.globalize_label (asm_out_file,
-                                          IDENTIFIER_POINTER (label));
-         ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
-       }
-    }
-}
-
-/* Switch [BACK] to the eh or debug frame table section, depending on
-   FOR_EH.  */
-
-static void
-switch_to_frame_table_section (int for_eh, bool back)
-{
-  if (for_eh)
-    switch_to_eh_frame_section (back);
-  else
-    {
-      if (!debug_frame_section)
-       debug_frame_section = get_section (DEBUG_FRAME_SECTION,
-                                          SECTION_DEBUG, NULL);
-      switch_to_section (debug_frame_section);
-    }
-}
-
-/* Output a Call Frame Information opcode and its operand(s).  */
-
-static void
-output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
-{
-  unsigned long r;
-  HOST_WIDE_INT off;
-
-  if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
-    dw2_asm_output_data (1, (cfi->dw_cfi_opc
-                            | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)),
-                        "DW_CFA_advance_loc " HOST_WIDE_INT_PRINT_HEX,
-                        ((unsigned HOST_WIDE_INT)
-                         cfi->dw_cfi_oprnd1.dw_cfi_offset));
-  else if (cfi->dw_cfi_opc == DW_CFA_offset)
-    {
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-      dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
-                          "DW_CFA_offset, column %#lx", r);
-      off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
-      dw2_asm_output_data_uleb128 (off, NULL);
-    }
-  else if (cfi->dw_cfi_opc == DW_CFA_restore)
-    {
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-      dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
-                          "DW_CFA_restore, column %#lx", r);
-    }
-  else
-    {
-      dw2_asm_output_data (1, cfi->dw_cfi_opc,
-                          "%s", dwarf_cfi_name (cfi->dw_cfi_opc));
-
-      switch (cfi->dw_cfi_opc)
-       {
-       case DW_CFA_set_loc:
-         if (for_eh)
-           dw2_asm_output_encoded_addr_rtx (
-               ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0),
-               gen_rtx_SYMBOL_REF (Pmode, cfi->dw_cfi_oprnd1.dw_cfi_addr),
-               false, NULL);
-         else
-           dw2_asm_output_addr (DWARF2_ADDR_SIZE,
-                                cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL);
-         fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
-         break;
-
-       case DW_CFA_advance_loc1:
-         dw2_asm_output_delta (1, cfi->dw_cfi_oprnd1.dw_cfi_addr,
-                               fde->dw_fde_current_label, NULL);
-         fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
-         break;
-
-       case DW_CFA_advance_loc2:
-         dw2_asm_output_delta (2, cfi->dw_cfi_oprnd1.dw_cfi_addr,
-                               fde->dw_fde_current_label, NULL);
-         fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
-         break;
-
-       case DW_CFA_advance_loc4:
-         dw2_asm_output_delta (4, cfi->dw_cfi_oprnd1.dw_cfi_addr,
-                               fde->dw_fde_current_label, NULL);
-         fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
-         break;
-
-       case DW_CFA_MIPS_advance_loc8:
-         dw2_asm_output_delta (8, cfi->dw_cfi_oprnd1.dw_cfi_addr,
-                               fde->dw_fde_current_label, NULL);
-         fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
-         break;
-
-       case DW_CFA_offset_extended:
-         r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-         dw2_asm_output_data_uleb128 (r, NULL);
-         off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
-         dw2_asm_output_data_uleb128 (off, NULL);
-         break;
-
-       case DW_CFA_def_cfa:
-         r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-         dw2_asm_output_data_uleb128 (r, NULL);
-         dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
-         break;
-
-       case DW_CFA_offset_extended_sf:
-         r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-         dw2_asm_output_data_uleb128 (r, NULL);
-         off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
-         dw2_asm_output_data_sleb128 (off, NULL);
-         break;
-
-       case DW_CFA_def_cfa_sf:
-         r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-         dw2_asm_output_data_uleb128 (r, NULL);
-         off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
-         dw2_asm_output_data_sleb128 (off, NULL);
-         break;
-
-       case DW_CFA_restore_extended:
-       case DW_CFA_undefined:
-       case DW_CFA_same_value:
-       case DW_CFA_def_cfa_register:
-         r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-         dw2_asm_output_data_uleb128 (r, NULL);
-         break;
-
-       case DW_CFA_register:
-         r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-         dw2_asm_output_data_uleb128 (r, NULL);
-         r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, for_eh);
-         dw2_asm_output_data_uleb128 (r, NULL);
-         break;
-
-       case DW_CFA_def_cfa_offset:
-       case DW_CFA_GNU_args_size:
-         dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset, NULL);
-         break;
-
-       case DW_CFA_def_cfa_offset_sf:
-         off = div_data_align (cfi->dw_cfi_oprnd1.dw_cfi_offset);
-         dw2_asm_output_data_sleb128 (off, NULL);
-         break;
-
-       case DW_CFA_GNU_window_save:
-         break;
-
-       case DW_CFA_def_cfa_expression:
-       case DW_CFA_expression:
-         output_cfa_loc (cfi);
-         break;
-
-       case DW_CFA_GNU_negative_offset_extended:
-         /* Obsoleted by DW_CFA_offset_extended_sf.  */
-         gcc_unreachable ();
-
-       default:
-         break;
-       }
-    }
-}
-
-/* Similar, but do it via assembler directives instead.  */
-
-static void
-output_cfi_directive (dw_cfi_ref cfi)
-{
-  unsigned long r, r2;
-
-  switch (cfi->dw_cfi_opc)
-    {
-    case DW_CFA_advance_loc:
-    case DW_CFA_advance_loc1:
-    case DW_CFA_advance_loc2:
-    case DW_CFA_advance_loc4:
-    case DW_CFA_MIPS_advance_loc8:
-    case DW_CFA_set_loc:
-      /* Should only be created by add_fde_cfi in a code path not
-        followed when emitting via directives.  The assembler is
-        going to take care of this for us.  */
-      gcc_unreachable ();
-
-    case DW_CFA_offset:
-    case DW_CFA_offset_extended:
-    case DW_CFA_offset_extended_sf:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (asm_out_file, "\t.cfi_offset %lu, "HOST_WIDE_INT_PRINT_DEC"\n",
-              r, cfi->dw_cfi_oprnd2.dw_cfi_offset);
-      break;
-
-    case DW_CFA_restore:
-    case DW_CFA_restore_extended:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (asm_out_file, "\t.cfi_restore %lu\n", r);
-      break;
-
-    case DW_CFA_undefined:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (asm_out_file, "\t.cfi_undefined %lu\n", r);
-      break;
-
-    case DW_CFA_same_value:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (asm_out_file, "\t.cfi_same_value %lu\n", r);
-      break;
-
-    case DW_CFA_def_cfa:
-    case DW_CFA_def_cfa_sf:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (asm_out_file, "\t.cfi_def_cfa %lu, "HOST_WIDE_INT_PRINT_DEC"\n",
-              r, cfi->dw_cfi_oprnd2.dw_cfi_offset);
-      break;
-
-    case DW_CFA_def_cfa_register:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (asm_out_file, "\t.cfi_def_cfa_register %lu\n", r);
-      break;
-
-    case DW_CFA_register:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      r2 = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, 1);
-      fprintf (asm_out_file, "\t.cfi_register %lu, %lu\n", r, r2);
-      break;
-
-    case DW_CFA_def_cfa_offset:
-    case DW_CFA_def_cfa_offset_sf:
-      fprintf (asm_out_file, "\t.cfi_def_cfa_offset "
-              HOST_WIDE_INT_PRINT_DEC"\n",
-              cfi->dw_cfi_oprnd1.dw_cfi_offset);
-      break;
-
-    case DW_CFA_remember_state:
-      fprintf (asm_out_file, "\t.cfi_remember_state\n");
-      break;
-    case DW_CFA_restore_state:
-      fprintf (asm_out_file, "\t.cfi_restore_state\n");
-      break;
-
-    case DW_CFA_GNU_args_size:
-      fprintf (asm_out_file, "\t.cfi_escape %#x,", DW_CFA_GNU_args_size);
-      dw2_asm_output_data_uleb128_raw (cfi->dw_cfi_oprnd1.dw_cfi_offset);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s args_size "HOST_WIDE_INT_PRINT_DEC,
-                ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset);
-      fputc ('\n', asm_out_file);
-      break;
-
-    case DW_CFA_GNU_window_save:
-      fprintf (asm_out_file, "\t.cfi_window_save\n");
-      break;
-
-    case DW_CFA_def_cfa_expression:
-    case DW_CFA_expression:
-      fprintf (asm_out_file, "\t.cfi_escape %#x,", cfi->dw_cfi_opc);
-      output_cfa_loc_raw (cfi);
-      fputc ('\n', asm_out_file);
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-}
-
-DEF_VEC_P (dw_cfi_ref);
-DEF_VEC_ALLOC_P (dw_cfi_ref, heap);
-
-/* Output CFIs to bring current FDE to the same state as after executing
-   CFIs in CFI chain.  DO_CFI_ASM is true if .cfi_* directives shall
-   be emitted, false otherwise.  If it is false, FDE and FOR_EH are the
-   other arguments to pass to output_cfi.  */
-
-static void
-output_cfis (dw_cfi_ref cfi, bool do_cfi_asm, dw_fde_ref fde, bool for_eh)
-{
-  struct dw_cfi_struct cfi_buf;
-  dw_cfi_ref cfi2;
-  dw_cfi_ref cfi_args_size = NULL, cfi_cfa = NULL, cfi_cfa_offset = NULL;
-  VEC (dw_cfi_ref, heap) *regs = VEC_alloc (dw_cfi_ref, heap, 32);
-  unsigned int len, idx;
-
-  for (;; cfi = cfi->dw_cfi_next)
-    switch (cfi ? cfi->dw_cfi_opc : DW_CFA_nop)
-      {
-      case DW_CFA_advance_loc:
-      case DW_CFA_advance_loc1:
-      case DW_CFA_advance_loc2:
-      case DW_CFA_advance_loc4:
-      case DW_CFA_MIPS_advance_loc8:
-      case DW_CFA_set_loc:
-       /* All advances should be ignored.  */
-       break;
-      case DW_CFA_remember_state:
-       {
-         dw_cfi_ref args_size = cfi_args_size;
-
-         /* Skip everything between .cfi_remember_state and
-            .cfi_restore_state.  */
-         for (cfi2 = cfi->dw_cfi_next; cfi2; cfi2 = cfi2->dw_cfi_next)
-           if (cfi2->dw_cfi_opc == DW_CFA_restore_state)
-             break;
-           else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size)
-             args_size = cfi2;
-           else
-             gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state);
-
-         if (cfi2 == NULL)
-           goto flush_all;
-         else
-           {
-             cfi = cfi2;
-             cfi_args_size = args_size;
-           }
-         break;
-       }
-      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 ();
-    }
-}
-
-/* Output one FDE.  */
-
-static void
-output_fde (dw_fde_ref fde, bool for_eh, bool second,
-           char *section_start_label, int fde_encoding, char *augmentation,
-           bool any_lsda_needed, int lsda_encoding)
-{
-  const char *begin, *end;
-  static unsigned int j;
-  char l1[20], l2[20];
-  dw_cfi_ref cfi;
-
-  targetm.asm_out.unwind_label (asm_out_file, fde->decl, for_eh,
-                               /* empty */ 0);
-  targetm.asm_out.internal_label (asm_out_file, FDE_LABEL,
-                                 for_eh + j);
-  ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + j);
-  ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + j);
-  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
-    dw2_asm_output_data (4, 0xffffffff, "Initial length escape value"
-                        " indicating 64-bit DWARF extension");
-  dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
-                       "FDE Length");
-  ASM_OUTPUT_LABEL (asm_out_file, l1);
-
-  if (for_eh)
-    dw2_asm_output_delta (4, l1, section_start_label, "FDE CIE offset");
-  else
-    dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label,
-                          debug_frame_section, "FDE CIE offset");
-
-  if (!fde->dw_fde_switched_sections)
-    {
-      begin = fde->dw_fde_begin;
-      end = fde->dw_fde_end;
-    }
-  else
-    {
-      /* For the first section, prefer dw_fde_begin over
-        dw_fde_{hot,cold}_section_label, as the latter
-        might be separated from the real start of the
-        function by alignment padding.  */
-      if (!second)
-       begin = fde->dw_fde_begin;
-      else if (fde->dw_fde_switched_cold_to_hot)
-       begin = fde->dw_fde_hot_section_label;
-      else
-       begin = fde->dw_fde_unlikely_section_label;
-      if (second ^ fde->dw_fde_switched_cold_to_hot)
-       end = fde->dw_fde_unlikely_section_end_label;
-      else
-       end = fde->dw_fde_hot_section_end_label;
-    }
-
-  if (for_eh)
-    {
-      rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, begin);
-      SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
-      dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref, false,
-                                      "FDE initial location");
-      dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
-                           end, begin, "FDE address range");
-    }
-  else
-    {
-      dw2_asm_output_addr (DWARF2_ADDR_SIZE, begin, "FDE initial location");
-      dw2_asm_output_delta (DWARF2_ADDR_SIZE, end, begin, "FDE address range");
-    }
-
-  if (augmentation[0])
-    {
-      if (any_lsda_needed)
-       {
-         int size = size_of_encoded_value (lsda_encoding);
-
-         if (lsda_encoding == DW_EH_PE_aligned)
-           {
-             int offset = (  4         /* Length */
-                           + 4         /* CIE offset */
-                           + 2 * size_of_encoded_value (fde_encoding)
-                           + 1         /* Augmentation size */ );
-             int pad = -offset & (PTR_SIZE - 1);
-
-             size += pad;
-             gcc_assert (size_of_uleb128 (size) == 1);
-           }
-
-         dw2_asm_output_data_uleb128 (size, "Augmentation size");
-
-         if (fde->uses_eh_lsda)
-           {
-             ASM_GENERATE_INTERNAL_LABEL (l1, second ? "LLSDAC" : "LLSDA",
-                                          fde->funcdef_number);
-             dw2_asm_output_encoded_addr_rtx (lsda_encoding,
-                                              gen_rtx_SYMBOL_REF (Pmode, l1),
-                                              false,
-                                              "Language Specific Data Area");
-           }
-         else
-           {
-             if (lsda_encoding == DW_EH_PE_aligned)
-               ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
-             dw2_asm_output_data (size_of_encoded_value (lsda_encoding), 0,
-                                  "Language Specific Data Area (none)");
-           }
-       }
-      else
-       dw2_asm_output_data_uleb128 (0, "Augmentation size");
-    }
-
-  /* Loop through the Call Frame Instructions associated with
-     this FDE.  */
-  fde->dw_fde_current_label = begin;
-  if (!fde->dw_fde_switched_sections)
-    for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
-      output_cfi (cfi, fde, for_eh);
-  else if (!second)
-    {
-      if (fde->dw_fde_switch_cfi)
-       for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
-         {
-           output_cfi (cfi, fde, for_eh);
-           if (cfi == fde->dw_fde_switch_cfi)
-             break;
-         }
-    }
-  else
-    {
-      dw_cfi_ref cfi_next = fde->dw_fde_cfi;
-
-      if (fde->dw_fde_switch_cfi)
-       {
-         cfi_next = fde->dw_fde_switch_cfi->dw_cfi_next;
-         fde->dw_fde_switch_cfi->dw_cfi_next = NULL;
-         output_cfis (fde->dw_fde_cfi, false, fde, for_eh);
-         fde->dw_fde_switch_cfi->dw_cfi_next = cfi_next;
-       }
-      for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next)
-       output_cfi (cfi, fde, for_eh);
-    }
-
-  /* If we are to emit a ref/link from function bodies to their frame tables,
-     do it now.  This is typically performed to make sure that tables
-     associated with functions are dragged with them and not discarded in
-     garbage collecting links. We need to do this on a per function basis to
-     cope with -ffunction-sections.  */
-
-#ifdef ASM_OUTPUT_DWARF_TABLE_REF
-  /* Switch to the function section, emit the ref to the tables, and
-     switch *back* into the table section.  */
-  switch_to_section (function_section (fde->decl));
-  ASM_OUTPUT_DWARF_TABLE_REF (section_start_label);
-  switch_to_frame_table_section (for_eh, true);
-#endif
-
-  /* Pad the FDE out to an address sized boundary.  */
-  ASM_OUTPUT_ALIGN (asm_out_file,
-                   floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
-  ASM_OUTPUT_LABEL (asm_out_file, l2);
-
-  j += 2;
-}
-
-/* Output the call frame information used to record information
-   that relates to calculating the frame pointer, and records the
-   location of saved registers.  */
-
-static void
-output_call_frame_info (int for_eh)
-{
-  unsigned int i;
-  dw_fde_ref fde;
-  dw_cfi_ref cfi;
-  char l1[20], l2[20], section_start_label[20];
-  bool any_lsda_needed = false;
-  char augmentation[6];
-  int augmentation_size;
-  int fde_encoding = DW_EH_PE_absptr;
-  int per_encoding = DW_EH_PE_absptr;
-  int lsda_encoding = DW_EH_PE_absptr;
-  int return_reg;
-  rtx personality = NULL;
-  int dw_cie_version;
-
-  /* Don't emit a CIE if there won't be any FDEs.  */
-  if (fde_table_in_use == 0)
-    return;
-
-  /* Nothing to do if the assembler's doing it all.  */
-  if (dwarf2out_do_cfi_asm ())
-    return;
-
-  /* If we make FDEs linkonce, we may have to emit an empty label for
-     an FDE that wouldn't otherwise be emitted.  We want to avoid
-     having an FDE kept around when the function it refers to is
-     discarded.  Example where this matters: a primary function
-     template in C++ requires EH information, but an explicit
-     specialization doesn't.  */
-  if (TARGET_USES_WEAK_UNWIND_INFO
-      && ! flag_asynchronous_unwind_tables
-      && flag_exceptions
-      && for_eh)
-    for (i = 0; i < fde_table_in_use; i++)
-      if ((fde_table[i].nothrow || fde_table[i].all_throwers_are_sibcalls)
-         && !fde_table[i].uses_eh_lsda
-         && ! DECL_WEAK (fde_table[i].decl))
-       targetm.asm_out.unwind_label (asm_out_file, fde_table[i].decl,
-                                     for_eh, /* empty */ 1);
-
-  /* If we don't have any functions we'll want to unwind out of, don't
-     emit any EH unwind information.  Note that if exceptions aren't
-     enabled, we won't have collected nothrow information, and if we
-     asked for asynchronous tables, we always want this info.  */
-  if (for_eh)
-    {
-      bool any_eh_needed = !flag_exceptions || flag_asynchronous_unwind_tables;
-
-      for (i = 0; i < fde_table_in_use; i++)
-       if (fde_table[i].uses_eh_lsda)
-         any_eh_needed = any_lsda_needed = true;
-       else if (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde_table[i].decl))
-         any_eh_needed = true;
-       else if (! fde_table[i].nothrow
-                && ! fde_table[i].all_throwers_are_sibcalls)
-         any_eh_needed = true;
-
-      if (! any_eh_needed)
-       return;
-    }
-
-  /* We're going to be generating comments, so turn on app.  */
-  if (flag_debug_asm)
-    app_enable ();
-
-  /* Switch to the proper frame section, first time.  */
-  switch_to_frame_table_section (for_eh, false);
-
-  ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
-  ASM_OUTPUT_LABEL (asm_out_file, section_start_label);
-
-  /* Output the CIE.  */
-  ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
-  ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
-  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
-    dw2_asm_output_data (4, 0xffffffff,
-      "Initial length escape value indicating 64-bit DWARF extension");
-  dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
-                       "Length of Common Information Entry");
-  ASM_OUTPUT_LABEL (asm_out_file, l1);
-
-  /* Now that the CIE pointer is PC-relative for EH,
-     use 0 to identify the CIE.  */
-  dw2_asm_output_data ((for_eh ? 4 : DWARF_OFFSET_SIZE),
-                      (for_eh ? 0 : DWARF_CIE_ID),
-                      "CIE Identifier Tag");
-
-  /* Use the CIE version 3 for DWARF3; allow DWARF2 to continue to
-     use CIE version 1, unless that would produce incorrect results
-     due to overflowing the return register column.  */
-  return_reg = DWARF2_FRAME_REG_OUT (DWARF_FRAME_RETURN_COLUMN, for_eh);
-  dw_cie_version = 1;
-  if (return_reg >= 256 || dwarf_version > 2)
-    dw_cie_version = 3;
-  dw2_asm_output_data (1, dw_cie_version, "CIE Version");
-
-  augmentation[0] = 0;
-  augmentation_size = 0;
-
-  personality = current_unit_personality;
-  if (for_eh)
-    {
-      char *p;
-
-      /* Augmentation:
-        z      Indicates that a uleb128 is present to size the
-               augmentation section.
-        L      Indicates the encoding (and thus presence) of
-               an LSDA pointer in the FDE augmentation.
-        R      Indicates a non-default pointer encoding for
-               FDE code pointers.
-        P      Indicates the presence of an encoding + language
-               personality routine in the CIE augmentation.  */
-
-      fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0);
-      per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
-      lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
-
-      p = augmentation + 1;
-      if (personality)
-       {
-         *p++ = 'P';
-         augmentation_size += 1 + size_of_encoded_value (per_encoding);
-         assemble_external_libcall (personality);
-       }
-      if (any_lsda_needed)
-       {
-         *p++ = 'L';
-         augmentation_size += 1;
-       }
-      if (fde_encoding != DW_EH_PE_absptr)
-       {
-         *p++ = 'R';
-         augmentation_size += 1;
-       }
-      if (p > augmentation + 1)
-       {
-         augmentation[0] = 'z';
-         *p = '\0';
-       }
-
-      /* Ug.  Some platforms can't do unaligned dynamic relocations at all.  */
-      if (personality && per_encoding == DW_EH_PE_aligned)
-       {
-         int offset = (  4             /* Length */
-                       + 4             /* CIE Id */
-                       + 1             /* CIE version */
-                       + strlen (augmentation) + 1     /* Augmentation */
-                       + size_of_uleb128 (1)           /* Code alignment */
-                       + size_of_sleb128 (DWARF_CIE_DATA_ALIGNMENT)
-                       + 1             /* RA column */
-                       + 1             /* Augmentation size */
-                       + 1             /* Personality encoding */ );
-         int pad = -offset & (PTR_SIZE - 1);
-
-         augmentation_size += pad;
-
-         /* Augmentations should be small, so there's scarce need to
-            iterate for a solution.  Die if we exceed one uleb128 byte.  */
-         gcc_assert (size_of_uleb128 (augmentation_size) == 1);
-       }
-    }
-
-  dw2_asm_output_nstring (augmentation, -1, "CIE Augmentation");
-  if (dw_cie_version >= 4)
-    {
-      dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "CIE Address Size");
-      dw2_asm_output_data (1, 0, "CIE Segment Size");
-    }
-  dw2_asm_output_data_uleb128 (1, "CIE Code Alignment Factor");
-  dw2_asm_output_data_sleb128 (DWARF_CIE_DATA_ALIGNMENT,
-                              "CIE Data Alignment Factor");
-
-  if (dw_cie_version == 1)
-    dw2_asm_output_data (1, return_reg, "CIE RA Column");
-  else
-    dw2_asm_output_data_uleb128 (return_reg, "CIE RA Column");
-
-  if (augmentation[0])
-    {
-      dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size");
-      if (personality)
-       {
-         dw2_asm_output_data (1, per_encoding, "Personality (%s)",
-                              eh_data_format_name (per_encoding));
-         dw2_asm_output_encoded_addr_rtx (per_encoding,
-                                          personality,
-                                          true, NULL);
-       }
-
-      if (any_lsda_needed)
-       dw2_asm_output_data (1, lsda_encoding, "LSDA Encoding (%s)",
-                            eh_data_format_name (lsda_encoding));
-
-      if (fde_encoding != DW_EH_PE_absptr)
-       dw2_asm_output_data (1, fde_encoding, "FDE Encoding (%s)",
-                            eh_data_format_name (fde_encoding));
-    }
-
-  for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
-    output_cfi (cfi, NULL, for_eh);
-
-  /* Pad the CIE out to an address sized boundary.  */
-  ASM_OUTPUT_ALIGN (asm_out_file,
-                   floor_log2 (for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE));
-  ASM_OUTPUT_LABEL (asm_out_file, l2);
-
-  /* Loop through all of the FDE's.  */
-  for (i = 0; i < fde_table_in_use; i++)
-    {
-      unsigned int k;
-      fde = &fde_table[i];
-
-      /* Don't emit EH unwind info for leaf functions that don't need it.  */
-      if (for_eh && !flag_asynchronous_unwind_tables && flag_exceptions
-         && (fde->nothrow || fde->all_throwers_are_sibcalls)
-         && ! (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde_table[i].decl))
-         && !fde->uses_eh_lsda)
-       continue;
-
-      for (k = 0; k < (fde->dw_fde_switched_sections ? 2 : 1); k++)
-       output_fde (fde, for_eh, k, section_start_label, fde_encoding,
-                   augmentation, any_lsda_needed, lsda_encoding);
-    }
-
-  if (for_eh && targetm.terminate_dw2_eh_frame_info)
-    dw2_asm_output_data (4, 0, "End of Table");
-#ifdef MIPS_DEBUGGING_INFO
-  /* Work around Irix 6 assembler bug whereby labels at the end of a section
-     get a value of 0.  Putting .align 0 after the label fixes it.  */
-  ASM_OUTPUT_ALIGN (asm_out_file, 0);
-#endif
-
-  /* Turn off app to make assembly quicker.  */
-  if (flag_debug_asm)
-    app_disable ();
-}
-
-/* Emit .cfi_startproc and .cfi_personality/.cfi_lsda if needed.  */
-
-static void
-dwarf2out_do_cfi_startproc (bool second)
-{
-  int enc;
-  rtx ref;
-  rtx personality = get_personality_function (current_function_decl);
-
-  fprintf (asm_out_file, "\t.cfi_startproc\n");
-
-  if (personality)
-    {
-      enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
-      ref = personality;
-
-      /* ??? The GAS support isn't entirely consistent.  We have to
-        handle indirect support ourselves, but PC-relative is done
-        in the assembler.  Further, the assembler can't handle any
-        of the weirder relocation types.  */
-      if (enc & DW_EH_PE_indirect)
-       ref = dw2_force_const_mem (ref, true);
-
-      fprintf (asm_out_file, "\t.cfi_personality %#x,", enc);
-      output_addr_const (asm_out_file, ref);
-      fputc ('\n', asm_out_file);
-    }
-
-  if (crtl->uses_eh_lsda)
-    {
-      char lab[20];
-
-      enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
-      ASM_GENERATE_INTERNAL_LABEL (lab, second ? "LLSDAC" : "LLSDA",
-                                  current_function_funcdef_no);
-      ref = gen_rtx_SYMBOL_REF (Pmode, lab);
-      SYMBOL_REF_FLAGS (ref) = SYMBOL_FLAG_LOCAL;
-
-      if (enc & DW_EH_PE_indirect)
-       ref = dw2_force_const_mem (ref, true);
-
-      fprintf (asm_out_file, "\t.cfi_lsda %#x,", enc);
-      output_addr_const (asm_out_file, ref);
-      fputc ('\n', asm_out_file);
-    }
-}
-
-/* Output a marker (i.e. a label) for the beginning of a function, before
-   the prologue.  */
-
-void
-dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
-                         const char *file ATTRIBUTE_UNUSED)
-{
-  char label[MAX_ARTIFICIAL_LABEL_BYTES];
-  char * dup_label;
-  dw_fde_ref fde;
-  section *fnsec;
-
-  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 ())
-    return;
-#endif
-
-  fnsec = function_section (current_function_decl);
-  switch_to_section (fnsec);
-  ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
-                              current_function_funcdef_no);
-  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
-                         current_function_funcdef_no);
-  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 ())
-    return;
-#endif
-
-  /* Expand the fde table if necessary.  */
-  if (fde_table_in_use == fde_table_allocated)
-    {
-      fde_table_allocated += FDE_TABLE_INCREMENT;
-      fde_table = GGC_RESIZEVEC (dw_fde_node, fde_table, fde_table_allocated);
-      memset (fde_table + fde_table_in_use, 0,
-             FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
-    }
-
-  /* Record the FDE associated with this function.  */
-  current_funcdef_fde = fde_table_in_use;
-
-  /* Add the new FDE at the end of the fde_table.  */
-  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_cfi = NULL;
-  fde->dw_fde_switch_cfi = NULL;
-  fde->funcdef_number = current_function_funcdef_no;
-  fde->nothrow = crtl->nothrow;
-  fde->uses_eh_lsda = crtl->uses_eh_lsda;
-  fde->all_throwers_are_sibcalls = crtl->all_throwers_are_sibcalls;
-  fde->drap_reg = INVALID_REGNUM;
-  fde->vdrap_reg = INVALID_REGNUM;
-  if (flag_reorder_blocks_and_partition)
-    {
-      section *unlikelysec;
-      if (first_function_block_is_cold)
-       fde->in_std_section = 1;
-      else
-       fde->in_std_section
-         = (fnsec == text_section
-            || (cold_text_section && fnsec == cold_text_section));
-      unlikelysec = unlikely_text_section ();
-      fde->cold_in_std_section
-       = (unlikelysec == text_section
-          || (cold_text_section && unlikelysec == cold_text_section));
-    }
-  else
-    {
-      fde->in_std_section
-       = (fnsec == text_section
-          || (cold_text_section && fnsec == cold_text_section));
-      fde->cold_in_std_section = 0;
-    }
-
-  args_size = old_args_size = 0;
-
-  /* We only want to output line number information for the genuine dwarf2
-     prologue case, not the eh frame case.  */
-#ifdef DWARF2_DEBUGGING_INFO
-  if (file)
-    dwarf2out_source_line (line, file, 0, true);
-#endif
-
-  if (dwarf2out_do_cfi_asm ())
-    dwarf2out_do_cfi_startproc (false);
-  else
-    {
-      rtx personality = get_personality_function (current_function_decl);
-      if (!current_unit_personality)
-        current_unit_personality = personality;
-
-      /* We cannot keep a current personality per function as without CFI
-        asm at the point where we emit the CFI data there is no current
-        function anymore.  */
-      if (personality
-         && current_unit_personality != personality)
-       sorry ("Multiple EH personalities are supported only with assemblers "
-              "supporting .cfi.personality directive.");
-    }
-}
-
-/* Output a marker (i.e. a label) for the absolute end of the generated code
-   for a function definition.  This gets called *after* the epilogue code has
-   been generated.  */
-
-void
-dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
-                       const char *file ATTRIBUTE_UNUSED)
-{
-  dw_fde_ref fde;
-  char label[MAX_ARTIFICIAL_LABEL_BYTES];
-
-#ifdef DWARF2_DEBUGGING_INFO
-  last_var_location_insn = NULL_RTX;
-#endif
-
-  if (dwarf2out_do_cfi_asm ())
-    fprintf (asm_out_file, "\t.cfi_endproc\n");
-
-  /* Output a label to mark the endpoint of the code generated for this
-     function.  */
-  ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL,
-                              current_function_funcdef_no);
-  ASM_OUTPUT_LABEL (asm_out_file, label);
-  fde = current_fde ();
-  gcc_assert (fde != NULL);
-  fde->dw_fde_end = xstrdup (label);
-}
-
-void
-dwarf2out_frame_init (void)
-{
-  /* Allocate the initial hunk of the fde_table.  */
-  fde_table = GGC_CNEWVEC (dw_fde_node, FDE_TABLE_INCREMENT);
-  fde_table_allocated = FDE_TABLE_INCREMENT;
-  fde_table_in_use = 0;
-
-  /* Generate the CFA instructions common to all FDE's.  Do it now for the
-     sake of lookup_cfa.  */
-
-  /* On entry, the Canonical Frame Address is at SP.  */
-  dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
-
-#ifdef DWARF2_UNWIND_INFO
-  if (DWARF2_UNWIND_INFO || DWARF2_FRAME_INFO)
-    initial_return_save (INCOMING_RETURN_ADDR_RTX);
-#endif
-}
-
-void
-dwarf2out_frame_finish (void)
-{
-  /* Output call frame information.  */
-  if (DWARF2_FRAME_INFO)
-    output_call_frame_info (0);
-
-#ifndef TARGET_UNWIND_INFO
-  /* Output another copy for the unwinder.  */
-  if (! USING_SJLJ_EXCEPTIONS && (flag_unwind_tables || flag_exceptions))
-    output_call_frame_info (1);
-#endif
-}
-
-/* Note that the current function section is being used for code.  */
-
-static void
-dwarf2out_note_section_used (void)
-{
-  section *sec = current_function_section ();
-  if (sec == text_section)
-    text_section_used = true;
-  else if (sec == cold_text_section)
-    cold_text_section_used = true;
-}
-
-void
-dwarf2out_switch_text_section (void)
-{
-  dw_fde_ref fde = current_fde ();
-
-  gcc_assert (cfun && fde && !fde->dw_fde_switched_sections);
-
-  fde->dw_fde_switched_sections = 1;
-  fde->dw_fde_switched_cold_to_hot = !in_cold_section_p;
-
-  fde->dw_fde_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;
-  have_multiple_function_sections = true;
-
-  /* Reset the current label on switching text sections, so that we
-     don't attempt to advance_loc4 between labels in different sections.  */
-  fde->dw_fde_current_label = NULL;
-
-  /* There is no need to mark used sections when not debugging.  */
-  if (cold_text_section != NULL)
-    dwarf2out_note_section_used ();
-
-  if (dwarf2out_do_cfi_asm ())
-    fprintf (asm_out_file, "\t.cfi_endproc\n");
-
-  /* Now do the real section switch.  */
-  switch_to_section (current_function_section ());
-
-  if (dwarf2out_do_cfi_asm ())
-    {
-      dwarf2out_do_cfi_startproc (true);
-      /* As this is a different FDE, insert all current CFI instructions
-        again.  */
-      output_cfis (fde->dw_fde_cfi, true, fde, true);
-    }
-  else
-    {
-      dw_cfi_ref cfi = fde->dw_fde_cfi;
-
-      cfi = fde->dw_fde_cfi;
-      if (cfi)
-       while (cfi->dw_cfi_next != NULL)
-         cfi = cfi->dw_cfi_next;
-      fde->dw_fde_switch_cfi = cfi;
-    }
-}
-#endif
-\f
-/* And now, the subset of the debugging information support code necessary
-   for emitting location expressions.  */
-
-/* Data about a single source file.  */
-struct GTY(()) dwarf_file_data {
-  const char * filename;
-  int emitted_number;
-};
-
-typedef struct dw_val_struct *dw_val_ref;
-typedef struct die_struct *dw_die_ref;
-typedef const struct die_struct *const_dw_die_ref;
-typedef struct dw_loc_descr_struct *dw_loc_descr_ref;
-typedef struct dw_loc_list_struct *dw_loc_list_ref;
-
-typedef struct GTY(()) deferred_locations_struct
-{
-  tree variable;
-  dw_die_ref die;
-} deferred_locations;
-
-DEF_VEC_O(deferred_locations);
-DEF_VEC_ALLOC_O(deferred_locations,gc);
-
-static GTY(()) VEC(deferred_locations, gc) *deferred_locations_list;
-
-DEF_VEC_P(dw_die_ref);
-DEF_VEC_ALLOC_P(dw_die_ref,heap);
-
-/* Each DIE may have a series of attribute/value pairs.  Values
-   can take on several forms.  The forms that are used in this
-   implementation are listed below.  */
-
-enum dw_val_class
-{
-  dw_val_class_addr,
-  dw_val_class_offset,
-  dw_val_class_loc,
-  dw_val_class_loc_list,
-  dw_val_class_range_list,
-  dw_val_class_const,
-  dw_val_class_unsigned_const,
-  dw_val_class_const_double,
-  dw_val_class_vec,
-  dw_val_class_flag,
-  dw_val_class_die_ref,
-  dw_val_class_fde_ref,
-  dw_val_class_lbl_id,
-  dw_val_class_lineptr,
-  dw_val_class_str,
-  dw_val_class_macptr,
-  dw_val_class_file,
-  dw_val_class_data8
-};
-
-/* Describe a floating point constant value, or a vector constant value.  */
-
-typedef struct GTY(()) dw_vec_struct {
-  unsigned char * GTY((length ("%h.length"))) array;
-  unsigned length;
-  unsigned elt_size;
-}
-dw_vec_const;
-
-/* The dw_val_node describes an attribute's value, as it is
-   represented internally.  */
-
-typedef struct GTY(()) dw_val_struct {
-  enum dw_val_class val_class;
-  union dw_val_struct_union
-    {
-      rtx GTY ((tag ("dw_val_class_addr"))) val_addr;
-      unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_offset"))) val_offset;
-      dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list;
-      dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
-      HOST_WIDE_INT GTY ((default)) val_int;
-      unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
-      double_int GTY ((tag ("dw_val_class_const_double"))) val_double;
-      dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
-      struct dw_val_die_union
-       {
-         dw_die_ref die;
-         int external;
-       } GTY ((tag ("dw_val_class_die_ref"))) val_die_ref;
-      unsigned GTY ((tag ("dw_val_class_fde_ref"))) val_fde_index;
-      struct indirect_string_node * GTY ((tag ("dw_val_class_str"))) val_str;
-      char * GTY ((tag ("dw_val_class_lbl_id"))) val_lbl_id;
-      unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag;
-      struct dwarf_file_data * GTY ((tag ("dw_val_class_file"))) val_file;
-      unsigned char GTY ((tag ("dw_val_class_data8"))) val_data8[8];
-    }
-  GTY ((desc ("%1.val_class"))) v;
-}
-dw_val_node;
-
-/* Locations in memory are described using a sequence of stack machine
-   operations.  */
-
-typedef struct GTY(()) dw_loc_descr_struct {
-  dw_loc_descr_ref dw_loc_next;
-  ENUM_BITFIELD (dwarf_location_atom) dw_loc_opc : 8;
-  /* Used to distinguish DW_OP_addr with a direct symbol relocation
-     from DW_OP_addr with a dtp-relative symbol relocation.  */
-  unsigned int dtprel : 1;
-  int dw_loc_addr;
-  dw_val_node dw_loc_oprnd1;
-  dw_val_node dw_loc_oprnd2;
-}
-dw_loc_descr_node;
+DEF_VEC_P(dw_die_ref);
+DEF_VEC_ALLOC_P(dw_die_ref,heap);
 
 /* Location lists are ranges + location descriptions for that range,
    so you can track variables that are in different places over
@@ -4259,10 +1214,18 @@ 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;
+  /* True if the range should be emitted even if begin and end
+     are the same.  */
+  bool force;
 } dw_loc_list_node;
 
-#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
-
 static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
 
 /* Convert a DWARF stack opcode into its string name.  */
@@ -4588,6 +1551,22 @@ 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";
+    case DW_OP_GNU_parameter_ref:
+      return "DW_OP_GNU_parameter_ref";
 
     default:
       return "OP_<unknown>";
@@ -4602,7 +1581,7 @@ static inline dw_loc_descr_ref
 new_loc_descr (enum dwarf_location_atom op, unsigned HOST_WIDE_INT oprnd1,
               unsigned HOST_WIDE_INT oprnd2)
 {
-  dw_loc_descr_ref descr = GGC_CNEW (dw_loc_descr_node);
+  dw_loc_descr_ref descr = ggc_alloc_cleared_dw_loc_descr_node ();
 
   descr->dw_loc_opc = op;
   descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
@@ -4637,9 +1616,112 @@ add_loc_descr (dw_loc_descr_ref *list_head, dw_loc_descr_ref descr)
   for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
     ;
 
-  *d = descr;
+  *d = descr;
+}
+
+/* Compare two location operands for exact equality.  */
+
+static bool
+dw_val_equal_p (dw_val_node *a, dw_val_node *b)
+{
+  if (a->val_class != b->val_class)
+    return false;
+  switch (a->val_class)
+    {
+    case dw_val_class_none:
+      return true;
+    case dw_val_class_addr:
+      return rtx_equal_p (a->v.val_addr, b->v.val_addr);
+
+    case dw_val_class_offset:
+    case dw_val_class_unsigned_const:
+    case dw_val_class_const:
+    case dw_val_class_range_list:
+    case dw_val_class_lineptr:
+    case dw_val_class_macptr:
+      /* These are all HOST_WIDE_INT, signed or unsigned.  */
+      return a->v.val_unsigned == b->v.val_unsigned;
+
+    case dw_val_class_loc:
+      return a->v.val_loc == b->v.val_loc;
+    case dw_val_class_loc_list:
+      return a->v.val_loc_list == b->v.val_loc_list;
+    case dw_val_class_die_ref:
+      return a->v.val_die_ref.die == b->v.val_die_ref.die;
+    case dw_val_class_fde_ref:
+      return a->v.val_fde_index == b->v.val_fde_index;
+    case dw_val_class_lbl_id:
+      return strcmp (a->v.val_lbl_id, b->v.val_lbl_id) == 0;
+    case dw_val_class_str:
+      return a->v.val_str == b->v.val_str;
+    case dw_val_class_flag:
+      return a->v.val_flag == b->v.val_flag;
+    case dw_val_class_file:
+      return a->v.val_file == b->v.val_file;
+    case dw_val_class_decl_ref:
+      return a->v.val_decl_ref == b->v.val_decl_ref;
+    
+    case dw_val_class_const_double:
+      return (a->v.val_double.high == b->v.val_double.high
+             && a->v.val_double.low == b->v.val_double.low);
+
+    case dw_val_class_vec:
+      {
+       size_t a_len = a->v.val_vec.elt_size * a->v.val_vec.length;
+       size_t b_len = b->v.val_vec.elt_size * b->v.val_vec.length;
+
+       return (a_len == b_len
+               && !memcmp (a->v.val_vec.array, b->v.val_vec.array, a_len));
+      }
+
+    case dw_val_class_data8:
+      return memcmp (a->v.val_data8, b->v.val_data8, 8) == 0;
+
+    case dw_val_class_vms_delta:
+      return (!strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)
+              && !strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1));
+    }
+  gcc_unreachable ();
+}
+
+/* Compare two location atoms for exact equality.  */
+
+static bool
+loc_descr_equal_p_1 (dw_loc_descr_ref a, dw_loc_descr_ref b)
+{
+  if (a->dw_loc_opc != b->dw_loc_opc)
+    return false;
+
+  /* ??? This is only ever set for DW_OP_constNu, for N equal to the
+     address size, but since we always allocate cleared storage it
+     should be zero for other types of locations.  */
+  if (a->dtprel != b->dtprel)
+    return false;
+
+  return (dw_val_equal_p (&a->dw_loc_oprnd1, &b->dw_loc_oprnd1)
+         && dw_val_equal_p (&a->dw_loc_oprnd2, &b->dw_loc_oprnd2));
+}
+
+/* Compare two complete location expressions for exact equality.  */
+
+bool
+loc_descr_equal_p (dw_loc_descr_ref a, dw_loc_descr_ref b)
+{
+  while (1)
+    {
+      if (a == b)
+       return true;
+      if (a == NULL || b == NULL)
+       return false;
+      if (!loc_descr_equal_p_1 (a, b))
+       return false;
+
+      a = a->dw_loc_next;
+      b = b->dw_loc_next;
+    }
 }
 
+
 /* Add a constant OFFSET to a location expression.  */
 
 static void
@@ -4676,12 +1758,11 @@ loc_descr_plus_const (dw_loc_descr_ref *list_head, HOST_WIDE_INT offset)
 
   else
     {
-      loc->dw_loc_next = int_loc_descriptor (offset);
-      add_loc_descr (&loc->dw_loc_next, new_loc_descr (DW_OP_plus, 0, 0));
+      loc->dw_loc_next = int_loc_descriptor (-offset);
+      add_loc_descr (&loc->dw_loc_next, new_loc_descr (DW_OP_minus, 0, 0));
     }
 }
 
-#ifdef DWARF2_DEBUGGING_INFO
 /* Add a constant OFFSET to a location list.  */
 
 static void
@@ -4691,7 +1772,11 @@ loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset)
   for (d = list_head; d != NULL; d = d->dw_loc_next)
     loc_descr_plus_const (&d->expr, offset);
 }
-#endif
+
+#define DWARF_REF_SIZE \
+  (dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE)
+
+static unsigned long int get_base_type_offset (dw_die_ref);
 
 /* Return the size of a location descriptor.  */
 
@@ -4799,12 +1884,72 @@ 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;
+    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:
+      if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const)
+       size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+      else
+       {
+         unsigned long o
+           = get_base_type_offset (loc->dw_loc_oprnd1.v.val_die_ref.die);
+         size += size_of_uleb128 (o);
+       }
+      break;
+    case DW_OP_GNU_parameter_ref:
+      size += 4;
+      break;
     default:
       break;
     }
@@ -4814,7 +1959,7 @@ size_of_loc_descr (dw_loc_descr_ref loc)
 
 /* Return the size of a series of location descriptors.  */
 
-static unsigned long
+unsigned long
 size_of_locs (dw_loc_descr_ref loc)
 {
   dw_loc_descr_ref l;
@@ -4840,14 +1985,19 @@ size_of_locs (dw_loc_descr_ref loc)
   return size;
 }
 
-#ifdef DWARF2_DEBUGGING_INFO
 static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
-#endif
+static void get_ref_die_offset_label (char *, dw_die_ref);
+static unsigned long int get_ref_die_offset (dw_die_ref);
 
-/* 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;
@@ -4860,10 +2010,28 @@ output_loc_operands (dw_loc_descr_ref loc)
       dw2_asm_output_data (2, val1->v.val_int, NULL);
       break;
     case DW_OP_const4u:
+      if (loc->dtprel)
+       {
+         gcc_assert (targetm.asm_out.output_dwarf_dtprel);
+         targetm.asm_out.output_dwarf_dtprel (asm_out_file, 4,
+                                              val1->v.val_addr);
+         fputc ('\n', asm_out_file);
+         break;
+       }
+      /* FALLTHRU */
     case DW_OP_const4s:
       dw2_asm_output_data (4, val1->v.val_int, NULL);
       break;
     case DW_OP_const8u:
+      if (loc->dtprel)
+       {
+         gcc_assert (targetm.asm_out.output_dwarf_dtprel);
+         targetm.asm_out.output_dwarf_dtprel (asm_out_file, 8,
+                                              val1->v.val_addr);
+         fputc ('\n', asm_out_file);
+         break;
+       }
+      /* FALLTHRU */
     case DW_OP_const8s:
       gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
       dw2_asm_output_data (8, val1->v.val_int, NULL);
@@ -5000,14 +2168,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);
@@ -5044,25 +2226,166 @@ 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:
+      if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const)
+       dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+      else
+       {
+         unsigned long o = get_base_type_offset (val1->v.val_die_ref.die);
+         gcc_assert (o);
+         dw2_asm_output_data_uleb128 (o, NULL);
+       }
+      break;
+
+    case DW_OP_GNU_parameter_ref:
+      {
+       unsigned long o;
+       gcc_assert (val1->val_class == dw_val_class_die_ref);
+       o = get_ref_die_offset (val1->v.val_die_ref.die);
+       dw2_asm_output_data (4, 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)
+void
+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);
     }
 }
 
@@ -5123,9 +2446,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);
@@ -5176,10 +2508,26 @@ 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:
+    case DW_OP_GNU_parameter_ref:
+      gcc_unreachable ();
       break;
 
     default:
@@ -5188,13 +2536,29 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
     }
 }
 
-static void
+void
 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)
@@ -5205,61 +2569,11 @@ output_loc_sequence_raw (dw_loc_descr_ref loc)
     }
 }
 
-/* This routine will generate the correct assembly data for a location
-   description based on a cfi entry with a complex address.  */
-
-static void
-output_cfa_loc (dw_cfi_ref cfi)
-{
-  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);
-      loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
-    }
-  else
-    loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
-
-  /* Output the size of the block.  */
-  size = size_of_locs (loc);
-  dw2_asm_output_data_uleb128 (size, NULL);
-
-  /* Now output the operations themselves.  */
-  output_loc_sequence (loc);
-}
-
-/* Similar, but used for .cfi_escape.  */
-
-static void
-output_cfa_loc_raw (dw_cfi_ref cfi)
-{
-  dw_loc_descr_ref loc;
-  unsigned long size;
-
-  if (cfi->dw_cfi_opc == DW_CFA_expression)
-    {
-      fprintf (asm_out_file, "%#x,", cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
-      loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
-    }
-  else
-    loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
-
-  /* Output the size of the block.  */
-  size = size_of_locs (loc);
-  dw2_asm_output_data_uleb128_raw (size);
-  fputc (',', asm_out_file);
-
-  /* Now output the operations themselves.  */
-  output_loc_sequence_raw (loc);
-}
-
 /* This function builds a dwarf location descriptor sequence from a
    dw_cfa_location, adding the given OFFSET to the result of the
    expression.  */
 
-static struct dw_loc_descr_struct *
+struct dw_loc_descr_struct *
 build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset)
 {
   struct dw_loc_descr_struct *head, *tmp;
@@ -5288,15 +2602,16 @@ build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset)
    the address at OFFSET from the CFA when stack is aligned to
    ALIGNMENT byte.  */
 
-static struct dw_loc_descr_struct *
-build_cfa_aligned_loc (HOST_WIDE_INT offset, HOST_WIDE_INT alignment)
+struct dw_loc_descr_struct *
+build_cfa_aligned_loc (dw_cfa_location *cfa,
+                      HOST_WIDE_INT offset, HOST_WIDE_INT alignment)
 {
   struct dw_loc_descr_struct *head;
   unsigned int dwarf_fp
     = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM);
 
- /* When CFA is defined as FP+OFFSET, emulate stack alignment.  */
-  if (cfa.reg == HARD_FRAME_POINTER_REGNUM && cfa.indirect == 0)
 /* When CFA is defined as FP+OFFSET, emulate stack alignment.  */
+  if (cfa->reg == HARD_FRAME_POINTER_REGNUM && cfa->indirect == 0)
     {
       head = new_reg_loc_descr (dwarf_fp, 0);
       add_loc_descr (&head, int_loc_descriptor (alignment));
@@ -5307,117 +2622,8 @@ build_cfa_aligned_loc (HOST_WIDE_INT offset, HOST_WIDE_INT alignment)
     head = new_reg_loc_descr (dwarf_fp, offset);
   return head;
 }
-
-/* This function fills in aa dw_cfa_location structure from a dwarf location
-   descriptor sequence.  */
-
-static void
-get_cfa_from_loc_descr (dw_cfa_location *cfa, struct dw_loc_descr_struct *loc)
-{
-  struct dw_loc_descr_struct *ptr;
-  cfa->offset = 0;
-  cfa->base_offset = 0;
-  cfa->indirect = 0;
-  cfa->reg = -1;
-
-  for (ptr = loc; ptr != NULL; ptr = ptr->dw_loc_next)
-    {
-      enum dwarf_location_atom op = ptr->dw_loc_opc;
-
-      switch (op)
-       {
-       case DW_OP_reg0:
-       case DW_OP_reg1:
-       case DW_OP_reg2:
-       case DW_OP_reg3:
-       case DW_OP_reg4:
-       case DW_OP_reg5:
-       case DW_OP_reg6:
-       case DW_OP_reg7:
-       case DW_OP_reg8:
-       case DW_OP_reg9:
-       case DW_OP_reg10:
-       case DW_OP_reg11:
-       case DW_OP_reg12:
-       case DW_OP_reg13:
-       case DW_OP_reg14:
-       case DW_OP_reg15:
-       case DW_OP_reg16:
-       case DW_OP_reg17:
-       case DW_OP_reg18:
-       case DW_OP_reg19:
-       case DW_OP_reg20:
-       case DW_OP_reg21:
-       case DW_OP_reg22:
-       case DW_OP_reg23:
-       case DW_OP_reg24:
-       case DW_OP_reg25:
-       case DW_OP_reg26:
-       case DW_OP_reg27:
-       case DW_OP_reg28:
-       case DW_OP_reg29:
-       case DW_OP_reg30:
-       case DW_OP_reg31:
-         cfa->reg = op - DW_OP_reg0;
-         break;
-       case DW_OP_regx:
-         cfa->reg = ptr->dw_loc_oprnd1.v.val_int;
-         break;
-       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:
-         cfa->reg = op - DW_OP_breg0;
-         cfa->base_offset = ptr->dw_loc_oprnd1.v.val_int;
-         break;
-       case DW_OP_bregx:
-         cfa->reg = ptr->dw_loc_oprnd1.v.val_int;
-         cfa->base_offset = ptr->dw_loc_oprnd2.v.val_int;
-         break;
-       case DW_OP_deref:
-         cfa->indirect = 1;
-         break;
-       case DW_OP_plus_uconst:
-         cfa->offset = ptr->dw_loc_oprnd1.v.val_unsigned;
-         break;
-       default:
-         internal_error ("DW_LOC_OP %s not implemented",
-                         dwarf_stack_op_name (ptr->dw_loc_opc));
-       }
-    }
-}
-#endif /* .debug_frame support */
 \f
 /* And now, the support for symbolic debugging information.  */
-#ifdef DWARF2_DEBUGGING_INFO
 
 /* .debug_str support.  */
 static int output_indirect_string (void **, void *);
@@ -5440,10 +2646,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);
 
@@ -5463,7 +2665,13 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   dwarf2out_ignore_block,
   dwarf2out_source_line,
   dwarf2out_begin_prologue,
-  debug_nothing_int_charstar,  /* end_prologue */
+#if VMS_DEBUGGING_INFO
+  dwarf2out_vms_end_prologue,
+  dwarf2out_vms_begin_epilogue,
+#else
+  debug_nothing_int_charstar,
+  debug_nothing_int_charstar,
+#endif
   dwarf2out_end_epilogue,
   dwarf2out_begin_function,
   debug_nothing_int,           /* end_function */
@@ -5480,14 +2688,10 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   debug_nothing_int,           /* handle_pch */
   dwarf2out_var_location,
   dwarf2out_switch_text_section,
-  dwarf2out_direct_call,
-  dwarf2out_virtual_call_token,
-  dwarf2out_copy_call_info,
-  dwarf2out_virtual_call,
   dwarf2out_set_name,
-  1                             /* start_end_main_source_file */
+  1,                            /* start_end_main_source_file */
+  TYPE_SYMTAB_IS_DIE            /* tree_type_symtab_field */
 };
-#endif
 \f
 /* NOTE: In the comments in this file, many references are made to
    "Debugging Information Entries".  This term is abbreviated as `DIE'
@@ -5498,6 +2702,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.  */
 
@@ -5507,31 +2721,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.
@@ -5551,13 +2804,12 @@ DEF_VEC_ALLOC_O(dw_attr_node,gc);
    die_sib.  die_child points to the node *before* the "first" child node.  */
 
 typedef struct GTY((chain_circular ("%h.die_sib"))) die_struct {
-  enum dwarf_tag die_tag;
   union die_symbol_or_type_node
     {
       char * GTY ((tag ("0"))) die_symbol;
       comdat_type_node_ref GTY ((tag ("1"))) die_type_node;
     }
-  GTY ((desc ("dwarf_version >= 4"))) die_id;
+  GTY ((desc ("use_debug_types"))) die_id;
   VEC(dw_attr_node,gc) * die_attr;
   dw_die_ref die_parent;
   dw_die_ref die_child;
@@ -5569,6 +2821,7 @@ typedef struct GTY((chain_circular ("%h.die_sib"))) die_struct {
   /* Die is used and must not be pruned as unused.  */
   int die_perennial_p;
   unsigned int decl_id;
+  enum dwarf_tag die_tag;
 }
 die_node;
 
@@ -5598,6 +2851,18 @@ struct GTY(()) dw_ranges_struct {
   int num;
 };
 
+/* A structure to hold a macinfo entry.  */
+
+typedef struct GTY(()) macinfo_struct {
+  unsigned char 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;
@@ -5621,7 +2886,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;
@@ -5629,25 +2894,20 @@ typedef struct GTY(()) skeleton_chain_struct
 }
 skeleton_chain_node;
 
-/* How to start an assembler comment.  */
-#ifndef ASM_COMMENT_START
-#define ASM_COMMENT_START ";#"
-#endif
-
 /* Define a macro which returns nonzero for a TYPE_DECL which was
-   implicitly generated for a tagged type.
+   implicitly generated for a type.
 
-   Note that unlike the gcc front end (which generates a NULL named
-   TYPE_DECL node for each complete tagged type, each array type, and
-   each function type node created) the g++ front end generates a
-   _named_ TYPE_DECL node for each tagged type node created.
+   Note that, unlike the C front-end (which generates a NULL named
+   TYPE_DECL node for each complete tagged type, each array type,
+   and each function type node created) the C++ front-end generates
+   _named_ TYPE_DECL node for each tagged type node created.
    These TYPE_DECLs have DECL_ARTIFICIAL set, so we know not to
-   generate a DW_TAG_typedef DIE for them.  */
+   generate a DW_TAG_typedef DIE for them.  Likewise with the Ada
+   front-end, but for each type, tagged or not.  */
 
 #define TYPE_DECL_IS_STUB(decl)                                \
   (DECL_NAME (decl) == NULL_TREE                       \
    || (DECL_ARTIFICIAL (decl)                          \
-       && is_tagged_type (TREE_TYPE (decl))            \
        && ((decl == TYPE_STUB_DECL (TREE_TYPE (decl))) \
           /* This is necessary for stub decls that     \
              appear in nested inline functions.  */    \
@@ -5697,7 +2957,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)
@@ -5713,14 +2973,12 @@ skeleton_chain_node;
 #define DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN 1
 #endif
 
-#ifdef DWARF2_DEBUGGING_INFO
 /* This location is used by calc_die_sizes() to keep track
    the offset of each DIE within the .debug_info section.  */
 static unsigned long next_die_offset;
-#endif
 
 /* 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;
@@ -5778,15 +3036,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.  */
@@ -5803,31 +3102,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;
-
-/* Number of elements currently allocated for line_info_table.  */
-static GTY(()) unsigned line_info_table_allocated;
+/* A global counter for generating labels for line number data.  */
+static unsigned int line_info_label_num;
 
-/* Number of elements in line_info_table currently in use.  */
-static GTY(()) unsigned line_info_table_in_use;
+/* 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;
 
-/* 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 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;
 
-/* Number of elements currently allocated for separate_line_info_table.  */
-static GTY(()) unsigned separate_line_info_table_allocated;
+/* 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 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.  */
@@ -5837,18 +3129,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;
@@ -5882,49 +3165,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;
-
-#ifdef DWARF2_DEBUGGING_INFO
 /* Record whether the function being analyzed contains inlined functions.  */
 static int current_function_has_inlines;
-#endif
-#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;
@@ -5937,11 +3179,18 @@ static GTY(()) struct dwarf_file_data * file_table_last_lookup;
 
 static GTY(()) VEC(die_arg_entry,gc) *tmpl_value_parm_die_table;
 
-#ifdef DWARF2_DEBUGGING_INFO
+/* 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 bool frame_pointer_fb_offset_valid;
+
+static VEC (dw_die_ref, heap) *base_types;
 
 /* Forward declarations for functions defined in this file.  */
 
@@ -6007,6 +3256,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 *);
@@ -6020,7 +3271,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 *);
@@ -6074,6 +3324,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);
@@ -6092,13 +3343,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);
@@ -6119,8 +3370,6 @@ static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT,
                                         enum var_init_status);
 static int is_based_loc (const_rtx);
 static int resolve_one_addr (rtx *, void *);
-static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode,
-                                           enum var_init_status);
 static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
                                               enum var_init_status);
 static dw_loc_descr_ref loc_descriptor (rtx, enum machine_mode mode,
@@ -6141,11 +3390,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);
@@ -6198,10 +3448,11 @@ 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);
-static void gen_decl_die (tree, tree, dw_die_ref);
+static dw_die_ref gen_decl_die (tree, tree, dw_die_ref);
 static dw_die_ref force_decl_die (tree);
 static dw_die_ref force_type_die (tree);
 static dw_die_ref setup_namespace_context (tree, dw_die_ref);
@@ -6210,6 +3461,8 @@ static struct dwarf_file_data * lookup_filename (const char *);
 static void retry_incomplete_types (void);
 static void gen_type_die_for_member (tree, tree, dw_die_ref);
 static void gen_generic_params_dies (tree);
+static void gen_tagged_type_die (tree, dw_die_ref, enum debug_info_usage);
+static void gen_type_die_with_usage (tree, dw_die_ref, enum debug_info_usage);
 static void splice_child_die (dw_die_ref, dw_die_ref);
 static int file_info_cmp (const void *, const void *);
 static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
@@ -6218,14 +3471,22 @@ 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);
 static void prune_unused_types_prune (dw_die_ref);
 static void prune_unused_types (void);
 static int maybe_emit_file (struct dwarf_file_data *fd);
+static inline const char *AT_vms_delta1 (dw_attr_ref);
+static inline const char *AT_vms_delta2 (dw_attr_ref);
+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
@@ -6240,6 +3501,9 @@ static void gen_remaining_tmpl_value_param_die_attribute (void);
 #ifndef DEBUG_MACINFO_SECTION
 #define DEBUG_MACINFO_SECTION  ".debug_macinfo"
 #endif
+#ifndef DEBUG_MACRO_SECTION
+#define DEBUG_MACRO_SECTION    ".debug_macro"
+#endif
 #ifndef DEBUG_LINE_SECTION
 #define DEBUG_LINE_SECTION     ".debug_line"
 #endif
@@ -6252,12 +3516,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
@@ -6303,11 +3561,9 @@ static void gen_remaining_tmpl_value_param_die_attribute (void);
 #ifndef DEBUG_MACINFO_SECTION_LABEL
 #define DEBUG_MACINFO_SECTION_LABEL     "Ldebug_macinfo"
 #endif
-
-/* Mangled name attribute to use.  This used to be a vendor extension
-   until DWARF 4 standardized it.  */
-#define AT_linkage_name \
-  (dwarf_version >= 4 ? DW_AT_linkage_name : DW_AT_MIPS_linkage_name)
+#ifndef DEBUG_MACRO_SECTION_LABEL
+#define DEBUG_MACRO_SECTION_LABEL      "Ldebug_macro"
+#endif
 
 
 /* Definitions of defaults for formats and names of various special
@@ -6342,11 +3598,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
+\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.  */
 
@@ -6399,6 +3661,38 @@ 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;
+}
+
+/* Return die_offset of a DIE reference other than base type.  */
+
+static unsigned long int
+get_ref_die_offset (dw_die_ref ref)
+{
+  gcc_assert (ref->die_offset);
+  return ref->die_offset;
+}
+
 /* Convert a DIE tag into its string name.  */
 
 static const char *
@@ -6546,6 +3840,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>";
     }
@@ -6709,6 +4007,8 @@ dwarf_attr_name (unsigned int attr)
       return "DW_AT_call_file";
     case DW_AT_call_line:
       return "DW_AT_call_line";
+    case DW_AT_object_pointer:
+      return "DW_AT_object_pointer";
 
     case DW_AT_signature:
       return "DW_AT_signature";
@@ -6731,14 +4031,24 @@ dwarf_attr_name (unsigned int attr)
       return "DW_AT_MIPS_tail_loop_begin";
     case DW_AT_MIPS_epilog_begin:
       return "DW_AT_MIPS_epilog_begin";
+#if VMS_DEBUGGING_INFO
+    case DW_AT_HP_prologue:
+      return "DW_AT_HP_prologue";
+#else
     case DW_AT_MIPS_loop_unroll_factor:
       return "DW_AT_MIPS_loop_unroll_factor";
+#endif
     case DW_AT_MIPS_software_pipeline_depth:
       return "DW_AT_MIPS_software_pipeline_depth";
     case DW_AT_MIPS_linkage_name:
       return "DW_AT_MIPS_linkage_name";
+#if VMS_DEBUGGING_INFO
+    case DW_AT_HP_epilogue:
+      return "DW_AT_HP_epilogue";
+#else
     case DW_AT_MIPS_stride:
       return "DW_AT_MIPS_stride";
+#endif
     case DW_AT_MIPS_abstract_name:
       return "DW_AT_MIPS_abstract_name";
     case DW_AT_MIPS_clone_origin:
@@ -6758,6 +4068,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:
@@ -6778,7542 +4089,9777 @@ 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_GNU_macros:
+      return "DW_AT_GNU_macros";
+
+    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";
+
+    default:
+      return "DW_AT_<unknown>";
+    }
+}
+
+/* Convert a DWARF value form code into its string name.  */
+
+static const char *
+dwarf_form_name (unsigned int form)
+{
+  switch (form)
+    {
+    case DW_FORM_addr:
+      return "DW_FORM_addr";
+    case DW_FORM_block2:
+      return "DW_FORM_block2";
+    case DW_FORM_block4:
+      return "DW_FORM_block4";
+    case DW_FORM_data2:
+      return "DW_FORM_data2";
+    case DW_FORM_data4:
+      return "DW_FORM_data4";
+    case DW_FORM_data8:
+      return "DW_FORM_data8";
+    case DW_FORM_string:
+      return "DW_FORM_string";
+    case DW_FORM_block:
+      return "DW_FORM_block";
+    case DW_FORM_block1:
+      return "DW_FORM_block1";
+    case DW_FORM_data1:
+      return "DW_FORM_data1";
+    case DW_FORM_flag:
+      return "DW_FORM_flag";
+    case DW_FORM_sdata:
+      return "DW_FORM_sdata";
+    case DW_FORM_strp:
+      return "DW_FORM_strp";
+    case DW_FORM_udata:
+      return "DW_FORM_udata";
+    case DW_FORM_ref_addr:
+      return "DW_FORM_ref_addr";
+    case DW_FORM_ref1:
+      return "DW_FORM_ref1";
+    case DW_FORM_ref2:
+      return "DW_FORM_ref2";
+    case DW_FORM_ref4:
+      return "DW_FORM_ref4";
+    case DW_FORM_ref8:
+      return "DW_FORM_ref8";
+    case DW_FORM_ref_udata:
+      return "DW_FORM_ref_udata";
+    case DW_FORM_indirect:
+      return "DW_FORM_indirect";
+    case DW_FORM_sec_offset:
+      return "DW_FORM_sec_offset";
+    case DW_FORM_exprloc:
+      return "DW_FORM_exprloc";
+    case DW_FORM_flag_present:
+      return "DW_FORM_flag_present";
+    case DW_FORM_ref_sig8:
+      return "DW_FORM_ref_sig8";
+    default:
+      return "DW_FORM_<unknown>";
+    }
+}
+\f
+/* Determine the "ultimate origin" of a decl.  The decl may be an inlined
+   instance of an inlined instance of a decl which is local to an inline
+   function, so we have to trace all of the way back through the origin chain
+   to find out what sort of node actually served as the original seed for the
+   given block.  */
+
+static tree
+decl_ultimate_origin (const_tree decl)
+{
+  if (!CODE_CONTAINS_STRUCT (TREE_CODE (decl), TS_DECL_COMMON))
+    return NULL_TREE;
+
+  /* output_inline_function sets DECL_ABSTRACT_ORIGIN for all the
+     nodes in the function to point to themselves; ignore that if
+     we're trying to output the abstract instance of this function.  */
+  if (DECL_ABSTRACT (decl) && DECL_ABSTRACT_ORIGIN (decl) == decl)
+    return NULL_TREE;
+
+  /* Since the DECL_ABSTRACT_ORIGIN for a DECL is supposed to be the
+     most distant ancestor, this should never happen.  */
+  gcc_assert (!DECL_FROM_INLINE (DECL_ORIGIN (decl)));
+
+  return DECL_ABSTRACT_ORIGIN (decl);
+}
+
+/* Get the class to which DECL belongs, if any.  In g++, the DECL_CONTEXT
+   of a virtual function may refer to a base class, so we check the 'this'
+   parameter.  */
+
+static tree
+decl_class_context (tree decl)
+{
+  tree context = NULL_TREE;
+
+  if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl))
+    context = DECL_CONTEXT (decl);
+  else
+    context = TYPE_MAIN_VARIANT
+      (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
+
+  if (context && !TYPE_P (context))
+    context = NULL_TREE;
+
+  return context;
+}
+\f
+/* Add an attribute/value pair to a DIE.  */
+
+static inline void
+add_dwarf_attr (dw_die_ref die, dw_attr_ref attr)
+{
+  /* Maybe this should be an assert?  */
+  if (die == NULL)
+    return;
+
+  if (die->die_attr == NULL)
+    die->die_attr = VEC_alloc (dw_attr_node, gc, 1);
+  VEC_safe_push (dw_attr_node, gc, die->die_attr, attr);
+}
+
+static inline enum dw_val_class
+AT_class (dw_attr_ref a)
+{
+  return a->dw_attr_val.val_class;
+}
+
+/* Add a flag value attribute to a DIE.  */
+
+static inline void
+add_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int flag)
+{
+  dw_attr_node attr;
+
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_flag;
+  attr.dw_attr_val.v.val_flag = flag;
+  add_dwarf_attr (die, &attr);
+}
+
+static inline unsigned
+AT_flag (dw_attr_ref a)
+{
+  gcc_assert (a && AT_class (a) == dw_val_class_flag);
+  return a->dw_attr_val.v.val_flag;
+}
+
+/* Add a signed integer attribute value to a DIE.  */
+
+static inline void
+add_AT_int (dw_die_ref die, enum dwarf_attribute attr_kind, HOST_WIDE_INT int_val)
+{
+  dw_attr_node attr;
+
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_const;
+  attr.dw_attr_val.v.val_int = int_val;
+  add_dwarf_attr (die, &attr);
+}
+
+static inline HOST_WIDE_INT
+AT_int (dw_attr_ref a)
+{
+  gcc_assert (a && AT_class (a) == dw_val_class_const);
+  return a->dw_attr_val.v.val_int;
+}
+
+/* Add an unsigned integer attribute value to a DIE.  */
+
+static inline void
+add_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind,
+                unsigned HOST_WIDE_INT unsigned_val)
+{
+  dw_attr_node attr;
+
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
+  attr.dw_attr_val.v.val_unsigned = unsigned_val;
+  add_dwarf_attr (die, &attr);
+}
+
+static inline unsigned HOST_WIDE_INT
+AT_unsigned (dw_attr_ref a)
+{
+  gcc_assert (a && AT_class (a) == dw_val_class_unsigned_const);
+  return a->dw_attr_val.v.val_unsigned;
+}
+
+/* Add an unsigned double integer attribute value to a DIE.  */
+
+static inline void
+add_AT_double (dw_die_ref die, enum dwarf_attribute attr_kind,
+              HOST_WIDE_INT high, unsigned HOST_WIDE_INT low)
+{
+  dw_attr_node attr;
+
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_const_double;
+  attr.dw_attr_val.v.val_double.high = high;
+  attr.dw_attr_val.v.val_double.low = low;
+  add_dwarf_attr (die, &attr);
+}
+
+/* Add a floating point attribute value to a DIE and return it.  */
+
+static inline void
+add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind,
+           unsigned int length, unsigned int elt_size, unsigned char *array)
+{
+  dw_attr_node attr;
+
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_vec;
+  attr.dw_attr_val.v.val_vec.length = length;
+  attr.dw_attr_val.v.val_vec.elt_size = elt_size;
+  attr.dw_attr_val.v.val_vec.array = array;
+  add_dwarf_attr (die, &attr);
+}
+
+/* Add an 8-byte data attribute value to a DIE.  */
+
+static inline void
+add_AT_data8 (dw_die_ref die, enum dwarf_attribute attr_kind,
+              unsigned char data8[8])
+{
+  dw_attr_node attr;
 
-    case DW_AT_VMS_rtnbeg_pd_address:
-      return "DW_AT_VMS_rtnbeg_pd_address";
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_data8;
+  memcpy (attr.dw_attr_val.v.val_data8, data8, 8);
+  add_dwarf_attr (die, &attr);
+}
 
-    default:
-      return "DW_AT_<unknown>";
-    }
+/* Hash and equality functions for debug_str_hash.  */
+
+static hashval_t
+debug_str_do_hash (const void *x)
+{
+  return htab_hash_string (((const struct indirect_string_node *)x)->str);
 }
 
-/* Convert a DWARF value form code into its string name.  */
+static int
+debug_str_eq (const void *x1, const void *x2)
+{
+  return strcmp ((((const struct indirect_string_node *)x1)->str),
+                (const char *)x2) == 0;
+}
 
-static const char *
-dwarf_form_name (unsigned int form)
+/* Add STR to the indirect string hash table.  */
+
+static struct indirect_string_node *
+find_AT_string (const char *str)
 {
-  switch (form)
+  struct indirect_string_node *node;
+  void **slot;
+
+  if (! debug_str_hash)
+    debug_str_hash = htab_create_ggc (10, debug_str_do_hash,
+                                     debug_str_eq, NULL);
+
+  slot = htab_find_slot_with_hash (debug_str_hash, str,
+                                  htab_hash_string (str), INSERT);
+  if (*slot == NULL)
     {
-    case DW_FORM_addr:
-      return "DW_FORM_addr";
-    case DW_FORM_block2:
-      return "DW_FORM_block2";
-    case DW_FORM_block4:
-      return "DW_FORM_block4";
-    case DW_FORM_data2:
-      return "DW_FORM_data2";
-    case DW_FORM_data4:
-      return "DW_FORM_data4";
-    case DW_FORM_data8:
-      return "DW_FORM_data8";
-    case DW_FORM_string:
-      return "DW_FORM_string";
-    case DW_FORM_block:
-      return "DW_FORM_block";
-    case DW_FORM_block1:
-      return "DW_FORM_block1";
-    case DW_FORM_data1:
-      return "DW_FORM_data1";
-    case DW_FORM_flag:
-      return "DW_FORM_flag";
-    case DW_FORM_sdata:
-      return "DW_FORM_sdata";
-    case DW_FORM_strp:
-      return "DW_FORM_strp";
-    case DW_FORM_udata:
-      return "DW_FORM_udata";
-    case DW_FORM_ref_addr:
-      return "DW_FORM_ref_addr";
-    case DW_FORM_ref1:
-      return "DW_FORM_ref1";
-    case DW_FORM_ref2:
-      return "DW_FORM_ref2";
-    case DW_FORM_ref4:
-      return "DW_FORM_ref4";
-    case DW_FORM_ref8:
-      return "DW_FORM_ref8";
-    case DW_FORM_ref_udata:
-      return "DW_FORM_ref_udata";
-    case DW_FORM_indirect:
-      return "DW_FORM_indirect";
-    case DW_FORM_sec_offset:
-      return "DW_FORM_sec_offset";
-    case DW_FORM_exprloc:
-      return "DW_FORM_exprloc";
-    case DW_FORM_flag_present:
-      return "DW_FORM_flag_present";
-    case DW_FORM_ref_sig8:
-      return "DW_FORM_ref_sig8";
-    default:
-      return "DW_FORM_<unknown>";
+      node = ggc_alloc_cleared_indirect_string_node ();
+      node->str = ggc_strdup (str);
+      *slot = node;
     }
+  else
+    node = (struct indirect_string_node *) *slot;
+
+  node->refcount++;
+  return node;
 }
-\f
-/* Determine the "ultimate origin" of a decl.  The decl may be an inlined
-   instance of an inlined instance of a decl which is local to an inline
-   function, so we have to trace all of the way back through the origin chain
-   to find out what sort of node actually served as the original seed for the
-   given block.  */
 
-static tree
-decl_ultimate_origin (const_tree decl)
+/* Add a string attribute value to a DIE.  */
+
+static inline void
+add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str)
 {
-  if (!CODE_CONTAINS_STRUCT (TREE_CODE (decl), TS_DECL_COMMON))
-    return NULL_TREE;
+  dw_attr_node attr;
+  struct indirect_string_node *node;
 
-  /* output_inline_function sets DECL_ABSTRACT_ORIGIN for all the
-     nodes in the function to point to themselves; ignore that if
-     we're trying to output the abstract instance of this function.  */
-  if (DECL_ABSTRACT (decl) && DECL_ABSTRACT_ORIGIN (decl) == decl)
-    return NULL_TREE;
+  node = find_AT_string (str);
 
-  /* Since the DECL_ABSTRACT_ORIGIN for a DECL is supposed to be the
-     most distant ancestor, this should never happen.  */
-  gcc_assert (!DECL_FROM_INLINE (DECL_ORIGIN (decl)));
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_str;
+  attr.dw_attr_val.v.val_str = node;
+  add_dwarf_attr (die, &attr);
+}
 
-  return DECL_ABSTRACT_ORIGIN (decl);
+static inline const char *
+AT_string (dw_attr_ref a)
+{
+  gcc_assert (a && AT_class (a) == dw_val_class_str);
+  return a->dw_attr_val.v.val_str->str;
 }
 
-/* Get the class to which DECL belongs, if any.  In g++, the DECL_CONTEXT
-   of a virtual function may refer to a base class, so we check the 'this'
-   parameter.  */
+/* Find out whether a string should be output inline in DIE
+   or out-of-line in .debug_str section.  */
 
-static tree
-decl_class_context (tree decl)
+static enum dwarf_form
+AT_string_form (dw_attr_ref a)
 {
-  tree context = NULL_TREE;
+  struct indirect_string_node *node;
+  unsigned int len;
+  char label[32];
 
-  if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl))
-    context = DECL_CONTEXT (decl);
-  else
-    context = TYPE_MAIN_VARIANT
-      (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
+  gcc_assert (a && AT_class (a) == dw_val_class_str);
 
-  if (context && !TYPE_P (context))
-    context = NULL_TREE;
+  node = a->dw_attr_val.v.val_str;
+  if (node->form)
+    return node->form;
 
-  return context;
+  len = strlen (node->str) + 1;
+
+  /* If the string is shorter or equal to the size of the reference, it is
+     always better to put it inline.  */
+  if (len <= DWARF_OFFSET_SIZE || node->refcount == 0)
+    return node->form = DW_FORM_string;
+
+  /* If we cannot expect the linker to merge strings in .debug_str
+     section, only put it into .debug_str if it is worth even in this
+     single module.  */
+  if (DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
+      || ((debug_str_section->common.flags & SECTION_MERGE) == 0
+      && (len - DWARF_OFFSET_SIZE) * node->refcount <= len))
+    return node->form = DW_FORM_string;
+
+  ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+  ++dw2_string_counter;
+  node->label = xstrdup (label);
+
+  return node->form = DW_FORM_strp;
 }
-\f
-/* Add an attribute/value pair to a DIE.  */
+
+/* Add a DIE reference attribute value to a DIE.  */
 
 static inline void
-add_dwarf_attr (dw_die_ref die, dw_attr_ref attr)
+add_AT_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind, dw_die_ref targ_die)
 {
-  /* Maybe this should be an assert?  */
-  if (die == NULL)
+  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
 
-  if (die->die_attr == NULL)
-    die->die_attr = VEC_alloc (dw_attr_node, gc, 1);
-  VEC_safe_push (dw_attr_node, gc, die->die_attr, attr);
+  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;
+  attr.dw_attr_val.v.val_die_ref.external = 0;
+  add_dwarf_attr (die, &attr);
+}
+
+/* Add an AT_specification attribute to a DIE, and also make the back
+   pointer from the specification to the definition.  */
+
+static inline void
+add_AT_specification (dw_die_ref die, dw_die_ref targ_die)
+{
+  add_AT_die_ref (die, DW_AT_specification, targ_die);
+  gcc_assert (!targ_die->die_definition);
+  targ_die->die_definition = die;
+}
+
+static inline dw_die_ref
+AT_ref (dw_attr_ref a)
+{
+  gcc_assert (a && AT_class (a) == dw_val_class_die_ref);
+  return a->dw_attr_val.v.val_die_ref.die;
+}
+
+static inline int
+AT_ref_external (dw_attr_ref a)
+{
+  if (a && AT_class (a) == dw_val_class_die_ref)
+    return a->dw_attr_val.v.val_die_ref.external;
+
+  return 0;
+}
+
+static inline void
+set_AT_ref_external (dw_attr_ref a, int i)
+{
+  gcc_assert (a && AT_class (a) == dw_val_class_die_ref);
+  a->dw_attr_val.v.val_die_ref.external = i;
+}
+
+/* Add an FDE reference attribute value to a DIE.  */
+
+static inline void
+add_AT_fde_ref (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int targ_fde)
+{
+  dw_attr_node attr;
+
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_fde_ref;
+  attr.dw_attr_val.v.val_fde_index = targ_fde;
+  add_dwarf_attr (die, &attr);
+}
+
+/* Add a location description attribute value to a DIE.  */
+
+static inline void
+add_AT_loc (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_descr_ref loc)
+{
+  dw_attr_node attr;
+
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_loc;
+  attr.dw_attr_val.v.val_loc = loc;
+  add_dwarf_attr (die, &attr);
 }
 
-static inline enum dw_val_class
-AT_class (dw_attr_ref a)
+static inline dw_loc_descr_ref
+AT_loc (dw_attr_ref a)
 {
-  return a->dw_attr_val.val_class;
+  gcc_assert (a && AT_class (a) == dw_val_class_loc);
+  return a->dw_attr_val.v.val_loc;
 }
 
-/* Add a flag value attribute to a DIE.  */
-
 static inline void
-add_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int flag)
+add_AT_loc_list (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_list_ref loc_list)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_flag;
-  attr.dw_attr_val.v.val_flag = flag;
+  attr.dw_attr_val.val_class = dw_val_class_loc_list;
+  attr.dw_attr_val.v.val_loc_list = loc_list;
   add_dwarf_attr (die, &attr);
+  have_location_lists = true;
 }
 
-static inline unsigned
-AT_flag (dw_attr_ref a)
+static inline dw_loc_list_ref
+AT_loc_list (dw_attr_ref a)
 {
-  gcc_assert (a && AT_class (a) == dw_val_class_flag);
-  return a->dw_attr_val.v.val_flag;
+  gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
+  return a->dw_attr_val.v.val_loc_list;
 }
 
-/* Add a signed integer attribute value to a DIE.  */
+static inline dw_loc_list_ref *
+AT_loc_list_ptr (dw_attr_ref a)
+{
+  gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
+  return &a->dw_attr_val.v.val_loc_list;
+}
+
+/* Add an address constant attribute value to a DIE.  */
 
 static inline void
-add_AT_int (dw_die_ref die, enum dwarf_attribute attr_kind, HOST_WIDE_INT int_val)
+add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_const;
-  attr.dw_attr_val.v.val_int = int_val;
+  attr.dw_attr_val.val_class = dw_val_class_addr;
+  attr.dw_attr_val.v.val_addr = addr;
   add_dwarf_attr (die, &attr);
 }
 
-static inline HOST_WIDE_INT
-AT_int (dw_attr_ref a)
+/* Get the RTX from to an address DIE attribute.  */
+
+static inline rtx
+AT_addr (dw_attr_ref a)
 {
-  gcc_assert (a && AT_class (a) == dw_val_class_const);
-  return a->dw_attr_val.v.val_int;
+  gcc_assert (a && AT_class (a) == dw_val_class_addr);
+  return a->dw_attr_val.v.val_addr;
 }
 
-/* Add an unsigned integer attribute value to a DIE.  */
+/* Add a file attribute value to a DIE.  */
 
 static inline void
-add_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind,
-                unsigned HOST_WIDE_INT unsigned_val)
+add_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind,
+            struct dwarf_file_data *fd)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
-  attr.dw_attr_val.v.val_unsigned = unsigned_val;
+  attr.dw_attr_val.val_class = dw_val_class_file;
+  attr.dw_attr_val.v.val_file = fd;
   add_dwarf_attr (die, &attr);
 }
 
-static inline unsigned HOST_WIDE_INT
-AT_unsigned (dw_attr_ref a)
+/* Get the dwarf_file_data from a file DIE attribute.  */
+
+static inline struct dwarf_file_data *
+AT_file (dw_attr_ref a)
 {
-  gcc_assert (a && AT_class (a) == dw_val_class_unsigned_const);
-  return a->dw_attr_val.v.val_unsigned;
+  gcc_assert (a && AT_class (a) == dw_val_class_file);
+  return a->dw_attr_val.v.val_file;
 }
 
-/* Add an unsigned double integer attribute value to a DIE.  */
+/* Add a vms delta attribute value to a DIE.  */
 
 static inline void
-add_AT_double (dw_die_ref die, enum dwarf_attribute attr_kind,
-              HOST_WIDE_INT high, unsigned HOST_WIDE_INT low)
+add_AT_vms_delta (dw_die_ref die, enum dwarf_attribute attr_kind,
+                 const char *lbl1, const char *lbl2)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_const_double;
-  attr.dw_attr_val.v.val_double.high = high;
-  attr.dw_attr_val.v.val_double.low = low;
+  attr.dw_attr_val.val_class = dw_val_class_vms_delta;
+  attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1);
+  attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2);
   add_dwarf_attr (die, &attr);
 }
 
-/* Add a floating point attribute value to a DIE and return it.  */
+/* Add a label identifier attribute value to a DIE.  */
 
 static inline void
-add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind,
-           unsigned int length, unsigned int elt_size, unsigned char *array)
+add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_vec;
-  attr.dw_attr_val.v.val_vec.length = length;
-  attr.dw_attr_val.v.val_vec.elt_size = elt_size;
-  attr.dw_attr_val.v.val_vec.array = array;
+  attr.dw_attr_val.val_class = dw_val_class_lbl_id;
+  attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
   add_dwarf_attr (die, &attr);
 }
 
-/* Add an 8-byte data attribute value to a DIE.  */
+/* Add a section offset attribute value to a DIE, an offset into the
+   debug_line section.  */
 
 static inline void
-add_AT_data8 (dw_die_ref die, enum dwarf_attribute attr_kind,
-              unsigned char data8[8])
+add_AT_lineptr (dw_die_ref die, enum dwarf_attribute attr_kind,
+               const char *label)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_data8;
-  memcpy (attr.dw_attr_val.v.val_data8, data8, 8);
+  attr.dw_attr_val.val_class = dw_val_class_lineptr;
+  attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
   add_dwarf_attr (die, &attr);
 }
 
-/* Hash and equality functions for debug_str_hash.  */
+/* Add a section offset attribute value to a DIE, an offset into the
+   debug_macinfo section.  */
 
-static hashval_t
-debug_str_do_hash (const void *x)
+static inline void
+add_AT_macptr (dw_die_ref die, enum dwarf_attribute attr_kind,
+              const char *label)
 {
-  return htab_hash_string (((const struct indirect_string_node *)x)->str);
-}
+  dw_attr_node attr;
 
-static int
-debug_str_eq (const void *x1, const void *x2)
-{
-  return strcmp ((((const struct indirect_string_node *)x1)->str),
-                (const char *)x2) == 0;
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_macptr;
+  attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
+  add_dwarf_attr (die, &attr);
 }
 
-/* Add STR to the indirect string hash table.  */
+/* Add an offset attribute value to a DIE.  */
 
-static struct indirect_string_node *
-find_AT_string (const char *str)
+static inline void
+add_AT_offset (dw_die_ref die, enum dwarf_attribute attr_kind,
+              unsigned HOST_WIDE_INT offset)
 {
-  struct indirect_string_node *node;
-  void **slot;
-
-  if (! debug_str_hash)
-    debug_str_hash = htab_create_ggc (10, debug_str_do_hash,
-                                     debug_str_eq, NULL);
-
-  slot = htab_find_slot_with_hash (debug_str_hash, str,
-                                  htab_hash_string (str), INSERT);
-  if (*slot == NULL)
-    {
-      node = (struct indirect_string_node *)
-              ggc_alloc_cleared (sizeof (struct indirect_string_node));
-      node->str = ggc_strdup (str);
-      *slot = node;
-    }
-  else
-    node = (struct indirect_string_node *) *slot;
+  dw_attr_node attr;
 
-  node->refcount++;
-  return node;
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_offset;
+  attr.dw_attr_val.v.val_offset = offset;
+  add_dwarf_attr (die, &attr);
 }
 
-/* Add a string attribute value to a DIE.  */
+/* Add an range_list attribute value to a DIE.  */
 
-static inline void
-add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str)
+static void
+add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
+                  long unsigned int offset)
 {
   dw_attr_node attr;
-  struct indirect_string_node *node;
-
-  node = find_AT_string (str);
 
   attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_str;
-  attr.dw_attr_val.v.val_str = node;
+  attr.dw_attr_val.val_class = dw_val_class_range_list;
+  attr.dw_attr_val.v.val_offset = offset;
   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.  */
+/* Return the start label of a delta attribute.  */
 
-static inline void
-gen_label_for_indirect_string (struct indirect_string_node *node)
+static inline const char *
+AT_vms_delta1 (dw_attr_ref a)
 {
-  char label[32];
+  gcc_assert (a && (AT_class (a) == dw_val_class_vms_delta));
+  return a->dw_attr_val.v.val_vms_delta.lbl1;
+}
 
-  if (node->label)
-    return;
+/* Return the end label of a delta attribute.  */
 
-  ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
-  ++dw2_string_counter;
-  node->label = xstrdup (label);
+static inline const char *
+AT_vms_delta2 (dw_attr_ref a)
+{
+  gcc_assert (a && (AT_class (a) == dw_val_class_vms_delta));
+  return a->dw_attr_val.v.val_vms_delta.lbl2;
+}
+
+static inline const char *
+AT_lbl (dw_attr_ref a)
+{
+  gcc_assert (a && (AT_class (a) == dw_val_class_lbl_id
+                   || AT_class (a) == dw_val_class_lineptr
+                   || AT_class (a) == dw_val_class_macptr));
+  return a->dw_attr_val.v.val_lbl_id;
 }
 
-/* Create a SYMBOL_REF rtx whose value is the initial address of a
-   debug string STR.  */
+/* Get the attribute of type attr_kind.  */
 
-static inline rtx
-get_debug_string_label (const char *str)
+static dw_attr_ref
+get_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
 {
-  struct indirect_string_node *node = find_AT_string (str);
+  dw_attr_ref a;
+  unsigned ix;
+  dw_die_ref spec = NULL;
 
-  debug_str_hash_forced = true;
+  if (! die)
+    return NULL;
 
-  gen_label_for_indirect_string (node);
+  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
+            || a->dw_attr == DW_AT_abstract_origin)
+      spec = AT_ref (a);
 
-  return gen_rtx_SYMBOL_REF (Pmode, node->label);
-}
+  if (spec)
+    return get_AT (spec, attr_kind);
 
-static inline const char *
-AT_string (dw_attr_ref a)
-{
-  gcc_assert (a && AT_class (a) == dw_val_class_str);
-  return a->dw_attr_val.v.val_str->str;
+  return NULL;
 }
 
-/* Find out whether a string should be output inline in DIE
-   or out-of-line in .debug_str section.  */
+/* Return the "low pc" attribute value, typically associated with a subprogram
+   DIE.  Return null if the "low pc" attribute is either not present, or if it
+   cannot be represented as an assembler label identifier.  */
 
-static enum dwarf_form
-AT_string_form (dw_attr_ref a)
+static inline const char *
+get_AT_low_pc (dw_die_ref die)
 {
-  struct indirect_string_node *node;
-  unsigned int len;
+  dw_attr_ref a = get_AT (die, DW_AT_low_pc);
 
-  gcc_assert (a && AT_class (a) == dw_val_class_str);
+  return a ? AT_lbl (a) : NULL;
+}
 
-  node = a->dw_attr_val.v.val_str;
-  if (node->form)
-    return node->form;
+/* Return the "high pc" attribute value, typically associated with a subprogram
+   DIE.  Return null if the "high pc" attribute is either not present, or if it
+   cannot be represented as an assembler label identifier.  */
 
-  len = strlen (node->str) + 1;
+static inline const char *
+get_AT_hi_pc (dw_die_ref die)
+{
+  dw_attr_ref a = get_AT (die, DW_AT_high_pc);
 
-  /* If the string is shorter or equal to the size of the reference, it is
-     always better to put it inline.  */
-  if (len <= DWARF_OFFSET_SIZE || node->refcount == 0)
-    return node->form = DW_FORM_string;
+  return a ? AT_lbl (a) : NULL;
+}
 
-  /* If we cannot expect the linker to merge strings in .debug_str
-     section, only put it into .debug_str if it is worth even in this
-     single module.  */
-  if (DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
-      || ((debug_str_section->common.flags & SECTION_MERGE) == 0
-      && (len - DWARF_OFFSET_SIZE) * node->refcount <= len))
-    return node->form = DW_FORM_string;
+/* Return the value of the string attribute designated by ATTR_KIND, or
+   NULL if it is not present.  */
 
-  gen_label_for_indirect_string (node);
+static inline const char *
+get_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+  dw_attr_ref a = get_AT (die, attr_kind);
 
-  return node->form = DW_FORM_strp;
+  return a ? AT_string (a) : NULL;
 }
 
-/* Add a DIE reference attribute value to a DIE.  */
+/* Return the value of the flag attribute designated by ATTR_KIND, or -1
+   if it is not present.  */
 
-static inline void
-add_AT_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind, dw_die_ref targ_die)
+static inline int
+get_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind)
 {
-  dw_attr_node attr;
+  dw_attr_ref a = get_AT (die, attr_kind);
 
-  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;
-  attr.dw_attr_val.v.val_die_ref.external = 0;
-  add_dwarf_attr (die, &attr);
+  return a ? AT_flag (a) : 0;
 }
 
-/* Add an AT_specification attribute to a DIE, and also make the back
-   pointer from the specification to the definition.  */
+/* Return the value of the unsigned attribute designated by ATTR_KIND, or 0
+   if it is not present.  */
 
-static inline void
-add_AT_specification (dw_die_ref die, dw_die_ref targ_die)
+static inline unsigned
+get_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind)
 {
-  add_AT_die_ref (die, DW_AT_specification, targ_die);
-  gcc_assert (!targ_die->die_definition);
-  targ_die->die_definition = die;
+  dw_attr_ref a = get_AT (die, attr_kind);
+
+  return a ? AT_unsigned (a) : 0;
 }
 
 static inline dw_die_ref
-AT_ref (dw_attr_ref a)
+get_AT_ref (dw_die_ref die, enum dwarf_attribute attr_kind)
 {
-  gcc_assert (a && AT_class (a) == dw_val_class_die_ref);
-  return a->dw_attr_val.v.val_die_ref.die;
+  dw_attr_ref a = get_AT (die, attr_kind);
+
+  return a ? AT_ref (a) : NULL;
 }
 
-static inline int
-AT_ref_external (dw_attr_ref a)
+static inline struct dwarf_file_data *
+get_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind)
 {
-  if (a && AT_class (a) == dw_val_class_die_ref)
-    return a->dw_attr_val.v.val_die_ref.external;
+  dw_attr_ref a = get_AT (die, attr_kind);
 
-  return 0;
+  return a ? AT_file (a) : NULL;
 }
 
-static inline void
-set_AT_ref_external (dw_attr_ref a, int i)
+/* Return TRUE if the language is C++.  */
+
+static inline bool
+is_cxx (void)
 {
-  gcc_assert (a && AT_class (a) == dw_val_class_die_ref);
-  a->dw_attr_val.v.val_die_ref.external = i;
+  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;
 }
 
-/* Add an FDE reference attribute value to a DIE.  */
+/* Return TRUE if the language is Fortran.  */
 
-static inline void
-add_AT_fde_ref (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int targ_fde)
+static inline bool
+is_fortran (void)
 {
-  dw_attr_node attr;
+  unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
 
-  attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_fde_ref;
-  attr.dw_attr_val.v.val_fde_index = targ_fde;
-  add_dwarf_attr (die, &attr);
+  return (lang == DW_LANG_Fortran77
+         || lang == DW_LANG_Fortran90
+         || lang == DW_LANG_Fortran95);
 }
 
-/* Add a location description attribute value to a DIE.  */
+/* Return TRUE if the language is Ada.  */
 
-static inline void
-add_AT_loc (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_descr_ref loc)
+static inline bool
+is_ada (void)
 {
-  dw_attr_node attr;
+  unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
 
-  attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_loc;
-  attr.dw_attr_val.v.val_loc = loc;
-  add_dwarf_attr (die, &attr);
+  return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
 }
 
-static inline dw_loc_descr_ref
-AT_loc (dw_attr_ref a)
-{
-  gcc_assert (a && AT_class (a) == dw_val_class_loc);
-  return a->dw_attr_val.v.val_loc;
-}
+/* Remove the specified attribute if present.  */
 
-static inline void
-add_AT_loc_list (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_list_ref loc_list)
+static void
+remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
 {
-  dw_attr_node attr;
+  dw_attr_ref a;
+  unsigned ix;
 
-  attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_loc_list;
-  attr.dw_attr_val.v.val_loc_list = loc_list;
-  add_dwarf_attr (die, &attr);
-  have_location_lists = true;
+  if (! die)
+    return;
+
+  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)
+         if (a->dw_attr_val.v.val_str->refcount)
+           a->dw_attr_val.v.val_str->refcount--;
+
+       /* VEC_ordered_remove should help reduce the number of abbrevs
+          that are needed.  */
+       VEC_ordered_remove (dw_attr_node, die->die_attr, ix);
+       return;
+      }
 }
 
-static inline dw_loc_list_ref
-AT_loc_list (dw_attr_ref a)
+/* Remove CHILD from its parent.  PREV must have the property that
+   PREV->DIE_SIB == CHILD.  Does not alter CHILD.  */
+
+static void
+remove_child_with_prev (dw_die_ref child, dw_die_ref prev)
 {
-  gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
-  return a->dw_attr_val.v.val_loc_list;
+  gcc_assert (child->die_parent == prev->die_parent);
+  gcc_assert (prev->die_sib == child);
+  if (prev == child)
+    {
+      gcc_assert (child->die_parent->die_child == child);
+      prev = NULL;
+    }
+  else
+    prev->die_sib = child->die_sib;
+  if (child->die_parent->die_child == child)
+    child->die_parent->die_child = prev;
 }
 
-static inline dw_loc_list_ref *
-AT_loc_list_ptr (dw_attr_ref a)
+/* Replace OLD_CHILD with NEW_CHILD.  PREV must have the property that
+   PREV->DIE_SIB == OLD_CHILD.  Does not alter OLD_CHILD.  */
+
+static void
+replace_child (dw_die_ref old_child, dw_die_ref new_child, dw_die_ref prev)
 {
-  gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
-  return &a->dw_attr_val.v.val_loc_list;
+  dw_die_ref parent = old_child->die_parent;
+
+  gcc_assert (parent == prev->die_parent);
+  gcc_assert (prev->die_sib == old_child);
+
+  new_child->die_parent = parent;
+  if (prev == old_child)
+    {
+      gcc_assert (parent->die_child == old_child);
+      new_child->die_sib = new_child;
+    }
+  else
+    {
+      prev->die_sib = new_child;
+      new_child->die_sib = old_child->die_sib;
+    }
+  if (old_child->die_parent->die_child == old_child)
+    old_child->die_parent->die_child = new_child;
 }
 
-/* Add an address constant attribute value to a DIE.  */
+/* Move all children from OLD_PARENT to NEW_PARENT.  */
 
-static inline void
-add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
+static void
+move_all_children (dw_die_ref old_parent, dw_die_ref new_parent)
 {
-  dw_attr_node attr;
-
-  attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_addr;
-  attr.dw_attr_val.v.val_addr = addr;
-  add_dwarf_attr (die, &attr);
+  dw_die_ref c;
+  new_parent->die_child = old_parent->die_child;
+  old_parent->die_child = NULL;
+  FOR_EACH_CHILD (new_parent, c, c->die_parent = new_parent);
 }
 
-/* Get the RTX from to an address DIE attribute.  */
+/* Remove child DIE whose die_tag is TAG.  Do nothing if no child
+   matches TAG.  */
 
-static inline rtx
-AT_addr (dw_attr_ref a)
+static void
+remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
 {
-  gcc_assert (a && AT_class (a) == dw_val_class_addr);
-  return a->dw_attr_val.v.val_addr;
+  dw_die_ref c;
+
+  c = die->die_child;
+  if (c) do {
+    dw_die_ref prev = c;
+    c = c->die_sib;
+    while (c->die_tag == tag)
+      {
+       remove_child_with_prev (c, prev);
+       /* Might have removed every child.  */
+       if (c == c->die_sib)
+         return;
+       c = c->die_sib;
+      }
+  } while (c != die->die_child);
 }
 
-/* Add a file attribute value to a DIE.  */
+/* Add a CHILD_DIE as the last child of DIE.  */
 
-static inline void
-add_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind,
-            struct dwarf_file_data *fd)
+static void
+add_child_die (dw_die_ref die, dw_die_ref child_die)
 {
-  dw_attr_node attr;
+  /* FIXME this should probably be an assert.  */
+  if (! die || ! child_die)
+    return;
+  gcc_assert (die != child_die);
 
-  attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_file;
-  attr.dw_attr_val.v.val_file = fd;
-  add_dwarf_attr (die, &attr);
+  child_die->die_parent = die;
+  if (die->die_child)
+    {
+      child_die->die_sib = die->die_child->die_sib;
+      die->die_child->die_sib = child_die;
+    }
+  else
+    child_die->die_sib = child_die;
+  die->die_child = child_die;
 }
 
-/* Get the dwarf_file_data from a file DIE attribute.  */
+/* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
+   is the specification, to the end of PARENT's list of children.
+   This is done by removing and re-adding it.  */
 
-static inline struct dwarf_file_data *
-AT_file (dw_attr_ref a)
+static void
+splice_child_die (dw_die_ref parent, dw_die_ref child)
 {
-  gcc_assert (a && AT_class (a) == dw_val_class_file);
-  return a->dw_attr_val.v.val_file;
+  dw_die_ref p;
+
+  /* We want the declaration DIE from inside the class, not the
+     specification DIE at toplevel.  */
+  if (child->die_parent != parent)
+    {
+      dw_die_ref tmp = get_AT_ref (child, DW_AT_specification);
+
+      if (tmp)
+       child = tmp;
+    }
+
+  gcc_assert (child->die_parent == parent
+             || (child->die_parent
+                 == get_AT_ref (parent, DW_AT_specification)));
+
+  for (p = child->die_parent->die_child; ; p = p->die_sib)
+    if (p->die_sib == child)
+      {
+       remove_child_with_prev (child, p);
+       break;
+      }
+
+  add_child_die (parent, child);
 }
 
-/* Add a label identifier attribute value to a DIE.  */
+/* Return a pointer to a newly created DIE node.  */
 
-static inline void
-add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
+static inline dw_die_ref
+new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
 {
-  dw_attr_node attr;
+  dw_die_ref die = ggc_alloc_cleared_die_node ();
 
-  attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_lbl_id;
-  attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
-  add_dwarf_attr (die, &attr);
-}
+  die->die_tag = tag_value;
 
-/* Add a section offset attribute value to a DIE, an offset into the
-   debug_line section.  */
+  if (parent_die != NULL)
+    add_child_die (parent_die, die);
+  else
+    {
+      limbo_die_node *limbo_node;
 
-static inline void
-add_AT_lineptr (dw_die_ref die, enum dwarf_attribute attr_kind,
-               const char *label)
-{
-  dw_attr_node attr;
+      limbo_node = ggc_alloc_cleared_limbo_die_node ();
+      limbo_node->die = die;
+      limbo_node->created_for = t;
+      limbo_node->next = limbo_die_list;
+      limbo_die_list = limbo_node;
+    }
 
-  attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_lineptr;
-  attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
-  add_dwarf_attr (die, &attr);
+  return die;
 }
 
-/* Add a section offset attribute value to a DIE, an offset into the
-   debug_macinfo section.  */
+/* Return the DIE associated with the given type specifier.  */
 
-static inline void
-add_AT_macptr (dw_die_ref die, enum dwarf_attribute attr_kind,
-              const char *label)
+static inline dw_die_ref
+lookup_type_die (tree type)
 {
-  dw_attr_node attr;
-
-  attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_macptr;
-  attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
-  add_dwarf_attr (die, &attr);
+  return TYPE_SYMTAB_DIE (type);
 }
 
-/* Add an offset attribute value to a DIE.  */
-
-static inline void
-add_AT_offset (dw_die_ref die, enum dwarf_attribute attr_kind,
-              unsigned HOST_WIDE_INT offset)
-{
-  dw_attr_node attr;
+/* 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.  */
 
-  attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_offset;
-  attr.dw_attr_val.v.val_offset = offset;
-  add_dwarf_attr (die, &attr);
+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;
 }
 
-/* Add an range_list attribute value to a DIE.  */
-
-static void
-add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
-                  long unsigned int offset)
-{
-  dw_attr_node attr;
+/* 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.
 
-  attr.dw_attr = attr_kind;
-  attr.dw_attr_val.val_class = dw_val_class_range_list;
-  attr.dw_attr_val.v.val_offset = offset;
-  add_dwarf_attr (die, &attr);
-}
+   [1]: Read the comment of is_naming_typedef_decl to learn about what
+   a naming typedef is.  */
 
-static inline const char *
-AT_lbl (dw_attr_ref a)
+static inline dw_die_ref
+lookup_type_die_strip_naming_typedef (tree type)
 {
-  gcc_assert (a && (AT_class (a) == dw_val_class_lbl_id
-                   || AT_class (a) == dw_val_class_lineptr
-                   || AT_class (a) == dw_val_class_macptr));
-  return a->dw_attr_val.v.val_lbl_id;
+  dw_die_ref die = lookup_type_die (type);
+  return strip_naming_typedef (type, die);
 }
 
-/* Get the attribute of type attr_kind.  */
+/* Equate a DIE to a given type specifier.  */
 
-static dw_attr_ref
-get_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
+static inline void
+equate_type_number_to_die (tree type, dw_die_ref type_die)
 {
-  dw_attr_ref a;
-  unsigned ix;
-  dw_die_ref spec = NULL;
-
-  if (! die)
-    return NULL;
-
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    if (a->dw_attr == attr_kind)
-      return a;
-    else if (a->dw_attr == DW_AT_specification
-            || a->dw_attr == DW_AT_abstract_origin)
-      spec = AT_ref (a);
+  TYPE_SYMTAB_DIE (type) = type_die;
+}
 
-  if (spec)
-    return get_AT (spec, attr_kind);
+/* Returns a hash value for X (which really is a die_struct).  */
 
-  return NULL;
+static hashval_t
+decl_die_table_hash (const void *x)
+{
+  return (hashval_t) ((const_dw_die_ref) x)->decl_id;
 }
 
-/* Return the "low pc" attribute value, typically associated with a subprogram
-   DIE.  Return null if the "low pc" attribute is either not present, or if it
-   cannot be represented as an assembler label identifier.  */
+/* Return nonzero if decl_id of die_struct X is the same as UID of decl *Y.  */
 
-static inline const char *
-get_AT_low_pc (dw_die_ref die)
+static int
+decl_die_table_eq (const void *x, const void *y)
 {
-  dw_attr_ref a = get_AT (die, DW_AT_low_pc);
-
-  return a ? AT_lbl (a) : NULL;
+  return (((const_dw_die_ref) x)->decl_id == DECL_UID ((const_tree) y));
 }
 
-/* Return the "high pc" attribute value, typically associated with a subprogram
-   DIE.  Return null if the "high pc" attribute is either not present, or if it
-   cannot be represented as an assembler label identifier.  */
+/* Return the DIE associated with a given declaration.  */
 
-static inline const char *
-get_AT_hi_pc (dw_die_ref die)
+static inline dw_die_ref
+lookup_decl_die (tree decl)
 {
-  dw_attr_ref a = get_AT (die, DW_AT_high_pc);
-
-  return a ? AT_lbl (a) : NULL;
+  return (dw_die_ref) htab_find_with_hash (decl_die_table, decl, DECL_UID (decl));
 }
 
-/* Return the value of the string attribute designated by ATTR_KIND, or
-   NULL if it is not present.  */
+/* Returns a hash value for X (which really is a var_loc_list).  */
 
-static inline const char *
-get_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind)
+static hashval_t
+decl_loc_table_hash (const void *x)
 {
-  dw_attr_ref a = get_AT (die, attr_kind);
-
-  return a ? AT_string (a) : NULL;
+  return (hashval_t) ((const var_loc_list *) x)->decl_id;
 }
 
-/* Return the value of the flag attribute designated by ATTR_KIND, or -1
-   if it is not present.  */
+/* Return nonzero if decl_id of var_loc_list X is the same as
+   UID of decl *Y.  */
 
-static inline int
-get_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind)
+static int
+decl_loc_table_eq (const void *x, const void *y)
 {
-  dw_attr_ref a = get_AT (die, attr_kind);
-
-  return a ? AT_flag (a) : 0;
+  return (((const var_loc_list *) x)->decl_id == DECL_UID ((const_tree) y));
 }
 
-/* Return the value of the unsigned attribute designated by ATTR_KIND, or 0
-   if it is not present.  */
+/* Return the var_loc list associated with a given declaration.  */
 
-static inline unsigned
-get_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind)
+static inline var_loc_list *
+lookup_decl_loc (const_tree decl)
 {
-  dw_attr_ref a = get_AT (die, attr_kind);
-
-  return a ? AT_unsigned (a) : 0;
+  if (!decl_loc_table)
+    return NULL;
+  return (var_loc_list *)
+    htab_find_with_hash (decl_loc_table, decl, DECL_UID (decl));
 }
 
-static inline dw_die_ref
-get_AT_ref (dw_die_ref die, enum dwarf_attribute attr_kind)
-{
-  dw_attr_ref a = get_AT (die, attr_kind);
+/* Returns a hash value for X (which really is a cached_dw_loc_list_list).  */
 
-  return a ? AT_ref (a) : NULL;
+static hashval_t
+cached_dw_loc_list_table_hash (const void *x)
+{
+  return (hashval_t) ((const cached_dw_loc_list *) x)->decl_id;
 }
 
-static inline struct dwarf_file_data *
-get_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind)
-{
-  dw_attr_ref a = get_AT (die, attr_kind);
+/* Return nonzero if decl_id of cached_dw_loc_list X is the same as
+   UID of decl *Y.  */
 
-  return a ? AT_file (a) : NULL;
+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));
 }
 
-/* Return TRUE if the language is C++.  */
+/* Equate a DIE to a particular declaration.  */
 
-static inline bool
-is_cxx (void)
+static void
+equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
 {
-  unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+  unsigned int decl_id = DECL_UID (decl);
+  void **slot;
 
-  return lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus;
+  slot = htab_find_slot_with_hash (decl_die_table, decl, decl_id, INSERT);
+  *slot = decl_die;
+  decl_die->decl_id = decl_id;
 }
 
-/* Return TRUE if the language is Fortran.  */
+/* Return how many bits covers PIECE EXPR_LIST.  */
 
-static inline bool
-is_fortran (void)
+static int
+decl_piece_bitsize (rtx piece)
 {
-  unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
-
-  return (lang == DW_LANG_Fortran77
-         || lang == DW_LANG_Fortran90
-         || lang == DW_LANG_Fortran95);
+  int ret = (int) GET_MODE (piece);
+  if (ret)
+    return ret;
+  gcc_assert (GET_CODE (XEXP (piece, 0)) == CONCAT
+             && CONST_INT_P (XEXP (XEXP (piece, 0), 0)));
+  return INTVAL (XEXP (XEXP (piece, 0), 0));
 }
 
-/* Return TRUE if the language is Ada.  */
+/* Return pointer to the location of location note in PIECE EXPR_LIST.  */
 
-static inline bool
-is_ada (void)
+static rtx *
+decl_piece_varloc_ptr (rtx piece)
 {
-  unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
-
-  return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
+  if ((int) GET_MODE (piece))
+    return &XEXP (piece, 0);
+  else
+    return &XEXP (XEXP (piece, 0), 1);
 }
 
-/* Remove the specified attribute if present.  */
+/* Create an EXPR_LIST for location note LOC_NOTE covering BITSIZE bits.
+   Next is the chain of following piece nodes.  */
 
-static void
-remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
+static rtx
+decl_piece_node (rtx loc_note, HOST_WIDE_INT bitsize, rtx next)
 {
-  dw_attr_ref a;
-  unsigned ix;
-
-  if (! die)
-    return;
+  if (bitsize <= (int) MAX_MACHINE_MODE)
+    return alloc_EXPR_LIST (bitsize, loc_note, next);
+  else
+    return alloc_EXPR_LIST (0, gen_rtx_CONCAT (VOIDmode,
+                                              GEN_INT (bitsize),
+                                              loc_note), next);
+}
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    if (a->dw_attr == attr_kind)
-      {
-       if (AT_class (a) == dw_val_class_str)
-         if (a->dw_attr_val.v.val_str->refcount)
-           a->dw_attr_val.v.val_str->refcount--;
+/* Return rtx that should be stored into loc field for
+   LOC_NOTE and BITPOS/BITSIZE.  */
 
-       /* VEC_ordered_remove should help reduce the number of abbrevs
-          that are needed.  */
-       VEC_ordered_remove (dw_attr_node, die->die_attr, ix);
-       return;
-      }
+static rtx
+construct_piece_list (rtx loc_note, HOST_WIDE_INT bitpos,
+                     HOST_WIDE_INT bitsize)
+{
+  if (bitsize != -1)
+    {
+      loc_note = decl_piece_node (loc_note, bitsize, NULL_RTX);
+      if (bitpos != 0)
+       loc_note = decl_piece_node (NULL_RTX, bitpos, loc_note);
+    }
+  return loc_note;
 }
 
-/* Remove CHILD from its parent.  PREV must have the property that
-   PREV->DIE_SIB == CHILD.  Does not alter CHILD.  */
+/* This function either modifies location piece list *DEST in
+   place (if SRC and INNER is NULL), or copies location piece list
+   *SRC to *DEST while modifying it.  Location BITPOS is modified
+   to contain LOC_NOTE, any pieces overlapping it are removed resp.
+   not copied and if needed some padding around it is added.
+   When modifying in place, DEST should point to EXPR_LIST where
+   earlier pieces cover PIECE_BITPOS bits, when copying SRC points
+   to the start of the whole list and INNER points to the EXPR_LIST
+   where earlier pieces cover PIECE_BITPOS bits.  */
 
 static void
-remove_child_with_prev (dw_die_ref child, dw_die_ref prev)
+adjust_piece_list (rtx *dest, rtx *src, rtx *inner,
+                  HOST_WIDE_INT bitpos, HOST_WIDE_INT piece_bitpos,
+                  HOST_WIDE_INT bitsize, rtx loc_note)
 {
-  gcc_assert (child->die_parent == prev->die_parent);
-  gcc_assert (prev->die_sib == child);
-  if (prev == child)
+  int diff;
+  bool copy = inner != NULL;
+
+  if (copy)
     {
-      gcc_assert (child->die_parent->die_child == child);
-      prev = NULL;
+      /* First copy all nodes preceeding the current bitpos.  */
+      while (src != inner)
+       {
+         *dest = decl_piece_node (*decl_piece_varloc_ptr (*src),
+                                  decl_piece_bitsize (*src), NULL_RTX);
+         dest = &XEXP (*dest, 1);
+         src = &XEXP (*src, 1);
+       }
+    }
+  /* Add padding if needed.  */
+  if (bitpos != piece_bitpos)
+    {
+      *dest = decl_piece_node (NULL_RTX, bitpos - piece_bitpos,
+                              copy ? NULL_RTX : *dest);
+      dest = &XEXP (*dest, 1);
+    }
+  else if (*dest && decl_piece_bitsize (*dest) == bitsize)
+    {
+      gcc_assert (!copy);
+      /* A piece with correct bitpos and bitsize already exist,
+        just update the location for it and return.  */
+      *decl_piece_varloc_ptr (*dest) = loc_note;
+      return;
+    }
+  /* Add the piece that changed.  */
+  *dest = decl_piece_node (loc_note, bitsize, copy ? NULL_RTX : *dest);
+  dest = &XEXP (*dest, 1);
+  /* Skip over pieces that overlap it.  */
+  diff = bitpos - piece_bitpos + bitsize;
+  if (!copy)
+    src = dest;
+  while (diff > 0 && *src)
+    {
+      rtx piece = *src;
+      diff -= decl_piece_bitsize (piece);
+      if (copy)
+       src = &XEXP (piece, 1);
+      else
+       {
+         *src = XEXP (piece, 1);
+         free_EXPR_LIST_node (piece);
+       }
+    }
+  /* Add padding if needed.  */
+  if (diff < 0 && *src)
+    {
+      if (!copy)
+       dest = src;
+      *dest = decl_piece_node (NULL_RTX, -diff, copy ? NULL_RTX : *dest);
+      dest = &XEXP (*dest, 1);
+    }
+  if (!copy)
+    return;
+  /* Finally copy all nodes following it.  */
+  while (*src)
+    {
+      *dest = decl_piece_node (*decl_piece_varloc_ptr (*src),
+                              decl_piece_bitsize (*src), NULL_RTX);
+      dest = &XEXP (*dest, 1);
+      src = &XEXP (*src, 1);
     }
-  else
-    prev->die_sib = child->die_sib;
-  if (child->die_parent->die_child == child)
-    child->die_parent->die_child = prev;
 }
 
-/* Replace OLD_CHILD with NEW_CHILD.  PREV must have the property that
-   PREV->DIE_SIB == OLD_CHILD.  Does not alter OLD_CHILD.  */
+/* Add a variable location node to the linked list for DECL.  */
 
-static void
-replace_child (dw_die_ref old_child, dw_die_ref new_child, dw_die_ref prev)
+static struct var_loc_node *
+add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
 {
-  dw_die_ref parent = old_child->die_parent;
+  unsigned int decl_id;
+  var_loc_list *temp;
+  void **slot;
+  struct var_loc_node *loc = NULL;
+  HOST_WIDE_INT bitsize = -1, bitpos = -1;
 
-  gcc_assert (parent == prev->die_parent);
-  gcc_assert (prev->die_sib == old_child);
+  if (DECL_DEBUG_EXPR_IS_FROM (decl))
+    {
+      tree realdecl = DECL_DEBUG_EXPR (decl);
+      if (realdecl && handled_component_p (realdecl))
+       {
+         HOST_WIDE_INT maxsize;
+         tree innerdecl;
+         innerdecl
+           = get_ref_base_and_extent (realdecl, &bitpos, &bitsize, &maxsize);
+         if (!DECL_P (innerdecl)
+             || DECL_IGNORED_P (innerdecl)
+             || TREE_STATIC (innerdecl)
+             || bitsize <= 0
+             || bitpos + bitsize > 256
+             || bitsize != maxsize)
+           return NULL;
+         decl = innerdecl;
+       }
+    }
 
-  new_child->die_parent = parent;
-  if (prev == old_child)
+  decl_id = DECL_UID (decl);
+  slot = htab_find_slot_with_hash (decl_loc_table, decl, decl_id, INSERT);
+  if (*slot == NULL)
     {
-      gcc_assert (parent->die_child == old_child);
-      new_child->die_sib = new_child;
+      temp = ggc_alloc_cleared_var_loc_list ();
+      temp->decl_id = decl_id;
+      *slot = temp;
     }
   else
+    temp = (var_loc_list *) *slot;
+
+  /* For PARM_DECLs try to keep around the original incoming value,
+     even if that means we'll emit a zero-range .debug_loc entry.  */
+  if (temp->last
+      && temp->first == temp->last
+      && TREE_CODE (decl) == PARM_DECL
+      && GET_CODE (temp->first->loc) == NOTE
+      && NOTE_VAR_LOCATION_DECL (temp->first->loc) == decl
+      && DECL_INCOMING_RTL (decl)
+      && NOTE_VAR_LOCATION_LOC (temp->first->loc)
+      && GET_CODE (NOTE_VAR_LOCATION_LOC (temp->first->loc))
+        == GET_CODE (DECL_INCOMING_RTL (decl))
+      && prev_real_insn (temp->first->loc) == NULL_RTX
+      && (bitsize != -1
+         || !rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->first->loc),
+                          NOTE_VAR_LOCATION_LOC (loc_note))
+         || (NOTE_VAR_LOCATION_STATUS (temp->first->loc)
+             != NOTE_VAR_LOCATION_STATUS (loc_note))))
+    {
+      loc = ggc_alloc_cleared_var_loc_node ();
+      temp->first->next = loc;
+      temp->last = loc;
+      loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
+    }
+  else if (temp->last)
     {
-      prev->die_sib = new_child;
-      new_child->die_sib = old_child->die_sib;
+      struct var_loc_node *last = temp->last, *unused = NULL;
+      rtx *piece_loc = NULL, last_loc_note;
+      int piece_bitpos = 0;
+      if (last->next)
+       {
+         last = last->next;
+         gcc_assert (last->next == NULL);
+       }
+      if (bitsize != -1 && GET_CODE (last->loc) == EXPR_LIST)
+       {
+         piece_loc = &last->loc;
+         do
+           {
+             int cur_bitsize = decl_piece_bitsize (*piece_loc);
+             if (piece_bitpos + cur_bitsize > bitpos)
+               break;
+             piece_bitpos += cur_bitsize;
+             piece_loc = &XEXP (*piece_loc, 1);
+           }
+         while (*piece_loc);
+       }
+      /* TEMP->LAST here is either pointer to the last but one or
+        last element in the chained list, LAST is pointer to the
+        last element.  */
+      if (label && strcmp (last->label, label) == 0)
+       {
+         /* For SRA optimized variables if there weren't any real
+            insns since last note, just modify the last node.  */
+         if (piece_loc != NULL)
+           {
+             adjust_piece_list (piece_loc, NULL, NULL,
+                                bitpos, piece_bitpos, bitsize, loc_note);
+             return NULL;
+           }
+         /* If the last note doesn't cover any instructions, remove it.  */
+         if (temp->last != last)
+           {
+             temp->last->next = NULL;
+             unused = last;
+             last = temp->last;
+             gcc_assert (strcmp (last->label, label) != 0);
+           }
+         else
+           {
+             gcc_assert (temp->first == temp->last
+                         || (temp->first->next == temp->last
+                             && TREE_CODE (decl) == PARM_DECL));
+             memset (temp->last, '\0', sizeof (*temp->last));
+             temp->last->loc = construct_piece_list (loc_note, bitpos, bitsize);
+             return temp->last;
+           }
+       }
+      if (bitsize == -1 && NOTE_P (last->loc))
+       last_loc_note = last->loc;
+      else if (piece_loc != NULL
+              && *piece_loc != NULL_RTX
+              && piece_bitpos == bitpos
+              && decl_piece_bitsize (*piece_loc) == bitsize)
+       last_loc_note = *decl_piece_varloc_ptr (*piece_loc);
+      else
+       last_loc_note = NULL_RTX;
+      /* If the current location is the same as the end of the list,
+        and either both or neither of the locations is uninitialized,
+        we have nothing to do.  */
+      if (last_loc_note == NULL_RTX
+         || (!rtx_equal_p (NOTE_VAR_LOCATION_LOC (last_loc_note),
+                           NOTE_VAR_LOCATION_LOC (loc_note)))
+         || ((NOTE_VAR_LOCATION_STATUS (last_loc_note)
+              != NOTE_VAR_LOCATION_STATUS (loc_note))
+             && ((NOTE_VAR_LOCATION_STATUS (last_loc_note)
+                  == VAR_INIT_STATUS_UNINITIALIZED)
+                 || (NOTE_VAR_LOCATION_STATUS (loc_note)
+                     == VAR_INIT_STATUS_UNINITIALIZED))))
+       {
+         /* Add LOC to the end of list and update LAST.  If the last
+            element of the list has been removed above, reuse its
+            memory for the new node, otherwise allocate a new one.  */
+         if (unused)
+           {
+             loc = unused;
+             memset (loc, '\0', sizeof (*loc));
+           }
+         else
+           loc = ggc_alloc_cleared_var_loc_node ();
+         if (bitsize == -1 || piece_loc == NULL)
+           loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
+         else
+           adjust_piece_list (&loc->loc, &last->loc, piece_loc,
+                              bitpos, piece_bitpos, bitsize, loc_note);
+         last->next = loc;
+         /* Ensure TEMP->LAST will point either to the new last but one
+            element of the chain, or to the last element in it.  */
+         if (last != temp->last)
+           temp->last = last;
+       }
+      else if (unused)
+       ggc_free (unused);
     }
-  if (old_child->die_parent->die_child == old_child)
-    old_child->die_parent->die_child = new_child;
+  else
+    {
+      loc = ggc_alloc_cleared_var_loc_node ();
+      temp->first = loc;
+      temp->last = loc;
+      loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
+    }
+  return loc;
 }
+\f
+/* Keep track of the number of spaces used to indent the
+   output of the debugging routines that print the structure of
+   the DIE internal representation.  */
+static int print_indent;
 
-/* Move all children from OLD_PARENT to NEW_PARENT.  */
+/* Indent the line the number of spaces given by print_indent.  */
 
-static void
-move_all_children (dw_die_ref old_parent, dw_die_ref new_parent)
+static inline void
+print_spaces (FILE *outfile)
 {
-  dw_die_ref c;
-  new_parent->die_child = old_parent->die_child;
-  old_parent->die_child = NULL;
-  FOR_EACH_CHILD (new_parent, c, c->die_parent = new_parent);
+  fprintf (outfile, "%*s", print_indent, "");
 }
 
-/* Remove child DIE whose die_tag is TAG.  Do nothing if no child
-   matches TAG.  */
+/* Print a type signature in hex.  */
 
-static void
-remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
+static inline void
+print_signature (FILE *outfile, char *sig)
 {
-  dw_die_ref c;
+  int i;
 
-  c = die->die_child;
-  if (c) do {
-    dw_die_ref prev = c;
-    c = c->die_sib;
-    while (c->die_tag == tag)
-      {
-       remove_child_with_prev (c, prev);
-       /* Might have removed every child.  */
-       if (c == c->die_sib)
-         return;
-       c = c->die_sib;
-      }
-  } while (c != die->die_child);
+  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+    fprintf (outfile, "%02x", sig[i] & 0xff);
 }
 
-/* Add a CHILD_DIE as the last child of DIE.  */
+/* Print the information associated with a given DIE, and its children.
+   This routine is a debugging aid only.  */
 
 static void
-add_child_die (dw_die_ref die, dw_die_ref child_die)
+print_die (dw_die_ref die, FILE *outfile)
 {
-  /* FIXME this should probably be an assert.  */
-  if (! die || ! child_die)
-    return;
-  gcc_assert (die != child_die);
+  dw_attr_ref a;
+  dw_die_ref c;
+  unsigned ix;
 
-  child_die->die_parent = die;
-  if (die->die_child)
+  print_spaces (outfile);
+  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", die->die_offset);
+  fprintf (outfile, " mark: %d\n", die->die_mark);
+
+  if (use_debug_types && die->die_id.die_type_node)
     {
-      child_die->die_sib = die->die_child->die_sib;
-      die->die_child->die_sib = child_die;
+      print_spaces (outfile);
+      fprintf (outfile, "  signature: ");
+      print_signature (outfile, die->die_id.die_type_node->signature);
+      fprintf (outfile, "\n");
     }
-  else
-    child_die->die_sib = child_die;
-  die->die_child = child_die;
-}
-
-/* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
-   is the specification, to the end of PARENT's list of children.
-   This is done by removing and re-adding it.  */
 
-static void
-splice_child_die (dw_die_ref parent, dw_die_ref child)
-{
-  dw_die_ref p;
-
-  /* We want the declaration DIE from inside the class, not the
-     specification DIE at toplevel.  */
-  if (child->die_parent != parent)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     {
-      dw_die_ref tmp = get_AT_ref (child, DW_AT_specification);
+      print_spaces (outfile);
+      fprintf (outfile, "  %s: ", dwarf_attr_name (a->dw_attr));
 
-      if (tmp)
-       child = tmp;
-    }
+      switch (AT_class (a))
+       {
+       case dw_val_class_addr:
+         fprintf (outfile, "address");
+         break;
+       case dw_val_class_offset:
+         fprintf (outfile, "offset");
+         break;
+       case dw_val_class_loc:
+         fprintf (outfile, "location descriptor");
+         break;
+       case dw_val_class_loc_list:
+         fprintf (outfile, "location list -> label:%s",
+                  AT_loc_list (a)->ll_symbol);
+         break;
+       case dw_val_class_range_list:
+         fprintf (outfile, "range list");
+         break;
+       case dw_val_class_const:
+         fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, AT_int (a));
+         break;
+       case dw_val_class_unsigned_const:
+         fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, AT_unsigned (a));
+         break;
+       case dw_val_class_const_double:
+         fprintf (outfile, "constant ("HOST_WIDE_INT_PRINT_DEC","\
+                           HOST_WIDE_INT_PRINT_UNSIGNED")",
+                  a->dw_attr_val.v.val_double.high,
+                  a->dw_attr_val.v.val_double.low);
+         break;
+       case dw_val_class_vec:
+         fprintf (outfile, "floating-point or vector constant");
+         break;
+       case dw_val_class_flag:
+         fprintf (outfile, "%u", AT_flag (a));
+         break;
+       case dw_val_class_die_ref:
+         if (AT_ref (a) != NULL)
+           {
+             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 (! 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>");
+         break;
+       case dw_val_class_vms_delta:
+         fprintf (outfile, "delta: @slotcount(%s-%s)",
+                  AT_vms_delta2 (a), AT_vms_delta1 (a));
+         break;
+       case dw_val_class_lbl_id:
+       case dw_val_class_lineptr:
+       case dw_val_class_macptr:
+         fprintf (outfile, "label: %s", AT_lbl (a));
+         break;
+       case dw_val_class_str:
+         if (AT_string (a) != NULL)
+           fprintf (outfile, "\"%s\"", AT_string (a));
+         else
+           fprintf (outfile, "<null>");
+         break;
+       case dw_val_class_file:
+         fprintf (outfile, "\"%s\" (%d)", AT_file (a)->filename,
+                  AT_file (a)->emitted_number);
+         break;
+       case dw_val_class_data8:
+         {
+           int i;
 
-  gcc_assert (child->die_parent == parent
-             || (child->die_parent
-                 == get_AT_ref (parent, DW_AT_specification)));
+            for (i = 0; i < 8; i++)
+              fprintf (outfile, "%02x", a->dw_attr_val.v.val_data8[i]);
+           break;
+          }
+       default:
+         break;
+       }
 
-  for (p = child->die_parent->die_child; ; p = p->die_sib)
-    if (p->die_sib == child)
-      {
-       remove_child_with_prev (child, p);
-       break;
-      }
+      fprintf (outfile, "\n");
+    }
 
-  add_child_die (parent, child);
+  if (die->die_child != NULL)
+    {
+      print_indent += 4;
+      FOR_EACH_CHILD (die, c, print_die (c, outfile));
+      print_indent -= 4;
+    }
+  if (print_indent == 0)
+    fprintf (outfile, "\n");
 }
 
-/* Return a pointer to a newly created DIE node.  */
+/* Print the information collected for a given DIE.  */
 
-static inline dw_die_ref
-new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
+DEBUG_FUNCTION void
+debug_dwarf_die (dw_die_ref die)
 {
-  dw_die_ref die = GGC_CNEW (die_node);
-
-  die->die_tag = tag_value;
-
-  if (parent_die != NULL)
-    add_child_die (parent_die, die);
-  else
-    {
-      limbo_die_node *limbo_node;
-
-      limbo_node = GGC_CNEW (limbo_die_node);
-      limbo_node->die = die;
-      limbo_node->created_for = t;
-      limbo_node->next = limbo_die_list;
-      limbo_die_list = limbo_node;
-    }
-
-  return die;
+  print_die (die, stderr);
 }
 
-/* Return the DIE associated with the given type specifier.  */
+/* Print all DWARF information collected for the compilation unit.
+   This routine is a debugging aid only.  */
 
-static inline dw_die_ref
-lookup_type_die (tree type)
+DEBUG_FUNCTION void
+debug_dwarf (void)
 {
-  return TYPE_SYMTAB_DIE (type);
+  print_indent = 0;
+  print_die (comp_unit_die (), stderr);
 }
+\f
+/* Start a new compilation unit DIE for an include file.  OLD_UNIT is the CU
+   for the enclosing include file, if any.  BINCL_DIE is the DW_TAG_GNU_BINCL
+   DIE that marks the start of the DIEs for this include file.  */
 
-/* Equate a DIE to a given type specifier.  */
-
-static inline void
-equate_type_number_to_die (tree type, dw_die_ref type_die)
+static dw_die_ref
+push_new_compile_unit (dw_die_ref old_unit, dw_die_ref bincl_die)
 {
-  TYPE_SYMTAB_DIE (type) = type_die;
+  const char *filename = get_AT_string (bincl_die, DW_AT_name);
+  dw_die_ref new_unit = gen_compile_unit_die (filename);
+
+  new_unit->die_sib = old_unit;
+  return new_unit;
 }
 
-/* Returns a hash value for X (which really is a die_struct).  */
+/* Close an include-file CU and reopen the enclosing one.  */
 
-static hashval_t
-decl_die_table_hash (const void *x)
+static dw_die_ref
+pop_compile_unit (dw_die_ref old_unit)
 {
-  return (hashval_t) ((const_dw_die_ref) x)->decl_id;
+  dw_die_ref new_unit = old_unit->die_sib;
+
+  old_unit->die_sib = NULL;
+  return new_unit;
 }
 
-/* Return nonzero if decl_id of die_struct X is the same as UID of decl *Y.  */
+#define CHECKSUM(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx)
+#define CHECKSUM_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO), ctx)
 
-static int
-decl_die_table_eq (const void *x, const void *y)
+/* Calculate the checksum of a location expression.  */
+
+static inline void
+loc_checksum (dw_loc_descr_ref loc, struct md5_ctx *ctx)
 {
-  return (((const_dw_die_ref) x)->decl_id == DECL_UID ((const_tree) y));
+  int tem;
+
+  tem = (loc->dtprel << 8) | ((unsigned int) loc->dw_loc_opc);
+  CHECKSUM (tem);
+  CHECKSUM (loc->dw_loc_oprnd1);
+  CHECKSUM (loc->dw_loc_oprnd2);
 }
 
-/* Return the DIE associated with a given declaration.  */
+/* Calculate the checksum of an attribute.  */
 
-static inline dw_die_ref
-lookup_decl_die (tree decl)
+static void
+attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
 {
-  return (dw_die_ref) htab_find_with_hash (decl_die_table, decl, DECL_UID (decl));
-}
+  dw_loc_descr_ref loc;
+  rtx r;
 
-/* Returns a hash value for X (which really is a var_loc_list).  */
+  CHECKSUM (at->dw_attr);
 
-static hashval_t
-decl_loc_table_hash (const void *x)
-{
-  return (hashval_t) ((const var_loc_list *) x)->decl_id;
-}
+  /* We don't care that this was compiled with a different compiler
+     snapshot; if the output is the same, that's what matters.  */
+  if (at->dw_attr == DW_AT_producer)
+    return;
 
-/* Return nonzero if decl_id of var_loc_list X is the same as
-   UID of decl *Y.  */
+  switch (AT_class (at))
+    {
+    case dw_val_class_const:
+      CHECKSUM (at->dw_attr_val.v.val_int);
+      break;
+    case dw_val_class_unsigned_const:
+      CHECKSUM (at->dw_attr_val.v.val_unsigned);
+      break;
+    case dw_val_class_const_double:
+      CHECKSUM (at->dw_attr_val.v.val_double);
+      break;
+    case dw_val_class_vec:
+      CHECKSUM (at->dw_attr_val.v.val_vec);
+      break;
+    case dw_val_class_flag:
+      CHECKSUM (at->dw_attr_val.v.val_flag);
+      break;
+    case dw_val_class_str:
+      CHECKSUM_STRING (AT_string (at));
+      break;
 
-static int
-decl_loc_table_eq (const void *x, const void *y)
-{
-  return (((const var_loc_list *) x)->decl_id == DECL_UID ((const_tree) y));
-}
+    case dw_val_class_addr:
+      r = AT_addr (at);
+      gcc_assert (GET_CODE (r) == SYMBOL_REF);
+      CHECKSUM_STRING (XSTR (r, 0));
+      break;
 
-/* Return the var_loc list associated with a given declaration.  */
+    case dw_val_class_offset:
+      CHECKSUM (at->dw_attr_val.v.val_offset);
+      break;
 
-static inline var_loc_list *
-lookup_decl_loc (const_tree decl)
-{
-  if (!decl_loc_table)
-    return NULL;
-  return (var_loc_list *)
-    htab_find_with_hash (decl_loc_table, decl, DECL_UID (decl));
-}
+    case dw_val_class_loc:
+      for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
+       loc_checksum (loc, ctx);
+      break;
 
-/* Equate a DIE to a particular declaration.  */
+    case dw_val_class_die_ref:
+      die_checksum (AT_ref (at), ctx, mark);
+      break;
 
-static void
-equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
-{
-  unsigned int decl_id = DECL_UID (decl);
-  void **slot;
+    case dw_val_class_fde_ref:
+    case dw_val_class_vms_delta:
+    case dw_val_class_lbl_id:
+    case dw_val_class_lineptr:
+    case dw_val_class_macptr:
+      break;
 
-  slot = htab_find_slot_with_hash (decl_die_table, decl, decl_id, INSERT);
-  *slot = decl_die;
-  decl_die->decl_id = decl_id;
-}
+    case dw_val_class_file:
+      CHECKSUM_STRING (AT_file (at)->filename);
+      break;
 
-/* Return how many bits covers PIECE EXPR_LIST.  */
+    case dw_val_class_data8:
+      CHECKSUM (at->dw_attr_val.v.val_data8);
+      break;
 
-static int
-decl_piece_bitsize (rtx piece)
-{
-  int ret = (int) GET_MODE (piece);
-  if (ret)
-    return ret;
-  gcc_assert (GET_CODE (XEXP (piece, 0)) == CONCAT
-             && CONST_INT_P (XEXP (XEXP (piece, 0), 0)));
-  return INTVAL (XEXP (XEXP (piece, 0), 0));
+    default:
+      break;
+    }
 }
 
-/* Return pointer to the location of location note in PIECE EXPR_LIST.  */
+/* Calculate the checksum of a DIE.  */
 
-static rtx *
-decl_piece_varloc_ptr (rtx piece)
+static void
+die_checksum (dw_die_ref die, struct md5_ctx *ctx, int *mark)
 {
-  if ((int) GET_MODE (piece))
-    return &XEXP (piece, 0);
-  else
-    return &XEXP (XEXP (piece, 0), 1);
-}
+  dw_die_ref c;
+  dw_attr_ref a;
+  unsigned ix;
 
-/* Create an EXPR_LIST for location note LOC_NOTE covering BITSIZE bits.
-   Next is the chain of following piece nodes.  */
+  /* To avoid infinite recursion.  */
+  if (die->die_mark)
+    {
+      CHECKSUM (die->die_mark);
+      return;
+    }
+  die->die_mark = ++(*mark);
 
-static rtx
-decl_piece_node (rtx loc_note, HOST_WIDE_INT bitsize, rtx next)
-{
-  if (bitsize <= (int) MAX_MACHINE_MODE)
-    return alloc_EXPR_LIST (bitsize, loc_note, next);
-  else
-    return alloc_EXPR_LIST (0, gen_rtx_CONCAT (VOIDmode,
-                                              GEN_INT (bitsize),
-                                              loc_note), next);
+  CHECKSUM (die->die_tag);
+
+  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));
 }
 
-/* Return rtx that should be stored into loc field for
-   LOC_NOTE and BITPOS/BITSIZE.  */
+#undef CHECKSUM
+#undef CHECKSUM_STRING
 
-static rtx
-construct_piece_list (rtx loc_note, HOST_WIDE_INT bitpos,
-                     HOST_WIDE_INT bitsize)
+/* For DWARF-4 types, include the trailing NULL when checksumming strings.  */
+#define CHECKSUM(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx)
+#define CHECKSUM_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO) + 1, ctx)
+#define CHECKSUM_SLEB128(FOO) checksum_sleb128 ((FOO), ctx)
+#define CHECKSUM_ULEB128(FOO) checksum_uleb128 ((FOO), ctx)
+#define CHECKSUM_ATTR(FOO) \
+  if (FOO) attr_checksum_ordered (die->die_tag, (FOO), ctx, mark)
+
+/* Calculate the checksum of a number in signed LEB128 format.  */
+
+static void
+checksum_sleb128 (HOST_WIDE_INT value, struct md5_ctx *ctx)
 {
-  if (bitsize != -1)
+  unsigned char byte;
+  bool more;
+
+  while (1)
     {
-      loc_note = decl_piece_node (loc_note, bitsize, NULL_RTX);
-      if (bitpos != 0)
-       loc_note = decl_piece_node (NULL_RTX, bitpos, loc_note);
+      byte = (value & 0x7f);
+      value >>= 7;
+      more = !((value == 0 && (byte & 0x40) == 0)
+               || (value == -1 && (byte & 0x40) != 0));
+      if (more)
+       byte |= 0x80;
+      CHECKSUM (byte);
+      if (!more)
+       break;
     }
-  return loc_note;
 }
 
-/* This function either modifies location piece list *DEST in
-   place (if SRC and INNER is NULL), or copies location piece list
-   *SRC to *DEST while modifying it.  Location BITPOS is modified
-   to contain LOC_NOTE, any pieces overlapping it are removed resp.
-   not copied and if needed some padding around it is added.
-   When modifying in place, DEST should point to EXPR_LIST where
-   earlier pieces cover PIECE_BITPOS bits, when copying SRC points
-   to the start of the whole list and INNER points to the EXPR_LIST
-   where earlier pieces cover PIECE_BITPOS bits.  */
+/* Calculate the checksum of a number in unsigned LEB128 format.  */
 
 static void
-adjust_piece_list (rtx *dest, rtx *src, rtx *inner,
-                  HOST_WIDE_INT bitpos, HOST_WIDE_INT piece_bitpos,
-                  HOST_WIDE_INT bitsize, rtx loc_note)
+checksum_uleb128 (unsigned HOST_WIDE_INT value, struct md5_ctx *ctx)
 {
-  int diff;
-  bool copy = inner != NULL;
-
-  if (copy)
-    {
-      /* First copy all nodes preceeding the current bitpos.  */
-      while (src != inner)
-       {
-         *dest = decl_piece_node (*decl_piece_varloc_ptr (*src),
-                                  decl_piece_bitsize (*src), NULL_RTX);
-         dest = &XEXP (*dest, 1);
-         src = &XEXP (*src, 1);
-       }
-    }
-  /* Add padding if needed.  */
-  if (bitpos != piece_bitpos)
-    {
-      *dest = decl_piece_node (NULL_RTX, bitpos - piece_bitpos,
-                              copy ? NULL_RTX : *dest);
-      dest = &XEXP (*dest, 1);
-    }
-  else if (*dest && decl_piece_bitsize (*dest) == bitsize)
-    {
-      gcc_assert (!copy);
-      /* A piece with correct bitpos and bitsize already exist,
-        just update the location for it and return.  */
-      *decl_piece_varloc_ptr (*dest) = loc_note;
-      return;
-    }
-  /* Add the piece that changed.  */
-  *dest = decl_piece_node (loc_note, bitsize, copy ? NULL_RTX : *dest);
-  dest = &XEXP (*dest, 1);
-  /* Skip over pieces that overlap it.  */
-  diff = bitpos - piece_bitpos + bitsize;
-  if (!copy)
-    src = dest;
-  while (diff > 0 && *src)
-    {
-      rtx piece = *src;
-      diff -= decl_piece_bitsize (piece);
-      if (copy)
-       src = &XEXP (piece, 1);
-      else
-       {
-         *src = XEXP (piece, 1);
-         free_EXPR_LIST_node (piece);
-       }
-    }
-  /* Add padding if needed.  */
-  if (diff < 0 && *src)
-    {
-      if (!copy)
-       dest = src;
-      *dest = decl_piece_node (NULL_RTX, -diff, copy ? NULL_RTX : *dest);
-      dest = &XEXP (*dest, 1);
-    }
-  if (!copy)
-    return;
-  /* Finally copy all nodes following it.  */
-  while (*src)
+  while (1)
     {
-      *dest = decl_piece_node (*decl_piece_varloc_ptr (*src),
-                              decl_piece_bitsize (*src), NULL_RTX);
-      dest = &XEXP (*dest, 1);
-      src = &XEXP (*src, 1);
+      unsigned char byte = (value & 0x7f);
+      value >>= 7;
+      if (value != 0)
+       /* More bytes to follow.  */
+       byte |= 0x80;
+      CHECKSUM (byte);
+      if (value == 0)
+       break;
     }
 }
 
-/* Add a variable location node to the linked list for DECL.  */
+/* Checksum the context of the DIE.  This adds the names of any
+   surrounding namespaces or structures to the checksum.  */
 
-static struct var_loc_node *
-add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
+static void
+checksum_die_context (dw_die_ref die, struct md5_ctx *ctx)
 {
-  unsigned int decl_id;
-  var_loc_list *temp;
-  void **slot;
-  struct var_loc_node *loc = NULL;
-  HOST_WIDE_INT bitsize = -1, bitpos = -1;
+  const char *name;
+  dw_die_ref spec;
+  int tag = die->die_tag;
 
-  if (DECL_DEBUG_EXPR_IS_FROM (decl))
+  if (tag != DW_TAG_namespace
+      && tag != DW_TAG_structure_type
+      && tag != DW_TAG_class_type)
+    return;
+
+  name = get_AT_string (die, DW_AT_name);
+
+  spec = get_AT_ref (die, DW_AT_specification);
+  if (spec != NULL)
+    die = spec;
+
+  if (die->die_parent != NULL)
+    checksum_die_context (die->die_parent, ctx);
+
+  CHECKSUM_ULEB128 ('C');
+  CHECKSUM_ULEB128 (tag);
+  if (name != NULL)
+    CHECKSUM_STRING (name);
+}
+
+/* Calculate the checksum of a location expression.  */
+
+static inline void
+loc_checksum_ordered (dw_loc_descr_ref loc, struct md5_ctx *ctx)
+{
+  /* Special case for lone DW_OP_plus_uconst: checksum as if the location
+     were emitted as a DW_FORM_sdata instead of a location expression.  */
+  if (loc->dw_loc_opc == DW_OP_plus_uconst && loc->dw_loc_next == NULL)
     {
-      tree realdecl = DECL_DEBUG_EXPR (decl);
-      if (realdecl && handled_component_p (realdecl))
-       {
-         HOST_WIDE_INT maxsize;
-         tree innerdecl;
-         innerdecl
-           = get_ref_base_and_extent (realdecl, &bitpos, &bitsize, &maxsize);
-         if (!DECL_P (innerdecl)
-             || DECL_IGNORED_P (innerdecl)
-             || TREE_STATIC (innerdecl)
-             || bitsize <= 0
-             || bitpos + bitsize > 256
-             || bitsize != maxsize)
-           return NULL;
-         decl = innerdecl;
-       }
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_SLEB128 ((HOST_WIDE_INT) loc->dw_loc_oprnd1.v.val_unsigned);
+      return;
     }
 
-  decl_id = DECL_UID (decl);
-  slot = htab_find_slot_with_hash (decl_loc_table, decl, decl_id, INSERT);
-  if (*slot == NULL)
+  /* Otherwise, just checksum the raw location expression.  */
+  while (loc != NULL)
     {
-      temp = GGC_CNEW (var_loc_list);
-      temp->decl_id = decl_id;
-      *slot = temp;
+      CHECKSUM_ULEB128 (loc->dw_loc_opc);
+      CHECKSUM (loc->dw_loc_oprnd1);
+      CHECKSUM (loc->dw_loc_oprnd2);
+      loc = loc->dw_loc_next;
     }
-  else
-    temp = (var_loc_list *) *slot;
+}
+
+/* Calculate the checksum of an attribute.  */
+
+static void
+attr_checksum_ordered (enum dwarf_tag tag, dw_attr_ref at,
+                      struct md5_ctx *ctx, int *mark)
+{
+  dw_loc_descr_ref loc;
+  rtx r;
 
-  if (temp->last)
+  if (AT_class (at) == dw_val_class_die_ref)
     {
-      struct var_loc_node *last = temp->last, *unused = NULL;
-      rtx *piece_loc = NULL, last_loc_note;
-      int piece_bitpos = 0;
-      if (last->next)
-       {
-         last = last->next;
-         gcc_assert (last->next == NULL);
-       }
-      if (bitsize != -1 && GET_CODE (last->loc) == EXPR_LIST)
-       {
-         piece_loc = &last->loc;
-         do
-           {
-             int cur_bitsize = decl_piece_bitsize (*piece_loc);
-             if (piece_bitpos + cur_bitsize > bitpos)
-               break;
-             piece_bitpos += cur_bitsize;
-             piece_loc = &XEXP (*piece_loc, 1);
-           }
-         while (*piece_loc);
-       }
-      /* TEMP->LAST here is either pointer to the last but one or
-        last element in the chained list, LAST is pointer to the
-        last element.  */
-      if (label && strcmp (last->label, label) == 0)
+      dw_die_ref target_die = AT_ref (at);
+
+      /* For pointer and reference types, we checksum only the (qualified)
+        name of the target type (if there is a name).  For friend entries,
+        we checksum only the (qualified) name of the target type or function.
+        This allows the checksum to remain the same whether the target type
+        is complete or not.  */
+      if ((at->dw_attr == DW_AT_type
+          && (tag == DW_TAG_pointer_type
+              || tag == DW_TAG_reference_type
+              || tag == DW_TAG_rvalue_reference_type
+              || tag == DW_TAG_ptr_to_member_type))
+         || (at->dw_attr == DW_AT_friend
+             && tag == DW_TAG_friend))
        {
-         /* For SRA optimized variables if there weren't any real
-            insns since last note, just modify the last node.  */
-         if (piece_loc != NULL)
-           {
-             adjust_piece_list (piece_loc, NULL, NULL,
-                                bitpos, piece_bitpos, bitsize, loc_note);
-             return NULL;
-           }
-         /* If the last note doesn't cover any instructions, remove it.  */
-         if (temp->last != last)
-           {
-             temp->last->next = NULL;
-             unused = last;
-             last = temp->last;
-             gcc_assert (strcmp (last->label, label) != 0);
-           }
-         else
+         dw_attr_ref name_attr = get_AT (target_die, DW_AT_name);
+
+         if (name_attr != NULL)
            {
-             gcc_assert (temp->first == temp->last);
-             memset (temp->last, '\0', sizeof (*temp->last));
-             temp->last->loc = construct_piece_list (loc_note, bitpos, bitsize);
-             return temp->last;
+             dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification);
+
+             if (decl == NULL)
+               decl = target_die;
+             CHECKSUM_ULEB128 ('N');
+             CHECKSUM_ULEB128 (at->dw_attr);
+             if (decl->die_parent != NULL)
+               checksum_die_context (decl->die_parent, ctx);
+             CHECKSUM_ULEB128 ('E');
+             CHECKSUM_STRING (AT_string (name_attr));
+             return;
            }
        }
-      if (bitsize == -1 && NOTE_P (last->loc))
-       last_loc_note = last->loc;
-      else if (piece_loc != NULL
-              && *piece_loc != NULL_RTX
-              && piece_bitpos == bitpos
-              && decl_piece_bitsize (*piece_loc) == bitsize)
-       last_loc_note = *decl_piece_varloc_ptr (*piece_loc);
+
+      /* For all other references to another DIE, we check to see if the
+         target DIE has already been visited.  If it has, we emit a
+         backward reference; if not, we descend recursively.  */
+      if (target_die->die_mark > 0)
+        {
+         CHECKSUM_ULEB128 ('R');
+         CHECKSUM_ULEB128 (at->dw_attr);
+         CHECKSUM_ULEB128 (target_die->die_mark);
+        }
       else
-       last_loc_note = NULL_RTX;
-      /* If the current location is the same as the end of the list,
-        and either both or neither of the locations is uninitialized,
-        we have nothing to do.  */
-      if (last_loc_note == NULL_RTX
-         || (!rtx_equal_p (NOTE_VAR_LOCATION_LOC (last_loc_note),
-                           NOTE_VAR_LOCATION_LOC (loc_note)))
-         || ((NOTE_VAR_LOCATION_STATUS (last_loc_note)
-              != NOTE_VAR_LOCATION_STATUS (loc_note))
-             && ((NOTE_VAR_LOCATION_STATUS (last_loc_note)
-                  == VAR_INIT_STATUS_UNINITIALIZED)
-                 || (NOTE_VAR_LOCATION_STATUS (loc_note)
-                     == VAR_INIT_STATUS_UNINITIALIZED))))
-       {
-         /* Add LOC to the end of list and update LAST.  If the last
-            element of the list has been removed above, reuse its
-            memory for the new node, otherwise allocate a new one.  */
-         if (unused)
-           {
-             loc = unused;
-             memset (loc, '\0', sizeof (*loc));
-           }
-         else
-           loc = GGC_CNEW (struct var_loc_node);
-         if (bitsize == -1 || piece_loc == NULL)
-           loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
-         else
-           adjust_piece_list (&loc->loc, &last->loc, piece_loc,
-                              bitpos, piece_bitpos, bitsize, loc_note);
-         last->next = loc;
-         /* Ensure TEMP->LAST will point either to the new last but one
-            element of the chain, or to the last element in it.  */
-         if (last != temp->last)
-           temp->last = last;
-       }
-      else if (unused)
-       ggc_free (unused);
+        {
+         dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification);
+
+         if (decl == NULL)
+           decl = target_die;
+         target_die->die_mark = ++(*mark);
+         CHECKSUM_ULEB128 ('T');
+         CHECKSUM_ULEB128 (at->dw_attr);
+         if (decl->die_parent != NULL)
+           checksum_die_context (decl->die_parent, ctx);
+         die_checksum_ordered (target_die, ctx, mark);
+        }
+      return;
     }
-  else
+
+  CHECKSUM_ULEB128 ('A');
+  CHECKSUM_ULEB128 (at->dw_attr);
+
+  switch (AT_class (at))
     {
-      loc = GGC_CNEW (struct var_loc_node);
-      temp->first = loc;
-      temp->last = loc;
-      loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
+    case dw_val_class_const:
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_SLEB128 (at->dw_attr_val.v.val_int);
+      break;
+
+    case dw_val_class_unsigned_const:
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_SLEB128 ((int) at->dw_attr_val.v.val_unsigned);
+      break;
+
+    case dw_val_class_const_double:
+      CHECKSUM_ULEB128 (DW_FORM_block);
+      CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_double));
+      CHECKSUM (at->dw_attr_val.v.val_double);
+      break;
+
+    case dw_val_class_vec:
+      CHECKSUM_ULEB128 (DW_FORM_block);
+      CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_vec));
+      CHECKSUM (at->dw_attr_val.v.val_vec);
+      break;
+
+    case dw_val_class_flag:
+      CHECKSUM_ULEB128 (DW_FORM_flag);
+      CHECKSUM_ULEB128 (at->dw_attr_val.v.val_flag ? 1 : 0);
+      break;
+
+    case dw_val_class_str:
+      CHECKSUM_ULEB128 (DW_FORM_string);
+      CHECKSUM_STRING (AT_string (at));
+      break;
+
+    case dw_val_class_addr:
+      r = AT_addr (at);
+      gcc_assert (GET_CODE (r) == SYMBOL_REF);
+      CHECKSUM_ULEB128 (DW_FORM_string);
+      CHECKSUM_STRING (XSTR (r, 0));
+      break;
+
+    case dw_val_class_offset:
+      CHECKSUM_ULEB128 (DW_FORM_sdata);
+      CHECKSUM_ULEB128 (at->dw_attr_val.v.val_offset);
+      break;
+
+    case dw_val_class_loc:
+      for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
+       loc_checksum_ordered (loc, ctx);
+      break;
+
+    case dw_val_class_fde_ref:
+    case dw_val_class_lbl_id:
+    case dw_val_class_lineptr:
+    case dw_val_class_macptr:
+      break;
+
+    case dw_val_class_file:
+      CHECKSUM_ULEB128 (DW_FORM_string);
+      CHECKSUM_STRING (AT_file (at)->filename);
+      break;
+
+    case dw_val_class_data8:
+      CHECKSUM (at->dw_attr_val.v.val_data8);
+      break;
+
+    default:
+      break;
     }
-  return loc;
 }
-\f
-/* Keep track of the number of spaces used to indent the
-   output of the debugging routines that print the structure of
-   the DIE internal representation.  */
-static int print_indent;
-
-/* Indent the line the number of spaces given by print_indent.  */
 
-static inline void
-print_spaces (FILE *outfile)
+struct checksum_attributes
 {
-  fprintf (outfile, "%*s", print_indent, "");
-}
+  dw_attr_ref at_name;
+  dw_attr_ref at_type;
+  dw_attr_ref at_friend;
+  dw_attr_ref at_accessibility;
+  dw_attr_ref at_address_class;
+  dw_attr_ref at_allocated;
+  dw_attr_ref at_artificial;
+  dw_attr_ref at_associated;
+  dw_attr_ref at_binary_scale;
+  dw_attr_ref at_bit_offset;
+  dw_attr_ref at_bit_size;
+  dw_attr_ref at_bit_stride;
+  dw_attr_ref at_byte_size;
+  dw_attr_ref at_byte_stride;
+  dw_attr_ref at_const_value;
+  dw_attr_ref at_containing_type;
+  dw_attr_ref at_count;
+  dw_attr_ref at_data_location;
+  dw_attr_ref at_data_member_location;
+  dw_attr_ref at_decimal_scale;
+  dw_attr_ref at_decimal_sign;
+  dw_attr_ref at_default_value;
+  dw_attr_ref at_digit_count;
+  dw_attr_ref at_discr;
+  dw_attr_ref at_discr_list;
+  dw_attr_ref at_discr_value;
+  dw_attr_ref at_encoding;
+  dw_attr_ref at_endianity;
+  dw_attr_ref at_explicit;
+  dw_attr_ref at_is_optional;
+  dw_attr_ref at_location;
+  dw_attr_ref at_lower_bound;
+  dw_attr_ref at_mutable;
+  dw_attr_ref at_ordering;
+  dw_attr_ref at_picture_string;
+  dw_attr_ref at_prototyped;
+  dw_attr_ref at_small;
+  dw_attr_ref at_segment;
+  dw_attr_ref at_string_length;
+  dw_attr_ref at_threads_scaled;
+  dw_attr_ref at_upper_bound;
+  dw_attr_ref at_use_location;
+  dw_attr_ref at_use_UTF8;
+  dw_attr_ref at_variable_parameter;
+  dw_attr_ref at_virtuality;
+  dw_attr_ref at_visibility;
+  dw_attr_ref at_vtable_elem_location;
+};
 
-/* Print a type signature in hex.  */
+/* Collect the attributes that we will want to use for the checksum.  */
 
-static inline void
-print_signature (FILE *outfile, char *sig)
+static void
+collect_checksum_attributes (struct checksum_attributes *attrs, dw_die_ref die)
 {
-  int i;
+  dw_attr_ref a;
+  unsigned ix;
 
-  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
-    fprintf (outfile, "%02x", sig[i] & 0xff);
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
+    {
+      switch (a->dw_attr)
+        {
+        case DW_AT_name:
+          attrs->at_name = a;
+          break;
+        case DW_AT_type:
+          attrs->at_type = a;
+          break;
+        case DW_AT_friend:
+          attrs->at_friend = a;
+          break;
+        case DW_AT_accessibility:
+          attrs->at_accessibility = a;
+          break;
+        case DW_AT_address_class:
+          attrs->at_address_class = a;
+          break;
+        case DW_AT_allocated:
+          attrs->at_allocated = a;
+          break;
+        case DW_AT_artificial:
+          attrs->at_artificial = a;
+          break;
+        case DW_AT_associated:
+          attrs->at_associated = a;
+          break;
+        case DW_AT_binary_scale:
+          attrs->at_binary_scale = a;
+          break;
+        case DW_AT_bit_offset:
+          attrs->at_bit_offset = a;
+          break;
+        case DW_AT_bit_size:
+          attrs->at_bit_size = a;
+          break;
+        case DW_AT_bit_stride:
+          attrs->at_bit_stride = a;
+          break;
+        case DW_AT_byte_size:
+          attrs->at_byte_size = a;
+          break;
+        case DW_AT_byte_stride:
+          attrs->at_byte_stride = a;
+          break;
+        case DW_AT_const_value:
+          attrs->at_const_value = a;
+          break;
+        case DW_AT_containing_type:
+          attrs->at_containing_type = a;
+          break;
+        case DW_AT_count:
+          attrs->at_count = a;
+          break;
+        case DW_AT_data_location:
+          attrs->at_data_location = a;
+          break;
+        case DW_AT_data_member_location:
+          attrs->at_data_member_location = a;
+          break;
+        case DW_AT_decimal_scale:
+          attrs->at_decimal_scale = a;
+          break;
+        case DW_AT_decimal_sign:
+          attrs->at_decimal_sign = a;
+          break;
+        case DW_AT_default_value:
+          attrs->at_default_value = a;
+          break;
+        case DW_AT_digit_count:
+          attrs->at_digit_count = a;
+          break;
+        case DW_AT_discr:
+          attrs->at_discr = a;
+          break;
+        case DW_AT_discr_list:
+          attrs->at_discr_list = a;
+          break;
+        case DW_AT_discr_value:
+          attrs->at_discr_value = a;
+          break;
+        case DW_AT_encoding:
+          attrs->at_encoding = a;
+          break;
+        case DW_AT_endianity:
+          attrs->at_endianity = a;
+          break;
+        case DW_AT_explicit:
+          attrs->at_explicit = a;
+          break;
+        case DW_AT_is_optional:
+          attrs->at_is_optional = a;
+          break;
+        case DW_AT_location:
+          attrs->at_location = a;
+          break;
+        case DW_AT_lower_bound:
+          attrs->at_lower_bound = a;
+          break;
+        case DW_AT_mutable:
+          attrs->at_mutable = a;
+          break;
+        case DW_AT_ordering:
+          attrs->at_ordering = a;
+          break;
+        case DW_AT_picture_string:
+          attrs->at_picture_string = a;
+          break;
+        case DW_AT_prototyped:
+          attrs->at_prototyped = a;
+          break;
+        case DW_AT_small:
+          attrs->at_small = a;
+          break;
+        case DW_AT_segment:
+          attrs->at_segment = a;
+          break;
+        case DW_AT_string_length:
+          attrs->at_string_length = a;
+          break;
+        case DW_AT_threads_scaled:
+          attrs->at_threads_scaled = a;
+          break;
+        case DW_AT_upper_bound:
+          attrs->at_upper_bound = a;
+          break;
+        case DW_AT_use_location:
+          attrs->at_use_location = a;
+          break;
+        case DW_AT_use_UTF8:
+          attrs->at_use_UTF8 = a;
+          break;
+        case DW_AT_variable_parameter:
+          attrs->at_variable_parameter = a;
+          break;
+        case DW_AT_virtuality:
+          attrs->at_virtuality = a;
+          break;
+        case DW_AT_visibility:
+          attrs->at_visibility = a;
+          break;
+        case DW_AT_vtable_elem_location:
+          attrs->at_vtable_elem_location = a;
+          break;
+        default:
+          break;
+        }
+    }
 }
 
-/* Print the information associated with a given DIE, and its children.
-   This routine is a debugging aid only.  */
+/* Calculate the checksum of a DIE, using an ordered subset of attributes.  */
 
 static void
-print_die (dw_die_ref die, FILE *outfile)
+die_checksum_ordered (dw_die_ref die, struct md5_ctx *ctx, int *mark)
 {
-  dw_attr_ref a;
   dw_die_ref c;
-  unsigned ix;
-
-  print_spaces (outfile);
-  fprintf (outfile, "DIE %4ld: %s\n",
-          die->die_offset, dwarf_tag_name (die->die_tag));
-  print_spaces (outfile);
-  fprintf (outfile, "  abbrev id: %lu", die->die_abbrev);
-  fprintf (outfile, " offset: %ld\n", die->die_offset);
-  if (dwarf_version >= 4 && die->die_id.die_type_node)
-    {
-      print_spaces (outfile);
-      fprintf (outfile, "  signature: ");
-      print_signature (outfile, die->die_id.die_type_node->signature);
-      fprintf (outfile, "\n");
-    }
-
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    {
-      print_spaces (outfile);
-      fprintf (outfile, "  %s: ", dwarf_attr_name (a->dw_attr));
-
-      switch (AT_class (a))
-       {
-       case dw_val_class_addr:
-         fprintf (outfile, "address");
-         break;
-       case dw_val_class_offset:
-         fprintf (outfile, "offset");
-         break;
-       case dw_val_class_loc:
-         fprintf (outfile, "location descriptor");
-         break;
-       case dw_val_class_loc_list:
-         fprintf (outfile, "location list -> label:%s",
-                  AT_loc_list (a)->ll_symbol);
-         break;
-       case dw_val_class_range_list:
-         fprintf (outfile, "range list");
-         break;
-       case dw_val_class_const:
-         fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, AT_int (a));
-         break;
-       case dw_val_class_unsigned_const:
-         fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, AT_unsigned (a));
-         break;
-       case dw_val_class_const_double:
-         fprintf (outfile, "constant ("HOST_WIDE_INT_PRINT_DEC","\
-                           HOST_WIDE_INT_PRINT_UNSIGNED")",
-                  a->dw_attr_val.v.val_double.high,
-                  a->dw_attr_val.v.val_double.low);
-         break;
-       case dw_val_class_vec:
-         fprintf (outfile, "floating-point or vector constant");
-         break;
-       case dw_val_class_flag:
-         fprintf (outfile, "%u", AT_flag (a));
-         break;
-       case dw_val_class_die_ref:
-         if (AT_ref (a) != NULL)
-           {
-             if (dwarf_version >= 4 && AT_ref (a)->die_id.die_type_node)
-               {
-                 fprintf (outfile, "die -> signature: ");
-                 print_signature (outfile,
-                                  AT_ref (a)->die_id.die_type_node->signature);
-                }
-             else if (dwarf_version < 4 && AT_ref (a)->die_id.die_symbol)
-               fprintf (outfile, "die -> label: %s",
-                        AT_ref (a)->die_id.die_symbol);
-             else
-               fprintf (outfile, "die -> %ld", AT_ref (a)->die_offset);
-           }
-         else
-           fprintf (outfile, "die -> <null>");
-         break;
-       case dw_val_class_lbl_id:
-       case dw_val_class_lineptr:
-       case dw_val_class_macptr:
-         fprintf (outfile, "label: %s", AT_lbl (a));
-         break;
-       case dw_val_class_str:
-         if (AT_string (a) != NULL)
-           fprintf (outfile, "\"%s\"", AT_string (a));
-         else
-           fprintf (outfile, "<null>");
-         break;
-       case dw_val_class_file:
-         fprintf (outfile, "\"%s\" (%d)", AT_file (a)->filename,
-                  AT_file (a)->emitted_number);
-         break;
-       case dw_val_class_data8:
-         {
-           int i;
+  dw_die_ref decl;
+  struct checksum_attributes attrs;
 
-            for (i = 0; i < 8; i++)
-              fprintf (outfile, "%02x", a->dw_attr_val.v.val_data8[i]);
-           break;
-          }
-       default:
-         break;
-       }
+  CHECKSUM_ULEB128 ('D');
+  CHECKSUM_ULEB128 (die->die_tag);
 
-      fprintf (outfile, "\n");
-    }
+  memset (&attrs, 0, sizeof (attrs));
 
-  if (die->die_child != NULL)
-    {
-      print_indent += 4;
-      FOR_EACH_CHILD (die, c, print_die (c, outfile));
-      print_indent -= 4;
-    }
-  if (print_indent == 0)
-    fprintf (outfile, "\n");
-}
+  decl = get_AT_ref (die, DW_AT_specification);
+  if (decl != NULL)
+    collect_checksum_attributes (&attrs, decl);
+  collect_checksum_attributes (&attrs, die);
 
-/* Print the contents of the source code line number correspondence table.
-   This routine is a debugging aid only.  */
+  CHECKSUM_ATTR (attrs.at_name);
+  CHECKSUM_ATTR (attrs.at_accessibility);
+  CHECKSUM_ATTR (attrs.at_address_class);
+  CHECKSUM_ATTR (attrs.at_allocated);
+  CHECKSUM_ATTR (attrs.at_artificial);
+  CHECKSUM_ATTR (attrs.at_associated);
+  CHECKSUM_ATTR (attrs.at_binary_scale);
+  CHECKSUM_ATTR (attrs.at_bit_offset);
+  CHECKSUM_ATTR (attrs.at_bit_size);
+  CHECKSUM_ATTR (attrs.at_bit_stride);
+  CHECKSUM_ATTR (attrs.at_byte_size);
+  CHECKSUM_ATTR (attrs.at_byte_stride);
+  CHECKSUM_ATTR (attrs.at_const_value);
+  CHECKSUM_ATTR (attrs.at_containing_type);
+  CHECKSUM_ATTR (attrs.at_count);
+  CHECKSUM_ATTR (attrs.at_data_location);
+  CHECKSUM_ATTR (attrs.at_data_member_location);
+  CHECKSUM_ATTR (attrs.at_decimal_scale);
+  CHECKSUM_ATTR (attrs.at_decimal_sign);
+  CHECKSUM_ATTR (attrs.at_default_value);
+  CHECKSUM_ATTR (attrs.at_digit_count);
+  CHECKSUM_ATTR (attrs.at_discr);
+  CHECKSUM_ATTR (attrs.at_discr_list);
+  CHECKSUM_ATTR (attrs.at_discr_value);
+  CHECKSUM_ATTR (attrs.at_encoding);
+  CHECKSUM_ATTR (attrs.at_endianity);
+  CHECKSUM_ATTR (attrs.at_explicit);
+  CHECKSUM_ATTR (attrs.at_is_optional);
+  CHECKSUM_ATTR (attrs.at_location);
+  CHECKSUM_ATTR (attrs.at_lower_bound);
+  CHECKSUM_ATTR (attrs.at_mutable);
+  CHECKSUM_ATTR (attrs.at_ordering);
+  CHECKSUM_ATTR (attrs.at_picture_string);
+  CHECKSUM_ATTR (attrs.at_prototyped);
+  CHECKSUM_ATTR (attrs.at_small);
+  CHECKSUM_ATTR (attrs.at_segment);
+  CHECKSUM_ATTR (attrs.at_string_length);
+  CHECKSUM_ATTR (attrs.at_threads_scaled);
+  CHECKSUM_ATTR (attrs.at_upper_bound);
+  CHECKSUM_ATTR (attrs.at_use_location);
+  CHECKSUM_ATTR (attrs.at_use_UTF8);
+  CHECKSUM_ATTR (attrs.at_variable_parameter);
+  CHECKSUM_ATTR (attrs.at_virtuality);
+  CHECKSUM_ATTR (attrs.at_visibility);
+  CHECKSUM_ATTR (attrs.at_vtable_elem_location);
+  CHECKSUM_ATTR (attrs.at_type);
+  CHECKSUM_ATTR (attrs.at_friend);
 
-static void
-print_dwarf_line_table (FILE *outfile)
-{
-  unsigned i;
-  dw_line_info_ref line_info;
+  /* Checksum the child DIEs, except for nested types and member functions.  */
+  c = die->die_child;
+  if (c) do {
+    dw_attr_ref name_attr;
 
-  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);
-    }
+    c = c->die_sib;
+    name_attr = get_AT (c, DW_AT_name);
+    if ((is_type_die (c) || c->die_tag == DW_TAG_subprogram)
+        && name_attr != NULL)
+      {
+        CHECKSUM_ULEB128 ('S');
+        CHECKSUM_ULEB128 (c->die_tag);
+        CHECKSUM_STRING (AT_string (name_attr));
+      }
+    else
+      {
+        /* Mark this DIE so it gets processed when unmarking.  */
+        if (c->die_mark == 0)
+          c->die_mark = -1;
+        die_checksum_ordered (c, ctx, mark);
+      }
+  } while (c != die->die_child);
 
-  fprintf (outfile, "\n\n");
+  CHECKSUM_ULEB128 (0);
 }
 
-/* Print the information collected for a given DIE.  */
+#undef CHECKSUM
+#undef CHECKSUM_STRING
+#undef CHECKSUM_ATTR
+#undef CHECKSUM_LEB128
+#undef CHECKSUM_ULEB128
 
-void
-debug_dwarf_die (dw_die_ref die)
+/* Generate the type signature for DIE.  This is computed by generating an
+   MD5 checksum over the DIE's tag, its relevant attributes, and its
+   children.  Attributes that are references to other DIEs are processed
+   by recursion, using the MARK field to prevent infinite recursion.
+   If the DIE is nested inside a namespace or another type, we also
+   need to include that context in the signature.  The lower 64 bits
+   of the resulting MD5 checksum comprise the signature.  */
+
+static void
+generate_type_signature (dw_die_ref die, comdat_type_node *type_node)
 {
-  print_die (die, stderr);
-}
+  int mark;
+  const char *name;
+  unsigned char checksum[16];
+  struct md5_ctx ctx;
+  dw_die_ref decl;
 
-/* Print all DWARF information collected for the compilation unit.
-   This routine is a debugging aid only.  */
+  name = get_AT_string (die, DW_AT_name);
+  decl = get_AT_ref (die, DW_AT_specification);
 
-void
-debug_dwarf (void)
-{
-  print_indent = 0;
-  print_die (comp_unit_die, stderr);
-  if (! DWARF2_ASM_LINE_DEBUG_INFO)
-    print_dwarf_line_table (stderr);
-}
-\f
-/* Start a new compilation unit DIE for an include file.  OLD_UNIT is the CU
-   for the enclosing include file, if any.  BINCL_DIE is the DW_TAG_GNU_BINCL
-   DIE that marks the start of the DIEs for this include file.  */
+  /* First, compute a signature for just the type name (and its surrounding
+     context, if any.  This is stored in the type unit DIE for link-time
+     ODR (one-definition rule) checking.  */
 
-static dw_die_ref
-push_new_compile_unit (dw_die_ref old_unit, dw_die_ref bincl_die)
-{
-  const char *filename = get_AT_string (bincl_die, DW_AT_name);
-  dw_die_ref new_unit = gen_compile_unit_die (filename);
+  if (is_cxx() && name != NULL)
+    {
+      md5_init_ctx (&ctx);
 
-  new_unit->die_sib = old_unit;
-  return new_unit;
-}
+      /* Checksum the names of surrounding namespaces and structures.  */
+      if (decl != NULL && decl->die_parent != NULL)
+        checksum_die_context (decl->die_parent, &ctx);
 
-/* Close an include-file CU and reopen the enclosing one.  */
+      md5_process_bytes (&die->die_tag, sizeof (die->die_tag), &ctx);
+      md5_process_bytes (name, strlen (name) + 1, &ctx);
+      md5_finish_ctx (&ctx, checksum);
 
-static dw_die_ref
-pop_compile_unit (dw_die_ref old_unit)
-{
-  dw_die_ref new_unit = old_unit->die_sib;
+      add_AT_data8 (type_node->root_die, DW_AT_GNU_odr_signature, &checksum[8]);
+    }
 
-  old_unit->die_sib = NULL;
-  return new_unit;
-}
+  /* Next, compute the complete type signature.  */
 
-#define CHECKSUM(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx)
-#define CHECKSUM_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO), ctx)
+  md5_init_ctx (&ctx);
+  mark = 1;
+  die->die_mark = mark;
 
-/* Calculate the checksum of a location expression.  */
+  /* Checksum the names of surrounding namespaces and structures.  */
+  if (decl != NULL && decl->die_parent != NULL)
+    checksum_die_context (decl->die_parent, &ctx);
 
-static inline void
-loc_checksum (dw_loc_descr_ref loc, struct md5_ctx *ctx)
-{
-  int tem;
+  /* Checksum the DIE and its children.  */
+  die_checksum_ordered (die, &ctx, &mark);
+  unmark_all_dies (die);
+  md5_finish_ctx (&ctx, checksum);
 
-  tem = (loc->dtprel << 8) | ((unsigned int) loc->dw_loc_opc);
-  CHECKSUM (tem);
-  CHECKSUM (loc->dw_loc_oprnd1);
-  CHECKSUM (loc->dw_loc_oprnd2);
-}
+  /* Store the signature in the type node and link the type DIE and the
+     type node together.  */
+  memcpy (type_node->signature, &checksum[16 - DWARF_TYPE_SIGNATURE_SIZE],
+          DWARF_TYPE_SIGNATURE_SIZE);
+  die->die_id.die_type_node = type_node;
+  type_node->type_die = die;
 
-/* Calculate the checksum of an attribute.  */
+  /* If the DIE is a specification, link its declaration to the type node
+     as well.  */
+  if (decl != NULL)
+    decl->die_id.die_type_node = type_node;
+}
 
-static void
-attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
+/* Do the location expressions look same?  */
+static inline int
+same_loc_p (dw_loc_descr_ref loc1, dw_loc_descr_ref loc2, int *mark)
 {
-  dw_loc_descr_ref loc;
-  rtx r;
+  return loc1->dw_loc_opc == loc2->dw_loc_opc
+        && same_dw_val_p (&loc1->dw_loc_oprnd1, &loc2->dw_loc_oprnd1, mark)
+        && same_dw_val_p (&loc1->dw_loc_oprnd2, &loc2->dw_loc_oprnd2, mark);
+}
 
-  CHECKSUM (at->dw_attr);
+/* Do the values look the same?  */
+static int
+same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
+{
+  dw_loc_descr_ref loc1, loc2;
+  rtx r1, r2;
 
-  /* We don't care that this was compiled with a different compiler
-     snapshot; if the output is the same, that's what matters.  */
-  if (at->dw_attr == DW_AT_producer)
-    return;
+  if (v1->val_class != v2->val_class)
+    return 0;
 
-  switch (AT_class (at))
+  switch (v1->val_class)
     {
     case dw_val_class_const:
-      CHECKSUM (at->dw_attr_val.v.val_int);
-      break;
+      return v1->v.val_int == v2->v.val_int;
     case dw_val_class_unsigned_const:
-      CHECKSUM (at->dw_attr_val.v.val_unsigned);
-      break;
+      return v1->v.val_unsigned == v2->v.val_unsigned;
     case dw_val_class_const_double:
-      CHECKSUM (at->dw_attr_val.v.val_double);
-      break;
+      return v1->v.val_double.high == v2->v.val_double.high
+            && v1->v.val_double.low == v2->v.val_double.low;
     case dw_val_class_vec:
-      CHECKSUM (at->dw_attr_val.v.val_vec);
-      break;
+      if (v1->v.val_vec.length != v2->v.val_vec.length
+         || v1->v.val_vec.elt_size != v2->v.val_vec.elt_size)
+       return 0;
+      if (memcmp (v1->v.val_vec.array, v2->v.val_vec.array,
+                 v1->v.val_vec.length * v1->v.val_vec.elt_size))
+       return 0;
+      return 1;
     case dw_val_class_flag:
-      CHECKSUM (at->dw_attr_val.v.val_flag);
-      break;
+      return v1->v.val_flag == v2->v.val_flag;
     case dw_val_class_str:
-      CHECKSUM_STRING (AT_string (at));
-      break;
+      return !strcmp(v1->v.val_str->str, v2->v.val_str->str);
 
     case dw_val_class_addr:
-      r = AT_addr (at);
-      gcc_assert (GET_CODE (r) == SYMBOL_REF);
-      CHECKSUM_STRING (XSTR (r, 0));
-      break;
+      r1 = v1->v.val_addr;
+      r2 = v2->v.val_addr;
+      if (GET_CODE (r1) != GET_CODE (r2))
+       return 0;
+      return !rtx_equal_p (r1, r2);
 
     case dw_val_class_offset:
-      CHECKSUM (at->dw_attr_val.v.val_offset);
-      break;
+      return v1->v.val_offset == v2->v.val_offset;
 
     case dw_val_class_loc:
-      for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
-       loc_checksum (loc, ctx);
-      break;
+      for (loc1 = v1->v.val_loc, loc2 = v2->v.val_loc;
+          loc1 && loc2;
+          loc1 = loc1->dw_loc_next, loc2 = loc2->dw_loc_next)
+       if (!same_loc_p (loc1, loc2, mark))
+         return 0;
+      return !loc1 && !loc2;
 
     case dw_val_class_die_ref:
-      die_checksum (AT_ref (at), ctx, mark);
-      break;
+      return same_die_p (v1->v.val_die_ref.die, v2->v.val_die_ref.die, mark);
 
     case dw_val_class_fde_ref:
+    case dw_val_class_vms_delta:
     case dw_val_class_lbl_id:
     case dw_val_class_lineptr:
     case dw_val_class_macptr:
-      break;
+      return 1;
 
     case dw_val_class_file:
-      CHECKSUM_STRING (AT_file (at)->filename);
-      break;
+      return v1->v.val_file == v2->v.val_file;
 
     case dw_val_class_data8:
-      CHECKSUM (at->dw_attr_val.v.val_data8);
-      break;
+      return !memcmp (v1->v.val_data8, v2->v.val_data8, 8);
 
     default:
-      break;
+      return 1;
     }
 }
 
-/* Calculate the checksum of a DIE.  */
+/* Do the attributes look the same?  */
 
-static void
-die_checksum (dw_die_ref die, struct md5_ctx *ctx, int *mark)
+static int
+same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark)
 {
-  dw_die_ref c;
-  dw_attr_ref a;
-  unsigned ix;
-
-  /* To avoid infinite recursion.  */
-  if (die->die_mark)
-    {
-      CHECKSUM (die->die_mark);
-      return;
-    }
-  die->die_mark = ++(*mark);
-
-  CHECKSUM (die->die_tag);
+  if (at1->dw_attr != at2->dw_attr)
+    return 0;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    attr_checksum (a, ctx, mark);
+  /* We don't care that this was compiled with a different compiler
+     snapshot; if the output is the same, that's what matters. */
+  if (at1->dw_attr == DW_AT_producer)
+    return 1;
 
-  FOR_EACH_CHILD (die, c, die_checksum (c, ctx, mark));
+  return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark);
 }
 
-#undef CHECKSUM
-#undef CHECKSUM_STRING
+/* Do the dies look the same?  */
 
-/* For DWARF-4 types, include the trailing NULL when checksumming strings.  */
-#define CHECKSUM(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx)
-#define CHECKSUM_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO) + 1, ctx)
-#define CHECKSUM_SLEB128(FOO) checksum_sleb128 ((FOO), ctx)
-#define CHECKSUM_ULEB128(FOO) checksum_uleb128 ((FOO), ctx)
-#define CHECKSUM_ATTR(FOO) \
-  if (FOO) attr_checksum_ordered (die->die_tag, (FOO), ctx, mark)
+static int
+same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
+{
+  dw_die_ref c1, c2;
+  dw_attr_ref a1;
+  unsigned ix;
 
-/* Calculate the checksum of a number in signed LEB128 format.  */
+  /* To avoid infinite recursion.  */
+  if (die1->die_mark)
+    return die1->die_mark == die2->die_mark;
+  die1->die_mark = die2->die_mark = ++(*mark);
 
-static void
-checksum_sleb128 (HOST_WIDE_INT value, struct md5_ctx *ctx)
-{
-  unsigned char byte;
-  bool more;
+  if (die1->die_tag != die2->die_tag)
+    return 0;
 
-  while (1)
-    {
-      byte = (value & 0x7f);
-      value >>= 7;
-      more = !((value == 0 && (byte & 0x40) == 0)
-               || (value == -1 && (byte & 0x40) != 0));
-      if (more)
-       byte |= 0x80;
-      CHECKSUM (byte);
-      if (!more)
-       break;
-    }
-}
+  if (VEC_length (dw_attr_node, die1->die_attr)
+      != VEC_length (dw_attr_node, die2->die_attr))
+    return 0;
 
-/* Calculate the checksum of a number in unsigned LEB128 format.  */
+  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;
 
-static void
-checksum_uleb128 (unsigned HOST_WIDE_INT value, struct md5_ctx *ctx)
-{
-  while (1)
+  c1 = die1->die_child;
+  c2 = die2->die_child;
+  if (! c1)
     {
-      unsigned char byte = (value & 0x7f);
-      value >>= 7;
-      if (value != 0)
-       /* More bytes to follow.  */
-       byte |= 0x80;
-      CHECKSUM (byte);
-      if (value == 0)
-       break;
+      if (c2)
+       return 0;
     }
+  else
+    for (;;)
+      {
+       if (!same_die_p (c1, c2, mark))
+         return 0;
+       c1 = c1->die_sib;
+       c2 = c2->die_sib;
+       if (c1 == die1->die_child)
+         {
+           if (c2 == die2->die_child)
+             break;
+           else
+             return 0;
+         }
+    }
+
+  return 1;
 }
 
-/* Checksum the context of the DIE.  This adds the names of any
-   surrounding namespaces or structures to the checksum.  */
+/* Do the dies look the same?  Wrapper around same_die_p.  */
 
-static void
-checksum_die_context (dw_die_ref die, struct md5_ctx *ctx)
+static int
+same_die_p_wrap (dw_die_ref die1, dw_die_ref die2)
 {
-  const char *name;
-  dw_die_ref spec;
-  int tag = die->die_tag;
-
-  if (tag != DW_TAG_namespace
-      && tag != DW_TAG_structure_type
-      && tag != DW_TAG_class_type)
-    return;
+  int mark = 0;
+  int ret = same_die_p (die1, die2, &mark);
 
-  name = get_AT_string (die, DW_AT_name);
+  unmark_all_dies (die1);
+  unmark_all_dies (die2);
 
-  spec = get_AT_ref (die, DW_AT_specification);
-  if (spec != NULL)
-    die = spec;
+  return ret;
+}
 
-  if (die->die_parent != NULL)
-    checksum_die_context (die->die_parent, ctx);
+/* The prefix to attach to symbols on DIEs in the current comdat debug
+   info section.  */
+static char *comdat_symbol_id;
 
-  CHECKSUM_ULEB128 ('C');
-  CHECKSUM_ULEB128 (tag);
-  if (name != NULL)
-    CHECKSUM_STRING (name);
-}
+/* The index of the current symbol within the current comdat CU.  */
+static unsigned int comdat_symbol_number;
 
-/* Calculate the checksum of a location expression.  */
+/* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its
+   children, and set comdat_symbol_id accordingly.  */
 
-static inline void
-loc_checksum_ordered (dw_loc_descr_ref loc, struct md5_ctx *ctx)
+static void
+compute_section_prefix (dw_die_ref unit_die)
 {
-  /* Special case for lone DW_OP_plus_uconst: checksum as if the location
-     were emitted as a DW_FORM_sdata instead of a location expression.  */
-  if (loc->dw_loc_opc == DW_OP_plus_uconst && loc->dw_loc_next == NULL)
-    {
-      CHECKSUM_ULEB128 (DW_FORM_sdata);
-      CHECKSUM_SLEB128 ((HOST_WIDE_INT) loc->dw_loc_oprnd1.v.val_unsigned);
-      return;
-    }
+  const char *die_name = get_AT_string (unit_die, DW_AT_name);
+  const char *base = die_name ? lbasename (die_name) : "anonymous";
+  char *name = XALLOCAVEC (char, strlen (base) + 64);
+  char *p;
+  int i, mark;
+  unsigned char checksum[16];
+  struct md5_ctx ctx;
 
-  /* Otherwise, just checksum the raw location expression.  */
-  while (loc != NULL)
-    {
-      CHECKSUM_ULEB128 (loc->dw_loc_opc);
-      CHECKSUM (loc->dw_loc_oprnd1);
-      CHECKSUM (loc->dw_loc_oprnd2);
-      loc = loc->dw_loc_next;
-    }
-}
+  /* Compute the checksum of the DIE, then append part of it as hex digits to
+     the name filename of the unit.  */
 
-/* Calculate the checksum of an attribute.  */
+  md5_init_ctx (&ctx);
+  mark = 0;
+  die_checksum (unit_die, &ctx, &mark);
+  unmark_all_dies (unit_die);
+  md5_finish_ctx (&ctx, checksum);
 
-static void
-attr_checksum_ordered (enum dwarf_tag tag, dw_attr_ref at,
-                      struct md5_ctx *ctx, int *mark)
-{
-  dw_loc_descr_ref loc;
-  rtx r;
+  sprintf (name, "%s.", base);
+  clean_symbol_name (name);
 
-  if (AT_class (at) == dw_val_class_die_ref)
+  p = name + strlen (name);
+  for (i = 0; i < 4; i++)
     {
-      dw_die_ref target_die = AT_ref (at);
+      sprintf (p, "%.2x", checksum[i]);
+      p += 2;
+    }
 
-      /* For pointer and reference types, we checksum only the (qualified)
-        name of the target type (if there is a name).  For friend entries,
-        we checksum only the (qualified) name of the target type or function.
-        This allows the checksum to remain the same whether the target type
-        is complete or not.  */
-      if ((at->dw_attr == DW_AT_type
-          && (tag == DW_TAG_pointer_type
-              || tag == DW_TAG_reference_type
-              || tag == DW_TAG_rvalue_reference_type
-              || tag == DW_TAG_ptr_to_member_type))
-         || (at->dw_attr == DW_AT_friend
-             && tag == DW_TAG_friend))
-       {
-         dw_attr_ref name_attr = get_AT (target_die, DW_AT_name);
+  comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
+  comdat_symbol_number = 0;
+}
 
-         if (name_attr != NULL)
-           {
-             dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification);
+/* Returns nonzero if DIE represents a type, in the sense of TYPE_P.  */
 
-             if (decl == NULL)
-               decl = target_die;
-             CHECKSUM_ULEB128 ('N');
-             CHECKSUM_ULEB128 (at->dw_attr);
-             if (decl->die_parent != NULL)
-               checksum_die_context (decl->die_parent, ctx);
-             CHECKSUM_ULEB128 ('E');
-             CHECKSUM_STRING (AT_string (name_attr));
-             return;
-           }
-       }
+static int
+is_type_die (dw_die_ref die)
+{
+  switch (die->die_tag)
+    {
+    case DW_TAG_array_type:
+    case DW_TAG_class_type:
+    case DW_TAG_interface_type:
+    case DW_TAG_enumeration_type:
+    case DW_TAG_pointer_type:
+    case DW_TAG_reference_type:
+    case DW_TAG_rvalue_reference_type:
+    case DW_TAG_string_type:
+    case DW_TAG_structure_type:
+    case DW_TAG_subroutine_type:
+    case DW_TAG_union_type:
+    case DW_TAG_ptr_to_member_type:
+    case DW_TAG_set_type:
+    case DW_TAG_subrange_type:
+    case DW_TAG_base_type:
+    case DW_TAG_const_type:
+    case DW_TAG_file_type:
+    case DW_TAG_packed_type:
+    case DW_TAG_volatile_type:
+    case DW_TAG_typedef:
+      return 1;
+    default:
+      return 0;
+    }
+}
 
-      /* For all other references to another DIE, we check to see if the
-         target DIE has already been visited.  If it has, we emit a
-         backward reference; if not, we descend recursively.  */
-      if (target_die->die_mark > 0)
-        {
-         CHECKSUM_ULEB128 ('R');
-         CHECKSUM_ULEB128 (at->dw_attr);
-         CHECKSUM_ULEB128 (target_die->die_mark);
-        }
-      else
-        {
-         dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification);
+/* Returns 1 iff C is the sort of DIE that should go into a COMDAT CU.
+   Basically, we want to choose the bits that are likely to be shared between
+   compilations (types) and leave out the bits that are specific to individual
+   compilations (functions).  */
 
-         if (decl == NULL)
-           decl = target_die;
-         target_die->die_mark = ++(*mark);
-         CHECKSUM_ULEB128 ('T');
-         CHECKSUM_ULEB128 (at->dw_attr);
-         if (decl->die_parent != NULL)
-           checksum_die_context (decl->die_parent, ctx);
-         die_checksum_ordered (target_die, ctx, mark);
-        }
-      return;
-    }
+static int
+is_comdat_die (dw_die_ref c)
+{
+  /* I think we want to leave base types and __vtbl_ptr_type in the main CU, as
+     we do for stabs.  The advantage is a greater likelihood of sharing between
+     objects that don't include headers in the same order (and therefore would
+     put the base types in a different comdat).  jason 8/28/00 */
 
-  CHECKSUM_ULEB128 ('A');
-  CHECKSUM_ULEB128 (at->dw_attr);
+  if (c->die_tag == DW_TAG_base_type)
+    return 0;
 
-  switch (AT_class (at))
+  if (c->die_tag == DW_TAG_pointer_type
+      || c->die_tag == DW_TAG_reference_type
+      || c->die_tag == DW_TAG_rvalue_reference_type
+      || c->die_tag == DW_TAG_const_type
+      || c->die_tag == DW_TAG_volatile_type)
     {
-    case dw_val_class_const:
-      CHECKSUM_ULEB128 (DW_FORM_sdata);
-      CHECKSUM_SLEB128 (at->dw_attr_val.v.val_int);
-      break;
+      dw_die_ref t = get_AT_ref (c, DW_AT_type);
 
-    case dw_val_class_unsigned_const:
-      CHECKSUM_ULEB128 (DW_FORM_sdata);
-      CHECKSUM_SLEB128 ((int) at->dw_attr_val.v.val_unsigned);
-      break;
+      return t ? is_comdat_die (t) : 0;
+    }
 
-    case dw_val_class_const_double:
-      CHECKSUM_ULEB128 (DW_FORM_block);
-      CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_double));
-      CHECKSUM (at->dw_attr_val.v.val_double);
-      break;
+  return is_type_die (c);
+}
 
-    case dw_val_class_vec:
-      CHECKSUM_ULEB128 (DW_FORM_block);
-      CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_vec));
-      CHECKSUM (at->dw_attr_val.v.val_vec);
-      break;
+/* Returns 1 iff C is the sort of DIE that might be referred to from another
+   compilation unit.  */
 
-    case dw_val_class_flag:
-      CHECKSUM_ULEB128 (DW_FORM_flag);
-      CHECKSUM_ULEB128 (at->dw_attr_val.v.val_flag ? 1 : 0);
-      break;
+static int
+is_symbol_die (dw_die_ref c)
+{
+  return (is_type_die (c)
+         || is_declaration_die (c)
+         || c->die_tag == DW_TAG_namespace
+         || c->die_tag == DW_TAG_module);
+}
 
-    case dw_val_class_str:
-      CHECKSUM_ULEB128 (DW_FORM_string);
-      CHECKSUM_STRING (AT_string (at));
-      break;
+/* Returns true iff C is a compile-unit DIE.  */
 
-    case dw_val_class_addr:
-      r = AT_addr (at);
-      gcc_assert (GET_CODE (r) == SYMBOL_REF);
-      CHECKSUM_ULEB128 (DW_FORM_string);
-      CHECKSUM_STRING (XSTR (r, 0));
-      break;
+static inline bool
+is_cu_die (dw_die_ref c)
+{
+  return c && c->die_tag == DW_TAG_compile_unit;
+}
 
-    case dw_val_class_offset:
-      CHECKSUM_ULEB128 (DW_FORM_sdata);
-      CHECKSUM_ULEB128 (at->dw_attr_val.v.val_offset);
-      break;
+static char *
+gen_internal_sym (const char *prefix)
+{
+  char buf[256];
 
-    case dw_val_class_loc:
-      for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
-       loc_checksum_ordered (loc, ctx);
-      break;
+  ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++);
+  return xstrdup (buf);
+}
 
-    case dw_val_class_fde_ref:
-    case dw_val_class_lbl_id:
-    case dw_val_class_lineptr:
-    case dw_val_class_macptr:
-      break;
+/* Assign symbols to all worthy DIEs under DIE.  */
 
-    case dw_val_class_file:
-      CHECKSUM_ULEB128 (DW_FORM_string);
-      CHECKSUM_STRING (AT_file (at)->filename);
-      break;
+static void
+assign_symbol_names (dw_die_ref die)
+{
+  dw_die_ref c;
 
-    case dw_val_class_data8:
-      CHECKSUM (at->dw_attr_val.v.val_data8);
-      break;
+  if (is_symbol_die (die))
+    {
+      if (comdat_symbol_id)
+       {
+         char *p = XALLOCAVEC (char, strlen (comdat_symbol_id) + 64);
 
-    default:
-      break;
+         sprintf (p, "%s.%s.%x", DIE_LABEL_PREFIX,
+                  comdat_symbol_id, comdat_symbol_number++);
+         die->die_id.die_symbol = xstrdup (p);
+       }
+      else
+       die->die_id.die_symbol = gen_internal_sym ("LDIE");
     }
+
+  FOR_EACH_CHILD (die, c, assign_symbol_names (c));
 }
 
-struct checksum_attributes
+struct cu_hash_table_entry
 {
-  dw_attr_ref at_name;
-  dw_attr_ref at_type;
-  dw_attr_ref at_friend;
-  dw_attr_ref at_accessibility;
-  dw_attr_ref at_address_class;
-  dw_attr_ref at_allocated;
-  dw_attr_ref at_artificial;
-  dw_attr_ref at_associated;
-  dw_attr_ref at_binary_scale;
-  dw_attr_ref at_bit_offset;
-  dw_attr_ref at_bit_size;
-  dw_attr_ref at_bit_stride;
-  dw_attr_ref at_byte_size;
-  dw_attr_ref at_byte_stride;
-  dw_attr_ref at_const_value;
-  dw_attr_ref at_containing_type;
-  dw_attr_ref at_count;
-  dw_attr_ref at_data_location;
-  dw_attr_ref at_data_member_location;
-  dw_attr_ref at_decimal_scale;
-  dw_attr_ref at_decimal_sign;
-  dw_attr_ref at_default_value;
-  dw_attr_ref at_digit_count;
-  dw_attr_ref at_discr;
-  dw_attr_ref at_discr_list;
-  dw_attr_ref at_discr_value;
-  dw_attr_ref at_encoding;
-  dw_attr_ref at_endianity;
-  dw_attr_ref at_explicit;
-  dw_attr_ref at_is_optional;
-  dw_attr_ref at_location;
-  dw_attr_ref at_lower_bound;
-  dw_attr_ref at_mutable;
-  dw_attr_ref at_ordering;
-  dw_attr_ref at_picture_string;
-  dw_attr_ref at_prototyped;
-  dw_attr_ref at_small;
-  dw_attr_ref at_segment;
-  dw_attr_ref at_string_length;
-  dw_attr_ref at_threads_scaled;
-  dw_attr_ref at_upper_bound;
-  dw_attr_ref at_use_location;
-  dw_attr_ref at_use_UTF8;
-  dw_attr_ref at_variable_parameter;
-  dw_attr_ref at_virtuality;
-  dw_attr_ref at_visibility;
-  dw_attr_ref at_vtable_elem_location;
+  dw_die_ref cu;
+  unsigned min_comdat_num, max_comdat_num;
+  struct cu_hash_table_entry *next;
 };
 
-/* Collect the attributes that we will want to use for the checksum.  */
-
-static void
-collect_checksum_attributes (struct checksum_attributes *attrs, dw_die_ref die)
+/* Routines to manipulate hash table of CUs.  */
+static hashval_t
+htab_cu_hash (const void *of)
 {
-  dw_attr_ref a;
-  unsigned ix;
+  const struct cu_hash_table_entry *const entry =
+    (const struct cu_hash_table_entry *) of;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    {
-      switch (a->dw_attr)
-        {
-        case DW_AT_name:
-          attrs->at_name = a;
-          break;
-        case DW_AT_type:
-          attrs->at_type = a;
-          break;
-        case DW_AT_friend:
-          attrs->at_friend = a;
-          break;
-        case DW_AT_accessibility:
-          attrs->at_accessibility = a;
-          break;
-        case DW_AT_address_class:
-          attrs->at_address_class = a;
-          break;
-        case DW_AT_allocated:
-          attrs->at_allocated = a;
-          break;
-        case DW_AT_artificial:
-          attrs->at_artificial = a;
-          break;
-        case DW_AT_associated:
-          attrs->at_associated = a;
-          break;
-        case DW_AT_binary_scale:
-          attrs->at_binary_scale = a;
-          break;
-        case DW_AT_bit_offset:
-          attrs->at_bit_offset = a;
-          break;
-        case DW_AT_bit_size:
-          attrs->at_bit_size = a;
-          break;
-        case DW_AT_bit_stride:
-          attrs->at_bit_stride = a;
-          break;
-        case DW_AT_byte_size:
-          attrs->at_byte_size = a;
-          break;
-        case DW_AT_byte_stride:
-          attrs->at_byte_stride = a;
-          break;
-        case DW_AT_const_value:
-          attrs->at_const_value = a;
-          break;
-        case DW_AT_containing_type:
-          attrs->at_containing_type = a;
-          break;
-        case DW_AT_count:
-          attrs->at_count = a;
-          break;
-        case DW_AT_data_location:
-          attrs->at_data_location = a;
-          break;
-        case DW_AT_data_member_location:
-          attrs->at_data_member_location = a;
-          break;
-        case DW_AT_decimal_scale:
-          attrs->at_decimal_scale = a;
-          break;
-        case DW_AT_decimal_sign:
-          attrs->at_decimal_sign = a;
-          break;
-        case DW_AT_default_value:
-          attrs->at_default_value = a;
-          break;
-        case DW_AT_digit_count:
-          attrs->at_digit_count = a;
-          break;
-        case DW_AT_discr:
-          attrs->at_discr = a;
-          break;
-        case DW_AT_discr_list:
-          attrs->at_discr_list = a;
-          break;
-        case DW_AT_discr_value:
-          attrs->at_discr_value = a;
-          break;
-        case DW_AT_encoding:
-          attrs->at_encoding = a;
-          break;
-        case DW_AT_endianity:
-          attrs->at_endianity = a;
-          break;
-        case DW_AT_explicit:
-          attrs->at_explicit = a;
-          break;
-        case DW_AT_is_optional:
-          attrs->at_is_optional = a;
-          break;
-        case DW_AT_location:
-          attrs->at_location = a;
-          break;
-        case DW_AT_lower_bound:
-          attrs->at_lower_bound = a;
-          break;
-        case DW_AT_mutable:
-          attrs->at_mutable = a;
-          break;
-        case DW_AT_ordering:
-          attrs->at_ordering = a;
-          break;
-        case DW_AT_picture_string:
-          attrs->at_picture_string = a;
-          break;
-        case DW_AT_prototyped:
-          attrs->at_prototyped = a;
-          break;
-        case DW_AT_small:
-          attrs->at_small = a;
-          break;
-        case DW_AT_segment:
-          attrs->at_segment = a;
-          break;
-        case DW_AT_string_length:
-          attrs->at_string_length = a;
-          break;
-        case DW_AT_threads_scaled:
-          attrs->at_threads_scaled = a;
-          break;
-        case DW_AT_upper_bound:
-          attrs->at_upper_bound = a;
-          break;
-        case DW_AT_use_location:
-          attrs->at_use_location = a;
-          break;
-        case DW_AT_use_UTF8:
-          attrs->at_use_UTF8 = a;
-          break;
-        case DW_AT_variable_parameter:
-          attrs->at_variable_parameter = a;
-          break;
-        case DW_AT_virtuality:
-          attrs->at_virtuality = a;
-          break;
-        case DW_AT_visibility:
-          attrs->at_visibility = a;
-          break;
-        case DW_AT_vtable_elem_location:
-          attrs->at_vtable_elem_location = a;
-          break;
-        default:
-          break;
-        }
-    }
+  return htab_hash_string (entry->cu->die_id.die_symbol);
 }
 
-/* Calculate the checksum of a DIE, using an ordered subset of attributes.  */
+static int
+htab_cu_eq (const void *of1, const void *of2)
+{
+  const struct cu_hash_table_entry *const entry1 =
+    (const struct cu_hash_table_entry *) of1;
+  const struct die_struct *const entry2 = (const struct die_struct *) of2;
+
+  return !strcmp (entry1->cu->die_id.die_symbol, entry2->die_id.die_symbol);
+}
 
 static void
-die_checksum_ordered (dw_die_ref die, struct md5_ctx *ctx, int *mark)
+htab_cu_del (void *what)
 {
-  dw_die_ref c;
-  dw_die_ref decl;
-  struct checksum_attributes attrs;
-
-  CHECKSUM_ULEB128 ('D');
-  CHECKSUM_ULEB128 (die->die_tag);
+  struct cu_hash_table_entry *next,
+    *entry = (struct cu_hash_table_entry *) what;
 
-  memset (&attrs, 0, sizeof (attrs));
+  while (entry)
+    {
+      next = entry->next;
+      free (entry);
+      entry = next;
+    }
+}
 
-  decl = get_AT_ref (die, DW_AT_specification);
-  if (decl != NULL)
-    collect_checksum_attributes (&attrs, decl);
-  collect_checksum_attributes (&attrs, die);
+/* Check whether we have already seen this CU and set up SYM_NUM
+   accordingly.  */
+static int
+check_duplicate_cu (dw_die_ref cu, htab_t htable, unsigned int *sym_num)
+{
+  struct cu_hash_table_entry dummy;
+  struct cu_hash_table_entry **slot, *entry, *last = &dummy;
 
-  CHECKSUM_ATTR (attrs.at_name);
-  CHECKSUM_ATTR (attrs.at_accessibility);
-  CHECKSUM_ATTR (attrs.at_address_class);
-  CHECKSUM_ATTR (attrs.at_allocated);
-  CHECKSUM_ATTR (attrs.at_artificial);
-  CHECKSUM_ATTR (attrs.at_associated);
-  CHECKSUM_ATTR (attrs.at_binary_scale);
-  CHECKSUM_ATTR (attrs.at_bit_offset);
-  CHECKSUM_ATTR (attrs.at_bit_size);
-  CHECKSUM_ATTR (attrs.at_bit_stride);
-  CHECKSUM_ATTR (attrs.at_byte_size);
-  CHECKSUM_ATTR (attrs.at_byte_stride);
-  CHECKSUM_ATTR (attrs.at_const_value);
-  CHECKSUM_ATTR (attrs.at_containing_type);
-  CHECKSUM_ATTR (attrs.at_count);
-  CHECKSUM_ATTR (attrs.at_data_location);
-  CHECKSUM_ATTR (attrs.at_data_member_location);
-  CHECKSUM_ATTR (attrs.at_decimal_scale);
-  CHECKSUM_ATTR (attrs.at_decimal_sign);
-  CHECKSUM_ATTR (attrs.at_default_value);
-  CHECKSUM_ATTR (attrs.at_digit_count);
-  CHECKSUM_ATTR (attrs.at_discr);
-  CHECKSUM_ATTR (attrs.at_discr_list);
-  CHECKSUM_ATTR (attrs.at_discr_value);
-  CHECKSUM_ATTR (attrs.at_encoding);
-  CHECKSUM_ATTR (attrs.at_endianity);
-  CHECKSUM_ATTR (attrs.at_explicit);
-  CHECKSUM_ATTR (attrs.at_is_optional);
-  CHECKSUM_ATTR (attrs.at_location);
-  CHECKSUM_ATTR (attrs.at_lower_bound);
-  CHECKSUM_ATTR (attrs.at_mutable);
-  CHECKSUM_ATTR (attrs.at_ordering);
-  CHECKSUM_ATTR (attrs.at_picture_string);
-  CHECKSUM_ATTR (attrs.at_prototyped);
-  CHECKSUM_ATTR (attrs.at_small);
-  CHECKSUM_ATTR (attrs.at_segment);
-  CHECKSUM_ATTR (attrs.at_string_length);
-  CHECKSUM_ATTR (attrs.at_threads_scaled);
-  CHECKSUM_ATTR (attrs.at_upper_bound);
-  CHECKSUM_ATTR (attrs.at_use_location);
-  CHECKSUM_ATTR (attrs.at_use_UTF8);
-  CHECKSUM_ATTR (attrs.at_variable_parameter);
-  CHECKSUM_ATTR (attrs.at_virtuality);
-  CHECKSUM_ATTR (attrs.at_visibility);
-  CHECKSUM_ATTR (attrs.at_vtable_elem_location);
-  CHECKSUM_ATTR (attrs.at_type);
-  CHECKSUM_ATTR (attrs.at_friend);
+  dummy.max_comdat_num = 0;
 
-  /* Checksum the child DIEs, except for nested types and member functions.  */
-  c = die->die_child;
-  if (c) do {
-    dw_attr_ref name_attr;
+  slot = (struct cu_hash_table_entry **)
+    htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_id.die_symbol),
+       INSERT);
+  entry = *slot;
 
-    c = c->die_sib;
-    name_attr = get_AT (c, DW_AT_name);
-    if ((is_type_die (c) || c->die_tag == DW_TAG_subprogram)
-        && name_attr != NULL)
-      {
-        CHECKSUM_ULEB128 ('S');
-        CHECKSUM_ULEB128 (c->die_tag);
-        CHECKSUM_STRING (AT_string (name_attr));
-      }
-    else
-      {
-        /* Mark this DIE so it gets processed when unmarking.  */
-        if (c->die_mark == 0)
-          c->die_mark = -1;
-        die_checksum_ordered (c, ctx, mark);
-      }
-  } while (c != die->die_child);
+  for (; entry; last = entry, entry = entry->next)
+    {
+      if (same_die_p_wrap (cu, entry->cu))
+       break;
+    }
 
-  CHECKSUM_ULEB128 (0);
-}
+  if (entry)
+    {
+      *sym_num = entry->min_comdat_num;
+      return 1;
+    }
 
-#undef CHECKSUM
-#undef CHECKSUM_STRING
-#undef CHECKSUM_ATTR
-#undef CHECKSUM_LEB128
-#undef CHECKSUM_ULEB128
+  entry = XCNEW (struct cu_hash_table_entry);
+  entry->cu = cu;
+  entry->min_comdat_num = *sym_num = last->max_comdat_num;
+  entry->next = *slot;
+  *slot = entry;
 
-/* Generate the type signature for DIE.  This is computed by generating an
-   MD5 checksum over the DIE's tag, its relevant attributes, and its
-   children.  Attributes that are references to other DIEs are processed
-   by recursion, using the MARK field to prevent infinite recursion.
-   If the DIE is nested inside a namespace or another type, we also
-   need to include that context in the signature.  The lower 64 bits
-   of the resulting MD5 checksum comprise the signature.  */
+  return 0;
+}
 
+/* Record SYM_NUM to record of CU in HTABLE.  */
 static void
-generate_type_signature (dw_die_ref die, comdat_type_node *type_node)
+record_comdat_symbol_number (dw_die_ref cu, htab_t htable, unsigned int sym_num)
 {
-  int mark;
-  const char *name;
-  unsigned char checksum[16];
-  struct md5_ctx ctx;
-  dw_die_ref decl;
+  struct cu_hash_table_entry **slot, *entry;
 
-  name = get_AT_string (die, DW_AT_name);
-  decl = get_AT_ref (die, DW_AT_specification);
+  slot = (struct cu_hash_table_entry **)
+    htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_id.die_symbol),
+       NO_INSERT);
+  entry = *slot;
 
-  /* First, compute a signature for just the type name (and its surrounding
-     context, if any.  This is stored in the type unit DIE for link-time
-     ODR (one-definition rule) checking.  */
+  entry->max_comdat_num = sym_num;
+}
 
-  if (is_cxx() && name != NULL)
-    {
-      md5_init_ctx (&ctx);
+/* Traverse the DIE (which is always comp_unit_die), and set up
+   additional compilation units for each of the include files we see
+   bracketed by BINCL/EINCL.  */
 
-      /* Checksum the names of surrounding namespaces and structures.  */
-      if (decl != NULL && decl->die_parent != NULL)
-        checksum_die_context (decl->die_parent, &ctx);
+static void
+break_out_includes (dw_die_ref die)
+{
+  dw_die_ref c;
+  dw_die_ref unit = NULL;
+  limbo_die_node *node, **pnode;
+  htab_t cu_hash_table;
 
-      md5_process_bytes (&die->die_tag, sizeof (die->die_tag), &ctx);
-      md5_process_bytes (name, strlen (name) + 1, &ctx);
-      md5_finish_ctx (&ctx, checksum);
+  c = die->die_child;
+  if (c) do {
+    dw_die_ref prev = c;
+    c = c->die_sib;
+    while (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL
+          || (unit && is_comdat_die (c)))
+      {
+       dw_die_ref next = c->die_sib;
 
-      add_AT_data8 (type_node->root_die, DW_AT_GNU_odr_signature, &checksum[8]);
-    }
+       /* This DIE is for a secondary CU; remove it from the main one.  */
+       remove_child_with_prev (c, prev);
 
-  /* Next, compute the complete type signature.  */
+       if (c->die_tag == DW_TAG_GNU_BINCL)
+         unit = push_new_compile_unit (unit, c);
+       else if (c->die_tag == DW_TAG_GNU_EINCL)
+         unit = pop_compile_unit (unit);
+       else
+         add_child_die (unit, c);
+       c = next;
+       if (c == die->die_child)
+         break;
+      }
+  } while (c != die->die_child);
 
-  md5_init_ctx (&ctx);
-  mark = 1;
-  die->die_mark = mark;
+#if 0
+  /* We can only use this in debugging, since the frontend doesn't check
+     to make sure that we leave every include file we enter.  */
+  gcc_assert (!unit);
+#endif
 
-  /* Checksum the names of surrounding namespaces and structures.  */
-  if (decl != NULL && decl->die_parent != NULL)
-    checksum_die_context (decl->die_parent, &ctx);
+  assign_symbol_names (die);
+  cu_hash_table = htab_create (10, htab_cu_hash, htab_cu_eq, htab_cu_del);
+  for (node = limbo_die_list, pnode = &limbo_die_list;
+       node;
+       node = node->next)
+    {
+      int is_dupl;
 
-  /* Checksum the DIE and its children.  */
-  die_checksum_ordered (die, &ctx, &mark);
-  unmark_all_dies (die);
-  md5_finish_ctx (&ctx, checksum);
+      compute_section_prefix (node->die);
+      is_dupl = check_duplicate_cu (node->die, cu_hash_table,
+                       &comdat_symbol_number);
+      assign_symbol_names (node->die);
+      if (is_dupl)
+       *pnode = node->next;
+      else
+       {
+         pnode = &node->next;
+         record_comdat_symbol_number (node->die, cu_hash_table,
+               comdat_symbol_number);
+       }
+    }
+  htab_delete (cu_hash_table);
+}
 
-  /* Store the signature in the type node and link the type DIE and the
-     type node together.  */
-  memcpy (type_node->signature, &checksum[16 - DWARF_TYPE_SIGNATURE_SIZE],
-          DWARF_TYPE_SIGNATURE_SIZE);
-  die->die_id.die_type_node = type_node;
-  type_node->type_die = die;
+/* Return non-zero if this DIE is a declaration.  */
 
-  /* If the DIE is a specification, link its declaration to the type node
-     as well.  */
-  if (decl != NULL)
-    decl->die_id.die_type_node = type_node;
+static int
+is_declaration_die (dw_die_ref die)
+{
+  dw_attr_ref a;
+  unsigned ix;
+
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
+    if (a->dw_attr == DW_AT_declaration)
+      return 1;
+
+  return 0;
 }
 
-/* Do the location expressions look same?  */
-static inline int
-same_loc_p (dw_loc_descr_ref loc1, dw_loc_descr_ref loc2, int *mark)
+/* Return non-zero if this DIE is nested inside a subprogram.  */
+
+static int
+is_nested_in_subprogram (dw_die_ref die)
 {
-  return loc1->dw_loc_opc == loc2->dw_loc_opc
-        && same_dw_val_p (&loc1->dw_loc_oprnd1, &loc2->dw_loc_oprnd1, mark)
-        && same_dw_val_p (&loc1->dw_loc_oprnd2, &loc2->dw_loc_oprnd2, mark);
+  dw_die_ref decl = get_AT_ref (die, DW_AT_specification);
+
+  if (decl == NULL)
+    decl = die;
+  return local_scope_p (decl);
 }
 
-/* Do the values look the same?  */
+/* Return non-zero if this DIE contains a defining declaration of a
+   subprogram.  */
+
 static int
-same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
+contains_subprogram_definition (dw_die_ref die)
 {
-  dw_loc_descr_ref loc1, loc2;
-  rtx r1, r2;
+  dw_die_ref c;
 
-  if (v1->val_class != v2->val_class)
-    return 0;
+  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;
+}
 
-  switch (v1->val_class)
+/* Return non-zero if this is a type DIE that should be moved to a
+   COMDAT .debug_types section.  */
+
+static int
+should_move_die_to_comdat (dw_die_ref die)
+{
+  switch (die->die_tag)
     {
-    case dw_val_class_const:
-      return v1->v.val_int == v2->v.val_int;
-    case dw_val_class_unsigned_const:
-      return v1->v.val_unsigned == v2->v.val_unsigned;
-    case dw_val_class_const_double:
-      return v1->v.val_double.high == v2->v.val_double.high
-            && v1->v.val_double.low == v2->v.val_double.low;
-    case dw_val_class_vec:
-      if (v1->v.val_vec.length != v2->v.val_vec.length
-         || v1->v.val_vec.elt_size != v2->v.val_vec.elt_size)
-       return 0;
-      if (memcmp (v1->v.val_vec.array, v2->v.val_vec.array,
-                 v1->v.val_vec.length * v1->v.val_vec.elt_size))
-       return 0;
+    case DW_TAG_class_type:
+    case DW_TAG_structure_type:
+    case DW_TAG_enumeration_type:
+    case DW_TAG_union_type:
+      /* Don't move declarations, inlined instances, or types nested in a
+        subprogram.  */
+      if (is_declaration_die (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_val_class_flag:
-      return v1->v.val_flag == v2->v.val_flag;
-    case dw_val_class_str:
-      return !strcmp(v1->v.val_str->str, v2->v.val_str->str);
-
-    case dw_val_class_addr:
-      r1 = v1->v.val_addr;
-      r2 = v2->v.val_addr;
-      if (GET_CODE (r1) != GET_CODE (r2))
-       return 0;
-      return !rtx_equal_p (r1, r2);
-
-    case dw_val_class_offset:
-      return v1->v.val_offset == v2->v.val_offset;
-
-    case dw_val_class_loc:
-      for (loc1 = v1->v.val_loc, loc2 = v2->v.val_loc;
-          loc1 && loc2;
-          loc1 = loc1->dw_loc_next, loc2 = loc2->dw_loc_next)
-       if (!same_loc_p (loc1, loc2, mark))
-         return 0;
-      return !loc1 && !loc2;
+    case DW_TAG_array_type:
+    case DW_TAG_interface_type:
+    case DW_TAG_pointer_type:
+    case DW_TAG_reference_type:
+    case DW_TAG_rvalue_reference_type:
+    case DW_TAG_string_type:
+    case DW_TAG_subroutine_type:
+    case DW_TAG_ptr_to_member_type:
+    case DW_TAG_set_type:
+    case DW_TAG_subrange_type:
+    case DW_TAG_base_type:
+    case DW_TAG_const_type:
+    case DW_TAG_file_type:
+    case DW_TAG_packed_type:
+    case DW_TAG_volatile_type:
+    case DW_TAG_typedef:
+    default:
+      return 0;
+    }
+}
 
-    case dw_val_class_die_ref:
-      return same_die_p (v1->v.val_die_ref.die, v2->v.val_die_ref.die, mark);
+/* Make a clone of DIE.  */
 
-    case dw_val_class_fde_ref:
-    case dw_val_class_lbl_id:
-    case dw_val_class_lineptr:
-    case dw_val_class_macptr:
-      return 1;
+static dw_die_ref
+clone_die (dw_die_ref die)
+{
+  dw_die_ref clone;
+  dw_attr_ref a;
+  unsigned ix;
 
-    case dw_val_class_file:
-      return v1->v.val_file == v2->v.val_file;
+  clone = ggc_alloc_cleared_die_node ();
+  clone->die_tag = die->die_tag;
 
-    case dw_val_class_data8:
-      return !memcmp (v1->v.val_data8, v2->v.val_data8, 8);
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
+    add_dwarf_attr (clone, a);
 
-    default:
-      return 1;
-    }
+  return clone;
 }
 
-/* Do the attributes look the same?  */
+/* Make a clone of the tree rooted at DIE.  */
 
-static int
-same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark)
+static dw_die_ref
+clone_tree (dw_die_ref die)
 {
-  if (at1->dw_attr != at2->dw_attr)
-    return 0;
+  dw_die_ref c;
+  dw_die_ref clone = clone_die (die);
 
-  /* We don't care that this was compiled with a different compiler
-     snapshot; if the output is the same, that's what matters. */
-  if (at1->dw_attr == DW_AT_producer)
-    return 1;
+  FOR_EACH_CHILD (die, c, add_child_die (clone, clone_tree(c)));
 
-  return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark);
+  return clone;
 }
 
-/* Do the dies look the same?  */
+/* Make a clone of DIE as a declaration.  */
 
-static int
-same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
+static dw_die_ref
+clone_as_declaration (dw_die_ref die)
 {
-  dw_die_ref c1, c2;
-  dw_attr_ref a1;
+  dw_die_ref clone;
+  dw_die_ref decl;
+  dw_attr_ref a;
   unsigned ix;
 
-  /* To avoid infinite recursion.  */
-  if (die1->die_mark)
-    return die1->die_mark == die2->die_mark;
-  die1->die_mark = die2->die_mark = ++(*mark);
-
-  if (die1->die_tag != die2->die_tag)
-    return 0;
+  /* If the DIE is already a declaration, just clone it.  */
+  if (is_declaration_die (die))
+    return clone_die (die);
 
-  if (VEC_length (dw_attr_node, die1->die_attr)
-      != VEC_length (dw_attr_node, die2->die_attr))
-    return 0;
+  /* If the DIE is a specification, just clone its declaration DIE.  */
+  decl = get_AT_ref (die, DW_AT_specification);
+  if (decl != NULL)
+    return clone_die (decl);
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++)
-    if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark))
-      return 0;
+  clone = ggc_alloc_cleared_die_node ();
+  clone->die_tag = die->die_tag;
 
-  c1 = die1->die_child;
-  c2 = die2->die_child;
-  if (! c1)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     {
-      if (c2)
-       return 0;
+      /* We don't want to copy over all attributes.
+         For example we don't want DW_AT_byte_size because otherwise we will no
+         longer have a declaration and GDB will treat it as a definition.  */
+
+      switch (a->dw_attr)
+        {
+        case DW_AT_artificial:
+        case DW_AT_containing_type:
+        case DW_AT_external:
+        case DW_AT_name:
+        case DW_AT_type:
+        case DW_AT_virtuality:
+        case DW_AT_linkage_name:
+        case DW_AT_MIPS_linkage_name:
+          add_dwarf_attr (clone, a);
+          break;
+        case DW_AT_byte_size:
+        default:
+          break;
+        }
     }
+
+  if (die->die_id.die_type_node)
+    add_AT_die_ref (clone, DW_AT_signature, die);
+
+  add_AT_flag (clone, DW_AT_declaration, 1);
+  return clone;
+}
+
+/* Copy the declaration context to the new compile unit DIE.  This includes
+   any surrounding namespace or type declarations.  If the DIE has an
+   AT_specification attribute, it also includes attributes and children
+   attached to the specification.  */
+
+static void
+copy_declaration_context (dw_die_ref unit, dw_die_ref die)
+{
+  dw_die_ref decl;
+  dw_die_ref new_decl;
+
+  decl = get_AT_ref (die, DW_AT_specification);
+  if (decl == NULL)
+    decl = die;
   else
-    for (;;)
-      {
-       if (!same_die_p (c1, c2, mark))
-         return 0;
-       c1 = c1->die_sib;
-       c2 = c2->die_sib;
-       if (c1 == die1->die_child)
-         {
-           if (c2 == die2->die_child)
-             break;
-           else
-             return 0;
-         }
+    {
+      unsigned ix;
+      dw_die_ref c;
+      dw_attr_ref a;
+
+      /* Copy the type node pointer from the new DIE to the original
+         declaration DIE so we can forward references later.  */
+      decl->die_id.die_type_node = die->die_id.die_type_node;
+
+      remove_AT (die, DW_AT_specification);
+
+      FOR_EACH_VEC_ELT (dw_attr_node, decl->die_attr, ix, a)
+        {
+          if (a->dw_attr != DW_AT_name
+              && a->dw_attr != DW_AT_declaration
+              && a->dw_attr != DW_AT_external)
+            add_dwarf_attr (die, a);
+        }
+
+      FOR_EACH_CHILD (decl, c, add_child_die (die, clone_tree(c)));
     }
 
-  return 1;
+  if (decl->die_parent != NULL
+      && decl->die_parent->die_tag != DW_TAG_compile_unit
+      && decl->die_parent->die_tag != DW_TAG_type_unit)
+    {
+      new_decl = copy_ancestor_tree (unit, decl, NULL);
+      if (new_decl != NULL)
+        {
+          remove_AT (new_decl, DW_AT_signature);
+          add_AT_specification (die, new_decl);
+        }
+    }
 }
 
-/* Do the dies look the same?  Wrapper around same_die_p.  */
+/* Generate the skeleton ancestor tree for the given NODE, then clone
+   the DIE and add the clone into the tree.  */
 
-static int
-same_die_p_wrap (dw_die_ref die1, dw_die_ref die2)
+static void
+generate_skeleton_ancestor_tree (skeleton_chain_node *node)
 {
-  int mark = 0;
-  int ret = same_die_p (die1, die2, &mark);
+  if (node->new_die != NULL)
+    return;
 
-  unmark_all_dies (die1);
-  unmark_all_dies (die2);
+  node->new_die = clone_as_declaration (node->old_die);
 
-  return ret;
+  if (node->parent != NULL)
+    {
+      generate_skeleton_ancestor_tree (node->parent);
+      add_child_die (node->parent->new_die, node->new_die);
+    }
 }
 
-/* The prefix to attach to symbols on DIEs in the current comdat debug
-   info section.  */
-static char *comdat_symbol_id;
-
-/* The index of the current symbol within the current comdat CU.  */
-static unsigned int comdat_symbol_number;
-
-/* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its
-   children, and set comdat_symbol_id accordingly.  */
+/* Generate a skeleton tree of DIEs containing any declarations that are
+   found in the original tree.  We traverse the tree looking for declaration
+   DIEs, and construct the skeleton from the bottom up whenever we find one.  */
 
 static void
-compute_section_prefix (dw_die_ref unit_die)
+generate_skeleton_bottom_up (skeleton_chain_node *parent)
 {
-  const char *die_name = get_AT_string (unit_die, DW_AT_name);
-  const char *base = die_name ? lbasename (die_name) : "anonymous";
-  char *name = XALLOCAVEC (char, strlen (base) + 64);
-  char *p;
-  int i, mark;
-  unsigned char checksum[16];
-  struct md5_ctx ctx;
-
-  /* Compute the checksum of the DIE, then append part of it as hex digits to
-     the name filename of the unit.  */
-
-  md5_init_ctx (&ctx);
-  mark = 0;
-  die_checksum (unit_die, &ctx, &mark);
-  unmark_all_dies (unit_die);
-  md5_finish_ctx (&ctx, checksum);
+  skeleton_chain_node node;
+  dw_die_ref c;
+  dw_die_ref first;
+  dw_die_ref prev = NULL;
+  dw_die_ref next = NULL;
 
-  sprintf (name, "%s.", base);
-  clean_symbol_name (name);
+  node.parent = parent;
 
-  p = name + strlen (name);
-  for (i = 0; i < 4; i++)
-    {
-      sprintf (p, "%.2x", checksum[i]);
-      p += 2;
-    }
+  first = c = parent->old_die->die_child;
+  if (c)
+    next = c->die_sib;
+  if (c) do {
+    if (prev == NULL || prev->die_sib == c)
+      prev = c;
+    c = next;
+    next = (c == first ? NULL : c->die_sib);
+    node.old_die = c;
+    node.new_die = NULL;
+    if (is_declaration_die (c))
+      {
+        /* Clone the existing DIE, move the original to the skeleton
+           tree (which is in the main CU), and put the clone, with
+           all the original's children, where the original came from.  */
+        dw_die_ref clone = clone_die (c);
+        move_all_children (c, clone);
 
-  comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
-  comdat_symbol_number = 0;
+        replace_child (c, clone, prev);
+        generate_skeleton_ancestor_tree (parent);
+        add_child_die (parent->new_die, c);
+        node.new_die = c;
+        c = clone;
+      }
+    generate_skeleton_bottom_up (&node);
+  } while (next != NULL);
 }
 
-/* Returns nonzero if DIE represents a type, in the sense of TYPE_P.  */
+/* Wrapper function for generate_skeleton_bottom_up.  */
 
-static int
-is_type_die (dw_die_ref die)
+static dw_die_ref
+generate_skeleton (dw_die_ref die)
 {
-  switch (die->die_tag)
-    {
-    case DW_TAG_array_type:
-    case DW_TAG_class_type:
-    case DW_TAG_interface_type:
-    case DW_TAG_enumeration_type:
-    case DW_TAG_pointer_type:
-    case DW_TAG_reference_type:
-    case DW_TAG_rvalue_reference_type:
-    case DW_TAG_string_type:
-    case DW_TAG_structure_type:
-    case DW_TAG_subroutine_type:
-    case DW_TAG_union_type:
-    case DW_TAG_ptr_to_member_type:
-    case DW_TAG_set_type:
-    case DW_TAG_subrange_type:
-    case DW_TAG_base_type:
-    case DW_TAG_const_type:
-    case DW_TAG_file_type:
-    case DW_TAG_packed_type:
-    case DW_TAG_volatile_type:
-    case DW_TAG_typedef:
-      return 1;
-    default:
-      return 0;
-    }
+  skeleton_chain_node node;
+
+  node.old_die = die;
+  node.new_die = NULL;
+  node.parent = NULL;
+
+  /* If this type definition is nested inside another type,
+     always leave at least a declaration in its place.  */
+  if (die->die_parent != NULL && is_type_die (die->die_parent))
+    node.new_die = clone_as_declaration (die);
+
+  generate_skeleton_bottom_up (&node);
+  return node.new_die;
 }
 
-/* Returns 1 iff C is the sort of DIE that should go into a COMDAT CU.
-   Basically, we want to choose the bits that are likely to be shared between
-   compilations (types) and leave out the bits that are specific to individual
-   compilations (functions).  */
+/* Remove the DIE from its parent, possibly replacing it with a cloned
+   declaration.  The original DIE will be moved to a new compile unit
+   so that existing references to it follow it to the new location.  If
+   any of the original DIE's descendants is a declaration, we need to
+   replace the original DIE with a skeleton tree and move the
+   declarations back into the skeleton tree.  */
 
-static int
-is_comdat_die (dw_die_ref c)
+static dw_die_ref
+remove_child_or_replace_with_skeleton (dw_die_ref child, dw_die_ref prev)
 {
-  /* I think we want to leave base types and __vtbl_ptr_type in the main CU, as
-     we do for stabs.  The advantage is a greater likelihood of sharing between
-     objects that don't include headers in the same order (and therefore would
-     put the base types in a different comdat).  jason 8/28/00 */
-
-  if (c->die_tag == DW_TAG_base_type)
-    return 0;
+  dw_die_ref skeleton;
 
-  if (c->die_tag == DW_TAG_pointer_type
-      || c->die_tag == DW_TAG_reference_type
-      || c->die_tag == DW_TAG_rvalue_reference_type
-      || c->die_tag == DW_TAG_const_type
-      || c->die_tag == DW_TAG_volatile_type)
+  skeleton = generate_skeleton (child);
+  if (skeleton == NULL)
+    remove_child_with_prev (child, prev);
+  else
     {
-      dw_die_ref t = get_AT_ref (c, DW_AT_type);
-
-      return t ? is_comdat_die (t) : 0;
+      skeleton->die_id.die_type_node = child->die_id.die_type_node;
+      replace_child (child, skeleton, prev);
     }
 
-  return is_type_die (c);
+  return skeleton;
 }
 
-/* Returns 1 iff C is the sort of DIE that might be referred to from another
-   compilation unit.  */
+/* Traverse the DIE and set up additional .debug_types sections for each
+   type worthy of being placed in a COMDAT section.  */
 
-static int
-is_symbol_die (dw_die_ref c)
+static void
+break_out_comdat_types (dw_die_ref die)
 {
-  return (is_type_die (c)
-         || is_declaration_die (c)
-         || c->die_tag == DW_TAG_namespace
-         || c->die_tag == DW_TAG_module);
-}
+  dw_die_ref c;
+  dw_die_ref first;
+  dw_die_ref prev = NULL;
+  dw_die_ref next = NULL;
+  dw_die_ref unit = NULL;
 
-static char *
-gen_internal_sym (const char *prefix)
-{
-  char buf[256];
+  first = c = die->die_child;
+  if (c)
+    next = c->die_sib;
+  if (c) do {
+    if (prev == NULL || prev->die_sib == c)
+      prev = c;
+    c = next;
+    next = (c == first ? NULL : c->die_sib);
+    if (should_move_die_to_comdat (c))
+      {
+        dw_die_ref replacement;
+       comdat_type_node_ref type_node;
 
-  ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++);
-  return xstrdup (buf);
-}
+        /* Create a new type unit DIE as the root for the new tree, and
+           add it to the list of comdat types.  */
+        unit = new_die (DW_TAG_type_unit, NULL, NULL);
+        add_AT_unsigned (unit, DW_AT_language,
+                         get_AT_unsigned (comp_unit_die (), DW_AT_language));
+        type_node = ggc_alloc_cleared_comdat_type_node ();
+        type_node->root_die = unit;
+        type_node->next = comdat_type_list;
+        comdat_type_list = type_node;
 
-/* Assign symbols to all worthy DIEs under DIE.  */
+        /* Generate the type signature.  */
+        generate_type_signature (c, type_node);
 
-static void
-assign_symbol_names (dw_die_ref die)
-{
-  dw_die_ref c;
+        /* Copy the declaration context, attributes, and children of the
+           declaration into the new compile unit DIE.  */
+       copy_declaration_context (unit, c);
 
-  if (is_symbol_die (die))
-    {
-      if (comdat_symbol_id)
-       {
-         char *p = XALLOCAVEC (char, strlen (comdat_symbol_id) + 64);
+        /* Remove this DIE from the main CU.  */
+       replacement = remove_child_or_replace_with_skeleton (c, prev);
 
-         sprintf (p, "%s.%s.%x", DIE_LABEL_PREFIX,
-                  comdat_symbol_id, comdat_symbol_number++);
-         die->die_id.die_symbol = xstrdup (p);
-       }
-      else
-       die->die_id.die_symbol = gen_internal_sym ("LDIE");
-    }
+        /* Break out nested types into their own type units.  */
+        break_out_comdat_types (c);
 
-  FOR_EACH_CHILD (die, c, assign_symbol_names (c));
+        /* Add the DIE to the new compunit.  */
+       add_child_die (unit, c);
+
+        if (replacement != NULL)
+          c = replacement;
+      }
+    else if (c->die_tag == DW_TAG_namespace
+             || c->die_tag == DW_TAG_class_type
+             || c->die_tag == DW_TAG_structure_type
+             || c->die_tag == DW_TAG_union_type)
+      {
+        /* Look for nested types that can be broken out.  */
+        break_out_comdat_types (c);
+      }
+  } while (next != NULL);
 }
 
-struct cu_hash_table_entry
+/* Structure to map a DIE in one CU to its copy in a comdat type unit.  */
+
+struct decl_table_entry
 {
-  dw_die_ref cu;
-  unsigned min_comdat_num, max_comdat_num;
-  struct cu_hash_table_entry *next;
+  dw_die_ref orig;
+  dw_die_ref copy;
 };
 
-/* Routines to manipulate hash table of CUs.  */
+/* Routines to manipulate hash table of copied declarations.  */
+
 static hashval_t
-htab_cu_hash (const void *of)
+htab_decl_hash (const void *of)
 {
-  const struct cu_hash_table_entry *const entry =
-    (const struct cu_hash_table_entry *) of;
+  const struct decl_table_entry *const entry =
+    (const struct decl_table_entry *) of;
 
-  return htab_hash_string (entry->cu->die_id.die_symbol);
+  return htab_hash_pointer (entry->orig);
 }
 
 static int
-htab_cu_eq (const void *of1, const void *of2)
+htab_decl_eq (const void *of1, const void *of2)
 {
-  const struct cu_hash_table_entry *const entry1 =
-    (const struct cu_hash_table_entry *) of1;
+  const struct decl_table_entry *const entry1 =
+    (const struct decl_table_entry *) of1;
   const struct die_struct *const entry2 = (const struct die_struct *) of2;
 
-  return !strcmp (entry1->cu->die_id.die_symbol, entry2->die_id.die_symbol);
+  return entry1->orig == entry2;
 }
 
 static void
-htab_cu_del (void *what)
+htab_decl_del (void *what)
 {
-  struct cu_hash_table_entry *next,
-    *entry = (struct cu_hash_table_entry *) what;
+  struct decl_table_entry *entry = (struct decl_table_entry *) what;
 
-  while (entry)
-    {
-      next = entry->next;
-      free (entry);
-      entry = next;
-    }
+  free (entry);
 }
 
-/* Check whether we have already seen this CU and set up SYM_NUM
-   accordingly.  */
-static int
-check_duplicate_cu (dw_die_ref cu, htab_t htable, unsigned int *sym_num)
+/* Copy DIE and its ancestors, up to, but not including, the compile unit
+   or type unit entry, to a new tree.  Adds the new tree to UNIT and returns
+   a pointer to the copy of DIE.  If DECL_TABLE is provided, it is used
+   to check if the ancestor has already been copied into UNIT.  */
+
+static dw_die_ref
+copy_ancestor_tree (dw_die_ref unit, dw_die_ref die, htab_t decl_table)
 {
-  struct cu_hash_table_entry dummy;
-  struct cu_hash_table_entry **slot, *entry, *last = &dummy;
+  dw_die_ref parent = die->die_parent;
+  dw_die_ref new_parent = unit;
+  dw_die_ref copy;
+  void **slot = NULL;
+  struct decl_table_entry *entry = NULL;
 
-  dummy.max_comdat_num = 0;
+  if (decl_table)
+    {
+      /* Check if the entry has already been copied to UNIT.  */
+      slot = htab_find_slot_with_hash (decl_table, die,
+                                       htab_hash_pointer (die), INSERT);
+      if (*slot != HTAB_EMPTY_ENTRY)
+        {
+          entry = (struct decl_table_entry *) *slot;
+          return entry->copy;
+        }
 
-  slot = (struct cu_hash_table_entry **)
-    htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_id.die_symbol),
-       INSERT);
-  entry = *slot;
+      /* Record in DECL_TABLE that DIE has been copied to UNIT.  */
+      entry = XCNEW (struct decl_table_entry);
+      entry->orig = die;
+      entry->copy = NULL;
+      *slot = entry;
+    }
 
-  for (; entry; last = entry, entry = entry->next)
+  if (parent != NULL)
     {
-      if (same_die_p_wrap (cu, entry->cu))
-       break;
+      dw_die_ref spec = get_AT_ref (parent, DW_AT_specification);
+      if (spec != NULL)
+        parent = spec;
+      if (parent->die_tag != DW_TAG_compile_unit
+          && parent->die_tag != DW_TAG_type_unit)
+        new_parent = copy_ancestor_tree (unit, parent, decl_table);
     }
 
-  if (entry)
+  copy = clone_as_declaration (die);
+  add_child_die (new_parent, copy);
+
+  if (decl_table != NULL)
     {
-      *sym_num = entry->min_comdat_num;
-      return 1;
+      /* Record the pointer to the copy.  */
+      entry->copy = copy;
     }
 
-  entry = XCNEW (struct cu_hash_table_entry);
-  entry->cu = cu;
-  entry->min_comdat_num = *sym_num = last->max_comdat_num;
-  entry->next = *slot;
-  *slot = entry;
-
-  return 0;
+  return copy;
 }
 
-/* Record SYM_NUM to record of CU in HTABLE.  */
+/* Walk the DIE and its children, looking for references to incomplete
+   or trivial types that are unmarked (i.e., that are not in the current
+   type_unit).  */
+
 static void
-record_comdat_symbol_number (dw_die_ref cu, htab_t htable, unsigned int sym_num)
+copy_decls_walk (dw_die_ref unit, dw_die_ref die, htab_t decl_table)
 {
-  struct cu_hash_table_entry **slot, *entry;
-
-  slot = (struct cu_hash_table_entry **)
-    htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_id.die_symbol),
-       NO_INSERT);
-  entry = *slot;
+  dw_die_ref c;
+  dw_attr_ref a;
+  unsigned ix;
 
-  entry->max_comdat_num = sym_num;
-}
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
+    {
+      if (AT_class (a) == dw_val_class_die_ref)
+        {
+          dw_die_ref targ = AT_ref (a);
+          comdat_type_node_ref type_node = targ->die_id.die_type_node;
+          void **slot;
+          struct decl_table_entry *entry;
 
-/* Traverse the DIE (which is always comp_unit_die), and set up
-   additional compilation units for each of the include files we see
-   bracketed by BINCL/EINCL.  */
+          if (targ->die_mark != 0 || type_node != NULL)
+            continue;
 
-static void
-break_out_includes (dw_die_ref die)
-{
-  dw_die_ref c;
-  dw_die_ref unit = NULL;
-  limbo_die_node *node, **pnode;
-  htab_t cu_hash_table;
+          slot = htab_find_slot_with_hash (decl_table, targ,
+                                           htab_hash_pointer (targ), INSERT);
 
-  c = die->die_child;
-  if (c) do {
-    dw_die_ref prev = c;
-    c = c->die_sib;
-    while (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL
-          || (unit && is_comdat_die (c)))
-      {
-       dw_die_ref next = c->die_sib;
+          if (*slot != HTAB_EMPTY_ENTRY)
+            {
+              /* TARG has already been copied, so we just need to
+                 modify the reference to point to the copy.  */
+              entry = (struct decl_table_entry *) *slot;
+              a->dw_attr_val.v.val_die_ref.die = entry->copy;
+            }
+          else
+            {
+              dw_die_ref parent = unit;
+              dw_die_ref copy = clone_tree (targ);
 
-       /* This DIE is for a secondary CU; remove it from the main one.  */
-       remove_child_with_prev (c, prev);
+              /* Make sure the cloned tree is marked as part of the
+                 type unit.  */
+              mark_dies (copy);
 
-       if (c->die_tag == DW_TAG_GNU_BINCL)
-         unit = push_new_compile_unit (unit, c);
-       else if (c->die_tag == DW_TAG_GNU_EINCL)
-         unit = pop_compile_unit (unit);
-       else
-         add_child_die (unit, c);
-       c = next;
-       if (c == die->die_child)
-         break;
-      }
-  } while (c != die->die_child);
+              /* Record in DECL_TABLE that TARG has been copied.
+                 Need to do this now, before the recursive call,
+                 because DECL_TABLE may be expanded and SLOT
+                 would no longer be a valid pointer.  */
+              entry = XCNEW (struct decl_table_entry);
+              entry->orig = targ;
+              entry->copy = copy;
+              *slot = entry;
 
-#if 0
-  /* We can only use this in debugging, since the frontend doesn't check
-     to make sure that we leave every include file we enter.  */
-  gcc_assert (!unit);
-#endif
+              /* If TARG has surrounding context, copy its ancestor tree
+                 into the new type unit.  */
+              if (targ->die_parent != NULL
+                  && targ->die_parent->die_tag != DW_TAG_compile_unit
+                  && targ->die_parent->die_tag != DW_TAG_type_unit)
+                parent = copy_ancestor_tree (unit, targ->die_parent,
+                                             decl_table);
 
-  assign_symbol_names (die);
-  cu_hash_table = htab_create (10, htab_cu_hash, htab_cu_eq, htab_cu_del);
-  for (node = limbo_die_list, pnode = &limbo_die_list;
-       node;
-       node = node->next)
-    {
-      int is_dupl;
+              add_child_die (parent, copy);
+              a->dw_attr_val.v.val_die_ref.die = copy;
 
-      compute_section_prefix (node->die);
-      is_dupl = check_duplicate_cu (node->die, cu_hash_table,
-                       &comdat_symbol_number);
-      assign_symbol_names (node->die);
-      if (is_dupl)
-       *pnode = node->next;
-      else
-       {
-         pnode = &node->next;
-         record_comdat_symbol_number (node->die, cu_hash_table,
-               comdat_symbol_number);
-       }
+              /* Make sure the newly-copied DIE is walked.  If it was
+                 installed in a previously-added context, it won't
+                 get visited otherwise.  */
+              if (parent != unit)
+               {
+                 /* Find the highest point of the newly-added tree,
+                    mark each node along the way, and walk from there.  */
+                 parent->die_mark = 1;
+                 while (parent->die_parent
+                        && parent->die_parent->die_mark == 0)
+                   {
+                     parent = parent->die_parent;
+                     parent->die_mark = 1;
+                   }
+                 copy_decls_walk (unit, parent, decl_table);
+               }
+            }
+        }
     }
-  htab_delete (cu_hash_table);
+
+  FOR_EACH_CHILD (die, c, copy_decls_walk (unit, c, decl_table));
+}
+
+/* Copy declarations for "unworthy" types into the new comdat section.
+   Incomplete types, modified types, and certain other types aren't broken
+   out into comdat sections of their own, so they don't have a signature,
+   and we need to copy the declaration into the same section so that we
+   don't have an external reference.  */
+
+static void
+copy_decls_for_unworthy_types (dw_die_ref unit)
+{
+  htab_t decl_table;
+
+  mark_dies (unit);
+  decl_table = htab_create (10, htab_decl_hash, htab_decl_eq, htab_decl_del);
+  copy_decls_walk (unit, unit, decl_table);
+  htab_delete (decl_table);
+  unmark_dies (unit);
 }
 
-/* Return non-zero if this DIE is a declaration.  */
+/* Traverse the DIE and add a sibling attribute if it may have the
+   effect of speeding up access to siblings.  To save some space,
+   avoid generating sibling attributes for DIE's without children.  */
 
-static int
-is_declaration_die (dw_die_ref die)
+static void
+add_sibling_attributes (dw_die_ref die)
 {
-  dw_attr_ref a;
-  unsigned ix;
+  dw_die_ref c;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    if (a->dw_attr == DW_AT_declaration)
-      return 1;
+  if (! die->die_child)
+    return;
 
-  return 0;
+  if (die->die_parent && die != die->die_parent->die_child)
+    add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
+
+  FOR_EACH_CHILD (die, c, add_sibling_attributes (c));
 }
 
-/* Return non-zero if this is a type DIE that should be moved to a
-   COMDAT .debug_types section.  */
+/* Output all location lists for the DIE and its children.  */
 
-static int
-should_move_die_to_comdat (dw_die_ref die)
+static void
+output_location_lists (dw_die_ref die)
 {
-  switch (die->die_tag)
-    {
-    case DW_TAG_class_type:
-    case DW_TAG_structure_type:
-    case DW_TAG_enumeration_type:
-    case DW_TAG_union_type:
-      /* Don't move declarations or inlined instances.  */
-      if (is_declaration_die (die) || get_AT (die, DW_AT_abstract_origin))
-        return 0;
-      return 1;
-    case DW_TAG_array_type:
-    case DW_TAG_interface_type:
-    case DW_TAG_pointer_type:
-    case DW_TAG_reference_type:
-    case DW_TAG_rvalue_reference_type:
-    case DW_TAG_string_type:
-    case DW_TAG_subroutine_type:
-    case DW_TAG_ptr_to_member_type:
-    case DW_TAG_set_type:
-    case DW_TAG_subrange_type:
-    case DW_TAG_base_type:
-    case DW_TAG_const_type:
-    case DW_TAG_file_type:
-    case DW_TAG_packed_type:
-    case DW_TAG_volatile_type:
-    case DW_TAG_typedef:
-    default:
-      return 0;
-    }
+  dw_die_ref c;
+  dw_attr_ref a;
+  unsigned 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));
+
+  FOR_EACH_CHILD (die, c, output_location_lists (c));
 }
 
-/* Make a clone of DIE.  */
+/* The format of each DIE (and its attribute value pairs) is encoded in an
+   abbreviation table.  This routine builds the abbreviation table and assigns
+   a unique abbreviation id for each abbreviation entry.  The children of each
+   die are visited recursively.  */
 
-static dw_die_ref
-clone_die (dw_die_ref die)
+static void
+build_abbrev_table (dw_die_ref die)
 {
-  dw_die_ref clone;
+  unsigned long abbrev_id;
+  unsigned int n_alloc;
+  dw_die_ref c;
   dw_attr_ref a;
   unsigned ix;
 
-  clone = GGC_CNEW (die_node);
-  clone->die_tag = die->die_tag;
+  /* Scan the DIE references, and mark as external any that refer to
+     DIEs from other CUs (i.e. those which are not marked).  */
+  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 (use_debug_types || AT_ref (a)->die_id.die_symbol);
+       set_AT_ref_external (a, 1);
+      }
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    add_dwarf_attr (clone, a);
+  for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+    {
+      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
+      dw_attr_ref die_a, abbrev_a;
+      unsigned ix;
+      bool ok = true;
 
-  return clone;
-}
+      if (abbrev->die_tag != die->die_tag)
+       continue;
+      if ((abbrev->die_child != NULL) != (die->die_child != NULL))
+       continue;
 
-/* Make a clone of the tree rooted at DIE.  */
+      if (VEC_length (dw_attr_node, abbrev->die_attr)
+         != VEC_length (dw_attr_node, die->die_attr))
+       continue;
 
-static dw_die_ref
-clone_tree (dw_die_ref die)
+      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)
+             || (value_format (abbrev_a) != value_format (die_a)))
+           {
+             ok = false;
+             break;
+           }
+       }
+      if (ok)
+       break;
+    }
+
+  if (abbrev_id >= abbrev_die_table_in_use)
+    {
+      if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
+       {
+         n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
+         abbrev_die_table = GGC_RESIZEVEC (dw_die_ref, abbrev_die_table,
+                                           n_alloc);
+
+         memset (&abbrev_die_table[abbrev_die_table_allocated], 0,
+                (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
+         abbrev_die_table_allocated = n_alloc;
+       }
+
+      ++abbrev_die_table_in_use;
+      abbrev_die_table[abbrev_id] = die;
+    }
+
+  die->die_abbrev = abbrev_id;
+  FOR_EACH_CHILD (die, c, build_abbrev_table (c));
+}
+\f
+/* Return the power-of-two number of bytes necessary to represent VALUE.  */
+
+static int
+constant_size (unsigned HOST_WIDE_INT value)
 {
-  dw_die_ref c;
-  dw_die_ref clone = clone_die (die);
+  int log;
 
-  FOR_EACH_CHILD (die, c, add_child_die (clone, clone_tree(c)));
+  if (value == 0)
+    log = 0;
+  else
+    log = floor_log2 (value);
 
-  return clone;
+  log = log / 8;
+  log = 1 << (floor_log2 (log) + 1);
+
+  return log;
 }
 
-/* Make a clone of DIE as a declaration.  */
+/* Return the size of a DIE as it is represented in the
+   .debug_info section.  */
 
-static dw_die_ref
-clone_as_declaration (dw_die_ref die)
+static unsigned long
+size_of_die (dw_die_ref die)
 {
-  dw_die_ref clone;
-  dw_die_ref decl;
+  unsigned long size = 0;
   dw_attr_ref a;
   unsigned ix;
 
-  /* If the DIE is already a declaration, just clone it.  */
-  if (is_declaration_die (die))
-    return clone_die (die);
-
-  /* If the DIE is a specification, just clone its declaration DIE.  */
-  decl = get_AT_ref (die, DW_AT_specification);
-  if (decl != NULL)
-    return clone_die (decl);
-
-  clone = GGC_CNEW (die_node);
-  clone->die_tag = die->die_tag;
-
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  size += size_of_uleb128 (die->die_abbrev);
+  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
-         longer have a declaration and GDB will treat it as a definition.  */
+      switch (AT_class (a))
+       {
+       case dw_val_class_addr:
+         size += DWARF2_ADDR_SIZE;
+         break;
+       case dw_val_class_offset:
+         size += DWARF_OFFSET_SIZE;
+         break;
+       case dw_val_class_loc:
+         {
+           unsigned long lsize = size_of_locs (AT_loc (a));
 
-      switch (a->dw_attr)
-        {
-        case DW_AT_artificial:
-        case DW_AT_containing_type:
-        case DW_AT_external:
-        case DW_AT_name:
-        case DW_AT_type:
-        case DW_AT_virtuality:
-        case DW_AT_linkage_name:
-        case DW_AT_MIPS_linkage_name:
-          add_dwarf_attr (clone, a);
-          break;
-        case DW_AT_byte_size:
-        default:
-          break;
-        }
+           /* Block length.  */
+           if (dwarf_version >= 4)
+             size += size_of_uleb128 (lsize);
+           else
+             size += constant_size (lsize);
+           size += lsize;
+         }
+         break;
+       case dw_val_class_loc_list:
+         size += DWARF_OFFSET_SIZE;
+         break;
+       case dw_val_class_range_list:
+         size += DWARF_OFFSET_SIZE;
+         break;
+       case dw_val_class_const:
+         size += size_of_sleb128 (AT_int (a));
+         break;
+       case dw_val_class_unsigned_const:
+         {
+           int csize = constant_size (AT_unsigned (a));
+           if (dwarf_version == 3
+               && a->dw_attr == DW_AT_data_member_location
+               && csize >= 4)
+             size += size_of_uleb128 (AT_unsigned (a));
+           else
+             size += csize;
+         }
+         break;
+       case dw_val_class_const_double:
+         size += 2 * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
+         if (HOST_BITS_PER_WIDE_INT >= 64)
+           size++; /* block */
+         break;
+       case dw_val_class_vec:
+         size += constant_size (a->dw_attr_val.v.val_vec.length
+                                * a->dw_attr_val.v.val_vec.elt_size)
+                 + a->dw_attr_val.v.val_vec.length
+                   * a->dw_attr_val.v.val_vec.elt_size; /* block */
+         break;
+       case dw_val_class_flag:
+         if (dwarf_version >= 4)
+           /* Currently all add_AT_flag calls pass in 1 as last argument,
+              so DW_FORM_flag_present can be used.  If that ever changes,
+              we'll need to use DW_FORM_flag and have some optimization
+              in build_abbrev_table that will change those to
+              DW_FORM_flag_present if it is set to 1 in all DIEs using
+              the same abbrev entry.  */
+           gcc_assert (a->dw_attr_val.v.val_flag == 1);
+         else
+           size += 1;
+         break;
+       case dw_val_class_die_ref:
+         if (AT_ref_external (a))
+           {
+             /* 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 (use_debug_types)
+               size += DWARF_TYPE_SIGNATURE_SIZE;
+             else if (dwarf_version == 2)
+               size += DWARF2_ADDR_SIZE;
+             else
+               size += DWARF_OFFSET_SIZE;
+           }
+         else
+           size += DWARF_OFFSET_SIZE;
+         break;
+       case dw_val_class_fde_ref:
+         size += DWARF_OFFSET_SIZE;
+         break;
+       case dw_val_class_lbl_id:
+         size += DWARF2_ADDR_SIZE;
+         break;
+       case dw_val_class_lineptr:
+       case dw_val_class_macptr:
+         size += DWARF_OFFSET_SIZE;
+         break;
+       case dw_val_class_str:
+         if (AT_string_form (a) == DW_FORM_strp)
+           size += DWARF_OFFSET_SIZE;
+         else
+           size += strlen (a->dw_attr_val.v.val_str->str) + 1;
+         break;
+       case dw_val_class_file:
+         size += constant_size (maybe_emit_file (a->dw_attr_val.v.val_file));
+         break;
+       case dw_val_class_data8:
+         size += 8;
+         break;
+       case dw_val_class_vms_delta:
+         size += DWARF_OFFSET_SIZE;
+         break;
+       default:
+         gcc_unreachable ();
+       }
     }
 
-  if (die->die_id.die_type_node)
-    add_AT_die_ref (clone, DW_AT_signature, die);
-
-  add_AT_flag (clone, DW_AT_declaration, 1);
-  return clone;
+  return size;
 }
 
-/* Copy the declaration context to the new compile unit DIE.  This includes
-   any surrounding namespace or type declarations.  If the DIE has an
-   AT_specification attribute, it also includes attributes and children
-   attached to the specification.  */
+/* Size the debugging information associated with a given DIE.  Visits the
+   DIE's children recursively.  Updates the global variable next_die_offset, on
+   each time through.  Uses the current value of next_die_offset to update the
+   die_offset field in each DIE.  */
 
 static void
-copy_declaration_context (dw_die_ref unit, dw_die_ref die)
+calc_die_sizes (dw_die_ref die)
 {
-  dw_die_ref decl;
-  dw_die_ref new_decl;
-
-  decl = get_AT_ref (die, DW_AT_specification);
-  if (decl == NULL)
-    decl = die;
-  else
-    {
-      unsigned ix;
-      dw_die_ref c;
-      dw_attr_ref a;
-
-      /* Copy the type node pointer from the new DIE to the original
-         declaration DIE so we can forward references later.  */
-      decl->die_id.die_type_node = die->die_id.die_type_node;
-
-      remove_AT (die, DW_AT_specification);
+  dw_die_ref c;
 
-      for (ix = 0; VEC_iterate (dw_attr_node, decl->die_attr, ix, a); ix++)
-        {
-          if (a->dw_attr != DW_AT_name
-              && a->dw_attr != DW_AT_declaration
-              && a->dw_attr != DW_AT_external)
-            add_dwarf_attr (die, a);
-        }
+  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);
 
-      FOR_EACH_CHILD (decl, c, add_child_die (die, clone_tree(c)));
-    }
+  FOR_EACH_CHILD (die, c, calc_die_sizes (c));
 
-  if (decl->die_parent != NULL
-      && decl->die_parent->die_tag != DW_TAG_compile_unit
-      && decl->die_parent->die_tag != DW_TAG_type_unit)
-    {
-      new_decl = copy_ancestor_tree (unit, decl, NULL);
-      if (new_decl != NULL)
-        {
-          remove_AT (new_decl, DW_AT_signature);
-          add_AT_specification (die, new_decl);
-        }
-    }
+  if (die->die_child != NULL)
+    /* Count the null byte used to terminate sibling lists.  */
+    next_die_offset += 1;
 }
 
-/* Generate the skeleton ancestor tree for the given NODE, then clone
-   the DIE and add the clone into the tree.  */
+/* 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
-generate_skeleton_ancestor_tree (skeleton_chain_node *node)
+calc_base_type_die_sizes (void)
 {
-  if (node->new_die != NULL)
-    return;
-
-  node->new_die = clone_as_declaration (node->old_die);
+  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
 
-  if (node->parent != NULL)
+  die_offset += size_of_die (comp_unit_die ());
+  for (i = 0; VEC_iterate (dw_die_ref, base_types, i, base_type); i++)
     {
-      generate_skeleton_ancestor_tree (node->parent);
-      add_child_die (node->parent->new_die, node->new_die);
+#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);
     }
 }
 
-/* Generate a skeleton tree of DIEs containing any declarations that are
-   found in the original tree.  We traverse the tree looking for declaration
-   DIEs, and construct the skeleton from the bottom up whenever we find one.  */
+/* 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
-generate_skeleton_bottom_up (skeleton_chain_node *parent)
+mark_dies (dw_die_ref die)
 {
-  skeleton_chain_node node;
   dw_die_ref c;
-  dw_die_ref first;
-  dw_die_ref prev = NULL;
-  dw_die_ref next = NULL;
-
-  node.parent = parent;
-
-  first = c = parent->old_die->die_child;
-  if (c)
-    next = c->die_sib;
-  if (c) do {
-    if (prev == NULL || prev->die_sib == c)
-      prev = c;
-    c = next;
-    next = (c == first ? NULL : c->die_sib);
-    node.old_die = c;
-    node.new_die = NULL;
-    if (is_declaration_die (c))
-      {
-        /* Clone the existing DIE, move the original to the skeleton
-           tree (which is in the main CU), and put the clone, with
-           all the original's children, where the original came from.  */
-        dw_die_ref clone = clone_die (c);
-        move_all_children (c, clone);
-
-        replace_child (c, clone, prev);
-        generate_skeleton_ancestor_tree (parent);
-        add_child_die (parent->new_die, c);
-        node.new_die = c;
-        c = clone;
-      }
-    generate_skeleton_bottom_up (&node);
-  } while (next != NULL);
-}
-
-/* Wrapper function for generate_skeleton_bottom_up.  */
-
-static dw_die_ref
-generate_skeleton (dw_die_ref die)
-{
-  skeleton_chain_node node;
-
-  node.old_die = die;
-  node.new_die = NULL;
-  node.parent = NULL;
-
-  /* If this type definition is nested inside another type,
-     always leave at least a declaration in its place.  */
-  if (die->die_parent != NULL && is_type_die (die->die_parent))
-    node.new_die = clone_as_declaration (die);
-
-  generate_skeleton_bottom_up (&node);
-  return node.new_die;
-}
-
-/* Remove the DIE from its parent, possibly replacing it with a cloned
-   declaration.  The original DIE will be moved to a new compile unit
-   so that existing references to it follow it to the new location.  If
-   any of the original DIE's descendants is a declaration, we need to
-   replace the original DIE with a skeleton tree and move the
-   declarations back into the skeleton tree.  */
-
-static dw_die_ref
-remove_child_or_replace_with_skeleton (dw_die_ref child, dw_die_ref prev)
-{
-  dw_die_ref skeleton;
 
-  skeleton = generate_skeleton (child);
-  if (skeleton == NULL)
-    remove_child_with_prev (child, prev);
-  else
-    {
-      skeleton->die_id.die_type_node = child->die_id.die_type_node;
-      replace_child (child, skeleton, prev);
-    }
+  gcc_assert (!die->die_mark);
 
-  return skeleton;
+  die->die_mark = 1;
+  FOR_EACH_CHILD (die, c, mark_dies (c));
 }
 
-/* Traverse the DIE and set up additional .debug_types sections for each
-   type worthy of being placed in a COMDAT section.  */
+/* Clear the marks for a die and its children.  */
 
 static void
-break_out_comdat_types (dw_die_ref die)
+unmark_dies (dw_die_ref die)
 {
   dw_die_ref c;
-  dw_die_ref first;
-  dw_die_ref prev = NULL;
-  dw_die_ref next = NULL;
-  dw_die_ref unit = NULL;
-
-  first = c = die->die_child;
-  if (c)
-    next = c->die_sib;
-  if (c) do {
-    if (prev == NULL || prev->die_sib == c)
-      prev = c;
-    c = next;
-    next = (c == first ? NULL : c->die_sib);
-    if (should_move_die_to_comdat (c))
-      {
-        dw_die_ref replacement;
-       comdat_type_node_ref type_node;
-
-        /* Create a new type unit DIE as the root for the new tree, and
-           add it to the list of comdat types.  */
-        unit = new_die (DW_TAG_type_unit, NULL, NULL);
-        add_AT_unsigned (unit, DW_AT_language,
-                         get_AT_unsigned (comp_unit_die, DW_AT_language));
-        type_node = GGC_CNEW (comdat_type_node);
-        type_node->root_die = unit;
-        type_node->next = comdat_type_list;
-        comdat_type_list = type_node;
-
-        /* Generate the type signature.  */
-        generate_type_signature (c, type_node);
-
-        /* Copy the declaration context, attributes, and children of the
-           declaration into the new compile unit DIE.  */
-       copy_declaration_context (unit, c);
-
-        /* Remove this DIE from the main CU.  */
-       replacement = remove_child_or_replace_with_skeleton (c, prev);
-
-        /* Break out nested types into their own type units.  */
-        break_out_comdat_types (c);
 
-        /* Add the DIE to the new compunit.  */
-       add_child_die (unit, c);
+  if (! use_debug_types)
+    gcc_assert (die->die_mark);
 
-        if (replacement != NULL)
-          c = replacement;
-      }
-    else if (c->die_tag == DW_TAG_namespace
-             || c->die_tag == DW_TAG_class_type
-             || c->die_tag == DW_TAG_structure_type
-             || c->die_tag == DW_TAG_union_type)
-      {
-        /* Look for nested types that can be broken out.  */
-        break_out_comdat_types (c);
-      }
-  } while (next != NULL);
+  die->die_mark = 0;
+  FOR_EACH_CHILD (die, c, unmark_dies (c));
 }
 
-/* Structure to map a DIE in one CU to its copy in a comdat type unit.  */
+/* Clear the marks for a die, its children and referred dies.  */
 
-struct decl_table_entry
+static void
+unmark_all_dies (dw_die_ref die)
 {
-  dw_die_ref orig;
-  dw_die_ref copy;
-};
+  dw_die_ref c;
+  dw_attr_ref a;
+  unsigned ix;
 
-/* Routines to manipulate hash table of copied declarations.  */
+  if (!die->die_mark)
+    return;
+  die->die_mark = 0;
 
-static hashval_t
-htab_decl_hash (const void *of)
-{
-  const struct decl_table_entry *const entry =
-    (const struct decl_table_entry *) of;
+  FOR_EACH_CHILD (die, c, unmark_all_dies (c));
 
-  return htab_hash_pointer (entry->orig);
+  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));
 }
 
-static int
-htab_decl_eq (const void *of1, const void *of2)
-{
-  const struct decl_table_entry *const entry1 =
-    (const struct decl_table_entry *) of1;
-  const struct die_struct *const entry2 = (const struct die_struct *) of2;
-
-  return entry1->orig == entry2;
-}
+/* Return the size of the .debug_pubnames or .debug_pubtypes table
+   generated for the compilation unit.  */
 
-static void
-htab_decl_del (void *what)
+static unsigned long
+size_of_pubnames (VEC (pubname_entry, gc) * names)
 {
-  struct decl_table_entry *entry = (struct decl_table_entry *) what;
+  unsigned long size;
+  unsigned i;
+  pubname_ref p;
 
-  free (entry);
+  size = DWARF_PUBNAMES_HEADER_SIZE;
+  FOR_EACH_VEC_ELT (pubname_entry, names, i, p)
+    if (names != pubtype_table
+       || p->die->die_offset != 0
+       || !flag_eliminate_unused_debug_types)
+      size += strlen (p->name) + DWARF_OFFSET_SIZE + 1;
+
+  size += DWARF_OFFSET_SIZE;
+  return size;
 }
 
-/* Copy DIE and its ancestors, up to, but not including, the compile unit
-   or type unit entry, to a new tree.  Adds the new tree to UNIT and returns
-   a pointer to the copy of DIE.  If DECL_TABLE is provided, it is used
-   to check if the ancestor has already been copied into UNIT.  */
+/* Return the size of the information in the .debug_aranges section.  */
 
-static dw_die_ref
-copy_ancestor_tree (dw_die_ref unit, dw_die_ref die, htab_t decl_table)
+static unsigned long
+size_of_aranges (void)
 {
-  dw_die_ref parent = die->die_parent;
-  dw_die_ref new_parent = unit;
-  dw_die_ref copy;
-  void **slot = NULL;
-  struct decl_table_entry *entry = NULL;
-
-  if (decl_table)
-    {
-      /* Check if the entry has already been copied to UNIT.  */
-      slot = htab_find_slot_with_hash (decl_table, die,
-                                       htab_hash_pointer (die), INSERT);
-      if (*slot != HTAB_EMPTY_ENTRY)
-        {
-          entry = (struct decl_table_entry *) *slot;
-          return entry->copy;
-        }
+  unsigned long size;
 
-      /* Record in DECL_TABLE that DIE has been copied to UNIT.  */
-      entry = XCNEW (struct decl_table_entry);
-      entry->orig = die;
-      entry->copy = NULL;
-      *slot = entry;
-    }
+  size = DWARF_ARANGES_HEADER_SIZE;
 
-  if (parent != NULL)
+  /* Count the address/length pair for this compilation unit.  */
+  if (text_section_used)
+    size += 2 * DWARF2_ADDR_SIZE;
+  if (cold_text_section_used)
+    size += 2 * DWARF2_ADDR_SIZE;
+  if (have_multiple_function_sections)
     {
-      dw_die_ref spec = get_AT_ref (parent, DW_AT_specification);
-      if (spec != NULL)
-        parent = spec;
-      if (parent->die_tag != DW_TAG_compile_unit
-          && parent->die_tag != DW_TAG_type_unit)
-        new_parent = copy_ancestor_tree (unit, parent, decl_table);
+      unsigned fde_idx;
+      dw_fde_ref fde;
+
+      FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde)
+       {
+         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;
+       }
     }
 
-  copy = clone_as_declaration (die);
-  add_child_die (new_parent, copy);
+  /* Count the two zero words used to terminated the address range table.  */
+  size += 2 * DWARF2_ADDR_SIZE;
+  return size;
+}
+\f
+/* Select the encoding of an attribute value.  */
 
-  if (decl_table != NULL)
+static enum dwarf_form
+value_format (dw_attr_ref a)
+{
+  switch (a->dw_attr_val.val_class)
     {
-      /* Make sure the copy is marked as part of the type unit.  */
-      copy->die_mark = 1;
-      /* Record the pointer to the copy.  */
-      entry->copy = copy;
-    }
+    case dw_val_class_addr:
+      /* Only very few attributes allow DW_FORM_addr.  */
+      switch (a->dw_attr)
+       {
+       case DW_AT_low_pc:
+       case DW_AT_high_pc:
+       case DW_AT_entry_pc:
+       case DW_AT_trampoline:
+         return DW_FORM_addr;
+       default:
+         break;
+       }
+      switch (DWARF2_ADDR_SIZE)
+       {
+       case 1:
+         return DW_FORM_data1;
+       case 2:
+         return DW_FORM_data2;
+       case 4:
+         return DW_FORM_data4;
+       case 8:
+         return DW_FORM_data8;
+       default:
+         gcc_unreachable ();
+       }
+    case dw_val_class_range_list:
+    case dw_val_class_loc_list:
+      if (dwarf_version >= 4)
+       return DW_FORM_sec_offset;
+      /* FALLTHRU */
+    case dw_val_class_vms_delta:
+    case dw_val_class_offset:
+      switch (DWARF_OFFSET_SIZE)
+       {
+       case 4:
+         return DW_FORM_data4;
+       case 8:
+         return DW_FORM_data8;
+       default:
+         gcc_unreachable ();
+       }
+    case dw_val_class_loc:
+      if (dwarf_version >= 4)
+       return DW_FORM_exprloc;
+      switch (constant_size (size_of_locs (AT_loc (a))))
+       {
+       case 1:
+         return DW_FORM_block1;
+       case 2:
+         return DW_FORM_block2;
+       default:
+         gcc_unreachable ();
+       }
+    case dw_val_class_const:
+      return DW_FORM_sdata;
+    case dw_val_class_unsigned_const:
+      switch (constant_size (AT_unsigned (a)))
+       {
+       case 1:
+         return DW_FORM_data1;
+       case 2:
+         return DW_FORM_data2;
+       case 4:
+         /* In DWARF3 DW_AT_data_member_location with
+            DW_FORM_data4 or DW_FORM_data8 is a loclistptr, not
+            constant, so we need to use DW_FORM_udata if we need
+            a large constant.  */
+         if (dwarf_version == 3 && a->dw_attr == DW_AT_data_member_location)
+           return DW_FORM_udata;
+         return DW_FORM_data4;
+       case 8:
+         if (dwarf_version == 3 && a->dw_attr == DW_AT_data_member_location)
+           return DW_FORM_udata;
+         return DW_FORM_data8;
+       default:
+         gcc_unreachable ();
+       }
+    case dw_val_class_const_double:
+      switch (HOST_BITS_PER_WIDE_INT)
+       {
+       case 8:
+         return DW_FORM_data2;
+       case 16:
+         return DW_FORM_data4;
+       case 32:
+         return DW_FORM_data8;
+       case 64:
+       default:
+         return DW_FORM_block1;
+       }
+    case dw_val_class_vec:
+      switch (constant_size (a->dw_attr_val.v.val_vec.length
+                            * a->dw_attr_val.v.val_vec.elt_size))
+       {
+       case 1:
+         return DW_FORM_block1;
+       case 2:
+         return DW_FORM_block2;
+       case 4:
+         return DW_FORM_block4;
+       default:
+         gcc_unreachable ();
+       }
+    case dw_val_class_flag:
+      if (dwarf_version >= 4)
+       {
+         /* Currently all add_AT_flag calls pass in 1 as last argument,
+            so DW_FORM_flag_present can be used.  If that ever changes,
+            we'll need to use DW_FORM_flag and have some optimization
+            in build_abbrev_table that will change those to
+            DW_FORM_flag_present if it is set to 1 in all DIEs using
+            the same abbrev entry.  */
+         gcc_assert (a->dw_attr_val.v.val_flag == 1);
+         return DW_FORM_flag_present;
+       }
+      return DW_FORM_flag;
+    case dw_val_class_die_ref:
+      if (AT_ref_external (a))
+       return use_debug_types ? DW_FORM_ref_sig8 : DW_FORM_ref_addr;
+      else
+       return DW_FORM_ref;
+    case dw_val_class_fde_ref:
+      return DW_FORM_data;
+    case dw_val_class_lbl_id:
+      return DW_FORM_addr;
+    case dw_val_class_lineptr:
+    case dw_val_class_macptr:
+      return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
+    case dw_val_class_str:
+      return AT_string_form (a);
+    case dw_val_class_file:
+      switch (constant_size (maybe_emit_file (a->dw_attr_val.v.val_file)))
+       {
+       case 1:
+         return DW_FORM_data1;
+       case 2:
+         return DW_FORM_data2;
+       case 4:
+         return DW_FORM_data4;
+       default:
+         gcc_unreachable ();
+       }
 
-  return copy;
+    case dw_val_class_data8:
+      return DW_FORM_data8;
+
+    default:
+      gcc_unreachable ();
+    }
 }
 
-/* Walk the DIE and its children, looking for references to incomplete
-   or trivial types that are unmarked (i.e., that are not in the current
-   type_unit).  */
+/* Output the encoding of an attribute value.  */
 
 static void
-copy_decls_walk (dw_die_ref unit, dw_die_ref die, htab_t decl_table)
+output_value_format (dw_attr_ref a)
 {
-  dw_die_ref c;
-  dw_attr_ref a;
-  unsigned ix;
-
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    {
-      if (AT_class (a) == dw_val_class_die_ref)
-        {
-          dw_die_ref targ = AT_ref (a);
-          comdat_type_node_ref type_node = targ->die_id.die_type_node;
-          void **slot;
-          struct decl_table_entry *entry;
+  enum dwarf_form form = value_format (a);
 
-          if (targ->die_mark != 0 || type_node != NULL)
-            continue;
+  dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
+}
 
-          slot = htab_find_slot_with_hash (decl_table, targ,
-                                           htab_hash_pointer (targ), INSERT);
+/* Output the .debug_abbrev section which defines the DIE abbreviation
+   table.  */
 
-          if (*slot != HTAB_EMPTY_ENTRY)
-            {
-              /* TARG has already been copied, so we just need to
-                 modify the reference to point to the copy.  */
-              entry = (struct decl_table_entry *) *slot;
-              a->dw_attr_val.v.val_die_ref.die = entry->copy;
-            }
-          else
-            {
-              dw_die_ref parent = unit;
-              dw_die_ref copy = clone_tree (targ);
+static void
+output_abbrev_section (void)
+{
+  unsigned long abbrev_id;
 
-              /* Make sure the cloned tree is marked as part of the
-                 type unit.  */
-              mark_dies (copy);
+  for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+    {
+      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
+      unsigned ix;
+      dw_attr_ref a_attr;
 
-              /* Record in DECL_TABLE that TARG has been copied.
-                 Need to do this now, before the recursive call,
-                 because DECL_TABLE may be expanded and SLOT
-                 would no longer be a valid pointer.  */
-              entry = XCNEW (struct decl_table_entry);
-              entry->orig = targ;
-              entry->copy = copy;
-              *slot = entry;
+      dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
+      dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
+                                  dwarf_tag_name (abbrev->die_tag));
 
-              /* If TARG has surrounding context, copy its ancestor tree
-                 into the new type unit.  */
-              if (targ->die_parent != NULL
-                  && targ->die_parent->die_tag != DW_TAG_compile_unit
-                  && targ->die_parent->die_tag != DW_TAG_type_unit)
-                parent = copy_ancestor_tree (unit, targ->die_parent,
-                                             decl_table);
+      if (abbrev->die_child != NULL)
+       dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
+      else
+       dw2_asm_output_data (1, DW_children_no, "DW_children_no");
 
-              add_child_die (parent, copy);
-              a->dw_attr_val.v.val_die_ref.die = copy;
+      for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
+          ix++)
+       {
+         dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
+                                      dwarf_attr_name (a_attr->dw_attr));
+         output_value_format (a_attr);
+       }
 
-              /* Make sure the newly-copied DIE is walked.  If it was
-                 installed in a previously-added context, it won't
-                 get visited otherwise.  */
-              if (parent != unit)
-                copy_decls_walk (unit, parent, decl_table);
-            }
-        }
+      dw2_asm_output_data (1, 0, NULL);
+      dw2_asm_output_data (1, 0, NULL);
     }
 
-  FOR_EACH_CHILD (die, c, copy_decls_walk (unit, c, decl_table));
+  /* Terminate the table.  */
+  dw2_asm_output_data (1, 0, NULL);
 }
 
-/* Copy declarations for "unworthy" types into the new comdat section.
-   Incomplete types, modified types, and certain other types aren't broken
-   out into comdat sections of their own, so they don't have a signature,
-   and we need to copy the declaration into the same section so that we
-   don't have an external reference.  */
+/* Output a symbol we can use to refer to this DIE from another CU.  */
 
-static void
-copy_decls_for_unworthy_types (dw_die_ref unit)
+static inline void
+output_die_symbol (dw_die_ref die)
 {
-  htab_t decl_table;
+  char *sym = die->die_id.die_symbol;
 
-  mark_dies (unit);
-  decl_table = htab_create (10, htab_decl_hash, htab_decl_eq, htab_decl_del);
-  copy_decls_walk (unit, unit, decl_table);
-  htab_delete (decl_table);
-  unmark_dies (unit);
+  if (sym == 0)
+    return;
+
+  if (strncmp (sym, DIE_LABEL_PREFIX, sizeof (DIE_LABEL_PREFIX) - 1) == 0)
+    /* We make these global, not weak; if the target doesn't support
+       .linkonce, it doesn't support combining the sections, so debugging
+       will break.  */
+    targetm.asm_out.globalize_label (asm_out_file, sym);
+
+  ASM_OUTPUT_LABEL (asm_out_file, sym);
 }
 
-/* Traverse the DIE and add a sibling attribute if it may have the
-   effect of speeding up access to siblings.  To save some space,
-   avoid generating sibling attributes for DIE's without children.  */
+/* Return a new location list, given the begin and end range, and the
+   expression.  */
 
-static void
-add_sibling_attributes (dw_die_ref die)
+static inline dw_loc_list_ref
+new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
+             const char *section)
 {
-  dw_die_ref c;
-
-  if (! die->die_child)
-    return;
+  dw_loc_list_ref retlist = ggc_alloc_cleared_dw_loc_list_node ();
 
-  if (die->die_parent && die != die->die_parent->die_child)
-    add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
+  retlist->begin = begin;
+  retlist->end = end;
+  retlist->expr = expr;
+  retlist->section = section;
 
-  FOR_EACH_CHILD (die, c, add_sibling_attributes (c));
+  return retlist;
 }
 
-/* Output all location lists for the DIE and its children.  */
+/* Generate a new internal symbol for this location list node, if it
+   hasn't got one yet.  */
 
-static void
-output_location_lists (dw_die_ref die)
+static inline void
+gen_llsym (dw_loc_list_ref list)
 {
-  dw_die_ref c;
-  dw_attr_ref a;
-  unsigned ix;
-
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    if (AT_class (a) == dw_val_class_loc_list)
-      output_loc_list (AT_loc_list (a));
-
-  FOR_EACH_CHILD (die, c, output_location_lists (c));
+  gcc_assert (!list->ll_symbol);
+  list->ll_symbol = gen_internal_sym ("LLST");
 }
 
-/* The format of each DIE (and its attribute value pairs) is encoded in an
-   abbreviation table.  This routine builds the abbreviation table and assigns
-   a unique abbreviation id for each abbreviation entry.  The children of each
-   die are visited recursively.  */
+/* Output the location list given to us.  */
 
 static void
-build_abbrev_table (dw_die_ref die)
+output_loc_list (dw_loc_list_ref list_head)
 {
-  unsigned long abbrev_id;
-  unsigned int n_alloc;
-  dw_die_ref c;
-  dw_attr_ref a;
-  unsigned ix;
-
-  /* Scan the DIE references, and mark as external any that refer to
-     DIEs from other CUs (i.e. those which are not marked).  */
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    if (AT_class (a) == dw_val_class_die_ref
-       && AT_ref (a)->die_mark == 0)
-      {
-       gcc_assert (dwarf_version >= 4 || AT_ref (a)->die_id.die_symbol);
-       set_AT_ref_external (a, 1);
-      }
+  dw_loc_list_ref curr = list_head;
 
-  for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
-    {
-      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
-      dw_attr_ref die_a, abbrev_a;
-      unsigned ix;
-      bool ok = true;
+  if (list_head->emitted)
+    return;
+  list_head->emitted = true;
 
-      if (abbrev->die_tag != die->die_tag)
-       continue;
-      if ((abbrev->die_child != NULL) != (die->die_child != NULL))
-       continue;
+  ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
 
-      if (VEC_length (dw_attr_node, abbrev->die_attr)
-         != VEC_length (dw_attr_node, die->die_attr))
+  /* Walk the location list, and output each range + expression.  */
+  for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
+    {
+      unsigned long size;
+      /* Don't output an entry that starts and ends at the same address.  */
+      if (strcmp (curr->begin, curr->end) == 0 && !curr->force)
        continue;
-
-      for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, die_a); ix++)
+      if (!have_multiple_function_sections)
        {
-         abbrev_a = VEC_index (dw_attr_node, abbrev->die_attr, ix);
-         if ((abbrev_a->dw_attr != die_a->dw_attr)
-             || (value_format (abbrev_a) != value_format (die_a)))
-           {
-             ok = false;
-             break;
-           }
+         dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
+                               "Location list begin address (%s)",
+                               list_head->ll_symbol);
+         dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->end, curr->section,
+                               "Location list end address (%s)",
+                               list_head->ll_symbol);
        }
-      if (ok)
-       break;
-    }
-
-  if (abbrev_id >= abbrev_die_table_in_use)
-    {
-      if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
+      else
        {
-         n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
-         abbrev_die_table = GGC_RESIZEVEC (dw_die_ref, abbrev_die_table,
-                                           n_alloc);
-
-         memset (&abbrev_die_table[abbrev_die_table_allocated], 0,
-                (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
-         abbrev_die_table_allocated = n_alloc;
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->begin,
+                              "Location list begin address (%s)",
+                              list_head->ll_symbol);
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->end,
+                              "Location list end address (%s)",
+                              list_head->ll_symbol);
        }
+      size = size_of_locs (curr->expr);
 
-      ++abbrev_die_table_in_use;
-      abbrev_die_table[abbrev_id] = die;
-    }
+      /* Output the block length for this list of location operations.  */
+      gcc_assert (size <= 0xffff);
+      dw2_asm_output_data (2, size, "%s", "Location expression size");
 
-  die->die_abbrev = abbrev_id;
-  FOR_EACH_CHILD (die, c, build_abbrev_table (c));
-}
-\f
-/* Return the power-of-two number of bytes necessary to represent VALUE.  */
+      output_loc_sequence (curr->expr, -1);
+    }
 
-static int
-constant_size (unsigned HOST_WIDE_INT value)
-{
-  int log;
+  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
+                      "Location list terminator begin (%s)",
+                      list_head->ll_symbol);
+  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
+                      "Location list terminator end (%s)",
+                      list_head->ll_symbol);
+}
 
-  if (value == 0)
-    log = 0;
-  else
-    log = floor_log2 (value);
+/* Output a type signature.  */
 
-  log = log / 8;
-  log = 1 << (floor_log2 (log) + 1);
+static inline void
+output_signature (const char *sig, const char *name)
+{
+  int i;
 
-  return log;
+  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+    dw2_asm_output_data (1, sig[i], i == 0 ? "%s" : NULL, name);
 }
 
-/* Return the size of a DIE as it is represented in the
-   .debug_info section.  */
+/* Output the DIE and its attributes.  Called recursively to generate
+   the definitions of each child DIE.  */
 
-static unsigned long
-size_of_die (dw_die_ref die)
+static void
+output_die (dw_die_ref die)
 {
-  unsigned long size = 0;
   dw_attr_ref a;
+  dw_die_ref c;
+  unsigned long size;
   unsigned ix;
 
-  size += size_of_uleb128 (die->die_abbrev);
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  /* If someone in another CU might refer to us, set up a symbol for
+     them to point to.  */
+  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_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     {
+      const char *name = dwarf_attr_name (a->dw_attr);
+
       switch (AT_class (a))
        {
        case dw_val_class_addr:
-         size += DWARF2_ADDR_SIZE;
+         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
          break;
+
        case dw_val_class_offset:
-         size += DWARF_OFFSET_SIZE;
+         dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
+                              "%s", name);
          break;
-       case dw_val_class_loc:
+
+       case dw_val_class_range_list:
          {
-           unsigned long lsize = size_of_locs (AT_loc (a));
+           char *p = strchr (ranges_section_label, '\0');
 
-           /* Block length.  */
-           if (dwarf_version >= 4)
-             size += size_of_uleb128 (lsize);
-           else
-             size += constant_size (lsize);
-           size += lsize;
+           sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
+                    a->dw_attr_val.v.val_offset);
+           dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
+                                  debug_ranges_section, "%s", name);
+           *p = '\0';
          }
          break;
-       case dw_val_class_loc_list:
-         size += DWARF_OFFSET_SIZE;
-         break;
-       case dw_val_class_range_list:
-         size += DWARF_OFFSET_SIZE;
+
+       case dw_val_class_loc:
+         size = size_of_locs (AT_loc (a));
+
+         /* Output the block length for this list of location operations.  */
+         if (dwarf_version >= 4)
+           dw2_asm_output_data_uleb128 (size, "%s", name);
+         else
+           dw2_asm_output_data (constant_size (size), size, "%s", name);
+
+         output_loc_sequence (AT_loc (a), -1);
          break;
+
        case dw_val_class_const:
-         size += size_of_sleb128 (AT_int (a));
+         /* ??? It would be slightly more efficient to use a scheme like is
+            used for unsigned constants below, but gdb 4.x does not sign
+            extend.  Gdb 5.x does sign extend.  */
+         dw2_asm_output_data_sleb128 (AT_int (a), "%s", name);
          break;
+
        case dw_val_class_unsigned_const:
-         size += constant_size (AT_unsigned (a));
+         {
+           int csize = constant_size (AT_unsigned (a));
+           if (dwarf_version == 3
+               && a->dw_attr == DW_AT_data_member_location
+               && csize >= 4)
+             dw2_asm_output_data_uleb128 (AT_unsigned (a), "%s", name);
+           else
+             dw2_asm_output_data (csize, AT_unsigned (a), "%s", name);
+         }
          break;
+
        case dw_val_class_const_double:
-         size += 2 * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
-         if (HOST_BITS_PER_WIDE_INT >= 64)
-           size++; /* block */
+         {
+           unsigned HOST_WIDE_INT first, second;
+
+           if (HOST_BITS_PER_WIDE_INT >= 64)
+             dw2_asm_output_data (1,
+                                  2 * HOST_BITS_PER_WIDE_INT
+                                  / HOST_BITS_PER_CHAR,
+                                  NULL);
+
+           if (WORDS_BIG_ENDIAN)
+             {
+               first = a->dw_attr_val.v.val_double.high;
+               second = a->dw_attr_val.v.val_double.low;
+             }
+           else
+             {
+               first = a->dw_attr_val.v.val_double.low;
+               second = a->dw_attr_val.v.val_double.high;
+             }
+
+           dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
+                                first, name);
+           dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
+                                second, NULL);
+         }
          break;
+
        case dw_val_class_vec:
-         size += constant_size (a->dw_attr_val.v.val_vec.length
-                                * a->dw_attr_val.v.val_vec.elt_size)
-                 + a->dw_attr_val.v.val_vec.length
-                   * a->dw_attr_val.v.val_vec.elt_size; /* block */
-         break;
+         {
+           unsigned int elt_size = a->dw_attr_val.v.val_vec.elt_size;
+           unsigned int len = a->dw_attr_val.v.val_vec.length;
+           unsigned int i;
+           unsigned char *p;
+
+           dw2_asm_output_data (constant_size (len * elt_size),
+                                len * elt_size, "%s", name);
+           if (elt_size > sizeof (HOST_WIDE_INT))
+             {
+               elt_size /= 2;
+               len *= 2;
+             }
+           for (i = 0, p = a->dw_attr_val.v.val_vec.array;
+                i < len;
+                i++, p += elt_size)
+             dw2_asm_output_data (elt_size, extract_int (p, elt_size),
+                                  "fp or vector constant word %u", i);
+           break;
+         }
+
        case dw_val_class_flag:
          if (dwarf_version >= 4)
-           /* Currently all add_AT_flag calls pass in 1 as last argument,
-              so DW_FORM_flag_present can be used.  If that ever changes,
-              we'll need to use DW_FORM_flag and have some optimization
-              in build_abbrev_table that will change those to
-              DW_FORM_flag_present if it is set to 1 in all DIEs using
-              the same abbrev entry.  */
-           gcc_assert (a->dw_attr_val.v.val_flag == 1);
-         else
-           size += 1;
+           {
+             /* Currently all add_AT_flag calls pass in 1 as last argument,
+                so DW_FORM_flag_present can be used.  If that ever changes,
+                we'll need to use DW_FORM_flag and have some optimization
+                in build_abbrev_table that will change those to
+                DW_FORM_flag_present if it is set to 1 in all DIEs using
+                the same abbrev entry.  */
+             gcc_assert (AT_flag (a) == 1);
+             if (flag_debug_asm)
+               fprintf (asm_out_file, "\t\t\t%s %s\n",
+                        ASM_COMMENT_START, name);
+             break;
+           }
+         dw2_asm_output_data (1, AT_flag (a), "%s", name);
+         break;
+
+       case dw_val_class_loc_list:
+         {
+           char *sym = AT_loc_list (a)->ll_symbol;
+
+           gcc_assert (sym);
+           dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
+                                  "%s", name);
+         }
          break;
+
        case dw_val_class_die_ref:
          if (AT_ref_external (a))
            {
-             /* In DWARF4, we use DW_FORM_sig8; for earlier versions
-                we use DW_FORM_ref_addr.  In DWARF2, DW_FORM_ref_addr
-                is sized by target address length, whereas in DWARF3
-                it's always sized as an offset.  */
-             if (dwarf_version >= 4)
-               size += DWARF_TYPE_SIGNATURE_SIZE;
-             else if (dwarf_version == 2)
-               size += DWARF2_ADDR_SIZE;
+             if (use_debug_types)
+               {
+                 comdat_type_node_ref type_node =
+                   AT_ref (a)->die_id.die_type_node;
+
+                 gcc_assert (type_node);
+                 output_signature (type_node->signature, name);
+               }
              else
-               size += DWARF_OFFSET_SIZE;
+               {
+                 char *sym = AT_ref (a)->die_id.die_symbol;
+                 int size;
+
+                 gcc_assert (sym);
+                 /* In DWARF2, DW_FORM_ref_addr is sized by target address
+                    length, whereas in DWARF3 it's always sized as an
+                    offset.  */
+                 if (dwarf_version == 2)
+                   size = DWARF2_ADDR_SIZE;
+                 else
+                   size = DWARF_OFFSET_SIZE;
+                 dw2_asm_output_offset (size, sym, debug_info_section, "%s",
+                                        name);
+               }
            }
          else
-           size += DWARF_OFFSET_SIZE;
+           {
+             gcc_assert (AT_ref (a)->die_offset);
+             dw2_asm_output_data (DWARF_OFFSET_SIZE, AT_ref (a)->die_offset,
+                                  "%s", name);
+           }
          break;
+
        case dw_val_class_fde_ref:
-         size += DWARF_OFFSET_SIZE;
+         {
+           char l1[20];
+
+           ASM_GENERATE_INTERNAL_LABEL (l1, FDE_LABEL,
+                                        a->dw_attr_val.v.val_fde_index * 2);
+           dw2_asm_output_offset (DWARF_OFFSET_SIZE, l1, debug_frame_section,
+                                  "%s", name);
+         }
          break;
+
+       case dw_val_class_vms_delta:
+         dw2_asm_output_vms_delta (DWARF_OFFSET_SIZE,
+                                   AT_vms_delta2 (a), AT_vms_delta1 (a),
+                                   "%s", name);
+         break;
+
        case dw_val_class_lbl_id:
-         size += DWARF2_ADDR_SIZE;
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
          break;
+
        case dw_val_class_lineptr:
+         dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
+                                debug_line_section, "%s", name);
+         break;
+
        case dw_val_class_macptr:
-         size += DWARF_OFFSET_SIZE;
+         dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
+                                debug_macinfo_section, "%s", name);
          break;
+
        case dw_val_class_str:
          if (AT_string_form (a) == DW_FORM_strp)
-           size += DWARF_OFFSET_SIZE;
+           dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+                                  a->dw_attr_val.v.val_str->label,
+                                  debug_str_section,
+                                  "%s: \"%s\"", name, AT_string (a));
          else
-           size += strlen (a->dw_attr_val.v.val_str->str) + 1;
+           dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
          break;
+
        case dw_val_class_file:
-         size += constant_size (maybe_emit_file (a->dw_attr_val.v.val_file));
-         break;
+         {
+           int f = maybe_emit_file (a->dw_attr_val.v.val_file);
+
+           dw2_asm_output_data (constant_size (f), f, "%s (%s)", name,
+                                a->dw_attr_val.v.val_file->filename);
+           break;
+         }
+
        case dw_val_class_data8:
-         size += 8;
-         break;
+         {
+           int i;
+
+           for (i = 0; i < 8; i++)
+             dw2_asm_output_data (1, a->dw_attr_val.v.val_data8[i],
+                                  i == 0 ? "%s" : NULL, name);
+           break;
+         }
+
        default:
          gcc_unreachable ();
        }
     }
 
-  return size;
+  FOR_EACH_CHILD (die, c, output_die (c));
+
+  /* Add null byte to terminate sibling list.  */
+  if (die->die_child != NULL)
+    dw2_asm_output_data (1, 0, "end of children of DIE %#lx",
+                        (unsigned long) die->die_offset);
 }
 
-/* Size the debugging information associated with a given DIE.  Visits the
-   DIE's children recursively.  Updates the global variable next_die_offset, on
-   each time through.  Uses the current value of next_die_offset to update the
-   die_offset field in each DIE.  */
+/* Output the compilation unit that appears at the beginning of the
+   .debug_info section, and precedes the DIE descriptions.  */
 
 static void
-calc_die_sizes (dw_die_ref die)
+output_compilation_unit_header (void)
 {
-  dw_die_ref c;
+  int ver = dwarf_version;
 
-  die->die_offset = next_die_offset;
-  next_die_offset += size_of_die (die);
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+    dw2_asm_output_data (4, 0xffffffff,
+      "Initial length escape value indicating 64-bit DWARF extension");
+  dw2_asm_output_data (DWARF_OFFSET_SIZE,
+                      next_die_offset - DWARF_INITIAL_LENGTH_SIZE,
+                      "Length of Compilation Unit Info");
+  dw2_asm_output_data (2, ver, "DWARF version number");
+  dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
+                        debug_abbrev_section,
+                        "Offset Into Abbrev. Section");
+  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+}
 
-  FOR_EACH_CHILD (die, c, calc_die_sizes (c));
+/* Output the compilation unit DIE and its children.  */
 
-  if (die->die_child != NULL)
-    /* Count the null byte used to terminate sibling lists.  */
-    next_die_offset += 1;
+static void
+output_comp_unit (dw_die_ref die, int output_if_empty)
+{
+  const char *secname;
+  char *oldsym, *tmp;
+
+  /* Unless we are outputting main CU, we may throw away empty ones.  */
+  if (!output_if_empty && die->die_child == NULL)
+    return;
+
+  /* Even if there are no children of this DIE, we must output the information
+     about the compilation unit.  Otherwise, on an empty translation unit, we
+     will generate a present, but empty, .debug_info section.  IRIX 6.5 `nm'
+     will then complain when examining the file.  First mark all the DIEs in
+     this CU so we know which get local refs.  */
+  mark_dies (die);
+
+  build_abbrev_table (die);
+
+  /* Initialize the beginning DIE offset - and calculate sizes/offsets.  */
+  next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
+  calc_die_sizes (die);
+
+  oldsym = die->die_id.die_symbol;
+  if (oldsym)
+    {
+      tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
+
+      sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym);
+      secname = tmp;
+      die->die_id.die_symbol = NULL;
+      switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
+    }
+  else
+    {
+      switch_to_section (debug_info_section);
+      ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label);
+      info_section_emitted = true;
+    }
+
+  /* Output debugging information.  */
+  output_compilation_unit_header ();
+  output_die (die);
+
+  /* Leave the marks on the main CU, so we can check them in
+     output_pubnames.  */
+  if (oldsym)
+    {
+      unmark_dies (die);
+      die->die_id.die_symbol = oldsym;
+    }
 }
 
-/* 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.  */
+/* Output a comdat type unit DIE and its children.  */
 
 static void
-mark_dies (dw_die_ref die)
+output_comdat_type_unit (comdat_type_node *node)
 {
-  dw_die_ref c;
+  const char *secname;
+  char *tmp;
+  int i;
+#if defined (OBJECT_FORMAT_ELF)
+  tree comdat_key;
+#endif
 
-  gcc_assert (!die->die_mark);
+  /* First mark all the DIEs in this CU so we know which get local refs.  */
+  mark_dies (node->root_die);
 
-  die->die_mark = 1;
-  FOR_EACH_CHILD (die, c, mark_dies (c));
+  build_abbrev_table (node->root_die);
+
+  /* Initialize the beginning DIE offset - and calculate sizes/offsets.  */
+  next_die_offset = DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE;
+  calc_die_sizes (node->root_die);
+
+#if defined (OBJECT_FORMAT_ELF)
+  secname = ".debug_types";
+  tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2);
+  sprintf (tmp, "wt.");
+  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+    sprintf (tmp + 3 + i * 2, "%02x", node->signature[i] & 0xff);
+  comdat_key = get_identifier (tmp);
+  targetm.asm_out.named_section (secname,
+                                 SECTION_DEBUG | SECTION_LINKONCE,
+                                 comdat_key);
+#else
+  tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2);
+  sprintf (tmp, ".gnu.linkonce.wt.");
+  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+    sprintf (tmp + 17 + i * 2, "%02x", node->signature[i] & 0xff);
+  secname = tmp;
+  switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
+#endif
+
+  /* Output debugging information.  */
+  output_compilation_unit_header ();
+  output_signature (node->signature, "Type Signature");
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, node->type_die->die_offset,
+                      "Offset to Type DIE");
+  output_die (node->root_die);
+
+  unmark_dies (node->root_die);
 }
 
-/* Clear the marks for a die and its children.  */
+/* Return the DWARF2/3 pubname associated with a decl.  */
+
+static const char *
+dwarf2_name (tree decl, int scope)
+{
+  if (DECL_NAMELESS (decl))
+    return NULL;
+  return lang_hooks.dwarf_name (decl, scope ? 1 : 0);
+}
+
+/* Add a new entry to .debug_pubnames if appropriate.  */
 
 static void
-unmark_dies (dw_die_ref die)
+add_pubname_string (const char *str, dw_die_ref die)
 {
-  dw_die_ref c;
+  if (targetm.want_debug_pub_sections)
+    {
+      pubname_entry e;
 
-  if (dwarf_version < 4)
-    gcc_assert (die->die_mark);
+      e.die = die;
+      e.name = xstrdup (str);
+      VEC_safe_push (pubname_entry, gc, pubname_table, &e);
+    }
+}
 
-  die->die_mark = 0;
-  FOR_EACH_CHILD (die, c, unmark_dies (c));
+static void
+add_pubname (tree decl, dw_die_ref die)
+{
+  if (targetm.want_debug_pub_sections && TREE_PUBLIC (decl))
+    {
+      const char *name = dwarf2_name (decl, 1);
+      if (name)
+       add_pubname_string (name, die);
+    }
 }
 
-/* Clear the marks for a die, its children and referred dies.  */
+/* Add a new entry to .debug_pubtypes if appropriate.  */
 
 static void
-unmark_all_dies (dw_die_ref die)
+add_pubtype (tree decl, dw_die_ref die)
 {
-  dw_die_ref c;
-  dw_attr_ref a;
-  unsigned ix;
+  pubname_entry e;
 
-  if (!die->die_mark)
+  if (!targetm.want_debug_pub_sections)
     return;
-  die->die_mark = 0;
 
-  FOR_EACH_CHILD (die, c, unmark_all_dies (c));
+  e.name = NULL;
+  if ((TREE_PUBLIC (decl)
+       || is_cu_die (die->die_parent))
+      && (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl)))
+    {
+      e.die = die;
+      if (TYPE_P (decl))
+       {
+         if (TYPE_NAME (decl))
+           {
+             if (TREE_CODE (TYPE_NAME (decl)) == IDENTIFIER_NODE)
+               e.name = IDENTIFIER_POINTER (TYPE_NAME (decl));
+             else if (TREE_CODE (TYPE_NAME (decl)) == TYPE_DECL
+                      && DECL_NAME (TYPE_NAME (decl)))
+               e.name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl)));
+             else
+              e.name = xstrdup ((const char *) get_AT_string (die, DW_AT_name));
+           }
+       }
+      else
+       {
+         e.name = dwarf2_name (decl, 1);
+         if (e.name)
+           e.name = xstrdup (e.name);
+       }
+
+      /* If we don't have a name for the type, there's no point in adding
+        it to the table.  */
+      if (e.name && e.name[0] != '\0')
+       VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
+    }
+}
+
+/* Output the public names table used to speed up access to externally
+   visible names; or the public types table used to find type definitions.  */
+
+static void
+output_pubnames (VEC (pubname_entry, gc) * names)
+{
+  unsigned i;
+  unsigned long pubnames_length = size_of_pubnames (names);
+  pubname_ref pub;
+
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+    dw2_asm_output_data (4, 0xffffffff,
+      "Initial length escape value indicating 64-bit DWARF extension");
+  if (names == pubname_table)
+    dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
+                        "Length of Public Names Info");
+  else
+    dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
+                        "Length of Public Type Names Info");
+  /* Version number for pubnames/pubtypes is still 2, even in DWARF3.  */
+  dw2_asm_output_data (2, 2, "DWARF Version");
+  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+                        debug_info_section,
+                        "Offset of Compilation Unit Info");
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
+                      "Compilation Unit Length");
+
+  FOR_EACH_VEC_ELT (pubname_entry, names, i, pub)
+    {
+      /* We shouldn't see pubnames for DIEs outside of the main CU.  */
+      if (names == pubname_table)
+       gcc_assert (pub->die->die_mark);
+
+      if (names != pubtype_table
+         || pub->die->die_offset != 0
+         || !flag_eliminate_unused_debug_types)
+       {
+         dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
+                              "DIE offset");
+
+         dw2_asm_output_nstring (pub->name, -1, "external name");
+       }
+    }
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    if (AT_class (a) == dw_val_class_die_ref)
-      unmark_all_dies (AT_ref (a));
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL);
 }
 
-/* Return the size of the .debug_pubnames or .debug_pubtypes table
-   generated for the compilation unit.  */
+/* 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 unsigned long
-size_of_pubnames (VEC (pubname_entry, gc) * names)
+static void
+output_aranges (unsigned long aranges_length)
 {
-  unsigned long size;
   unsigned i;
-  pubname_ref p;
-
-  size = DWARF_PUBNAMES_HEADER_SIZE;
-  for (i = 0; VEC_iterate (pubname_entry, names, i, p); i++)
-    if (names != pubtype_table
-       || p->die->die_offset != 0
-       || !flag_eliminate_unused_debug_types)
-      size += strlen (p->name) + DWARF_OFFSET_SIZE + 1;
-
-  size += DWARF_OFFSET_SIZE;
-  return size;
-}
 
-/* Return the size of the information in the .debug_aranges section.  */
-
-static unsigned long
-size_of_aranges (void)
-{
-  unsigned long size;
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+    dw2_asm_output_data (4, 0xffffffff,
+      "Initial length escape value indicating 64-bit DWARF extension");
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, aranges_length,
+                      "Length of Address Ranges Info");
+  /* Version number for aranges is still 2, even in DWARF3.  */
+  dw2_asm_output_data (2, 2, "DWARF Version");
+  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+                        debug_info_section,
+                        "Offset of Compilation Unit Info");
+  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
+  dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
 
-  size = DWARF_ARANGES_HEADER_SIZE;
+  /* We need to align to twice the pointer size here.  */
+  if (DWARF_ARANGES_PAD_SIZE)
+    {
+      /* Pad using a 2 byte words so that padding is correct for any
+        pointer size.  */
+      dw2_asm_output_data (2, 0, "Pad to %d byte boundary",
+                          2 * DWARF2_ADDR_SIZE);
+      for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
+       dw2_asm_output_data (2, 0, NULL);
+    }
 
-  /* Count the address/length pair for this compilation unit.  */
+  /* It is necessary not to output these entries if the sections were
+     not used; if the sections were not used, the length will be 0 and
+     the address may end up as 0 if the section is discarded by ld
+     --gc-sections, leaving an invalid (0, 0) entry that can be
+     confused with the terminator.  */
   if (text_section_used)
-    size += 2 * DWARF2_ADDR_SIZE;
+    {
+      dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_section_label, "Address");
+      dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
+                           text_section_label, "Length");
+    }
   if (cold_text_section_used)
-    size += 2 * DWARF2_ADDR_SIZE;
-  size += 2 * DWARF2_ADDR_SIZE * arange_table_in_use;
-
-  /* Count the two zero words used to terminated the address range table.  */
-  size += 2 * DWARF2_ADDR_SIZE;
-  return size;
-}
-\f
-/* Select the encoding of an attribute value.  */
+    {
+      dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label,
+                          "Address");
+      dw2_asm_output_delta (DWARF2_ADDR_SIZE, cold_end_label,
+                           cold_text_section_label, "Length");
+    }
 
-static enum dwarf_form
-value_format (dw_attr_ref a)
-{
-  switch (a->dw_attr_val.val_class)
+  if (have_multiple_function_sections)
     {
-    case dw_val_class_addr:
-      /* Only very few attributes allow DW_FORM_addr.  */
-      switch (a->dw_attr)
-       {
-       case DW_AT_low_pc:
-       case DW_AT_high_pc:
-       case DW_AT_entry_pc:
-       case DW_AT_trampoline:
-         return DW_FORM_addr;
-       default:
-         break;
-       }
-      switch (DWARF2_ADDR_SIZE)
-       {
-       case 1:
-         return DW_FORM_data1;
-       case 2:
-         return DW_FORM_data2;
-       case 4:
-         return DW_FORM_data4;
-       case 8:
-         return DW_FORM_data8;
-       default:
-         gcc_unreachable ();
-       }
-    case dw_val_class_range_list:
-    case dw_val_class_loc_list:
-      if (dwarf_version >= 4)
-       return DW_FORM_sec_offset;
-      /* FALLTHRU */
-    case dw_val_class_offset:
-      switch (DWARF_OFFSET_SIZE)
-       {
-       case 4:
-         return DW_FORM_data4;
-       case 8:
-         return DW_FORM_data8;
-       default:
-         gcc_unreachable ();
-       }
-    case dw_val_class_loc:
-      if (dwarf_version >= 4)
-       return DW_FORM_exprloc;
-      switch (constant_size (size_of_locs (AT_loc (a))))
-       {
-       case 1:
-         return DW_FORM_block1;
-       case 2:
-         return DW_FORM_block2;
-       default:
-         gcc_unreachable ();
-       }
-    case dw_val_class_const:
-      return DW_FORM_sdata;
-    case dw_val_class_unsigned_const:
-      switch (constant_size (AT_unsigned (a)))
-       {
-       case 1:
-         return DW_FORM_data1;
-       case 2:
-         return DW_FORM_data2;
-       case 4:
-         return DW_FORM_data4;
-       case 8:
-         return DW_FORM_data8;
-       default:
-         gcc_unreachable ();
-       }
-    case dw_val_class_const_double:
-      switch (HOST_BITS_PER_WIDE_INT)
-       {
-       case 8:
-         return DW_FORM_data2;
-       case 16:
-         return DW_FORM_data4;
-       case 32:
-         return DW_FORM_data8;
-       case 64:
-       default:
-         return DW_FORM_block1;
-       }
-    case dw_val_class_vec:
-      switch (constant_size (a->dw_attr_val.v.val_vec.length
-                            * a->dw_attr_val.v.val_vec.elt_size))
-       {
-       case 1:
-         return DW_FORM_block1;
-       case 2:
-         return DW_FORM_block2;
-       case 4:
-         return DW_FORM_block4;
-       default:
-         gcc_unreachable ();
-       }
-    case dw_val_class_flag:
-      if (dwarf_version >= 4)
-       {
-         /* Currently all add_AT_flag calls pass in 1 as last argument,
-            so DW_FORM_flag_present can be used.  If that ever changes,
-            we'll need to use DW_FORM_flag and have some optimization
-            in build_abbrev_table that will change those to
-            DW_FORM_flag_present if it is set to 1 in all DIEs using
-            the same abbrev entry.  */
-         gcc_assert (a->dw_attr_val.v.val_flag == 1);
-         return DW_FORM_flag_present;
-       }
-      return DW_FORM_flag;
-    case dw_val_class_die_ref:
-      if (AT_ref_external (a))
-       return dwarf_version >= 4 ? DW_FORM_sig8 : DW_FORM_ref_addr;
-      else
-       return DW_FORM_ref;
-    case dw_val_class_fde_ref:
-      return DW_FORM_data;
-    case dw_val_class_lbl_id:
-      return DW_FORM_addr;
-    case dw_val_class_lineptr:
-    case dw_val_class_macptr:
-      return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
-    case dw_val_class_str:
-      return AT_string_form (a);
-    case dw_val_class_file:
-      switch (constant_size (maybe_emit_file (a->dw_attr_val.v.val_file)))
+      unsigned fde_idx;
+      dw_fde_ref fde;
+
+      FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde)
        {
-       case 1:
-         return DW_FORM_data1;
-       case 2:
-         return DW_FORM_data2;
-       case 4:
-         return DW_FORM_data4;
-       default:
-         gcc_unreachable ();
+         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");
+           }
        }
+    }
 
-    case dw_val_class_data8:
-      return DW_FORM_data8;
+  /* Output the terminator words.  */
+  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+}
 
-    default:
-      gcc_unreachable ();
+/* Add a new entry to .debug_ranges.  Return the offset at which it
+   was placed.  */
+
+static unsigned int
+add_ranges_num (int num)
+{
+  unsigned int in_use = ranges_table_in_use;
+
+  if (in_use == ranges_table_allocated)
+    {
+      ranges_table_allocated += RANGES_TABLE_INCREMENT;
+      ranges_table = GGC_RESIZEVEC (struct dw_ranges_struct, ranges_table,
+                                   ranges_table_allocated);
+      memset (ranges_table + ranges_table_in_use, 0,
+             RANGES_TABLE_INCREMENT * sizeof (struct dw_ranges_struct));
     }
+
+  ranges_table[in_use].num = num;
+  ranges_table_in_use = in_use + 1;
+
+  return in_use * 2 * DWARF2_ADDR_SIZE;
+}
+
+/* Add a new entry to .debug_ranges corresponding to a block, or a
+   range terminator if BLOCK is NULL.  */
+
+static unsigned int
+add_ranges (const_tree block)
+{
+  return add_ranges_num (block ? BLOCK_NUMBER (block) : 0);
 }
 
-/* Output the encoding of an attribute value.  */
+/* Add a new entry to .debug_ranges corresponding to a pair of
+   labels.  */
 
 static void
-output_value_format (dw_attr_ref a)
+add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
+                     bool *added)
 {
-  enum dwarf_form form = value_format (a);
+  unsigned int in_use = ranges_by_label_in_use;
+  unsigned int offset;
 
-  dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
-}
+  if (in_use == ranges_by_label_allocated)
+    {
+      ranges_by_label_allocated += RANGES_TABLE_INCREMENT;
+      ranges_by_label = GGC_RESIZEVEC (struct dw_ranges_by_label_struct,
+                                      ranges_by_label,
+                                      ranges_by_label_allocated);
+      memset (ranges_by_label + ranges_by_label_in_use, 0,
+             RANGES_TABLE_INCREMENT
+             * sizeof (struct dw_ranges_by_label_struct));
+    }
 
-/* Output the .debug_abbrev section which defines the DIE abbreviation
-   table.  */
+  ranges_by_label[in_use].begin = begin;
+  ranges_by_label[in_use].end = end;
+  ranges_by_label_in_use = in_use + 1;
+
+  offset = add_ranges_num (-(int)in_use - 1);
+  if (!*added)
+    {
+      add_AT_range_list (die, DW_AT_ranges, offset);
+      *added = true;
+    }
+}
 
 static void
-output_abbrev_section (void)
+output_ranges (void)
 {
-  unsigned long abbrev_id;
+  unsigned i;
+  static const char *const start_fmt = "Offset %#x";
+  const char *fmt = start_fmt;
 
-  for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+  for (i = 0; i < ranges_table_in_use; i++)
     {
-      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
-      unsigned ix;
-      dw_attr_ref a_attr;
+      int block_num = ranges_table[i].num;
 
-      dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
-      dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
-                                  dwarf_tag_name (abbrev->die_tag));
+      if (block_num > 0)
+       {
+         char blabel[MAX_ARTIFICIAL_LABEL_BYTES];
+         char elabel[MAX_ARTIFICIAL_LABEL_BYTES];
 
-      if (abbrev->die_child != NULL)
-       dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
-      else
-       dw2_asm_output_data (1, DW_children_no, "DW_children_no");
+         ASM_GENERATE_INTERNAL_LABEL (blabel, BLOCK_BEGIN_LABEL, block_num);
+         ASM_GENERATE_INTERNAL_LABEL (elabel, BLOCK_END_LABEL, block_num);
 
-      for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
-          ix++)
-       {
-         dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
-                                      dwarf_attr_name (a_attr->dw_attr));
-         output_value_format (a_attr);
+         /* If all code is in the text section, then the compilation
+            unit base address defaults to DW_AT_low_pc, which is the
+            base of the text section.  */
+         if (!have_multiple_function_sections)
+           {
+             dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
+                                   text_section_label,
+                                   fmt, i * 2 * DWARF2_ADDR_SIZE);
+             dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
+                                   text_section_label, NULL);
+           }
+
+         /* Otherwise, the compilation unit base address is zero,
+            which allows us to use absolute addresses, and not worry
+            about whether the target supports cross-section
+            arithmetic.  */
+         else
+           {
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
+                                  fmt, i * 2 * DWARF2_ADDR_SIZE);
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE, elabel, NULL);
+           }
+
+         fmt = NULL;
        }
 
-      dw2_asm_output_data (1, 0, NULL);
-      dw2_asm_output_data (1, 0, NULL);
-    }
+      /* Negative block_num stands for an index into ranges_by_label.  */
+      else if (block_num < 0)
+       {
+         int lab_idx = - block_num - 1;
 
-  /* Terminate the table.  */
-  dw2_asm_output_data (1, 0, NULL);
+         if (!have_multiple_function_sections)
+           {
+             gcc_unreachable ();
+#if 0
+             /* If we ever use add_ranges_by_labels () for a single
+                function section, all we have to do is to take out
+                the #if 0 above.  */
+             dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+                                   ranges_by_label[lab_idx].begin,
+                                   text_section_label,
+                                   fmt, i * 2 * DWARF2_ADDR_SIZE);
+             dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+                                   ranges_by_label[lab_idx].end,
+                                   text_section_label, NULL);
+#endif
+           }
+         else
+           {
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+                                  ranges_by_label[lab_idx].begin,
+                                  fmt, i * 2 * DWARF2_ADDR_SIZE);
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+                                  ranges_by_label[lab_idx].end,
+                                  NULL);
+           }
+       }
+      else
+       {
+         dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+         dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+         fmt = start_fmt;
+       }
+    }
 }
 
-/* Output a symbol we can use to refer to this DIE from another CU.  */
-
-static inline void
-output_die_symbol (dw_die_ref die)
+/* Data structure containing information about input files.  */
+struct file_info
 {
-  char *sym = die->die_id.die_symbol;
+  const char *path;    /* Complete file name.  */
+  const char *fname;   /* File name part.  */
+  int length;          /* Length of entire string.  */
+  struct dwarf_file_data * file_idx;   /* Index in input file table.  */
+  int dir_idx;         /* Index in directory table.  */
+};
 
-  if (sym == 0)
-    return;
+/* Data structure containing information about directories with source
+   files.  */
+struct dir_info
+{
+  const char *path;    /* Path including directory name.  */
+  int length;          /* Path length.  */
+  int prefix;          /* Index of directory entry which is a prefix.  */
+  int count;           /* Number of files in this directory.  */
+  int dir_idx;         /* Index of directory used as base.  */
+};
 
-  if (strncmp (sym, DIE_LABEL_PREFIX, sizeof (DIE_LABEL_PREFIX) - 1) == 0)
-    /* We make these global, not weak; if the target doesn't support
-       .linkonce, it doesn't support combining the sections, so debugging
-       will break.  */
-    targetm.asm_out.globalize_label (asm_out_file, sym);
+/* Callback function for file_info comparison.  We sort by looking at
+   the directories in the path.  */
 
-  ASM_OUTPUT_LABEL (asm_out_file, sym);
-}
+static int
+file_info_cmp (const void *p1, const void *p2)
+{
+  const struct file_info *const s1 = (const struct file_info *) p1;
+  const struct file_info *const s2 = (const struct file_info *) p2;
+  const unsigned char *cp1;
+  const unsigned char *cp2;
 
-/* Return a new location list, given the begin and end range, and the
-   expression.  */
+  /* Take care of file names without directories.  We need to make sure that
+     we return consistent values to qsort since some will get confused if
+     we return the same value when identical operands are passed in opposite
+     orders.  So if neither has a directory, return 0 and otherwise return
+     1 or -1 depending on which one has the directory.  */
+  if ((s1->path == s1->fname || s2->path == s2->fname))
+    return (s2->path == s2->fname) - (s1->path == s1->fname);
 
-static inline dw_loc_list_ref
-new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
-             const char *section)
-{
-  dw_loc_list_ref retlist = GGC_CNEW (dw_loc_list_node);
+  cp1 = (const unsigned char *) s1->path;
+  cp2 = (const unsigned char *) s2->path;
 
-  retlist->begin = begin;
-  retlist->end = end;
-  retlist->expr = expr;
-  retlist->section = section;
+  while (1)
+    {
+      ++cp1;
+      ++cp2;
+      /* Reached the end of the first path?  If so, handle like above.  */
+      if ((cp1 == (const unsigned char *) s1->fname)
+         || (cp2 == (const unsigned char *) s2->fname))
+       return ((cp2 == (const unsigned char *) s2->fname)
+               - (cp1 == (const unsigned char *) s1->fname));
 
-  return retlist;
+      /* Character of current path component the same?  */
+      else if (*cp1 != *cp2)
+       return *cp1 - *cp2;
+    }
 }
 
-/* Generate a new internal symbol for this location list node, if it
-   hasn't got one yet.  */
-
-static inline void
-gen_llsym (dw_loc_list_ref list)
+struct file_name_acquire_data
 {
-  gcc_assert (!list->ll_symbol);
-  list->ll_symbol = gen_internal_sym ("LLST");
-}
+  struct file_info *files;
+  int used_files;
+  int max_files;
+};
 
-/* Output the location list given to us.  */
+/* Traversal function for the hash table.  */
 
-static void
-output_loc_list (dw_loc_list_ref list_head)
+static int
+file_name_acquire (void ** slot, void *data)
 {
-  dw_loc_list_ref curr = list_head;
-
-  ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
+  struct file_name_acquire_data *fnad = (struct file_name_acquire_data *) data;
+  struct dwarf_file_data *d = (struct dwarf_file_data *) *slot;
+  struct file_info *fi;
+  const char *f;
 
-  /* Walk the location list, and output each range + expression.  */
-  for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
-    {
-      unsigned long size;
-      /* Don't output an entry that starts and ends at the same address.  */
-      if (strcmp (curr->begin, curr->end) == 0)
-       continue;
-      if (!have_multiple_function_sections)
-       {
-         dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
-                               "Location list begin address (%s)",
-                               list_head->ll_symbol);
-         dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->end, curr->section,
-                               "Location list end address (%s)",
-                               list_head->ll_symbol);
-       }
-      else
-       {
-         dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->begin,
-                              "Location list begin address (%s)",
-                              list_head->ll_symbol);
-         dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->end,
-                              "Location list end address (%s)",
-                              list_head->ll_symbol);
-       }
-      size = size_of_locs (curr->expr);
+  gcc_assert (fnad->max_files >= d->emitted_number);
 
-      /* Output the block length for this list of location operations.  */
-      gcc_assert (size <= 0xffff);
-      dw2_asm_output_data (2, size, "%s", "Location expression size");
+  if (! d->emitted_number)
+    return 1;
 
-      output_loc_sequence (curr->expr);
-    }
+  gcc_assert (fnad->max_files != fnad->used_files);
 
-  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
-                      "Location list terminator begin (%s)",
-                      list_head->ll_symbol);
-  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
-                      "Location list terminator end (%s)",
-                      list_head->ll_symbol);
-}
+  fi = fnad->files + fnad->used_files++;
 
-/* Output a type signature.  */
+  /* Skip all leading "./".  */
+  f = d->filename;
+  while (f[0] == '.' && IS_DIR_SEPARATOR (f[1]))
+    f += 2;
 
-static inline void
-output_signature (const char *sig, const char *name)
-{
-  int i;
+  /* Create a new array entry.  */
+  fi->path = f;
+  fi->length = strlen (f);
+  fi->file_idx = d;
 
-  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
-    dw2_asm_output_data (1, sig[i], i == 0 ? "%s" : NULL, name);
+  /* Search for the file name part.  */
+  f = strrchr (f, DIR_SEPARATOR);
+#if defined (DIR_SEPARATOR_2)
+  {
+    char *g = strrchr (fi->path, DIR_SEPARATOR_2);
+
+    if (g != NULL)
+      {
+       if (f == NULL || f < g)
+         f = g;
+      }
+  }
+#endif
+
+  fi->fname = f == NULL ? fi->path : f + 1;
+  return 1;
 }
 
-/* Output the DIE and its attributes.  Called recursively to generate
-   the definitions of each child DIE.  */
+/* Output the directory table and the file name table.  We try to minimize
+   the total amount of memory needed.  A heuristic is used to avoid large
+   slowdowns with many input files.  */
 
 static void
-output_die (dw_die_ref die)
+output_file_names (void)
 {
-  dw_attr_ref a;
-  dw_die_ref c;
-  unsigned long size;
-  unsigned ix;
-
-  /* If someone in another CU might refer to us, set up a symbol for
-     them to point to.  */
-  if (dwarf_version < 4 && 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));
+  struct file_name_acquire_data fnad;
+  int numfiles;
+  struct file_info *files;
+  struct dir_info *dirs;
+  int *saved;
+  int *savehere;
+  int *backmap;
+  int ndirs;
+  int idx_offset;
+  int i;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+  if (!last_emitted_file)
     {
-      const char *name = dwarf_attr_name (a->dw_attr);
-
-      switch (AT_class (a))
-       {
-       case dw_val_class_addr:
-         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
-         break;
+      dw2_asm_output_data (1, 0, "End directory table");
+      dw2_asm_output_data (1, 0, "End file name table");
+      return;
+    }
 
-       case dw_val_class_offset:
-         dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
-                              "%s", name);
-         break;
+  numfiles = last_emitted_file->emitted_number;
 
-       case dw_val_class_range_list:
-         {
-           char *p = strchr (ranges_section_label, '\0');
+  /* Allocate the various arrays we need.  */
+  files = XALLOCAVEC (struct file_info, numfiles);
+  dirs = XALLOCAVEC (struct dir_info, numfiles);
 
-           sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
-                    a->dw_attr_val.v.val_offset);
-           dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
-                                  debug_ranges_section, "%s", name);
-           *p = '\0';
-         }
-         break;
+  fnad.files = files;
+  fnad.used_files = 0;
+  fnad.max_files = numfiles;
+  htab_traverse (file_table, file_name_acquire, &fnad);
+  gcc_assert (fnad.used_files == fnad.max_files);
 
-       case dw_val_class_loc:
-         size = size_of_locs (AT_loc (a));
+  qsort (files, numfiles, sizeof (files[0]), file_info_cmp);
 
-         /* Output the block length for this list of location operations.  */
-         if (dwarf_version >= 4)
-           dw2_asm_output_data_uleb128 (size, "%s", name);
-         else
-           dw2_asm_output_data (constant_size (size), size, "%s", name);
+  /* Find all the different directories used.  */
+  dirs[0].path = files[0].path;
+  dirs[0].length = files[0].fname - files[0].path;
+  dirs[0].prefix = -1;
+  dirs[0].count = 1;
+  dirs[0].dir_idx = 0;
+  files[0].dir_idx = 0;
+  ndirs = 1;
 
-         output_loc_sequence (AT_loc (a));
-         break;
+  for (i = 1; i < numfiles; i++)
+    if (files[i].fname - files[i].path == dirs[ndirs - 1].length
+       && memcmp (dirs[ndirs - 1].path, files[i].path,
+                  dirs[ndirs - 1].length) == 0)
+      {
+       /* Same directory as last entry.  */
+       files[i].dir_idx = ndirs - 1;
+       ++dirs[ndirs - 1].count;
+      }
+    else
+      {
+       int j;
 
-       case dw_val_class_const:
-         /* ??? It would be slightly more efficient to use a scheme like is
-            used for unsigned constants below, but gdb 4.x does not sign
-            extend.  Gdb 5.x does sign extend.  */
-         dw2_asm_output_data_sleb128 (AT_int (a), "%s", name);
-         break;
+       /* This is a new directory.  */
+       dirs[ndirs].path = files[i].path;
+       dirs[ndirs].length = files[i].fname - files[i].path;
+       dirs[ndirs].count = 1;
+       dirs[ndirs].dir_idx = ndirs;
+       files[i].dir_idx = ndirs;
 
-       case dw_val_class_unsigned_const:
-         dw2_asm_output_data (constant_size (AT_unsigned (a)),
-                              AT_unsigned (a), "%s", name);
-         break;
+       /* Search for a prefix.  */
+       dirs[ndirs].prefix = -1;
+       for (j = 0; j < ndirs; j++)
+         if (dirs[j].length < dirs[ndirs].length
+             && dirs[j].length > 1
+             && (dirs[ndirs].prefix == -1
+                 || dirs[j].length > dirs[dirs[ndirs].prefix].length)
+             && memcmp (dirs[j].path, dirs[ndirs].path, dirs[j].length) == 0)
+           dirs[ndirs].prefix = j;
 
-       case dw_val_class_const_double:
-         {
-           unsigned HOST_WIDE_INT first, second;
+       ++ndirs;
+      }
 
-           if (HOST_BITS_PER_WIDE_INT >= 64)
-             dw2_asm_output_data (1,
-                                  2 * HOST_BITS_PER_WIDE_INT
-                                  / HOST_BITS_PER_CHAR,
-                                  NULL);
+  /* Now to the actual work.  We have to find a subset of the directories which
+     allow expressing the file name using references to the directory table
+     with the least amount of characters.  We do not do an exhaustive search
+     where we would have to check out every combination of every single
+     possible prefix.  Instead we use a heuristic which provides nearly optimal
+     results in most cases and never is much off.  */
+  saved = XALLOCAVEC (int, ndirs);
+  savehere = XALLOCAVEC (int, ndirs);
 
-           if (WORDS_BIG_ENDIAN)
-             {
-               first = a->dw_attr_val.v.val_double.high;
-               second = a->dw_attr_val.v.val_double.low;
-             }
-           else
-             {
-               first = a->dw_attr_val.v.val_double.low;
-               second = a->dw_attr_val.v.val_double.high;
-             }
+  memset (saved, '\0', ndirs * sizeof (saved[0]));
+  for (i = 0; i < ndirs; i++)
+    {
+      int j;
+      int total;
 
-           dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
-                                first, name);
-           dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
-                                second, NULL);
-         }
-         break;
+      /* We can always save some space for the current directory.  But this
+        does not mean it will be enough to justify adding the directory.  */
+      savehere[i] = dirs[i].length;
+      total = (savehere[i] - saved[i]) * dirs[i].count;
 
-       case dw_val_class_vec:
-         {
-           unsigned int elt_size = a->dw_attr_val.v.val_vec.elt_size;
-           unsigned int len = a->dw_attr_val.v.val_vec.length;
-           unsigned int i;
-           unsigned char *p;
+      for (j = i + 1; j < ndirs; j++)
+       {
+         savehere[j] = 0;
+         if (saved[j] < dirs[i].length)
+           {
+             /* Determine whether the dirs[i] path is a prefix of the
+                dirs[j] path.  */
+             int k;
 
-           dw2_asm_output_data (constant_size (len * elt_size),
-                                len * elt_size, "%s", name);
-           if (elt_size > sizeof (HOST_WIDE_INT))
-             {
-               elt_size /= 2;
-               len *= 2;
-             }
-           for (i = 0, p = a->dw_attr_val.v.val_vec.array;
-                i < len;
-                i++, p += elt_size)
-             dw2_asm_output_data (elt_size, extract_int (p, elt_size),
-                                  "fp or vector constant word %u", i);
-           break;
-         }
+             k = dirs[j].prefix;
+             while (k != -1 && k != (int) i)
+               k = dirs[k].prefix;
 
-       case dw_val_class_flag:
-         if (dwarf_version >= 4)
-           {
-             /* Currently all add_AT_flag calls pass in 1 as last argument,
-                so DW_FORM_flag_present can be used.  If that ever changes,
-                we'll need to use DW_FORM_flag and have some optimization
-                in build_abbrev_table that will change those to
-                DW_FORM_flag_present if it is set to 1 in all DIEs using
-                the same abbrev entry.  */
-             gcc_assert (AT_flag (a) == 1);
-             if (flag_debug_asm)
-               fprintf (asm_out_file, "\t\t\t%s %s\n",
-                        ASM_COMMENT_START, name);
-             break;
+             if (k == (int) i)
+               {
+                 /* Yes it is.  We can possibly save some memory by
+                    writing the filenames in dirs[j] relative to
+                    dirs[i].  */
+                 savehere[j] = dirs[i].length;
+                 total += (savehere[j] - saved[j]) * dirs[j].count;
+               }
            }
-         dw2_asm_output_data (1, AT_flag (a), "%s", name);
-         break;
+       }
 
-       case dw_val_class_loc_list:
-         {
-           char *sym = AT_loc_list (a)->ll_symbol;
+      /* Check whether we can save enough to justify adding the dirs[i]
+        directory.  */
+      if (total > dirs[i].length + 1)
+       {
+         /* It's worthwhile adding.  */
+         for (j = i; j < ndirs; j++)
+           if (savehere[j] > 0)
+             {
+               /* Remember how much we saved for this directory so far.  */
+               saved[j] = savehere[j];
 
-           gcc_assert (sym);
-           dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
-                                  "%s", name);
-         }
-         break;
+               /* Remember the prefix directory.  */
+               dirs[j].dir_idx = i;
+             }
+       }
+    }
 
-       case dw_val_class_die_ref:
-         if (AT_ref_external (a))
-           {
-             if (dwarf_version >= 4)
-               {
-                 comdat_type_node_ref type_node =
-                   AT_ref (a)->die_id.die_type_node;
+  /* Emit the directory name table.  */
+  idx_offset = dirs[0].length > 0 ? 1 : 0;
+  for (i = 1 - idx_offset; i < ndirs; i++)
+    dw2_asm_output_nstring (dirs[i].path,
+                           dirs[i].length
+                            - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
+                           "Directory Entry: %#x", i + idx_offset);
 
-                 gcc_assert (type_node);
-                 output_signature (type_node->signature, name);
-               }
-             else
-               {
-                 char *sym = AT_ref (a)->die_id.die_symbol;
-                 int size;
+  dw2_asm_output_data (1, 0, "End directory table");
 
-                 gcc_assert (sym);
-                 /* In DWARF2, DW_FORM_ref_addr is sized by target address
-                    length, whereas in DWARF3 it's always sized as an
-                    offset.  */
-                 if (dwarf_version == 2)
-                   size = DWARF2_ADDR_SIZE;
-                 else
-                   size = DWARF_OFFSET_SIZE;
-                 dw2_asm_output_offset (size, sym, debug_info_section, "%s",
-                                        name);
-               }
-           }
-         else
-           {
-             gcc_assert (AT_ref (a)->die_offset);
-             dw2_asm_output_data (DWARF_OFFSET_SIZE, AT_ref (a)->die_offset,
-                                  "%s", name);
-           }
-         break;
+  /* We have to emit them in the order of emitted_number since that's
+     used in the debug info generation.  To do this efficiently we
+     generate a back-mapping of the indices first.  */
+  backmap = XALLOCAVEC (int, numfiles);
+  for (i = 0; i < numfiles; i++)
+    backmap[files[i].file_idx->emitted_number - 1] = i;
 
-       case dw_val_class_fde_ref:
-         {
-           char l1[20];
+  /* Now write all the file names.  */
+  for (i = 0; i < numfiles; i++)
+    {
+      int file_idx = backmap[i];
+      int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
 
-           ASM_GENERATE_INTERNAL_LABEL (l1, FDE_LABEL,
-                                        a->dw_attr_val.v.val_fde_index * 2);
-           dw2_asm_output_offset (DWARF_OFFSET_SIZE, l1, debug_frame_section,
-                                  "%s", name);
-         }
-         break;
+#ifdef VMS_DEBUGGING_INFO
+#define MAX_VMS_VERSION_LEN 6 /* ";32768" */
 
-       case dw_val_class_lbl_id:
-         dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
-         break;
+      /* Setting these fields can lead to debugger miscomparisons,
+         but VMS Debug requires them to be set correctly.  */
 
-       case dw_val_class_lineptr:
-         dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
-                                debug_line_section, "%s", name);
-         break;
+      int ver;
+      long long cdt;
+      long siz;
+      int maxfilelen = strlen (files[file_idx].path)
+                              + dirs[dir_idx].length
+                              + MAX_VMS_VERSION_LEN + 1;
+      char *filebuf = XALLOCAVEC (char, maxfilelen);
 
-       case dw_val_class_macptr:
-         dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
-                                debug_macinfo_section, "%s", name);
-         break;
+      vms_file_stats_name (files[file_idx].path, 0, 0, 0, &ver);
+      snprintf (filebuf, maxfilelen, "%s;%d",
+               files[file_idx].path + dirs[dir_idx].length, ver);
 
-       case dw_val_class_str:
-         if (AT_string_form (a) == DW_FORM_strp)
-           dw2_asm_output_offset (DWARF_OFFSET_SIZE,
-                                  a->dw_attr_val.v.val_str->label,
-                                  debug_str_section,
-                                  "%s: \"%s\"", name, AT_string (a));
-         else
-           dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
-         break;
+      dw2_asm_output_nstring
+       (filebuf, -1, "File Entry: %#x", (unsigned) i + 1);
 
-       case dw_val_class_file:
-         {
-           int f = maybe_emit_file (a->dw_attr_val.v.val_file);
+      /* Include directory index.  */
+      dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
 
-           dw2_asm_output_data (constant_size (f), f, "%s (%s)", name,
-                                a->dw_attr_val.v.val_file->filename);
-           break;
-         }
+      /* Modification time.  */
+      dw2_asm_output_data_uleb128
+        ((vms_file_stats_name (files[file_idx].path, &cdt, 0, 0, 0) == 0)
+         ? cdt : 0,
+        NULL);
 
-       case dw_val_class_data8:
-         {
-           int i;
+      /* File length in bytes.  */
+      dw2_asm_output_data_uleb128
+        ((vms_file_stats_name (files[file_idx].path, 0, &siz, 0, 0) == 0)
+         ? siz : 0,
+        NULL);
+#else
+      dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
+                             "File Entry: %#x", (unsigned) i + 1);
 
-           for (i = 0; i < 8; i++)
-             dw2_asm_output_data (1, a->dw_attr_val.v.val_data8[i],
-                                  i == 0 ? "%s" : NULL, name);
-           break;
-         }
+      /* Include directory index.  */
+      dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
 
-       default:
-         gcc_unreachable ();
-       }
-    }
+      /* Modification time.  */
+      dw2_asm_output_data_uleb128 (0, NULL);
 
-  FOR_EACH_CHILD (die, c, output_die (c));
+      /* File length in bytes.  */
+      dw2_asm_output_data_uleb128 (0, NULL);
+#endif /* VMS_DEBUGGING_INFO */
+    }
 
-  /* Add null byte to terminate sibling list.  */
-  if (die->die_child != NULL)
-    dw2_asm_output_data (1, 0, "end of children of DIE %#lx",
-                        (unsigned long) die->die_offset);
+  dw2_asm_output_data (1, 0, "End file name table");
 }
 
-/* Output the compilation unit that appears at the beginning of the
-   .debug_info section, and precedes the DIE descriptions.  */
+
+/* Output one line number table into the .debug_line section.  */
 
 static void
-output_compilation_unit_header (void)
+output_one_line_info_table (dw_line_info_table *table)
 {
-  int ver = dwarf_version;
+  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;
 
-  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
-    dw2_asm_output_data (4, 0xffffffff,
-      "Initial length escape value indicating 64-bit DWARF extension");
-  dw2_asm_output_data (DWARF_OFFSET_SIZE,
-                      next_die_offset - DWARF_INITIAL_LENGTH_SIZE,
-                      "Length of Compilation Unit Info");
-  dw2_asm_output_data (2, ver, "DWARF version number");
-  dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
-                        debug_abbrev_section,
-                        "Offset Into Abbrev. Section");
-  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
-}
+  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);
 
-/* Output the compilation unit DIE and its children.  */
+         /* 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;
 
-static void
-output_comp_unit (dw_die_ref die, int output_if_empty)
-{
-  const char *secname;
-  char *oldsym, *tmp;
+       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;
 
-  /* Unless we are outputting main CU, we may throw away empty ones.  */
-  if (!output_if_empty && die->die_child == NULL)
-    return;
+             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;
 
-  /* Even if there are no children of this DIE, we must output the information
-     about the compilation unit.  Otherwise, on an empty translation unit, we
-     will generate a present, but empty, .debug_info section.  IRIX 6.5 `nm'
-     will then complain when examining the file.  First mark all the DIEs in
-     this CU so we know which get local refs.  */
-  mark_dies (die);
+       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;
 
-  build_abbrev_table (die);
+       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;
 
-  /* Initialize the beginning DIE offset - and calculate sizes/offsets.  */
-  next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
-  calc_die_sizes (die);
+       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;
 
-  oldsym = die->die_id.die_symbol;
-  if (oldsym)
-    {
-      tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
+       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;
 
-      sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym);
-      secname = tmp;
-      die->die_id.die_symbol = NULL;
-      switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
+       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;
+       }
     }
-  else
-    switch_to_section (debug_info_section);
 
-  /* Output debugging information.  */
-  output_compilation_unit_header ();
-  output_die (die);
+  /* 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);
 
-  /* Leave the marks on the main CU, so we can check them in
-     output_pubnames.  */
-  if (oldsym)
-    {
-      unmark_dies (die);
-      die->die_id.die_symbol = oldsym;
-    }
+  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 a comdat type unit DIE and its children.  */
+/* Output the source line number correspondence information.  This
+   information goes into the .debug_line section.  */
 
 static void
-output_comdat_type_unit (comdat_type_node *node)
+output_line_info (void)
 {
-  const char *secname;
-  char *tmp;
-  int i;
-#if defined (OBJECT_FORMAT_ELF)
-  tree comdat_key;
-#endif
-
-  /* First mark all the DIEs in this CU so we know which get local refs.  */
-  mark_dies (node->root_die);
-
-  build_abbrev_table (node->root_die);
+  char l1[20], l2[20], p1[20], p2[20];
+  int ver = dwarf_version;
+  bool saw_one = false;
+  int opc;
 
-  /* Initialize the beginning DIE offset - and calculate sizes/offsets.  */
-  next_die_offset = DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE;
-  calc_die_sizes (node->root_die);
+  ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (p1, LN_PROLOG_AS_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (p2, LN_PROLOG_END_LABEL, 0);
 
-#if defined (OBJECT_FORMAT_ELF)
-  secname = ".debug_types";
-  tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2);
-  sprintf (tmp, "wt.");
-  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
-    sprintf (tmp + 3 + i * 2, "%02x", node->signature[i] & 0xff);
-  comdat_key = get_identifier (tmp);
-  targetm.asm_out.named_section (secname,
-                                 SECTION_DEBUG | SECTION_LINKONCE,
-                                 comdat_key);
-#else
-  tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2);
-  sprintf (tmp, ".gnu.linkonce.wt.");
-  for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
-    sprintf (tmp + 17 + i * 2, "%02x", node->signature[i] & 0xff);
-  secname = tmp;
-  switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
-#endif
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+    dw2_asm_output_data (4, 0xffffffff,
+      "Initial length escape value indicating 64-bit DWARF extension");
+  dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
+                       "Length of Source Line Info");
+  ASM_OUTPUT_LABEL (asm_out_file, l1);
 
-  /* Output debugging information.  */
-  output_compilation_unit_header ();
-  output_signature (node->signature, "Type Signature");
-  dw2_asm_output_data (DWARF_OFFSET_SIZE, node->type_die->die_offset,
-                      "Offset to Type DIE");
-  output_die (node->root_die);
+  dw2_asm_output_data (2, ver, "DWARF Version");
+  dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
+  ASM_OUTPUT_LABEL (asm_out_file, p1);
 
-  unmark_dies (node->root_die);
-}
+  /* 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");
 
-/* Return the DWARF2/3 pubname associated with a decl.  */
+  if (ver >= 4)
+    dw2_asm_output_data (1, DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN,
+                        "Maximum Operations Per Instruction");
+  dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START,
+                      "Default is_stmt_start flag");
+  dw2_asm_output_data (1, DWARF_LINE_BASE,
+                      "Line Base Value (Special Opcodes)");
+  dw2_asm_output_data (1, DWARF_LINE_RANGE,
+                      "Line Range Value (Special Opcodes)");
+  dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE,
+                      "Special Opcode Base");
 
-static const char *
-dwarf2_name (tree decl, int scope)
-{
-  return lang_hooks.dwarf_name (decl, scope ? 1 : 0);
-}
+  for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; opc++)
+    {
+      int n_op_args;
+      switch (opc)
+       {
+       case DW_LNS_advance_pc:
+       case DW_LNS_advance_line:
+       case DW_LNS_set_file:
+       case DW_LNS_set_column:
+       case DW_LNS_fixed_advance_pc:
+       case DW_LNS_set_isa:
+         n_op_args = 1;
+         break;
+       default:
+         n_op_args = 0;
+         break;
+       }
 
-/* Add a new entry to .debug_pubnames if appropriate.  */
+      dw2_asm_output_data (1, n_op_args, "opcode: %#x has %d args",
+                          opc, n_op_args);
+    }
 
-static void
-add_pubname_string (const char *str, dw_die_ref die)
-{
-  pubname_entry e;
+  /* Write out the information about the files we use.  */
+  output_file_names ();
+  ASM_OUTPUT_LABEL (asm_out_file, p2);
 
-  e.die = die;
-  e.name = xstrdup (str);
-  VEC_safe_push (pubname_entry, gc, pubname_table, &e);
-}
+  if (separate_line_info)
+    {
+      dw_line_info_table *table;
+      size_t i;
 
-static void
-add_pubname (tree decl, dw_die_ref die)
-{
-  if (TREE_PUBLIC (decl))
+      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;
+         }
+    }
+  if (cold_text_section_line_info && cold_text_section_line_info->in_use)
     {
-      const char *name = dwarf2_name (decl, 1);
-      if (name)
-       add_pubname_string (name, die);
+      output_one_line_info_table (cold_text_section_line_info);
+      saw_one = true;
     }
+
+  /* ??? 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);
 }
+\f
+/* Given a pointer to a tree node for some base type, return a pointer to
+   a DIE that describes the given type.
 
-/* Add a new entry to .debug_pubtypes if appropriate.  */
+   This routine must only be called for GCC type nodes that correspond to
+   Dwarf base (fundamental) types.  */
 
-static void
-add_pubtype (tree decl, dw_die_ref die)
+static dw_die_ref
+base_type_die (tree type)
 {
-  pubname_entry e;
+  dw_die_ref base_type_result;
+  enum dwarf_type encoding;
 
-  e.name = NULL;
-  if ((TREE_PUBLIC (decl)
-       || die->die_parent == comp_unit_die)
-      && (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl)))
+  if (TREE_CODE (type) == ERROR_MARK || TREE_CODE (type) == VOID_TYPE)
+    return 0;
+
+  /* If this is a subtype that should not be emitted as a subrange type,
+     use the base type.  See subrange_type_for_debug_p.  */
+  if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type) != NULL_TREE)
+    type = TREE_TYPE (type);
+
+  switch (TREE_CODE (type))
     {
-      e.die = die;
-      if (TYPE_P (decl))
+    case INTEGER_TYPE:
+      if ((dwarf_version >= 4 || !dwarf_strict)
+         && TYPE_NAME (type)
+         && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+         && DECL_IS_BUILTIN (TYPE_NAME (type))
+         && DECL_NAME (TYPE_NAME (type)))
        {
-         if (TYPE_NAME (decl))
+         const char *name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+         if (strcmp (name, "char16_t") == 0
+             || strcmp (name, "char32_t") == 0)
            {
-             if (TREE_CODE (TYPE_NAME (decl)) == IDENTIFIER_NODE)
-               e.name = IDENTIFIER_POINTER (TYPE_NAME (decl));
-             else if (TREE_CODE (TYPE_NAME (decl)) == TYPE_DECL
-                      && DECL_NAME (TYPE_NAME (decl)))
-               e.name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl)));
-             else
-              e.name = xstrdup ((const char *) get_AT_string (die, DW_AT_name));
+             encoding = DW_ATE_UTF;
+             break;
            }
        }
+      if (TYPE_STRING_FLAG (type))
+       {
+         if (TYPE_UNSIGNED (type))
+           encoding = DW_ATE_unsigned_char;
+         else
+           encoding = DW_ATE_signed_char;
+       }
+      else if (TYPE_UNSIGNED (type))
+       encoding = DW_ATE_unsigned;
       else
+       encoding = DW_ATE_signed;
+      break;
+
+    case REAL_TYPE:
+      if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))
        {
-         e.name = dwarf2_name (decl, 1);
-         if (e.name)
-           e.name = xstrdup (e.name);
+         if (dwarf_version >= 3 || !dwarf_strict)
+           encoding = DW_ATE_decimal_float;
+         else
+           encoding = DW_ATE_lo_user;
        }
+      else
+       encoding = DW_ATE_float;
+      break;
 
-      /* If we don't have a name for the type, there's no point in adding
-        it to the table.  */
-      if (e.name && e.name[0] != '\0')
-       VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
+    case FIXED_POINT_TYPE:
+      if (!(dwarf_version >= 3 || !dwarf_strict))
+       encoding = DW_ATE_lo_user;
+      else if (TYPE_UNSIGNED (type))
+       encoding = DW_ATE_unsigned_fixed;
+      else
+       encoding = DW_ATE_signed_fixed;
+      break;
+
+      /* Dwarf2 doesn't know anything about complex ints, so use
+        a user defined type for it.  */
+    case COMPLEX_TYPE:
+      if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
+       encoding = DW_ATE_complex_float;
+      else
+       encoding = DW_ATE_lo_user;
+      break;
+
+    case BOOLEAN_TYPE:
+      /* GNU FORTRAN/Ada/C++ BOOLEAN type.  */
+      encoding = DW_ATE_boolean;
+      break;
+
+    default:
+      /* No other TREE_CODEs are Dwarf fundamental types.  */
+      gcc_unreachable ();
     }
+
+  base_type_result = new_die (DW_TAG_base_type, comp_unit_die (), type);
+
+  add_AT_unsigned (base_type_result, DW_AT_byte_size,
+                  int_size_in_bytes (type));
+  add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
+
+  return base_type_result;
 }
 
-/* Output the public names table used to speed up access to externally
-   visible names; or the public types table used to find type definitions.  */
+/* Given a pointer to an arbitrary ..._TYPE tree node, return nonzero if the
+   given input type is a Dwarf "fundamental" type.  Otherwise return null.  */
 
-static void
-output_pubnames (VEC (pubname_entry, gc) * names)
+static inline int
+is_base_type (tree type)
 {
-  unsigned i;
-  unsigned long pubnames_length = size_of_pubnames (names);
-  pubname_ref pub;
+  switch (TREE_CODE (type))
+    {
+    case ERROR_MARK:
+    case VOID_TYPE:
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case FIXED_POINT_TYPE:
+    case COMPLEX_TYPE:
+    case BOOLEAN_TYPE:
+      return 1;
+
+    case ARRAY_TYPE:
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+    case ENUMERAL_TYPE:
+    case FUNCTION_TYPE:
+    case METHOD_TYPE:
+    case POINTER_TYPE:
+    case REFERENCE_TYPE:
+    case NULLPTR_TYPE:
+    case OFFSET_TYPE:
+    case LANG_TYPE:
+    case VECTOR_TYPE:
+      return 0;
+
+    default:
+      gcc_unreachable ();
+    }
 
-  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
-    dw2_asm_output_data (4, 0xffffffff,
-      "Initial length escape value indicating 64-bit DWARF extension");
-  if (names == pubname_table)
-    dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
-                        "Length of Public Names Info");
-  else
-    dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
-                        "Length of Public Type Names Info");
-  /* Version number for pubnames/pubtypes is still 2, even in DWARF3.  */
-  dw2_asm_output_data (2, 2, "DWARF Version");
-  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
-                        debug_info_section,
-                        "Offset of Compilation Unit Info");
-  dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
-                      "Compilation Unit Length");
+  return 0;
+}
 
-  for (i = 0; VEC_iterate (pubname_entry, names, i, pub); i++)
-    {
-      /* We shouldn't see pubnames for DIEs outside of the main CU.  */
-      if (names == pubname_table)
-       gcc_assert (pub->die->die_mark);
+/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
+   node, return the size in bits for the type if it is a constant, or else
+   return the alignment for the type if the type's size is not constant, or
+   else return BITS_PER_WORD if the type actually turns out to be an
+   ERROR_MARK node.  */
 
-      if (names != pubtype_table
-         || pub->die->die_offset != 0
-         || !flag_eliminate_unused_debug_types)
-       {
-         dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
-                              "DIE offset");
+static inline unsigned HOST_WIDE_INT
+simple_type_size_in_bits (const_tree type)
+{
+  if (TREE_CODE (type) == ERROR_MARK)
+    return BITS_PER_WORD;
+  else if (TYPE_SIZE (type) == NULL_TREE)
+    return 0;
+  else if (host_integerp (TYPE_SIZE (type), 1))
+    return tree_low_cst (TYPE_SIZE (type), 1);
+  else
+    return TYPE_ALIGN (type);
+}
 
-         dw2_asm_output_nstring (pub->name, -1, "external name");
-       }
-    }
+/* Similarly, but return a double_int instead of UHWI.  */
 
-  dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL);
+static inline double_int
+double_int_type_size_in_bits (const_tree type)
+{
+  if (TREE_CODE (type) == ERROR_MARK)
+    return uhwi_to_double_int (BITS_PER_WORD);
+  else if (TYPE_SIZE (type) == NULL_TREE)
+    return double_int_zero;
+  else if (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
+    return tree_to_double_int (TYPE_SIZE (type));
+  else
+    return uhwi_to_double_int (TYPE_ALIGN (type));
 }
 
-/* Add a new entry to .debug_aranges if appropriate.  */
+/*  Given a pointer to a tree node for a subrange type, return a pointer
+    to a DIE that describes the given type.  */
 
-static void
-add_arange (tree decl, dw_die_ref die)
+static dw_die_ref
+subrange_type_die (tree type, tree low, tree high, dw_die_ref context_die)
 {
-  if (! DECL_SECTION_NAME (decl))
-    return;
+  dw_die_ref subrange_die;
+  const HOST_WIDE_INT size_in_bytes = int_size_in_bytes (type);
 
-  if (arange_table_in_use == arange_table_allocated)
+  if (context_die == NULL)
+    context_die = comp_unit_die ();
+
+  subrange_die = new_die (DW_TAG_subrange_type, context_die, type);
+
+  if (int_size_in_bytes (TREE_TYPE (type)) != size_in_bytes)
     {
-      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));
+      /* The size of the subrange type and its base type do not match,
+        so we need to generate a size attribute for the subrange type.  */
+      add_AT_unsigned (subrange_die, DW_AT_byte_size, size_in_bytes);
     }
 
-  arange_table[arange_table_in_use++] = die;
+  if (low)
+    add_bound_info (subrange_die, DW_AT_lower_bound, low);
+  if (high)
+    add_bound_info (subrange_die, DW_AT_upper_bound, high);
+
+  return subrange_die;
 }
 
-/* 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.  */
+/* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
+   entry that chains various modifiers in front of the given type.  */
 
-static void
-output_aranges (void)
+static dw_die_ref
+modified_type_die (tree type, int is_const_type, int is_volatile_type,
+                  dw_die_ref context_die)
 {
-  unsigned i;
-  unsigned long aranges_length = size_of_aranges ();
+  enum tree_code code = TREE_CODE (type);
+  dw_die_ref mod_type_die;
+  dw_die_ref sub_die = NULL;
+  tree item_type = NULL;
+  tree qualified_type;
+  tree name, low, high;
 
-  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
-    dw2_asm_output_data (4, 0xffffffff,
-      "Initial length escape value indicating 64-bit DWARF extension");
-  dw2_asm_output_data (DWARF_OFFSET_SIZE, aranges_length,
-                      "Length of Address Ranges Info");
-  /* Version number for aranges is still 2, even in DWARF3.  */
-  dw2_asm_output_data (2, 2, "DWARF Version");
-  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
-                        debug_info_section,
-                        "Offset of Compilation Unit Info");
-  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
-  dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
+  if (code == ERROR_MARK)
+    return NULL;
 
-  /* We need to align to twice the pointer size here.  */
-  if (DWARF_ARANGES_PAD_SIZE)
-    {
-      /* Pad using a 2 byte words so that padding is correct for any
-        pointer size.  */
-      dw2_asm_output_data (2, 0, "Pad to %d byte boundary",
-                          2 * DWARF2_ADDR_SIZE);
-      for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
-       dw2_asm_output_data (2, 0, NULL);
-    }
+  /* See if we already have the appropriately qualified variant of
+     this type.  */
+  qualified_type
+    = get_qualified_type (type,
+                         ((is_const_type ? TYPE_QUAL_CONST : 0)
+                          | (is_volatile_type ? TYPE_QUAL_VOLATILE : 0)));
 
-  /* It is necessary not to output these entries if the sections were
-     not used; if the sections were not used, the length will be 0 and
-     the address may end up as 0 if the section is discarded by ld
-     --gc-sections, leaving an invalid (0, 0) entry that can be
-     confused with the terminator.  */
-  if (text_section_used)
+  if (qualified_type == sizetype
+      && TYPE_NAME (qualified_type)
+      && TREE_CODE (TYPE_NAME (qualified_type)) == TYPE_DECL)
     {
-      dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_section_label, "Address");
-      dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
-                           text_section_label, "Length");
+      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 (cold_text_section_used)
+
+  /* If we do, then we can just use its DIE, if it exists.  */
+  if (qualified_type)
     {
-      dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label,
-                          "Address");
-      dw2_asm_output_delta (DWARF2_ADDR_SIZE, cold_end_label,
-                           cold_text_section_label, "Length");
+      mod_type_die = lookup_type_die (qualified_type);
+      if (mod_type_die)
+       return mod_type_die;
     }
 
-  for (i = 0; i < arange_table_in_use; i++)
-    {
-      dw_die_ref die = arange_table[i];
+  name = qualified_type ? TYPE_NAME (qualified_type) : NULL;
 
-      /* We shouldn't see aranges for DIEs outside of the main CU.  */
-      gcc_assert (die->die_mark);
+  /* Handle C typedef types.  */
+  if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name)
+      && !DECL_ARTIFICIAL (name))
+    {
+      tree dtype = TREE_TYPE (name);
 
-      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
+      if (qualified_type == dtype)
        {
-         /* 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");
+         /* For a named type, use the typedef.  */
+         gen_type_die (qualified_type, context_die);
+         return lookup_type_die (qualified_type);
        }
+      else if (is_const_type < TYPE_READONLY (dtype)
+              || is_volatile_type < TYPE_VOLATILE (dtype)
+              || (is_const_type <= TYPE_READONLY (dtype)
+                  && is_volatile_type <= TYPE_VOLATILE (dtype)
+                  && DECL_ORIGINAL_TYPE (name) != type))
+       /* cv-unqualified version of named type.  Just use the unnamed
+          type to which it refers.  */
+       return modified_type_die (DECL_ORIGINAL_TYPE (name),
+                                 is_const_type, is_volatile_type,
+                                 context_die);
+      /* Else cv-qualified version of named type; fall through.  */
     }
 
-  /* Output the terminator words.  */
-  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
-  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
-}
-
-/* Add a new entry to .debug_ranges.  Return the offset at which it
-   was placed.  */
+  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);
+      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, is_const_type, 0, context_die);
+    }
+  else if (code == POINTER_TYPE)
+    {
+      mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die (), type);
+      add_AT_unsigned (mod_type_die, DW_AT_byte_size,
+                      simple_type_size_in_bits (type) / BITS_PER_UNIT);
+      item_type = TREE_TYPE (type);
+      if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type)))
+       add_AT_unsigned (mod_type_die, DW_AT_address_class,
+                        TYPE_ADDR_SPACE (item_type));
+    }
+  else if (code == REFERENCE_TYPE)
+    {
+      if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4)
+       mod_type_die = new_die (DW_TAG_rvalue_reference_type, comp_unit_die (),
+                               type);
+      else
+       mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die (), type);
+      add_AT_unsigned (mod_type_die, DW_AT_byte_size,
+                      simple_type_size_in_bits (type) / BITS_PER_UNIT);
+      item_type = TREE_TYPE (type);
+      if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type)))
+       add_AT_unsigned (mod_type_die, DW_AT_address_class,
+                        TYPE_ADDR_SPACE (item_type));
+    }
+  else if (code == INTEGER_TYPE
+          && TREE_TYPE (type) != NULL_TREE
+          && subrange_type_for_debug_p (type, &low, &high))
+    {
+      mod_type_die = subrange_type_die (type, low, high, context_die);
+      item_type = TREE_TYPE (type);
+    }
+  else if (is_base_type (type))
+    mod_type_die = base_type_die (type);
+  else
+    {
+      gen_type_die (type, context_die);
 
-static unsigned int
-add_ranges_num (int num)
-{
-  unsigned int in_use = ranges_table_in_use;
+      /* We have to get the type_main_variant here (and pass that to the
+        `lookup_type_die' routine) because the ..._TYPE node we have
+        might simply be a *copy* of some original type node (where the
+        copy was created to help us keep track of typedef names) and
+        that copy might have a different TYPE_UID from the original
+        ..._TYPE node.  */
+      if (TREE_CODE (type) != VECTOR_TYPE)
+       return lookup_type_die (type_main_variant (type));
+      else
+       /* Vectors have the debugging information in the type,
+          not the main variant.  */
+       return lookup_type_die (type);
+    }
 
-  if (in_use == ranges_table_allocated)
+  /* Builtin types don't have a DECL_ORIGINAL_TYPE.  For those,
+     don't output a DW_TAG_typedef, since there isn't one in the
+     user's program; just attach a DW_AT_name to the type.
+     Don't attach a DW_AT_name to DW_TAG_const_type or DW_TAG_volatile_type
+     if the base type already has the same name.  */
+  if (name
+      && ((TREE_CODE (name) != TYPE_DECL
+          && (qualified_type == TYPE_MAIN_VARIANT (type)
+              || (!is_const_type && !is_volatile_type)))
+         || (TREE_CODE (name) == TYPE_DECL
+             && TREE_TYPE (name) == qualified_type
+             && DECL_NAME (name))))
+    {
+      if (TREE_CODE (name) == TYPE_DECL)
+       /* Could just call add_name_and_src_coords_attributes here,
+          but since this is a builtin type it doesn't have any
+          useful source coordinates anyway.  */
+       name = DECL_NAME (name);
+      add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
+      add_gnat_descriptive_type_attribute (mod_type_die, type, context_die);
+      if (TYPE_ARTIFICIAL (type))
+       add_AT_flag (mod_type_die, DW_AT_artificial, 1);
+    }
+  /* This probably indicates a bug.  */
+  else if (mod_type_die && mod_type_die->die_tag == DW_TAG_base_type)
     {
-      ranges_table_allocated += RANGES_TABLE_INCREMENT;
-      ranges_table = GGC_RESIZEVEC (struct dw_ranges_struct, ranges_table,
-                                   ranges_table_allocated);
-      memset (ranges_table + ranges_table_in_use, 0,
-             RANGES_TABLE_INCREMENT * sizeof (struct dw_ranges_struct));
+      name = TYPE_NAME (type);
+      if (name
+         && TREE_CODE (name) == TYPE_DECL)
+       name = DECL_NAME (name);
+      add_name_attribute (mod_type_die,
+                         name ? IDENTIFIER_POINTER (name) : "__unknown__");
     }
 
-  ranges_table[in_use].num = num;
-  ranges_table_in_use = in_use + 1;
+  if (qualified_type)
+    equate_type_number_to_die (qualified_type, mod_type_die);
 
-  return in_use * 2 * DWARF2_ADDR_SIZE;
-}
+  if (item_type)
+    /* We must do this after the equate_type_number_to_die call, in case
+       this is a recursive type.  This ensures that the modified_type_die
+       recursion will terminate even if the type is recursive.  Recursive
+       types are possible in Ada.  */
+    sub_die = modified_type_die (item_type,
+                                TYPE_READONLY (item_type),
+                                TYPE_VOLATILE (item_type),
+                                context_die);
 
-/* Add a new entry to .debug_ranges corresponding to a block, or a
-   range terminator if BLOCK is NULL.  */
+  if (sub_die != NULL)
+    add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
 
-static unsigned int
-add_ranges (const_tree block)
-{
-  return add_ranges_num (block ? BLOCK_NUMBER (block) : 0);
+  return mod_type_die;
 }
 
-/* Add a new entry to .debug_ranges corresponding to a pair of
-   labels.  */
+/* Generate DIEs for the generic parameters of T.
+   T must be either a generic type or a generic function.
+   See http://gcc.gnu.org/wiki/TemplateParmsDwarf for more.  */
 
 static void
-add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
-                     bool *added)
+gen_generic_params_dies (tree t)
 {
-  unsigned int in_use = ranges_by_label_in_use;
-  unsigned int offset;
+  tree parms, args;
+  int parms_num, i;
+  dw_die_ref die = NULL;
 
-  if (in_use == ranges_by_label_allocated)
-    {
-      ranges_by_label_allocated += RANGES_TABLE_INCREMENT;
-      ranges_by_label = GGC_RESIZEVEC (struct dw_ranges_by_label_struct,
-                                      ranges_by_label,
-                                      ranges_by_label_allocated);
-      memset (ranges_by_label + ranges_by_label_in_use, 0,
-             RANGES_TABLE_INCREMENT
-             * sizeof (struct dw_ranges_by_label_struct));
-    }
+  if (!t || (TYPE_P (t) && !COMPLETE_TYPE_P (t)))
+    return;
 
-  ranges_by_label[in_use].begin = begin;
-  ranges_by_label[in_use].end = end;
-  ranges_by_label_in_use = in_use + 1;
+  if (TYPE_P (t))
+    die = lookup_type_die (t);
+  else if (DECL_P (t))
+    die = lookup_decl_die (t);
 
-  offset = add_ranges_num (-(int)in_use - 1);
-  if (!*added)
-    {
-      add_AT_range_list (die, DW_AT_ranges, offset);
-      *added = true;
-    }
-}
+  gcc_assert (die);
 
-static void
-output_ranges (void)
-{
-  unsigned i;
-  static const char *const start_fmt = "Offset %#x";
-  const char *fmt = start_fmt;
+  parms = lang_hooks.get_innermost_generic_parms (t);
+  if (!parms)
+    /* T has no generic parameter. It means T is neither a generic type
+       or function. End of story.  */
+    return;
 
-  for (i = 0; i < ranges_table_in_use; i++)
+  parms_num = TREE_VEC_LENGTH (parms);
+  args = lang_hooks.get_innermost_generic_args (t);
+  for (i = 0; i < parms_num; i++)
     {
-      int block_num = ranges_table[i].num;
+      tree parm, arg, arg_pack_elems;
 
-      if (block_num > 0)
+      parm = TREE_VEC_ELT (parms, i);
+      arg = TREE_VEC_ELT (args, i);
+      arg_pack_elems = lang_hooks.types.get_argument_pack_elems (arg);
+      gcc_assert (parm && TREE_VALUE (parm) && arg);
+
+      if (parm && TREE_VALUE (parm) && arg)
        {
-         char blabel[MAX_ARTIFICIAL_LABEL_BYTES];
-         char elabel[MAX_ARTIFICIAL_LABEL_BYTES];
+         /* If PARM represents a template parameter pack,
+            emit a DW_TAG_GNU_template_parameter_pack DIE, followed
+            by DW_TAG_template_*_parameter DIEs for the argument
+            pack elements of ARG. Note that ARG would then be
+            an argument pack.  */
+         if (arg_pack_elems)
+           template_parameter_pack_die (TREE_VALUE (parm),
+                                        arg_pack_elems,
+                                        die);
+         else
+           generic_parameter_die (TREE_VALUE (parm), arg,
+                                  true /* Emit DW_AT_name */, die);
+       }
+    }
+}
 
-         ASM_GENERATE_INTERNAL_LABEL (blabel, BLOCK_BEGIN_LABEL, block_num);
-         ASM_GENERATE_INTERNAL_LABEL (elabel, BLOCK_END_LABEL, block_num);
+/* Create and return a DIE for PARM which should be
+   the representation of a generic type parameter.
+   For instance, in the C++ front end, PARM would be a template parameter.
+   ARG is the argument to PARM.
+   EMIT_NAME_P if tree, the DIE will have DW_AT_name attribute set to the
+   name of the PARM.
+   PARENT_DIE is the parent DIE which the new created DIE should be added to,
+   as a child node.  */
 
-         /* If all code is in the text section, then the compilation
-            unit base address defaults to DW_AT_low_pc, which is the
-            base of the text section.  */
-         if (!have_multiple_function_sections)
-           {
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
-                                   text_section_label,
-                                   fmt, i * 2 * DWARF2_ADDR_SIZE);
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
-                                   text_section_label, NULL);
-           }
+static dw_die_ref
+generic_parameter_die (tree parm, tree arg,
+                      bool emit_name_p,
+                      dw_die_ref parent_die)
+{
+  dw_die_ref tmpl_die = NULL;
+  const char *name = NULL;
 
-         /* Otherwise, the compilation unit base address is zero,
-            which allows us to use absolute addresses, and not worry
-            about whether the target supports cross-section
-            arithmetic.  */
-         else
-           {
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
-                                  fmt, i * 2 * DWARF2_ADDR_SIZE);
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE, elabel, NULL);
-           }
+  if (!parm || !DECL_NAME (parm) || !arg)
+    return NULL;
 
-         fmt = NULL;
-       }
+  /* We support non-type generic parameters and arguments,
+     type generic parameters and arguments, as well as
+     generic generic parameters (a.k.a. template template parameters in C++)
+     and arguments.  */
+  if (TREE_CODE (parm) == PARM_DECL)
+    /* PARM is a nontype generic parameter  */
+    tmpl_die = new_die (DW_TAG_template_value_param, parent_die, parm);
+  else if (TREE_CODE (parm) == TYPE_DECL)
+    /* PARM is a type generic parameter.  */
+    tmpl_die = new_die (DW_TAG_template_type_param, parent_die, parm);
+  else if (lang_hooks.decls.generic_generic_parameter_decl_p (parm))
+    /* PARM is a generic generic parameter.
+       Its DIE is a GNU extension. It shall have a
+       DW_AT_name attribute to represent the name of the template template
+       parameter, and a DW_AT_GNU_template_name attribute to represent the
+       name of the template template argument.  */
+    tmpl_die = new_die (DW_TAG_GNU_template_template_param,
+                       parent_die, parm);
+  else
+    gcc_unreachable ();
 
-      /* Negative block_num stands for an index into ranges_by_label.  */
-      else if (block_num < 0)
+  if (tmpl_die)
+    {
+      tree tmpl_type;
+
+      /* If PARM is a generic parameter pack, it means we are
+         emitting debug info for a template argument pack element.
+        In other terms, ARG is a template argument pack element.
+        In that case, we don't emit any DW_AT_name attribute for
+        the die.  */
+      if (emit_name_p)
        {
-         int lab_idx = - block_num - 1;
+         name = IDENTIFIER_POINTER (DECL_NAME (parm));
+         gcc_assert (name);
+         add_AT_string (tmpl_die, DW_AT_name, name);
+       }
 
-         if (!have_multiple_function_sections)
-           {
-             gcc_unreachable ();
-#if 0
-             /* If we ever use add_ranges_by_labels () for a single
-                function section, all we have to do is to take out
-                the #if 0 above.  */
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE,
-                                   ranges_by_label[lab_idx].begin,
-                                   text_section_label,
-                                   fmt, i * 2 * DWARF2_ADDR_SIZE);
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE,
-                                   ranges_by_label[lab_idx].end,
-                                   text_section_label, NULL);
-#endif
-           }
-         else
-           {
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE,
-                                  ranges_by_label[lab_idx].begin,
-                                  fmt, i * 2 * DWARF2_ADDR_SIZE);
-             dw2_asm_output_addr (DWARF2_ADDR_SIZE,
-                                  ranges_by_label[lab_idx].end,
-                                  NULL);
-           }
+      if (!lang_hooks.decls.generic_generic_parameter_decl_p (parm))
+       {
+         /* DWARF3, 5.6.8 says if PARM is a non-type generic parameter
+            TMPL_DIE should have a child DW_AT_type attribute that is set
+            to the type of the argument to PARM, which is ARG.
+            If PARM is a type generic parameter, TMPL_DIE should have a
+            child DW_AT_type that is set to ARG.  */
+         tmpl_type = TYPE_P (arg) ? arg : TREE_TYPE (arg);
+         add_type_attribute (tmpl_die, tmpl_type, 0,
+                             TREE_THIS_VOLATILE (tmpl_type),
+                             parent_die);
        }
       else
        {
-         dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
-         dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
-         fmt = start_fmt;
+         /* So TMPL_DIE is a DIE representing a
+            a generic generic template parameter, a.k.a template template
+            parameter in C++ and arg is a template.  */
+
+         /* The DW_AT_GNU_template_name attribute of the DIE must be set
+            to the name of the argument.  */
+         name = dwarf2_name (TYPE_P (arg) ? TYPE_NAME (arg) : arg, 1);
+         if (name)
+           add_AT_string (tmpl_die, DW_AT_GNU_template_name, name);
        }
+
+      if (TREE_CODE (parm) == PARM_DECL)
+       /* So PARM is a non-type generic parameter.
+          DWARF3 5.6.8 says we must set a DW_AT_const_value child
+          attribute of TMPL_DIE which value represents the value
+          of ARG.
+          We must be careful here:
+          The value of ARG might reference some function decls.
+          We might currently be emitting debug info for a generic
+          type and types are emitted before function decls, we don't
+          know if the function decls referenced by ARG will actually be
+          emitted after cgraph computations.
+          So must defer the generation of the DW_AT_const_value to
+          after cgraph is ready.  */
+       append_entry_to_tmpl_value_parm_die_table (tmpl_die, arg);
     }
+
+  return tmpl_die;
 }
 
-/* Data structure containing information about input files.  */
-struct file_info
-{
-  const char *path;    /* Complete file name.  */
-  const char *fname;   /* File name part.  */
-  int length;          /* Length of entire string.  */
-  struct dwarf_file_data * file_idx;   /* Index in input file table.  */
-  int dir_idx;         /* Index in directory table.  */
-};
+/* Generate and return a  DW_TAG_GNU_template_parameter_pack DIE representing.
+   PARM_PACK must be a template parameter pack. The returned DIE
+   will be child DIE of PARENT_DIE.  */
 
-/* Data structure containing information about directories with source
-   files.  */
-struct dir_info
+static dw_die_ref
+template_parameter_pack_die (tree parm_pack,
+                            tree parm_pack_args,
+                            dw_die_ref parent_die)
 {
-  const char *path;    /* Path including directory name.  */
-  int length;          /* Path length.  */
-  int prefix;          /* Index of directory entry which is a prefix.  */
-  int count;           /* Number of files in this directory.  */
-  int dir_idx;         /* Index of directory used as base.  */
-};
+  dw_die_ref die;
+  int j;
 
-/* Callback function for file_info comparison.  We sort by looking at
-   the directories in the path.  */
+  gcc_assert (parent_die && parm_pack);
 
-static int
-file_info_cmp (const void *p1, const void *p2)
+  die = new_die (DW_TAG_GNU_template_parameter_pack, parent_die, parm_pack);
+  add_name_and_src_coords_attributes (die, parm_pack);
+  for (j = 0; j < TREE_VEC_LENGTH (parm_pack_args); j++)
+    generic_parameter_die (parm_pack,
+                          TREE_VEC_ELT (parm_pack_args, j),
+                          false /* Don't emit DW_AT_name */,
+                          die);
+  return die;
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
+   an enumerated type.  */
+
+static inline int
+type_is_enum (const_tree type)
 {
-  const struct file_info *const s1 = (const struct file_info *) p1;
-  const struct file_info *const s2 = (const struct file_info *) p2;
-  const unsigned char *cp1;
-  const unsigned char *cp2;
+  return TREE_CODE (type) == ENUMERAL_TYPE;
+}
 
-  /* Take care of file names without directories.  We need to make sure that
-     we return consistent values to qsort since some will get confused if
-     we return the same value when identical operands are passed in opposite
-     orders.  So if neither has a directory, return 0 and otherwise return
-     1 or -1 depending on which one has the directory.  */
-  if ((s1->path == s1->fname || s2->path == s2->fname))
-    return (s2->path == s2->fname) - (s1->path == s1->fname);
+/* Return the DBX register number described by a given RTL node.  */
 
-  cp1 = (const unsigned char *) s1->path;
-  cp2 = (const unsigned char *) s2->path;
+static unsigned int
+dbx_reg_number (const_rtx rtl)
+{
+  unsigned regno = REGNO (rtl);
 
-  while (1)
-    {
-      ++cp1;
-      ++cp2;
-      /* Reached the end of the first path?  If so, handle like above.  */
-      if ((cp1 == (const unsigned char *) s1->fname)
-         || (cp2 == (const unsigned char *) s2->fname))
-       return ((cp2 == (const unsigned char *) s2->fname)
-               - (cp1 == (const unsigned char *) s1->fname));
+  gcc_assert (regno < FIRST_PSEUDO_REGISTER);
 
-      /* Character of current path component the same?  */
-      else if (*cp1 != *cp2)
-       return *cp1 - *cp2;
+#ifdef LEAF_REG_REMAP
+  if (current_function_uses_only_leaf_regs)
+    {
+      int leaf_reg = LEAF_REG_REMAP (regno);
+      if (leaf_reg != -1)
+       regno = (unsigned) leaf_reg;
     }
+#endif
+
+  return DBX_REGISTER_NUMBER (regno);
 }
 
-struct file_name_acquire_data
+/* Optionally add a DW_OP_piece term to a location description expression.
+   DW_OP_piece is only added if the location description expression already
+   doesn't end with DW_OP_piece.  */
+
+static void
+add_loc_descr_op_piece (dw_loc_descr_ref *list_head, int size)
 {
-  struct file_info *files;
-  int used_files;
-  int max_files;
-};
+  dw_loc_descr_ref loc;
 
-/* Traversal function for the hash table.  */
+  if (*list_head != NULL)
+    {
+      /* Find the end of the chain.  */
+      for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
+       ;
 
-static int
-file_name_acquire (void ** slot, void *data)
+      if (loc->dw_loc_opc != DW_OP_piece)
+       loc->dw_loc_next = new_loc_descr (DW_OP_piece, size, 0);
+    }
+}
+
+/* Return a location descriptor that designates a machine register or
+   zero if there is none.  */
+
+static dw_loc_descr_ref
+reg_loc_descriptor (rtx rtl, enum var_init_status initialized)
 {
-  struct file_name_acquire_data *fnad = (struct file_name_acquire_data *) data;
-  struct dwarf_file_data *d = (struct dwarf_file_data *) *slot;
-  struct file_info *fi;
-  const char *f;
+  rtx regs;
 
-  gcc_assert (fnad->max_files >= d->emitted_number);
+  if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
+    return 0;
 
-  if (! d->emitted_number)
-    return 1;
+  /* We only use "frame base" when we're sure we're talking about the
+     post-prologue local stack frame.  We do this by *not* running
+     register elimination until this point, and recognizing the special
+     argument pointer and soft frame pointer rtx's.
+     Use DW_OP_fbreg offset DW_OP_stack_value in this case.  */
+  if ((rtl == arg_pointer_rtx || rtl == frame_pointer_rtx)
+      && eliminate_regs (rtl, VOIDmode, NULL_RTX) != rtl)
+    {
+      dw_loc_descr_ref result = NULL;
 
-  gcc_assert (fnad->max_files != fnad->used_files);
+      if (dwarf_version >= 4 || !dwarf_strict)
+       {
+         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));
+       }
+      return result;
+    }
 
-  fi = fnad->files + fnad->used_files++;
+  regs = targetm.dwarf_register_span (rtl);
 
-  /* Skip all leading "./".  */
-  f = d->filename;
-  while (f[0] == '.' && IS_DIR_SEPARATOR (f[1]))
-    f += 2;
+  if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
+    return multiple_reg_loc_descriptor (rtl, regs, initialized);
+  else
+    return one_reg_loc_descriptor (dbx_reg_number (rtl), initialized);
+}
 
-  /* Create a new array entry.  */
-  fi->path = f;
-  fi->length = strlen (f);
-  fi->file_idx = d;
+/* Return a location descriptor that designates a machine register for
+   a given hard register number.  */
 
-  /* Search for the file name part.  */
-  f = strrchr (f, DIR_SEPARATOR);
-#if defined (DIR_SEPARATOR_2)
-  {
-    char *g = strrchr (fi->path, DIR_SEPARATOR_2);
+static dw_loc_descr_ref
+one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized)
+{
+  dw_loc_descr_ref reg_loc_descr;
 
-    if (g != NULL)
-      {
-       if (f == NULL || f < g)
-         f = g;
-      }
-  }
-#endif
+  if (regno <= 31)
+    reg_loc_descr
+      = new_loc_descr ((enum dwarf_location_atom) (DW_OP_reg0 + regno), 0, 0);
+  else
+    reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0);
 
-  fi->fname = f == NULL ? fi->path : f + 1;
-  return 1;
+  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&reg_loc_descr, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
+  return reg_loc_descr;
 }
 
-/* Output the directory table and the file name table.  We try to minimize
-   the total amount of memory needed.  A heuristic is used to avoid large
-   slowdowns with many input files.  */
+/* Given an RTL of a register, return a location descriptor that
+   designates a value that spans more than one register.  */
 
-static void
-output_file_names (void)
+static dw_loc_descr_ref
+multiple_reg_loc_descriptor (rtx rtl, rtx regs,
+                            enum var_init_status initialized)
 {
-  struct file_name_acquire_data fnad;
-  int numfiles;
-  struct file_info *files;
-  struct dir_info *dirs;
-  int *saved;
-  int *savehere;
-  int *backmap;
-  int ndirs;
-  int idx_offset;
-  int i;
+  int nregs, size, i;
+  unsigned reg;
+  dw_loc_descr_ref loc_result = NULL;
 
-  if (!last_emitted_file)
+  reg = REGNO (rtl);
+#ifdef LEAF_REG_REMAP
+  if (current_function_uses_only_leaf_regs)
     {
-      dw2_asm_output_data (1, 0, "End directory table");
-      dw2_asm_output_data (1, 0, "End file name table");
-      return;
+      int leaf_reg = LEAF_REG_REMAP (reg);
+      if (leaf_reg != -1)
+       reg = (unsigned) leaf_reg;
+    }
+#endif
+  gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
+  nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
+
+  /* Simple, contiguous registers.  */
+  if (regs == NULL_RTX)
+    {
+      size = GET_MODE_SIZE (GET_MODE (rtl)) / nregs;
+
+      loc_result = NULL;
+      while (nregs--)
+       {
+         dw_loc_descr_ref t;
+
+         t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg),
+                                     VAR_INIT_STATUS_INITIALIZED);
+         add_loc_descr (&loc_result, t);
+         add_loc_descr_op_piece (&loc_result, size);
+         ++reg;
+       }
+      return loc_result;
+    }
+
+  /* Now onto stupid register sets in non contiguous locations.  */
+
+  gcc_assert (GET_CODE (regs) == PARALLEL);
+
+  size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
+  loc_result = NULL;
+
+  for (i = 0; i < XVECLEN (regs, 0); ++i)
+    {
+      dw_loc_descr_ref t;
+
+      t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)),
+                                 VAR_INIT_STATUS_INITIALIZED);
+      add_loc_descr (&loc_result, t);
+      size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
+      add_loc_descr_op_piece (&loc_result, size);
     }
 
-  numfiles = last_emitted_file->emitted_number;
+  if (loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+  return loc_result;
+}
 
-  /* Allocate the various arrays we need.  */
-  files = XALLOCAVEC (struct file_info, numfiles);
-  dirs = XALLOCAVEC (struct dir_info, numfiles);
+static unsigned long size_of_int_loc_descriptor (HOST_WIDE_INT);
 
-  fnad.files = files;
-  fnad.used_files = 0;
-  fnad.max_files = numfiles;
-  htab_traverse (file_table, file_name_acquire, &fnad);
-  gcc_assert (fnad.used_files == fnad.max_files);
+/* Return a location descriptor that designates a constant i,
+   as a compound operation from constant (i >> shift), constant shift
+   and DW_OP_shl.  */
 
-  qsort (files, numfiles, sizeof (files[0]), file_info_cmp);
+static dw_loc_descr_ref
+int_shift_loc_descriptor (HOST_WIDE_INT i, int shift)
+{
+  dw_loc_descr_ref ret = int_loc_descriptor (i >> shift);
+  add_loc_descr (&ret, int_loc_descriptor (shift));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_shl, 0, 0));
+  return ret;
+}
 
-  /* Find all the different directories used.  */
-  dirs[0].path = files[0].path;
-  dirs[0].length = files[0].fname - files[0].path;
-  dirs[0].prefix = -1;
-  dirs[0].count = 1;
-  dirs[0].dir_idx = 0;
-  files[0].dir_idx = 0;
-  ndirs = 1;
+/* Return a location descriptor that designates a constant.  */
 
-  for (i = 1; i < numfiles; i++)
-    if (files[i].fname - files[i].path == dirs[ndirs - 1].length
-       && memcmp (dirs[ndirs - 1].path, files[i].path,
-                  dirs[ndirs - 1].length) == 0)
-      {
-       /* Same directory as last entry.  */
-       files[i].dir_idx = ndirs - 1;
-       ++dirs[ndirs - 1].count;
-      }
-    else
-      {
-       int j;
+static dw_loc_descr_ref
+int_loc_descriptor (HOST_WIDE_INT i)
+{
+  enum dwarf_location_atom op;
 
-       /* This is a new directory.  */
-       dirs[ndirs].path = files[i].path;
-       dirs[ndirs].length = files[i].fname - files[i].path;
-       dirs[ndirs].count = 1;
-       dirs[ndirs].dir_idx = ndirs;
-       files[i].dir_idx = ndirs;
+  /* Pick the smallest representation of a constant, rather than just
+     defaulting to the LEB encoding.  */
+  if (i >= 0)
+    {
+      int clz = clz_hwi (i);
+      int ctz = ctz_hwi (i);
+      if (i <= 31)
+       op = (enum dwarf_location_atom) (DW_OP_lit0 + i);
+      else if (i <= 0xff)
+       op = DW_OP_const1u;
+      else if (i <= 0xffff)
+       op = DW_OP_const2u;
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 5
+              && clz + 5 + 255 >= HOST_BITS_PER_WIDE_INT)
+       /* DW_OP_litX DW_OP_litY DW_OP_shl takes just 3 bytes and
+          DW_OP_litX DW_OP_const1u Y DW_OP_shl takes just 4 bytes,
+          while DW_OP_const4u is 5 bytes.  */
+       return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 5);
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8
+              && clz + 8 + 31 >= HOST_BITS_PER_WIDE_INT)
+       /* DW_OP_const1u X DW_OP_litY DW_OP_shl takes just 4 bytes,
+          while DW_OP_const4u is 5 bytes.  */
+       return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 8);
+      else if (HOST_BITS_PER_WIDE_INT == 32 || i <= 0xffffffff)
+       op = DW_OP_const4u;
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8
+              && clz + 8 + 255 >= HOST_BITS_PER_WIDE_INT)
+       /* DW_OP_const1u X DW_OP_const1u Y DW_OP_shl takes just 5 bytes,
+          while DW_OP_constu of constant >= 0x100000000 takes at least
+          6 bytes.  */
+       return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 8);
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 16
+              && clz + 16 + (size_of_uleb128 (i) > 5 ? 255 : 31)
+                 >= HOST_BITS_PER_WIDE_INT)
+       /* DW_OP_const2u X DW_OP_litY DW_OP_shl takes just 5 bytes,
+          DW_OP_const2u X DW_OP_const1u Y DW_OP_shl takes 6 bytes,
+          while DW_OP_constu takes in this case at least 6 bytes.  */
+       return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 16);
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 32
+              && clz + 32 + 31 >= HOST_BITS_PER_WIDE_INT
+              && size_of_uleb128 (i) > 6)
+       /* DW_OP_const4u X DW_OP_litY DW_OP_shl takes just 7 bytes.  */
+       return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 32);
+      else
+       op = DW_OP_constu;
+    }
+  else
+    {
+      if (i >= -0x80)
+       op = DW_OP_const1s;
+      else if (i >= -0x8000)
+       op = DW_OP_const2s;
+      else if (HOST_BITS_PER_WIDE_INT == 32 || i >= -0x80000000)
+       {
+         if (size_of_int_loc_descriptor (i) < 5)
+           {
+             dw_loc_descr_ref ret = int_loc_descriptor (-i);
+             add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0));
+             return ret;
+           }
+         op = DW_OP_const4s;
+       }
+      else
+       {
+         if (size_of_int_loc_descriptor (i)
+             < (unsigned long) 1 + size_of_sleb128 (i))
+           {
+             dw_loc_descr_ref ret = int_loc_descriptor (-i);
+             add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0));
+             return ret;
+           }
+         op = DW_OP_consts;
+       }
+    }
 
-       /* Search for a prefix.  */
-       dirs[ndirs].prefix = -1;
-       for (j = 0; j < ndirs; j++)
-         if (dirs[j].length < dirs[ndirs].length
-             && dirs[j].length > 1
-             && (dirs[ndirs].prefix == -1
-                 || dirs[j].length > dirs[dirs[ndirs].prefix].length)
-             && memcmp (dirs[j].path, dirs[ndirs].path, dirs[j].length) == 0)
-           dirs[ndirs].prefix = j;
+  return new_loc_descr (op, i, 0);
+}
 
-       ++ndirs;
-      }
+/* Return size_of_locs (int_shift_loc_descriptor (i, shift))
+   without actually allocating it.  */
 
-  /* Now to the actual work.  We have to find a subset of the directories which
-     allow expressing the file name using references to the directory table
-     with the least amount of characters.  We do not do an exhaustive search
-     where we would have to check out every combination of every single
-     possible prefix.  Instead we use a heuristic which provides nearly optimal
-     results in most cases and never is much off.  */
-  saved = XALLOCAVEC (int, ndirs);
-  savehere = XALLOCAVEC (int, ndirs);
+static unsigned long
+size_of_int_shift_loc_descriptor (HOST_WIDE_INT i, int shift)
+{
+  return size_of_int_loc_descriptor (i >> shift)
+        + size_of_int_loc_descriptor (shift)
+        + 1;
+}
 
-  memset (saved, '\0', ndirs * sizeof (saved[0]));
-  for (i = 0; i < ndirs; i++)
-    {
-      int j;
-      int total;
+/* Return size_of_locs (int_loc_descriptor (i)) without
+   actually allocating it.  */
 
-      /* We can always save some space for the current directory.  But this
-        does not mean it will be enough to justify adding the directory.  */
-      savehere[i] = dirs[i].length;
-      total = (savehere[i] - saved[i]) * dirs[i].count;
+static unsigned long
+size_of_int_loc_descriptor (HOST_WIDE_INT i)
+{
+  unsigned long s;
 
-      for (j = i + 1; j < ndirs; j++)
+  if (i >= 0)
+    {
+      int clz, ctz;
+      if (i <= 31)
+       return 1;
+      else if (i <= 0xff)
+       return 2;
+      else if (i <= 0xffff)
+       return 3;
+      clz = clz_hwi (i);
+      ctz = ctz_hwi (i);
+      if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 5
+         && clz + 5 + 255 >= HOST_BITS_PER_WIDE_INT)
+       return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
+                                                   - clz - 5);
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8
+              && clz + 8 + 31 >= HOST_BITS_PER_WIDE_INT)
+       return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
+                                                   - clz - 8);
+      else if (HOST_BITS_PER_WIDE_INT == 32 || i <= 0xffffffff)
+       return 5;
+      s = size_of_uleb128 ((unsigned HOST_WIDE_INT) i);
+      if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8
+         && clz + 8 + 255 >= HOST_BITS_PER_WIDE_INT)
+       return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
+                                                   - clz - 8);
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 16
+              && clz + 16 + (s > 5 ? 255 : 31) >= HOST_BITS_PER_WIDE_INT)
+       return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
+                                                   - clz - 16);
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 32
+              && clz + 32 + 31 >= HOST_BITS_PER_WIDE_INT
+              && s > 6)
+       return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
+                                                   - clz - 32);
+      else
+       return 1 + s;
+    }
+  else
+    {
+      if (i >= -0x80)
+       return 2;
+      else if (i >= -0x8000)
+       return 3;
+      else if (HOST_BITS_PER_WIDE_INT == 32 || i >= -0x80000000)
        {
-         savehere[j] = 0;
-         if (saved[j] < dirs[i].length)
+         if (-(unsigned HOST_WIDE_INT) i != (unsigned HOST_WIDE_INT) i)
            {
-             /* Determine whether the dirs[i] path is a prefix of the
-                dirs[j] path.  */
-             int k;
-
-             k = dirs[j].prefix;
-             while (k != -1 && k != (int) i)
-               k = dirs[k].prefix;
-
-             if (k == (int) i)
-               {
-                 /* Yes it is.  We can possibly save some memory by
-                    writing the filenames in dirs[j] relative to
-                    dirs[i].  */
-                 savehere[j] = dirs[i].length;
-                 total += (savehere[j] - saved[j]) * dirs[j].count;
-               }
+             s = size_of_int_loc_descriptor (-i) + 1;
+             if (s < 5)
+               return s;
            }
+         return 5;
        }
-
-      /* Check whether we can save enough to justify adding the dirs[i]
-        directory.  */
-      if (total > dirs[i].length + 1)
+      else
        {
-         /* It's worthwhile adding.  */
-         for (j = i; j < ndirs; j++)
-           if (savehere[j] > 0)
-             {
-               /* Remember how much we saved for this directory so far.  */
-               saved[j] = savehere[j];
-
-               /* Remember the prefix directory.  */
-               dirs[j].dir_idx = i;
-             }
+         unsigned long r = 1 + size_of_sleb128 (i);
+         if (-(unsigned HOST_WIDE_INT) i != (unsigned HOST_WIDE_INT) i)
+           {
+             s = size_of_int_loc_descriptor (-i) + 1;
+             if (s < r)
+               return s;
+           }
+         return r;
        }
     }
+}
 
-  /* Emit the directory name table.  */
-  idx_offset = dirs[0].length > 0 ? 1 : 0;
-  for (i = 1 - idx_offset; i < ndirs; i++)
-    dw2_asm_output_nstring (dirs[i].path,
-                           dirs[i].length
-                            - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
-                           "Directory Entry: %#x", i + idx_offset);
+/* Return loc description representing "address" of integer value.
+   This can appear only as toplevel expression.  */
 
-  dw2_asm_output_data (1, 0, "End directory table");
+static dw_loc_descr_ref
+address_of_int_loc_descriptor (int size, HOST_WIDE_INT i)
+{
+  int litsize;
+  dw_loc_descr_ref loc_result = NULL;
 
-  /* We have to emit them in the order of emitted_number since that's
-     used in the debug info generation.  To do this efficiently we
-     generate a back-mapping of the indices first.  */
-  backmap = XALLOCAVEC (int, numfiles);
-  for (i = 0; i < numfiles; i++)
-    backmap[files[i].file_idx->emitted_number - 1] = i;
+  if (!(dwarf_version >= 4 || !dwarf_strict))
+    return NULL;
 
-  /* Now write all the file names.  */
-  for (i = 0; i < numfiles; i++)
+  litsize = size_of_int_loc_descriptor (i);
+  /* Determine if DW_OP_stack_value or DW_OP_implicit_value
+     is more compact.  For DW_OP_stack_value we need:
+     litsize + 1 (DW_OP_stack_value)
+     and for DW_OP_implicit_value:
+     1 (DW_OP_implicit_value) + 1 (length) + size.  */
+  if ((int) DWARF2_ADDR_SIZE >= size && litsize + 1 <= 1 + 1 + size)
     {
-      int file_idx = backmap[i];
-      int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
+      loc_result = int_loc_descriptor (i);
+      add_loc_descr (&loc_result,
+                    new_loc_descr (DW_OP_stack_value, 0, 0));
+      return loc_result;
+    }
 
-#ifdef VMS_DEBUGGING_INFO
-#define MAX_VMS_VERSION_LEN 6 /* ";32768" */
+  loc_result = new_loc_descr (DW_OP_implicit_value,
+                             size, 0);
+  loc_result->dw_loc_oprnd2.val_class = dw_val_class_const;
+  loc_result->dw_loc_oprnd2.v.val_int = i;
+  return loc_result;
+}
 
-      /* Setting these fields can lead to debugger miscomparisons,
-         but VMS Debug requires them to be set correctly.  */
+/* Return a location descriptor that designates a base+offset location.  */
 
-      int ver;
-      long long cdt;
-      long siz;
-      int maxfilelen = strlen (files[file_idx].path)
-                              + dirs[dir_idx].length
-                              + MAX_VMS_VERSION_LEN + 1;
-      char *filebuf = XALLOCAVEC (char, maxfilelen);
+static dw_loc_descr_ref
+based_loc_descr (rtx reg, HOST_WIDE_INT offset,
+                enum var_init_status initialized)
+{
+  unsigned int regno;
+  dw_loc_descr_ref result;
+  dw_fde_ref fde = cfun->fde;
 
-      vms_file_stats_name (files[file_idx].path, 0, 0, 0, &ver);
-      snprintf (filebuf, maxfilelen, "%s;%d",
-               files[file_idx].path + dirs[dir_idx].length, ver);
+  /* We only use "frame base" when we're sure we're talking about the
+     post-prologue local stack frame.  We do this by *not* running
+     register elimination until this point, and recognizing the special
+     argument pointer and soft frame pointer rtx's.  */
+  if (reg == arg_pointer_rtx || reg == frame_pointer_rtx)
+    {
+      rtx elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+
+      if (elim != reg)
+       {
+         if (GET_CODE (elim) == PLUS)
+           {
+             offset += INTVAL (XEXP (elim, 1));
+             elim = XEXP (elim, 0);
+           }
+         gcc_assert ((SUPPORTS_STACK_ALIGNMENT
+                      && (elim == hard_frame_pointer_rtx
+                          || elim == stack_pointer_rtx))
+                     || elim == (frame_pointer_needed
+                                 ? hard_frame_pointer_rtx
+                                 : stack_pointer_rtx));
+
+         /* If drap register is used to align stack, use frame
+            pointer + offset to access stack variables.  If stack
+            is aligned without drap, use stack pointer + offset to
+            access stack variables.  */
+         if (crtl->stack_realign_tried
+             && reg == frame_pointer_rtx)
+           {
+             int base_reg
+               = DWARF_FRAME_REGNUM ((fde && fde->drap_reg != INVALID_REGNUM)
+                                     ? HARD_FRAME_POINTER_REGNUM
+                                     : REGNO (elim));
+             return new_reg_loc_descr (base_reg, offset);
+           }
 
-      dw2_asm_output_nstring
-       (filebuf, -1, "File Entry: %#x", (unsigned) i + 1);
+         gcc_assert (frame_pointer_fb_offset_valid);
+         offset += frame_pointer_fb_offset;
+         return new_loc_descr (DW_OP_fbreg, offset, 0);
+       }
+    }
 
-      /* Include directory index.  */
-      dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+  regno = DWARF_FRAME_REGNUM (REGNO (reg));
 
-      /* Modification time.  */
-      dw2_asm_output_data_uleb128
-        ((vms_file_stats_name (files[file_idx].path, &cdt, 0, 0, 0) == 0)
-         ? cdt : 0,
-        NULL);
+  if (!optimize && fde
+      && (fde->drap_reg == regno || fde->vdrap_reg == regno))
+    {
+      /* Use cfa+offset to represent the location of arguments passed
+        on the stack when drap is used to align stack.
+        Only do this when not optimizing, for optimized code var-tracking
+        is supposed to track where the arguments live and the register
+        used as vdrap or drap in some spot might be used for something
+        else in other part of the routine.  */
+      return new_loc_descr (DW_OP_fbreg, offset, 0);
+    }
 
-      /* File length in bytes.  */
-      dw2_asm_output_data_uleb128
-        ((vms_file_stats_name (files[file_idx].path, 0, &siz, 0, 0) == 0)
-         ? siz : 0,
-        NULL);
-#else
-      dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
-                             "File Entry: %#x", (unsigned) i + 1);
+  if (regno <= 31)
+    result = new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + regno),
+                           offset, 0);
+  else
+    result = new_loc_descr (DW_OP_bregx, regno, offset);
 
-      /* Include directory index.  */
-      dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
 
-      /* Modification time.  */
-      dw2_asm_output_data_uleb128 (0, NULL);
+  return result;
+}
 
-      /* File length in bytes.  */
-      dw2_asm_output_data_uleb128 (0, NULL);
-#endif
-    }
+/* Return true if this RTL expression describes a base+offset calculation.  */
 
-  dw2_asm_output_data (1, 0, "End file name table");
+static inline int
+is_based_loc (const_rtx rtl)
+{
+  return (GET_CODE (rtl) == PLUS
+         && ((REG_P (XEXP (rtl, 0))
+              && REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
+              && CONST_INT_P (XEXP (rtl, 1)))));
 }
 
+/* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0)
+   failed.  */
 
-/* Output the source line number correspondence information.  This
-   information goes into the .debug_line section.  */
-
-static void
-output_line_info (void)
+static dw_loc_descr_ref
+tls_mem_loc_descriptor (rtx mem)
 {
-  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;
+  tree base;
+  dw_loc_descr_ref loc_result;
 
-  ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (p1, LN_PROLOG_AS_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (p2, LN_PROLOG_END_LABEL, 0);
+  if (MEM_EXPR (mem) == NULL_TREE || !MEM_OFFSET_KNOWN_P (mem))
+    return 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_delta (DWARF_OFFSET_SIZE, l2, l1,
-                       "Length of Source Line Info");
-  ASM_OUTPUT_LABEL (asm_out_file, l1);
+  base = get_base_address (MEM_EXPR (mem));
+  if (base == NULL
+      || TREE_CODE (base) != VAR_DECL
+      || !DECL_THREAD_LOCAL_P (base))
+    return NULL;
 
-  dw2_asm_output_data (2, ver, "DWARF Version");
-  dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
-  ASM_OUTPUT_LABEL (asm_out_file, p1);
+  loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1);
+  if (loc_result == NULL)
+    return NULL;
 
-  /* 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 (MEM_OFFSET (mem))
+    loc_descr_plus_const (&loc_result, MEM_OFFSET (mem));
 
-  if (ver >= 4)
-    dw2_asm_output_data (1, DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN,
-                        "Maximum Operations Per Instruction");
-  dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START,
-                      "Default is_stmt_start flag");
-  dw2_asm_output_data (1, DWARF_LINE_BASE,
-                      "Line Base Value (Special Opcodes)");
-  dw2_asm_output_data (1, DWARF_LINE_RANGE,
-                      "Line Range Value (Special Opcodes)");
-  dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE,
-                      "Special Opcode Base");
+  return loc_result;
+}
 
-  for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; opc++)
+/* Output debug info about reason why we failed to expand expression as dwarf
+   expression.  */
+
+static void
+expansion_failed (tree expr, rtx rtl, char const *reason)
+{
+  if (dump_file && (dump_flags & TDF_DETAILS))
     {
-      switch (opc)
+      fprintf (dump_file, "Failed to expand as dwarf: ");
+      if (expr)
+       print_generic_expr (dump_file, expr, dump_flags);
+      if (rtl)
        {
-       case DW_LNS_advance_pc:
-       case DW_LNS_advance_line:
-       case DW_LNS_set_file:
-       case DW_LNS_set_column:
-       case DW_LNS_fixed_advance_pc:
-         n_op_args = 1;
-         break;
-       default:
-         n_op_args = 0;
-         break;
+         fprintf (dump_file, "\n");
+         print_rtl (dump_file, rtl);
        }
-
-      dw2_asm_output_data (1, n_op_args, "opcode: %#x has %d args",
-                          opc, n_op_args);
+      fprintf (dump_file, "\nReason: %s\n", reason);
     }
+}
 
-  /* Write out the information about the files we use.  */
-  output_file_names ();
-  ASM_OUTPUT_LABEL (asm_out_file, p2);
-
-  /* We used to set the address register to the first location in the text
-     section here, but that didn't accomplish anything since we already
-     have a line note for the opening brace of the first function.  */
+/* Helper function for const_ok_for_output, called either directly
+   or via for_each_rtx.  */
 
-  /* Generate the line number to PC correspondence table, encoded as
-     a series of state machine operations.  */
-  current_file = 1;
-  current_line = 1;
+static int
+const_ok_for_output_1 (rtx *rtlp, void *data ATTRIBUTE_UNUSED)
+{
+  rtx rtl = *rtlp;
 
-  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 (GET_CODE (rtl) == UNSPEC)
     {
-      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;
+      /* If delegitimize_address couldn't do anything with the UNSPEC, assume
+        we can't express it in the debug info.  */
+#ifdef ENABLE_CHECKING
+      /* 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");
+      return 1;
+    }
 
-      /* 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);
-       }
+  if (GET_CODE (rtl) != SYMBOL_REF)
+    return 0;
 
-      /* 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)
+  if (CONSTANT_POOL_ADDRESS_P (rtl))
+    {
+      bool marked;
+      get_pool_constant_mark (rtl, &marked);
+      /* If all references to this pool constant were optimized away,
+        it was not output and thus we can't represent it.  */
+      if (!marked)
        {
-         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");
-           }
+         expansion_failed (NULL_TREE, rtl,
+                           "Constant was removed from constant pool.\n");
+         return 1;
        }
-      else
-       /* We still need to start a new row, so output a copy insn.  */
-       dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
-    }
-
-  /* Emit debug info for the address of the end of the function.  */
-  if (0)
-    {
-      dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-                          "DW_LNS_fixed_advance_pc");
-      dw2_asm_output_delta (2, text_end_label, prev_line_label, NULL);
-    }
-  else
-    {
-      dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-      dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-      dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-      dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_end_label, NULL);
     }
 
-  dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
-  dw2_asm_output_data_uleb128 (1, NULL);
-  dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
+  if (SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
+    return 1;
 
-  function = 0;
-  current_file = 1;
-  current_line = 1;
-  for (lt_index = 0; lt_index < separate_line_info_table_in_use;)
+  /* Avoid references to external symbols in debug info, on several targets
+     the linker might even refuse to link when linking a shared library,
+     and in many other cases the relocations for .debug_info/.debug_loc are
+     dropped, so the address becomes zero anyway.  Hidden symbols, guaranteed
+     to be defined within the same shared library or executable are fine.  */
+  if (SYMBOL_REF_EXTERNAL_P (rtl))
     {
-      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;
+      tree decl = SYMBOL_REF_DECL (rtl);
 
-         /* 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
+      if (decl == NULL || !targetm.binds_local_p (decl))
        {
-         /* ??? 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);
-           }
+         expansion_failed (NULL_TREE, rtl,
+                           "Symbol not defined in current TU.\n");
+         return 1;
        }
+    }
 
-      strcpy (prev_line_label, line_label);
+  return 0;
+}
 
-      /* 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);
-       }
+/* Return true if constant RTL can be emitted in DW_OP_addr or
+   DW_AT_const_value.  TLS SYMBOL_REFs, external SYMBOL_REFs or
+   non-marked constant pool SYMBOL_REFs can't be referenced in it.  */
 
-      /* 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");
+static bool
+const_ok_for_output (rtx rtl)
+{
+  if (GET_CODE (rtl) == SYMBOL_REF)
+    return const_ok_for_output_1 (&rtl, NULL) == 0;
 
-#if 0
-    cont:
-#endif
+  if (GET_CODE (rtl) == CONST)
+    return for_each_rtx (&XEXP (rtl, 0), const_ok_for_output_1, NULL) == 0;
 
-      lt_index++;
+  return true;
+}
 
-      /* 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;
+/* Return a reference to DW_TAG_base_type corresponding to MODE and UNSIGNEDP
+   if possible, NULL otherwise.  */
 
-         /* 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);
-           }
+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);
 
-         /* Output the marker for the end of this sequence.  */
-         dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
-         dw2_asm_output_data_uleb128 (1, NULL);
-         dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
-       }
+  if (type == NULL)
+    return NULL;
+  switch (TREE_CODE (type))
+    {
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+      break;
+    default:
+      return NULL;
     }
-
-  /* Output the marker for the end of the line number info.  */
-  ASM_OUTPUT_LABEL (asm_out_file, l2);
+  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;
 }
 
-/* Return the size of the .debug_dcall table for the compilation unit.  */
+/* For OP descriptor assumed to be in unsigned MODE, convert it to a unsigned
+   type matching MODE, or, if MODE is narrower than or as wide as
+   DWARF2_ADDR_SIZE, untyped.  Return NULL if the conversion is not
+   possible.  */
 
-static unsigned long
-size_of_dcall_table (void)
+static dw_loc_descr_ref
+convert_descriptor_to_mode (enum machine_mode mode, dw_loc_descr_ref op)
 {
-  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;
+  enum machine_mode outer_mode = mode;
+  dw_die_ref type_die;
+  dw_loc_descr_ref cvt;
 
-  /* Each entry:  code label + DIE offset.  */
-  for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, p); i++)
+  if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE)
     {
-      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);
+      add_loc_descr (&op, new_loc_descr (DW_OP_GNU_convert, 0, 0));
+      return op;
     }
-
-  return size;
+  type_die = base_type_for_mode (outer_mode, 1);
+  if (type_die == NULL)
+    return NULL;
+  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 (&op, cvt);
+  return op;
 }
 
-/* Output the direct call table used to disambiguate PC values when
-   identical function have been merged.  */
+/* Return location descriptor for comparison OP with operands OP0 and OP1.  */
 
-static void
-output_dcall_table (void)
+static dw_loc_descr_ref
+compare_loc_descriptor (enum dwarf_location_atom op, dw_loc_descr_ref op0,
+                       dw_loc_descr_ref op1)
 {
-  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++)
+  dw_loc_descr_ref ret = op0;
+  add_loc_descr (&ret, op1);
+  add_loc_descr (&ret, new_loc_descr (op, 0, 0));
+  if (STORE_FLAG_VALUE != 1)
     {
-      /* 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");
+      add_loc_descr (&ret, int_loc_descriptor (STORE_FLAG_VALUE));
+      add_loc_descr (&ret, new_loc_descr (DW_OP_mul, 0, 0));
     }
+  return ret;
 }
-\f
-/* Return the size of the .debug_vcall table for the compilation unit.  */
 
-static unsigned long
-size_of_vcall_table (void)
+/* Return location descriptor for signed comparison OP RTL.  */
+
+static dw_loc_descr_ref
+scompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl,
+                        enum machine_mode mem_mode)
 {
-  unsigned long size;
-  unsigned int i;
-  vcall_entry *p;
+  enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
+  dw_loc_descr_ref op0, op1;
+  int shift;
 
-  /* Header:  version + pointer size.  */
-  size = 2 + 1;
+  if (op_mode == VOIDmode)
+    op_mode = GET_MODE (XEXP (rtl, 1));
+  if (op_mode == VOIDmode)
+    return NULL;
 
-  /* 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);
+  if (dwarf_strict
+      && (GET_MODE_CLASS (op_mode) != MODE_INT
+         || GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE))
+    return NULL;
 
-  return size;
-}
+  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);
 
-/* Output the virtual call table used to disambiguate PC values when
-   identical function have been merged.  */
+  if (op0 == NULL || op1 == NULL)
+    return NULL;
 
-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 (GET_MODE_CLASS (op_mode) != MODE_INT
+      || GET_MODE_SIZE (op_mode) == DWARF2_ADDR_SIZE)
+    return compare_loc_descriptor (op, op0, op1);
 
-  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)");
+  if (GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE)
+    {
+      dw_die_ref type_die = base_type_for_mode (op_mode, 0);
+      dw_loc_descr_ref cvt;
 
-  for (i = 0; VEC_iterate (vcall_entry, vcall_table, i, p); i++)
+      if (type_die == NULL)
+       return NULL;
+      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);
+      return compare_loc_descriptor (op, op0, op1);
+    }
+
+  shift = (DWARF2_ADDR_SIZE - GET_MODE_SIZE (op_mode)) * 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)))))
+       return compare_loc_descriptor (op, op0, op1);
+
+      /* EQ/NE comparison against constant in narrower type than
+        DWARF2_ADDR_SIZE can be performed either as
+        DW_OP_const1u <shift> DW_OP_shl DW_OP_const* <cst << shift>
+        DW_OP_{eq,ne}
+        or
+        DW_OP_const*u <mode_mask> DW_OP_and DW_OP_const* <cst & mode_mask>
+        DW_OP_{eq,ne}.  Pick whatever is shorter.  */
+      if (CONST_INT_P (XEXP (rtl, 1))
+         && GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT
+         && (size_of_int_loc_descriptor (shift) + 1
+             + size_of_int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift)
+             >= size_of_int_loc_descriptor (GET_MODE_MASK (op_mode)) + 1
+                + size_of_int_loc_descriptor (INTVAL (XEXP (rtl, 1))
+                                              & GET_MODE_MASK (op_mode))))
+       {
+         add_loc_descr (&op0, int_loc_descriptor (GET_MODE_MASK (op_mode)));
+         add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+         op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1))
+                                   & GET_MODE_MASK (op_mode));
+         return compare_loc_descriptor (op, op0, op1);
+       }
+    }
+  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
     {
-      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");
+      add_loc_descr (&op1, int_loc_descriptor (shift));
+      add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
     }
+  return compare_loc_descriptor (op, op0, op1);
 }
-\f
-/* Given a pointer to a tree node for some base type, return a pointer to
-   a DIE that describes the given type.
 
-   This routine must only be called for GCC type nodes that correspond to
-   Dwarf base (fundamental) types.  */
+/* Return location descriptor for unsigned comparison OP RTL.  */
 
-static dw_die_ref
-base_type_die (tree type)
+static dw_loc_descr_ref
+ucompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl,
+                        enum machine_mode mem_mode)
 {
-  dw_die_ref base_type_result;
-  enum dwarf_type encoding;
+  enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
+  dw_loc_descr_ref op0, op1;
 
-  if (TREE_CODE (type) == ERROR_MARK || TREE_CODE (type) == VOID_TYPE)
-    return 0;
+  if (op_mode == VOIDmode)
+    op_mode = GET_MODE (XEXP (rtl, 1));
+  if (op_mode == VOIDmode)
+    return NULL;
+  if (GET_MODE_CLASS (op_mode) != MODE_INT)
+    return NULL;
 
-  /* If this is a subtype that should not be emitted as a subrange type,
-     use the base type.  See subrange_type_for_debug_p.  */
-  if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type) != NULL_TREE)
-    type = TREE_TYPE (type);
+  if (dwarf_strict && GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE)
+    return NULL;
 
-  switch (TREE_CODE (type))
+  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 == NULL || op1 == NULL)
+    return NULL;
+
+  if (GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
     {
-    case INTEGER_TYPE:
-      if (TYPE_STRING_FLAG (type))
+      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))
        {
-         if (TYPE_UNSIGNED (type))
-           encoding = DW_ATE_unsigned_char;
-         else
-           encoding = DW_ATE_signed_char;
+         add_loc_descr (&op0, int_loc_descriptor (mask));
+         add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
        }
-      else if (TYPE_UNSIGNED (type))
-       encoding = DW_ATE_unsigned;
-      else
-       encoding = DW_ATE_signed;
-      break;
-
-    case REAL_TYPE:
-      if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))
+      if (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))
        {
-         if (dwarf_version >= 3 || !dwarf_strict)
-           encoding = DW_ATE_decimal_float;
-         else
-           encoding = DW_ATE_lo_user;
+         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
-       encoding = DW_ATE_float;
-      break;
+       add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst,
+                                           bias, 0));
+    }
+  return compare_loc_descriptor (op, op0, op1);
+}
 
-    case FIXED_POINT_TYPE:
-      if (!(dwarf_version >= 3 || !dwarf_strict))
-       encoding = DW_ATE_lo_user;
-      else if (TYPE_UNSIGNED (type))
-       encoding = DW_ATE_unsigned_fixed;
-      else
-       encoding = DW_ATE_signed_fixed;
-      break;
+/* Return location descriptor for {U,S}{MIN,MAX}.  */
 
-      /* Dwarf2 doesn't know anything about complex ints, so use
-        a user defined type for it.  */
-    case COMPLEX_TYPE:
-      if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
-       encoding = DW_ATE_complex_float;
-      else
-       encoding = DW_ATE_lo_user;
-      break;
+static dw_loc_descr_ref
+minmax_loc_descriptor (rtx rtl, enum machine_mode mode,
+                      enum machine_mode mem_mode)
+{
+  enum dwarf_location_atom op;
+  dw_loc_descr_ref op0, op1, ret;
+  dw_loc_descr_ref bra_node, drop_node;
 
-    case BOOLEAN_TYPE:
-      /* GNU FORTRAN/Ada/C++ BOOLEAN type.  */
-      encoding = DW_ATE_boolean;
-      break;
+  if (dwarf_strict
+      && (GET_MODE_CLASS (mode) != MODE_INT
+         || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE))
+    return NULL;
 
-    default:
-      /* No other TREE_CODEs are Dwarf fundamental types.  */
-      gcc_unreachable ();
+  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+
+  if (op0 == NULL || op1 == NULL)
+    return NULL;
+
+  add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
+  add_loc_descr (&op1, new_loc_descr (DW_OP_swap, 0, 0));
+  add_loc_descr (&op1, new_loc_descr (DW_OP_over, 0, 0));
+  if (GET_CODE (rtl) == UMIN || GET_CODE (rtl) == UMAX)
+    {
+      if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
+       {
+         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 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 if (GET_MODE_CLASS (mode) == MODE_INT
+          && GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
+    {
+      int shift = (DWARF2_ADDR_SIZE - GET_MODE_SIZE (mode)) * BITS_PER_UNIT;
+      add_loc_descr (&op0, int_loc_descriptor (shift));
+      add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+      add_loc_descr (&op1, int_loc_descriptor (shift));
+      add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
     }
+  else if (GET_MODE_CLASS (mode) == MODE_INT
+          && GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE)
+    {
+      dw_die_ref type_die = base_type_for_mode (mode, 0);
+      dw_loc_descr_ref cvt;
+      if (type_die == NULL)
+       return NULL;
+      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);
+    }
+
+  if (GET_CODE (rtl) == SMIN || GET_CODE (rtl) == UMIN)
+    op = DW_OP_lt;
+  else
+    op = DW_OP_gt;
+  ret = op0;
+  add_loc_descr (&ret, op1);
+  add_loc_descr (&ret, new_loc_descr (op, 0, 0));
+  bra_node = new_loc_descr (DW_OP_bra, 0, 0);
+  add_loc_descr (&ret, bra_node);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  drop_node = new_loc_descr (DW_OP_drop, 0, 0);
+  add_loc_descr (&ret, drop_node);
+  bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+  bra_node->dw_loc_oprnd1.v.val_loc = drop_node;
+  if ((GET_CODE (rtl) == SMIN || GET_CODE (rtl) == SMAX)
+      && GET_MODE_CLASS (mode) == MODE_INT
+      && GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE)
+    ret = convert_descriptor_to_mode (mode, ret);
+  return ret;
+}
 
-  base_type_result = new_die (DW_TAG_base_type, comp_unit_die, type);
+/* Helper function for mem_loc_descriptor.  Perform OP binary op,
+   but after converting arguments to type_die, afterwards
+   convert back to unsigned.  */
 
-  add_AT_unsigned (base_type_result, DW_AT_byte_size,
-                  int_size_in_bytes (type));
-  add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
+static dw_loc_descr_ref
+typed_binop (enum dwarf_location_atom op, rtx rtl, dw_die_ref type_die,
+            enum machine_mode mode, enum machine_mode mem_mode)
+{
+  dw_loc_descr_ref cvt, op0, op1;
 
-  return base_type_result;
+  if (type_die == NULL)
+    return NULL;
+  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  if (op0 == NULL || op1 == NULL)
+    return NULL;
+  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);
+  add_loc_descr (&op0, op1);
+  add_loc_descr (&op0, new_loc_descr (op, 0, 0));
+  return convert_descriptor_to_mode (mode, op0);
+}
+
+/* CLZ (where constV is CLZ_DEFINED_VALUE_AT_ZERO computed value,
+   const0 is DW_OP_lit0 or corresponding typed constant,
+   const1 is DW_OP_lit1 or corresponding typed constant
+   and constMSB is constant with just the MSB bit set
+   for the mode):
+       DW_OP_dup DW_OP_bra <L1> DW_OP_drop constV DW_OP_skip <L4>
+   L1: const0 DW_OP_swap
+   L2: DW_OP_dup constMSB DW_OP_and DW_OP_bra <L3> const1 DW_OP_shl
+       DW_OP_swap DW_OP_plus_uconst <1> DW_OP_swap DW_OP_skip <L2>
+   L3: DW_OP_drop
+   L4: DW_OP_nop
+
+   CTZ is similar:
+       DW_OP_dup DW_OP_bra <L1> DW_OP_drop constV DW_OP_skip <L4>
+   L1: const0 DW_OP_swap
+   L2: DW_OP_dup const1 DW_OP_and DW_OP_bra <L3> const1 DW_OP_shr
+       DW_OP_swap DW_OP_plus_uconst <1> DW_OP_swap DW_OP_skip <L2>
+   L3: DW_OP_drop
+   L4: DW_OP_nop
+
+   FFS is similar:
+       DW_OP_dup DW_OP_bra <L1> DW_OP_drop const0 DW_OP_skip <L4>
+   L1: const1 DW_OP_swap
+   L2: DW_OP_dup const1 DW_OP_and DW_OP_bra <L3> const1 DW_OP_shr
+       DW_OP_swap DW_OP_plus_uconst <1> DW_OP_swap DW_OP_skip <L2>
+   L3: DW_OP_drop
+   L4: DW_OP_nop  */
+
+static dw_loc_descr_ref
+clz_loc_descriptor (rtx rtl, enum machine_mode mode,
+                   enum machine_mode mem_mode)
+{
+  dw_loc_descr_ref op0, ret, tmp;
+  HOST_WIDE_INT valv;
+  dw_loc_descr_ref l1jump, l1label;
+  dw_loc_descr_ref l2jump, l2label;
+  dw_loc_descr_ref l3jump, l3label;
+  dw_loc_descr_ref l4jump, l4label;
+  rtx msb;
+
+  if (GET_MODE_CLASS (mode) != MODE_INT
+      || GET_MODE (XEXP (rtl, 0)) != mode
+      || (GET_CODE (rtl) == CLZ
+         && GET_MODE_BITSIZE (mode) > 2 * HOST_BITS_PER_WIDE_INT))
+    return NULL;
+
+  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  if (op0 == NULL)
+    return NULL;
+  ret = op0;
+  if (GET_CODE (rtl) == CLZ)
+    {
+      if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, valv))
+       valv = GET_MODE_BITSIZE (mode);
+    }
+  else if (GET_CODE (rtl) == FFS)
+    valv = 0;
+  else if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, valv))
+    valv = GET_MODE_BITSIZE (mode);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_dup, 0, 0));
+  l1jump = new_loc_descr (DW_OP_bra, 0, 0);
+  add_loc_descr (&ret, l1jump);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_drop, 0, 0));
+  tmp = mem_loc_descriptor (GEN_INT (valv), mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  l4jump = new_loc_descr (DW_OP_skip, 0, 0);
+  add_loc_descr (&ret, l4jump);
+  l1label = mem_loc_descriptor (GET_CODE (rtl) == FFS
+                               ? const1_rtx : const0_rtx,
+                               mode, mem_mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+  if (l1label == NULL)
+    return NULL;
+  add_loc_descr (&ret, l1label);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  l2label = new_loc_descr (DW_OP_dup, 0, 0);
+  add_loc_descr (&ret, l2label);
+  if (GET_CODE (rtl) != CLZ)
+    msb = const1_rtx;
+  else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+    msb = GEN_INT ((unsigned HOST_WIDE_INT) 1
+                  << (GET_MODE_BITSIZE (mode) - 1));
+  else
+    msb = immed_double_const (0, (unsigned HOST_WIDE_INT) 1
+                                 << (GET_MODE_BITSIZE (mode)
+                                     - HOST_BITS_PER_WIDE_INT - 1), mode);
+  if (GET_CODE (msb) == CONST_INT && INTVAL (msb) < 0)
+    tmp = new_loc_descr (HOST_BITS_PER_WIDE_INT == 32
+                        ? DW_OP_const4u : HOST_BITS_PER_WIDE_INT == 64
+                        ? DW_OP_const8u : DW_OP_constu, INTVAL (msb), 0);
+  else
+    tmp = mem_loc_descriptor (msb, mode, mem_mode,
+                             VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_and, 0, 0));
+  l3jump = new_loc_descr (DW_OP_bra, 0, 0);
+  add_loc_descr (&ret, l3jump);
+  tmp = mem_loc_descriptor (const1_rtx, mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (GET_CODE (rtl) == CLZ
+                                     ? DW_OP_shl : DW_OP_shr, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst, 1, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  l2jump = new_loc_descr (DW_OP_skip, 0, 0);
+  add_loc_descr (&ret, l2jump);
+  l3label = new_loc_descr (DW_OP_drop, 0, 0);
+  add_loc_descr (&ret, l3label);
+  l4label = new_loc_descr (DW_OP_nop, 0, 0);
+  add_loc_descr (&ret, l4label);
+  l1jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+  l1jump->dw_loc_oprnd1.v.val_loc = l1label;
+  l2jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+  l2jump->dw_loc_oprnd1.v.val_loc = l2label;
+  l3jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+  l3jump->dw_loc_oprnd1.v.val_loc = l3label;
+  l4jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+  l4jump->dw_loc_oprnd1.v.val_loc = l4label;
+  return ret;
 }
 
-/* Given a pointer to an arbitrary ..._TYPE tree node, return nonzero if the
-   given input type is a Dwarf "fundamental" type.  Otherwise return null.  */
+/* POPCOUNT (const0 is DW_OP_lit0 or corresponding typed constant,
+   const1 is DW_OP_lit1 or corresponding typed constant):
+       const0 DW_OP_swap
+   L1: DW_OP_dup DW_OP_bra <L2> DW_OP_dup DW_OP_rot const1 DW_OP_and
+       DW_OP_plus DW_OP_swap const1 DW_OP_shr DW_OP_skip <L1>
+   L2: DW_OP_drop
 
-static inline int
-is_base_type (tree type)
+   PARITY is similar:
+   L1: DW_OP_dup DW_OP_bra <L2> DW_OP_dup DW_OP_rot const1 DW_OP_and
+       DW_OP_xor DW_OP_swap const1 DW_OP_shr DW_OP_skip <L1>
+   L2: DW_OP_drop  */
+
+static dw_loc_descr_ref
+popcount_loc_descriptor (rtx rtl, enum machine_mode mode,
+                        enum machine_mode mem_mode)
 {
-  switch (TREE_CODE (type))
-    {
-    case ERROR_MARK:
-    case VOID_TYPE:
-    case INTEGER_TYPE:
-    case REAL_TYPE:
-    case FIXED_POINT_TYPE:
-    case COMPLEX_TYPE:
-    case BOOLEAN_TYPE:
-      return 1;
+  dw_loc_descr_ref op0, ret, tmp;
+  dw_loc_descr_ref l1jump, l1label;
+  dw_loc_descr_ref l2jump, l2label;
 
-    case ARRAY_TYPE:
-    case RECORD_TYPE:
-    case UNION_TYPE:
-    case QUAL_UNION_TYPE:
-    case ENUMERAL_TYPE:
-    case FUNCTION_TYPE:
-    case METHOD_TYPE:
-    case POINTER_TYPE:
-    case REFERENCE_TYPE:
-    case OFFSET_TYPE:
-    case LANG_TYPE:
-    case VECTOR_TYPE:
-      return 0;
+  if (GET_MODE_CLASS (mode) != MODE_INT
+      || GET_MODE (XEXP (rtl, 0)) != mode)
+    return NULL;
+
+  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  if (op0 == NULL)
+    return NULL;
+  ret = op0;
+  tmp = mem_loc_descriptor (const0_rtx, mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  l1label = new_loc_descr (DW_OP_dup, 0, 0);
+  add_loc_descr (&ret, l1label);
+  l2jump = new_loc_descr (DW_OP_bra, 0, 0);
+  add_loc_descr (&ret, l2jump);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_dup, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_rot, 0, 0));
+  tmp = mem_loc_descriptor (const1_rtx, mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_and, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (GET_CODE (rtl) == POPCOUNT
+                                     ? DW_OP_plus : DW_OP_xor, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  tmp = mem_loc_descriptor (const1_rtx, mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_shr, 0, 0));
+  l1jump = new_loc_descr (DW_OP_skip, 0, 0);
+  add_loc_descr (&ret, l1jump);
+  l2label = new_loc_descr (DW_OP_drop, 0, 0);
+  add_loc_descr (&ret, l2label);
+  l1jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+  l1jump->dw_loc_oprnd1.v.val_loc = l1label;
+  l2jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+  l2jump->dw_loc_oprnd1.v.val_loc = l2label;
+  return ret;
+}
+
+/* BSWAP (constS is initial shift count, either 56 or 24):
+       constS const0
+   L1: DW_OP_pick <2> constS DW_OP_pick <3> DW_OP_minus DW_OP_shr
+       const255 DW_OP_and DW_OP_pick <2> DW_OP_shl DW_OP_or
+       DW_OP_swap DW_OP_dup const0 DW_OP_eq DW_OP_bra <L2> const8
+       DW_OP_minus DW_OP_swap DW_OP_skip <L1>
+   L2: DW_OP_drop DW_OP_swap DW_OP_drop  */
+
+static dw_loc_descr_ref
+bswap_loc_descriptor (rtx rtl, enum machine_mode mode,
+                     enum machine_mode mem_mode)
+{
+  dw_loc_descr_ref op0, ret, tmp;
+  dw_loc_descr_ref l1jump, l1label;
+  dw_loc_descr_ref l2jump, l2label;
+
+  if (GET_MODE_CLASS (mode) != MODE_INT
+      || BITS_PER_UNIT != 8
+      || (GET_MODE_BITSIZE (mode) != 32
+         &&  GET_MODE_BITSIZE (mode) != 64))
+    return NULL;
+
+  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  if (op0 == NULL)
+    return NULL;
+
+  ret = op0;
+  tmp = mem_loc_descriptor (GEN_INT (GET_MODE_BITSIZE (mode) - 8),
+                           mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  tmp = mem_loc_descriptor (const0_rtx, mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  l1label = new_loc_descr (DW_OP_pick, 2, 0);
+  add_loc_descr (&ret, l1label);
+  tmp = mem_loc_descriptor (GEN_INT (GET_MODE_BITSIZE (mode) - 8),
+                           mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_pick, 3, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_minus, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_shr, 0, 0));
+  tmp = mem_loc_descriptor (GEN_INT (255), mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_and, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_pick, 2, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_shl, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_or, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_dup, 0, 0));
+  tmp = mem_loc_descriptor (const0_rtx, mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_eq, 0, 0));
+  l2jump = new_loc_descr (DW_OP_bra, 0, 0);
+  add_loc_descr (&ret, l2jump);
+  tmp = mem_loc_descriptor (GEN_INT (8), mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_minus, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  l1jump = new_loc_descr (DW_OP_skip, 0, 0);
+  add_loc_descr (&ret, l1jump);
+  l2label = new_loc_descr (DW_OP_drop, 0, 0);
+  add_loc_descr (&ret, l2label);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_drop, 0, 0));
+  l1jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+  l1jump->dw_loc_oprnd1.v.val_loc = l1label;
+  l2jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+  l2jump->dw_loc_oprnd1.v.val_loc = l2label;
+  return ret;
+}
+
+/* ROTATE (constMASK is mode mask, BITSIZE is bitsize of mode):
+   DW_OP_over DW_OP_over DW_OP_shl [ constMASK DW_OP_and ] DW_OP_rot
+   [ DW_OP_swap constMASK DW_OP_and DW_OP_swap ] DW_OP_neg
+   DW_OP_plus_uconst <BITSIZE> DW_OP_shr DW_OP_or
+
+   ROTATERT is similar:
+   DW_OP_over DW_OP_over DW_OP_neg DW_OP_plus_uconst <BITSIZE>
+   DW_OP_shl [ constMASK DW_OP_and ] DW_OP_rot
+   [ DW_OP_swap constMASK DW_OP_and DW_OP_swap ] DW_OP_shr DW_OP_or  */
+
+static dw_loc_descr_ref
+rotate_loc_descriptor (rtx rtl, enum machine_mode mode,
+                      enum machine_mode mem_mode)
+{
+  rtx rtlop1 = XEXP (rtl, 1);
+  dw_loc_descr_ref op0, op1, ret, mask[2] = { NULL, NULL };
+  int i;
 
-    default:
-      gcc_unreachable ();
-    }
+  if (GET_MODE_CLASS (mode) != MODE_INT)
+    return NULL;
 
-  return 0;
+  if (GET_MODE (rtlop1) != VOIDmode
+      && GET_MODE_BITSIZE (GET_MODE (rtlop1)) < GET_MODE_BITSIZE (mode))
+    rtlop1 = gen_rtx_ZERO_EXTEND (mode, rtlop1);
+  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  op1 = mem_loc_descriptor (rtlop1, mode, mem_mode,
+                           VAR_INIT_STATUS_INITIALIZED);
+  if (op0 == NULL || op1 == NULL)
+    return NULL;
+  if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
+    for (i = 0; i < 2; i++)
+      {
+       if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_WIDE_INT)
+         mask[i] = mem_loc_descriptor (GEN_INT (GET_MODE_MASK (mode)),
+                                       mode, mem_mode,
+                                       VAR_INIT_STATUS_INITIALIZED);
+       else if (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT)
+         mask[i] = new_loc_descr (HOST_BITS_PER_WIDE_INT == 32
+                                  ? DW_OP_const4u
+                                  : HOST_BITS_PER_WIDE_INT == 64
+                                  ? DW_OP_const8u : DW_OP_constu,
+                                  GET_MODE_MASK (mode), 0);
+       else
+         mask[i] = NULL;
+       if (mask[i] == NULL)
+         return NULL;
+       add_loc_descr (&mask[i], new_loc_descr (DW_OP_and, 0, 0));
+      }
+  ret = op0;
+  add_loc_descr (&ret, op1);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_over, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_over, 0, 0));
+  if (GET_CODE (rtl) == ROTATERT)
+    {
+      add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0));
+      add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst,
+                                         GET_MODE_BITSIZE (mode), 0));
+    }
+  add_loc_descr (&ret, new_loc_descr (DW_OP_shl, 0, 0));
+  if (mask[0] != NULL)
+    add_loc_descr (&ret, mask[0]);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_rot, 0, 0));
+  if (mask[1] != NULL)
+    {
+      add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+      add_loc_descr (&ret, mask[1]);
+      add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+    }
+  if (GET_CODE (rtl) == ROTATE)
+    {
+      add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0));
+      add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst,
+                                         GET_MODE_BITSIZE (mode), 0));
+    }
+  add_loc_descr (&ret, new_loc_descr (DW_OP_shr, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_or, 0, 0));
+  return ret;
 }
 
-/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
-   node, return the size in bits for the type if it is a constant, or else
-   return the alignment for the type if the type's size is not constant, or
-   else return BITS_PER_WORD if the type actually turns out to be an
-   ERROR_MARK node.  */
+/* Helper function for mem_loc_descriptor.  Return DW_OP_GNU_parameter_ref
+   for DEBUG_PARAMETER_REF RTL.  */
 
-static inline unsigned HOST_WIDE_INT
-simple_type_size_in_bits (const_tree type)
+static dw_loc_descr_ref
+parameter_ref_descriptor (rtx rtl)
 {
-  if (TREE_CODE (type) == ERROR_MARK)
-    return BITS_PER_WORD;
-  else if (TYPE_SIZE (type) == NULL_TREE)
-    return 0;
-  else if (host_integerp (TYPE_SIZE (type), 1))
-    return tree_low_cst (TYPE_SIZE (type), 1);
+  dw_loc_descr_ref ret;
+  dw_die_ref ref;
+
+  if (dwarf_strict)
+    return NULL;
+  gcc_assert (TREE_CODE (DEBUG_PARAMETER_REF_DECL (rtl)) == PARM_DECL);
+  ref = lookup_decl_die (DEBUG_PARAMETER_REF_DECL (rtl));
+  ret = new_loc_descr (DW_OP_GNU_parameter_ref, 0, 0);
+  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
-    return TYPE_ALIGN (type);
+    {
+      ret->dw_loc_oprnd1.val_class = dw_val_class_decl_ref;
+      ret->dw_loc_oprnd1.v.val_decl_ref = DEBUG_PARAMETER_REF_DECL (rtl);
+    }
+  return ret;
 }
 
-/*  Given a pointer to a tree node for a subrange type, return a pointer
-    to a DIE that describes the given type.  */
+/* Helper function to get mode of MEM's address.  */
 
-static dw_die_ref
-subrange_type_die (tree type, tree low, tree high, dw_die_ref context_die)
+enum machine_mode
+get_address_mode (rtx mem)
 {
-  dw_die_ref subrange_die;
-  const HOST_WIDE_INT size_in_bytes = int_size_in_bytes (type);
-
-  if (context_die == NULL)
-    context_die = comp_unit_die;
+  enum machine_mode mode = GET_MODE (XEXP (mem, 0));
+  if (mode != VOIDmode)
+    return mode;
+  return targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem));
+}
 
-  subrange_die = new_die (DW_TAG_subrange_type, context_die, type);
+/* The following routine converts the RTL for a variable or parameter
+   (resident in memory) into an equivalent Dwarf representation of a
+   mechanism for getting the address of that same variable onto the top of a
+   hypothetical "address evaluation" stack.
 
-  if (int_size_in_bytes (TREE_TYPE (type)) != size_in_bytes)
-    {
-      /* The size of the subrange type and its base type do not match,
-        so we need to generate a size attribute for the subrange type.  */
-      add_AT_unsigned (subrange_die, DW_AT_byte_size, size_in_bytes);
-    }
+   When creating memory location descriptors, we are effectively transforming
+   the RTL for a memory-resident object into its Dwarf postfix expression
+   equivalent.  This routine recursively descends an RTL tree, turning
+   it into Dwarf postfix code as it goes.
 
-  if (low)
-    add_bound_info (subrange_die, DW_AT_lower_bound, low);
-  if (high)
-    add_bound_info (subrange_die, DW_AT_upper_bound, high);
+   MODE is the mode that should be assumed for the rtl if it is VOIDmode.
 
-  return subrange_die;
-}
+   MEM_MODE is the mode of the memory reference, needed to handle some
+   autoincrement addressing modes.
 
-/* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
-   entry that chains various modifiers in front of the given type.  */
+   Return 0 if we can't represent the location.  */
 
-static dw_die_ref
-modified_type_die (tree type, int is_const_type, int is_volatile_type,
-                  dw_die_ref context_die)
+dw_loc_descr_ref
+mem_loc_descriptor (rtx rtl, enum machine_mode mode,
+                   enum machine_mode mem_mode,
+                   enum var_init_status initialized)
 {
-  enum tree_code code = TREE_CODE (type);
-  dw_die_ref mod_type_die;
-  dw_die_ref sub_die = NULL;
-  tree item_type = NULL;
-  tree qualified_type;
-  tree name, low, high;
-
-  if (code == ERROR_MARK)
-    return NULL;
+  dw_loc_descr_ref mem_loc_result = NULL;
+  enum dwarf_location_atom op;
+  dw_loc_descr_ref op0, op1;
 
-  /* See if we already have the appropriately qualified variant of
-     this type.  */
-  qualified_type
-    = get_qualified_type (type,
-                         ((is_const_type ? TYPE_QUAL_CONST : 0)
-                          | (is_volatile_type ? TYPE_QUAL_VOLATILE : 0)));
+  if (mode == VOIDmode)
+    mode = GET_MODE (rtl);
 
-  if (qualified_type == sizetype
-      && TYPE_NAME (qualified_type)
-      && TREE_CODE (TYPE_NAME (qualified_type)) == TYPE_DECL)
-    {
-#ifdef ENABLE_CHECKING
-      gcc_assert (TREE_CODE (TREE_TYPE (TYPE_NAME (qualified_type)))
-                 == INTEGER_TYPE
-                 && TYPE_PRECISION (TREE_TYPE (TYPE_NAME (qualified_type)))
-                    == TYPE_PRECISION (qualified_type)
-                 && TYPE_UNSIGNED (TREE_TYPE (TYPE_NAME (qualified_type)))
-                    == TYPE_UNSIGNED (qualified_type));
-#endif
-      qualified_type = TREE_TYPE (TYPE_NAME (qualified_type));
-    }
+  /* Note that for a dynamically sized array, the location we will generate a
+     description of here will be the lowest numbered location which is
+     actually within the array.  That's *not* necessarily the same as the
+     zeroth element of the array.  */
 
-  /* If we do, then we can just use its DIE, if it exists.  */
-  if (qualified_type)
-    {
-      mod_type_die = lookup_type_die (qualified_type);
-      if (mod_type_die)
-       return mod_type_die;
-    }
+  rtl = targetm.delegitimize_address (rtl);
 
-  name = qualified_type ? TYPE_NAME (qualified_type) : NULL;
+  if (mode != GET_MODE (rtl) && GET_MODE (rtl) != VOIDmode)
+    return NULL;
 
-  /* Handle C typedef types.  */
-  if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name)
-      && !DECL_ARTIFICIAL (name))
+  switch (GET_CODE (rtl))
     {
-      tree dtype = TREE_TYPE (name);
+    case POST_INC:
+    case POST_DEC:
+    case POST_MODIFY:
+      return mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, initialized);
 
-      if (qualified_type == dtype)
+    case SUBREG:
+      /* The case of a subreg may arise when we have a local (register)
+        variable or a formal (register) parameter which doesn't quite fill
+        up an entire register.  For now, just assume that it is
+        legitimate to make the Dwarf info refer to the whole register which
+        contains the given subreg.  */
+      if (!subreg_lowpart_p (rtl))
+       break;
+      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)
        {
-         /* For a named type, use the typedef.  */
-         gen_type_die (qualified_type, context_die);
-         return lookup_type_die (qualified_type);
+         mem_loc_result = mem_loc_descriptor (SUBREG_REG (rtl),
+                                              GET_MODE (SUBREG_REG (rtl)),
+                                              mem_mode, initialized);
+         break;
        }
-      else if (is_const_type < TYPE_READONLY (dtype)
-              || is_volatile_type < TYPE_VOLATILE (dtype)
-              || (is_const_type <= TYPE_READONLY (dtype)
-                  && is_volatile_type <= TYPE_VOLATILE (dtype)
-                  && DECL_ORIGINAL_TYPE (name) != type))
-       /* cv-unqualified version of named type.  Just use the unnamed
-          type to which it refers.  */
-       return modified_type_die (DECL_ORIGINAL_TYPE (name),
-                                 is_const_type, is_volatile_type,
-                                 context_die);
-      /* Else cv-qualified version of named type; fall through.  */
-    }
-
-  if (is_const_type)
-    {
-      mod_type_die = new_die (DW_TAG_const_type, comp_unit_die, type);
-      sub_die = modified_type_die (type, 0, is_volatile_type, context_die);
-    }
-  else if (is_volatile_type)
-    {
-      mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die, type);
-      sub_die = modified_type_die (type, 0, 0, context_die);
-    }
-  else if (code == POINTER_TYPE)
-    {
-      mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die, type);
-      add_AT_unsigned (mod_type_die, DW_AT_byte_size,
-                      simple_type_size_in_bits (type) / BITS_PER_UNIT);
-      item_type = TREE_TYPE (type);
-      if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type)))
-       add_AT_unsigned (mod_type_die, DW_AT_address_class,
-                        TYPE_ADDR_SPACE (item_type));
-    }
-  else if (code == REFERENCE_TYPE)
-    {
-      if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4)
-       mod_type_die = new_die (DW_TAG_rvalue_reference_type, comp_unit_die,
-                               type);
+      if (dwarf_strict)
+       break;
+      if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (rtl))))
+       break;
+      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;
       else
-       mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die, type);
-      add_AT_unsigned (mod_type_die, DW_AT_byte_size,
-                      simple_type_size_in_bits (type) / BITS_PER_UNIT);
-      item_type = TREE_TYPE (type);
-      if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type)))
-       add_AT_unsigned (mod_type_die, DW_AT_address_class,
-                        TYPE_ADDR_SPACE (item_type));
-    }
-  else if (code == INTEGER_TYPE
-          && TREE_TYPE (type) != NULL_TREE
-          && subrange_type_for_debug_p (type, &low, &high))
-    {
-      mod_type_die = subrange_type_die (type, low, high, context_die);
-      item_type = TREE_TYPE (type);
-    }
-  else if (is_base_type (type))
-    mod_type_die = base_type_die (type);
-  else
-    {
-      gen_type_die (type, context_die);
+       {
+         dw_die_ref type_die;
+         dw_loc_descr_ref cvt;
 
-      /* We have to get the type_main_variant here (and pass that to the
-        `lookup_type_die' routine) because the ..._TYPE node we have
-        might simply be a *copy* of some original type node (where the
-        copy was created to help us keep track of typedef names) and
-        that copy might have a different TYPE_UID from the original
-        ..._TYPE node.  */
-      if (TREE_CODE (type) != VECTOR_TYPE)
-       return lookup_type_die (type_main_variant (type));
-      else
-       /* Vectors have the debugging information in the type,
-          not the main variant.  */
-       return lookup_type_die (type);
-    }
+         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,
+                                        GET_MODE_CLASS (mode) == MODE_INT);
+         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;
 
-  /* Builtin types don't have a DECL_ORIGINAL_TYPE.  For those,
-     don't output a DW_TAG_typedef, since there isn't one in the
-     user's program; just attach a DW_AT_name to the type.
-     Don't attach a DW_AT_name to DW_TAG_const_type or DW_TAG_volatile_type
-     if the base type already has the same name.  */
-  if (name
-      && ((TREE_CODE (name) != TYPE_DECL
-          && (qualified_type == TYPE_MAIN_VARIANT (type)
-              || (!is_const_type && !is_volatile_type)))
-         || (TREE_CODE (name) == TYPE_DECL
-             && TREE_TYPE (name) == qualified_type
-             && DECL_NAME (name))))
-    {
-      if (TREE_CODE (name) == TYPE_DECL)
-       /* Could just call add_name_and_src_coords_attributes here,
-          but since this is a builtin type it doesn't have any
-          useful source coordinates anyway.  */
-       name = DECL_NAME (name);
-      add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
-    }
-  /* This probably indicates a bug.  */
-  else if (mod_type_die && mod_type_die->die_tag == DW_TAG_base_type)
-    add_name_attribute (mod_type_die, "__unknown__");
+    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,
+                                        GET_MODE_CLASS (mode) == MODE_INT);
+         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
+        a "base register".  This distinction is not based in any way upon
+        what category of register the hardware believes the given register
+        belongs to.  This is strictly DWARF terminology we're dealing with
+        here. Note that in cases where the location of a memory-resident
+        data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
+        OP_CONST (0)) the actual DWARF location descriptor that we generate
+        may just be OP_BASEREG (basereg).  This may look deceptively like
+        the object in question was allocated to a register (rather than in
+        memory) so DWARF consumers need to be aware of the subtle
+        distinction between OP_REG and OP_BASEREG.  */
+      if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
+       mem_loc_result = based_loc_descr (rtl, 0, VAR_INIT_STATUS_INITIALIZED);
+      else if (stack_realign_drap
+              && crtl->drap_reg
+              && crtl->args.internal_arg_pointer == rtl
+              && REGNO (crtl->drap_reg) < FIRST_PSEUDO_REGISTER)
+       {
+         /* If RTL is internal_arg_pointer, which has been optimized
+            out, use DRAP instead.  */
+         mem_loc_result = based_loc_descr (crtl->drap_reg, 0,
+                                           VAR_INIT_STATUS_INITIALIZED);
+       }
+      break;
 
-  if (qualified_type)
-    equate_type_number_to_die (qualified_type, mod_type_die);
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
+      if (GET_MODE_CLASS (mode) != MODE_INT)
+       break;
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (XEXP (rtl, 0)),
+                               mem_mode, VAR_INIT_STATUS_INITIALIZED);
+      if (op0 == 0)
+       break;
+      else if (GET_CODE (rtl) == ZERO_EXTEND
+              && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE
+              && GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0)))
+                 < HOST_BITS_PER_WIDE_INT
+              /* If DW_OP_const{1,2,4}u won't be used, it is shorter
+                 to expand zero extend as two shifts instead of
+                 masking.  */
+              && GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) <= 4)
+       {
+         enum machine_mode imode = GET_MODE (XEXP (rtl, 0));
+         mem_loc_result = op0;
+         add_loc_descr (&mem_loc_result,
+                        int_loc_descriptor (GET_MODE_MASK (imode)));
+         add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_and, 0, 0));
+       }
+      else if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE)
+       {
+         int shift = DWARF2_ADDR_SIZE
+                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+         shift *= BITS_PER_UNIT;
+         if (GET_CODE (rtl) == SIGN_EXTEND)
+           op = DW_OP_shra;
+         else
+           op = DW_OP_shr;
+         mem_loc_result = op0;
+         add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
+         add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
+         add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
+         add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+       }
+      else if (!dwarf_strict)
+       {
+         dw_die_ref type_die1, type_die2;
+         dw_loc_descr_ref cvt;
 
-  if (item_type)
-    /* We must do this after the equate_type_number_to_die call, in case
-       this is a recursive type.  This ensures that the modified_type_die
-       recursion will terminate even if the type is recursive.  Recursive
-       types are possible in Ada.  */
-    sub_die = modified_type_die (item_type,
-                                TYPE_READONLY (item_type),
-                                TYPE_VOLATILE (item_type),
-                                context_die);
+         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, 1);
+         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;
 
-  if (sub_die != NULL)
-    add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
+    case MEM:
+      {
+       rtx new_rtl = avoid_constant_pool_reference (rtl);
+       if (new_rtl != rtl)
+         {
+           mem_loc_result = mem_loc_descriptor (new_rtl, mode, mem_mode,
+                                                initialized);
+           if (mem_loc_result != NULL)
+             return mem_loc_result;
+         }
+      }
+      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 != NULL)
+       {
+         if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE
+             || GET_MODE_CLASS (mode) != MODE_INT)
+           {
+             dw_die_ref type_die;
+             dw_loc_descr_ref deref;
+
+             if (dwarf_strict)
+               return NULL;
+             type_die
+               = base_type_for_mode (mode, GET_MODE_CLASS (mode) == MODE_INT);
+             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 (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 (mode), 0));
+       }
+      break;
 
-  return mod_type_die;
-}
+    case LO_SUM:
+      return mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, initialized);
 
-/* Generate DIEs for the generic parameters of T.
-   T must be either a generic type or a generic function.
-   See http://gcc.gnu.org/wiki/TemplateParmsDwarf for more.  */
+    case LABEL_REF:
+      /* Some ports can transform a symbol ref into a label ref, because
+        the symbol ref is too far away and has to be dumped into a constant
+        pool.  */
+    case CONST:
+    case SYMBOL_REF:
+      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)
+       {
+         dw_loc_descr_ref temp;
 
-static void
-gen_generic_params_dies (tree t)
-{
-  tree parms, args;
-  int parms_num, i;
-  dw_die_ref die = NULL;
+         /* If this is not defined, we have no way to emit the data.  */
+         if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
+           break;
 
-  if (!t || (TYPE_P (t) && !COMPLETE_TYPE_P (t)))
-    return;
+         /* We used to emit DW_OP_addr here, but that's wrong, since
+            DW_OP_addr should be relocated by the debug info consumer,
+            while DW_OP_GNU_push_tls_address operand should not.  */
+         temp = new_loc_descr (DWARF2_ADDR_SIZE == 4
+                               ? DW_OP_const4u : DW_OP_const8u, 0, 0);
+         temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
+         temp->dw_loc_oprnd1.v.val_addr = rtl;
+         temp->dtprel = true;
 
-  if (TYPE_P (t))
-    die = lookup_type_die (t);
-  else if (DECL_P (t))
-    die = lookup_decl_die (t);
+         mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
+         add_loc_descr (&mem_loc_result, temp);
 
-  gcc_assert (die);
+         break;
+       }
 
-  parms = lang_hooks.get_innermost_generic_parms (t);
-  if (!parms)
-    /* T has no generic parameter. It means T is neither a generic type
-       or function. End of story.  */
-    return;
+      if (!const_ok_for_output (rtl))
+       break;
 
-  parms_num = TREE_VEC_LENGTH (parms);
-  args = lang_hooks.get_innermost_generic_args (t);
-  for (i = 0; i < parms_num; i++)
-    {
-      tree parm, arg, arg_pack_elems;
+    symref:
+      mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
+      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
+      mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+      break;
 
-      parm = TREE_VEC_ELT (parms, i);
-      arg = TREE_VEC_ELT (args, i);
-      arg_pack_elems = lang_hooks.types.get_argument_pack_elems (arg);
-      gcc_assert (parm && TREE_VALUE (parm) && arg);
+    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;
 
-      if (parm && TREE_VALUE (parm) && arg)
+    case ENTRY_VALUE:
+      if (dwarf_strict)
+       return NULL;
+      if (REG_P (ENTRY_VALUE_EXP (rtl)))
        {
-         /* If PARM represents a template parameter pack,
-            emit a DW_TAG_GNU_template_parameter_pack DIE, followed
-            by DW_TAG_template_*_parameter DIEs for the argument
-            pack elements of ARG. Note that ARG would then be
-            an argument pack.  */
-         if (arg_pack_elems)
-           template_parameter_pack_die (TREE_VALUE (parm),
-                                        arg_pack_elems,
-                                        die);
+         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
-           generic_parameter_die (TREE_VALUE (parm), arg,
-                                  true /* Emit DW_AT_name */, die);
+           op0
+             = one_reg_loc_descriptor (dbx_reg_number (ENTRY_VALUE_EXP (rtl)),
+                                       VAR_INIT_STATUS_INITIALIZED);
        }
-    }
-}
-
-/* Create and return a DIE for PARM which should be
-   the representation of a generic type parameter.
-   For instance, in the C++ front end, PARM would be a template parameter.
-   ARG is the argument to PARM.
-   EMIT_NAME_P if tree, the DIE will have DW_AT_name attribute set to the
-   name of the PARM.
-   PARENT_DIE is the parent DIE which the new created DIE should be added to,
-   as a child node.  */
+      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;
+      break;
 
-static dw_die_ref
-generic_parameter_die (tree parm, tree arg,
-                      bool emit_name_p,
-                      dw_die_ref parent_die)
-{
-  dw_die_ref tmpl_die = NULL;
-  const char *name = NULL;
+    case DEBUG_PARAMETER_REF:
+      mem_loc_result = parameter_ref_descriptor (rtl);
+      break;
 
-  if (!parm || !DECL_NAME (parm) || !arg)
-    return NULL;
+    case PRE_MODIFY:
+      /* Extract the PLUS expression nested inside and fall into
+        PLUS code below.  */
+      rtl = XEXP (rtl, 1);
+      goto plus;
 
-  /* We support non-type generic parameters and arguments,
-     type generic parameters and arguments, as well as
-     generic generic parameters (a.k.a. template template parameters in C++)
-     and arguments.  */
-  if (TREE_CODE (parm) == PARM_DECL)
-    /* PARM is a nontype generic parameter  */
-    tmpl_die = new_die (DW_TAG_template_value_param, parent_die, parm);
-  else if (TREE_CODE (parm) == TYPE_DECL)
-    /* PARM is a type generic parameter.  */
-    tmpl_die = new_die (DW_TAG_template_type_param, parent_die, parm);
-  else if (lang_hooks.decls.generic_generic_parameter_decl_p (parm))
-    /* PARM is a generic generic parameter.
-       Its DIE is a GNU extension. It shall have a
-       DW_AT_name attribute to represent the name of the template template
-       parameter, and a DW_AT_GNU_template_name attribute to represent the
-       name of the template template argument.  */
-    tmpl_die = new_die (DW_TAG_GNU_template_template_param,
-                       parent_die, parm);
-  else
-    gcc_unreachable ();
+    case PRE_INC:
+    case PRE_DEC:
+      /* Turn these into a PLUS expression and fall into the PLUS code
+        below.  */
+      rtl = gen_rtx_PLUS (mode, XEXP (rtl, 0),
+                         GEN_INT (GET_CODE (rtl) == PRE_INC
+                                  ? GET_MODE_UNIT_SIZE (mem_mode)
+                                  : -GET_MODE_UNIT_SIZE (mem_mode)));
 
-  if (tmpl_die)
-    {
-      tree tmpl_type;
+      /* ... fall through ...  */
 
-      /* If PARM is a generic parameter pack, it means we are
-         emitting debug info for a template argument pack element.
-        In other terms, ARG is a template argument pack element.
-        In that case, we don't emit any DW_AT_name attribute for
-        the die.  */
-      if (emit_name_p)
+    case PLUS:
+    plus:
+      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
        {
-         name = IDENTIFIER_POINTER (DECL_NAME (parm));
-         gcc_assert (name);
-         add_AT_string (tmpl_die, DW_AT_name, name);
-       }
+         mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+                                              VAR_INIT_STATUS_INITIALIZED);
+         if (mem_loc_result == 0)
+           break;
 
-      if (!lang_hooks.decls.generic_generic_parameter_decl_p (parm))
-       {
-         /* DWARF3, 5.6.8 says if PARM is a non-type generic parameter
-            TMPL_DIE should have a child DW_AT_type attribute that is set
-            to the type of the argument to PARM, which is ARG.
-            If PARM is a type generic parameter, TMPL_DIE should have a
-            child DW_AT_type that is set to ARG.  */
-         tmpl_type = TYPE_P (arg) ? arg : TREE_TYPE (arg);
-         add_type_attribute (tmpl_die, tmpl_type, 0,
-                             TREE_THIS_VOLATILE (tmpl_type),
-                             parent_die);
+         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
+           {
+             op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
+                                       VAR_INIT_STATUS_INITIALIZED);
+             if (op1 == 0)
+               break;
+             add_loc_descr (&mem_loc_result, op1);
+             add_loc_descr (&mem_loc_result,
+                            new_loc_descr (DW_OP_plus, 0, 0));
+           }
        }
-      else
-       {
-         /* So TMPL_DIE is a DIE representing a
-            a generic generic template parameter, a.k.a template template
-            parameter in C++ and arg is a template.  */
+      break;
 
-         /* The DW_AT_GNU_template_name attribute of the DIE must be set
-            to the name of the argument.  */
-         name = dwarf2_name (TYPE_P (arg) ? TYPE_NAME (arg) : arg, 1);
-         if (name)
-           add_AT_string (tmpl_die, DW_AT_GNU_template_name, name);
+    /* If a pseudo-reg is optimized away, it is possible for it to
+       be replaced with a MEM containing a multiply or shift.  */
+    case MINUS:
+      op = DW_OP_minus;
+      goto do_binop;
+
+    case MULT:
+      op = DW_OP_mul;
+      goto do_binop;
+
+    case DIV:
+      if (!dwarf_strict
+         && GET_MODE_CLASS (mode) == MODE_INT
+         && GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE)
+       {
+         mem_loc_result = typed_binop (DW_OP_div, rtl,
+                                       base_type_for_mode (mode, 0),
+                                       mode, mem_mode);
+         break;
        }
+      op = DW_OP_div;
+      goto do_binop;
 
-      if (TREE_CODE (parm) == PARM_DECL)
-       /* So PARM is a non-type generic parameter.
-          DWARF3 5.6.8 says we must set a DW_AT_const_value child
-          attribute of TMPL_DIE which value represents the value
-          of ARG.
-          We must be careful here:
-          The value of ARG might reference some function decls.
-          We might currently be emitting debug info for a generic
-          type and types are emitted before function decls, we don't
-          know if the function decls referenced by ARG will actually be
-          emitted after cgraph computations.
-          So must defer the generation of the DW_AT_const_value to
-          after cgraph is ready.  */
-       append_entry_to_tmpl_value_parm_die_table (tmpl_die, arg);
-    }
+    case UMOD:
+      op = DW_OP_mod;
+      goto do_binop;
 
-  return tmpl_die;
-}
+    case ASHIFT:
+      op = DW_OP_shl;
+      goto do_shift;
 
-/* Generate and return a  DW_TAG_GNU_template_parameter_pack DIE representing.
-   PARM_PACK must be a template parameter pack. The returned DIE
-   will be child DIE of PARENT_DIE.  */
+    case ASHIFTRT:
+      op = DW_OP_shra;
+      goto do_shift;
 
-static dw_die_ref
-template_parameter_pack_die (tree parm_pack,
-                            tree parm_pack_args,
-                            dw_die_ref parent_die)
-{
-  dw_die_ref die;
-  int j;
+    case LSHIFTRT:
+      op = DW_OP_shr;
+      goto do_shift;
 
-  gcc_assert (parent_die && parm_pack);
+    do_shift:
+      if (GET_MODE_CLASS (mode) != MODE_INT)
+       break;
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      {
+       rtx rtlop1 = XEXP (rtl, 1);
+       if (GET_MODE (rtlop1) != VOIDmode
+           && GET_MODE_BITSIZE (GET_MODE (rtlop1))
+              < GET_MODE_BITSIZE (mode))
+         rtlop1 = gen_rtx_ZERO_EXTEND (mode, rtlop1);
+       op1 = mem_loc_descriptor (rtlop1, mode, mem_mode,
+                                 VAR_INIT_STATUS_INITIALIZED);
+      }
 
-  die = new_die (DW_TAG_GNU_template_parameter_pack, parent_die, parm_pack);
-  add_name_and_src_coords_attributes (die, parm_pack);
-  for (j = 0; j < TREE_VEC_LENGTH (parm_pack_args); j++)
-    generic_parameter_die (parm_pack,
-                          TREE_VEC_ELT (parm_pack_args, j),
-                          false /* Don't emit DW_AT_name */,
-                          die);
-  return die;
-}
+      if (op0 == 0 || op1 == 0)
+       break;
 
-/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
-   an enumerated type.  */
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      break;
 
-static inline int
-type_is_enum (const_tree type)
-{
-  return TREE_CODE (type) == ENUMERAL_TYPE;
-}
+    case AND:
+      op = DW_OP_and;
+      goto do_binop;
 
-/* Return the DBX register number described by a given RTL node.  */
+    case IOR:
+      op = DW_OP_or;
+      goto do_binop;
 
-static unsigned int
-dbx_reg_number (const_rtx rtl)
-{
-  unsigned regno = REGNO (rtl);
+    case XOR:
+      op = DW_OP_xor;
+      goto do_binop;
 
-  gcc_assert (regno < FIRST_PSEUDO_REGISTER);
+    do_binop:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-#ifdef LEAF_REG_REMAP
-  if (current_function_uses_only_leaf_regs)
-    {
-      int leaf_reg = LEAF_REG_REMAP (regno);
-      if (leaf_reg != -1)
-       regno = (unsigned) leaf_reg;
-    }
-#endif
+      if (op0 == 0 || op1 == 0)
+       break;
 
-  return DBX_REGISTER_NUMBER (regno);
-}
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      break;
 
-/* Optionally add a DW_OP_piece term to a location description expression.
-   DW_OP_piece is only added if the location description expression already
-   doesn't end with DW_OP_piece.  */
+    case MOD:
+      if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE && !dwarf_strict)
+       {
+         mem_loc_result = typed_binop (DW_OP_mod, rtl,
+                                       base_type_for_mode (mode, 0),
+                                       mode, mem_mode);
+         break;
+       }
 
-static void
-add_loc_descr_op_piece (dw_loc_descr_ref *list_head, int size)
-{
-  dw_loc_descr_ref loc;
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-  if (*list_head != NULL)
-    {
-      /* Find the end of the chain.  */
-      for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
-       ;
+      if (op0 == 0 || op1 == 0)
+       break;
 
-      if (loc->dw_loc_opc != DW_OP_piece)
-       loc->dw_loc_next = new_loc_descr (DW_OP_piece, size, 0);
-    }
-}
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_over, 0, 0));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_over, 0, 0));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_div, 0, 0));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_minus, 0, 0));
+      break;
 
-/* Return a location descriptor that designates a machine register or
-   zero if there is none.  */
+    case UDIV:
+      if (!dwarf_strict && GET_MODE_CLASS (mode) == MODE_INT)
+       {
+         if (GET_MODE_CLASS (mode) > DWARF2_ADDR_SIZE)
+           {
+             op = DW_OP_div;
+             goto do_binop;
+           }
+         mem_loc_result = typed_binop (DW_OP_div, rtl,
+                                       base_type_for_mode (mode, 1),
+                                       mode, mem_mode);
+       }
+      break;
 
-static dw_loc_descr_ref
-reg_loc_descriptor (rtx rtl, enum var_init_status initialized)
-{
-  rtx regs;
+    case NOT:
+      op = DW_OP_not;
+      goto do_unop;
 
-  if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
-    return 0;
+    case ABS:
+      op = DW_OP_abs;
+      goto do_unop;
 
-  regs = targetm.dwarf_register_span (rtl);
+    case NEG:
+      op = DW_OP_neg;
+      goto do_unop;
 
-  if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
-    return multiple_reg_loc_descriptor (rtl, regs, initialized);
-  else
-    return one_reg_loc_descriptor (dbx_reg_number (rtl), initialized);
-}
+    do_unop:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-/* Return a location descriptor that designates a machine register for
-   a given hard register number.  */
+      if (op0 == 0)
+       break;
 
-static dw_loc_descr_ref
-one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized)
-{
-  dw_loc_descr_ref reg_loc_descr;
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      break;
 
-  if (regno <= 31)
-    reg_loc_descr
-      = new_loc_descr ((enum dwarf_location_atom) (DW_OP_reg0 + regno), 0, 0);
-  else
-    reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0);
+    case CONST_INT:
+      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, 1);
+         enum machine_mode amode;
+         if (type_die == NULL)
+           return NULL;
+         amode = mode_for_size (DWARF2_ADDR_SIZE * BITS_PER_UNIT,
+                                MODE_INT, 0);
+         if (INTVAL (rtl) >= 0
+             && amode != BLKmode
+             && trunc_int_for_mode (INTVAL (rtl), amode) == INTVAL (rtl)
+             /* const DW_OP_GNU_convert <XXX> vs.
+                DW_OP_GNU_const_type <XXX, 1, const>.  */
+             && size_of_int_loc_descriptor (INTVAL (rtl)) + 1 + 1
+                < (unsigned long) 1 + 1 + 1 + GET_MODE_SIZE (mode))
+           {
+             mem_loc_result = int_loc_descriptor (INTVAL (rtl));
+             op0 = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+             op0->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+             op0->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+             op0->dw_loc_oprnd1.v.val_die_ref.external = 0;
+             add_loc_descr (&mem_loc_result, op0);
+             return mem_loc_result;
+           }
+         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;
 
-  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&reg_loc_descr, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+    case CONST_DOUBLE:
+      if (!dwarf_strict)
+       {
+         dw_die_ref type_die;
 
-  return reg_loc_descr;
-}
+         /* 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,
+                                        GET_MODE_CLASS (mode) == MODE_INT);
+         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);
 
-/* Given an RTL of a register, return a location descriptor that
-   designates a value that spans more than one register.  */
+             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;
 
-static dw_loc_descr_ref
-multiple_reg_loc_descriptor (rtx rtl, rtx regs,
-                            enum var_init_status initialized)
-{
-  int nregs, size, i;
-  unsigned reg;
-  dw_loc_descr_ref loc_result = NULL;
+    case EQ:
+      mem_loc_result = scompare_loc_descriptor (DW_OP_eq, rtl, mem_mode);
+      break;
 
-  reg = REGNO (rtl);
-#ifdef LEAF_REG_REMAP
-  if (current_function_uses_only_leaf_regs)
-    {
-      int leaf_reg = LEAF_REG_REMAP (reg);
-      if (leaf_reg != -1)
-       reg = (unsigned) leaf_reg;
-    }
-#endif
-  gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
-  nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
+    case GE:
+      mem_loc_result = scompare_loc_descriptor (DW_OP_ge, rtl, mem_mode);
+      break;
 
-  /* Simple, contiguous registers.  */
-  if (regs == NULL_RTX)
-    {
-      size = GET_MODE_SIZE (GET_MODE (rtl)) / nregs;
+    case GT:
+      mem_loc_result = scompare_loc_descriptor (DW_OP_gt, rtl, mem_mode);
+      break;
 
-      loc_result = NULL;
-      while (nregs--)
-       {
-         dw_loc_descr_ref t;
+    case LE:
+      mem_loc_result = scompare_loc_descriptor (DW_OP_le, rtl, mem_mode);
+      break;
 
-         t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg),
-                                     VAR_INIT_STATUS_INITIALIZED);
-         add_loc_descr (&loc_result, t);
-         add_loc_descr_op_piece (&loc_result, size);
-         ++reg;
-       }
-      return loc_result;
-    }
+    case LT:
+      mem_loc_result = scompare_loc_descriptor (DW_OP_lt, rtl, mem_mode);
+      break;
 
-  /* Now onto stupid register sets in non contiguous locations.  */
+    case NE:
+      mem_loc_result = scompare_loc_descriptor (DW_OP_ne, rtl, mem_mode);
+      break;
 
-  gcc_assert (GET_CODE (regs) == PARALLEL);
+    case GEU:
+      mem_loc_result = ucompare_loc_descriptor (DW_OP_ge, rtl, mem_mode);
+      break;
 
-  size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
-  loc_result = NULL;
+    case GTU:
+      mem_loc_result = ucompare_loc_descriptor (DW_OP_gt, rtl, mem_mode);
+      break;
 
-  for (i = 0; i < XVECLEN (regs, 0); ++i)
-    {
-      dw_loc_descr_ref t;
+    case LEU:
+      mem_loc_result = ucompare_loc_descriptor (DW_OP_le, rtl, mem_mode);
+      break;
 
-      t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)),
-                                 VAR_INIT_STATUS_INITIALIZED);
-      add_loc_descr (&loc_result, t);
-      size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
-      add_loc_descr_op_piece (&loc_result, size);
-    }
+    case LTU:
+      mem_loc_result = ucompare_loc_descriptor (DW_OP_lt, rtl, mem_mode);
+      break;
 
-  if (loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
-  return loc_result;
-}
+    case UMIN:
+    case UMAX:
+      if (GET_MODE_CLASS (mode) != MODE_INT)
+       break;
+      /* FALLTHRU */
+    case SMIN:
+    case SMAX:
+      mem_loc_result = minmax_loc_descriptor (rtl, mode, mem_mode);
+      break;
 
-#endif /* DWARF2_DEBUGGING_INFO */
+    case ZERO_EXTRACT:
+    case SIGN_EXTRACT:
+      if (CONST_INT_P (XEXP (rtl, 1))
+         && CONST_INT_P (XEXP (rtl, 2))
+         && ((unsigned) INTVAL (XEXP (rtl, 1))
+             + (unsigned) INTVAL (XEXP (rtl, 2))
+             <= GET_MODE_BITSIZE (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), GET_MODE (XEXP (rtl, 0)),
+                                   mem_mode, VAR_INIT_STATUS_INITIALIZED);
+         if (op0 == 0)
+           break;
+         if (GET_CODE (rtl) == SIGN_EXTRACT)
+           op = DW_OP_shra;
+         else
+           op = DW_OP_shr;
+         mem_loc_result = op0;
+         size = INTVAL (XEXP (rtl, 1));
+         shift = INTVAL (XEXP (rtl, 2));
+         if (BITS_BIG_ENDIAN)
+           shift = GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0)))
+                   - shift - size;
+         if (shift + size != (int) DWARF2_ADDR_SIZE)
+           {
+             add_loc_descr (&mem_loc_result,
+                            int_loc_descriptor (DWARF2_ADDR_SIZE
+                                                - shift - size));
+             add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
+           }
+         if (size != (int) DWARF2_ADDR_SIZE)
+           {
+             add_loc_descr (&mem_loc_result,
+                            int_loc_descriptor (DWARF2_ADDR_SIZE - size));
+             add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+           }
+       }
+      break;
 
-#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+    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;
 
-/* Return a location descriptor that designates a constant.  */
+       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;
 
-static dw_loc_descr_ref
-int_loc_descriptor (HOST_WIDE_INT i)
-{
-  enum dwarf_location_atom op;
+    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;
 
-  /* Pick the smallest representation of a constant, rather than just
-     defaulting to the LEB encoding.  */
-  if (i >= 0)
-    {
-      if (i <= 31)
-       op = (enum dwarf_location_atom) (DW_OP_lit0 + i);
-      else if (i <= 0xff)
-       op = DW_OP_const1u;
-      else if (i <= 0xffff)
-       op = DW_OP_const2u;
-      else if (HOST_BITS_PER_WIDE_INT == 32
-              || i <= 0xffffffff)
-       op = DW_OP_const4u;
-      else
-       op = DW_OP_constu;
-    }
-  else
-    {
-      if (i >= -0x80)
-       op = DW_OP_const1s;
-      else if (i >= -0x8000)
-       op = DW_OP_const2s;
-      else if (HOST_BITS_PER_WIDE_INT == 32
-              || i >= -0x80000000)
-       op = DW_OP_const4s;
-      else
-       op = DW_OP_consts;
-    }
+         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) == 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) == FIX
+                 || GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE))
+           {
+             op0 = convert_descriptor_to_mode (mode, op0);
+             if (op0 == NULL)
+               break;
+           }
+         mem_loc_result = op0;
+       }
+      break;
 
-  return new_loc_descr (op, i, 0);
-}
-#endif
+    case CLZ:
+    case CTZ:
+    case FFS:
+      mem_loc_result = clz_loc_descriptor (rtl, mode, mem_mode);
+      break;
 
-#ifdef DWARF2_DEBUGGING_INFO
-/* Return loc description representing "address" of integer value.
-   This can appear only as toplevel expression.  */
+    case POPCOUNT:
+    case PARITY:
+      mem_loc_result = popcount_loc_descriptor (rtl, mode, mem_mode);
+      break;
 
-static dw_loc_descr_ref
-address_of_int_loc_descriptor (int size, HOST_WIDE_INT i)
-{
-  int litsize;
-  dw_loc_descr_ref loc_result = NULL;
+    case BSWAP:
+      mem_loc_result = bswap_loc_descriptor (rtl, mode, mem_mode);
+      break;
 
-  if (!(dwarf_version >= 4 || !dwarf_strict))
-    return NULL;
+    case ROTATE:
+    case ROTATERT:
+      mem_loc_result = rotate_loc_descriptor (rtl, mode, mem_mode);
+      break;
 
-  if (i >= 0)
-    {
-      if (i <= 31)
-       litsize = 1;
-      else if (i <= 0xff)
-       litsize = 2;
-      else if (i <= 0xffff)
-       litsize = 3;
-      else if (HOST_BITS_PER_WIDE_INT == 32
-              || i <= 0xffffffff)
-       litsize = 5;
-      else
-       litsize = 1 + size_of_uleb128 ((unsigned HOST_WIDE_INT) i);
-    }
-  else
-    {
-      if (i >= -0x80)
-       litsize = 2;
-      else if (i >= -0x8000)
-       litsize = 3;
-      else if (HOST_BITS_PER_WIDE_INT == 32
-              || i >= -0x80000000)
-       litsize = 5;
-      else
-       litsize = 1 + size_of_sleb128 (i);
-    }
-  /* Determine if DW_OP_stack_value or DW_OP_implicit_value
-     is more compact.  For DW_OP_stack_value we need:
-     litsize + 1 (DW_OP_stack_value)
-     and for DW_OP_implicit_value:
-     1 (DW_OP_implicit_value) + 1 (length) + size.  */
-  if ((int) DWARF2_ADDR_SIZE >= size && litsize + 1 <= 1 + 1 + size)
-    {
-      loc_result = int_loc_descriptor (i);
-      add_loc_descr (&loc_result,
-                    new_loc_descr (DW_OP_stack_value, 0, 0));
-      return loc_result;
+    case COMPARE:
+    case TRUNCATE:
+      /* In theory, we could implement the above.  */
+      /* DWARF cannot represent the unsigned compare operations
+        natively.  */
+    case SS_MULT:
+    case US_MULT:
+    case SS_DIV:
+    case US_DIV:
+    case SS_PLUS:
+    case US_PLUS:
+    case SS_MINUS:
+    case US_MINUS:
+    case SS_NEG:
+    case US_NEG:
+    case SS_ABS:
+    case SS_ASHIFT:
+    case US_ASHIFT:
+    case SS_TRUNCATE:
+    case US_TRUNCATE:
+    case UNORDERED:
+    case ORDERED:
+    case UNEQ:
+    case UNGE:
+    case UNGT:
+    case UNLE:
+    case UNLT:
+    case LTGT:
+    case FRACT_CONVERT:
+    case UNSIGNED_FRACT_CONVERT:
+    case SAT_FRACT:
+    case UNSIGNED_SAT_FRACT:
+    case SQRT:
+    case ASM_OPERANDS:
+    case VEC_MERGE:
+    case VEC_SELECT:
+    case VEC_CONCAT:
+    case VEC_DUPLICATE:
+    case UNSPEC:
+    case HIGH:
+    case FMA:
+    case STRICT_LOW_PART:
+    case CONST_VECTOR:
+    case CONST_FIXED:
+    case CLRSB:
+      /* If delegitimize_address couldn't do anything with the UNSPEC, we
+        can't express it in the debug info.  This can happen e.g. with some
+        TLS UNSPECs.  */
+      break;
+
+    case CONST_STRING:
+      resolve_one_addr (&rtl, NULL);
+      goto symref;
+
+    default:
+#ifdef ENABLE_CHECKING
+      print_rtl (stderr, rtl);
+      gcc_unreachable ();
+#else
+      break;
+#endif
     }
 
-  loc_result = new_loc_descr (DW_OP_implicit_value,
-                             size, 0);
-  loc_result->dw_loc_oprnd2.val_class = dw_val_class_const;
-  loc_result->dw_loc_oprnd2.v.val_int = i;
-  return loc_result;
+  if (mem_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
+  return mem_loc_result;
 }
 
-/* Return a location descriptor that designates a base+offset location.  */
+/* Return a descriptor that describes the concatenation of two locations.
+   This is typically a complex variable.  */
 
 static dw_loc_descr_ref
-based_loc_descr (rtx reg, HOST_WIDE_INT offset,
-                enum var_init_status initialized)
+concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
 {
-  unsigned int regno;
-  dw_loc_descr_ref result;
-  dw_fde_ref fde = current_fde ();
-
-  /* We only use "frame base" when we're sure we're talking about the
-     post-prologue local stack frame.  We do this by *not* running
-     register elimination until this point, and recognizing the special
-     argument pointer and soft frame pointer rtx's.  */
-  if (reg == arg_pointer_rtx || reg == frame_pointer_rtx)
-    {
-      rtx elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
-
-      if (elim != reg)
-       {
-         if (GET_CODE (elim) == PLUS)
-           {
-             offset += INTVAL (XEXP (elim, 1));
-             elim = XEXP (elim, 0);
-           }
-         gcc_assert ((SUPPORTS_STACK_ALIGNMENT
-                      && (elim == hard_frame_pointer_rtx
-                          || elim == stack_pointer_rtx))
-                     || elim == (frame_pointer_needed
-                                 ? hard_frame_pointer_rtx
-                                 : stack_pointer_rtx));
+  dw_loc_descr_ref cc_loc_result = NULL;
+  dw_loc_descr_ref x0_ref
+    = loc_descriptor (x0, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+  dw_loc_descr_ref x1_ref
+    = loc_descriptor (x1, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
 
-         /* If drap register is used to align stack, use frame
-            pointer + offset to access stack variables.  If stack
-            is aligned without drap, use stack pointer + offset to
-            access stack variables.  */
-         if (crtl->stack_realign_tried
-             && reg == frame_pointer_rtx)
-           {
-             int base_reg
-               = DWARF_FRAME_REGNUM ((fde && fde->drap_reg != INVALID_REGNUM)
-                                     ? HARD_FRAME_POINTER_REGNUM
-                                     : STACK_POINTER_REGNUM);
-             return new_reg_loc_descr (base_reg, offset);
-           }
+  if (x0_ref == 0 || x1_ref == 0)
+    return 0;
 
-         offset += frame_pointer_fb_offset;
-         return new_loc_descr (DW_OP_fbreg, offset, 0);
-       }
-    }
-  else if (!optimize
-          && fde
-          && (fde->drap_reg == REGNO (reg)
-              || fde->vdrap_reg == REGNO (reg)))
-    {
-      /* Use cfa+offset to represent the location of arguments passed
-        on the stack when drap is used to align stack.
-        Only do this when not optimizing, for optimized code var-tracking
-        is supposed to track where the arguments live and the register
-        used as vdrap or drap in some spot might be used for something
-        else in other part of the routine.  */
-      return new_loc_descr (DW_OP_fbreg, offset, 0);
-    }
+  cc_loc_result = x0_ref;
+  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x0)));
 
-  regno = dbx_reg_number (reg);
-  if (regno <= 31)
-    result = new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + regno),
-                           offset, 0);
-  else
-    result = new_loc_descr (DW_OP_bregx, regno, offset);
+  add_loc_descr (&cc_loc_result, x1_ref);
+  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1)));
 
   if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
-
-  return result;
-}
-
-/* Return true if this RTL expression describes a base+offset calculation.  */
+    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
 
-static inline int
-is_based_loc (const_rtx rtl)
-{
-  return (GET_CODE (rtl) == PLUS
-         && ((REG_P (XEXP (rtl, 0))
-              && REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
-              && CONST_INT_P (XEXP (rtl, 1)))));
+  return cc_loc_result;
 }
 
-/* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0)
-   failed.  */
+/* Return a descriptor that describes the concatenation of N
+   locations.  */
 
 static dw_loc_descr_ref
-tls_mem_loc_descriptor (rtx mem)
+concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
 {
-  tree base;
-  dw_loc_descr_ref loc_result;
+  unsigned int i;
+  dw_loc_descr_ref cc_loc_result = NULL;
+  unsigned int n = XVECLEN (concatn, 0);
 
-  if (MEM_EXPR (mem) == NULL_TREE || MEM_OFFSET (mem) == NULL_RTX)
-    return NULL;
+  for (i = 0; i < n; ++i)
+    {
+      dw_loc_descr_ref ref;
+      rtx x = XVECEXP (concatn, 0, i);
 
-  base = get_base_address (MEM_EXPR (mem));
-  if (base == NULL
-      || TREE_CODE (base) != VAR_DECL
-      || !DECL_THREAD_LOCAL_P (base))
-    return NULL;
+      ref = loc_descriptor (x, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+      if (ref == NULL)
+       return NULL;
 
-  loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1);
-  if (loc_result == NULL)
-    return NULL;
+      add_loc_descr (&cc_loc_result, ref);
+      add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
+    }
 
-  if (INTVAL (MEM_OFFSET (mem)))
-    loc_descr_plus_const (&loc_result, INTVAL (MEM_OFFSET (mem)));
+  if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
 
-  return loc_result;
+  return cc_loc_result;
 }
 
-/* Output debug info about reason why we failed to expand expression as dwarf
-   expression.  */
+/* Helper function for loc_descriptor.  Return DW_OP_GNU_implicit_pointer
+   for DEBUG_IMPLICIT_PTR RTL.  */
 
-static void
-expansion_failed (tree expr, rtx rtl, char const *reason)
+static dw_loc_descr_ref
+implicit_ptr_descriptor (rtx rtl, HOST_WIDE_INT offset)
 {
-  if (dump_file && (dump_flags & TDF_DETAILS))
+  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
     {
-      fprintf (dump_file, "Failed to expand as dwarf: ");
-      if (expr)
-       print_generic_expr (dump_file, expr, dump_flags);
-      if (rtl)
-       {
-         fprintf (dump_file, "\n");
-         print_rtl (dump_file, rtl);
-       }
-      fprintf (dump_file, "\nReason: %s\n", reason);
+      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;
 }
 
-/* Helper function for const_ok_for_output, called either directly
-   or via for_each_rtx.  */
+/* Output a proper Dwarf location descriptor for a variable or parameter
+   which is either allocated in a register or in a memory location.  For a
+   register, we just generate an OP_REG and the register number.  For a
+   memory location we provide a Dwarf postfix expression describing how to
+   generate the (dynamic) address of the object onto the address stack.
 
-static int
-const_ok_for_output_1 (rtx *rtlp, void *data ATTRIBUTE_UNUSED)
+   MODE is mode of the decl if this loc_descriptor is going to be used in
+   .debug_loc section where DW_OP_stack_value and DW_OP_implicit_value are
+   allowed, VOIDmode otherwise.
+
+   If we don't know how to describe it, return 0.  */
+
+static dw_loc_descr_ref
+loc_descriptor (rtx rtl, enum machine_mode mode,
+               enum var_init_status initialized)
 {
-  rtx rtl = *rtlp;
+  dw_loc_descr_ref loc_result = NULL;
 
-  if (GET_CODE (rtl) == UNSPEC)
+  switch (GET_CODE (rtl))
     {
-      /* If delegitimize_address couldn't do anything with the UNSPEC, assume
-        we can't express it in the debug info.  */
-#ifdef ENABLE_CHECKING
-      inform (current_function_decl
-             ? DECL_SOURCE_LOCATION (current_function_decl)
-             : UNKNOWN_LOCATION,
-             "non-delegitimized UNSPEC %d found in variable location",
-             XINT (rtl, 1));
-#endif
-      expansion_failed (NULL_TREE, rtl,
-                       "UNSPEC hasn't been delegitimized.\n");
-      return 1;
-    }
+    case SUBREG:
+      /* The case of a subreg may arise when we have a local (register)
+        variable or a formal (register) parameter which doesn't quite fill
+        up an entire register.  For now, just assume that it is
+        legitimate to make the Dwarf info refer to the whole register which
+        contains the given subreg.  */
+      if (REG_P (SUBREG_REG (rtl)) && subreg_lowpart_p (rtl))
+       loc_result = loc_descriptor (SUBREG_REG (rtl),
+                                    GET_MODE (SUBREG_REG (rtl)), initialized);
+      else
+       goto do_default;
+      break;
 
-  if (GET_CODE (rtl) != SYMBOL_REF)
-    return 0;
+    case REG:
+      loc_result = reg_loc_descriptor (rtl, initialized);
+      break;
 
-  if (CONSTANT_POOL_ADDRESS_P (rtl))
-    {
-      bool marked;
-      get_pool_constant_mark (rtl, &marked);
-      /* If all references to this pool constant were optimized away,
-        it was not output and thus we can't represent it.  */
-      if (!marked)
+    case MEM:
+      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)
        {
-         expansion_failed (NULL_TREE, rtl,
-                           "Constant was removed from constant pool.\n");
-         return 1;
+         rtx new_rtl = avoid_constant_pool_reference (rtl);
+         if (new_rtl != rtl)
+           loc_result = loc_descriptor (new_rtl, mode, initialized);
        }
-    }
+      break;
 
-  if (SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
-    return 1;
+    case CONCAT:
+      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1),
+                                         initialized);
+      break;
 
-  /* Avoid references to external symbols in debug info, on several targets
-     the linker might even refuse to link when linking a shared library,
-     and in many other cases the relocations for .debug_info/.debug_loc are
-     dropped, so the address becomes zero anyway.  Hidden symbols, guaranteed
-     to be defined within the same shared library or executable are fine.  */
-  if (SYMBOL_REF_EXTERNAL_P (rtl))
-    {
-      tree decl = SYMBOL_REF_DECL (rtl);
+    case CONCATN:
+      loc_result = concatn_loc_descriptor (rtl, initialized);
+      break;
 
-      if (decl == NULL || !targetm.binds_local_p (decl))
+    case VAR_LOCATION:
+      /* Single part.  */
+      if (GET_CODE (PAT_VAR_LOCATION_LOC (rtl)) != PARALLEL)
        {
-         expansion_failed (NULL_TREE, rtl,
-                           "Symbol not defined in current TU.\n");
-         return 1;
+         rtx loc = PAT_VAR_LOCATION_LOC (rtl);
+         if (GET_CODE (loc) == EXPR_LIST)
+           loc = XEXP (loc, 0);
+         loc_result = loc_descriptor (loc, mode, initialized);
+         break;
        }
-    }
 
-  return 0;
-}
+      rtl = XEXP (rtl, 1);
+      /* FALLTHRU */
 
-/* Return true if constant RTL can be emitted in DW_OP_addr or
-   DW_AT_const_value.  TLS SYMBOL_REFs, external SYMBOL_REFs or
-   non-marked constant pool SYMBOL_REFs can't be referenced in it.  */
+    case PARALLEL:
+      {
+       rtvec par_elems = XVEC (rtl, 0);
+       int num_elem = GET_NUM_ELEM (par_elems);
+       enum machine_mode mode;
+       int i;
 
-static bool
-const_ok_for_output (rtx rtl)
-{
-  if (GET_CODE (rtl) == SYMBOL_REF)
-    return const_ok_for_output_1 (&rtl, NULL) == 0;
+       /* Create the first one, so we have something to add to.  */
+       loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
+                                    VOIDmode, initialized);
+       if (loc_result == NULL)
+         return NULL;
+       mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
+       add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+       for (i = 1; i < num_elem; i++)
+         {
+           dw_loc_descr_ref temp;
 
-  if (GET_CODE (rtl) == CONST)
-    return for_each_rtx (&XEXP (rtl, 0), const_ok_for_output_1, NULL) == 0;
+           temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
+                                  VOIDmode, initialized);
+           if (temp == NULL)
+             return NULL;
+           add_loc_descr (&loc_result, temp);
+           mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
+           add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+         }
+      }
+      break;
 
-  return true;
-}
+    case CONST_INT:
+      if (mode != VOIDmode && mode != BLKmode)
+       loc_result = address_of_int_loc_descriptor (GET_MODE_SIZE (mode),
+                                                   INTVAL (rtl));
+      break;
 
-/* The following routine converts the RTL for a variable or parameter
-   (resident in memory) into an equivalent Dwarf representation of a
-   mechanism for getting the address of that same variable onto the top of a
-   hypothetical "address evaluation" stack.
+    case CONST_DOUBLE:
+      if (mode == VOIDmode)
+       mode = GET_MODE (rtl);
 
-   When creating memory location descriptors, we are effectively transforming
-   the RTL for a memory-resident object into its Dwarf postfix expression
-   equivalent.  This routine recursively descends an RTL tree, turning
-   it into Dwarf postfix code as it goes.
+      if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
+       {
+         gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
 
-   MODE is the mode of the memory reference, needed to handle some
-   autoincrement addressing modes.
+         /* Note that a CONST_DOUBLE rtx could represent either an integer
+            or a floating-point constant.  A CONST_DOUBLE is used whenever
+            the constant requires more than one word in order to be
+            adequately represented.  We output CONST_DOUBLEs as blocks.  */
+         loc_result = new_loc_descr (DW_OP_implicit_value,
+                                     GET_MODE_SIZE (mode), 0);
+         if (SCALAR_FLOAT_MODE_P (mode))
+           {
+             unsigned int length = GET_MODE_SIZE (mode);
+             unsigned char *array
+                  = (unsigned char*) ggc_alloc_atomic (length);
 
-   CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the
-   location list for RTL.
+             insert_float (rtl, array);
+             loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+             loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4;
+             loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
+             loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+           }
+         else
+           {
+             loc_result->dw_loc_oprnd2.val_class = dw_val_class_const_double;
+             loc_result->dw_loc_oprnd2.v.val_double
+               = rtx_to_double_int (rtl);
+           }
+       }
+      break;
 
-   Return 0 if we can't represent the location.  */
+    case CONST_VECTOR:
+      if (mode == VOIDmode)
+       mode = GET_MODE (rtl);
 
-static dw_loc_descr_ref
-mem_loc_descriptor (rtx rtl, enum machine_mode mode,
-                   enum var_init_status initialized)
-{
-  dw_loc_descr_ref mem_loc_result = NULL;
-  enum dwarf_location_atom op;
-  dw_loc_descr_ref op0, op1;
+      if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
+       {
+         unsigned int elt_size = GET_MODE_UNIT_SIZE (GET_MODE (rtl));
+         unsigned int length = CONST_VECTOR_NUNITS (rtl);
+         unsigned char *array = (unsigned char *)
+           ggc_alloc_atomic (length * elt_size);
+         unsigned int i;
+         unsigned char *p;
 
-  /* Note that for a dynamically sized array, the location we will generate a
-     description of here will be the lowest numbered location which is
-     actually within the array.  That's *not* necessarily the same as the
-     zeroth element of the array.  */
+         gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
+         switch (GET_MODE_CLASS (mode))
+           {
+           case MODE_VECTOR_INT:
+             for (i = 0, p = array; i < length; i++, p += elt_size)
+               {
+                 rtx elt = CONST_VECTOR_ELT (rtl, i);
+                 double_int val = rtx_to_double_int (elt);
 
-  rtl = targetm.delegitimize_address (rtl);
+                 if (elt_size <= sizeof (HOST_WIDE_INT))
+                   insert_int (double_int_to_shwi (val), elt_size, p);
+                 else
+                   {
+                     gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
+                     insert_double (val, p);
+                   }
+               }
+             break;
 
-  switch (GET_CODE (rtl))
-    {
-    case POST_INC:
-    case POST_DEC:
-    case POST_MODIFY:
-      return mem_loc_descriptor (XEXP (rtl, 0), mode, initialized);
+           case MODE_VECTOR_FLOAT:
+             for (i = 0, p = array; i < length; i++, p += elt_size)
+               {
+                 rtx elt = CONST_VECTOR_ELT (rtl, i);
+                 insert_float (elt, p);
+               }
+             break;
 
-    case SUBREG:
-      /* The case of a subreg may arise when we have a local (register)
-        variable or a formal (register) parameter which doesn't quite fill
-        up an entire register.  For now, just assume that it is
-        legitimate to make the Dwarf info refer to the whole register which
-        contains the given subreg.  */
-      if (!subreg_lowpart_p (rtl))
-       break;
-      rtl = SUBREG_REG (rtl);
-      if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE)
-       break;
-      if (GET_MODE_CLASS (GET_MODE (rtl)) != MODE_INT)
-       break;
-      mem_loc_result = mem_loc_descriptor (rtl, mode, initialized);
+           default:
+             gcc_unreachable ();
+           }
+
+         loc_result = new_loc_descr (DW_OP_implicit_value,
+                                     length * elt_size, 0);
+         loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+         loc_result->dw_loc_oprnd2.v.val_vec.length = length;
+         loc_result->dw_loc_oprnd2.v.val_vec.elt_size = elt_size;
+         loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+       }
       break;
 
-    case REG:
-      /* Whenever a register number forms a part of the description of the
-        method for calculating the (dynamic) address of a memory resident
-        object, DWARF rules require the register number be referred to as
-        a "base register".  This distinction is not based in any way upon
-        what category of register the hardware believes the given register
-        belongs to.  This is strictly DWARF terminology we're dealing with
-        here. Note that in cases where the location of a memory-resident
-        data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
-        OP_CONST (0)) the actual DWARF location descriptor that we generate
-        may just be OP_BASEREG (basereg).  This may look deceptively like
-        the object in question was allocated to a register (rather than in
-        memory) so DWARF consumers need to be aware of the subtle
-        distinction between OP_REG and OP_BASEREG.  */
-      if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
-       mem_loc_result = based_loc_descr (rtl, 0, VAR_INIT_STATUS_INITIALIZED);
-      else if (stack_realign_drap
-              && crtl->drap_reg
-              && crtl->args.internal_arg_pointer == rtl
-              && REGNO (crtl->drap_reg) < FIRST_PSEUDO_REGISTER)
+    case CONST:
+      if (mode == VOIDmode
+         || GET_CODE (XEXP (rtl, 0)) == CONST_INT
+         || GET_CODE (XEXP (rtl, 0)) == CONST_DOUBLE
+         || GET_CODE (XEXP (rtl, 0)) == CONST_VECTOR)
        {
-         /* If RTL is internal_arg_pointer, which has been optimized
-            out, use DRAP instead.  */
-         mem_loc_result = based_loc_descr (crtl->drap_reg, 0,
-                                           VAR_INIT_STATUS_INITIALIZED);
+         loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
+         break;
+       }
+      /* FALLTHROUGH */
+    case SYMBOL_REF:
+      if (!const_ok_for_output (rtl))
+       break;
+    case LABEL_REF:
+      if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
+         && (dwarf_version >= 4 || !dwarf_strict))
+       {
+         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
+         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
+         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+         add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
+         VEC_safe_push (rtx, gc, used_rtx_array, rtl);
        }
       break;
 
-    case SIGN_EXTEND:
-    case ZERO_EXTEND:
-      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
-      if (op0 == 0)
-       break;
-      else
+    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)))
        {
-         int shift = DWARF2_ADDR_SIZE
-                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
-         shift *= BITS_PER_UNIT;
-         if (GET_CODE (rtl) == SIGN_EXTEND)
-           op = DW_OP_shra;
-         else
-           op = DW_OP_shr;
-         mem_loc_result = op0;
-         add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
-         add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
-         add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
-         add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+         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 && mode != VOIDmode && mode != BLKmode))
+       {
+         /* Value expression.  */
+         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));
        }
       break;
+    }
+
+  return loc_result;
+}
+
+/* We need to figure out what section we should use as the base for the
+   address ranges where a given location is valid.
+   1. If this particular DECL has a section associated with it, use that.
+   2. If this function has a section associated with it, use that.
+   3. Otherwise, use the text section.
+   XXX: If you split a variable across multiple sections, we won't notice.  */
+
+static const char *
+secname_for_decl (const_tree decl)
+{
+  const char *secname;
+
+  if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl))
+    {
+      tree sectree = DECL_SECTION_NAME (decl);
+      secname = TREE_STRING_POINTER (sectree);
+    }
+  else if (current_function_decl && DECL_SECTION_NAME (current_function_decl))
+    {
+      tree sectree = DECL_SECTION_NAME (current_function_decl);
+      secname = TREE_STRING_POINTER (sectree);
+    }
+  else if (cfun && in_cold_section_p)
+    secname = crtl->subsections.cold_section_label;
+  else
+    secname = text_section_label;
+
+  return secname;
+}
+
+/* Return true when DECL_BY_REFERENCE is defined and set for DECL.  */
 
-    case MEM:
-      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
-                                          VAR_INIT_STATUS_INITIALIZED);
-      if (mem_loc_result == NULL)
-       mem_loc_result = tls_mem_loc_descriptor (rtl);
-      if (mem_loc_result != 0)
+static bool
+decl_by_reference_p (tree decl)
+{
+  return ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL
+          || TREE_CODE (decl) == VAR_DECL)
+         && DECL_BY_REFERENCE (decl));
+}
+
+/* Helper function for dw_loc_list.  Compute proper Dwarf location descriptor
+   for VARLOC.  */
+
+static dw_loc_descr_ref
+dw_loc_list_1 (tree loc, rtx varloc, int want_address,
+              enum var_init_status initialized)
+{
+  int have_address = 0;
+  dw_loc_descr_ref descr;
+  enum machine_mode mode;
+
+  if (want_address != 2)
+    {
+      gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
+      /* Single part.  */
+      if (GET_CODE (PAT_VAR_LOCATION_LOC (varloc)) != PARALLEL)
        {
-         if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE)
+         varloc = PAT_VAR_LOCATION_LOC (varloc);
+         if (GET_CODE (varloc) == EXPR_LIST)
+           varloc = XEXP (varloc, 0);
+         mode = GET_MODE (varloc);
+         if (MEM_P (varloc))
            {
-             expansion_failed (NULL_TREE, rtl, "DWARF address size mismatch");
-             return 0;
+             rtx addr = XEXP (varloc, 0);
+             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, VOIDmode,
+                                               initialized);
+               }
            }
-         else if (GET_MODE_SIZE (GET_MODE (rtl)) == DWARF2_ADDR_SIZE)
-           add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
          else
-           add_loc_descr (&mem_loc_result,
-                          new_loc_descr (DW_OP_deref_size,
-                                         GET_MODE_SIZE (GET_MODE (rtl)), 0));
+           descr = mem_loc_descriptor (varloc, mode, VOIDmode, initialized);
        }
       else
+       return 0;
+    }
+  else
+    {
+      if (GET_CODE (varloc) == VAR_LOCATION)
+       mode = DECL_MODE (PAT_VAR_LOCATION_DECL (varloc));
+      else
+       mode = DECL_MODE (loc);
+      descr = loc_descriptor (varloc, mode, initialized);
+      have_address = 1;
+    }
+
+  if (!descr)
+    return 0;
+
+  if (want_address == 2 && !have_address
+      && (dwarf_version >= 4 || !dwarf_strict))
+    {
+      if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE)
        {
-         rtx new_rtl = avoid_constant_pool_reference (rtl);
-         if (new_rtl != rtl)
-           return mem_loc_descriptor (new_rtl, mode, initialized);
+         expansion_failed (loc, NULL_RTX,
+                           "DWARF address size mismatch");
+         return 0;
        }
-      break;
-
-    case LO_SUM:
-        rtl = XEXP (rtl, 1);
+      add_loc_descr (&descr, new_loc_descr (DW_OP_stack_value, 0, 0));
+      have_address = 1;
+    }
+  /* Show if we can't fill the request for an address.  */
+  if (want_address && !have_address)
+    {
+      expansion_failed (loc, NULL_RTX,
+                       "Want address and only have value");
+      return 0;
+    }
 
-      /* ... fall through ...  */
+  /* If we've got an address and don't want one, dereference.  */
+  if (!want_address && have_address)
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
+      enum dwarf_location_atom op;
 
-    case LABEL_REF:
-      /* Some ports can transform a symbol ref into a label ref, because
-        the symbol ref is too far away and has to be dumped into a constant
-        pool.  */
-    case CONST:
-    case SYMBOL_REF:
-      if (GET_CODE (rtl) == SYMBOL_REF
-         && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
+      if (size > DWARF2_ADDR_SIZE || size == -1)
        {
-         dw_loc_descr_ref temp;
+         expansion_failed (loc, NULL_RTX,
+                           "DWARF address size mismatch");
+         return 0;
+       }
+      else if (size == DWARF2_ADDR_SIZE)
+       op = DW_OP_deref;
+      else
+       op = DW_OP_deref_size;
 
-         /* If this is not defined, we have no way to emit the data.  */
-         if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
-           break;
+      add_loc_descr (&descr, new_loc_descr (op, size, 0));
+    }
 
-         temp = new_loc_descr (DW_OP_addr, 0, 0);
-         temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
-         temp->dw_loc_oprnd1.v.val_addr = rtl;
-         temp->dtprel = true;
+  return descr;
+}
 
-         mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
-         add_loc_descr (&mem_loc_result, temp);
+/* Create a DW_OP_piece or DW_OP_bit_piece for bitsize, or return NULL
+   if it is not possible.  */
 
-         break;
-       }
+static dw_loc_descr_ref
+new_loc_descr_op_bit_piece (HOST_WIDE_INT bitsize, HOST_WIDE_INT offset)
+{
+  if ((bitsize % BITS_PER_UNIT) == 0 && offset == 0)
+    return new_loc_descr (DW_OP_piece, bitsize / BITS_PER_UNIT, 0);
+  else if (dwarf_version >= 3 || !dwarf_strict)
+    return new_loc_descr (DW_OP_bit_piece, bitsize, offset);
+  else
+    return NULL;
+}
 
-      if (!const_ok_for_output (rtl))
-       break;
+/* Helper function for dw_loc_list.  Compute proper Dwarf location descriptor
+   for VAR_LOC_NOTE for variable DECL that has been optimized by SRA.  */
 
-    symref:
-      mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
-      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
-      mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
-      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
-      break;
+static dw_loc_descr_ref
+dw_sra_loc_expr (tree decl, rtx loc)
+{
+  rtx p;
+  unsigned int padsize = 0;
+  dw_loc_descr_ref descr, *descr_tail;
+  unsigned HOST_WIDE_INT decl_size;
+  rtx varloc;
+  enum var_init_status initialized;
 
-    case CONCAT:
-    case CONCATN:
-    case VAR_LOCATION:
-      expansion_failed (NULL_TREE, rtl,
-                       "CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor");
-      return 0;
+  if (DECL_SIZE (decl) == NULL
+      || !host_integerp (DECL_SIZE (decl), 1))
+    return NULL;
 
-    case PRE_MODIFY:
-      /* Extract the PLUS expression nested inside and fall into
-        PLUS code below.  */
-      rtl = XEXP (rtl, 1);
-      goto plus;
+  decl_size = tree_low_cst (DECL_SIZE (decl), 1);
+  descr = NULL;
+  descr_tail = &descr;
 
-    case PRE_INC:
-    case PRE_DEC:
-      /* Turn these into a PLUS expression and fall into the PLUS code
-        below.  */
-      rtl = gen_rtx_PLUS (word_mode, XEXP (rtl, 0),
-                         GEN_INT (GET_CODE (rtl) == PRE_INC
-                                  ? GET_MODE_UNIT_SIZE (mode)
-                                  : -GET_MODE_UNIT_SIZE (mode)));
+  for (p = loc; p; p = XEXP (p, 1))
+    {
+      unsigned int bitsize = decl_piece_bitsize (p);
+      rtx loc_note = *decl_piece_varloc_ptr (p);
+      dw_loc_descr_ref cur_descr;
+      dw_loc_descr_ref *tail, last = NULL;
+      unsigned int opsize = 0;
 
-      /* ... fall through ...  */
+      if (loc_note == NULL_RTX
+         || NOTE_VAR_LOCATION_LOC (loc_note) == NULL_RTX)
+       {
+         padsize += bitsize;
+         continue;
+       }
+      initialized = NOTE_VAR_LOCATION_STATUS (loc_note);
+      varloc = NOTE_VAR_LOCATION (loc_note);
+      cur_descr = dw_loc_list_1 (decl, varloc, 2, initialized);
+      if (cur_descr == NULL)
+       {
+         padsize += bitsize;
+         continue;
+       }
 
-    case PLUS:
-    plus:
-      if (is_based_loc (rtl))
-       mem_loc_result = based_loc_descr (XEXP (rtl, 0),
-                                         INTVAL (XEXP (rtl, 1)),
-                                         VAR_INIT_STATUS_INITIALIZED);
-      else
+      /* Check that cur_descr either doesn't use
+        DW_OP_*piece operations, or their sum is equal
+        to bitsize.  Otherwise we can't embed it.  */
+      for (tail = &cur_descr; *tail != NULL;
+          tail = &(*tail)->dw_loc_next)
+       if ((*tail)->dw_loc_opc == DW_OP_piece)
+         {
+           opsize += (*tail)->dw_loc_oprnd1.v.val_unsigned
+                     * BITS_PER_UNIT;
+           last = *tail;
+         }
+       else if ((*tail)->dw_loc_opc == DW_OP_bit_piece)
+         {
+           opsize += (*tail)->dw_loc_oprnd1.v.val_unsigned;
+           last = *tail;
+         }
+
+      if (last != NULL && opsize != bitsize)
        {
-         mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                                              VAR_INIT_STATUS_INITIALIZED);
-         if (mem_loc_result == 0)
-           break;
+         padsize += bitsize;
+         continue;
+       }
 
-         if (CONST_INT_P (XEXP (rtl, 1)))
-           loc_descr_plus_const (&mem_loc_result, INTVAL (XEXP (rtl, 1)));
-         else
+      /* If there is a hole, add DW_OP_*piece after empty DWARF
+        expression, which means that those bits are optimized out.  */
+      if (padsize)
+       {
+         if (padsize > decl_size)
+           return NULL;
+         decl_size -= padsize;
+         *descr_tail = new_loc_descr_op_bit_piece (padsize, 0);
+         if (*descr_tail == NULL)
+           return NULL;
+         descr_tail = &(*descr_tail)->dw_loc_next;
+         padsize = 0;
+       }
+      *descr_tail = cur_descr;
+      descr_tail = tail;
+      if (bitsize > decl_size)
+       return NULL;
+      decl_size -= bitsize;
+      if (last == NULL)
+       {
+         HOST_WIDE_INT offset = 0;
+         if (GET_CODE (varloc) == VAR_LOCATION
+             && GET_CODE (PAT_VAR_LOCATION_LOC (varloc)) != PARALLEL)
+           {
+             varloc = PAT_VAR_LOCATION_LOC (varloc);
+             if (GET_CODE (varloc) == EXPR_LIST)
+               varloc = XEXP (varloc, 0);
+           }
+         do 
            {
-             dw_loc_descr_ref mem_loc_result2
-               = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                                     VAR_INIT_STATUS_INITIALIZED);
-             if (mem_loc_result2 == 0)
+             if (GET_CODE (varloc) == CONST
+                 || GET_CODE (varloc) == SIGN_EXTEND
+                 || GET_CODE (varloc) == ZERO_EXTEND)
+               varloc = XEXP (varloc, 0);
+             else if (GET_CODE (varloc) == SUBREG)
+               varloc = SUBREG_REG (varloc);
+             else
                break;
-             add_loc_descr (&mem_loc_result, mem_loc_result2);
-             add_loc_descr (&mem_loc_result,
-                            new_loc_descr (DW_OP_plus, 0, 0));
            }
-       }
-      break;
-
-    /* If a pseudo-reg is optimized away, it is possible for it to
-       be replaced with a MEM containing a multiply or shift.  */
-    case MINUS:
-      op = DW_OP_minus;
-      goto do_binop;
-
-    case MULT:
-      op = DW_OP_mul;
-      goto do_binop;
-
-    case DIV:
-      op = DW_OP_div;
-      goto do_binop;
-
-    case UMOD:
-      op = DW_OP_mod;
-      goto do_binop;
-
-    case ASHIFT:
-      op = DW_OP_shl;
-      goto do_binop;
-
-    case ASHIFTRT:
-      op = DW_OP_shra;
-      goto do_binop;
-
-    case LSHIFTRT:
-      op = DW_OP_shr;
-      goto do_binop;
-
-    case AND:
-      op = DW_OP_and;
-      goto do_binop;
-
-    case IOR:
-      op = DW_OP_or;
-      goto do_binop;
-
-    case XOR:
-      op = DW_OP_xor;
-      goto do_binop;
+         while (1);
+         /* DW_OP_bit_size offset should be zero for register
+            or implicit location descriptions and empty location
+            descriptions, but for memory addresses needs big endian
+            adjustment.  */
+         if (MEM_P (varloc))
+           {
+             unsigned HOST_WIDE_INT memsize
+               = MEM_SIZE (varloc) * BITS_PER_UNIT;
+             if (memsize != bitsize)
+               {
+                 if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
+                     && (memsize > BITS_PER_WORD || bitsize > BITS_PER_WORD))
+                   return NULL;
+                 if (memsize < bitsize)
+                   return NULL;
+                 if (BITS_BIG_ENDIAN)
+                   offset = memsize - bitsize;
+               }
+           }
 
-    do_binop:
-      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
-      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
+         *descr_tail = new_loc_descr_op_bit_piece (bitsize, offset);
+         if (*descr_tail == NULL)
+           return NULL;
+         descr_tail = &(*descr_tail)->dw_loc_next;
+       }
+    }
 
-      if (op0 == 0 || op1 == 0)
-       break;
+  /* If there were any non-empty expressions, add padding till the end of
+     the decl.  */
+  if (descr != NULL && decl_size != 0)
+    {
+      *descr_tail = new_loc_descr_op_bit_piece (decl_size, 0);
+      if (*descr_tail == NULL)
+       return NULL;
+    }
+  return descr;
+}
 
-      mem_loc_result = op0;
-      add_loc_descr (&mem_loc_result, op1);
-      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
-      break;
+/* Return the dwarf representation of the location list LOC_LIST of
+   DECL.  WANT_ADDRESS has the same meaning as in loc_list_from_tree
+   function.  */
 
-    case MOD:
-      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
-      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
+static dw_loc_list_ref
+dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
+{
+  const char *endname, *secname;
+  rtx varloc;
+  enum var_init_status initialized;
+  struct var_loc_node *node;
+  dw_loc_descr_ref descr;
+  char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
+  dw_loc_list_ref list = NULL;
+  dw_loc_list_ref *listp = &list;
 
-      if (op0 == 0 || op1 == 0)
-       break;
+  /* Now that we know what section we are using for a base,
+     actually construct the list of locations.
+     The first location information is what is passed to the
+     function that creates the location list, and the remaining
+     locations just get added on to that list.
+     Note that we only know the start address for a location
+     (IE location changes), so to build the range, we use
+     the range [current location start, next location start].
+     This means we have to special case the last node, and generate
+     a range of [last location start, end of function label].  */
 
-      mem_loc_result = op0;
-      add_loc_descr (&mem_loc_result, op1);
-      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_over, 0, 0));
-      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_over, 0, 0));
-      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_div, 0, 0));
-      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
-      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_minus, 0, 0));
-      break;
+  secname = secname_for_decl (decl);
 
-    case NOT:
-      op = DW_OP_not;
-      goto do_unop;
+  for (node = loc_list->first; node; node = node->next)
+    if (GET_CODE (node->loc) == EXPR_LIST
+       || NOTE_VAR_LOCATION_LOC (node->loc) != NULL_RTX)
+      {
+       if (GET_CODE (node->loc) == EXPR_LIST)
+         {
+           /* This requires DW_OP_{,bit_}piece, which is not usable
+              inside DWARF expressions.  */
+           if (want_address != 2)
+             continue;
+           descr = dw_sra_loc_expr (decl, node->loc);
+           if (descr == NULL)
+             continue;
+         }
+       else
+         {
+           initialized = NOTE_VAR_LOCATION_STATUS (node->loc);
+           varloc = NOTE_VAR_LOCATION (node->loc);
+           descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
+         }
+       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 = cfun->fde->dw_fde_end;
+               range_across_switch = true;
+             }
+           /* The variable has a location between NODE->LABEL and
+              NODE->NEXT->LABEL.  */
+           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.  */
+           else if (!current_function_decl)
+             endname = text_end_label;
+           else
+             {
+               ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+                                            current_function_funcdef_no);
+               endname = ggc_strdup (label_id);
+             }
 
-    case ABS:
-      op = DW_OP_abs;
-      goto do_unop;
+           *listp = new_loc_list (descr, node->label, endname, secname);
+           if (TREE_CODE (decl) == PARM_DECL
+               && node == loc_list->first
+               && GET_CODE (node->loc) == NOTE
+               && strcmp (node->label, endname) == 0)
+             (*listp)->force = true;
+           listp = &(*listp)->dw_loc_next;
 
-    case NEG:
-      op = DW_OP_neg;
-      goto do_unop;
+           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 = cfun->fde->dw_fde_second_end;
+               *listp = new_loc_list (descr,
+                                      cfun->fde->dw_fde_second_begin,
+                                      endname, secname);
+               listp = &(*listp)->dw_loc_next;
+             }
+         }
+      }
 
-    do_unop:
-      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
+  /* Try to avoid the overhead of a location list emitting a location
+     expression instead, but only if we didn't have more than one
+     location entry in the first place.  If some entries were not
+     representable, we don't want to pretend a single entry that was
+     applies to the entire scope in which the variable is
+     available.  */
+  if (list && loc_list->first->next)
+    gen_llsym (list);
 
-      if (op0 == 0)
-       break;
+  return list;
+}
 
-      mem_loc_result = op0;
-      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
-      break;
+/* Return if the loc_list has only single element and thus can be represented
+   as location description.   */
 
-    case CONST_INT:
-      mem_loc_result = int_loc_descriptor (INTVAL (rtl));
-      break;
+static bool
+single_element_loc_list_p (dw_loc_list_ref list)
+{
+  gcc_assert (!list->dw_loc_next || list->ll_symbol);
+  return !list->ll_symbol;
+}
 
-    case EQ:
-      op = DW_OP_eq;
-      goto do_scompare;
+/* To each location in list LIST add loc descr REF.  */
 
-    case GE:
-      op = DW_OP_ge;
-      goto do_scompare;
+static void
+add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref)
+{
+  dw_loc_descr_ref copy;
+  add_loc_descr (&list->expr, ref);
+  list = list->dw_loc_next;
+  while (list)
+    {
+      copy = ggc_alloc_dw_loc_descr_node ();
+      memcpy (copy, ref, sizeof (dw_loc_descr_node));
+      add_loc_descr (&list->expr, copy);
+      while (copy->dw_loc_next)
+       {
+         dw_loc_descr_ref new_copy = ggc_alloc_dw_loc_descr_node ();
+         memcpy (new_copy, copy->dw_loc_next, sizeof (dw_loc_descr_node));
+         copy->dw_loc_next = new_copy;
+         copy = new_copy;
+       }
+      list = list->dw_loc_next;
+    }
+}
 
-    case GT:
-      op = DW_OP_gt;
-      goto do_scompare;
+/* Given two lists RET and LIST
+   produce location list that is result of adding expression in LIST
+   to expression in RET on each possition in program.
+   Might be destructive on both RET and LIST.
 
-    case LE:
-      op = DW_OP_le;
-      goto do_scompare;
+   TODO: We handle only simple cases of RET or LIST having at most one
+   element. General case would inolve sorting the lists in program order
+   and merging them that will need some additional work.
+   Adding that will improve quality of debug info especially for SRA-ed
+   structures.  */
 
-    case LT:
-      op = DW_OP_lt;
-      goto do_scompare;
+static void
+add_loc_list (dw_loc_list_ref *ret, dw_loc_list_ref list)
+{
+  if (!list)
+    return;
+  if (!*ret)
+    {
+      *ret = list;
+      return;
+    }
+  if (!list->dw_loc_next)
+    {
+      add_loc_descr_to_each (*ret, list->expr);
+      return;
+    }
+  if (!(*ret)->dw_loc_next)
+    {
+      add_loc_descr_to_each (list, (*ret)->expr);
+      *ret = list;
+      return;
+    }
+  expansion_failed (NULL_TREE, NULL_RTX,
+                   "Don't know how to merge two non-trivial"
+                   " location lists.\n");
+  *ret = NULL;
+  return;
+}
 
-    case NE:
-      op = DW_OP_ne;
-      goto do_scompare;
+/* LOC is constant expression.  Try a luck, look it up in constant
+   pool and return its loc_descr of its address.  */
 
-    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));
+static dw_loc_descr_ref
+cst_pool_loc_descr (tree loc)
+{
+  /* Get an RTL for this, if something has been emitted.  */
+  rtx rtl = lookup_constant_def (loc);
 
-         if (op_mode == VOIDmode)
-           op_mode = GET_MODE (XEXP (rtl, 1));
-         if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT)
-           break;
+  if (!rtl || !MEM_P (rtl))
+    {
+      gcc_assert (!rtl);
+      return 0;
+    }
+  gcc_assert (GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF);
 
-         op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                                   VAR_INIT_STATUS_INITIALIZED);
-         op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                                   VAR_INIT_STATUS_INITIALIZED);
+  /* TODO: We might get more coverage if we was actually delaying expansion
+     of all expressions till end of compilation when constant pools are fully
+     populated.  */
+  if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (XEXP (rtl, 0))))
+    {
+      expansion_failed (loc, NULL_RTX,
+                       "CST value in contant pool but not marked.");
+      return 0;
+    }
+  return mem_loc_descriptor (XEXP (rtl, 0), get_address_mode (rtl),
+                            GET_MODE (rtl), VAR_INIT_STATUS_INITIALIZED);
+}
 
-         if (op0 == 0 || op1 == 0)
-           break;
+/* Return dw_loc_list representing address of addr_expr LOC
+   by looking for innder INDIRECT_REF expression and turing it
+   into simple arithmetics.  */
 
-         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));
-               }
-           }
-       }
+static dw_loc_list_ref
+loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev)
+{
+  tree obj, offset;
+  HOST_WIDE_INT bitsize, bitpos, bytepos;
+  enum machine_mode mode;
+  int volatilep;
+  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
+  dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
 
-    do_compare:
-      mem_loc_result = op0;
-      add_loc_descr (&mem_loc_result, op1);
-      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
-      if (STORE_FLAG_VALUE != 1)
+  obj = get_inner_reference (TREE_OPERAND (loc, 0),
+                            &bitsize, &bitpos, &offset, &mode,
+                            &unsignedp, &volatilep, false);
+  STRIP_NOPS (obj);
+  if (bitpos % BITS_PER_UNIT)
+    {
+      expansion_failed (loc, NULL_RTX, "bitfield access");
+      return 0;
+    }
+  if (!INDIRECT_REF_P (obj))
+    {
+      expansion_failed (obj,
+                       NULL_RTX, "no indirect ref in inner refrence");
+      return 0;
+    }
+  if (!offset && !bitpos)
+    list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1);
+  else if (toplev
+          && int_size_in_bytes (TREE_TYPE (loc)) <= DWARF2_ADDR_SIZE
+          && (dwarf_version >= 4 || !dwarf_strict))
+    {
+      list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0);
+      if (!list_ret)
+       return 0;
+      if (offset)
        {
-         add_loc_descr (&mem_loc_result,
-                        int_loc_descriptor (STORE_FLAG_VALUE));
-         add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
+         /* Variable offset.  */
+         list_ret1 = loc_list_from_tree (offset, 0);
+         if (list_ret1 == 0)
+           return 0;
+         add_loc_list (&list_ret, list_ret1);
+         if (!list_ret)
+           return 0;
+         add_loc_descr_to_each (list_ret,
+                                new_loc_descr (DW_OP_plus, 0, 0));
        }
-      break;
-
-    case GEU:
-      op = DW_OP_ge;
-      goto do_ucompare;
-
-    case GTU:
-      op = DW_OP_gt;
-      goto do_ucompare;
-
-    case LEU:
-      op = DW_OP_le;
-      goto do_ucompare;
-
-    case LTU:
-      op = DW_OP_lt;
-      goto do_ucompare;
+      bytepos = bitpos / BITS_PER_UNIT;
+      if (bytepos > 0)
+       add_loc_descr_to_each (list_ret,
+                              new_loc_descr (DW_OP_plus_uconst,
+                                             bytepos, 0));
+      else if (bytepos < 0)
+       loc_list_plus_const (list_ret, bytepos);
+      add_loc_descr_to_each (list_ret,
+                            new_loc_descr (DW_OP_stack_value, 0, 0));
+    }
+  return list_ret;
+}
 
-    do_ucompare:
-      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
-         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 1))) > DWARF2_ADDR_SIZE)
-       break;
-      else
-       {
-         enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
 
-         if (op_mode == VOIDmode)
-           op_mode = GET_MODE (XEXP (rtl, 1));
-         if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT)
-           break;
+/* Generate Dwarf location list representing LOC.
+   If WANT_ADDRESS is false, expression computing LOC will be computed
+   If WANT_ADDRESS is 1, expression computing address of LOC will be returned
+   if WANT_ADDRESS is 2, expression computing address useable in location
+     will be returned (i.e. DW_OP_reg can be used
+     to refer to register values).  */
 
-         op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                                   VAR_INIT_STATUS_INITIALIZED);
-         op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                                   VAR_INIT_STATUS_INITIALIZED);
+static dw_loc_list_ref
+loc_list_from_tree (tree loc, int want_address)
+{
+  dw_loc_descr_ref ret = NULL, ret1 = NULL;
+  dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
+  int have_address = 0;
+  enum dwarf_location_atom op;
 
-         if (op0 == 0 || op1 == 0)
-           break;
+  /* ??? Most of the time we do not take proper care for sign/zero
+     extending the values properly.  Hopefully this won't be a real
+     problem...  */
 
-         if (op_mode != VOIDmode
-             && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
-           {
-             HOST_WIDE_INT mask = GET_MODE_MASK (op_mode);
-             dw_loc_descr_ref last0, last1;
-             for (last0 = op0;
-                  last0->dw_loc_next != NULL;
-                  last0 = last0->dw_loc_next)
-               ;
-             for (last1 = op1;
-                  last1->dw_loc_next != NULL;
-                  last1 = last1->dw_loc_next)
-               ;
-             if (CONST_INT_P (XEXP (rtl, 0)))
-               op0 = int_loc_descriptor (INTVAL (XEXP (rtl, 0)) & mask);
-             /* deref_size zero extends, so no need to mask it again.  */
-             else if (last0->dw_loc_opc != DW_OP_deref_size
-                      || last0->dw_loc_oprnd1.v.val_int
-                         > GET_MODE_SIZE (op_mode))
-               {
-                 add_loc_descr (&op0, int_loc_descriptor (mask));
-                 add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
-               }
-             if (CONST_INT_P (XEXP (rtl, 1)))
-               op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask);
-             /* deref_size zero extends, so no need to mask it again.  */
-             else if (last1->dw_loc_opc != DW_OP_deref_size
-                      || last1->dw_loc_oprnd1.v.val_int
-                         > GET_MODE_SIZE (op_mode))
-               {
-                 add_loc_descr (&op1, int_loc_descriptor (mask));
-                 add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
-               }
-           }
-         else
-           {
-             HOST_WIDE_INT bias = 1;
-             bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
-             add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
-             if (CONST_INT_P (XEXP (rtl, 1)))
-               op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias
-                                         + INTVAL (XEXP (rtl, 1)));
-             else
-               add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst,
-                                                   bias, 0));
-           }
-       }
-      goto do_compare;
+  switch (TREE_CODE (loc))
+    {
+    case ERROR_MARK:
+      expansion_failed (loc, NULL_RTX, "ERROR_MARK");
+      return 0;
 
-    case SMIN:
-    case SMAX:
-    case UMIN:
-    case UMAX:
-      if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
-         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
-         || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
-       break;
+    case PLACEHOLDER_EXPR:
+      /* This case involves extracting fields from an object to determine the
+        position of other fields.  We don't try to encode this here.  The
+        only user of this is Ada, which encodes the needed information using
+        the names of types.  */
+      expansion_failed (loc, NULL_RTX, "PLACEHOLDER_EXPR");
+      return 0;
 
-      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
-      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
+    case CALL_EXPR:
+      expansion_failed (loc, NULL_RTX, "CALL_EXPR");
+      /* There are no opcodes for these operations.  */
+      return 0;
 
-      if (op0 == 0 || op1 == 0)
-       break;
+    case PREINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      expansion_failed (loc, NULL_RTX, "PRE/POST INDCREMENT/DECREMENT");
+      /* There are no opcodes for these operations.  */
+      return 0;
 
-      add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
-      add_loc_descr (&op1, new_loc_descr (DW_OP_swap, 0, 0));
-      add_loc_descr (&op1, new_loc_descr (DW_OP_over, 0, 0));
-      if (GET_CODE (rtl) == UMIN || GET_CODE (rtl) == UMAX)
+    case ADDR_EXPR:
+      /* If we already want an address, see if there is INDIRECT_REF inside
+         e.g. for &this->field.  */
+      if (want_address)
        {
-         if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
-           {
-             HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0)));
-             add_loc_descr (&op0, int_loc_descriptor (mask));
-             add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
-             add_loc_descr (&op1, int_loc_descriptor (mask));
-             add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
-           }
-         else
-           {
-             HOST_WIDE_INT bias = 1;
-             bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
-             add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
-             add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0));
-           }
+         list_ret = loc_list_for_address_of_addr_expr_of_indirect_ref
+                      (loc, want_address == 2);
+         if (list_ret)
+           have_address = 1;
+         else if (decl_address_ip_invariant_p (TREE_OPERAND (loc, 0))
+                  && (ret = cst_pool_loc_descr (loc)))
+           have_address = 1;
        }
-      else if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+        /* Otherwise, process the argument and look for the address.  */
+      if (!list_ret && !ret)
+        list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 1);
+      else
        {
-         int shift = DWARF2_ADDR_SIZE
-                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
-         shift *= BITS_PER_UNIT;
-         add_loc_descr (&op0, int_loc_descriptor (shift));
-         add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
-         add_loc_descr (&op1, int_loc_descriptor (shift));
-         add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+         if (want_address)
+           expansion_failed (loc, NULL_RTX, "need address of ADDR_EXPR");
+         return NULL;
        }
-
-      if (GET_CODE (rtl) == SMIN || GET_CODE (rtl) == UMIN)
-       op = DW_OP_lt;
-      else
-       op = DW_OP_gt;
-      mem_loc_result = op0;
-      add_loc_descr (&mem_loc_result, op1);
-      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
-      {
-       dw_loc_descr_ref bra_node, drop_node;
-
-       bra_node = new_loc_descr (DW_OP_bra, 0, 0);
-       add_loc_descr (&mem_loc_result, bra_node);
-       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_swap, 0, 0));
-       drop_node = new_loc_descr (DW_OP_drop, 0, 0);
-       add_loc_descr (&mem_loc_result, drop_node);
-       bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
-       bra_node->dw_loc_oprnd1.v.val_loc = drop_node;
-      }
       break;
 
-    case ZERO_EXTRACT:
-    case SIGN_EXTRACT:
-      if (CONST_INT_P (XEXP (rtl, 1))
-         && CONST_INT_P (XEXP (rtl, 2))
-         && ((unsigned) INTVAL (XEXP (rtl, 1))
-             + (unsigned) INTVAL (XEXP (rtl, 2))
-             <= GET_MODE_BITSIZE (GET_MODE (rtl)))
-         && GET_MODE_BITSIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE
-         && GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0))) <= DWARF2_ADDR_SIZE)
+    case VAR_DECL:
+      if (DECL_THREAD_LOCAL_P (loc))
        {
-         int shift, size;
-         op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                                   VAR_INIT_STATUS_INITIALIZED);
-         if (op0 == 0)
-           break;
-         if (GET_CODE (rtl) == SIGN_EXTRACT)
-           op = DW_OP_shra;
-         else
-           op = DW_OP_shr;
-         mem_loc_result = op0;
-         size = INTVAL (XEXP (rtl, 1));
-         shift = INTVAL (XEXP (rtl, 2));
-         if (BITS_BIG_ENDIAN)
-           shift = GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0)))
-                   - shift - size;
-         if (shift + size != (int) DWARF2_ADDR_SIZE)
+         rtx rtl;
+         enum dwarf_location_atom first_op;
+         enum dwarf_location_atom second_op;
+         bool dtprel = false;
+
+         if (targetm.have_tls)
            {
-             add_loc_descr (&mem_loc_result,
-                            int_loc_descriptor (DWARF2_ADDR_SIZE
-                                                - shift - size));
-             add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
+             /* If this is not defined, we have no way to emit the
+                data.  */
+             if (!targetm.asm_out.output_dwarf_dtprel)
+               return 0;
+
+              /* The way DW_OP_GNU_push_tls_address is specified, we
+                 can only look up addresses of objects in the current
+                 module.  We used DW_OP_addr as first op, but that's
+                 wrong, because DW_OP_addr is relocated by the debug
+                 info consumer, while DW_OP_GNU_push_tls_address
+                 operand shouldn't be.  */
+             if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
+               return 0;
+             first_op = DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u;
+             dtprel = true;
+             second_op = DW_OP_GNU_push_tls_address;
            }
-         if (size != (int) DWARF2_ADDR_SIZE)
+         else
            {
-             add_loc_descr (&mem_loc_result,
-                            int_loc_descriptor (DWARF2_ADDR_SIZE - size));
-             add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+             if (!targetm.emutls.debug_form_tls_address
+                 || !(dwarf_version >= 3 || !dwarf_strict))
+               return 0;
+             /* We stuffed the control variable into the DECL_VALUE_EXPR
+                to signal (via DECL_HAS_VALUE_EXPR_P) that the decl should
+                no longer appear in gimple code.  We used the control
+                variable in specific so that we could pick it up here.  */
+             loc = DECL_VALUE_EXPR (loc);
+             first_op = DW_OP_addr;
+             second_op = DW_OP_form_tls_address;
            }
-       }
-      break;
-
-    case COMPARE:
-    case IF_THEN_ELSE:
-    case ROTATE:
-    case ROTATERT:
-    case TRUNCATE:
-      /* In theory, we could implement the above.  */
-      /* DWARF cannot represent the unsigned compare operations
-        natively.  */
-    case SS_MULT:
-    case US_MULT:
-    case SS_DIV:
-    case US_DIV:
-    case SS_PLUS:
-    case US_PLUS:
-    case SS_MINUS:
-    case US_MINUS:
-    case SS_NEG:
-    case US_NEG:
-    case SS_ABS:
-    case SS_ASHIFT:
-    case US_ASHIFT:
-    case SS_TRUNCATE:
-    case US_TRUNCATE:
-    case UDIV:
-    case UNORDERED:
-    case ORDERED:
-    case UNEQ:
-    case UNGE:
-    case UNGT:
-    case UNLE:
-    case UNLT:
-    case LTGT:
-    case FLOAT_EXTEND:
-    case FLOAT_TRUNCATE:
-    case FLOAT:
-    case UNSIGNED_FLOAT:
-    case FIX:
-    case UNSIGNED_FIX:
-    case FRACT_CONVERT:
-    case UNSIGNED_FRACT_CONVERT:
-    case SAT_FRACT:
-    case UNSIGNED_SAT_FRACT:
-    case SQRT:
-    case BSWAP:
-    case FFS:
-    case CLZ:
-    case CTZ:
-    case POPCOUNT:
-    case PARITY:
-    case ASM_OPERANDS:
-    case VEC_MERGE:
-    case VEC_SELECT:
-    case VEC_CONCAT:
-    case VEC_DUPLICATE:
-    case UNSPEC:
-    case HIGH:
-      /* If delegitimize_address couldn't do anything with the UNSPEC, we
-        can't express it in the debug info.  This can happen e.g. with some
-        TLS UNSPECs.  */
-      break;
 
-    case CONST_STRING:
-      resolve_one_addr (&rtl, NULL);
-      goto symref;
+         rtl = rtl_for_decl_location (loc);
+         if (rtl == NULL_RTX)
+           return 0;
 
-    default:
-#ifdef ENABLE_CHECKING
-      print_rtl (stderr, rtl);
-      gcc_unreachable ();
-#else
-      break;
-#endif
-    }
+         if (!MEM_P (rtl))
+           return 0;
+         rtl = XEXP (rtl, 0);
+         if (! CONSTANT_P (rtl))
+           return 0;
 
-  if (mem_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+         ret = new_loc_descr (first_op, 0, 0);
+         ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
+         ret->dw_loc_oprnd1.v.val_addr = rtl;
+         ret->dtprel = dtprel;
 
-  return mem_loc_result;
-}
+         ret1 = new_loc_descr (second_op, 0, 0);
+         add_loc_descr (&ret, ret1);
 
-/* Return a descriptor that describes the concatenation of two locations.
-   This is typically a complex variable.  */
+         have_address = 1;
+         break;
+       }
+      /* FALLTHRU */
 
-static dw_loc_descr_ref
-concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
-{
-  dw_loc_descr_ref cc_loc_result = NULL;
-  dw_loc_descr_ref x0_ref
-    = loc_descriptor (x0, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
-  dw_loc_descr_ref x1_ref
-    = loc_descriptor (x1, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+    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 */
 
-  if (x0_ref == 0 || x1_ref == 0)
-    return 0;
+    case FUNCTION_DECL:
+      {
+       rtx rtl;
+       var_loc_list *loc_list = lookup_decl_loc (loc);
 
-  cc_loc_result = x0_ref;
-  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x0)));
+       if (loc_list && loc_list->first)
+         {
+           list_ret = dw_loc_list (loc_list, loc, want_address);
+           have_address = want_address != 0;
+           break;
+         }
+       rtl = rtl_for_decl_location (loc);
+       if (rtl == NULL_RTX)
+         {
+           expansion_failed (loc, NULL_RTX, "DECL has no RTL");
+           return 0;
+         }
+       else if (CONST_INT_P (rtl))
+         {
+           HOST_WIDE_INT val = INTVAL (rtl);
+           if (TYPE_UNSIGNED (TREE_TYPE (loc)))
+             val &= GET_MODE_MASK (DECL_MODE (loc));
+           ret = int_loc_descriptor (val);
+         }
+       else if (GET_CODE (rtl) == CONST_STRING)
+         {
+           expansion_failed (loc, NULL_RTX, "CONST_STRING");
+           return 0;
+         }
+       else if (CONSTANT_P (rtl) && const_ok_for_output (rtl))
+         {
+           ret = new_loc_descr (DW_OP_addr, 0, 0);
+           ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
+           ret->dw_loc_oprnd1.v.val_addr = rtl;
+         }
+       else
+         {
+           enum machine_mode mode, mem_mode;
 
-  add_loc_descr (&cc_loc_result, x1_ref);
-  add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1)));
+           /* Certain constructs can only be represented at top-level.  */
+           if (want_address == 2)
+             {
+               ret = loc_descriptor (rtl, VOIDmode,
+                                     VAR_INIT_STATUS_INITIALIZED);
+               have_address = 1;
+             }
+           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, mem_mode,
+                                         VAR_INIT_STATUS_INITIALIZED);
+             }
+           if (!ret)
+             expansion_failed (loc, rtl,
+                               "failed to produce loc descriptor for rtl");
+         }
+      }
+      break;
 
-  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+    case MEM_REF:
+      /* ??? FIXME.  */
+      if (!integer_zerop (TREE_OPERAND (loc, 1)))
+       return 0;
+      /* Fallthru.  */
+    case INDIRECT_REF:
+      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+      have_address = 1;
+      break;
 
-  return cc_loc_result;
-}
+    case COMPOUND_EXPR:
+      return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address);
 
-/* Return a descriptor that describes the concatenation of N
-   locations.  */
+    CASE_CONVERT:
+    case VIEW_CONVERT_EXPR:
+    case SAVE_EXPR:
+    case MODIFY_EXPR:
+      return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address);
 
-static dw_loc_descr_ref
-concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
-{
-  unsigned int i;
-  dw_loc_descr_ref cc_loc_result = NULL;
-  unsigned int n = XVECLEN (concatn, 0);
+    case COMPONENT_REF:
+    case BIT_FIELD_REF:
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+      {
+       tree obj, offset;
+       HOST_WIDE_INT bitsize, bitpos, bytepos;
+       enum machine_mode mode;
+       int volatilep;
+       int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
 
-  for (i = 0; i < n; ++i)
-    {
-      dw_loc_descr_ref ref;
-      rtx x = XVECEXP (concatn, 0, i);
+       obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
+                                  &unsignedp, &volatilep, false);
 
-      ref = loc_descriptor (x, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
-      if (ref == NULL)
-       return NULL;
+       gcc_assert (obj != loc);
 
-      add_loc_descr (&cc_loc_result, ref);
-      add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
-    }
+       list_ret = loc_list_from_tree (obj,
+                                      want_address == 2
+                                      && !bitpos && !offset ? 2 : 1);
+       /* TODO: We can extract value of the small expression via shifting even
+          for nonzero bitpos.  */
+       if (list_ret == 0)
+         return 0;
+       if (bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0)
+         {
+           expansion_failed (loc, NULL_RTX,
+                             "bitfield access");
+           return 0;
+         }
 
-  if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
-    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+       if (offset != NULL_TREE)
+         {
+           /* Variable offset.  */
+           list_ret1 = loc_list_from_tree (offset, 0);
+           if (list_ret1 == 0)
+             return 0;
+           add_loc_list (&list_ret, list_ret1);
+           if (!list_ret)
+             return 0;
+           add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus, 0, 0));
+         }
 
-  return cc_loc_result;
-}
+       bytepos = bitpos / BITS_PER_UNIT;
+       if (bytepos > 0)
+         add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0));
+       else if (bytepos < 0)
+         loc_list_plus_const (list_ret, bytepos);
 
-/* 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.
+       have_address = 1;
+       break;
+      }
 
-   MODE is mode of the decl if this loc_descriptor is going to be used in
-   .debug_loc section where DW_OP_stack_value and DW_OP_implicit_value are
-   allowed, VOIDmode otherwise.
+    case INTEGER_CST:
+      if ((want_address || !host_integerp (loc, 0))
+         && (ret = cst_pool_loc_descr (loc)))
+       have_address = 1;
+      else if (want_address == 2
+              && host_integerp (loc, 0)
+              && (ret = address_of_int_loc_descriptor
+                          (int_size_in_bytes (TREE_TYPE (loc)),
+                           tree_low_cst (loc, 0))))
+       have_address = 1;
+      else if (host_integerp (loc, 0))
+       ret = int_loc_descriptor (tree_low_cst (loc, 0));
+      else
+       {
+         expansion_failed (loc, NULL_RTX,
+                           "Integer operand is not host integer");
+         return 0;
+       }
+      break;
 
-   If we don't know how to describe it, return 0.  */
+    case CONSTRUCTOR:
+    case REAL_CST:
+    case STRING_CST:
+    case COMPLEX_CST:
+      if ((ret = cst_pool_loc_descr (loc)))
+       have_address = 1;
+      else
+      /* We can construct small constants here using int_loc_descriptor.  */
+       expansion_failed (loc, NULL_RTX,
+                         "constructor or constant not in constant pool");
+      break;
 
-static dw_loc_descr_ref
-loc_descriptor (rtx rtl, enum machine_mode mode,
-               enum var_init_status initialized)
-{
-  dw_loc_descr_ref loc_result = NULL;
+    case TRUTH_AND_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case BIT_AND_EXPR:
+      op = DW_OP_and;
+      goto do_binop;
 
-  switch (GET_CODE (rtl))
-    {
-    case SUBREG:
-      /* The case of a subreg may arise when we have a local (register)
-        variable or a formal (register) parameter which doesn't quite fill
-        up an entire register.  For now, just assume that it is
-        legitimate to make the Dwarf info refer to the whole register which
-        contains the given subreg.  */
-      loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized);
-      break;
+    case TRUTH_XOR_EXPR:
+    case BIT_XOR_EXPR:
+      op = DW_OP_xor;
+      goto do_binop;
 
-    case REG:
-      loc_result = reg_loc_descriptor (rtl, initialized);
-      break;
+    case TRUTH_OR_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case BIT_IOR_EXPR:
+      op = DW_OP_or;
+      goto do_binop;
 
-    case SIGN_EXTEND:
-    case ZERO_EXTEND:
-      loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
-      break;
+    case FLOOR_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case TRUNC_DIV_EXPR:
+      if (TYPE_UNSIGNED (TREE_TYPE (loc)))
+       return 0;
+      op = DW_OP_div;
+      goto do_binop;
 
-    case MEM:
-      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
-                                      initialized);
-      if (loc_result == NULL)
-       loc_result = tls_mem_loc_descriptor (rtl);
-      if (loc_result == NULL)
+    case MINUS_EXPR:
+      op = DW_OP_minus;
+      goto do_binop;
+
+    case FLOOR_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case TRUNC_MOD_EXPR:
+      if (TYPE_UNSIGNED (TREE_TYPE (loc)))
        {
-         rtx new_rtl = avoid_constant_pool_reference (rtl);
-         if (new_rtl != rtl)
-           loc_result = loc_descriptor (new_rtl, mode, initialized);
+         op = DW_OP_mod;
+         goto do_binop;
        }
-      break;
+      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+      list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0);
+      if (list_ret == 0 || list_ret1 == 0)
+       return 0;
 
-    case CONCAT:
-      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1),
-                                         initialized);
+      add_loc_list (&list_ret, list_ret1);
+      if (list_ret == 0)
+       return 0;
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_over, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_over, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_div, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_mul, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_minus, 0, 0));
       break;
 
-    case CONCATN:
-      loc_result = concatn_loc_descriptor (rtl, initialized);
-      break;
+    case MULT_EXPR:
+      op = DW_OP_mul;
+      goto do_binop;
 
-    case VAR_LOCATION:
-      /* Single part.  */
-      if (GET_CODE (PAT_VAR_LOCATION_LOC (rtl)) != PARALLEL)
+    case LSHIFT_EXPR:
+      op = DW_OP_shl;
+      goto do_binop;
+
+    case RSHIFT_EXPR:
+      op = (TYPE_UNSIGNED (TREE_TYPE (loc)) ? DW_OP_shr : DW_OP_shra);
+      goto do_binop;
+
+    case POINTER_PLUS_EXPR:
+    case PLUS_EXPR:
+      if (host_integerp (TREE_OPERAND (loc, 1), 0))
        {
-         rtx loc = PAT_VAR_LOCATION_LOC (rtl);
-         if (GET_CODE (loc) == EXPR_LIST)
-           loc = XEXP (loc, 0);
-         loc_result = loc_descriptor (loc, mode, initialized);
+         list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+         if (list_ret == 0)
+           return 0;
+
+         loc_list_plus_const (list_ret, tree_low_cst (TREE_OPERAND (loc, 1), 0));
          break;
        }
 
-      rtl = XEXP (rtl, 1);
-      /* FALLTHRU */
+      op = DW_OP_plus;
+      goto do_binop;
 
-    case PARALLEL:
-      {
-       rtvec par_elems = XVEC (rtl, 0);
-       int num_elem = GET_NUM_ELEM (par_elems);
-       enum machine_mode mode;
-       int i;
+    case LE_EXPR:
+      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+       return 0;
 
-       /* Create the first one, so we have something to add to.  */
-       loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
-                                    VOIDmode, initialized);
-       if (loc_result == NULL)
-         return NULL;
-       mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
-       add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
-       for (i = 1; i < num_elem; i++)
-         {
-           dw_loc_descr_ref temp;
+      op = DW_OP_le;
+      goto do_binop;
 
-           temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
-                                  VOIDmode, initialized);
-           if (temp == NULL)
-             return NULL;
-           add_loc_descr (&loc_result, temp);
-           mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
-           add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
-         }
-      }
-      break;
+    case GE_EXPR:
+      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+       return 0;
 
-    case CONST_INT:
-      if (mode != VOIDmode && mode != BLKmode)
-       loc_result = address_of_int_loc_descriptor (GET_MODE_SIZE (mode),
-                                                   INTVAL (rtl));
-      break;
+      op = DW_OP_ge;
+      goto do_binop;
 
-    case CONST_DOUBLE:
-      if (mode == VOIDmode)
-       mode = GET_MODE (rtl);
+    case LT_EXPR:
+      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+       return 0;
 
-      if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
-       {
-         gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
+      op = DW_OP_lt;
+      goto do_binop;
+
+    case GT_EXPR:
+      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+       return 0;
 
-         /* Note that a CONST_DOUBLE rtx could represent either an integer
-            or a floating-point constant.  A CONST_DOUBLE is used whenever
-            the constant requires more than one word in order to be
-            adequately represented.  We output CONST_DOUBLEs as blocks.  */
-         loc_result = new_loc_descr (DW_OP_implicit_value,
-                                     GET_MODE_SIZE (mode), 0);
-         if (SCALAR_FLOAT_MODE_P (mode))
-           {
-             unsigned int length = GET_MODE_SIZE (mode);
-             unsigned char *array = GGC_NEWVEC (unsigned char, length);
+      op = DW_OP_gt;
+      goto do_binop;
 
-             insert_float (rtl, array);
-             loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
-             loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4;
-             loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
-             loc_result->dw_loc_oprnd2.v.val_vec.array = array;
-           }
-         else
-           {
-             loc_result->dw_loc_oprnd2.val_class = dw_val_class_const_double;
-             loc_result->dw_loc_oprnd2.v.val_double
-               = rtx_to_double_int (rtl);
-           }
-       }
-      break;
+    case EQ_EXPR:
+      op = DW_OP_eq;
+      goto do_binop;
 
-    case CONST_VECTOR:
-      if (mode == VOIDmode)
-       mode = GET_MODE (rtl);
+    case NE_EXPR:
+      op = DW_OP_ne;
+      goto do_binop;
 
-      if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
-       {
-         unsigned int elt_size = GET_MODE_UNIT_SIZE (GET_MODE (rtl));
-         unsigned int length = CONST_VECTOR_NUNITS (rtl);
-         unsigned char *array = GGC_NEWVEC (unsigned char, length * elt_size);
-         unsigned int i;
-         unsigned char *p;
+    do_binop:
+      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+      list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0);
+      if (list_ret == 0 || list_ret1 == 0)
+       return 0;
 
-         gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
-         switch (GET_MODE_CLASS (mode))
-           {
-           case MODE_VECTOR_INT:
-             for (i = 0, p = array; i < length; i++, p += elt_size)
-               {
-                 rtx elt = CONST_VECTOR_ELT (rtl, i);
-                 double_int val = rtx_to_double_int (elt);
+      add_loc_list (&list_ret, list_ret1);
+      if (list_ret == 0)
+       return 0;
+      add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0));
+      break;
 
-                 if (elt_size <= sizeof (HOST_WIDE_INT))
-                   insert_int (double_int_to_shwi (val), elt_size, p);
-                 else
-                   {
-                     gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
-                     insert_double (val, p);
-                   }
-               }
-             break;
+    case TRUTH_NOT_EXPR:
+    case BIT_NOT_EXPR:
+      op = DW_OP_not;
+      goto do_unop;
 
-           case MODE_VECTOR_FLOAT:
-             for (i = 0, p = array; i < length; i++, p += elt_size)
-               {
-                 rtx elt = CONST_VECTOR_ELT (rtl, i);
-                 insert_float (elt, p);
-               }
-             break;
+    case ABS_EXPR:
+      op = DW_OP_abs;
+      goto do_unop;
 
-           default:
-             gcc_unreachable ();
-           }
+    case NEGATE_EXPR:
+      op = DW_OP_neg;
+      goto do_unop;
 
-         loc_result = new_loc_descr (DW_OP_implicit_value,
-                                     length * elt_size, 0);
-         loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
-         loc_result->dw_loc_oprnd2.v.val_vec.length = length;
-         loc_result->dw_loc_oprnd2.v.val_vec.elt_size = elt_size;
-         loc_result->dw_loc_oprnd2.v.val_vec.array = array;
-       }
-      break;
+    do_unop:
+      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+      if (list_ret == 0)
+       return 0;
 
-    case CONST:
-      if (mode == VOIDmode
-         || GET_CODE (XEXP (rtl, 0)) == CONST_INT
-         || GET_CODE (XEXP (rtl, 0)) == CONST_DOUBLE
-         || GET_CODE (XEXP (rtl, 0)) == CONST_VECTOR)
-       {
-         loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
-         break;
-       }
-      /* FALLTHROUGH */
-    case SYMBOL_REF:
-      if (!const_ok_for_output (rtl))
-       break;
-    case LABEL_REF:
-      if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
-         && (dwarf_version >= 4 || !dwarf_strict))
-       {
-         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
-         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
-         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
-         add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
-         VEC_safe_push (rtx, gc, used_rtx_array, rtl);
-       }
+      add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0));
       break;
 
-    default:
-      if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE (rtl) == mode
-         && GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE
-         && (dwarf_version >= 4 || !dwarf_strict))
-       {
-         /* Value expression.  */
-         loc_result = mem_loc_descriptor (rtl, VOIDmode, initialized);
-         if (loc_result)
-           add_loc_descr (&loc_result,
-                          new_loc_descr (DW_OP_stack_value, 0, 0));
-       }
-      break;
-    }
+    case MIN_EXPR:
+    case MAX_EXPR:
+      {
+       const enum tree_code code =
+         TREE_CODE (loc) == MIN_EXPR ? GT_EXPR : LT_EXPR;
 
-  return loc_result;
-}
+       loc = build3 (COND_EXPR, TREE_TYPE (loc),
+                     build2 (code, integer_type_node,
+                             TREE_OPERAND (loc, 0), TREE_OPERAND (loc, 1)),
+                     TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
+      }
 
-/* We need to figure out what section we should use as the base for the
-   address ranges where a given location is valid.
-   1. If this particular DECL has a section associated with it, use that.
-   2. If this function has a section associated with it, use that.
-   3. Otherwise, use the text section.
-   XXX: If you split a variable across multiple sections, we won't notice.  */
+      /* ... fall through ...  */
 
-static const char *
-secname_for_decl (const_tree decl)
-{
-  const char *secname;
+    case COND_EXPR:
+      {
+       dw_loc_descr_ref lhs
+         = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
+       dw_loc_list_ref rhs
+         = loc_list_from_tree (TREE_OPERAND (loc, 2), 0);
+       dw_loc_descr_ref bra_node, jump_node, tmp;
 
-  if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl))
-    {
-      tree sectree = DECL_SECTION_NAME (decl);
-      secname = TREE_STRING_POINTER (sectree);
-    }
-  else if (current_function_decl && DECL_SECTION_NAME (current_function_decl))
-    {
-      tree sectree = DECL_SECTION_NAME (current_function_decl);
-      secname = TREE_STRING_POINTER (sectree);
-    }
-  else if (cfun && in_cold_section_p)
-    secname = crtl->subsections.cold_section_label;
-  else
-    secname = text_section_label;
+       list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+       if (list_ret == 0 || lhs == 0 || rhs == 0)
+         return 0;
 
-  return secname;
-}
+       bra_node = new_loc_descr (DW_OP_bra, 0, 0);
+       add_loc_descr_to_each (list_ret, bra_node);
 
-/* Return true when DECL_BY_REFERENCE is defined and set for DECL.  */
+       add_loc_list (&list_ret, rhs);
+       jump_node = new_loc_descr (DW_OP_skip, 0, 0);
+       add_loc_descr_to_each (list_ret, jump_node);
 
-static bool
-decl_by_reference_p (tree decl)
-{
-  return ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL
-          || TREE_CODE (decl) == VAR_DECL)
-         && DECL_BY_REFERENCE (decl));
-}
+       add_loc_descr_to_each (list_ret, lhs);
+       bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+       bra_node->dw_loc_oprnd1.v.val_loc = lhs;
 
-/* Helper function for dw_loc_list.  Compute proper Dwarf location descriptor
-   for VARLOC.  */
+       /* ??? Need a node to point the skip at.  Use a nop.  */
+       tmp = new_loc_descr (DW_OP_nop, 0, 0);
+       add_loc_descr_to_each (list_ret, tmp);
+       jump_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+       jump_node->dw_loc_oprnd1.v.val_loc = tmp;
+      }
+      break;
 
-static dw_loc_descr_ref
-dw_loc_list_1 (tree loc, rtx varloc, int want_address,
-              enum var_init_status initialized)
-{
-  int have_address = 0;
-  dw_loc_descr_ref descr;
-  enum machine_mode mode;
+    case FIX_TRUNC_EXPR:
+      return 0;
 
-  if (want_address != 2)
-    {
-      gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
-      /* Single part.  */
-      if (GET_CODE (PAT_VAR_LOCATION_LOC (varloc)) != PARALLEL)
+    default:
+      /* Leave front-end specific codes as simply unknown.  This comes
+        up, for instance, with the C STMT_EXPR.  */
+      if ((unsigned int) TREE_CODE (loc)
+         >= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
        {
-         varloc = PAT_VAR_LOCATION_LOC (varloc);
-         if (GET_CODE (varloc) == EXPR_LIST)
-           varloc = XEXP (varloc, 0);
-         mode = GET_MODE (varloc);
-         if (MEM_P (varloc))
-           {
-             rtx addr = XEXP (varloc, 0);
-             descr = mem_loc_descriptor (addr, mode, initialized);
-             if (descr)
-               have_address = 1;
-             else
-               {
-                 rtx x = avoid_constant_pool_reference (varloc);
-                 if (x != varloc)
-                   descr = mem_loc_descriptor (x, mode, initialized);
-               }
-           }
-         else
-           descr = mem_loc_descriptor (varloc, mode, initialized);
-       }
-      else
-       return 0;
-    }
-  else
-    {
-      if (GET_CODE (varloc) == VAR_LOCATION)
-       mode = DECL_MODE (PAT_VAR_LOCATION_DECL (varloc));
-      else
-       mode = DECL_MODE (loc);
-      descr = loc_descriptor (varloc, mode, initialized);
-      have_address = 1;
+         expansion_failed (loc, NULL_RTX,
+                           "language specific tree node");
+         return 0;
+       }
+
+#ifdef ENABLE_CHECKING
+      /* Otherwise this is a generic code; we should just lists all of
+        these explicitly.  We forgot one.  */
+      gcc_unreachable ();
+#else
+      /* In a release build, we want to degrade gracefully: better to
+        generate incomplete debugging information than to crash.  */
+      return NULL;
+#endif
     }
 
-  if (!descr)
+  if (!ret && !list_ret)
     return 0;
 
   if (want_address == 2 && !have_address
@@ -14325,7 +13871,11 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address,
                            "DWARF address size mismatch");
          return 0;
        }
-      add_loc_descr (&descr, new_loc_descr (DW_OP_stack_value, 0, 0));
+      if (ret)
+       add_loc_descr (&ret, new_loc_descr (DW_OP_stack_value, 0, 0));
+      else
+       add_loc_descr_to_each (list_ret,
+                              new_loc_descr (DW_OP_stack_value, 0, 0));
       have_address = 1;
     }
   /* Show if we can't fill the request for an address.  */
@@ -14336,11 +13886,12 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address,
       return 0;
     }
 
+  gcc_assert (!ret || !list_ret);
+
   /* If we've got an address and don't want one, dereference.  */
   if (!want_address && have_address)
     {
       HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
-      enum dwarf_location_atom op;
 
       if (size > DWARF2_ADDR_SIZE || size == -1)
        {
@@ -14353,7393 +13904,8516 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address,
       else
        op = DW_OP_deref_size;
 
-      add_loc_descr (&descr, new_loc_descr (op, size, 0));
-    }
-
-  return descr;
-}
-
-/* Create a DW_OP_piece or DW_OP_bit_piece for bitsize, or return NULL
-   if it is not possible.  */
-
-static dw_loc_descr_ref
-new_loc_descr_op_bit_piece (HOST_WIDE_INT bitsize, HOST_WIDE_INT offset)
-{
-  if ((bitsize % BITS_PER_UNIT) == 0 && offset == 0)
-    return new_loc_descr (DW_OP_piece, bitsize / BITS_PER_UNIT, 0);
-  else if (dwarf_version >= 3 || !dwarf_strict)
-    return new_loc_descr (DW_OP_bit_piece, bitsize, offset);
-  else
-    return NULL;
-}
-
-/* Helper function for dw_loc_list.  Compute proper Dwarf location descriptor
-   for VAR_LOC_NOTE for variable DECL that has been optimized by SRA.  */
-
-static dw_loc_descr_ref
-dw_sra_loc_expr (tree decl, rtx loc)
-{
-  rtx p;
-  unsigned int padsize = 0;
-  dw_loc_descr_ref descr, *descr_tail;
-  unsigned HOST_WIDE_INT decl_size;
-  rtx varloc;
-  enum var_init_status initialized;
-
-  if (DECL_SIZE (decl) == NULL
-      || !host_integerp (DECL_SIZE (decl), 1))
-    return NULL;
-
-  decl_size = tree_low_cst (DECL_SIZE (decl), 1);
-  descr = NULL;
-  descr_tail = &descr;
-
-  for (p = loc; p; p = XEXP (p, 1))
-    {
-      unsigned int bitsize = decl_piece_bitsize (p);
-      rtx loc_note = *decl_piece_varloc_ptr (p);
-      dw_loc_descr_ref cur_descr;
-      dw_loc_descr_ref *tail, last = NULL;
-      unsigned int opsize = 0;
-
-      if (loc_note == NULL_RTX
-         || NOTE_VAR_LOCATION_LOC (loc_note) == NULL_RTX)
-       {
-         padsize += bitsize;
-         continue;
-       }
-      initialized = NOTE_VAR_LOCATION_STATUS (loc_note);
-      varloc = NOTE_VAR_LOCATION (loc_note);
-      cur_descr = dw_loc_list_1 (decl, varloc, 2, initialized);
-      if (cur_descr == NULL)
-       {
-         padsize += bitsize;
-         continue;
-       }
-
-      /* Check that cur_descr either doesn't use
-        DW_OP_*piece operations, or their sum is equal
-        to bitsize.  Otherwise we can't embed it.  */
-      for (tail = &cur_descr; *tail != NULL;
-          tail = &(*tail)->dw_loc_next)
-       if ((*tail)->dw_loc_opc == DW_OP_piece)
-         {
-           opsize += (*tail)->dw_loc_oprnd1.v.val_unsigned
-                     * BITS_PER_UNIT;
-           last = *tail;
-         }
-       else if ((*tail)->dw_loc_opc == DW_OP_bit_piece)
-         {
-           opsize += (*tail)->dw_loc_oprnd1.v.val_unsigned;
-           last = *tail;
-         }
-
-      if (last != NULL && opsize != bitsize)
-       {
-         padsize += bitsize;
-         continue;
-       }
-
-      /* If there is a hole, add DW_OP_*piece after empty DWARF
-        expression, which means that those bits are optimized out.  */
-      if (padsize)
-       {
-         if (padsize > decl_size)
-           return NULL;
-         decl_size -= padsize;
-         *descr_tail = new_loc_descr_op_bit_piece (padsize, 0);
-         if (*descr_tail == NULL)
-           return NULL;
-         descr_tail = &(*descr_tail)->dw_loc_next;
-         padsize = 0;
-       }
-      *descr_tail = cur_descr;
-      descr_tail = tail;
-      if (bitsize > decl_size)
-       return NULL;
-      decl_size -= bitsize;
-      if (last == NULL)
-       {
-         HOST_WIDE_INT offset = 0;
-         if (GET_CODE (varloc) == VAR_LOCATION
-             && GET_CODE (PAT_VAR_LOCATION_LOC (varloc)) != PARALLEL)
-           {
-             varloc = PAT_VAR_LOCATION_LOC (varloc);
-             if (GET_CODE (varloc) == EXPR_LIST)
-               varloc = XEXP (varloc, 0);
-           }
-         do 
-           {
-             if (GET_CODE (varloc) == CONST
-                 || GET_CODE (varloc) == SIGN_EXTEND
-                 || GET_CODE (varloc) == ZERO_EXTEND)
-               varloc = XEXP (varloc, 0);
-             else if (GET_CODE (varloc) == SUBREG)
-               varloc = SUBREG_REG (varloc);
-             else
-               break;
-           }
-         while (1);
-         /* DW_OP_bit_size offset should be zero for register
-            or implicit location descriptions and empty location
-            descriptions, but for memory addresses needs big endian
-            adjustment.  */
-         if (MEM_P (varloc))
-           {
-             unsigned HOST_WIDE_INT memsize
-               = INTVAL (MEM_SIZE (varloc)) * BITS_PER_UNIT;
-             if (memsize != bitsize)
-               {
-                 if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
-                     && (memsize > BITS_PER_WORD || bitsize > BITS_PER_WORD))
-                   return NULL;
-                 if (memsize < bitsize)
-                   return NULL;
-                 if (BITS_BIG_ENDIAN)
-                   offset = memsize - bitsize;
-               }
-           }
-
-         *descr_tail = new_loc_descr_op_bit_piece (bitsize, offset);
-         if (*descr_tail == NULL)
-           return NULL;
-         descr_tail = &(*descr_tail)->dw_loc_next;
-       }
-    }
-
-  /* If there were any non-empty expressions, add padding till the end of
-     the decl.  */
-  if (descr != NULL && decl_size != 0)
-    {
-      *descr_tail = new_loc_descr_op_bit_piece (decl_size, 0);
-      if (*descr_tail == NULL)
-       return NULL;
+      if (ret)
+       add_loc_descr (&ret, new_loc_descr (op, size, 0));
+      else
+       add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0));
     }
-  return descr;
-}
-
-/* Return the dwarf representation of the location list LOC_LIST of
-   DECL.  WANT_ADDRESS has the same meaning as in loc_list_from_tree
-   function.  */
-
-static dw_loc_list_ref
-dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
-{
-  const char *endname, *secname;
-  rtx varloc;
-  enum var_init_status initialized;
-  struct var_loc_node *node;
-  dw_loc_descr_ref descr;
-  char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
-  dw_loc_list_ref list = NULL;
-  dw_loc_list_ref *listp = &list;
-
-  /* Now that we know what section we are using for a base,
-     actually construct the list of locations.
-     The first location information is what is passed to the
-     function that creates the location list, and the remaining
-     locations just get added on to that list.
-     Note that we only know the start address for a location
-     (IE location changes), so to build the range, we use
-     the range [current location start, next location start].
-     This means we have to special case the last node, and generate
-     a range of [last location start, end of function label].  */
-
-  secname = secname_for_decl (decl);
-
-  for (node = loc_list->first; node; node = node->next)
-    if (GET_CODE (node->loc) == EXPR_LIST
-       || NOTE_VAR_LOCATION_LOC (node->loc) != NULL_RTX)
-      {
-       if (GET_CODE (node->loc) == EXPR_LIST)
-         {
-           /* This requires DW_OP_{,bit_}piece, which is not usable
-              inside DWARF expressions.  */
-           if (want_address != 2)
-             continue;
-           descr = dw_sra_loc_expr (decl, node->loc);
-           if (descr == NULL)
-             continue;
-         }
-       else
-         {
-           initialized = NOTE_VAR_LOCATION_STATUS (node->loc);
-           varloc = NOTE_VAR_LOCATION (node->loc);
-           descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
-         }
-       if (descr)
-         {
-           /* The variable has a location between NODE->LABEL and
-              NODE->NEXT->LABEL.  */
-           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.  */
-           else if (!current_function_decl)
-             endname = text_end_label;
-           else
-             {
-               ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
-                                            current_function_funcdef_no);
-               endname = ggc_strdup (label_id);
-             }
+  if (ret)
+    list_ret = new_loc_list (ret, NULL, NULL, NULL);
 
-           *listp = new_loc_list (descr, node->label, endname, secname);
-           listp = &(*listp)->dw_loc_next;
-         }
-      }
+  return list_ret;
+}
 
-  /* Try to avoid the overhead of a location list emitting a location
-     expression instead, but only if we didn't have more than one
-     location entry in the first place.  If some entries were not
-     representable, we don't want to pretend a single entry that was
-     applies to the entire scope in which the variable is
-     available.  */
-  if (list && loc_list->first->next)
-    gen_llsym (list);
+/* Same as above but return only single location expression.  */
+static dw_loc_descr_ref
+loc_descriptor_from_tree (tree loc, int want_address)
+{
+  dw_loc_list_ref ret = loc_list_from_tree (loc, want_address);
+  if (!ret)
+    return NULL;
+  if (ret->dw_loc_next)
+    {
+      expansion_failed (loc, NULL_RTX,
+                       "Location list where only loc descriptor needed");
+      return NULL;
+    }
+  return ret->expr;
+}
 
-  return list;
+/* Given a value, round it up to the lowest multiple of `boundary'
+   which is not less than the value itself.  */
+
+static inline HOST_WIDE_INT
+ceiling (HOST_WIDE_INT value, unsigned int boundary)
+{
+  return (((value + boundary - 1) / boundary) * boundary);
 }
 
-/* Return if the loc_list has only single element and thus can be represented
-   as location description.   */
+/* Given a pointer to what is assumed to be a FIELD_DECL node, return a
+   pointer to the declared type for the relevant field variable, or return
+   `integer_type_node' if the given node turns out to be an
+   ERROR_MARK node.  */
 
-static bool
-single_element_loc_list_p (dw_loc_list_ref list)
+static inline tree
+field_type (const_tree decl)
 {
-  gcc_assert (!list->dw_loc_next || list->ll_symbol);
-  return !list->ll_symbol;
+  tree type;
+
+  if (TREE_CODE (decl) == ERROR_MARK)
+    return integer_type_node;
+
+  type = DECL_BIT_FIELD_TYPE (decl);
+  if (type == NULL_TREE)
+    type = TREE_TYPE (decl);
+
+  return type;
 }
 
-/* To each location in list LIST add loc descr REF.  */
+/* Given a pointer to a tree node, return the alignment in bits for
+   it, or else return BITS_PER_WORD if the node actually turns out to
+   be an ERROR_MARK node.  */
 
-static void
-add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref)
+static inline unsigned
+simple_type_align_in_bits (const_tree type)
 {
-  dw_loc_descr_ref copy;
-  add_loc_descr (&list->expr, ref);
-  list = list->dw_loc_next;
-  while (list)
-    {
-      copy = GGC_CNEW (dw_loc_descr_node);
-      memcpy (copy, ref, sizeof (dw_loc_descr_node));
-      add_loc_descr (&list->expr, copy);
-      while (copy->dw_loc_next)
-       {
-         dw_loc_descr_ref new_copy = GGC_CNEW (dw_loc_descr_node);
-         memcpy (new_copy, copy->dw_loc_next, sizeof (dw_loc_descr_node));
-         copy->dw_loc_next = new_copy;
-         copy = new_copy;
-       }
-      list = list->dw_loc_next;
-    }
+  return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD;
 }
 
-/* Given two lists RET and LIST
-   produce location list that is result of adding expression in LIST
-   to expression in RET on each possition in program.
-   Might be destructive on both RET and LIST.
+static inline unsigned
+simple_decl_align_in_bits (const_tree decl)
+{
+  return (TREE_CODE (decl) != ERROR_MARK) ? DECL_ALIGN (decl) : BITS_PER_WORD;
+}
 
-   TODO: We handle only simple cases of RET or LIST having at most one
-   element. General case would inolve sorting the lists in program order
-   and merging them that will need some additional work.
-   Adding that will improve quality of debug info especially for SRA-ed
-   structures.  */
+/* Return the result of rounding T up to ALIGN.  */
 
-static void
-add_loc_list (dw_loc_list_ref *ret, dw_loc_list_ref list)
+static inline double_int
+round_up_to_align (double_int t, unsigned int align)
 {
-  if (!list)
-    return;
-  if (!*ret)
-    {
-      *ret = list;
-      return;
-    }
-  if (!list->dw_loc_next)
-    {
-      add_loc_descr_to_each (*ret, list->expr);
-      return;
-    }
-  if (!(*ret)->dw_loc_next)
-    {
-      add_loc_descr_to_each (list, (*ret)->expr);
-      *ret = list;
-      return;
-    }
-  expansion_failed (NULL_TREE, NULL_RTX,
-                   "Don't know how to merge two non-trivial"
-                   " location lists.\n");
-  *ret = NULL;
-  return;
+  double_int alignd = uhwi_to_double_int (align);
+  t = double_int_add (t, alignd);
+  t = double_int_add (t, double_int_minus_one);
+  t = double_int_div (t, alignd, true, TRUNC_DIV_EXPR);
+  t = double_int_mul (t, alignd);
+  return t;
 }
 
-/* LOC is constant expression.  Try a luck, look it up in constant
-   pool and return its loc_descr of its address.  */
+/* Given a pointer to a FIELD_DECL, compute and return the byte offset of the
+   lowest addressed byte of the "containing object" for the given FIELD_DECL,
+   or return 0 if we are unable to determine what that offset is, either
+   because the argument turns out to be a pointer to an ERROR_MARK node, or
+   because the offset is actually variable.  (We can't handle the latter case
+   just yet).  */
 
-static dw_loc_descr_ref
-cst_pool_loc_descr (tree loc)
+static HOST_WIDE_INT
+field_byte_offset (const_tree decl)
 {
-  /* Get an RTL for this, if something has been emitted.  */
-  rtx rtl = lookup_constant_def (loc);
-  enum machine_mode mode;
+  double_int object_offset_in_bits;
+  double_int object_offset_in_bytes;
+  double_int bitpos_int;
 
-  if (!rtl || !MEM_P (rtl))
-    {
-      gcc_assert (!rtl);
-      return 0;
-    }
-  gcc_assert (GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF);
+  if (TREE_CODE (decl) == ERROR_MARK)
+    return 0;
 
-  /* TODO: We might get more coverage if we was actually delaying expansion
-     of all expressions till end of compilation when constant pools are fully
-     populated.  */
-  if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (XEXP (rtl, 0))))
-    {
-      expansion_failed (loc, NULL_RTX,
-                       "CST value in contant pool but not marked.");
-      return 0;
-    }
-  mode = GET_MODE (rtl);
-  rtl = XEXP (rtl, 0);
-  return mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
-}
+  gcc_assert (TREE_CODE (decl) == FIELD_DECL);
 
-/* Return dw_loc_list representing address of addr_expr LOC
-   by looking for innder INDIRECT_REF expression and turing it
-   into simple arithmetics.  */
+  /* We cannot yet cope with fields whose positions are variable, so
+     for now, when we see such things, we simply return 0.  Someday, we may
+     be able to handle such cases, but it will be damn difficult.  */
+  if (TREE_CODE (bit_position (decl)) != INTEGER_CST)
+    return 0;
 
-static dw_loc_list_ref
-loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev)
-{
-  tree obj, offset;
-  HOST_WIDE_INT bitsize, bitpos, bytepos;
-  enum machine_mode mode;
-  int volatilep;
-  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
-  dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
+  bitpos_int = tree_to_double_int (bit_position (decl));
 
-  obj = get_inner_reference (TREE_OPERAND (loc, 0),
-                            &bitsize, &bitpos, &offset, &mode,
-                            &unsignedp, &volatilep, false);
-  STRIP_NOPS (obj);
-  if (bitpos % BITS_PER_UNIT)
-    {
-      expansion_failed (loc, NULL_RTX, "bitfield access");
-      return 0;
-    }
-  if (!INDIRECT_REF_P (obj))
-    {
-      expansion_failed (obj,
-                       NULL_RTX, "no indirect ref in inner refrence");
-      return 0;
-    }
-  if (!offset && !bitpos)
-    list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1);
-  else if (toplev
-          && int_size_in_bytes (TREE_TYPE (loc)) <= DWARF2_ADDR_SIZE
-          && (dwarf_version >= 4 || !dwarf_strict))
+#ifdef PCC_BITFIELD_TYPE_MATTERS
+  if (PCC_BITFIELD_TYPE_MATTERS)
     {
-      list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0);
-      if (!list_ret)
-       return 0;
-      if (offset)
+      tree type;
+      tree field_size_tree;
+      double_int deepest_bitpos;
+      double_int field_size_in_bits;
+      unsigned int type_align_in_bits;
+      unsigned int decl_align_in_bits;
+      double_int type_size_in_bits;
+
+      type = field_type (decl);
+      type_size_in_bits = double_int_type_size_in_bits (type);
+      type_align_in_bits = simple_type_align_in_bits (type);
+
+      field_size_tree = DECL_SIZE (decl);
+
+      /* The size could be unspecified if there was an error, or for
+        a flexible array member.  */
+      if (!field_size_tree)
+       field_size_tree = bitsize_zero_node;
+
+      /* If the size of the field is not constant, use the type size.  */
+      if (TREE_CODE (field_size_tree) == INTEGER_CST)
+       field_size_in_bits = tree_to_double_int (field_size_tree);
+      else
+       field_size_in_bits = type_size_in_bits;
+
+      decl_align_in_bits = simple_decl_align_in_bits (decl);
+
+      /* The GCC front-end doesn't make any attempt to keep track of the
+        starting bit offset (relative to the start of the containing
+        structure type) of the hypothetical "containing object" for a
+        bit-field.  Thus, when computing the byte offset value for the
+        start of the "containing object" of a bit-field, we must deduce
+        this information on our own. This can be rather tricky to do in
+        some cases.  For example, handling the following structure type
+        definition when compiling for an i386/i486 target (which only
+        aligns long long's to 32-bit boundaries) can be very tricky:
+
+        struct S { int field1; long long field2:31; };
+
+        Fortunately, there is a simple rule-of-thumb which can be used
+        in such cases.  When compiling for an i386/i486, GCC will
+        allocate 8 bytes for the structure shown above.  It decides to
+        do this based upon one simple rule for bit-field allocation.
+        GCC allocates each "containing object" for each bit-field at
+        the first (i.e. lowest addressed) legitimate alignment boundary
+        (based upon the required minimum alignment for the declared
+        type of the field) which it can possibly use, subject to the
+        condition that there is still enough available space remaining
+        in the containing object (when allocated at the selected point)
+        to fully accommodate all of the bits of the bit-field itself.
+
+        This simple rule makes it obvious why GCC allocates 8 bytes for
+        each object of the structure type shown above.  When looking
+        for a place to allocate the "containing object" for `field2',
+        the compiler simply tries to allocate a 64-bit "containing
+        object" at each successive 32-bit boundary (starting at zero)
+        until it finds a place to allocate that 64- bit field such that
+        at least 31 contiguous (and previously unallocated) bits remain
+        within that selected 64 bit field.  (As it turns out, for the
+        example above, the compiler finds it is OK to allocate the
+        "containing object" 64-bit field at bit-offset zero within the
+        structure type.)
+
+        Here we attempt to work backwards from the limited set of facts
+        we're given, and we try to deduce from those facts, where GCC
+        must have believed that the containing object started (within
+        the structure type). The value we deduce is then used (by the
+        callers of this routine) to generate DW_AT_location and
+        DW_AT_bit_offset attributes for fields (both bit-fields and, in
+        the case of DW_AT_location, regular fields as well).  */
+
+      /* Figure out the bit-distance from the start of the structure to
+        the "deepest" bit of the bit-field.  */
+      deepest_bitpos = double_int_add (bitpos_int, field_size_in_bits);
+
+      /* This is the tricky part.  Use some fancy footwork to deduce
+        where the lowest addressed bit of the containing object must
+        be.  */
+      object_offset_in_bits
+       = double_int_sub (deepest_bitpos, type_size_in_bits);
+
+      /* Round up to type_align by default.  This works best for
+        bitfields.  */
+      object_offset_in_bits
+       = round_up_to_align (object_offset_in_bits, type_align_in_bits);
+
+      if (double_int_ucmp (object_offset_in_bits, bitpos_int) > 0)
        {
-         /* Variable offset.  */
-         list_ret1 = loc_list_from_tree (offset, 0);
-         if (list_ret1 == 0)
-           return 0;
-         add_loc_list (&list_ret, list_ret1);
-         if (!list_ret)
-           return 0;
-         add_loc_descr_to_each (list_ret,
-                                new_loc_descr (DW_OP_plus, 0, 0));
+         object_offset_in_bits
+           = double_int_sub (deepest_bitpos, type_size_in_bits);
+
+         /* Round up to decl_align instead.  */
+         object_offset_in_bits
+           = round_up_to_align (object_offset_in_bits, decl_align_in_bits);
        }
-      bytepos = bitpos / BITS_PER_UNIT;
-      if (bytepos > 0)
-       add_loc_descr_to_each (list_ret,
-                              new_loc_descr (DW_OP_plus_uconst,
-                                             bytepos, 0));
-      else if (bytepos < 0)
-       loc_list_plus_const (list_ret, bytepos);
-      add_loc_descr_to_each (list_ret,
-                            new_loc_descr (DW_OP_stack_value, 0, 0));
     }
-  return list_ret;
+  else
+#endif /* PCC_BITFIELD_TYPE_MATTERS */
+    object_offset_in_bits = bitpos_int;
+
+  object_offset_in_bytes
+    = double_int_div (object_offset_in_bits,
+                     uhwi_to_double_int (BITS_PER_UNIT), true,
+                     TRUNC_DIV_EXPR);
+  return double_int_to_shwi (object_offset_in_bytes);
 }
+\f
+/* The following routines define various Dwarf attributes and any data
+   associated with them.  */
 
+/* Add a location description attribute value to a DIE.
 
-/* Generate Dwarf location list representing LOC.
-   If WANT_ADDRESS is false, expression computing LOC will be computed
-   If WANT_ADDRESS is 1, expression computing address of LOC will be returned
-   if WANT_ADDRESS is 2, expression computing address useable in location
-     will be returned (i.e. DW_OP_reg can be used
-     to refer to register values).  */
+   This emits location attributes suitable for whole variables and
+   whole parameters.  Note that the location attributes for struct fields are
+   generated by the routine `data_member_location_attribute' below.  */
 
-static dw_loc_list_ref
-loc_list_from_tree (tree loc, int want_address)
+static inline void
+add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
+                            dw_loc_list_ref descr)
 {
-  dw_loc_descr_ref ret = NULL, ret1 = NULL;
-  dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
-  int have_address = 0;
-  enum dwarf_location_atom op;
+  if (descr == 0)
+    return;
+  if (single_element_loc_list_p (descr))
+    add_AT_loc (die, attr_kind, descr->expr);
+  else
+    add_AT_loc_list (die, attr_kind, descr);
+}
 
-  /* ??? Most of the time we do not take proper care for sign/zero
-     extending the values properly.  Hopefully this won't be a real
-     problem...  */
+/* Add DW_AT_accessibility attribute to DIE if needed.  */
 
-  switch (TREE_CODE (loc))
+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))
     {
-    case ERROR_MARK:
-      expansion_failed (loc, NULL_RTX, "ERROR_MARK");
-      return 0;
+      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);
+}
 
-    case PLACEHOLDER_EXPR:
-      /* This case involves extracting fields from an object to determine the
-        position of other fields.  We don't try to encode this here.  The
-        only user of this is Ada, which encodes the needed information using
-        the names of types.  */
-      expansion_failed (loc, NULL_RTX, "PLACEHOLDER_EXPR");
-      return 0;
+/* Attach the specialized form of location attribute used for data members of
+   struct and union types.  In the special case of a FIELD_DECL node which
+   represents a bit-field, the "offset" part of this special location
+   descriptor must indicate the distance in bytes from the lowest-addressed
+   byte of the containing struct or union type to the lowest-addressed byte of
+   the "containing object" for the bit-field.  (See the `field_byte_offset'
+   function above).
 
-    case CALL_EXPR:
-      expansion_failed (loc, NULL_RTX, "CALL_EXPR");
-      /* There are no opcodes for these operations.  */
-      return 0;
+   For any given bit-field, the "containing object" is a hypothetical object
+   (of some integral or enum type) within which the given bit-field lives.  The
+   type of this hypothetical "containing object" is always the same as the
+   declared type of the individual bit-field itself (for GCC anyway... the
+   DWARF spec doesn't actually mandate this).  Note that it is the size (in
+   bytes) of the hypothetical "containing object" which will be given in the
+   DW_AT_byte_size attribute for this bit-field.  (See the
+   `byte_size_attribute' function below.)  It is also used when calculating the
+   value of the DW_AT_bit_offset attribute.  (See the `bit_offset_attribute'
+   function below.)  */
 
-    case PREINCREMENT_EXPR:
-    case PREDECREMENT_EXPR:
-    case POSTINCREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-      expansion_failed (loc, NULL_RTX, "PRE/POST INDCREMENT/DECREMENT");
-      /* There are no opcodes for these operations.  */
-      return 0;
+static void
+add_data_member_location_attribute (dw_die_ref die, tree decl)
+{
+  HOST_WIDE_INT offset;
+  dw_loc_descr_ref loc_descr = 0;
 
-    case ADDR_EXPR:
-      /* If we already want an address, see if there is INDIRECT_REF inside
-         e.g. for &this->field.  */
-      if (want_address)
-       {
-         list_ret = loc_list_for_address_of_addr_expr_of_indirect_ref
-                      (loc, want_address == 2);
-         if (list_ret)
-           have_address = 1;
-         else if (decl_address_ip_invariant_p (TREE_OPERAND (loc, 0))
-                  && (ret = cst_pool_loc_descr (loc)))
-           have_address = 1;
-       }
-        /* Otherwise, process the argument and look for the address.  */
-      if (!list_ret && !ret)
-        list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 1);
-      else
+  if (TREE_CODE (decl) == TREE_BINFO)
+    {
+      /* We're working on the TAG_inheritance for a base class.  */
+      if (BINFO_VIRTUAL_P (decl) && is_cxx ())
        {
-         if (want_address)
-           expansion_failed (loc, NULL_RTX, "need address of ADDR_EXPR");
-         return NULL;
-       }
-      break;
+         /* For C++ virtual bases we can't just use BINFO_OFFSET, as they
+            aren't at a fixed offset from all (sub)objects of the same
+            type.  We need to extract the appropriate offset from our
+            vtable.  The following dwarf expression means
 
-    case VAR_DECL:
-      if (DECL_THREAD_LOCAL_P (loc))
-       {
-         rtx rtl;
-         enum dwarf_location_atom first_op;
-         enum dwarf_location_atom second_op;
-         bool dtprel = false;
+              BaseAddr = ObAddr + *((*ObAddr) - Offset)
 
-         if (targetm.have_tls)
-           {
-             /* If this is not defined, we have no way to emit the
-                data.  */
-             if (!targetm.asm_out.output_dwarf_dtprel)
-               return 0;
+            This is specific to the V3 ABI, of course.  */
 
-              /* The way DW_OP_GNU_push_tls_address is specified, we
-                 can only look up addresses of objects in the current
-                 module.  */
-             if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
-               return 0;
-             first_op = DW_OP_addr;
-             dtprel = true;
-             second_op = DW_OP_GNU_push_tls_address;
-           }
-         else
-           {
-             if (!targetm.emutls.debug_form_tls_address
-                 || !(dwarf_version >= 3 || !dwarf_strict))
-               return 0;
-             loc = emutls_decl (loc);
-             first_op = DW_OP_addr;
-             second_op = DW_OP_form_tls_address;
-           }
+         dw_loc_descr_ref tmp;
 
-         rtl = rtl_for_decl_location (loc);
-         if (rtl == NULL_RTX)
-           return 0;
+         /* Make a copy of the object address.  */
+         tmp = new_loc_descr (DW_OP_dup, 0, 0);
+         add_loc_descr (&loc_descr, tmp);
 
-         if (!MEM_P (rtl))
-           return 0;
-         rtl = XEXP (rtl, 0);
-         if (! CONSTANT_P (rtl))
-           return 0;
+         /* Extract the vtable address.  */
+         tmp = new_loc_descr (DW_OP_deref, 0, 0);
+         add_loc_descr (&loc_descr, tmp);
 
-         ret = new_loc_descr (first_op, 0, 0);
-         ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
-         ret->dw_loc_oprnd1.v.val_addr = rtl;
-         ret->dtprel = dtprel;
+         /* Calculate the address of the offset.  */
+         offset = tree_low_cst (BINFO_VPTR_FIELD (decl), 0);
+         gcc_assert (offset < 0);
 
-         ret1 = new_loc_descr (second_op, 0, 0);
-         add_loc_descr (&ret, ret1);
+         tmp = int_loc_descriptor (-offset);
+         add_loc_descr (&loc_descr, tmp);
+         tmp = new_loc_descr (DW_OP_minus, 0, 0);
+         add_loc_descr (&loc_descr, tmp);
 
-         have_address = 1;
-         break;
+         /* Extract the offset.  */
+         tmp = new_loc_descr (DW_OP_deref, 0, 0);
+         add_loc_descr (&loc_descr, tmp);
+
+         /* Add it to the object address.  */
+         tmp = new_loc_descr (DW_OP_plus, 0, 0);
+         add_loc_descr (&loc_descr, tmp);
        }
-      /* FALLTHRU */
+      else
+       offset = tree_low_cst (BINFO_OFFSET (decl), 0);
+    }
+  else
+    offset = field_byte_offset (decl);
 
-    case PARM_DECL:
-      if (DECL_HAS_VALUE_EXPR_P (loc))
-       return loc_list_from_tree (DECL_VALUE_EXPR (loc),
-                                  want_address);
-      /* FALLTHRU */
+  if (! loc_descr)
+    {
+      if (dwarf_version > 2)
+       {
+         /* Don't need to output a location expression, just the constant. */
+         if (offset < 0)
+           add_AT_int (die, DW_AT_data_member_location, offset);
+         else
+           add_AT_unsigned (die, DW_AT_data_member_location, offset);
+         return;
+       }
+      else
+       {
+         enum dwarf_location_atom op;
 
-    case RESULT_DECL:
-    case FUNCTION_DECL:
-      {
-       rtx rtl;
-       var_loc_list *loc_list = lookup_decl_loc (loc);
+         /* The DWARF2 standard says that we should assume that the structure
+            address is already on the stack, so we can specify a structure
+            field address by using DW_OP_plus_uconst.  */
 
-       if (loc_list && loc_list->first)
-         {
-           list_ret = dw_loc_list (loc_list, loc, want_address);
-           have_address = want_address != 0;
-           break;
-         }
-       rtl = rtl_for_decl_location (loc);
-       if (rtl == NULL_RTX)
-         {
-           expansion_failed (loc, NULL_RTX, "DECL has no RTL");
-           return 0;
-         }
-       else if (CONST_INT_P (rtl))
-         {
-           HOST_WIDE_INT val = INTVAL (rtl);
-           if (TYPE_UNSIGNED (TREE_TYPE (loc)))
-             val &= GET_MODE_MASK (DECL_MODE (loc));
-           ret = int_loc_descriptor (val);
-         }
-       else if (GET_CODE (rtl) == CONST_STRING)
-         {
-           expansion_failed (loc, NULL_RTX, "CONST_STRING");
-           return 0;
-         }
-       else if (CONSTANT_P (rtl) && const_ok_for_output (rtl))
-         {
-           ret = new_loc_descr (DW_OP_addr, 0, 0);
-           ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
-           ret->dw_loc_oprnd1.v.val_addr = rtl;
-         }
-       else
-         {
-           enum machine_mode mode;
+#ifdef MIPS_DEBUGGING_INFO
+         /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst
+            operator correctly.  It works only if we leave the offset on the
+            stack.  */
+         op = DW_OP_constu;
+#else
+         op = DW_OP_plus_uconst;
+#endif
+
+         loc_descr = new_loc_descr (op, offset, 0);
+       }
+    }
 
-           /* Certain constructs can only be represented at top-level.  */
-           if (want_address == 2)
-             {
-               ret = loc_descriptor (rtl, VOIDmode,
-                                     VAR_INIT_STATUS_INITIALIZED);
-               have_address = 1;
-             }
-           else
-             {
-               mode = GET_MODE (rtl);
-               if (MEM_P (rtl))
-                 {
-                   rtl = XEXP (rtl, 0);
-                   have_address = 1;
-                 }
-               ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
-             }
-           if (!ret)
-             expansion_failed (loc, rtl,
-                               "failed to produce loc descriptor for rtl");
-         }
-      }
-      break;
+  add_AT_loc (die, DW_AT_data_member_location, loc_descr);
+}
 
-    case INDIRECT_REF:
-    case ALIGN_INDIRECT_REF:
-    case MISALIGNED_INDIRECT_REF:
-      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
-      have_address = 1;
-      break;
+/* Writes integer values to dw_vec_const array.  */
 
-    case COMPOUND_EXPR:
-      return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address);
+static void
+insert_int (HOST_WIDE_INT val, unsigned int size, unsigned char *dest)
+{
+  while (size != 0)
+    {
+      *dest++ = val & 0xff;
+      val >>= 8;
+      --size;
+    }
+}
 
-    CASE_CONVERT:
-    case VIEW_CONVERT_EXPR:
-    case SAVE_EXPR:
-    case MODIFY_EXPR:
-      return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address);
+/* Reads integers from dw_vec_const array.  Inverse of insert_int.  */
 
-    case COMPONENT_REF:
-    case BIT_FIELD_REF:
-    case ARRAY_REF:
-    case ARRAY_RANGE_REF:
-    case REALPART_EXPR:
-    case IMAGPART_EXPR:
-      {
-       tree obj, offset;
-       HOST_WIDE_INT bitsize, bitpos, bytepos;
-       enum machine_mode mode;
-       int volatilep;
-       int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
+static HOST_WIDE_INT
+extract_int (const unsigned char *src, unsigned int size)
+{
+  HOST_WIDE_INT val = 0;
 
-       obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
-                                  &unsignedp, &volatilep, false);
+  src += size;
+  while (size != 0)
+    {
+      val <<= 8;
+      val |= *--src & 0xff;
+      --size;
+    }
+  return val;
+}
 
-       gcc_assert (obj != loc);
+/* Writes double_int values to dw_vec_const array.  */
 
-       list_ret = loc_list_from_tree (obj,
-                                      want_address == 2
-                                      && !bitpos && !offset ? 2 : 1);
-       /* TODO: We can extract value of the small expression via shifting even
-          for nonzero bitpos.  */
-       if (list_ret == 0)
-         return 0;
-       if (bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0)
-         {
-           expansion_failed (loc, NULL_RTX,
-                             "bitfield access");
-           return 0;
-         }
+static void
+insert_double (double_int val, unsigned char *dest)
+{
+  unsigned char *p0 = dest;
+  unsigned char *p1 = dest + sizeof (HOST_WIDE_INT);
 
-       if (offset != NULL_TREE)
-         {
-           /* Variable offset.  */
-           list_ret1 = loc_list_from_tree (offset, 0);
-           if (list_ret1 == 0)
-             return 0;
-           add_loc_list (&list_ret, list_ret1);
-           if (!list_ret)
-             return 0;
-           add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus, 0, 0));
-         }
+  if (WORDS_BIG_ENDIAN)
+    {
+      p0 = p1;
+      p1 = dest;
+    }
 
-       bytepos = bitpos / BITS_PER_UNIT;
-       if (bytepos > 0)
-         add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0));
-       else if (bytepos < 0)
-         loc_list_plus_const (list_ret, bytepos);
+  insert_int ((HOST_WIDE_INT) val.low, sizeof (HOST_WIDE_INT), p0);
+  insert_int ((HOST_WIDE_INT) val.high, sizeof (HOST_WIDE_INT), p1);
+}
 
-       have_address = 1;
-       break;
-      }
+/* Writes floating point values to dw_vec_const array.  */
 
-    case INTEGER_CST:
-      if ((want_address || !host_integerp (loc, 0))
-         && (ret = cst_pool_loc_descr (loc)))
-       have_address = 1;
-      else if (want_address == 2
-              && host_integerp (loc, 0)
-              && (ret = address_of_int_loc_descriptor
-                          (int_size_in_bytes (TREE_TYPE (loc)),
-                           tree_low_cst (loc, 0))))
-       have_address = 1;
-      else if (host_integerp (loc, 0))
-       ret = int_loc_descriptor (tree_low_cst (loc, 0));
-      else
-       {
-         expansion_failed (loc, NULL_RTX,
-                           "Integer operand is not host integer");
-         return 0;
-       }
-      break;
+static void
+insert_float (const_rtx rtl, unsigned char *array)
+{
+  REAL_VALUE_TYPE rv;
+  long val[4];
+  int i;
 
-    case CONSTRUCTOR:
-    case REAL_CST:
-    case STRING_CST:
-    case COMPLEX_CST:
-      if ((ret = cst_pool_loc_descr (loc)))
-       have_address = 1;
-      else
-      /* We can construct small constants here using int_loc_descriptor.  */
-       expansion_failed (loc, NULL_RTX,
-                         "constructor or constant not in constant pool");
-      break;
+  REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
+  real_to_target (val, &rv, GET_MODE (rtl));
 
-    case TRUTH_AND_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case BIT_AND_EXPR:
-      op = DW_OP_and;
-      goto do_binop;
+  /* real_to_target puts 32-bit pieces in each long.  Pack them.  */
+  for (i = 0; i < GET_MODE_SIZE (GET_MODE (rtl)) / 4; i++)
+    {
+      insert_int (val[i], 4, array);
+      array += 4;
+    }
+}
 
-    case TRUTH_XOR_EXPR:
-    case BIT_XOR_EXPR:
-      op = DW_OP_xor;
-      goto do_binop;
+/* Attach a DW_AT_const_value attribute for a variable or a parameter which
+   does not have a "location" either in memory or in a register.  These
+   things can arise in GNU C when a constant is passed as an actual parameter
+   to an inlined function.  They can also arise in C++ where declared
+   constants do not necessarily get memory "homes".  */
 
-    case TRUTH_OR_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case BIT_IOR_EXPR:
-      op = DW_OP_or;
-      goto do_binop;
+static bool
+add_const_value_attribute (dw_die_ref die, rtx rtl)
+{
+  switch (GET_CODE (rtl))
+    {
+    case CONST_INT:
+      {
+       HOST_WIDE_INT val = INTVAL (rtl);
 
-    case FLOOR_DIV_EXPR:
-    case CEIL_DIV_EXPR:
-    case ROUND_DIV_EXPR:
-    case TRUNC_DIV_EXPR:
-      if (TYPE_UNSIGNED (TREE_TYPE (loc)))
-       return 0;
-      op = DW_OP_div;
-      goto do_binop;
+       if (val < 0)
+         add_AT_int (die, DW_AT_const_value, val);
+       else
+         add_AT_unsigned (die, DW_AT_const_value, (unsigned HOST_WIDE_INT) val);
+      }
+      return true;
 
-    case MINUS_EXPR:
-      op = DW_OP_minus;
-      goto do_binop;
+    case CONST_DOUBLE:
+      /* Note that a CONST_DOUBLE rtx could represent either an integer or a
+        floating-point constant.  A CONST_DOUBLE is used whenever the
+        constant requires more than one word in order to be adequately
+        represented.  */
+      {
+       enum machine_mode mode = GET_MODE (rtl);
 
-    case FLOOR_MOD_EXPR:
-    case CEIL_MOD_EXPR:
-    case ROUND_MOD_EXPR:
-    case TRUNC_MOD_EXPR:
-      if (TYPE_UNSIGNED (TREE_TYPE (loc)))
-       {
-         op = DW_OP_mod;
-         goto do_binop;
-       }
-      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
-      list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0);
-      if (list_ret == 0 || list_ret1 == 0)
-       return 0;
+       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);
+           add_AT_vec (die, DW_AT_const_value, length / 4, 4, array);
+         }
+       else
+         add_AT_double (die, DW_AT_const_value,
+                        CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
+      }
+      return true;
+
+    case CONST_VECTOR:
+      {
+       enum machine_mode mode = GET_MODE (rtl);
+       unsigned int elt_size = GET_MODE_UNIT_SIZE (mode);
+       unsigned int length = CONST_VECTOR_NUNITS (rtl);
+       unsigned char *array = (unsigned char *) ggc_alloc_atomic
+         (length * elt_size);
+       unsigned int i;
+       unsigned char *p;
+
+       switch (GET_MODE_CLASS (mode))
+         {
+         case MODE_VECTOR_INT:
+           for (i = 0, p = array; i < length; i++, p += elt_size)
+             {
+               rtx elt = CONST_VECTOR_ELT (rtl, i);
+               double_int val = rtx_to_double_int (elt);
 
-      add_loc_list (&list_ret, list_ret1);
-      if (list_ret == 0)
-       return 0;
-      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_over, 0, 0));
-      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_over, 0, 0));
-      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_div, 0, 0));
-      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_mul, 0, 0));
-      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_minus, 0, 0));
-      break;
+               if (elt_size <= sizeof (HOST_WIDE_INT))
+                 insert_int (double_int_to_shwi (val), elt_size, p);
+               else
+                 {
+                   gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
+                   insert_double (val, p);
+                 }
+             }
+           break;
 
-    case MULT_EXPR:
-      op = DW_OP_mul;
-      goto do_binop;
+         case MODE_VECTOR_FLOAT:
+           for (i = 0, p = array; i < length; i++, p += elt_size)
+             {
+               rtx elt = CONST_VECTOR_ELT (rtl, i);
+               insert_float (elt, p);
+             }
+           break;
 
-    case LSHIFT_EXPR:
-      op = DW_OP_shl;
-      goto do_binop;
+         default:
+           gcc_unreachable ();
+         }
 
-    case RSHIFT_EXPR:
-      op = (TYPE_UNSIGNED (TREE_TYPE (loc)) ? DW_OP_shr : DW_OP_shra);
-      goto do_binop;
+       add_AT_vec (die, DW_AT_const_value, length, elt_size, array);
+      }
+      return true;
 
-    case POINTER_PLUS_EXPR:
-    case PLUS_EXPR:
-      if (TREE_CODE (TREE_OPERAND (loc, 1)) == INTEGER_CST
-         && host_integerp (TREE_OPERAND (loc, 1), 0))
+    case CONST_STRING:
+      if (dwarf_version >= 4 || !dwarf_strict)
        {
-         list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
-         if (list_ret == 0)
-           return 0;
-
-         loc_list_plus_const (list_ret, tree_low_cst (TREE_OPERAND (loc, 1), 0));
-         break;
+         dw_loc_descr_ref loc_result;
+         resolve_one_addr (&rtl, NULL);
+       rtl_addr:
+         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
+         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
+         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+         add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
+         add_AT_loc (die, DW_AT_location, loc_result);
+         VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+         return true;
        }
+      return false;
 
-      op = DW_OP_plus;
-      goto do_binop;
-
-    case LE_EXPR:
-      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
-       return 0;
+    case CONST:
+      if (CONSTANT_P (XEXP (rtl, 0)))
+       return add_const_value_attribute (die, XEXP (rtl, 0));
+      /* FALLTHROUGH */
+    case SYMBOL_REF:
+      if (!const_ok_for_output (rtl))
+       return false;
+    case LABEL_REF:
+      if (dwarf_version >= 4 || !dwarf_strict)
+       goto rtl_addr;
+      return false;
 
-      op = DW_OP_le;
-      goto do_binop;
+    case PLUS:
+      /* In cases where an inlined instance of an inline function is passed
+        the address of an `auto' variable (which is local to the caller) we
+        can get a situation where the DECL_RTL of the artificial local
+        variable (for the inlining) which acts as a stand-in for the
+        corresponding formal parameter (of the inline function) will look
+        like (plus:SI (reg:SI FRAME_PTR) (const_int ...)).  This is not
+        exactly a compile-time constant expression, but it isn't the address
+        of the (artificial) local variable either.  Rather, it represents the
+        *value* which the artificial local variable always has during its
+        lifetime.  We currently have no way to represent such quasi-constant
+        values in Dwarf, so for now we just punt and generate nothing.  */
+      return false;
 
-    case GE_EXPR:
-      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
-       return 0;
+    case HIGH:
+    case CONST_FIXED:
+      return false;
 
-      op = DW_OP_ge;
-      goto do_binop;
+    case MEM:
+      if (GET_CODE (XEXP (rtl, 0)) == CONST_STRING
+         && MEM_READONLY_P (rtl)
+         && GET_MODE (rtl) == BLKmode)
+       {
+         add_AT_string (die, DW_AT_const_value, XSTR (XEXP (rtl, 0), 0));
+         return true;
+       }
+      return false;
 
-    case LT_EXPR:
-      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
-       return 0;
+    default:
+      /* No other kinds of rtx should be possible here.  */
+      gcc_unreachable ();
+    }
+  return false;
+}
 
-      op = DW_OP_lt;
-      goto do_binop;
+/* Determine whether the evaluation of EXPR references any variables
+   or functions which aren't otherwise used (and therefore may not be
+   output).  */
+static tree
+reference_to_unused (tree * tp, int * walk_subtrees,
+                    void * data ATTRIBUTE_UNUSED)
+{
+  if (! EXPR_P (*tp) && ! CONSTANT_CLASS_P (*tp))
+    *walk_subtrees = 0;
 
-    case GT_EXPR:
-      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
-       return 0;
+  if (DECL_P (*tp) && ! TREE_PUBLIC (*tp) && ! TREE_USED (*tp)
+      && ! TREE_ASM_WRITTEN (*tp))
+    return *tp;
+  /* ???  The C++ FE emits debug information for using decls, so
+     putting gcc_unreachable here falls over.  See PR31899.  For now
+     be conservative.  */
+  else if (!cgraph_global_info_ready
+          && (TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == FUNCTION_DECL))
+    return *tp;
+  else if (TREE_CODE (*tp) == VAR_DECL)
+    {
+      struct varpool_node *node = varpool_get_node (*tp);
+      if (!node || !node->needed)
+       return *tp;
+    }
+  else if (TREE_CODE (*tp) == FUNCTION_DECL
+          && (!DECL_EXTERNAL (*tp) || DECL_DECLARED_INLINE_P (*tp)))
+    {
+      /* The call graph machinery must have finished analyzing,
+         optimizing and gimplifying the CU by now.
+        So if *TP has no call graph node associated
+        to it, it means *TP will not be emitted.  */
+      if (!cgraph_get_node (*tp))
+       return *tp;
+    }
+  else if (TREE_CODE (*tp) == STRING_CST && !TREE_ASM_WRITTEN (*tp))
+    return *tp;
 
-      op = DW_OP_gt;
-      goto do_binop;
+  return NULL_TREE;
+}
 
-    case EQ_EXPR:
-      op = DW_OP_eq;
-      goto do_binop;
+/* Generate an RTL constant from a decl initializer INIT with decl type TYPE,
+   for use in a later add_const_value_attribute call.  */
 
-    case NE_EXPR:
-      op = DW_OP_ne;
-      goto do_binop;
+static rtx
+rtl_for_decl_init (tree init, tree type)
+{
+  rtx rtl = NULL_RTX;
 
-    do_binop:
-      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
-      list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0);
-      if (list_ret == 0 || list_ret1 == 0)
-       return 0;
+  STRIP_NOPS (init);
 
-      add_loc_list (&list_ret, list_ret1);
-      if (list_ret == 0)
-       return 0;
-      add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0));
-      break;
+  /* 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)
+    {
+      tree enttype = TREE_TYPE (type);
+      tree domain = TYPE_DOMAIN (type);
+      enum machine_mode mode = TYPE_MODE (enttype);
 
-    case TRUTH_NOT_EXPR:
-    case BIT_NOT_EXPR:
-      op = DW_OP_not;
-      goto do_unop;
+      if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == 1
+         && domain
+         && integer_zerop (TYPE_MIN_VALUE (domain))
+         && compare_tree_int (TYPE_MAX_VALUE (domain),
+                              TREE_STRING_LENGTH (init) - 1) == 0
+         && ((size_t) TREE_STRING_LENGTH (init)
+             == strlen (TREE_STRING_POINTER (init)) + 1))
+       {
+         rtl = gen_rtx_CONST_STRING (VOIDmode,
+                                     ggc_strdup (TREE_STRING_POINTER (init)));
+         rtl = gen_rtx_MEM (BLKmode, rtl);
+         MEM_READONLY_P (rtl) = 1;
+       }
+    }
+  /* Other aggregates, and complex values, could be represented using
+     CONCAT: FIXME!  */
+  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
+          && !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
+     reference variables which won't be output.  */
+  else if (initializer_constant_valid_p (init, type)
+          && ! walk_tree (&init, reference_to_unused, NULL, NULL))
+    {
+      /* Convert vector CONSTRUCTOR initializers to VECTOR_CST if
+        possible.  */
+      if (TREE_CODE (type) == VECTOR_TYPE)
+       switch (TREE_CODE (init))
+         {
+         case VECTOR_CST:
+           break;
+         case CONSTRUCTOR:
+           if (TREE_CONSTANT (init))
+             {
+               VEC(constructor_elt,gc) *elts = CONSTRUCTOR_ELTS (init);
+               bool constant_p = true;
+               tree value;
+               unsigned HOST_WIDE_INT ix;
 
-    case ABS_EXPR:
-      op = DW_OP_abs;
-      goto do_unop;
+               /* Even when ctor is constant, it might contain non-*_CST
+                  elements (e.g. { 1.0/0.0 - 1.0/0.0, 0.0 }) and those don't
+                  belong into VECTOR_CST nodes.  */
+               FOR_EACH_CONSTRUCTOR_VALUE (elts, ix, value)
+                 if (!CONSTANT_CLASS_P (value))
+                   {
+                     constant_p = false;
+                     break;
+                   }
 
-    case NEGATE_EXPR:
-      op = DW_OP_neg;
-      goto do_unop;
+               if (constant_p)
+                 {
+                   init = build_vector_from_ctor (type, elts);
+                   break;
+                 }
+             }
+           /* FALLTHRU */
 
-    do_unop:
-      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
-      if (list_ret == 0)
-       return 0;
+         default:
+           return NULL;
+         }
 
-      add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0));
-      break;
+      rtl = expand_expr (init, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
 
-    case MIN_EXPR:
-    case MAX_EXPR:
-      {
-       const enum tree_code code =
-         TREE_CODE (loc) == MIN_EXPR ? GT_EXPR : LT_EXPR;
+      /* If expand_expr returns a MEM, it wasn't immediate.  */
+      gcc_assert (!rtl || !MEM_P (rtl));
+    }
 
-       loc = build3 (COND_EXPR, TREE_TYPE (loc),
-                     build2 (code, integer_type_node,
-                             TREE_OPERAND (loc, 0), TREE_OPERAND (loc, 1)),
-                     TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
-      }
+  return rtl;
+}
 
-      /* ... fall through ...  */
+/* Generate RTL for the variable DECL to represent its location.  */
 
-    case COND_EXPR:
-      {
-       dw_loc_descr_ref lhs
-         = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
-       dw_loc_list_ref rhs
-         = loc_list_from_tree (TREE_OPERAND (loc, 2), 0);
-       dw_loc_descr_ref bra_node, jump_node, tmp;
+static rtx
+rtl_for_decl_location (tree decl)
+{
+  rtx rtl;
 
-       list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
-       if (list_ret == 0 || lhs == 0 || rhs == 0)
-         return 0;
+  /* Here we have to decide where we are going to say the parameter "lives"
+     (as far as the debugger is concerned).  We only have a couple of
+     choices.  GCC provides us with DECL_RTL and with DECL_INCOMING_RTL.
 
-       bra_node = new_loc_descr (DW_OP_bra, 0, 0);
-       add_loc_descr_to_each (list_ret, bra_node);
+     DECL_RTL normally indicates where the parameter lives during most of the
+     activation of the function.  If optimization is enabled however, this
+     could be either NULL or else a pseudo-reg.  Both of those cases indicate
+     that the parameter doesn't really live anywhere (as far as the code
+     generation parts of GCC are concerned) during most of the function's
+     activation.  That will happen (for example) if the parameter is never
+     referenced within the function.
 
-       add_loc_list (&list_ret, rhs);
-       jump_node = new_loc_descr (DW_OP_skip, 0, 0);
-       add_loc_descr_to_each (list_ret, jump_node);
+     We could just generate a location descriptor here for all non-NULL
+     non-pseudo values of DECL_RTL and ignore all of the rest, but we can be
+     a little nicer than that if we also consider DECL_INCOMING_RTL in cases
+     where DECL_RTL is NULL or is a pseudo-reg.
 
-       add_loc_descr_to_each (list_ret, lhs);
-       bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
-       bra_node->dw_loc_oprnd1.v.val_loc = lhs;
+     Note however that we can only get away with using DECL_INCOMING_RTL as
+     a backup substitute for DECL_RTL in certain limited cases.  In cases
+     where DECL_ARG_TYPE (decl) indicates the same type as TREE_TYPE (decl),
+     we can be sure that the parameter was passed using the same type as it is
+     declared to have within the function, and that its DECL_INCOMING_RTL
+     points us to a place where a value of that type is passed.
 
-       /* ??? Need a node to point the skip at.  Use a nop.  */
-       tmp = new_loc_descr (DW_OP_nop, 0, 0);
-       add_loc_descr_to_each (list_ret, tmp);
-       jump_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
-       jump_node->dw_loc_oprnd1.v.val_loc = tmp;
-      }
-      break;
+     In cases where DECL_ARG_TYPE (decl) and TREE_TYPE (decl) are different,
+     we cannot (in general) use DECL_INCOMING_RTL as a substitute for DECL_RTL
+     because in these cases DECL_INCOMING_RTL points us to a value of some
+     type which is *different* from the type of the parameter itself.  Thus,
+     if we tried to use DECL_INCOMING_RTL to generate a location attribute in
+     such cases, the debugger would end up (for example) trying to fetch a
+     `float' from a place which actually contains the first part of a
+     `double'.  That would lead to really incorrect and confusing
+     output at debug-time.
 
-    case FIX_TRUNC_EXPR:
-      return 0;
+     So, in general, we *do not* use DECL_INCOMING_RTL as a backup for DECL_RTL
+     in cases where DECL_ARG_TYPE (decl) != TREE_TYPE (decl).  There
+     are a couple of exceptions however.  On little-endian machines we can
+     get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE (decl) is
+     not the same as TREE_TYPE (decl), but only when DECL_ARG_TYPE (decl) is
+     an integral type that is smaller than TREE_TYPE (decl). These cases arise
+     when (on a little-endian machine) a non-prototyped function has a
+     parameter declared to be of type `short' or `char'.  In such cases,
+     TREE_TYPE (decl) will be `short' or `char', DECL_ARG_TYPE (decl) will
+     be `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the
+     passed `int' value.  If the debugger then uses that address to fetch
+     a `short' or a `char' (on a little-endian machine) the result will be
+     the correct data, so we allow for such exceptional cases below.
 
-    default:
-      /* Leave front-end specific codes as simply unknown.  This comes
-        up, for instance, with the C STMT_EXPR.  */
-      if ((unsigned int) TREE_CODE (loc)
-         >= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
-       {
-         expansion_failed (loc, NULL_RTX,
-                           "language specific tree node");
-         return 0;
-       }
+     Note that our goal here is to describe the place where the given formal
+     parameter lives during most of the function's activation (i.e. between the
+     end of the prologue and the start of the epilogue).  We'll do that as best
+     as we can. Note however that if the given formal parameter is modified
+     sometime during the execution of the function, then a stack backtrace (at
+     debug-time) will show the function as having been called with the *new*
+     value rather than the value which was originally passed in.  This happens
+     rarely enough that it is not a major problem, but it *is* a problem, and
+     I'd like to fix it.
 
-#ifdef ENABLE_CHECKING
-      /* Otherwise this is a generic code; we should just lists all of
-        these explicitly.  We forgot one.  */
-      gcc_unreachable ();
-#else
-      /* In a release build, we want to degrade gracefully: better to
-        generate incomplete debugging information than to crash.  */
-      return NULL;
-#endif
-    }
+     A future version of dwarf2out.c may generate two additional attributes for
+     any given DW_TAG_formal_parameter DIE which will describe the "passed
+     type" and the "passed location" for the given formal parameter in addition
+     to the attributes we now generate to indicate the "declared type" and the
+     "active location" for each parameter.  This additional set of attributes
+     could be used by debuggers for stack backtraces. Separately, note that
+     sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL can be NULL also.
+     This happens (for example) for inlined-instances of inline function formal
+     parameters which are never referenced.  This really shouldn't be
+     happening.  All PARM_DECL nodes should get valid non-NULL
+     DECL_INCOMING_RTL values.  FIXME.  */
 
-  if (!ret && !list_ret)
-    return 0;
+  /* Use DECL_RTL as the "location" unless we find something better.  */
+  rtl = DECL_RTL_IF_SET (decl);
 
-  if (want_address == 2 && !have_address
-      && (dwarf_version >= 4 || !dwarf_strict))
+  /* When generating abstract instances, ignore everything except
+     constants, symbols living in memory, and symbols living in
+     fixed registers.  */
+  if (! reload_completed)
     {
-      if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE)
+      if (rtl
+         && (CONSTANT_P (rtl)
+             || (MEM_P (rtl)
+                 && CONSTANT_P (XEXP (rtl, 0)))
+             || (REG_P (rtl)
+                 && TREE_CODE (decl) == VAR_DECL
+                 && TREE_STATIC (decl))))
        {
-         expansion_failed (loc, NULL_RTX,
-                           "DWARF address size mismatch");
-         return 0;
+         rtl = targetm.delegitimize_address (rtl);
+         return rtl;
        }
-      if (ret)
-       add_loc_descr (&ret, new_loc_descr (DW_OP_stack_value, 0, 0));
-      else
-       add_loc_descr_to_each (list_ret,
-                              new_loc_descr (DW_OP_stack_value, 0, 0));
-      have_address = 1;
+      rtl = NULL_RTX;
     }
-  /* Show if we can't fill the request for an address.  */
-  if (want_address && !have_address)
+  else if (TREE_CODE (decl) == PARM_DECL)
     {
-      expansion_failed (loc, NULL_RTX,
-                       "Want address and only have value");
-      return 0;
-    }
-
-  gcc_assert (!ret || !list_ret);
+      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);
+         enum machine_mode dmode = TYPE_MODE (declared_type);
+         enum machine_mode pmode = TYPE_MODE (passed_type);
 
-  /* If we've got an address and don't want one, dereference.  */
-  if (!want_address && have_address)
-    {
-      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
+         /* This decl represents a formal parameter which was optimized out.
+            Note that DECL_INCOMING_RTL may be NULL in here, but we handle
+            all cases where (rtl == NULL_RTX) just below.  */
+         if (dmode == pmode)
+           rtl = DECL_INCOMING_RTL (decl);
+         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))
+           {
+             rtx inc = DECL_INCOMING_RTL (decl);
+             if (REG_P (inc))
+               rtl = inc;
+             else if (MEM_P (inc))
+               {
+                 if (BYTES_BIG_ENDIAN)
+                   rtl = adjust_address_nv (inc, dmode,
+                                            GET_MODE_SIZE (pmode)
+                                            - GET_MODE_SIZE (dmode));
+                 else
+                   rtl = inc;
+               }
+           }
+       }
 
-      if (size > DWARF2_ADDR_SIZE || size == -1)
+      /* If the parm was passed in registers, but lives on the stack, then
+        make a big endian correction if the mode of the type of the
+        parameter is not the same as the mode of the rtl.  */
+      /* ??? This is the same series of checks that are made in dbxout.c before
+        we reach the big endian correction code there.  It isn't clear if all
+        of these checks are necessary here, but keeping them all is the safe
+        thing to do.  */
+      else if (MEM_P (rtl)
+              && XEXP (rtl, 0) != const0_rtx
+              && ! CONSTANT_P (XEXP (rtl, 0))
+              /* Not passed in memory.  */
+              && !MEM_P (DECL_INCOMING_RTL (decl))
+              /* Not passed by invisible reference.  */
+              && (!REG_P (XEXP (rtl, 0))
+                  || REGNO (XEXP (rtl, 0)) == HARD_FRAME_POINTER_REGNUM
+                  || REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_ARG_POINTER
+                  || REGNO (XEXP (rtl, 0)) == ARG_POINTER_REGNUM
+#endif
+                    )
+              /* Big endian correction check.  */
+              && BYTES_BIG_ENDIAN
+              && TYPE_MODE (TREE_TYPE (decl)) != GET_MODE (rtl)
+              && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)))
+                  < UNITS_PER_WORD))
        {
-         expansion_failed (loc, NULL_RTX,
-                           "DWARF address size mismatch");
-         return 0;
+         int offset = (UNITS_PER_WORD
+                       - GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl))));
+
+         rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)),
+                            plus_constant (XEXP (rtl, 0), offset));
        }
-      else if (size == DWARF2_ADDR_SIZE)
-       op = DW_OP_deref;
-      else
-       op = DW_OP_deref_size;
+    }
+  else if (TREE_CODE (decl) == VAR_DECL
+          && rtl
+          && MEM_P (rtl)
+          && GET_MODE (rtl) != TYPE_MODE (TREE_TYPE (decl))
+          && BYTES_BIG_ENDIAN)
+    {
+      int rsize = GET_MODE_SIZE (GET_MODE (rtl));
+      int dsize = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)));
 
-      if (ret)
-       add_loc_descr (&ret, new_loc_descr (op, size, 0));
-      else
-       add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0));
+      /* If a variable is declared "register" yet is smaller than
+        a register, then if we store the variable to memory, it
+        looks like we're storing a register-sized value, when in
+        fact we are not.  We need to adjust the offset of the
+        storage location to reflect the actual value's bytes,
+        else gdb will not be able to display it.  */
+      if (rsize > dsize)
+       rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)),
+                          plus_constant (XEXP (rtl, 0), rsize-dsize));
     }
-  if (ret)
-    list_ret = new_loc_list (ret, NULL, NULL, NULL);
 
-  return list_ret;
-}
+  /* A variable with no DECL_RTL but a DECL_INITIAL is a compile-time constant,
+     and will have been substituted directly into all expressions that use it.
+     C does not have such a concept, but C++ and other languages do.  */
+  if (!rtl && TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
+    rtl = rtl_for_decl_init (DECL_INITIAL (decl), TREE_TYPE (decl));
 
-/* Same as above but return only single location expression.  */
-static dw_loc_descr_ref
-loc_descriptor_from_tree (tree loc, int want_address)
-{
-  dw_loc_list_ref ret = loc_list_from_tree (loc, want_address);
-  if (!ret)
-    return NULL;
-  if (ret->dw_loc_next)
+  if (rtl)
+    rtl = targetm.delegitimize_address (rtl);
+
+  /* If we don't look past the constant pool, we risk emitting a
+     reference to a constant pool entry that isn't referenced from
+     code, and thus is not emitted.  */
+  if (rtl)
+    rtl = avoid_constant_pool_reference (rtl);
+
+  /* Try harder to get a rtl.  If this symbol ends up not being emitted
+     in the current CU, resolve_addr will remove the expression referencing
+     it.  */
+  if (rtl == NULL_RTX
+      && TREE_CODE (decl) == VAR_DECL
+      && !DECL_EXTERNAL (decl)
+      && TREE_STATIC (decl)
+      && DECL_NAME (decl)
+      && !DECL_HARD_REGISTER (decl)
+      && DECL_MODE (decl) != VOIDmode)
     {
-      expansion_failed (loc, NULL_RTX,
-                       "Location list where only loc descriptor needed");
-      return NULL;
+      rtl = make_decl_rtl_for_debug (decl);
+      if (!MEM_P (rtl)
+         || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF
+         || SYMBOL_REF_DECL (XEXP (rtl, 0)) != decl)
+       rtl = NULL_RTX;
     }
-  return ret->expr;
-}
 
-/* Given a value, round it up to the lowest multiple of `boundary'
-   which is not less than the value itself.  */
-
-static inline HOST_WIDE_INT
-ceiling (HOST_WIDE_INT value, unsigned int boundary)
-{
-  return (((value + boundary - 1) / boundary) * boundary);
+  return rtl;
 }
 
-/* Given a pointer to what is assumed to be a FIELD_DECL node, return a
-   pointer to the declared type for the relevant field variable, or return
-   `integer_type_node' if the given node turns out to be an
-   ERROR_MARK node.  */
+/* Check whether decl is a Fortran COMMON symbol.  If not, NULL_TREE is
+   returned.  If so, the decl for the COMMON block is returned, and the
+   value is the offset into the common block for the symbol.  */
 
-static inline tree
-field_type (const_tree decl)
+static tree
+fortran_common (tree decl, HOST_WIDE_INT *value)
 {
-  tree type;
+  tree val_expr, cvar;
+  enum machine_mode mode;
+  HOST_WIDE_INT bitsize, bitpos;
+  tree offset;
+  int volatilep = 0, unsignedp = 0;
 
-  if (TREE_CODE (decl) == ERROR_MARK)
-    return integer_type_node;
+  /* If the decl isn't a VAR_DECL, or if it isn't static, or if
+     it does not have a value (the offset into the common area), or if it
+     is thread local (as opposed to global) then it isn't common, and shouldn't
+     be handled as such.  */
+  if (TREE_CODE (decl) != VAR_DECL
+      || !TREE_STATIC (decl)
+      || !DECL_HAS_VALUE_EXPR_P (decl)
+      || !is_fortran ())
+    return NULL_TREE;
 
-  type = DECL_BIT_FIELD_TYPE (decl);
-  if (type == NULL_TREE)
-    type = TREE_TYPE (decl);
+  val_expr = DECL_VALUE_EXPR (decl);
+  if (TREE_CODE (val_expr) != COMPONENT_REF)
+    return NULL_TREE;
 
-  return type;
-}
+  cvar = get_inner_reference (val_expr, &bitsize, &bitpos, &offset,
+                             &mode, &unsignedp, &volatilep, true);
 
-/* Given a pointer to a tree node, return the alignment in bits for
-   it, or else return BITS_PER_WORD if the node actually turns out to
-   be an ERROR_MARK node.  */
+  if (cvar == NULL_TREE
+      || TREE_CODE (cvar) != VAR_DECL
+      || DECL_ARTIFICIAL (cvar)
+      || !TREE_PUBLIC (cvar))
+    return NULL_TREE;
 
-static inline unsigned
-simple_type_align_in_bits (const_tree type)
-{
-  return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD;
-}
+  *value = 0;
+  if (offset != NULL)
+    {
+      if (!host_integerp (offset, 0))
+       return NULL_TREE;
+      *value = tree_low_cst (offset, 0);
+    }
+  if (bitpos != 0)
+    *value += bitpos / BITS_PER_UNIT;
 
-static inline unsigned
-simple_decl_align_in_bits (const_tree decl)
-{
-  return (TREE_CODE (decl) != ERROR_MARK) ? DECL_ALIGN (decl) : BITS_PER_WORD;
+  return cvar;
 }
 
-/* Return the result of rounding T up to ALIGN.  */
-
-static inline HOST_WIDE_INT
-round_up_to_align (HOST_WIDE_INT t, unsigned int align)
-{
-  /* We must be careful if T is negative because HOST_WIDE_INT can be
-     either "above" or "below" unsigned int as per the C promotion
-     rules, depending on the host, thus making the signedness of the
-     direct multiplication and division unpredictable.  */
-  unsigned HOST_WIDE_INT u = (unsigned HOST_WIDE_INT) t;
-
-  u += align - 1;
-  u /= align;
-  u *= align;
-
-  return (HOST_WIDE_INT) u;
-}
+/* Generate *either* a DW_AT_location attribute or else a DW_AT_const_value
+   data attribute for a variable or a parameter.  We generate the
+   DW_AT_const_value attribute only in those cases where the given variable
+   or parameter does not have a true "location" either in memory or in a
+   register.  This can happen (for example) when a constant is passed as an
+   actual argument in a call to an inline function.  (It's possible that
+   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.
 
-/* Given a pointer to a FIELD_DECL, compute and return the byte offset of the
-   lowest addressed byte of the "containing object" for the given FIELD_DECL,
-   or return 0 if we are unable to determine what that offset is, either
-   because the argument turns out to be a pointer to an ERROR_MARK node, or
-   because the offset is actually variable.  (We can't handle the latter case
-   just yet).  */
+   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 HOST_WIDE_INT
-field_byte_offset (const_tree decl)
+static bool
+add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p,
+                                      enum dwarf_attribute attr)
 {
-  HOST_WIDE_INT object_offset_in_bits;
-  HOST_WIDE_INT bitpos_int;
+  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 0;
+    return false;
 
-  gcc_assert (TREE_CODE (decl) == FIELD_DECL);
+  gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
+             || TREE_CODE (decl) == RESULT_DECL);
 
-  /* We cannot yet cope with fields whose positions are variable, so
-     for now, when we see such things, we simply return 0.  Someday, we may
-     be able to handle such cases, but it will be damn difficult.  */
-  if (! host_integerp (bit_position (decl), 0))
-    return 0;
+  /* Try to get some constant RTL for this decl, and use that as the value of
+     the location.  */
 
-  bitpos_int = int_bit_position (decl);
+  rtl = rtl_for_decl_location (decl);
+  if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
+      && add_const_value_attribute (die, rtl))
+    return true;
 
-#ifdef PCC_BITFIELD_TYPE_MATTERS
-  if (PCC_BITFIELD_TYPE_MATTERS)
+  /* See if we have single element location list that is equivalent to
+     a constant value.  That way we are better to use add_const_value_attribute
+     rather than expanding constant value equivalent.  */
+  loc_list = lookup_decl_loc (decl);
+  if (loc_list
+      && loc_list->first
+      && loc_list->first->next == NULL
+      && NOTE_P (loc_list->first->loc)
+      && NOTE_VAR_LOCATION (loc_list->first->loc)
+      && NOTE_VAR_LOCATION_LOC (loc_list->first->loc))
     {
-      tree type;
-      tree field_size_tree;
-      HOST_WIDE_INT deepest_bitpos;
-      unsigned HOST_WIDE_INT field_size_in_bits;
-      unsigned int type_align_in_bits;
-      unsigned int decl_align_in_bits;
-      unsigned HOST_WIDE_INT type_size_in_bits;
-
-      type = field_type (decl);
-      type_size_in_bits = simple_type_size_in_bits (type);
-      type_align_in_bits = simple_type_align_in_bits (type);
-
-      field_size_tree = DECL_SIZE (decl);
-
-      /* The size could be unspecified if there was an error, or for
-        a flexible array member.  */
-      if (!field_size_tree)
-       field_size_tree = bitsize_zero_node;
-
-      /* If the size of the field is not constant, use the type size.  */
-      if (host_integerp (field_size_tree, 1))
-        field_size_in_bits = tree_low_cst (field_size_tree, 1);
-      else
-        field_size_in_bits = type_size_in_bits;
-
-      decl_align_in_bits = simple_decl_align_in_bits (decl);
-
-      /* The GCC front-end doesn't make any attempt to keep track of the
-         starting bit offset (relative to the start of the containing
-         structure type) of the hypothetical "containing object" for a
-         bit-field.  Thus, when computing the byte offset value for the
-         start of the "containing object" of a bit-field, we must deduce
-         this information on our own. This can be rather tricky to do in
-         some cases.  For example, handling the following structure type
-         definition when compiling for an i386/i486 target (which only
-         aligns long long's to 32-bit boundaries) can be very tricky:
-
-        struct S { int field1; long long field2:31; };
-
-         Fortunately, there is a simple rule-of-thumb which can be used
-         in such cases.  When compiling for an i386/i486, GCC will
-         allocate 8 bytes for the structure shown above.  It decides to
-         do this based upon one simple rule for bit-field allocation.
-         GCC allocates each "containing object" for each bit-field at
-         the first (i.e. lowest addressed) legitimate alignment boundary
-         (based upon the required minimum alignment for the declared
-         type of the field) which it can possibly use, subject to the
-         condition that there is still enough available space remaining
-         in the containing object (when allocated at the selected point)
-         to fully accommodate all of the bits of the bit-field itself.
-
-         This simple rule makes it obvious why GCC allocates 8 bytes for
-         each object of the structure type shown above.  When looking
-         for a place to allocate the "containing object" for `field2',
-         the compiler simply tries to allocate a 64-bit "containing
-         object" at each successive 32-bit boundary (starting at zero)
-         until it finds a place to allocate that 64- bit field such that
-         at least 31 contiguous (and previously unallocated) bits remain
-         within that selected 64 bit field.  (As it turns out, for the
-         example above, the compiler finds it is OK to allocate the
-         "containing object" 64-bit field at bit-offset zero within the
-         structure type.)
-
-         Here we attempt to work backwards from the limited set of facts
-         we're given, and we try to deduce from those facts, where GCC
-         must have believed that the containing object started (within
-         the structure type). The value we deduce is then used (by the
-         callers of this routine) to generate DW_AT_location and
-         DW_AT_bit_offset attributes for fields (both bit-fields and, in
-         the case of DW_AT_location, regular fields as well).  */
-
-      /* Figure out the bit-distance from the start of the structure to
-         the "deepest" bit of the bit-field.  */
-      deepest_bitpos = bitpos_int + field_size_in_bits;
-
-      /* This is the tricky part.  Use some fancy footwork to deduce
-         where the lowest addressed bit of the containing object must
-         be.  */
-      object_offset_in_bits = deepest_bitpos - type_size_in_bits;
-
-      /* Round up to type_align by default.  This works best for
-         bitfields.  */
-      object_offset_in_bits
-        = round_up_to_align (object_offset_in_bits, type_align_in_bits);
-
-      if (object_offset_in_bits > bitpos_int)
-        {
-          object_offset_in_bits = deepest_bitpos - type_size_in_bits;
+      struct var_loc_node *node;
 
-          /* Round up to decl_align instead.  */
-          object_offset_in_bits
-            = round_up_to_align (object_offset_in_bits, decl_align_in_bits);
-        }
+      node = loc_list->first;
+      rtl = NOTE_VAR_LOCATION_LOC (node->loc);
+      if (GET_CODE (rtl) == EXPR_LIST)
+       rtl = XEXP (rtl, 0);
+      if ((CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
+         && add_const_value_attribute (die, rtl))
+        return true;
     }
-  else
-#endif
-    object_offset_in_bits = bitpos_int;
-
-  return object_offset_in_bits / BITS_PER_UNIT;
+  /* 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);
+      return true;
+    }
+  /* None of that worked, so it must not really have a location;
+     try adding a constant value attribute from the DECL_INITIAL.  */
+  return tree_add_const_value_attribute_for_decl (die, decl);
 }
-\f
-/* The following routines define various Dwarf attributes and any data
-   associated with them.  */
 
-/* Add a location description attribute value to a DIE.
-
-   This emits location attributes suitable for whole variables and
-   whole parameters.  Note that the location attributes for struct fields are
-   generated by the routine `data_member_location_attribute' below.  */
+/* Add VARIABLE and DIE into deferred locations list.  */
 
-static inline void
-add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
-                            dw_loc_list_ref descr)
+static void
+defer_location (tree variable, dw_die_ref die)
 {
-  if (descr == 0)
-    return;
-  if (single_element_loc_list_p (descr))
-    add_AT_loc (die, attr_kind, descr->expr);
-  else
-    add_AT_loc_list (die, attr_kind, descr);
+  deferred_locations entry;
+  entry.variable = variable;
+  entry.die = die;
+  VEC_safe_push (deferred_locations, gc, deferred_locations_list, &entry);
 }
 
-/* Attach the specialized form of location attribute used for data members of
-   struct and union types.  In the special case of a FIELD_DECL node which
-   represents a bit-field, the "offset" part of this special location
-   descriptor must indicate the distance in bytes from the lowest-addressed
-   byte of the containing struct or union type to the lowest-addressed byte of
-   the "containing object" for the bit-field.  (See the `field_byte_offset'
-   function above).
-
-   For any given bit-field, the "containing object" is a hypothetical object
-   (of some integral or enum type) within which the given bit-field lives.  The
-   type of this hypothetical "containing object" is always the same as the
-   declared type of the individual bit-field itself (for GCC anyway... the
-   DWARF spec doesn't actually mandate this).  Note that it is the size (in
-   bytes) of the hypothetical "containing object" which will be given in the
-   DW_AT_byte_size attribute for this bit-field.  (See the
-   `byte_size_attribute' function below.)  It is also used when calculating the
-   value of the DW_AT_bit_offset attribute.  (See the `bit_offset_attribute'
-   function below.)  */
+/* Helper function for tree_add_const_value_attribute.  Natively encode
+   initializer INIT into an array.  Return true if successful.  */
 
-static void
-add_data_member_location_attribute (dw_die_ref die, tree decl)
+static bool
+native_encode_initializer (tree init, unsigned char *array, int size)
 {
-  HOST_WIDE_INT offset;
-  dw_loc_descr_ref loc_descr = 0;
+  tree type;
 
-  if (TREE_CODE (decl) == TREE_BINFO)
+  if (init == NULL_TREE)
+    return false;
+
+  STRIP_NOPS (init);
+  switch (TREE_CODE (init))
     {
-      /* We're working on the TAG_inheritance for a base class.  */
-      if (BINFO_VIRTUAL_P (decl) && is_cxx ())
+    case STRING_CST:
+      type = TREE_TYPE (init);
+      if (TREE_CODE (type) == ARRAY_TYPE)
        {
-         /* For C++ virtual bases we can't just use BINFO_OFFSET, as they
-            aren't at a fixed offset from all (sub)objects of the same
-            type.  We need to extract the appropriate offset from our
-            vtable.  The following dwarf expression means
+         tree enttype = TREE_TYPE (type);
+         enum machine_mode mode = TYPE_MODE (enttype);
 
-              BaseAddr = ObAddr + *((*ObAddr) - Offset)
+         if (GET_MODE_CLASS (mode) != MODE_INT || GET_MODE_SIZE (mode) != 1)
+           return false;
+         if (int_size_in_bytes (type) != size)
+           return false;
+         if (size > TREE_STRING_LENGTH (init))
+           {
+             memcpy (array, TREE_STRING_POINTER (init),
+                     TREE_STRING_LENGTH (init));
+             memset (array + TREE_STRING_LENGTH (init),
+                     '\0', size - TREE_STRING_LENGTH (init));
+           }
+         else
+           memcpy (array, TREE_STRING_POINTER (init), size);
+         return true;
+       }
+      return false;
+    case CONSTRUCTOR:
+      type = TREE_TYPE (init);
+      if (int_size_in_bytes (type) != size)
+       return false;
+      if (TREE_CODE (type) == ARRAY_TYPE)
+       {
+         HOST_WIDE_INT min_index;
+         unsigned HOST_WIDE_INT cnt;
+         int curpos = 0, fieldsize;
+         constructor_elt *ce;
 
-            This is specific to the V3 ABI, of course.  */
+         if (TYPE_DOMAIN (type) == NULL_TREE
+             || !host_integerp (TYPE_MIN_VALUE (TYPE_DOMAIN (type)), 0))
+           return false;
 
-         dw_loc_descr_ref tmp;
+         fieldsize = int_size_in_bytes (TREE_TYPE (type));
+         if (fieldsize <= 0)
+           return false;
 
-         /* Make a copy of the object address.  */
-         tmp = new_loc_descr (DW_OP_dup, 0, 0);
-         add_loc_descr (&loc_descr, tmp);
+         min_index = tree_low_cst (TYPE_MIN_VALUE (TYPE_DOMAIN (type)), 0);
+         memset (array, '\0', size);
+         FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (init), cnt, ce)
+           {
+             tree val = ce->value;
+             tree index = ce->index;
+             int pos = curpos;
+             if (index && TREE_CODE (index) == RANGE_EXPR)
+               pos = (tree_low_cst (TREE_OPERAND (index, 0), 0) - min_index)
+                     * fieldsize;
+             else if (index)
+               pos = (tree_low_cst (index, 0) - min_index) * fieldsize;
 
-         /* Extract the vtable address.  */
-         tmp = new_loc_descr (DW_OP_deref, 0, 0);
-         add_loc_descr (&loc_descr, tmp);
+             if (val)
+               {
+                 STRIP_NOPS (val);
+                 if (!native_encode_initializer (val, array + pos, fieldsize))
+                   return false;
+               }
+             curpos = pos + fieldsize;
+             if (index && TREE_CODE (index) == RANGE_EXPR)
+               {
+                 int count = tree_low_cst (TREE_OPERAND (index, 1), 0)
+                             - tree_low_cst (TREE_OPERAND (index, 0), 0);
+                 while (count-- > 0)
+                   {
+                     if (val)
+                       memcpy (array + curpos, array + pos, fieldsize);
+                     curpos += fieldsize;
+                   }
+               }
+             gcc_assert (curpos <= size);
+           }
+         return true;
+       }
+      else if (TREE_CODE (type) == RECORD_TYPE
+              || TREE_CODE (type) == UNION_TYPE)
+       {
+         tree field = NULL_TREE;
+         unsigned HOST_WIDE_INT cnt;
+         constructor_elt *ce;
 
-         /* Calculate the address of the offset.  */
-         offset = tree_low_cst (BINFO_VPTR_FIELD (decl), 0);
-         gcc_assert (offset < 0);
+         if (int_size_in_bytes (type) != size)
+           return false;
 
-         tmp = int_loc_descriptor (-offset);
-         add_loc_descr (&loc_descr, tmp);
-         tmp = new_loc_descr (DW_OP_minus, 0, 0);
-         add_loc_descr (&loc_descr, tmp);
+         if (TREE_CODE (type) == RECORD_TYPE)
+           field = TYPE_FIELDS (type);
 
-         /* Extract the offset.  */
-         tmp = new_loc_descr (DW_OP_deref, 0, 0);
-         add_loc_descr (&loc_descr, tmp);
+         FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (init), cnt, ce)
+           {
+             tree val = ce->value;
+             int pos, fieldsize;
 
-         /* Add it to the object address.  */
-         tmp = new_loc_descr (DW_OP_plus, 0, 0);
-         add_loc_descr (&loc_descr, tmp);
+             if (ce->index != 0)
+               field = ce->index;
+
+             if (val)
+               STRIP_NOPS (val);
+
+             if (field == NULL_TREE || DECL_BIT_FIELD (field))
+               return false;
+
+             if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
+                 && TYPE_DOMAIN (TREE_TYPE (field))
+                 && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
+               return false;
+             else if (DECL_SIZE_UNIT (field) == NULL_TREE
+                      || !host_integerp (DECL_SIZE_UNIT (field), 0))
+               return false;
+             fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 0);
+             pos = int_byte_position (field);
+             gcc_assert (pos + fieldsize <= size);
+             if (val
+                 && !native_encode_initializer (val, array + pos, fieldsize))
+               return false;
+           }
+         return true;
        }
-      else
-       offset = tree_low_cst (BINFO_OFFSET (decl), 0);
+      return false;
+    case VIEW_CONVERT_EXPR:
+    case NON_LVALUE_EXPR:
+      return native_encode_initializer (TREE_OPERAND (init, 0), array, size);
+    default:
+      return native_encode_expr (init, array, size) == size;
     }
-  else
-    offset = field_byte_offset (decl);
+}
 
-  if (! loc_descr)
-    {
-      if (dwarf_version > 2)
-       {
-         /* Don't need to output a location expression, just the constant. */
-         add_AT_int (die, DW_AT_data_member_location, offset);
-         return;
-       }
-      else
-       {
-         enum dwarf_location_atom op;
+/* Attach a DW_AT_const_value attribute to DIE. The value of the
+   attribute is the const value T.  */
 
-         /* The DWARF2 standard says that we should assume that the structure
-            address is already on the stack, so we can specify a structure
-            field address by using DW_OP_plus_uconst.  */
+static bool
+tree_add_const_value_attribute (dw_die_ref die, tree t)
+{
+  tree init;
+  tree type = TREE_TYPE (t);
+  rtx rtl;
 
-#ifdef MIPS_DEBUGGING_INFO
-         /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst
-            operator correctly.  It works only if we leave the offset on the
-            stack.  */
-         op = DW_OP_constu;
-#else
-         op = DW_OP_plus_uconst;
-#endif
+  if (!t || !TREE_TYPE (t) || TREE_TYPE (t) == error_mark_node)
+    return false;
 
-         loc_descr = new_loc_descr (op, offset, 0);
+  init = t;
+  gcc_assert (!DECL_P (init));
+
+  rtl = rtl_for_decl_init (init, type);
+  if (rtl)
+    return add_const_value_attribute (die, rtl);
+  /* If the host and target are sane, try harder.  */
+  else if (CHAR_BIT == 8 && BITS_PER_UNIT == 8
+          && initializer_constant_valid_p (init, type))
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (init));
+      if (size > 0 && (int) size == size)
+       {
+         unsigned char *array = (unsigned char *)
+           ggc_alloc_cleared_atomic (size);
+
+         if (native_encode_initializer (init, array, size))
+           {
+             add_AT_vec (die, DW_AT_const_value, size, 1, array);
+             return true;
+           }
        }
     }
-
-  add_AT_loc (die, DW_AT_data_member_location, loc_descr);
+  return false;
 }
 
-/* Writes integer values to dw_vec_const array.  */
+/* Attach a DW_AT_const_value attribute to VAR_DIE. The value of the
+   attribute is the const value of T, where T is an integral constant
+   variable with static storage duration
+   (so it can't be a PARM_DECL or a RESULT_DECL).  */
 
-static void
-insert_int (HOST_WIDE_INT val, unsigned int size, unsigned char *dest)
+static bool
+tree_add_const_value_attribute_for_decl (dw_die_ref var_die, tree decl)
 {
-  while (size != 0)
-    {
-      *dest++ = val & 0xff;
-      val >>= 8;
-      --size;
-    }
-}
 
-/* Reads integers from dw_vec_const array.  Inverse of insert_int.  */
+  if (!decl
+      || (TREE_CODE (decl) != VAR_DECL
+         && TREE_CODE (decl) != CONST_DECL)
+      || (TREE_CODE (decl) == VAR_DECL
+         && !TREE_STATIC (decl)))
+    return false;
 
-static HOST_WIDE_INT
-extract_int (const unsigned char *src, unsigned int size)
-{
-  HOST_WIDE_INT val = 0;
+    if (TREE_READONLY (decl)
+       && ! TREE_THIS_VOLATILE (decl)
+       && DECL_INITIAL (decl))
+      /* OK */;
+    else
+      return false;
 
-  src += size;
-  while (size != 0)
-    {
-      val <<= 8;
-      val |= *--src & 0xff;
-      --size;
-    }
-  return val;
+  /* Don't add DW_AT_const_value if abstract origin already has one.  */
+  if (get_AT (var_die, DW_AT_const_value))
+    return false;
+
+  return tree_add_const_value_attribute (var_die, DECL_INITIAL (decl));
 }
 
-/* Writes double_int values to dw_vec_const array.  */
+/* Convert the CFI instructions for the current function into a
+   location list.  This is used for DW_AT_frame_base when we targeting
+   a dwarf2 consumer that does not support the dwarf3
+   DW_OP_call_frame_cfa.  OFFSET is a constant to be added to all CFA
+   expressions.  */
 
-static void
-insert_double (double_int val, unsigned char *dest)
+static dw_loc_list_ref
+convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
 {
-  unsigned char *p0 = dest;
-  unsigned char *p1 = dest + sizeof (HOST_WIDE_INT);
+  int ix;
+  dw_fde_ref fde;
+  dw_loc_list_ref list, *list_tail;
+  dw_cfi_ref cfi;
+  dw_cfa_location last_cfa, next_cfa;
+  const char *start_label, *last_label, *section;
+  dw_cfa_location remember;
 
-  if (WORDS_BIG_ENDIAN)
-    {
-      p0 = p1;
-      p1 = dest;
-    }
+  fde = cfun->fde;
+  gcc_assert (fde != NULL);
 
-  insert_int ((HOST_WIDE_INT) val.low, sizeof (HOST_WIDE_INT), p0);
-  insert_int ((HOST_WIDE_INT) val.high, sizeof (HOST_WIDE_INT), p1);
-}
+  section = secname_for_decl (current_function_decl);
+  list_tail = &list;
+  list = NULL;
 
-/* Writes floating point values to dw_vec_const array.  */
+  memset (&next_cfa, 0, sizeof (next_cfa));
+  next_cfa.reg = INVALID_REGNUM;
+  remember = next_cfa;
 
-static void
-insert_float (const_rtx rtl, unsigned char *array)
-{
-  REAL_VALUE_TYPE rv;
-  long val[4];
-  int i;
+  start_label = fde->dw_fde_begin;
 
-  REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
-  real_to_target (val, &rv, GET_MODE (rtl));
+  /* ??? Bald assumption that the CIE opcode list does not contain
+     advance opcodes.  */
+  FOR_EACH_VEC_ELT (dw_cfi_ref, cie_cfi_vec, ix, cfi)
+    lookup_cfa_1 (cfi, &next_cfa, &remember);
 
-  /* real_to_target puts 32-bit pieces in each long.  Pack them.  */
-  for (i = 0; i < GET_MODE_SIZE (GET_MODE (rtl)) / 4; i++)
+  last_cfa = next_cfa;
+  last_label = start_label;
+
+  if (fde->dw_fde_second_begin && fde->dw_fde_switch_cfi_index == 0)
     {
-      insert_int (val[i], 4, array);
-      array += 4;
+      /* 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;
     }
-}
-
-/* Attach a DW_AT_const_value attribute for a variable or a parameter which
-   does not have a "location" either in memory or in a register.  These
-   things can arise in GNU C when a constant is passed as an actual parameter
-   to an inlined function.  They can also arise in C++ where declared
-   constants do not necessarily get memory "homes".  */
 
-static bool
-add_const_value_attribute (dw_die_ref die, rtx rtl)
-{
-  switch (GET_CODE (rtl))
+  FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi)
     {
-    case CONST_INT:
-      {
-       HOST_WIDE_INT val = INTVAL (rtl);
-
-       if (val < 0)
-         add_AT_int (die, DW_AT_const_value, val);
-       else
-         add_AT_unsigned (die, DW_AT_const_value, (unsigned HOST_WIDE_INT) val);
-      }
-      return true;
-
-    case CONST_DOUBLE:
-      /* Note that a CONST_DOUBLE rtx could represent either an integer or a
-        floating-point constant.  A CONST_DOUBLE is used whenever the
-        constant requires more than one word in order to be adequately
-        represented.  */
-      {
-       enum machine_mode mode = GET_MODE (rtl);
+      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 (SCALAR_FLOAT_MODE_P (mode))
-         {
-           unsigned int length = GET_MODE_SIZE (mode);
-           unsigned char *array = GGC_NEWVEC (unsigned char, length);
+             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;
 
-           insert_float (rtl, array);
-           add_AT_vec (die, DW_AT_const_value, length / 4, 4, array);
-         }
-       else
-         add_AT_double (die, DW_AT_const_value,
-                        CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
-      }
-      return true;
+       case DW_CFA_advance_loc:
+         /* The encoding is complex enough that we should never emit this.  */
+         gcc_unreachable ();
 
-    case CONST_VECTOR:
-      {
-       enum machine_mode mode = GET_MODE (rtl);
-       unsigned int elt_size = GET_MODE_UNIT_SIZE (mode);
-       unsigned int length = CONST_VECTOR_NUNITS (rtl);
-       unsigned char *array = GGC_NEWVEC (unsigned char, length * elt_size);
-       unsigned int i;
-       unsigned char *p;
+       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);
 
-       switch (GET_MODE_CLASS (mode))
-         {
-         case MODE_VECTOR_INT:
-           for (i = 0, p = array; i < length; i++, p += elt_size)
-             {
-               rtx elt = CONST_VECTOR_ELT (rtl, i);
-               double_int val = rtx_to_double_int (elt);
+             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 (elt_size <= sizeof (HOST_WIDE_INT))
-                 insert_int (double_int_to_shwi (val), elt_size, p);
-               else
-                 {
-                   gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
-                   insert_double (val, p);
-                 }
-             }
-           break;
+  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;
+      start_label = last_label;
+    }
 
-         case MODE_VECTOR_FLOAT:
-           for (i = 0, p = array; i < length; i++, p += elt_size)
-             {
-               rtx elt = CONST_VECTOR_ELT (rtl, i);
-               insert_float (elt, p);
-             }
-           break;
+  *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
+                            start_label,
+                            fde->dw_fde_second_begin
+                            ? fde->dw_fde_second_end : fde->dw_fde_end,
+                            section);
 
-         default:
-           gcc_unreachable ();
-         }
+  if (list && list->dw_loc_next)
+    gen_llsym (list);
 
-       add_AT_vec (die, DW_AT_const_value, length, elt_size, array);
-      }
-      return true;
+  return list;
+}
 
-    case CONST_STRING:
-      if (dwarf_version >= 4 || !dwarf_strict)
-       {
-         dw_loc_descr_ref loc_result;
-         resolve_one_addr (&rtl, NULL);
-       rtl_addr:
-         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
-         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
-         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
-         add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
-         add_AT_loc (die, DW_AT_location, loc_result);
-         VEC_safe_push (rtx, gc, used_rtx_array, rtl);
-         return true;
-       }
-      return false;
+/* Compute a displacement from the "steady-state frame pointer" to the
+   frame base (often the same as the CFA), and store it in
+   frame_pointer_fb_offset.  OFFSET is added to the displacement
+   before the latter is negated.  */
 
-    case CONST:
-      if (CONSTANT_P (XEXP (rtl, 0)))
-       return add_const_value_attribute (die, XEXP (rtl, 0));
-      /* FALLTHROUGH */
-    case SYMBOL_REF:
-      if (!const_ok_for_output (rtl))
-       return false;
-    case LABEL_REF:
-      if (dwarf_version >= 4 || !dwarf_strict)
-       goto rtl_addr;
-      return false;
+static void
+compute_frame_pointer_to_fb_displacement (HOST_WIDE_INT offset)
+{
+  rtx reg, elim;
 
-    case PLUS:
-      /* In cases where an inlined instance of an inline function is passed
-        the address of an `auto' variable (which is local to the caller) we
-        can get a situation where the DECL_RTL of the artificial local
-        variable (for the inlining) which acts as a stand-in for the
-        corresponding formal parameter (of the inline function) will look
-        like (plus:SI (reg:SI FRAME_PTR) (const_int ...)).  This is not
-        exactly a compile-time constant expression, but it isn't the address
-        of the (artificial) local variable either.  Rather, it represents the
-        *value* which the artificial local variable always has during its
-        lifetime.  We currently have no way to represent such quasi-constant
-        values in Dwarf, so for now we just punt and generate nothing.  */
-      return false;
+#ifdef FRAME_POINTER_CFA_OFFSET
+  reg = frame_pointer_rtx;
+  offset += FRAME_POINTER_CFA_OFFSET (current_function_decl);
+#else
+  reg = arg_pointer_rtx;
+  offset += ARG_POINTER_CFA_OFFSET (current_function_decl);
+#endif
 
-    case HIGH:
-    case CONST_FIXED:
-      return false;
+  elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+  if (GET_CODE (elim) == PLUS)
+    {
+      offset += INTVAL (XEXP (elim, 1));
+      elim = XEXP (elim, 0);
+    }
 
-    case MEM:
-      if (GET_CODE (XEXP (rtl, 0)) == CONST_STRING
-         && MEM_READONLY_P (rtl)
-         && GET_MODE (rtl) == BLKmode)
-       {
-         add_AT_string (die, DW_AT_const_value, XSTR (XEXP (rtl, 0), 0));
-         return true;
-       }
-      return false;
+  frame_pointer_fb_offset = -offset;
 
-    default:
-      /* No other kinds of rtx should be possible here.  */
-      gcc_unreachable ();
-    }
-  return false;
+  /* ??? AVR doesn't set up valid eliminations when there is no stack frame
+     in which to eliminate.  This is because it's stack pointer isn't 
+     directly accessible as a register within the ISA.  To work around
+     this, assume that while we cannot provide a proper value for
+     frame_pointer_fb_offset, we won't need one either.  */
+  frame_pointer_fb_offset_valid
+    = ((SUPPORTS_STACK_ALIGNMENT
+       && (elim == hard_frame_pointer_rtx
+           || elim == stack_pointer_rtx))
+       || elim == (frame_pointer_needed
+                  ? hard_frame_pointer_rtx
+                  : stack_pointer_rtx));
 }
 
-/* Determine whether the evaluation of EXPR references any variables
-   or functions which aren't otherwise used (and therefore may not be
-   output).  */
-static tree
-reference_to_unused (tree * tp, int * walk_subtrees,
-                    void * data ATTRIBUTE_UNUSED)
-{
-  if (! EXPR_P (*tp) && ! CONSTANT_CLASS_P (*tp))
-    *walk_subtrees = 0;
+/* Generate a DW_AT_name attribute given some string value to be included as
+   the value of the attribute.  */
 
-  if (DECL_P (*tp) && ! TREE_PUBLIC (*tp) && ! TREE_USED (*tp)
-      && ! TREE_ASM_WRITTEN (*tp))
-    return *tp;
-  /* ???  The C++ FE emits debug information for using decls, so
-     putting gcc_unreachable here falls over.  See PR31899.  For now
-     be conservative.  */
-  else if (!cgraph_global_info_ready
-          && (TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == FUNCTION_DECL))
-    return *tp;
-  else if (TREE_CODE (*tp) == VAR_DECL)
+static void
+add_name_attribute (dw_die_ref die, const char *name_string)
+{
+  if (name_string != NULL && *name_string != 0)
     {
-      struct varpool_node *node = varpool_node (*tp);
-      if (!node->needed)
-       return *tp;
+      if (demangle_name_func)
+       name_string = (*demangle_name_func) (name_string);
+
+      add_AT_string (die, DW_AT_name, name_string);
     }
-  else if (TREE_CODE (*tp) == FUNCTION_DECL
-          && (!DECL_EXTERNAL (*tp) || DECL_DECLARED_INLINE_P (*tp)))
+}
+
+/* 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)
     {
-      /* The call graph machinery must have finished analyzing,
-         optimizing and gimplifying the CU by now.
-        So if *TP has no call graph node associated
-        to it, it means *TP will not be emitted.  */
-      if (!cgraph_get_node (*tp))
-       return *tp;
+      /* The descriptive type indirectly references TYPE if this is also the
+        case for TYPE itself.  Do not deal with the circularity here.  */
+      TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type)) = 1;
+      gen_type_die (dtype, context_die);
+      TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type)) = 0;
+      dtype_die = lookup_type_die (dtype);
+      gcc_assert (dtype_die);
     }
-  else if (TREE_CODE (*tp) == STRING_CST && !TREE_ASM_WRITTEN (*tp))
-    return *tp;
 
-  return NULL_TREE;
+  add_AT_die_ref (die, DW_AT_GNAT_descriptive_type, dtype_die);
 }
 
-/* Generate an RTL constant from a decl initializer INIT with decl type TYPE,
-   for use in a later add_const_value_attribute call.  */
+/* Generate a DW_AT_comp_dir attribute for DIE.  */
 
-static rtx
-rtl_for_decl_init (tree init, tree type)
+static void
+add_comp_dir_attribute (dw_die_ref die)
 {
-  rtx rtl = NULL_RTX;
+  const char *wd = get_src_pwd ();
+  char *wd1;
 
-  /* 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)
+  if (wd == NULL)
+    return;
+
+  if (DWARF2_DIR_SHOULD_END_WITH_SEPARATOR)
     {
-      tree enttype = TREE_TYPE (type);
-      tree domain = TYPE_DOMAIN (type);
-      enum machine_mode mode = TYPE_MODE (enttype);
+      int wdlen;
 
-      if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == 1
-         && domain
-         && integer_zerop (TYPE_MIN_VALUE (domain))
-         && compare_tree_int (TYPE_MAX_VALUE (domain),
-                              TREE_STRING_LENGTH (init) - 1) == 0
-         && ((size_t) TREE_STRING_LENGTH (init)
-             == strlen (TREE_STRING_POINTER (init)) + 1))
-       {
-         rtl = gen_rtx_CONST_STRING (VOIDmode,
-                                     ggc_strdup (TREE_STRING_POINTER (init)));
-         rtl = gen_rtx_MEM (BLKmode, rtl);
-         MEM_READONLY_P (rtl) = 1;
-       }
+      wdlen = strlen (wd);
+      wd1 = (char *) ggc_alloc_atomic (wdlen + 2);
+      strcpy (wd1, wd);
+      wd1 [wdlen] = DIR_SEPARATOR;
+      wd1 [wdlen + 1] = 0;
+      wd = wd1;
     }
-  /* Other aggregates, and complex values, could be represented using
-     CONCAT: FIXME!  */
-  else if (AGGREGATE_TYPE_P (type) || 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)
-    ;
-  /* If the initializer is something that we know will expand into an
-     immediate RTL constant, expand it now.  We must be careful not to
-     reference variables which won't be output.  */
-  else if (initializer_constant_valid_p (init, type)
-          && ! walk_tree (&init, reference_to_unused, NULL, NULL))
+
+    add_AT_string (die, DW_AT_comp_dir, remap_debug_filename (wd));
+}
+
+/* Return the default for DW_AT_lower_bound, or -1 if there is not any
+   default.  */
+
+static int
+lower_bound_default (void)
+{
+  switch (get_AT_unsigned (comp_unit_die (), DW_AT_language))
     {
-      /* Convert vector CONSTRUCTOR initializers to VECTOR_CST if
-        possible.  */
-      if (TREE_CODE (type) == VECTOR_TYPE)
-       switch (TREE_CODE (init))
+    case DW_LANG_C:
+    case DW_LANG_C89:
+    case DW_LANG_C99:
+    case DW_LANG_C_plus_plus:
+    case DW_LANG_ObjC:
+    case DW_LANG_ObjC_plus_plus:
+    case DW_LANG_Java:
+      return 0;
+    case DW_LANG_Fortran77:
+    case DW_LANG_Fortran90:
+    case DW_LANG_Fortran95:
+      return 1;
+    case DW_LANG_UPC:
+    case DW_LANG_D:
+    case DW_LANG_Python:
+      return dwarf_version >= 4 ? 0 : -1;
+    case DW_LANG_Ada95:
+    case DW_LANG_Ada83:
+    case DW_LANG_Cobol74:
+    case DW_LANG_Cobol85:
+    case DW_LANG_Pascal83:
+    case DW_LANG_Modula2:
+    case DW_LANG_PLI:
+      return dwarf_version >= 4 ? 1 : -1;
+    default:
+      return -1;
+    }
+}
+
+/* Given a tree node describing an array bound (either lower or upper) output
+   a representation for that bound.  */
+
+static void
+add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree bound)
+{
+  switch (TREE_CODE (bound))
+    {
+    case ERROR_MARK:
+      return;
+
+    /* All fixed-bounds are represented by INTEGER_CST nodes.  */
+    case INTEGER_CST:
+      {
+       unsigned int prec = simple_type_size_in_bits (TREE_TYPE (bound));
+       int dflt;
+
+       /* Use the default if possible.  */
+       if (bound_attr == DW_AT_lower_bound
+           && host_integerp (bound, 0)
+           && (dflt = lower_bound_default ()) != -1
+           && tree_low_cst (bound, 0) == dflt)
+         ;
+
+       /* Otherwise represent the bound as an unsigned value with the
+          precision of its type.  The precision and signedness of the
+          type will be necessary to re-interpret it unambiguously.  */
+       else if (prec < HOST_BITS_PER_WIDE_INT)
          {
-         case VECTOR_CST:
-           break;
-         case CONSTRUCTOR:
-           if (TREE_CONSTANT (init))
-             {
-               VEC(constructor_elt,gc) *elts = CONSTRUCTOR_ELTS (init);
-               bool constant_p = true;
-               tree value;
-               unsigned HOST_WIDE_INT ix;
+           unsigned HOST_WIDE_INT mask
+             = ((unsigned HOST_WIDE_INT) 1 << prec) - 1;
+           add_AT_unsigned (subrange_die, bound_attr,
+                            TREE_INT_CST_LOW (bound) & mask);
+         }
+       else if (prec == HOST_BITS_PER_WIDE_INT
+                || TREE_INT_CST_HIGH (bound) == 0)
+         add_AT_unsigned (subrange_die, bound_attr,
+                          TREE_INT_CST_LOW (bound));
+       else
+         add_AT_double (subrange_die, bound_attr, TREE_INT_CST_HIGH (bound),
+                        TREE_INT_CST_LOW (bound));
+      }
+      break;
 
-               /* Even when ctor is constant, it might contain non-*_CST
-                  elements (e.g. { 1.0/0.0 - 1.0/0.0, 0.0 }) and those don't
-                  belong into VECTOR_CST nodes.  */
-               FOR_EACH_CONSTRUCTOR_VALUE (elts, ix, value)
-                 if (!CONSTANT_CLASS_P (value))
-                   {
-                     constant_p = false;
-                     break;
-                   }
+    CASE_CONVERT:
+    case VIEW_CONVERT_EXPR:
+      add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0));
+      break;
+
+    case SAVE_EXPR:
+      break;
+
+    case VAR_DECL:
+    case PARM_DECL:
+    case RESULT_DECL:
+      {
+       dw_die_ref decl_die = lookup_decl_die (bound);
+
+       /* ??? Can this happen, or should the variable have been bound
+          first?  Probably it can, since I imagine that we try to create
+          the types of parameters in the order in which they exist in
+          the list, and won't have created a forward reference to a
+          later parameter.  */
+       if (decl_die != NULL)
+         {
+           add_AT_die_ref (subrange_die, bound_attr, decl_die);
+           break;
+         }
+      }
+      /* FALLTHRU */
 
-               if (constant_p)
-                 {
-                   init = build_vector_from_ctor (type, elts);
-                   break;
-                 }
-             }
-           /* FALLTHRU */
+    default:
+      {
+       /* Otherwise try to create a stack operation procedure to
+          evaluate the value of the array bound.  */
 
-         default:
-           return NULL;
+       dw_die_ref ctx, decl_die;
+       dw_loc_list_ref list;
+
+       list = loc_list_from_tree (bound, 2);
+       if (list == NULL || single_element_loc_list_p (list))
+         {
+           /* If DW_AT_*bound is not a reference nor constant, it is
+              a DWARF expression rather than location description.
+              For that loc_list_from_tree (bound, 0) is needed.
+              If that fails to give a single element list,
+              fall back to outputting this as a reference anyway.  */
+           dw_loc_list_ref list2 = loc_list_from_tree (bound, 0);
+           if (list2 && single_element_loc_list_p (list2))
+             {
+               add_AT_loc (subrange_die, bound_attr, list2->expr);
+               break;
+             }
          }
+       if (list == NULL)
+         break;
 
-      rtl = expand_expr (init, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
+       if (current_function_decl == 0)
+         ctx = comp_unit_die ();
+       else
+         ctx = lookup_decl_die (current_function_decl);
 
-      /* If expand_expr returns a MEM, it wasn't immediate.  */
-      gcc_assert (!rtl || !MEM_P (rtl));
+       decl_die = new_die (DW_TAG_variable, ctx, bound);
+       add_AT_flag (decl_die, DW_AT_artificial, 1);
+       add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
+       add_AT_location_description (decl_die, DW_AT_location, list);
+       add_AT_die_ref (subrange_die, bound_attr, decl_die);
+       break;
+      }
     }
-
-  return rtl;
 }
 
-/* Generate RTL for the variable DECL to represent its location.  */
+/* Add subscript info to TYPE_DIE, describing an array TYPE, collapsing
+   possibly nested array subscripts in a flat sequence if COLLAPSE_P is true.
+   Note that the block of subscript information for an array type also
+   includes information about the element type of the given array type.  */
 
-static rtx
-rtl_for_decl_location (tree decl)
+static void
+add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
 {
-  rtx rtl;
-
-  /* Here we have to decide where we are going to say the parameter "lives"
-     (as far as the debugger is concerned).  We only have a couple of
-     choices.  GCC provides us with DECL_RTL and with DECL_INCOMING_RTL.
-
-     DECL_RTL normally indicates where the parameter lives during most of the
-     activation of the function.  If optimization is enabled however, this
-     could be either NULL or else a pseudo-reg.  Both of those cases indicate
-     that the parameter doesn't really live anywhere (as far as the code
-     generation parts of GCC are concerned) during most of the function's
-     activation.  That will happen (for example) if the parameter is never
-     referenced within the function.
-
-     We could just generate a location descriptor here for all non-NULL
-     non-pseudo values of DECL_RTL and ignore all of the rest, but we can be
-     a little nicer than that if we also consider DECL_INCOMING_RTL in cases
-     where DECL_RTL is NULL or is a pseudo-reg.
-
-     Note however that we can only get away with using DECL_INCOMING_RTL as
-     a backup substitute for DECL_RTL in certain limited cases.  In cases
-     where DECL_ARG_TYPE (decl) indicates the same type as TREE_TYPE (decl),
-     we can be sure that the parameter was passed using the same type as it is
-     declared to have within the function, and that its DECL_INCOMING_RTL
-     points us to a place where a value of that type is passed.
-
-     In cases where DECL_ARG_TYPE (decl) and TREE_TYPE (decl) are different,
-     we cannot (in general) use DECL_INCOMING_RTL as a substitute for DECL_RTL
-     because in these cases DECL_INCOMING_RTL points us to a value of some
-     type which is *different* from the type of the parameter itself.  Thus,
-     if we tried to use DECL_INCOMING_RTL to generate a location attribute in
-     such cases, the debugger would end up (for example) trying to fetch a
-     `float' from a place which actually contains the first part of a
-     `double'.  That would lead to really incorrect and confusing
-     output at debug-time.
-
-     So, in general, we *do not* use DECL_INCOMING_RTL as a backup for DECL_RTL
-     in cases where DECL_ARG_TYPE (decl) != TREE_TYPE (decl).  There
-     are a couple of exceptions however.  On little-endian machines we can
-     get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE (decl) is
-     not the same as TREE_TYPE (decl), but only when DECL_ARG_TYPE (decl) is
-     an integral type that is smaller than TREE_TYPE (decl). These cases arise
-     when (on a little-endian machine) a non-prototyped function has a
-     parameter declared to be of type `short' or `char'.  In such cases,
-     TREE_TYPE (decl) will be `short' or `char', DECL_ARG_TYPE (decl) will
-     be `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the
-     passed `int' value.  If the debugger then uses that address to fetch
-     a `short' or a `char' (on a little-endian machine) the result will be
-     the correct data, so we allow for such exceptional cases below.
-
-     Note that our goal here is to describe the place where the given formal
-     parameter lives during most of the function's activation (i.e. between the
-     end of the prologue and the start of the epilogue).  We'll do that as best
-     as we can. Note however that if the given formal parameter is modified
-     sometime during the execution of the function, then a stack backtrace (at
-     debug-time) will show the function as having been called with the *new*
-     value rather than the value which was originally passed in.  This happens
-     rarely enough that it is not a major problem, but it *is* a problem, and
-     I'd like to fix it.
+  unsigned dimension_number;
+  tree lower, upper;
+  dw_die_ref subrange_die;
 
-     A future version of dwarf2out.c may generate two additional attributes for
-     any given DW_TAG_formal_parameter DIE which will describe the "passed
-     type" and the "passed location" for the given formal parameter in addition
-     to the attributes we now generate to indicate the "declared type" and the
-     "active location" for each parameter.  This additional set of attributes
-     could be used by debuggers for stack backtraces. Separately, note that
-     sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL can be NULL also.
-     This happens (for example) for inlined-instances of inline function formal
-     parameters which are never referenced.  This really shouldn't be
-     happening.  All PARM_DECL nodes should get valid non-NULL
-     DECL_INCOMING_RTL values.  FIXME.  */
+  for (dimension_number = 0;
+       TREE_CODE (type) == ARRAY_TYPE && (dimension_number == 0 || collapse_p);
+       type = TREE_TYPE (type), dimension_number++)
+    {
+      tree domain = TYPE_DOMAIN (type);
 
-  /* Use DECL_RTL as the "location" unless we find something better.  */
-  rtl = DECL_RTL_IF_SET (decl);
+      if (TYPE_STRING_FLAG (type) && is_fortran () && dimension_number > 0)
+       break;
 
-  /* When generating abstract instances, ignore everything except
-     constants, symbols living in memory, and symbols living in
-     fixed registers.  */
-  if (! reload_completed)
-    {
-      if (rtl
-         && (CONSTANT_P (rtl)
-             || (MEM_P (rtl)
-                 && CONSTANT_P (XEXP (rtl, 0)))
-             || (REG_P (rtl)
-                 && TREE_CODE (decl) == VAR_DECL
-                 && TREE_STATIC (decl))))
-       {
-         rtl = targetm.delegitimize_address (rtl);
-         return rtl;
-       }
-      rtl = NULL_RTX;
-    }
-  else if (TREE_CODE (decl) == PARM_DECL)
-    {
-      if (rtl == NULL_RTX || is_pseudo_reg (rtl))
+      /* Arrays come in three flavors: Unspecified bounds, fixed bounds,
+        and (in GNU C only) variable bounds.  Handle all three forms
+        here.  */
+      subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
+      if (domain)
        {
-         tree declared_type = TREE_TYPE (decl);
-         tree passed_type = DECL_ARG_TYPE (decl);
-         enum machine_mode dmode = TYPE_MODE (declared_type);
-         enum machine_mode pmode = TYPE_MODE (passed_type);
+         /* We have an array type with specified bounds.  */
+         lower = TYPE_MIN_VALUE (domain);
+         upper = TYPE_MAX_VALUE (domain);
 
-         /* This decl represents a formal parameter which was optimized out.
-            Note that DECL_INCOMING_RTL may be NULL in here, but we handle
-            all cases where (rtl == NULL_RTX) just below.  */
-         if (dmode == pmode)
-           rtl = DECL_INCOMING_RTL (decl);
-         else if (SCALAR_INT_MODE_P (dmode)
-                  && GET_MODE_SIZE (dmode) <= GET_MODE_SIZE (pmode)
-                  && DECL_INCOMING_RTL (decl))
+         /* Define the index type.  */
+         if (TREE_TYPE (domain))
            {
-             rtx inc = DECL_INCOMING_RTL (decl);
-             if (REG_P (inc))
-               rtl = inc;
-             else if (MEM_P (inc))
-               {
-                 if (BYTES_BIG_ENDIAN)
-                   rtl = adjust_address_nv (inc, dmode,
-                                            GET_MODE_SIZE (pmode)
-                                            - GET_MODE_SIZE (dmode));
-                 else
-                   rtl = inc;
-               }
+             /* ??? This is probably an Ada unnamed subrange type.  Ignore the
+                TREE_TYPE field.  We can't emit debug info for this
+                because it is an unnamed integral type.  */
+             if (TREE_CODE (domain) == INTEGER_TYPE
+                 && TYPE_NAME (domain) == NULL_TREE
+                 && TREE_CODE (TREE_TYPE (domain)) == INTEGER_TYPE
+                 && TYPE_NAME (TREE_TYPE (domain)) == NULL_TREE)
+               ;
+             else
+               add_type_attribute (subrange_die, TREE_TYPE (domain), 0, 0,
+                                   type_die);
            }
-       }
-
-      /* If the parm was passed in registers, but lives on the stack, then
-        make a big endian correction if the mode of the type of the
-        parameter is not the same as the mode of the rtl.  */
-      /* ??? This is the same series of checks that are made in dbxout.c before
-        we reach the big endian correction code there.  It isn't clear if all
-        of these checks are necessary here, but keeping them all is the safe
-        thing to do.  */
-      else if (MEM_P (rtl)
-              && XEXP (rtl, 0) != const0_rtx
-              && ! CONSTANT_P (XEXP (rtl, 0))
-              /* Not passed in memory.  */
-              && !MEM_P (DECL_INCOMING_RTL (decl))
-              /* Not passed by invisible reference.  */
-              && (!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
-                  || REGNO (XEXP (rtl, 0)) == ARG_POINTER_REGNUM
-#endif
-                    )
-              /* Big endian correction check.  */
-              && BYTES_BIG_ENDIAN
-              && TYPE_MODE (TREE_TYPE (decl)) != GET_MODE (rtl)
-              && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)))
-                  < UNITS_PER_WORD))
-       {
-         int offset = (UNITS_PER_WORD
-                       - GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl))));
-
-         rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)),
-                            plus_constant (XEXP (rtl, 0), offset));
-       }
-    }
-  else if (TREE_CODE (decl) == VAR_DECL
-          && rtl
-          && MEM_P (rtl)
-          && GET_MODE (rtl) != TYPE_MODE (TREE_TYPE (decl))
-          && BYTES_BIG_ENDIAN)
-    {
-      int rsize = GET_MODE_SIZE (GET_MODE (rtl));
-      int dsize = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)));
 
-      /* If a variable is declared "register" yet is smaller than
-        a register, then if we store the variable to memory, it
-        looks like we're storing a register-sized value, when in
-        fact we are not.  We need to adjust the offset of the
-        storage location to reflect the actual value's bytes,
-        else gdb will not be able to display it.  */
-      if (rsize > dsize)
-       rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)),
-                          plus_constant (XEXP (rtl, 0), rsize-dsize));
-    }
+         /* ??? If upper is NULL, the array has unspecified length,
+            but it does have a lower bound.  This happens with Fortran
+              dimension arr(N:*)
+            Since the debugger is definitely going to need to know N
+            to produce useful results, go ahead and output the lower
+            bound solo, and hope the debugger can cope.  */
 
-  /* A variable with no DECL_RTL but a DECL_INITIAL is a compile-time constant,
-     and will have been substituted directly into all expressions that use it.
-     C does not have such a concept, but C++ and other languages do.  */
-  if (!rtl && TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
-    rtl = rtl_for_decl_init (DECL_INITIAL (decl), TREE_TYPE (decl));
+         add_bound_info (subrange_die, DW_AT_lower_bound, lower);
+         if (upper)
+           add_bound_info (subrange_die, DW_AT_upper_bound, upper);
+       }
 
-  if (rtl)
-    rtl = targetm.delegitimize_address (rtl);
+      /* Otherwise we have an array type with an unspecified length.  The
+        DWARF-2 spec does not say how to handle this; let's just leave out the
+        bounds.  */
+    }
+}
 
-  /* If we don't look past the constant pool, we risk emitting a
-     reference to a constant pool entry that isn't referenced from
-     code, and thus is not emitted.  */
-  if (rtl)
-    rtl = avoid_constant_pool_reference (rtl);
+static void
+add_byte_size_attribute (dw_die_ref die, tree tree_node)
+{
+  unsigned size;
 
-  /* Try harder to get a rtl.  If this symbol ends up not being emitted
-     in the current CU, resolve_addr will remove the expression referencing
-     it.  */
-  if (rtl == NULL_RTX
-      && TREE_CODE (decl) == VAR_DECL
-      && !DECL_EXTERNAL (decl)
-      && TREE_STATIC (decl)
-      && DECL_NAME (decl)
-      && !DECL_HARD_REGISTER (decl)
-      && DECL_MODE (decl) != VOIDmode)
+  switch (TREE_CODE (tree_node))
     {
-      rtl = make_decl_rtl_for_debug (decl);
-      if (!MEM_P (rtl)
-         || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF
-         || SYMBOL_REF_DECL (XEXP (rtl, 0)) != decl)
-       rtl = NULL_RTX;
+    case ERROR_MARK:
+      size = 0;
+      break;
+    case ENUMERAL_TYPE:
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      size = int_size_in_bytes (tree_node);
+      break;
+    case FIELD_DECL:
+      /* For a data member of a struct or union, the DW_AT_byte_size is
+        generally given as the number of bytes normally allocated for an
+        object of the *declared* type of the member itself.  This is true
+        even for bit-fields.  */
+      size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT;
+      break;
+    default:
+      gcc_unreachable ();
     }
 
-  return rtl;
+  /* Note that `size' might be -1 when we get to this point.  If it is, that
+     indicates that the byte size of the entity in question is variable.  We
+     have no good way of expressing this fact in Dwarf at the present time,
+     so just let the -1 pass on through.  */
+  add_AT_unsigned (die, DW_AT_byte_size, size);
 }
 
-/* Check whether decl is a Fortran COMMON symbol.  If not, NULL_TREE is
-   returned.  If so, the decl for the COMMON block is returned, and the
-   value is the offset into the common block for the symbol.  */
+/* For a FIELD_DECL node which represents a bit-field, output an attribute
+   which specifies the distance in bits from the highest order bit of the
+   "containing object" for the bit-field to the highest order bit of the
+   bit-field itself.
 
-static tree
-fortran_common (tree decl, HOST_WIDE_INT *value)
+   For any given bit-field, the "containing object" is a hypothetical object
+   (of some integral or enum type) within which the given bit-field lives.  The
+   type of this hypothetical "containing object" is always the same as the
+   declared type of the individual bit-field itself.  The determination of the
+   exact location of the "containing object" for a bit-field is rather
+   complicated.  It's handled by the `field_byte_offset' function (above).
+
+   Note that it is the size (in bytes) of the hypothetical "containing object"
+   which will be given in the DW_AT_byte_size attribute for this bit-field.
+   (See `byte_size_attribute' above).  */
+
+static inline void
+add_bit_offset_attribute (dw_die_ref die, tree decl)
 {
-  tree val_expr, cvar;
-  enum machine_mode mode;
-  HOST_WIDE_INT bitsize, bitpos;
-  tree offset;
-  int volatilep = 0, unsignedp = 0;
+  HOST_WIDE_INT object_offset_in_bytes = field_byte_offset (decl);
+  tree type = DECL_BIT_FIELD_TYPE (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 bit_offset;
 
-  /* If the decl isn't a VAR_DECL, or if it isn't static, or if
-     it does not have a value (the offset into the common area), or if it
-     is thread local (as opposed to global) then it isn't common, and shouldn't
-     be handled as such.  */
-  if (TREE_CODE (decl) != VAR_DECL
-      || !TREE_STATIC (decl)
-      || !DECL_HAS_VALUE_EXPR_P (decl)
-      || !is_fortran ())
-    return NULL_TREE;
+  /* Must be a field and a bit field.  */
+  gcc_assert (type && TREE_CODE (decl) == FIELD_DECL);
 
-  val_expr = DECL_VALUE_EXPR (decl);
-  if (TREE_CODE (val_expr) != COMPONENT_REF)
-    return NULL_TREE;
+  /* We can't yet handle bit-fields whose offsets are variable, so if we
+     encounter such things, just return without generating any attribute
+     whatsoever.  Likewise for variable or too large size.  */
+  if (! host_integerp (bit_position (decl), 0)
+      || ! host_integerp (DECL_SIZE (decl), 1))
+    return;
 
-  cvar = get_inner_reference (val_expr, &bitsize, &bitpos, &offset,
-                             &mode, &unsignedp, &volatilep, true);
+  bitpos_int = int_bit_position (decl);
 
-  if (cvar == NULL_TREE
-      || TREE_CODE (cvar) != VAR_DECL
-      || DECL_ARTIFICIAL (cvar)
-      || !TREE_PUBLIC (cvar))
-    return NULL_TREE;
+  /* Note that the bit offset is always the distance (in bits) from the
+     highest-order bit of the "containing object" to the highest-order bit of
+     the bit-field itself.  Since the "high-order end" of any object or field
+     is different on big-endian and little-endian machines, the computation
+     below must take account of these differences.  */
+  highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT;
+  highest_order_field_bit_offset = bitpos_int;
 
-  *value = 0;
-  if (offset != NULL)
+  if (! BYTES_BIG_ENDIAN)
     {
-      if (!host_integerp (offset, 0))
-       return NULL_TREE;
-      *value = tree_low_cst (offset, 0);
+      highest_order_field_bit_offset += tree_low_cst (DECL_SIZE (decl), 0);
+      highest_order_object_bit_offset += simple_type_size_in_bits (type);
     }
-  if (bitpos != 0)
-    *value += bitpos / BITS_PER_UNIT;
 
-  return cvar;
+  bit_offset
+    = (! BYTES_BIG_ENDIAN
+       ? highest_order_object_bit_offset - highest_order_field_bit_offset
+       : highest_order_field_bit_offset - highest_order_object_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);
 }
 
-/* Generate *either* a DW_AT_location attribute or else a DW_AT_const_value
-   data attribute for a variable or a parameter.  We generate the
-   DW_AT_const_value attribute only in those cases where the given variable
-   or parameter does not have a true "location" either in memory or in a
-   register.  This can happen (for example) when a constant is passed as an
-   actual argument in a call to an inline function.  (It's possible that
-   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.  */
+/* For a FIELD_DECL node which represents a bit field, output an attribute
+   which specifies the length in bits of the given field.  */
 
-static bool
-add_location_or_const_value_attribute (dw_die_ref die, tree decl,
-                                      enum dwarf_attribute attr)
+static inline void
+add_bit_size_attribute (dw_die_ref die, tree decl)
 {
-  rtx rtl;
-  dw_loc_list_ref list;
-  var_loc_list *loc_list;
+  /* Must be a field and a bit field.  */
+  gcc_assert (TREE_CODE (decl) == FIELD_DECL
+             && DECL_BIT_FIELD_TYPE (decl));
 
-  if (TREE_CODE (decl) == ERROR_MARK)
-    return false;
+  if (host_integerp (DECL_SIZE (decl), 1))
+    add_AT_unsigned (die, DW_AT_bit_size, tree_low_cst (DECL_SIZE (decl), 1));
+}
 
-  gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
-             || TREE_CODE (decl) == RESULT_DECL);
+/* If the compiled language is ANSI C, then add a 'prototyped'
+   attribute, if arg types are given for the parameters of a function.  */
 
-  /* Try to get some constant RTL for this decl, and use that as the value of
-     the location.  */
+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
+      && prototype_p (func_type))
+    add_AT_flag (die, DW_AT_prototyped, 1);
+}
 
-  rtl = rtl_for_decl_location (decl);
-  if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
-      && add_const_value_attribute (die, rtl))
-    return true;
+/* Add an 'abstract_origin' attribute below a given DIE.  The DIE is found
+   by looking in either the type declaration or object declaration
+   equate table.  */
 
-  /* See if we have single element location list that is equivalent to
-     a constant value.  That way we are better to use add_const_value_attribute
-     rather than expanding constant value equivalent.  */
-  loc_list = lookup_decl_loc (decl);
-  if (loc_list
-      && loc_list->first
-      && loc_list->first->next == NULL
-      && NOTE_P (loc_list->first->loc)
-      && NOTE_VAR_LOCATION (loc_list->first->loc)
-      && NOTE_VAR_LOCATION_LOC (loc_list->first->loc))
+static inline dw_die_ref
+add_abstract_origin_attribute (dw_die_ref die, tree origin)
+{
+  dw_die_ref origin_die = NULL;
+
+  if (TREE_CODE (origin) != FUNCTION_DECL)
     {
-      struct var_loc_node *node;
+      /* We may have gotten separated from the block for the inlined
+        function, if we're in an exception handler or some such; make
+        sure that the abstract function has been written out.
 
-      node = loc_list->first;
-      rtl = NOTE_VAR_LOCATION_LOC (node->loc);
-      if (GET_CODE (rtl) == EXPR_LIST)
-       rtl = XEXP (rtl, 0);
-      if ((CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
-         && add_const_value_attribute (die, rtl))
-        return true;
+        Doing this for nested functions is wrong, however; functions are
+        distinct units, and our context might not even be inline.  */
+      tree fn = origin;
+
+      if (TYPE_P (fn))
+       fn = TYPE_STUB_DECL (fn);
+
+      fn = decl_function_context (fn);
+      if (fn)
+       dwarf2out_abstract_function (fn);
     }
-  list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2);
-  if (list)
+
+  if (DECL_P (origin))
+    origin_die = lookup_decl_die (origin);
+  else if (TYPE_P (origin))
+    origin_die = lookup_type_die (origin);
+
+  /* XXX: Functions that are never lowered don't always have correct block
+     trees (in the case of java, they simply have no block tree, in some other
+     languages).  For these functions, there is nothing we can really do to
+     output correct debug info for inlined functions in all cases.  Rather
+     than die, we'll just produce deficient debug info now, in that we will
+     have variables without a proper abstract origin.  In the future, when all
+     functions are lowered, we should re-add a gcc_assert (origin_die)
+     here.  */
+
+  if (origin_die)
+    add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
+  return origin_die;
+}
+
+/* We do not currently support the pure_virtual attribute.  */
+
+static inline void
+add_pure_or_virtual_attribute (dw_die_ref die, tree func_decl)
+{
+  if (DECL_VINDEX (func_decl))
     {
-      add_AT_location_description (die, attr, list);
-      return true;
+      add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
+
+      if (host_integerp (DECL_VINDEX (func_decl), 0))
+       add_AT_loc (die, DW_AT_vtable_elem_location,
+                   new_loc_descr (DW_OP_constu,
+                                  tree_low_cst (DECL_VINDEX (func_decl), 0),
+                                  0));
+
+      /* GNU extension: Record what type this method came from originally.  */
+      if (debug_info_level > DINFO_LEVEL_TERSE
+         && DECL_CONTEXT (func_decl))
+       add_AT_die_ref (die, DW_AT_containing_type,
+                       lookup_type_die (DECL_CONTEXT (func_decl)));
     }
-  /* None of that worked, so it must not really have a location;
-     try adding a constant value attribute from the DECL_INITIAL.  */
-  return tree_add_const_value_attribute_for_decl (die, decl);
 }
-
-/* Add VARIABLE and DIE into deferred locations list.  */
+\f
+/* Add a DW_AT_linkage_name or DW_AT_MIPS_linkage_name attribute for the
+   given decl.  This used to be a vendor extension until after DWARF 4
+   standardized it.  */
 
 static void
-defer_location (tree variable, dw_die_ref die)
+add_linkage_attr (dw_die_ref die, tree decl)
 {
-  deferred_locations entry;
-  entry.variable = variable;
-  entry.die = die;
-  VEC_safe_push (deferred_locations, gc, deferred_locations_list, &entry);
+  const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+
+  /* Mimic what assemble_name_raw does with a leading '*'.  */
+  if (name[0] == '*')
+    name = &name[1];
+
+  if (dwarf_version >= 4)
+    add_AT_string (die, DW_AT_linkage_name, name);
+  else
+    add_AT_string (die, DW_AT_MIPS_linkage_name, name);
 }
 
-/* Helper function for tree_add_const_value_attribute.  Natively encode
-   initializer INIT into an array.  Return true if successful.  */
+/* Add source coordinate attributes for the given decl.  */
 
-static bool
-native_encode_initializer (tree init, unsigned char *array, int size)
+static void
+add_src_coords_attributes (dw_die_ref die, tree decl)
 {
-  tree type;
+  expanded_location s;
 
-  if (init == NULL_TREE)
-    return false;
+  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);
+}
 
-  STRIP_NOPS (init);
-  switch (TREE_CODE (init))
+/* Add DW_AT_{,MIPS_}linkage_name attribute for the given decl.  */
+
+static void
+add_linkage_name (dw_die_ref die, tree decl)
+{
+  if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
+       && TREE_PUBLIC (decl)
+       && !DECL_ABSTRACT (decl)
+       && !(TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl))
+       && die->die_tag != DW_TAG_member)
     {
-    case STRING_CST:
-      type = TREE_TYPE (init);
-      if (TREE_CODE (type) == ARRAY_TYPE)
+      /* Defer until we have an assembler name set.  */
+      if (!DECL_ASSEMBLER_NAME_SET_P (decl))
        {
-         tree enttype = TREE_TYPE (type);
-         enum machine_mode mode = TYPE_MODE (enttype);
+         limbo_die_node *asm_name;
 
-         if (GET_MODE_CLASS (mode) != MODE_INT || GET_MODE_SIZE (mode) != 1)
-           return false;
-         if (int_size_in_bytes (type) != size)
-           return false;
-         if (size > TREE_STRING_LENGTH (init))
-           {
-             memcpy (array, TREE_STRING_POINTER (init),
-                     TREE_STRING_LENGTH (init));
-             memset (array + TREE_STRING_LENGTH (init),
-                     '\0', size - TREE_STRING_LENGTH (init));
-           }
-         else
-           memcpy (array, TREE_STRING_POINTER (init), size);
-         return true;
+         asm_name = ggc_alloc_cleared_limbo_die_node ();
+         asm_name->die = die;
+         asm_name->created_for = decl;
+         asm_name->next = deferred_asm_name;
+         deferred_asm_name = asm_name;
        }
-      return false;
-    case CONSTRUCTOR:
-      type = TREE_TYPE (init);
-      if (int_size_in_bytes (type) != size)
-       return false;
-      if (TREE_CODE (type) == ARRAY_TYPE)
-       {
-         HOST_WIDE_INT min_index;
-         unsigned HOST_WIDE_INT cnt;
-         int curpos = 0, fieldsize;
-         constructor_elt *ce;
+      else if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
+       add_linkage_attr (die, decl);
+    }
+}
 
-         if (TYPE_DOMAIN (type) == NULL_TREE
-             || !host_integerp (TYPE_MIN_VALUE (TYPE_DOMAIN (type)), 0))
-           return false;
+/* Add a DW_AT_name attribute and source coordinate attribute for the
+   given decl, but only if it actually has a name.  */
 
-         fieldsize = int_size_in_bytes (TREE_TYPE (type));
-         if (fieldsize <= 0)
-           return false;
+static void
+add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
+{
+  tree decl_name;
 
-         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++)
-           {
-             tree val = ce->value;
-             tree index = ce->index;
-             int pos = curpos;
-             if (index && TREE_CODE (index) == RANGE_EXPR)
-               pos = (tree_low_cst (TREE_OPERAND (index, 0), 0) - min_index)
-                     * fieldsize;
-             else if (index)
-               pos = (tree_low_cst (index, 0) - min_index) * fieldsize;
+  decl_name = DECL_NAME (decl);
+  if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL)
+    {
+      const char *name = dwarf2_name (decl, 0);
+      if (name)
+       add_name_attribute (die, name);
+      if (! DECL_ARTIFICIAL (decl))
+       add_src_coords_attributes (die, decl);
 
-             if (val)
-               {
-                 STRIP_NOPS (val);
-                 if (!native_encode_initializer (val, array + pos, fieldsize))
-                   return false;
-               }
-             curpos = pos + fieldsize;
-             if (index && TREE_CODE (index) == RANGE_EXPR)
-               {
-                 int count = tree_low_cst (TREE_OPERAND (index, 1), 0)
-                             - tree_low_cst (TREE_OPERAND (index, 0), 0);
-                 while (count > 0)
-                   {
-                     if (val)
-                       memcpy (array + curpos, array + pos, fieldsize);
-                     curpos += fieldsize;
-                   }
-               }
-             gcc_assert (curpos <= size);
-           }
-         return true;
-       }
-      else if (TREE_CODE (type) == RECORD_TYPE
-              || TREE_CODE (type) == UNION_TYPE)
-       {
-         tree field = NULL_TREE;
-         unsigned HOST_WIDE_INT cnt;
-         constructor_elt *ce;
+      add_linkage_name (die, decl);
+    }
 
-         if (int_size_in_bytes (type) != size)
-           return false;
+#ifdef VMS_DEBUGGING_INFO
+  /* Get the function's name, as described by its RTL.  This may be different
+     from the DECL_NAME name used in the source file.  */
+  if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
+    {
+      add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
+                  XEXP (DECL_RTL (decl), 0));
+      VEC_safe_push (rtx, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
+    }
+#endif /* VMS_DEBUGGING_INFO */
+}
 
-         if (TREE_CODE (type) == RECORD_TYPE)
-           field = TYPE_FIELDS (type);
+#ifdef VMS_DEBUGGING_INFO
+/* Output the debug main pointer die for VMS */
 
-         for (cnt = 0;
-              VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (init), cnt, ce);
-              cnt++, field = field ? TREE_CHAIN (field) : 0)
-           {
-             tree val = ce->value;
-             int pos, fieldsize;
+void
+dwarf2out_vms_debug_main_pointer (void)
+{
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+  dw_die_ref die;
 
-             if (ce->index != 0)
-               field = ce->index;
+  /* Allocate the VMS debug main subprogram die.  */
+  die = ggc_alloc_cleared_die_node ();
+  die->die_tag = DW_TAG_subprogram;
+  add_name_attribute (die, VMS_DEBUG_MAIN_POINTER);
+  ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL,
+                              current_function_funcdef_no);
+  add_AT_lbl_id (die, DW_AT_entry_pc, label);
 
-             if (val)
-               STRIP_NOPS (val);
+  /* 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;
+    }
+  else
+    {
+      die->die_sib = die;
+      comp_unit_die ()->die_child = die;
+    }
+}
+#endif /* VMS_DEBUGGING_INFO */
 
-             if (field == NULL_TREE || DECL_BIT_FIELD (field))
-               return false;
+/* Push a new declaration scope.  */
 
-             if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
-                 && TYPE_DOMAIN (TREE_TYPE (field))
-                 && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
-               return false;
-             else if (DECL_SIZE_UNIT (field) == NULL_TREE
-                      || !host_integerp (DECL_SIZE_UNIT (field), 0))
-               return false;
-             fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 0);
-             pos = int_byte_position (field);
-             gcc_assert (pos + fieldsize <= size);
-             if (val
-                 && !native_encode_initializer (val, array + pos, fieldsize))
-               return false;
-           }
-         return true;
-       }
-      return false;
-    case VIEW_CONVERT_EXPR:
-    case NON_LVALUE_EXPR:
-      return native_encode_initializer (TREE_OPERAND (init, 0), array, size);
-    default:
-      return native_encode_expr (init, array, size) == size;
-    }
+static void
+push_decl_scope (tree scope)
+{
+  VEC_safe_push (tree, gc, decl_scope_table, scope);
 }
 
-/* Attach a DW_AT_const_value attribute to DIE. The value of the
-   attribute is the const value T.  */
+/* Pop a declaration scope.  */
 
-static bool
-tree_add_const_value_attribute (dw_die_ref die, tree t)
+static inline void
+pop_decl_scope (void)
 {
-  tree init;
-  tree type = TREE_TYPE (t);
-  rtx rtl;
+  VEC_pop (tree, decl_scope_table);
+}
 
-  if (!t || !TREE_TYPE (t) || TREE_TYPE (t) == error_mark_node)
-    return false;
+/* Return the DIE for the scope that immediately contains this type.
+   Non-named types get global scope.  Named types nested in other
+   types get their containing scope if it's open, or global scope
+   otherwise.  All other types (i.e. function-local named types) get
+   the current active scope.  */
 
-  init = t;
-  gcc_assert (!DECL_P (init));
+static dw_die_ref
+scope_die_for (tree t, dw_die_ref context_die)
+{
+  dw_die_ref scope_die = NULL;
+  tree containing_scope;
+  int i;
 
-  rtl = rtl_for_decl_init (init, type);
-  if (rtl)
-    return add_const_value_attribute (die, rtl);
-  /* If the host and target are sane, try harder.  */
-  else if (CHAR_BIT == 8 && BITS_PER_UNIT == 8
-          && initializer_constant_valid_p (init, type))
+  /* Non-types always go in the current scope.  */
+  gcc_assert (TYPE_P (t));
+
+  containing_scope = TYPE_CONTEXT (t);
+
+  /* Use the containing namespace if it was passed in (for a declaration).  */
+  if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL)
+    {
+      if (context_die == lookup_decl_die (containing_scope))
+       /* OK */;
+      else
+       containing_scope = NULL_TREE;
+    }
+
+  /* Ignore function type "scopes" from the C frontend.  They mean that
+     a tagged type is local to a parmlist of a function declarator, but
+     that isn't useful to DWARF.  */
+  if (containing_scope && TREE_CODE (containing_scope) == FUNCTION_TYPE)
+    containing_scope = NULL_TREE;
+
+  if (SCOPE_FILE_SCOPE_P (containing_scope))
+    scope_die = comp_unit_die ();
+  else if (TYPE_P (containing_scope))
     {
-      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (init));
-      if (size > 0 && (int) size == size)
+      /* For types, we can just look up the appropriate DIE.  But
+        first we check to see if we're in the middle of emitting it
+        so we know where the new DIE should go.  */
+      for (i = VEC_length (tree, decl_scope_table) - 1; i >= 0; --i)
+       if (VEC_index (tree, decl_scope_table, i) == containing_scope)
+         break;
+
+      if (i < 0)
        {
-         unsigned char *array = GGC_CNEWVEC (unsigned char, size);
+         gcc_assert (debug_info_level <= DINFO_LEVEL_TERSE
+                     || TREE_ASM_WRITTEN (containing_scope));
+         /*We are not in the middle of emitting the type
+           CONTAINING_SCOPE. Let's see if it's emitted already.  */
+         scope_die = lookup_type_die (containing_scope);
 
-         if (native_encode_initializer (init, array, size))
-           {
-             add_AT_vec (die, DW_AT_const_value, size, 1, array);
-             return true;
-           }
+         /* If none of the current dies are suitable, we get file scope.  */
+         if (scope_die == NULL)
+           scope_die = comp_unit_die ();
        }
+      else
+       scope_die = lookup_type_die_strip_naming_typedef (containing_scope);
     }
-  return false;
+  else
+    scope_die = context_die;
+
+  return scope_die;
 }
 
-/* Attach a DW_AT_const_value attribute to VAR_DIE. The value of the
-   attribute is the const value of T, where T is an integral constant
-   variable with static storage duration
-   (so it can't be a PARM_DECL or a RESULT_DECL).  */
+/* Returns nonzero if CONTEXT_DIE is internal to a function.  */
 
-static bool
-tree_add_const_value_attribute_for_decl (dw_die_ref var_die, tree decl)
+static inline int
+local_scope_p (dw_die_ref context_die)
 {
+  for (; context_die; context_die = context_die->die_parent)
+    if (context_die->die_tag == DW_TAG_inlined_subroutine
+       || context_die->die_tag == DW_TAG_subprogram)
+      return 1;
 
-  if (!decl
-      || (TREE_CODE (decl) != VAR_DECL
-         && TREE_CODE (decl) != CONST_DECL))
-    return false;
-
-    if (TREE_READONLY (decl)
-       && ! TREE_THIS_VOLATILE (decl)
-       && DECL_INITIAL (decl))
-      /* OK */;
-    else
-      return false;
-
-  /* Don't add DW_AT_const_value if abstract origin already has one.  */
-  if (get_AT (var_die, DW_AT_const_value))
-    return false;
-
-  return tree_add_const_value_attribute (var_die, DECL_INITIAL (decl));
+  return 0;
 }
 
-/* Convert the CFI instructions for the current function into a
-   location list.  This is used for DW_AT_frame_base when we targeting
-   a dwarf2 consumer that does not support the dwarf3
-   DW_OP_call_frame_cfa.  OFFSET is a constant to be added to all CFA
-   expressions.  */
+/* Returns nonzero if CONTEXT_DIE is a class.  */
 
-static dw_loc_list_ref
-convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
+static inline int
+class_scope_p (dw_die_ref context_die)
 {
-  dw_fde_ref fde;
-  dw_loc_list_ref list, *list_tail;
-  dw_cfi_ref cfi;
-  dw_cfa_location last_cfa, next_cfa;
-  const char *start_label, *last_label, *section;
-  dw_cfa_location remember;
-
-  fde = current_fde ();
-  gcc_assert (fde != NULL);
-
-  section = secname_for_decl (current_function_decl);
-  list_tail = &list;
-  list = NULL;
-
-  memset (&next_cfa, 0, sizeof (next_cfa));
-  next_cfa.reg = INVALID_REGNUM;
-  remember = next_cfa;
-
-  start_label = fde->dw_fde_begin;
-
-  /* ??? Bald assumption that the CIE opcode list does not contain
-     advance opcodes.  */
-  for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
-    lookup_cfa_1 (cfi, &next_cfa, &remember);
-
-  last_cfa = next_cfa;
-  last_label = start_label;
+  return (context_die
+         && (context_die->die_tag == DW_TAG_structure_type
+             || context_die->die_tag == DW_TAG_class_type
+             || context_die->die_tag == DW_TAG_interface_type
+             || context_die->die_tag == DW_TAG_union_type));
+}
 
-  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);
+/* Returns nonzero if CONTEXT_DIE is a class or namespace, for deciding
+   whether or not to treat a DIE in this context as a declaration.  */
 
-           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;
+static inline int
+class_or_namespace_scope_p (dw_die_ref context_die)
+{
+  return (class_scope_p (context_die)
+         || (context_die && context_die->die_tag == DW_TAG_namespace));
+}
 
-      case DW_CFA_advance_loc:
-       /* The encoding is complex enough that we should never emit this.  */
-       gcc_unreachable ();
+/* Many forms of DIEs require a "type description" attribute.  This
+   routine locates the proper "type descriptor" die for the type given
+   by 'type', and adds a DW_AT_type attribute below the given die.  */
 
-      default:
-       lookup_cfa_1 (cfi, &next_cfa, &remember);
-       break;
-      }
+static void
+add_type_attribute (dw_die_ref object_die, tree type, int decl_const,
+                   int decl_volatile, dw_die_ref context_die)
+{
+  enum tree_code code  = TREE_CODE (type);
+  dw_die_ref type_die  = NULL;
 
-  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;
-      start_label = last_label;
-    }
+  /* ??? If this type is an unnamed subrange type of an integral, floating-point
+     or fixed-point type, use the inner type.  This is because we have no
+     support for unnamed types in base_type_die.  This can happen if this is
+     an Ada subrange type.  Correct solution is emit a subrange type die.  */
+  if ((code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE)
+      && TREE_TYPE (type) != 0 && TYPE_NAME (type) == 0)
+    type = TREE_TYPE (type), code = TREE_CODE (type);
 
-  *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
-                            start_label, fde->dw_fde_end, section);
+  if (code == ERROR_MARK
+      /* Handle a special case.  For functions whose return type is void, we
+        generate *no* type attribute.  (Note that no object may have type
+        `void', so this only applies to function return types).  */
+      || code == VOID_TYPE)
+    return;
 
-  if (list && list->dw_loc_next)
-    gen_llsym (list);
+  type_die = modified_type_die (type,
+                               decl_const || TYPE_READONLY (type),
+                               decl_volatile || TYPE_VOLATILE (type),
+                               context_die);
 
-  return list;
+  if (type_die != NULL)
+    add_AT_die_ref (object_die, DW_AT_type, type_die);
 }
 
-/* Compute a displacement from the "steady-state frame pointer" to the
-   frame base (often the same as the CFA), and store it in
-   frame_pointer_fb_offset.  OFFSET is added to the displacement
-   before the latter is negated.  */
-
+/* Given an object die, add the calling convention attribute for the
+   function call type.  */
 static void
-compute_frame_pointer_to_fb_displacement (HOST_WIDE_INT offset)
+add_calling_convention_attribute (dw_die_ref subr_die, tree decl)
 {
-  rtx reg, elim;
+  enum dwarf_calling_convention value = DW_CC_normal;
 
-#ifdef FRAME_POINTER_CFA_OFFSET
-  reg = frame_pointer_rtx;
-  offset += FRAME_POINTER_CFA_OFFSET (current_function_decl);
-#else
-  reg = arg_pointer_rtx;
-  offset += ARG_POINTER_CFA_OFFSET (current_function_decl);
-#endif
+  value = ((enum dwarf_calling_convention)
+          targetm.dwarf_calling_convention (TREE_TYPE (decl)));
 
-  elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
-  if (GET_CODE (elim) == PLUS)
+  if (is_fortran ()
+      && !strcmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), "MAIN__"))
     {
-      offset += INTVAL (XEXP (elim, 1));
-      elim = XEXP (elim, 0);
-    }
+      /* 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;
 
-  gcc_assert ((SUPPORTS_STACK_ALIGNMENT
-              && (elim == hard_frame_pointer_rtx
-                  || elim == stack_pointer_rtx))
-             || elim == (frame_pointer_needed
-                         ? hard_frame_pointer_rtx
-                         : stack_pointer_rtx));
+      if (dwarf_version >= 4 || !dwarf_strict)
+       add_AT_flag (subr_die, DW_AT_main_subprogram, 1);
+    }
 
-  frame_pointer_fb_offset = -offset;
+  /* Only add the attribute if the backend requests it, and
+     is not DW_CC_normal.  */
+  if (value && (value != DW_CC_normal))
+    add_AT_unsigned (subr_die, DW_AT_calling_convention, value);
 }
 
-/* Generate a DW_AT_name attribute given some string value to be included as
-   the value of the attribute.  */
+/* Given a tree pointer to a struct, class, union, or enum type node, return
+   a pointer to the (string) tag name for the given type, or zero if the type
+   was declared without a tag.  */
 
-static void
-add_name_attribute (dw_die_ref die, const char *name_string)
+static const char *
+type_tag (const_tree type)
 {
-  if (name_string != NULL && *name_string != 0)
+  const char *name = 0;
+
+  if (TYPE_NAME (type) != 0)
     {
-      if (demangle_name_func)
-       name_string = (*demangle_name_func) (name_string);
+      tree t = 0;
 
-      add_AT_string (die, DW_AT_name, name_string);
+      /* Find the IDENTIFIER_NODE for the type name.  */
+      if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE
+         && !TYPE_NAMELESS (type))
+       t = TYPE_NAME (type);
+
+      /* The g++ front end makes the TYPE_NAME of *each* tagged type point to
+        a TYPE_DECL node, regardless of whether or not a `typedef' was
+        involved.  */
+      else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+              && ! DECL_IGNORED_P (TYPE_NAME (type)))
+       {
+         /* We want to be extra verbose.  Don't call dwarf_name if
+            DECL_NAME isn't set.  The default hook for decl_printable_name
+            doesn't like that, and in this context it's correct to return
+            0, instead of "<anonymous>" or the like.  */
+         if (DECL_NAME (TYPE_NAME (type))
+             && !DECL_NAMELESS (TYPE_NAME (type)))
+           name = lang_hooks.dwarf_name (TYPE_NAME (type), 2);
+       }
+
+      /* Now get the name as a string, or invent one.  */
+      if (!name && t != 0)
+       name = IDENTIFIER_POINTER (t);
     }
+
+  return (name == 0 || *name == '\0') ? 0 : name;
 }
 
-/* Generate a DW_AT_comp_dir attribute for DIE.  */
+/* Return the type associated with a data member, make a special check
+   for bit field types.  */
 
-static void
-add_comp_dir_attribute (dw_die_ref die)
+static inline tree
+member_declared_type (const_tree member)
 {
-  const char *wd = get_src_pwd ();
-  char *wd1;
-
-  if (wd == NULL)
-    return;
+  return (DECL_BIT_FIELD_TYPE (member)
+         ? DECL_BIT_FIELD_TYPE (member) : TREE_TYPE (member));
+}
 
-  if (DWARF2_DIR_SHOULD_END_WITH_SEPARATOR)
-    {
-      int wdlen;
+/* Get the decl's label, as described by its RTL. This may be different
+   from the DECL_NAME name used in the source file.  */
 
-      wdlen = strlen (wd);
-      wd1 = GGC_NEWVEC (char, wdlen + 2);
-      strcpy (wd1, wd);
-      wd1 [wdlen] = DIR_SEPARATOR;
-      wd1 [wdlen + 1] = 0;
-      wd = wd1;
-    }
+#if 0
+static const char *
+decl_start_label (tree decl)
+{
+  rtx x;
+  const char *fnname;
 
-    add_AT_string (die, DW_AT_comp_dir, remap_debug_filename (wd));
-}
+  x = DECL_RTL (decl);
+  gcc_assert (MEM_P (x));
 
-/* Return the default for DW_AT_lower_bound, or -1 if there is not any
-   default.  */
+  x = XEXP (x, 0);
+  gcc_assert (GET_CODE (x) == SYMBOL_REF);
 
-static int
-lower_bound_default (void)
-{
-  switch (get_AT_unsigned (comp_unit_die, DW_AT_language))
-    {
-    case DW_LANG_C:
-    case DW_LANG_C89:
-    case DW_LANG_C99:
-    case DW_LANG_C_plus_plus:
-    case DW_LANG_ObjC:
-    case DW_LANG_ObjC_plus_plus:
-    case DW_LANG_Java:
-      return 0;
-    case DW_LANG_Fortran77:
-    case DW_LANG_Fortran90:
-    case DW_LANG_Fortran95:
-      return 1;
-    case DW_LANG_UPC:
-    case DW_LANG_D:
-    case DW_LANG_Python:
-      return dwarf_version >= 4 ? 0 : -1;
-    case DW_LANG_Ada95:
-    case DW_LANG_Ada83:
-    case DW_LANG_Cobol74:
-    case DW_LANG_Cobol85:
-    case DW_LANG_Pascal83:
-    case DW_LANG_Modula2:
-    case DW_LANG_PLI:
-      return dwarf_version >= 4 ? 1 : -1;
-    default:
-      return -1;
-    }
+  fnname = XSTR (x, 0);
+  return fnname;
 }
-
-/* Given a tree node describing an array bound (either lower or upper) output
-   a representation for that bound.  */
+#endif
+\f
+/* These routines generate the internal representation of the DIE's for
+   the compilation unit.  Debugging information is collected by walking
+   the declaration trees passed in from dwarf2out_decl().  */
 
 static void
-add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree bound)
+gen_array_type_die (tree type, dw_die_ref context_die)
 {
-  switch (TREE_CODE (bound))
-    {
-    case ERROR_MARK:
-      return;
+  dw_die_ref scope_die = scope_die_for (type, context_die);
+  dw_die_ref array_die;
 
-    /* All fixed-bounds are represented by INTEGER_CST nodes.  */
-    case INTEGER_CST:
-      {
-       unsigned int prec = simple_type_size_in_bits (TREE_TYPE (bound));
-       int dflt;
+  /* GNU compilers represent multidimensional array types as sequences of one
+     dimensional array types whose element types are themselves array types.
+     We sometimes squish that down to a single array_type DIE with multiple
+     subscripts in the Dwarf debugging info.  The draft Dwarf specification
+     say that we are allowed to do this kind of compression in C, because
+     there is no difference between an array of arrays and a multidimensional
+     array.  We don't do this for Ada to remain as close as possible to the
+     actual representation, which is especially important against the language
+     flexibilty wrt arrays of variable size.  */
 
-       /* Use the default if possible.  */
-       if (bound_attr == DW_AT_lower_bound
-           && host_integerp (bound, 0)
-           && (dflt = lower_bound_default ()) != -1
-           && tree_low_cst (bound, 0) == dflt)
-         ;
+  bool collapse_nested_arrays = !is_ada ();
+  tree element_type;
 
-       /* Otherwise represent the bound as an unsigned value with the
-          precision of its type.  The precision and signedness of the
-          type will be necessary to re-interpret it unambiguously.  */
-       else if (prec < HOST_BITS_PER_WIDE_INT)
-         {
-           unsigned HOST_WIDE_INT mask
-             = ((unsigned HOST_WIDE_INT) 1 << prec) - 1;
-           add_AT_unsigned (subrange_die, bound_attr,
-                            TREE_INT_CST_LOW (bound) & mask);
-         }
-       else if (prec == HOST_BITS_PER_WIDE_INT
-                || TREE_INT_CST_HIGH (bound) == 0)
-         add_AT_unsigned (subrange_die, bound_attr,
-                          TREE_INT_CST_LOW (bound));
-       else
-         add_AT_double (subrange_die, bound_attr, TREE_INT_CST_HIGH (bound),
-                        TREE_INT_CST_LOW (bound));
-      }
-      break;
+  /* Emit DW_TAG_string_type for Fortran character types (with kind 1 only, as
+     DW_TAG_string_type doesn't have DW_AT_type attribute).  */
+  if (TYPE_STRING_FLAG (type)
+      && TREE_CODE (type) == ARRAY_TYPE
+      && is_fortran ()
+      && TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (char_type_node))
+    {
+      HOST_WIDE_INT size;
 
-    CASE_CONVERT:
-    case VIEW_CONVERT_EXPR:
-      add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0));
-      break;
+      array_die = new_die (DW_TAG_string_type, scope_die, type);
+      add_name_attribute (array_die, type_tag (type));
+      equate_type_number_to_die (type, array_die);
+      size = int_size_in_bytes (type);
+      if (size >= 0)
+       add_AT_unsigned (array_die, DW_AT_byte_size, size);
+      else if (TYPE_DOMAIN (type) != NULL_TREE
+              && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
+              && DECL_P (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
+       {
+         tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+         dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2);
 
-    case SAVE_EXPR:
-      break;
+         size = int_size_in_bytes (TREE_TYPE (szdecl));
+         if (loc && size > 0)
+           {
+             add_AT_location_description (array_die, DW_AT_string_length, loc);
+             if (size != DWARF2_ADDR_SIZE)
+               add_AT_unsigned (array_die, DW_AT_byte_size, size);
+           }
+       }
+      return;
+    }
 
-    case VAR_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
-      {
-       dw_die_ref decl_die = lookup_decl_die (bound);
+  /* ??? The SGI dwarf reader fails for array of array of enum types
+     (e.g. const enum machine_mode insn_operand_mode[2][10]) unless the inner
+     array type comes before the outer array type.  We thus call gen_type_die
+     before we new_die and must prevent nested array types collapsing for this
+     target.  */
 
-       /* ??? Can this happen, or should the variable have been bound
-          first?  Probably it can, since I imagine that we try to create
-          the types of parameters in the order in which they exist in
-          the list, and won't have created a forward reference to a
-          later parameter.  */
-       if (decl_die != NULL)
-         {
-           add_AT_die_ref (subrange_die, bound_attr, decl_die);
-           break;
-         }
-      }
-      /* FALLTHRU */
+#ifdef MIPS_DEBUGGING_INFO
+  gen_type_die (TREE_TYPE (type), context_die);
+  collapse_nested_arrays = false;
+#endif
 
-    default:
-      {
-       /* Otherwise try to create a stack operation procedure to
-          evaluate the value of the array bound.  */
+  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);
+  if (TYPE_ARTIFICIAL (type))
+    add_AT_flag (array_die, DW_AT_artificial, 1);
+  equate_type_number_to_die (type, array_die);
 
-       dw_die_ref ctx, decl_die;
-       dw_loc_list_ref list;
+  if (TREE_CODE (type) == VECTOR_TYPE)
+    add_AT_flag (array_die, DW_AT_GNU_vector, 1);
 
-       list = loc_list_from_tree (bound, 2);
-       if (list == NULL || single_element_loc_list_p (list))
-         {
-           /* If DW_AT_*bound is not a reference nor constant, it is
-              a DWARF expression rather than location description.
-              For that loc_list_from_tree (bound, 0) is needed.
-              If that fails to give a single element list,
-              fall back to outputting this as a reference anyway.  */
-           dw_loc_list_ref list2 = loc_list_from_tree (bound, 0);
-           if (list2 && single_element_loc_list_p (list2))
-             {
-               add_AT_loc (subrange_die, bound_attr, list2->expr);
-               break;
-             }
-         }
-       if (list == NULL)
-         break;
+  /* For Fortran multidimensional arrays use DW_ORD_col_major ordering.  */
+  if (is_fortran ()
+      && TREE_CODE (type) == ARRAY_TYPE
+      && TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE
+      && !TYPE_STRING_FLAG (TREE_TYPE (type)))
+    add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_col_major);
 
-       if (current_function_decl == 0)
-         ctx = comp_unit_die;
-       else
-         ctx = lookup_decl_die (current_function_decl);
+#if 0
+  /* We default the array ordering.  SDB will probably do
+     the right things even if DW_AT_ordering is not present.  It's not even
+     an issue until we start to get into multidimensional arrays anyway.  If
+     SDB is ever caught doing the Wrong Thing for multi-dimensional arrays,
+     then we'll have to put the DW_AT_ordering attribute back in.  (But if
+     and when we find out that we need to put these in, we will only do so
+     for multidimensional arrays.  */
+  add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major);
+#endif
 
-       decl_die = new_die (DW_TAG_variable, ctx, bound);
-       add_AT_flag (decl_die, DW_AT_artificial, 1);
-       add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
-       add_AT_location_description (decl_die, DW_AT_location, list);
-       add_AT_die_ref (subrange_die, bound_attr, decl_die);
-       break;
-      }
+#ifdef MIPS_DEBUGGING_INFO
+  /* The SGI compilers handle arrays of unknown bound by setting
+     AT_declaration and not emitting any subrange DIEs.  */
+  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));
     }
-}
-
-/* Add subscript info to TYPE_DIE, describing an array TYPE, collapsing
-   possibly nested array subscripts in a flat sequence if COLLAPSE_P is true.
-   Note that the block of subscript information for an array type also
-   includes information about the element type of the given array type.  */
+  else
+    add_subscript_info (array_die, type, collapse_nested_arrays);
 
-static void
-add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
-{
-  unsigned dimension_number;
-  tree lower, upper;
-  dw_die_ref subrange_die;
+  /* Add representation of the type of the elements of this array type and
+     emit the corresponding DIE if we haven't done it already.  */
+  element_type = TREE_TYPE (type);
+  if (collapse_nested_arrays)
+    while (TREE_CODE (element_type) == ARRAY_TYPE)
+      {
+       if (TYPE_STRING_FLAG (element_type) && is_fortran ())
+         break;
+       element_type = TREE_TYPE (element_type);
+      }
 
-  for (dimension_number = 0;
-       TREE_CODE (type) == ARRAY_TYPE && (dimension_number == 0 || collapse_p);
-       type = TREE_TYPE (type), dimension_number++)
-    {
-      tree domain = TYPE_DOMAIN (type);
+#ifndef MIPS_DEBUGGING_INFO
+  gen_type_die (element_type, context_die);
+#endif
 
-      if (TYPE_STRING_FLAG (type) && is_fortran () && dimension_number > 0)
-       break;
+  add_type_attribute (array_die, element_type, 0, 0, context_die);
 
-      /* Arrays come in three flavors: Unspecified bounds, fixed bounds,
-        and (in GNU C only) variable bounds.  Handle all three forms
-        here.  */
-      subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
-      if (domain)
-       {
-         /* We have an array type with specified bounds.  */
-         lower = TYPE_MIN_VALUE (domain);
-         upper = TYPE_MAX_VALUE (domain);
+  if (get_AT (array_die, DW_AT_name))
+    add_pubtype (type, array_die);
+}
 
-         /* Define the index type.  */
-         if (TREE_TYPE (domain))
-           {
-             /* ??? This is probably an Ada unnamed subrange type.  Ignore the
-                TREE_TYPE field.  We can't emit debug info for this
-                because it is an unnamed integral type.  */
-             if (TREE_CODE (domain) == INTEGER_TYPE
-                 && TYPE_NAME (domain) == NULL_TREE
-                 && TREE_CODE (TREE_TYPE (domain)) == INTEGER_TYPE
-                 && TYPE_NAME (TREE_TYPE (domain)) == NULL_TREE)
-               ;
-             else
-               add_type_attribute (subrange_die, TREE_TYPE (domain), 0, 0,
-                                   type_die);
-           }
+static dw_loc_descr_ref
+descr_info_loc (tree val, tree base_decl)
+{
+  HOST_WIDE_INT size;
+  dw_loc_descr_ref loc, loc2;
+  enum dwarf_location_atom op;
 
-         /* ??? If upper is NULL, the array has unspecified length,
-            but it does have a lower bound.  This happens with Fortran
-              dimension arr(N:*)
-            Since the debugger is definitely going to need to know N
-            to produce useful results, go ahead and output the lower
-            bound solo, and hope the debugger can cope.  */
+  if (val == base_decl)
+    return new_loc_descr (DW_OP_push_object_address, 0, 0);
 
-         add_bound_info (subrange_die, DW_AT_lower_bound, lower);
-         if (upper)
-           add_bound_info (subrange_die, DW_AT_upper_bound, upper);
+  switch (TREE_CODE (val))
+    {
+    CASE_CONVERT:
+      return descr_info_loc (TREE_OPERAND (val, 0), base_decl);
+    case VAR_DECL:
+      return loc_descriptor_from_tree (val, 0);
+    case INTEGER_CST:
+      if (host_integerp (val, 0))
+       return int_loc_descriptor (tree_low_cst (val, 0));
+      break;
+    case INDIRECT_REF:
+      size = int_size_in_bytes (TREE_TYPE (val));
+      if (size < 0)
+       break;
+      loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
+      if (!loc)
+       break;
+      if (size == DWARF2_ADDR_SIZE)
+       add_loc_descr (&loc, new_loc_descr (DW_OP_deref, 0, 0));
+      else
+       add_loc_descr (&loc, new_loc_descr (DW_OP_deref_size, size, 0));
+      return loc;
+    case POINTER_PLUS_EXPR:
+    case PLUS_EXPR:
+      if (host_integerp (TREE_OPERAND (val, 1), 1)
+         && (unsigned HOST_WIDE_INT) tree_low_cst (TREE_OPERAND (val, 1), 1)
+            < 16384)
+       {
+         loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
+         if (!loc)
+           break;
+         loc_descr_plus_const (&loc, tree_low_cst (TREE_OPERAND (val, 1), 0));
        }
-
-      /* Otherwise we have an array type with an unspecified length.  The
-        DWARF-2 spec does not say how to handle this; let's just leave out the
-        bounds.  */
+      else
+       {
+         op = DW_OP_plus;
+       do_binop:
+         loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
+         if (!loc)
+           break;
+         loc2 = descr_info_loc (TREE_OPERAND (val, 1), base_decl);
+         if (!loc2)
+           break;
+         add_loc_descr (&loc, loc2);
+         add_loc_descr (&loc2, new_loc_descr (op, 0, 0));
+       }
+      return loc;
+    case MINUS_EXPR:
+      op = DW_OP_minus;
+      goto do_binop;
+    case MULT_EXPR:
+      op = DW_OP_mul;
+      goto do_binop;
+    case EQ_EXPR:
+      op = DW_OP_eq;
+      goto do_binop;
+    case NE_EXPR:
+      op = DW_OP_ne;
+      goto do_binop;
+    default:
+      break;
     }
+  return NULL;
 }
 
 static void
-add_byte_size_attribute (dw_die_ref die, tree tree_node)
+add_descr_info_field (dw_die_ref die, enum dwarf_attribute attr,
+                     tree val, tree base_decl)
 {
-  unsigned size;
+  dw_loc_descr_ref loc;
 
-  switch (TREE_CODE (tree_node))
+  if (host_integerp (val, 0))
     {
-    case ERROR_MARK:
-      size = 0;
-      break;
-    case ENUMERAL_TYPE:
-    case RECORD_TYPE:
-    case UNION_TYPE:
-    case QUAL_UNION_TYPE:
-      size = int_size_in_bytes (tree_node);
-      break;
-    case FIELD_DECL:
-      /* For a data member of a struct or union, the DW_AT_byte_size is
-        generally given as the number of bytes normally allocated for an
-        object of the *declared* type of the member itself.  This is true
-        even for bit-fields.  */
-      size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT;
-      break;
-    default:
-      gcc_unreachable ();
+      add_AT_unsigned (die, attr, tree_low_cst (val, 0));
+      return;
     }
 
-  /* Note that `size' might be -1 when we get to this point.  If it is, that
-     indicates that the byte size of the entity in question is variable.  We
-     have no good way of expressing this fact in Dwarf at the present time,
-     so just let the -1 pass on through.  */
-  add_AT_unsigned (die, DW_AT_byte_size, size);
+  loc = descr_info_loc (val, base_decl);
+  if (!loc)
+    return;
+
+  add_AT_loc (die, attr, loc);
 }
 
-/* For a FIELD_DECL node which represents a bit-field, output an attribute
-   which specifies the distance in bits from the highest order bit of the
-   "containing object" for the bit-field to the highest order bit of the
-   bit-field itself.
+/* This routine generates DIE for array with hidden descriptor, details
+   are filled into *info by a langhook.  */
 
-   For any given bit-field, the "containing object" is a hypothetical object
-   (of some integral or enum type) within which the given bit-field lives.  The
-   type of this hypothetical "containing object" is always the same as the
-   declared type of the individual bit-field itself.  The determination of the
-   exact location of the "containing object" for a bit-field is rather
-   complicated.  It's handled by the `field_byte_offset' function (above).
+static void
+gen_descr_array_type_die (tree type, struct array_descr_info *info,
+                         dw_die_ref context_die)
+{
+  dw_die_ref scope_die = scope_die_for (type, context_die);
+  dw_die_ref array_die;
+  int dim;
 
-   Note that it is the size (in bytes) of the hypothetical "containing object"
-   which will be given in the DW_AT_byte_size attribute for this bit-field.
-   (See `byte_size_attribute' above).  */
+  array_die = new_die (DW_TAG_array_type, scope_die, type);
+  add_name_attribute (array_die, type_tag (type));
+  equate_type_number_to_die (type, array_die);
 
-static inline void
-add_bit_offset_attribute (dw_die_ref die, tree decl)
-{
-  HOST_WIDE_INT object_offset_in_bytes = field_byte_offset (decl);
-  tree type = DECL_BIT_FIELD_TYPE (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;
+  /* For Fortran multidimensional arrays use DW_ORD_col_major ordering.  */
+  if (is_fortran ()
+      && info->ndimensions >= 2)
+    add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_col_major);
 
-  /* Must be a field and a bit field.  */
-  gcc_assert (type && TREE_CODE (decl) == FIELD_DECL);
+  if (info->data_location)
+    add_descr_info_field (array_die, DW_AT_data_location, info->data_location,
+                         info->base_decl);
+  if (info->associated)
+    add_descr_info_field (array_die, DW_AT_associated, info->associated,
+                         info->base_decl);
+  if (info->allocated)
+    add_descr_info_field (array_die, DW_AT_allocated, info->allocated,
+                         info->base_decl);
 
-  /* We can't yet handle bit-fields whose offsets are variable, so if we
-     encounter such things, just return without generating any attribute
-     whatsoever.  Likewise for variable or too large size.  */
-  if (! host_integerp (bit_position (decl), 0)
-      || ! host_integerp (DECL_SIZE (decl), 1))
-    return;
+  for (dim = 0; dim < info->ndimensions; dim++)
+    {
+      dw_die_ref subrange_die
+       = new_die (DW_TAG_subrange_type, array_die, NULL);
 
-  bitpos_int = int_bit_position (decl);
+      if (info->dimen[dim].lower_bound)
+       {
+         /* If it is the default value, omit it.  */
+         int dflt;
 
-  /* Note that the bit offset is always the distance (in bits) from the
-     highest-order bit of the "containing object" to the highest-order bit of
-     the bit-field itself.  Since the "high-order end" of any object or field
-     is different on big-endian and little-endian machines, the computation
-     below must take account of these differences.  */
-  highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT;
-  highest_order_field_bit_offset = bitpos_int;
+         if (host_integerp (info->dimen[dim].lower_bound, 0)
+             && (dflt = lower_bound_default ()) != -1
+             && tree_low_cst (info->dimen[dim].lower_bound, 0) == dflt)
+           ;
+         else
+           add_descr_info_field (subrange_die, DW_AT_lower_bound,
+                                 info->dimen[dim].lower_bound,
+                                 info->base_decl);
+       }
+      if (info->dimen[dim].upper_bound)
+       add_descr_info_field (subrange_die, DW_AT_upper_bound,
+                             info->dimen[dim].upper_bound,
+                             info->base_decl);
+      if (info->dimen[dim].stride)
+       add_descr_info_field (subrange_die, DW_AT_byte_stride,
+                             info->dimen[dim].stride,
+                             info->base_decl);
+    }
 
-  if (! BYTES_BIG_ENDIAN)
+  gen_type_die (info->element_type, context_die);
+  add_type_attribute (array_die, info->element_type, 0, 0, context_die);
+
+  if (get_AT (array_die, DW_AT_name))
+    add_pubtype (type, array_die);
+}
+
+#if 0
+static void
+gen_entry_point_die (tree decl, dw_die_ref context_die)
+{
+  tree origin = decl_ultimate_origin (decl);
+  dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die, decl);
+
+  if (origin != NULL)
+    add_abstract_origin_attribute (decl_die, origin);
+  else
     {
-      highest_order_field_bit_offset += tree_low_cst (DECL_SIZE (decl), 0);
-      highest_order_object_bit_offset += simple_type_size_in_bits (type);
+      add_name_and_src_coords_attributes (decl_die, decl);
+      add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)),
+                         0, 0, context_die);
     }
 
-  bit_offset
-    = (! BYTES_BIG_ENDIAN
-       ? 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 (DECL_ABSTRACT (decl))
+    equate_decl_number_to_die (decl, decl_die);
+  else
+    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
 }
+#endif
 
-/* For a FIELD_DECL node which represents a bit field, output an attribute
-   which specifies the length in bits of the given field.  */
+/* Walk through the list of incomplete types again, trying once more to
+   emit full debugging info for them.  */
 
-static inline void
-add_bit_size_attribute (dw_die_ref die, tree decl)
+static void
+retry_incomplete_types (void)
 {
-  /* Must be a field and a bit field.  */
-  gcc_assert (TREE_CODE (decl) == FIELD_DECL
-             && DECL_BIT_FIELD_TYPE (decl));
+  int i;
 
-  if (host_integerp (DECL_SIZE (decl), 1))
-    add_AT_unsigned (die, DW_AT_bit_size, tree_low_cst (DECL_SIZE (decl), 1));
+  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 ());
 }
 
-/* If the compiled language is ANSI C, then add a 'prototyped'
-   attribute, if arg types are given for the parameters of a function.  */
+/* Determine what tag to use for a record type.  */
 
-static inline void
-add_prototyped_attribute (dw_die_ref die, tree func_type)
+static enum dwarf_tag
+record_type_tag (tree type)
 {
-  if (get_AT_unsigned (comp_unit_die, DW_AT_language) == DW_LANG_C89
-      && TYPE_ARG_TYPES (func_type) != NULL)
-    add_AT_flag (die, DW_AT_prototyped, 1);
+  if (! lang_hooks.types.classify_record)
+    return DW_TAG_structure_type;
+
+  switch (lang_hooks.types.classify_record (type))
+    {
+    case RECORD_IS_STRUCT:
+      return DW_TAG_structure_type;
+
+    case RECORD_IS_CLASS:
+      return DW_TAG_class_type;
+
+    case RECORD_IS_INTERFACE:
+      if (dwarf_version >= 3 || !dwarf_strict)
+       return DW_TAG_interface_type;
+      return DW_TAG_structure_type;
+
+    default:
+      gcc_unreachable ();
+    }
 }
 
-/* Add an 'abstract_origin' attribute below a given DIE.  The DIE is found
-   by looking in either the type declaration or object declaration
-   equate table.  */
+/* Generate a DIE to represent an enumeration type.  Note that these DIEs
+   include all of the information about the enumeration values also. Each
+   enumerated type name/value is listed as a child of the enumerated type
+   DIE.  */
 
-static inline dw_die_ref
-add_abstract_origin_attribute (dw_die_ref die, tree origin)
+static dw_die_ref
+gen_enumeration_type_die (tree type, dw_die_ref context_die)
 {
-  dw_die_ref origin_die = NULL;
+  dw_die_ref type_die = lookup_type_die (type);
 
-  if (TREE_CODE (origin) != FUNCTION_DECL)
+  if (type_die == NULL)
     {
-      /* We may have gotten separated from the block for the inlined
-        function, if we're in an exception handler or some such; make
-        sure that the abstract function has been written out.
+      type_die = new_die (DW_TAG_enumeration_type,
+                         scope_die_for (type, context_die), type);
+      equate_type_number_to_die (type, type_die);
+      add_name_attribute (type_die, type_tag (type));
+      add_gnat_descriptive_type_attribute (type_die, type, context_die);
+      if (TYPE_ARTIFICIAL (type))
+       add_AT_flag (type_die, DW_AT_artificial, 1);
+      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;
+  else
+    remove_AT (type_die, DW_AT_declaration);
 
-        Doing this for nested functions is wrong, however; functions are
-        distinct units, and our context might not even be inline.  */
-      tree fn = origin;
+  /* Handle a GNU C/C++ extension, i.e. incomplete enum types.  If the
+     given enum type is incomplete, do not generate the DW_AT_byte_size
+     attribute or the DW_AT_element_list attribute.  */
+  if (TYPE_SIZE (type))
+    {
+      tree link;
 
-      if (TYPE_P (fn))
-       fn = TYPE_STUB_DECL (fn);
+      TREE_ASM_WRITTEN (type) = 1;
+      add_byte_size_attribute (type_die, type);
+      if (TYPE_STUB_DECL (type) != NULL_TREE)
+       {
+         add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
+         add_accessibility_attribute (type_die, TYPE_STUB_DECL (type));
+       }
 
-      fn = decl_function_context (fn);
-      if (fn)
-       dwarf2out_abstract_function (fn);
-    }
+      /* If the first reference to this type was as the return type of an
+        inline function, then it may not have a parent.  Fix this now.  */
+      if (type_die->die_parent == NULL)
+       add_child_die (scope_die_for (type, context_die), type_die);
 
-  if (DECL_P (origin))
-    origin_die = lookup_decl_die (origin);
-  else if (TYPE_P (origin))
-    origin_die = lookup_type_die (origin);
+      for (link = TYPE_VALUES (type);
+          link != NULL; link = TREE_CHAIN (link))
+       {
+         dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die, link);
+         tree value = TREE_VALUE (link);
 
-  /* XXX: Functions that are never lowered don't always have correct block
-     trees (in the case of java, they simply have no block tree, in some other
-     languages).  For these functions, there is nothing we can really do to
-     output correct debug info for inlined functions in all cases.  Rather
-     than die, we'll just produce deficient debug info now, in that we will
-     have variables without a proper abstract origin.  In the future, when all
-     functions are lowered, we should re-add a gcc_assert (origin_die)
-     here.  */
+         add_name_attribute (enum_die,
+                             IDENTIFIER_POINTER (TREE_PURPOSE (link)));
 
-  if (origin_die)
-    add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
-  return origin_die;
+         if (TREE_CODE (value) == CONST_DECL)
+           value = DECL_INITIAL (value);
+
+         if (host_integerp (value, TYPE_UNSIGNED (TREE_TYPE (value))))
+           /* DWARF2 does not provide a way of indicating whether or
+              not enumeration constants are signed or unsigned.  GDB
+              always assumes the values are signed, so we output all
+              values as if they were signed.  That means that
+              enumeration constants with very large unsigned values
+              will appear to have negative values in the debugger.  */
+           add_AT_int (enum_die, DW_AT_const_value,
+                       tree_low_cst (value, tree_int_cst_sgn (value) > 0));
+       }
+    }
+  else
+    add_AT_flag (type_die, DW_AT_declaration, 1);
+
+  if (get_AT (type_die, DW_AT_name))
+    add_pubtype (type, type_die);
+
+  return type_die;
 }
 
-/* We do not currently support the pure_virtual attribute.  */
+/* Generate a DIE to represent either a real live formal parameter decl or to
+   represent just the type of some formal parameter position in some function
+   type.
 
-static inline void
-add_pure_or_virtual_attribute (dw_die_ref die, tree func_decl)
+   Note that this routine is a bit unusual because its argument may be a
+   ..._DECL node (i.e. either a PARM_DECL or perhaps a VAR_DECL which
+   represents an inlining of some PARM_DECL) or else some sort of a ..._TYPE
+   node.  If it's the former then this function is being called to output a
+   DIE to represent a formal parameter object (or some inlining thereof).  If
+   it's the latter, then this function is only being called to output a
+   DW_TAG_formal_parameter DIE to stand as a placeholder for some formal
+   argument type of some subprogram type.
+   If EMIT_NAME_P is true, name and source coordinate attributes
+   are emitted.  */
+
+static dw_die_ref
+gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
+                         dw_die_ref context_die)
 {
-  if (DECL_VINDEX (func_decl))
+  tree node_or_origin = node ? node : origin;
+  tree ultimate_origin;
+  dw_die_ref parm_die
+    = new_die (DW_TAG_formal_parameter, context_die, node);
+
+  switch (TREE_CODE_CLASS (TREE_CODE (node_or_origin)))
     {
-      add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
+    case tcc_declaration:
+      ultimate_origin = decl_ultimate_origin (node_or_origin);
+      if (node || ultimate_origin)
+       origin = ultimate_origin;
+      if (origin != NULL)
+       add_abstract_origin_attribute (parm_die, origin);
+      else if (emit_name_p)
+       add_name_and_src_coords_attributes (parm_die, node);
+      if (origin == NULL
+         || (! DECL_ABSTRACT (node_or_origin)
+             && variably_modified_type_p (TREE_TYPE (node_or_origin),
+                                          decl_function_context
+                                                           (node_or_origin))))
+       {
+         tree type = TREE_TYPE (node_or_origin);
+         if (decl_by_reference_p (node_or_origin))
+           add_type_attribute (parm_die, TREE_TYPE (type), 0, 0,
+                               context_die);
+         else
+           add_type_attribute (parm_die, type,
+                               TREE_READONLY (node_or_origin),
+                               TREE_THIS_VOLATILE (node_or_origin),
+                               context_die);
+       }
+      if (origin == NULL && DECL_ARTIFICIAL (node))
+       add_AT_flag (parm_die, DW_AT_artificial, 1);
 
-      if (host_integerp (DECL_VINDEX (func_decl), 0))
-       add_AT_loc (die, DW_AT_vtable_elem_location,
-                   new_loc_descr (DW_OP_constu,
-                                  tree_low_cst (DECL_VINDEX (func_decl), 0),
-                                  0));
+      if (node && node != origin)
+        equate_decl_number_to_die (node, parm_die);
+      if (! DECL_ABSTRACT (node_or_origin))
+       add_location_or_const_value_attribute (parm_die, node_or_origin,
+                                              node == NULL, DW_AT_location);
 
-      /* GNU extension: Record what type this method came from originally.  */
-      if (debug_info_level > DINFO_LEVEL_TERSE
-         && DECL_CONTEXT (func_decl))
-       add_AT_die_ref (die, DW_AT_containing_type,
-                       lookup_type_die (DECL_CONTEXT (func_decl)));
-    }
-}
-\f
-/* Add source coordinate attributes for the given decl.  */
+      break;
 
-static void
-add_src_coords_attributes (dw_die_ref die, tree decl)
-{
-  expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+    case tcc_type:
+      /* We were called with some kind of a ..._TYPE node.  */
+      add_type_attribute (parm_die, node_or_origin, 0, 0, context_die);
+      break;
 
-  add_AT_file (die, DW_AT_decl_file, lookup_filename (s.file));
-  add_AT_unsigned (die, DW_AT_decl_line, s.line);
+    default:
+      gcc_unreachable ();
+    }
+
+  return parm_die;
 }
 
-/* Add a DW_AT_name attribute and source coordinate attribute for the
-   given decl, but only if it actually has a name.  */
+/* Generate and return a DW_TAG_GNU_formal_parameter_pack. Also generate
+   children DW_TAG_formal_parameter DIEs representing the arguments of the
+   parameter pack.
 
-static void
-add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
-{
-  tree decl_name;
+   PARM_PACK must be a function parameter pack.
+   PACK_ARG is the first argument of the parameter pack. Its TREE_CHAIN
+   must point to the subsequent arguments of the function PACK_ARG belongs to.
+   SUBR_DIE is the DIE of the function PACK_ARG belongs to.
+   If NEXT_ARG is non NULL, *NEXT_ARG is set to the function argument
+   following the last one for which a DIE was generated.  */
 
-  decl_name = DECL_NAME (decl);
-  if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL)
-    {
-      const char *name = dwarf2_name (decl, 0);
-      if (name)
-       add_name_attribute (die, name);
-      if (! DECL_ARTIFICIAL (decl))
-       add_src_coords_attributes (die, decl);
+static dw_die_ref
+gen_formal_parameter_pack_die  (tree parm_pack,
+                               tree pack_arg,
+                               dw_die_ref subr_die,
+                               tree *next_arg)
+{
+  tree arg;
+  dw_die_ref parm_pack_die;
 
-      if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
-         && TREE_PUBLIC (decl)
-         && !DECL_ABSTRACT (decl)
-         && !(TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl)))
-       {
-         /* Defer until we have an assembler name set.  */
-         if (!DECL_ASSEMBLER_NAME_SET_P (decl))
-           {
-             limbo_die_node *asm_name;
+  gcc_assert (parm_pack
+             && lang_hooks.function_parameter_pack_p (parm_pack)
+             && subr_die);
 
-             asm_name = GGC_CNEW (limbo_die_node);
-             asm_name->die = die;
-             asm_name->created_for = decl;
-             asm_name->next = deferred_asm_name;
-             deferred_asm_name = asm_name;
-           }
-         else if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
-           add_AT_string (die, AT_linkage_name,
-                          IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
-       }
-    }
+  parm_pack_die = new_die (DW_TAG_GNU_formal_parameter_pack, subr_die, parm_pack);
+  add_src_coords_attributes (parm_pack_die, parm_pack);
 
-#ifdef VMS_DEBUGGING_INFO
-  /* Get the function's name, as described by its RTL.  This may be different
-     from the DECL_NAME name used in the source file.  */
-  if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
+  for (arg = pack_arg; arg; arg = DECL_CHAIN (arg))
     {
-      add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
-                  XEXP (DECL_RTL (decl), 0));
-      VEC_safe_push (rtx, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
+      if (! lang_hooks.decls.function_parm_expanded_from_pack_p (arg,
+                                                                parm_pack))
+       break;
+      gen_formal_parameter_die (arg, NULL,
+                               false /* Don't emit name attribute.  */,
+                               parm_pack_die);
     }
-#endif
+  if (next_arg)
+    *next_arg = arg;
+  return parm_pack_die;
 }
 
-/* Push a new declaration scope.  */
+/* Generate a special type of DIE used as a stand-in for a trailing ellipsis
+   at the end of an (ANSI prototyped) formal parameters list.  */
 
 static void
-push_decl_scope (tree scope)
-{
-  VEC_safe_push (tree, gc, decl_scope_table, scope);
-}
-
-/* Pop a declaration scope.  */
-
-static inline void
-pop_decl_scope (void)
+gen_unspecified_parameters_die (tree decl_or_type, dw_die_ref context_die)
 {
-  VEC_pop (tree, decl_scope_table);
+  new_die (DW_TAG_unspecified_parameters, context_die, decl_or_type);
 }
 
-/* Return the DIE for the scope that immediately contains this type.
-   Non-named types get global scope.  Named types nested in other
-   types get their containing scope if it's open, or global scope
-   otherwise.  All other types (i.e. function-local named types) get
-   the current active scope.  */
+/* Generate a list of nameless DW_TAG_formal_parameter DIEs (and perhaps a
+   DW_TAG_unspecified_parameters DIE) to represent the types of the formal
+   parameters as specified in some function type specification (except for
+   those which appear as part of a function *definition*).  */
 
-static dw_die_ref
-scope_die_for (tree t, dw_die_ref context_die)
+static void
+gen_formal_types_die (tree function_or_method_type, dw_die_ref context_die)
 {
-  dw_die_ref scope_die = NULL;
-  tree containing_scope;
-  int i;
-
-  /* Non-types always go in the current scope.  */
-  gcc_assert (TYPE_P (t));
-
-  containing_scope = TYPE_CONTEXT (t);
+  tree link;
+  tree formal_type = NULL;
+  tree first_parm_type;
+  tree arg;
 
-  /* Use the containing namespace if it was passed in (for a declaration).  */
-  if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL)
+  if (TREE_CODE (function_or_method_type) == FUNCTION_DECL)
     {
-      if (context_die == lookup_decl_die (containing_scope))
-       /* OK */;
-      else
-       containing_scope = NULL_TREE;
+      arg = DECL_ARGUMENTS (function_or_method_type);
+      function_or_method_type = TREE_TYPE (function_or_method_type);
     }
+  else
+    arg = NULL_TREE;
 
-  /* Ignore function type "scopes" from the C frontend.  They mean that
-     a tagged type is local to a parmlist of a function declarator, but
-     that isn't useful to DWARF.  */
-  if (containing_scope && TREE_CODE (containing_scope) == FUNCTION_TYPE)
-    containing_scope = NULL_TREE;
+  first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
 
-  if (containing_scope == NULL_TREE)
-    scope_die = comp_unit_die;
-  else if (TYPE_P (containing_scope))
+  /* Make our first pass over the list of formal parameter types and output a
+     DW_TAG_formal_parameter DIE for each one.  */
+  for (link = first_parm_type; link; )
     {
-      /* For types, we can just look up the appropriate DIE.  But
-        first we check to see if we're in the middle of emitting it
-        so we know where the new DIE should go.  */
-      for (i = VEC_length (tree, decl_scope_table) - 1; i >= 0; --i)
-       if (VEC_index (tree, decl_scope_table, i) == containing_scope)
-         break;
+      dw_die_ref parm_die;
 
-      if (i < 0)
-       {
-         gcc_assert (debug_info_level <= DINFO_LEVEL_TERSE
-                     || TREE_ASM_WRITTEN (containing_scope));
+      formal_type = TREE_VALUE (link);
+      if (formal_type == void_type_node)
+       break;
 
-         /* If none of the current dies are suitable, we get file scope.  */
-         scope_die = comp_unit_die;
+      /* Output a (nameless) DIE to represent the formal parameter itself.  */
+      parm_die = gen_formal_parameter_die (formal_type, NULL,
+                                          true /* Emit name attribute.  */,
+                                          context_die);
+      if (TREE_CODE (function_or_method_type) == METHOD_TYPE
+         && link == first_parm_type)
+       {
+         add_AT_flag (parm_die, DW_AT_artificial, 1);
+         if (dwarf_version >= 3 || !dwarf_strict)
+           add_AT_die_ref (context_die, DW_AT_object_pointer, parm_die);
        }
-      else
-       scope_die = lookup_type_die (containing_scope);
-    }
-  else
-    scope_die = context_die;
-
-  return scope_die;
-}
+      else if (arg && DECL_ARTIFICIAL (arg))
+       add_AT_flag (parm_die, DW_AT_artificial, 1);
 
-/* Returns nonzero if CONTEXT_DIE is internal to a function.  */
+      link = TREE_CHAIN (link);
+      if (arg)
+       arg = DECL_CHAIN (arg);
+    }
 
-static inline int
-local_scope_p (dw_die_ref context_die)
-{
-  for (; context_die; context_die = context_die->die_parent)
-    if (context_die->die_tag == DW_TAG_inlined_subroutine
-       || context_die->die_tag == DW_TAG_subprogram)
-      return 1;
+  /* If this function type has an ellipsis, add a
+     DW_TAG_unspecified_parameters DIE to the end of the parameter list.  */
+  if (formal_type != void_type_node)
+    gen_unspecified_parameters_die (function_or_method_type, context_die);
 
-  return 0;
+  /* Make our second (and final) pass over the list of formal parameter types
+     and output DIEs to represent those types (as necessary).  */
+  for (link = TYPE_ARG_TYPES (function_or_method_type);
+       link && TREE_VALUE (link);
+       link = TREE_CHAIN (link))
+    gen_type_die (TREE_VALUE (link), context_die);
 }
 
-/* Returns nonzero if CONTEXT_DIE is a class.  */
+/* We want to generate the DIE for TYPE so that we can generate the
+   die for MEMBER, which has been defined; we will need to refer back
+   to the member declaration nested within TYPE.  If we're trying to
+   generate minimal debug info for TYPE, processing TYPE won't do the
+   trick; we need to attach the member declaration by hand.  */
 
-static inline int
-class_scope_p (dw_die_ref context_die)
+static void
+gen_type_die_for_member (tree type, tree member, dw_die_ref context_die)
 {
-  return (context_die
-         && (context_die->die_tag == DW_TAG_structure_type
-             || context_die->die_tag == DW_TAG_class_type
-             || context_die->die_tag == DW_TAG_interface_type
-             || context_die->die_tag == DW_TAG_union_type));
-}
+  gen_type_die (type, context_die);
 
-/* Returns nonzero if CONTEXT_DIE is a class or namespace, for deciding
-   whether or not to treat a DIE in this context as a declaration.  */
+  /* If we're trying to avoid duplicate debug info, we may not have
+     emitted the member decl for this function.  Emit it now.  */
+  if (TYPE_STUB_DECL (type)
+      && TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
+      && ! lookup_decl_die (member))
+    {
+      dw_die_ref type_die;
+      gcc_assert (!decl_ultimate_origin (member));
 
-static inline int
-class_or_namespace_scope_p (dw_die_ref context_die)
-{
-  return (class_scope_p (context_die)
-         || (context_die && context_die->die_tag == DW_TAG_namespace));
+      push_decl_scope (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)
+       {
+         /* Ignore the nameless fields that are used to skip bits but handle
+            C++ anonymous unions and structs.  */
+         if (DECL_NAME (member) != NULL_TREE
+             || TREE_CODE (TREE_TYPE (member)) == UNION_TYPE
+             || TREE_CODE (TREE_TYPE (member)) == RECORD_TYPE)
+           {
+             gen_type_die (member_declared_type (member), type_die);
+             gen_field_die (member, type_die);
+           }
+       }
+      else
+       gen_variable_die (member, NULL_TREE, type_die);
+
+      pop_decl_scope ();
+    }
 }
 
-/* Many forms of DIEs require a "type description" attribute.  This
-   routine locates the proper "type descriptor" die for the type given
-   by 'type', and adds a DW_AT_type attribute below the given die.  */
+/* Generate the DWARF2 info for the "abstract" instance of a function which we
+   may later generate inlined and/or out-of-line instances of.  */
 
 static void
-add_type_attribute (dw_die_ref object_die, tree type, int decl_const,
-                   int decl_volatile, dw_die_ref context_die)
+dwarf2out_abstract_function (tree decl)
 {
-  enum tree_code code  = TREE_CODE (type);
-  dw_die_ref type_die  = NULL;
+  dw_die_ref old_die;
+  tree save_fn;
+  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;
 
-  /* ??? If this type is an unnamed subrange type of an integral, floating-point
-     or fixed-point type, use the inner type.  This is because we have no
-     support for unnamed types in base_type_die.  This can happen if this is
-     an Ada subrange type.  Correct solution is emit a subrange type die.  */
-  if ((code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE)
-      && TREE_TYPE (type) != 0 && TYPE_NAME (type) == 0)
-    type = TREE_TYPE (type), code = TREE_CODE (type);
+  /* Make sure we have the actual abstract inline, not a clone.  */
+  decl = DECL_ORIGIN (decl);
 
-  if (code == ERROR_MARK
-      /* Handle a special case.  For functions whose return type is void, we
-        generate *no* type attribute.  (Note that no object may have type
-        `void', so this only applies to function return types).  */
-      || code == VOID_TYPE)
+  old_die = lookup_decl_die (decl);
+  if (old_die && get_AT (old_die, DW_AT_inline))
+    /* We've already generated the abstract instance.  */
     return;
 
-  type_die = modified_type_die (type,
-                               decl_const || TYPE_READONLY (type),
-                               decl_volatile || TYPE_VOLATILE (type),
-                               context_die);
+  /* We can be called while recursively when seeing block defining inlined subroutine
+     DIE.  Be sure to not clobber the outer location table nor use it or we would
+     get locations in abstract instantces.  */
+  old_decl_loc_table = decl_loc_table;
+  decl_loc_table = NULL;
+  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.  */
+  if (debug_info_level > DINFO_LEVEL_TERSE)
+    {
+      context = decl_class_context (decl);
+      if (context)
+       gen_type_die_for_member
+         (context, decl, decl_function_context (decl) ? NULL : comp_unit_die ());
+    }
+
+  /* Pretend we've just finished compiling this function.  */
+  save_fn = current_function_decl;
+  current_function_decl = decl;
+  push_cfun (DECL_STRUCT_FUNCTION (decl));
+
+  was_abstract = DECL_ABSTRACT (decl);
+  set_decl_abstract_flags (decl, 1);
+  dwarf2out_decl (decl);
+  if (! was_abstract)
+    set_decl_abstract_flags (decl, 0);
 
-  if (type_die != NULL)
-    add_AT_die_ref (object_die, DW_AT_type, type_die);
+  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 ();
 }
 
-/* Given an object die, add the calling convention attribute for the
-   function call type.  */
-static void
-add_calling_convention_attribute (dw_die_ref subr_die, tree decl)
-{
-  enum dwarf_calling_convention value = DW_CC_normal;
+/* Helper function of premark_used_types() which gets called through
+   htab_traverse.
 
-  value = ((enum dwarf_calling_convention)
-          targetm.dwarf_calling_convention (TREE_TYPE (decl)));
+   Marks the DIE of a given type in *SLOT as perennial, so it never gets
+   marked as unused by prune_unused_types.  */
 
-  /* 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;
+static int
+premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+  tree type;
+  dw_die_ref die;
 
-  /* Only add the attribute if the backend requests it, and
-     is not DW_CC_normal.  */
-  if (value && (value != DW_CC_normal))
-    add_AT_unsigned (subr_die, DW_AT_calling_convention, value);
+  type = (tree) *slot;
+  die = lookup_type_die (type);
+  if (die != NULL)
+    die->die_perennial_p = 1;
+  return 1;
 }
 
-/* Given a tree pointer to a struct, class, union, or enum type node, return
-   a pointer to the (string) tag name for the given type, or zero if the type
-   was declared without a tag.  */
+/* Helper function of premark_types_used_by_global_vars which gets called
+   through htab_traverse.
 
-static const char *
-type_tag (const_tree type)
+   Marks the DIE of a given type in *SLOT as perennial, so it never gets
+   marked as unused by prune_unused_types. The DIE of the type is marked
+   only if the global variable using the type will actually be emitted.  */
+
+static int
+premark_types_used_by_global_vars_helper (void **slot,
+                                         void *data ATTRIBUTE_UNUSED)
 {
-  const char *name = 0;
+  struct types_used_by_vars_entry *entry;
+  dw_die_ref die;
 
-  if (TYPE_NAME (type) != 0)
+  entry = (struct types_used_by_vars_entry *) *slot;
+  gcc_assert (entry->type != NULL
+             && entry->var_decl != NULL);
+  die = lookup_type_die (entry->type);
+  if (die)
     {
-      tree t = 0;
-
-      /* Find the IDENTIFIER_NODE for the type name.  */
-      if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
-       t = TYPE_NAME (type);
-
-      /* The g++ front end makes the TYPE_NAME of *each* tagged type point to
-        a TYPE_DECL node, regardless of whether or not a `typedef' was
-        involved.  */
-      else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
-              && ! DECL_IGNORED_P (TYPE_NAME (type)))
+      /* Ask cgraph if the global variable really is to be emitted.
+         If yes, then we'll keep the DIE of ENTRY->TYPE.  */
+      struct varpool_node *node = varpool_get_node (entry->var_decl);
+      if (node && node->needed)
        {
-         /* We want to be extra verbose.  Don't call dwarf_name if
-            DECL_NAME isn't set.  The default hook for decl_printable_name
-            doesn't like that, and in this context it's correct to return
-            0, instead of "<anonymous>" or the like.  */
-         if (DECL_NAME (TYPE_NAME (type)))
-           name = lang_hooks.dwarf_name (TYPE_NAME (type), 2);
+         die->die_perennial_p = 1;
+         /* Keep the parent DIEs as well.  */
+         while ((die = die->die_parent) && die->die_perennial_p == 0)
+           die->die_perennial_p = 1;
        }
-
-      /* Now get the name as a string, or invent one.  */
-      if (!name && t != 0)
-       name = IDENTIFIER_POINTER (t);
     }
-
-  return (name == 0 || *name == '\0') ? 0 : name;
+  return 1;
 }
 
-/* Return the type associated with a data member, make a special check
-   for bit field types.  */
+/* Mark all members of used_types_hash as perennial.  */
 
-static inline tree
-member_declared_type (const_tree member)
+static void
+premark_used_types (void)
 {
-  return (DECL_BIT_FIELD_TYPE (member)
-         ? DECL_BIT_FIELD_TYPE (member) : TREE_TYPE (member));
+  if (cfun && cfun->used_types_hash)
+    htab_traverse (cfun->used_types_hash, premark_used_types_helper, NULL);
 }
 
-/* Get the decl's label, as described by its RTL. This may be different
-   from the DECL_NAME name used in the source file.  */
+/* Mark all members of types_used_by_vars_entry as perennial.  */
 
-#if 0
-static const char *
-decl_start_label (tree decl)
+static void
+premark_types_used_by_global_vars (void)
 {
-  rtx x;
-  const char *fnname;
+  if (types_used_by_vars_hash)
+    htab_traverse (types_used_by_vars_hash,
+                  premark_types_used_by_global_vars_helper, NULL);
+}
 
-  x = DECL_RTL (decl);
-  gcc_assert (MEM_P (x));
+/* Generate a DW_TAG_GNU_call_site DIE in function DECL under SUBR_DIE
+   for CA_LOC call arg loc node.  */
 
-  x = XEXP (x, 0);
-  gcc_assert (GET_CODE (x) == SYMBOL_REF);
+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;
 
-  fnname = XSTR (x, 0);
-  return fnname;
+  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;
 }
-#endif
-\f
-/* These routines generate the internal representation of the DIE's for
-   the compilation unit.  Debugging information is collected by walking
-   the declaration trees passed in from dwarf2out_decl().  */
+
+/* Generate a DIE to represent a declared function (either file-scope or
+   block-local).  */
 
 static void
-gen_array_type_die (tree type, dw_die_ref context_die)
+gen_subprogram_die (tree decl, dw_die_ref context_die)
 {
-  dw_die_ref scope_die = scope_die_for (type, context_die);
-  dw_die_ref array_die;
+  tree origin = decl_ultimate_origin (decl);
+  dw_die_ref subr_die;
+  tree outer_scope;
+  dw_die_ref old_die = lookup_decl_die (decl);
+  int declaration = (current_function_decl != decl
+                    || class_or_namespace_scope_p (context_die));
 
-  /* GNU compilers represent multidimensional array types as sequences of one
-     dimensional array types whose element types are themselves array types.
-     We sometimes squish that down to a single array_type DIE with multiple
-     subscripts in the Dwarf debugging info.  The draft Dwarf specification
-     say that we are allowed to do this kind of compression in C, because
-     there is no difference between an array of arrays and a multidimensional
-     array.  We don't do this for Ada to remain as close as possible to the
-     actual representation, which is especially important against the language
-     flexibilty wrt arrays of variable size.  */
+  premark_used_types ();
 
-  bool collapse_nested_arrays = !is_ada ();
-  tree element_type;
+  /* It is possible to have both DECL_ABSTRACT and DECLARATION be true if we
+     started to generate the abstract instance of an inline, decided to output
+     its containing class, and proceeded to emit the declaration of the inline
+     from the member list for the class.  If so, DECLARATION takes priority;
+     we'll get back to the abstract instance when done with the class.  */
 
-  /* Emit DW_TAG_string_type for Fortran character types (with kind 1 only, as
-     DW_TAG_string_type doesn't have DW_AT_type attribute).  */
-  if (TYPE_STRING_FLAG (type)
-      && TREE_CODE (type) == ARRAY_TYPE
-      && is_fortran ()
-      && TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (char_type_node))
+  /* The class-scope declaration DIE must be the primary DIE.  */
+  if (origin && declaration && class_or_namespace_scope_p (context_die))
     {
-      HOST_WIDE_INT size;
-
-      array_die = new_die (DW_TAG_string_type, scope_die, type);
-      add_name_attribute (array_die, type_tag (type));
-      equate_type_number_to_die (type, array_die);
-      size = int_size_in_bytes (type);
-      if (size >= 0)
-       add_AT_unsigned (array_die, DW_AT_byte_size, size);
-      else if (TYPE_DOMAIN (type) != NULL_TREE
-              && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
-              && DECL_P (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
-       {
-         tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
-         dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2);
-
-         size = int_size_in_bytes (TREE_TYPE (szdecl));
-         if (loc && size > 0)
-           {
-             add_AT_location_description (array_die, DW_AT_string_length, loc);
-             if (size != DWARF2_ADDR_SIZE)
-               add_AT_unsigned (array_die, DW_AT_byte_size, size);
-           }
-       }
-      return;
+      origin = NULL;
+      gcc_assert (!old_die);
     }
 
-  /* ??? The SGI dwarf reader fails for array of array of enum types
-     (e.g. const enum machine_mode insn_operand_mode[2][10]) unless the inner
-     array type comes before the outer array type.  We thus call gen_type_die
-     before we new_die and must prevent nested array types collapsing for this
-     target.  */
+  /* Now that the C++ front end lazily declares artificial member fns, we
+     might need to retrofit the declaration into its class.  */
+  if (!declaration && !origin && !old_die
+      && DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))
+      && !class_or_namespace_scope_p (context_die)
+      && debug_info_level > DINFO_LEVEL_TERSE)
+    old_die = force_decl_die (decl);
 
-#ifdef MIPS_DEBUGGING_INFO
-  gen_type_die (TREE_TYPE (type), context_die);
-  collapse_nested_arrays = false;
-#endif
+  if (origin != NULL)
+    {
+      gcc_assert (!declaration || local_scope_p (context_die));
 
-  array_die = new_die (DW_TAG_array_type, scope_die, type);
-  add_name_attribute (array_die, type_tag (type));
-  equate_type_number_to_die (type, array_die);
+      /* Fixup die_parent for the abstract instance of a nested
+        inline function.  */
+      if (old_die && old_die->die_parent == NULL)
+       add_child_die (context_die, old_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);
+      subr_die = new_die (DW_TAG_subprogram, context_die, decl);
+      add_abstract_origin_attribute (subr_die, origin);
+      /*  This is where the actual code for a cloned function is.
+         Let's emit linkage name attribute for it.  This helps
+         debuggers to e.g, set breakpoints into
+         constructors/destructors when the user asks "break
+         K::K".  */
+      add_linkage_name (subr_die, decl);
     }
+  else if (old_die)
+    {
+      expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+      struct dwarf_file_data * file_index = lookup_filename (s.file);
 
-  /* For Fortran multidimensional arrays use DW_ORD_col_major ordering.  */
-  if (is_fortran ()
-      && TREE_CODE (type) == ARRAY_TYPE
-      && TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE
-      && !TYPE_STRING_FLAG (TREE_TYPE (type)))
-    add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_col_major);
+      if (!get_AT_flag (old_die, DW_AT_declaration)
+         /* We can have a normal definition following an inline one in the
+            case of redefinition of GNU C extern inlines.
+            It seems reasonable to use AT_specification in this case.  */
+         && !get_AT (old_die, DW_AT_inline))
+       {
+         /* Detect and ignore this case, where we are trying to output
+            something we have already output.  */
+         return;
+       }
 
-#if 0
-  /* We default the array ordering.  SDB will probably do
-     the right things even if DW_AT_ordering is not present.  It's not even
-     an issue until we start to get into multidimensional arrays anyway.  If
-     SDB is ever caught doing the Wrong Thing for multi-dimensional arrays,
-     then we'll have to put the DW_AT_ordering attribute back in.  (But if
-     and when we find out that we need to put these in, we will only do so
-     for multidimensional arrays.  */
-  add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major);
-#endif
+      /* If the definition comes from the same place as the declaration,
+        maybe use the old DIE.  We always want the DIE for this function
+        that has the *_pc attributes to be under comp_unit_die so the
+        debugger can find it.  We also need to do this for abstract
+        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 ((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)
+                     == (unsigned) s.line))))
+       {
+         subr_die = old_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))
-    add_AT_flag (array_die, DW_AT_declaration, 1);
+         /* Clear out the declaration attribute and the formal parameters.
+            Do not remove all children, because it is possible that this
+            declaration die was forced using force_decl_die(). In such
+            cases die that forced declaration die (e.g. TAG_imported_module)
+            is one of the children that we do not want to remove.  */
+         remove_AT (subr_die, DW_AT_declaration);
+         remove_AT (subr_die, DW_AT_object_pointer);
+         remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+       }
+      else
+       {
+         subr_die = new_die (DW_TAG_subprogram, context_die, decl);
+         add_AT_specification (subr_die, old_die);
+         if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
+           add_AT_file (subr_die, DW_AT_decl_file, file_index);
+         if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
+           add_AT_unsigned (subr_die, DW_AT_decl_line, s.line);
+       }
+    }
   else
-#endif
-    add_subscript_info (array_die, type, collapse_nested_arrays);
+    {
+      subr_die = new_die (DW_TAG_subprogram, context_die, decl);
 
-  /* Add representation of the type of the elements of this array type and
-     emit the corresponding DIE if we haven't done it already.  */
-  element_type = TREE_TYPE (type);
-  if (collapse_nested_arrays)
-    while (TREE_CODE (element_type) == ARRAY_TYPE)
-      {
-       if (TYPE_STRING_FLAG (element_type) && is_fortran ())
-         break;
-       element_type = TREE_TYPE (element_type);
-      }
+      if (TREE_PUBLIC (decl))
+       add_AT_flag (subr_die, DW_AT_external, 1);
 
-#ifndef MIPS_DEBUGGING_INFO
-  gen_type_die (element_type, context_die);
-#endif
+      add_name_and_src_coords_attributes (subr_die, decl);
+      if (debug_info_level > DINFO_LEVEL_TERSE)
+       {
+         add_prototyped_attribute (subr_die, TREE_TYPE (decl));
+         add_type_attribute (subr_die, TREE_TYPE (TREE_TYPE (decl)),
+                             0, 0, context_die);
+       }
 
-  add_type_attribute (array_die, element_type, 0, 0, context_die);
+      add_pure_or_virtual_attribute (subr_die, decl);
+      if (DECL_ARTIFICIAL (decl))
+       add_AT_flag (subr_die, DW_AT_artificial, 1);
 
-  if (get_AT (array_die, DW_AT_name))
-    add_pubtype (type, array_die);
-}
+      add_accessibility_attribute (subr_die, decl);
+    }
 
-static dw_loc_descr_ref
-descr_info_loc (tree val, tree base_decl)
-{
-  HOST_WIDE_INT size;
-  dw_loc_descr_ref loc, loc2;
-  enum dwarf_location_atom op;
+  if (declaration)
+    {
+      if (!old_die || !get_AT (old_die, DW_AT_inline))
+       {
+         add_AT_flag (subr_die, DW_AT_declaration, 1);
 
-  if (val == base_decl)
-    return new_loc_descr (DW_OP_push_object_address, 0, 0);
+         /* If this is an explicit function declaration then generate
+            a DW_AT_explicit attribute.  */
+         if (lang_hooks.decls.function_decl_explicit_p (decl)
+             && (dwarf_version >= 3 || !dwarf_strict))
+           add_AT_flag (subr_die, DW_AT_explicit, 1);
 
-  switch (TREE_CODE (val))
+         /* The first time we see a member function, it is in the context of
+            the class to which it belongs.  We make sure of this by emitting
+            the class first.  The next time is the definition, which is
+            handled above.  The two may come from the same source text.
+
+            Note that force_decl_die() forces function declaration die. It is
+            later reused to represent definition.  */
+         equate_decl_number_to_die (decl, subr_die);
+       }
+    }
+  else if (DECL_ABSTRACT (decl))
     {
-    CASE_CONVERT:
-      return descr_info_loc (TREE_OPERAND (val, 0), base_decl);
-    case VAR_DECL:
-      return loc_descriptor_from_tree (val, 0);
-    case INTEGER_CST:
-      if (host_integerp (val, 0))
-       return int_loc_descriptor (tree_low_cst (val, 0));
-      break;
-    case INDIRECT_REF:
-      size = int_size_in_bytes (TREE_TYPE (val));
-      if (size < 0)
-       break;
-      loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
-      if (!loc)
-       break;
-      if (size == DWARF2_ADDR_SIZE)
-       add_loc_descr (&loc, new_loc_descr (DW_OP_deref, 0, 0));
-      else
-       add_loc_descr (&loc, new_loc_descr (DW_OP_deref_size, size, 0));
-      return loc;
-    case POINTER_PLUS_EXPR:
-    case PLUS_EXPR:
-      if (host_integerp (TREE_OPERAND (val, 1), 1)
-         && (unsigned HOST_WIDE_INT) tree_low_cst (TREE_OPERAND (val, 1), 1)
-            < 16384)
+      if (DECL_DECLARED_INLINE_P (decl))
        {
-         loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
-         if (!loc)
-           break;
-         loc_descr_plus_const (&loc, tree_low_cst (TREE_OPERAND (val, 1), 0));
+         if (cgraph_function_possibly_inlined_p (decl))
+           add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
+         else
+           add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_not_inlined);
        }
       else
        {
-         op = DW_OP_plus;
-       do_binop:
-         loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
-         if (!loc)
-           break;
-         loc2 = descr_info_loc (TREE_OPERAND (val, 1), base_decl);
-         if (!loc2)
-           break;
-         add_loc_descr (&loc, loc2);
-         add_loc_descr (&loc2, new_loc_descr (op, 0, 0));
+         if (cgraph_function_possibly_inlined_p (decl))
+           add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
+         else
+           add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_not_inlined);
        }
-      return loc;
-    case MINUS_EXPR:
-      op = DW_OP_minus;
-      goto do_binop;
-    case MULT_EXPR:
-      op = DW_OP_mul;
-      goto do_binop;
-    case EQ_EXPR:
-      op = DW_OP_eq;
-      goto do_binop;
-    case NE_EXPR:
-      op = DW_OP_ne;
-      goto do_binop;
-    default:
-      break;
-    }
-  return NULL;
-}
 
-static void
-add_descr_info_field (dw_die_ref die, enum dwarf_attribute attr,
-                     tree val, tree base_decl)
-{
-  dw_loc_descr_ref loc;
+      if (DECL_DECLARED_INLINE_P (decl)
+         && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
+       add_AT_flag (subr_die, DW_AT_artificial, 1);
 
-  if (host_integerp (val, 0))
-    {
-      add_AT_unsigned (die, attr, tree_low_cst (val, 0));
-      return;
+      equate_decl_number_to_die (decl, subr_die);
     }
+  else if (!DECL_EXTERNAL (decl))
+    {
+      HOST_WIDE_INT cfa_fb_offset;
 
-  loc = descr_info_loc (val, base_decl);
-  if (!loc)
-    return;
+      if (!old_die || !get_AT (old_die, DW_AT_inline))
+       equate_decl_number_to_die (decl, subr_die);
 
-  add_AT_loc (die, attr, loc);
-}
+      if (!flag_reorder_blocks_and_partition)
+       {
+         dw_fde_ref fde = cfun->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);
+           }
 
-/* This routine generates DIE for array with hidden descriptor, details
-   are filled into *info by a langhook.  */
+#if VMS_DEBUGGING_INFO
+      /* HP OpenVMS Industry Standard 64: DWARF Extensions
+        Section 2.3 Prologue and Epilogue Attributes:
+        When a breakpoint is set on entry to a function, it is generally
+        desirable for execution to be suspended, not on the very first
+        instruction of the function, but rather at a point after the
+        function's frame has been set up, after any language defined local
+        declaration processing has been completed, and before execution of
+        the first statement of the function begins. Debuggers generally
+        cannot properly determine where this point is.  Similarly for a
+        breakpoint set on exit from a function. The prologue and epilogue
+        attributes allow a compiler to communicate the location(s) to use.  */
 
-static void
-gen_descr_array_type_die (tree type, struct array_descr_info *info,
-                         dw_die_ref context_die)
-{
-  dw_die_ref scope_die = scope_die_for (type, context_die);
-  dw_die_ref array_die;
-  int dim;
+      {
+        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);
 
-  array_die = new_die (DW_TAG_array_type, scope_die, type);
-  add_name_attribute (array_die, type_tag (type));
-  equate_type_number_to_die (type, array_die);
+        if (fde->dw_fde_vms_begin_epilogue)
+          add_AT_vms_delta (subr_die, DW_AT_HP_epilogue,
+           fde->dw_fde_begin, fde->dw_fde_vms_begin_epilogue);
+      }
+#endif
 
-  /* For Fortran multidimensional arrays use DW_ORD_col_major ordering.  */
-  if (is_fortran ()
-      && info->ndimensions >= 2)
-    add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_col_major);
+         add_pubname (decl, subr_die);
+       }
+      else
+       {
+         /* Generate pubnames entries for the split function code ranges.  */
+         dw_fde_ref fde = cfun->fde;
 
-  if (info->data_location)
-    add_descr_info_field (array_die, DW_AT_data_location, info->data_location,
-                         info->base_decl);
-  if (info->associated)
-    add_descr_info_field (array_die, DW_AT_associated, info->associated,
-                         info->base_decl);
-  if (info->allocated)
-    add_descr_info_field (array_die, DW_AT_allocated, info->allocated,
-                         info->base_decl);
+         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);
 
-  for (dim = 0; dim < info->ndimensions; dim++)
-    {
-      dw_die_ref subrange_die
-       = new_die (DW_TAG_subrange_type, array_die, NULL);
+                     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);
+           }
+       }
 
-      if (info->dimen[dim].lower_bound)
+#ifdef MIPS_DEBUGGING_INFO
+      /* Add a reference to the FDE for this routine.  */
+      add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, cfun->fde->fde_index);
+#endif
+
+      cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
+
+      /* We define the "frame base" as the function's CFA.  This is more
+        convenient for several reasons: (1) It's stable across the prologue
+        and epilogue, which makes it better than just a frame pointer,
+        (2) With dwarf3, there exists a one-byte encoding that allows us
+        to reference the .debug_frame data by proxy, but failing that,
+        (3) We can at least reuse the code inspection and interpretation
+        code that determines the CFA position at various points in the
+        function.  */
+      if (dwarf_version >= 3)
        {
-         /* If it is the default value, omit it.  */
-         int dflt;
-
-         if (host_integerp (info->dimen[dim].lower_bound, 0)
-             && (dflt = lower_bound_default ()) != -1
-             && tree_low_cst (info->dimen[dim].lower_bound, 0) == dflt)
-           ;
+         dw_loc_descr_ref op = new_loc_descr (DW_OP_call_frame_cfa, 0, 0);
+         add_AT_loc (subr_die, DW_AT_frame_base, op);
+       }
+      else
+       {
+         dw_loc_list_ref list = convert_cfa_to_fb_loc_list (cfa_fb_offset);
+         if (list->dw_loc_next)
+           add_AT_loc_list (subr_die, DW_AT_frame_base, list);
          else
-           add_descr_info_field (subrange_die, DW_AT_lower_bound,
-                                 info->dimen[dim].lower_bound,
-                                 info->base_decl);
+           add_AT_loc (subr_die, DW_AT_frame_base, list->expr);
        }
-      if (info->dimen[dim].upper_bound)
-       add_descr_info_field (subrange_die, DW_AT_upper_bound,
-                             info->dimen[dim].upper_bound,
-                             info->base_decl);
-      if (info->dimen[dim].stride)
-       add_descr_info_field (subrange_die, DW_AT_byte_stride,
-                             info->dimen[dim].stride,
-                             info->base_decl);
-    }
 
-  gen_type_die (info->element_type, context_die);
-  add_type_attribute (array_die, info->element_type, 0, 0, context_die);
+      /* Compute a displacement from the "steady-state frame pointer" to
+        the CFA.  The former is what all stack slots and argument slots
+        will reference in the rtl; the later is what we've told the
+        debugger about.  We'll need to adjust all frame_base references
+        by this displacement.  */
+      compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
 
-  if (get_AT (array_die, DW_AT_name))
-    add_pubtype (type, array_die);
-}
+      if (cfun->static_chain_decl)
+       add_AT_location_description (subr_die, DW_AT_static_link,
+                loc_list_from_tree (cfun->static_chain_decl, 2));
+    }
 
-#if 0
-static void
-gen_entry_point_die (tree decl, dw_die_ref context_die)
-{
-  tree origin = decl_ultimate_origin (decl);
-  dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die, decl);
+  /* Generate child dies for template paramaters.  */
+  if (debug_info_level > DINFO_LEVEL_TERSE)
+    gen_generic_params_dies (decl);
 
-  if (origin != NULL)
-    add_abstract_origin_attribute (decl_die, origin);
-  else
-    {
-      add_name_and_src_coords_attributes (decl_die, decl);
-      add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)),
-                         0, 0, context_die);
-    }
+  /* Now output descriptions of the arguments for this function. This gets
+     (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list
+     for a FUNCTION_DECL doesn't indicate cases where there was a trailing
+     `...' at the end of the formal parameter list.  In order to find out if
+     there was a trailing ellipsis or not, we must instead look at the type
+     associated with the FUNCTION_DECL.  This will be a node of type
+     FUNCTION_TYPE. If the chain of type nodes hanging off of this
+     FUNCTION_TYPE node ends with a void_type_node then there should *not* be
+     an ellipsis at the end.  */
 
-  if (DECL_ABSTRACT (decl))
-    equate_decl_number_to_die (decl, decl_die);
+  /* In the case where we are describing a mere function declaration, all we
+     need to do here (and all we *can* do here) is to describe the *types* of
+     its formal parameters.  */
+  if (debug_info_level <= DINFO_LEVEL_TERSE)
+    ;
+  else if (declaration)
+    gen_formal_types_die (decl, subr_die);
   else
-    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
-}
-#endif
-
-/* Walk through the list of incomplete types again, trying once more to
-   emit full debugging info for them.  */
+    {
+      /* Generate DIEs to represent all known formal parameters.  */
+      tree parm = DECL_ARGUMENTS (decl);
+      tree generic_decl = lang_hooks.decls.get_generic_function_decl (decl);
+      tree generic_decl_parm = generic_decl
+                               ? DECL_ARGUMENTS (generic_decl)
+                               : NULL;
 
-static void
-retry_incomplete_types (void)
-{
-  int i;
+      /* Now we want to walk the list of parameters of the function and
+        emit their relevant DIEs.
 
-  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);
-}
+        We consider the case of DECL being an instance of a generic function
+        as well as it being a normal function.
 
-/* Determine what tag to use for a record type.  */
+        If DECL is an instance of a generic function we walk the
+        parameters of the generic function declaration _and_ the parameters of
+        DECL itself. This is useful because we want to emit specific DIEs for
+        function parameter packs and those are declared as part of the
+        generic function declaration. In that particular case,
+        the parameter pack yields a DW_TAG_GNU_formal_parameter_pack DIE.
+        That DIE has children DIEs representing the set of arguments
+        of the pack. Note that the set of pack arguments can be empty.
+        In that case, the DW_TAG_GNU_formal_parameter_pack DIE will not have any
+        children DIE.
 
-static enum dwarf_tag
-record_type_tag (tree type)
-{
-  if (! lang_hooks.types.classify_record)
-    return DW_TAG_structure_type;
+        Otherwise, we just consider the parameters of DECL.  */
+      while (generic_decl_parm || parm)
+       {
+         if (generic_decl_parm
+             && lang_hooks.function_parameter_pack_p (generic_decl_parm))
+           gen_formal_parameter_pack_die (generic_decl_parm,
+                                          parm, subr_die,
+                                          &parm);
+         else if (parm)
+           {
+             dw_die_ref parm_die = gen_decl_die (parm, NULL, subr_die);
 
-  switch (lang_hooks.types.classify_record (type))
-    {
-    case RECORD_IS_STRUCT:
-      return DW_TAG_structure_type;
+             if (parm == DECL_ARGUMENTS (decl)
+                 && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
+                 && parm_die
+                 && (dwarf_version >= 3 || !dwarf_strict))
+               add_AT_die_ref (subr_die, DW_AT_object_pointer, parm_die);
 
-    case RECORD_IS_CLASS:
-      return DW_TAG_class_type;
+             parm = DECL_CHAIN (parm);
+           }
 
-    case RECORD_IS_INTERFACE:
-      if (dwarf_version >= 3 || !dwarf_strict)
-       return DW_TAG_interface_type;
-      return DW_TAG_structure_type;
+         if (generic_decl_parm)
+           generic_decl_parm = DECL_CHAIN (generic_decl_parm);
+       }
 
-    default:
-      gcc_unreachable ();
+      /* Decide whether we need an unspecified_parameters DIE at the end.
+        There are 2 more cases to do this for: 1) the ansi ... declaration -
+        this is detectable when the end of the arg list is not a
+        void_type_node 2) an unprototyped function declaration (not a
+        definition).  This just means that we have no info about the
+        parameters at all.  */
+      if (prototype_p (TREE_TYPE (decl)))
+       {
+         /* This is the prototyped case, check for....  */
+         if (stdarg_p (TREE_TYPE (decl)))
+           gen_unspecified_parameters_die (decl, subr_die);
+       }
+      else if (DECL_INITIAL (decl) == NULL_TREE)
+       gen_unspecified_parameters_die (decl, subr_die);
     }
-}
-
-/* Generate a DIE to represent an enumeration type.  Note that these DIEs
-   include all of the information about the enumeration values also. Each
-   enumerated type name/value is listed as a child of the enumerated type
-   DIE.  */
 
-static dw_die_ref
-gen_enumeration_type_die (tree type, dw_die_ref context_die)
-{
-  dw_die_ref type_die = lookup_type_die (type);
+  /* Output Dwarf info for all of the stuff within the body of the function
+     (if it has one - it may be just a declaration).  */
+  outer_scope = DECL_INITIAL (decl);
 
-  if (type_die == NULL)
-    {
-      type_die = new_die (DW_TAG_enumeration_type,
-                         scope_die_for (type, context_die), type);
-      equate_type_number_to_die (type, type_die);
-      add_name_attribute (type_die, type_tag (type));
-      if ((dwarf_version >= 4 || !dwarf_strict)
-         && ENUM_IS_SCOPED (type))
-       add_AT_flag (type_die, DW_AT_enum_class, 1);
-    }
-  else if (! TYPE_SIZE (type))
-    return type_die;
-  else
-    remove_AT (type_die, DW_AT_declaration);
+  /* OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
+     a function.  This BLOCK actually represents the outermost binding contour
+     for the function, i.e. the contour in which the function's formal
+     parameters and labels get declared. Curiously, it appears that the front
+     end doesn't actually put the PARM_DECL nodes for the current function onto
+     the BLOCK_VARS list for this outer scope, but are strung off of the
+     DECL_ARGUMENTS list for the function instead.
 
-  /* Handle a GNU C/C++ extension, i.e. incomplete enum types.  If the
-     given enum type is incomplete, do not generate the DW_AT_byte_size
-     attribute or the DW_AT_element_list attribute.  */
-  if (TYPE_SIZE (type))
+     The BLOCK_VARS list for the `outer_scope' does provide us with a list of
+     the LABEL_DECL nodes for the function however, and we output DWARF info
+     for those in decls_for_scope.  Just within the `outer_scope' there will be
+     a BLOCK node representing the function's outermost pair of curly braces,
+     and any blocks used for the base and member initializers of a C++
+     constructor function.  */
+  if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK)
     {
-      tree link;
+      int call_site_note_count = 0;
+      int tail_call_site_note_count = 0;
 
-      TREE_ASM_WRITTEN (type) = 1;
-      add_byte_size_attribute (type_die, type);
-      if (TYPE_STUB_DECL (type) != NULL_TREE)
-       add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
+      /* 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);
 
-      /* If the first reference to this type was as the return type of an
-        inline function, then it may not have a parent.  Fix this now.  */
-      if (type_die->die_parent == NULL)
-       add_child_die (scope_die_for (type, context_die), type_die);
+      current_function_has_inlines = 0;
+      decls_for_scope (outer_scope, subr_die, 0);
 
-      for (link = TYPE_VALUES (type);
-          link != NULL; link = TREE_CHAIN (link))
+      if (call_arg_locations && !dwarf_strict)
        {
-         dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die, link);
-         tree value = TREE_VALUE (link);
-
-         add_name_attribute (enum_die,
-                             IDENTIFIER_POINTER (TREE_PURPOSE (link)));
+         struct call_arg_loc_node *ca_loc;
+         for (ca_loc = call_arg_locations; ca_loc; ca_loc = ca_loc->next)
+           {
+             dw_die_ref die = NULL;
+             rtx tloc = NULL_RTX, tlocc = NULL_RTX;
+             rtx arg, next_arg;
 
-         if (TREE_CODE (value) == CONST_DECL)
-           value = DECL_INITIAL (value);
+             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, tdie = NULL;
+
+                 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;
+                   }
+                 reg = NULL;
+                 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 if (GET_CODE (XEXP (XEXP (arg, 0), 0))
+                          == DEBUG_PARAMETER_REF)
+                   {
+                     tree tdecl
+                       = DEBUG_PARAMETER_REF_DECL (XEXP (XEXP (arg, 0), 0));
+                     tdie = lookup_decl_die (tdecl);
+                     if (tdie == NULL)
+                       continue;
+                   }
+                 else
+                   continue;
+                 if (reg == NULL
+                     && GET_CODE (XEXP (XEXP (arg, 0), 0))
+                        != DEBUG_PARAMETER_REF)
+                   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);
+                 if (reg != NULL)
+                   add_AT_loc (cdie, DW_AT_location, reg);
+                 else if (tdie != NULL)
+                   add_AT_die_ref (cdie, DW_AT_abstract_origin, tdie);
+                 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 (host_integerp (value, TYPE_UNSIGNED (TREE_TYPE (value))))
-           /* DWARF2 does not provide a way of indicating whether or
-              not enumeration constants are signed or unsigned.  GDB
-              always assumes the values are signed, so we output all
-              values as if they were signed.  That means that
-              enumeration constants with very large unsigned values
-              will appear to have negative values in the debugger.  */
-           add_AT_int (enum_die, DW_AT_const_value,
-                       tree_low_cst (value, tree_int_cst_sgn (value) > 0));
+                 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++;
+               }
+           }
+       }
+      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;
     }
-  else
-    add_AT_flag (type_die, DW_AT_declaration, 1);
+  /* Add the calling convention attribute if requested.  */
+  add_calling_convention_attribute (subr_die, decl);
 
-  if (get_AT (type_die, DW_AT_name))
-    add_pubtype (type, type_die);
+}
 
-  return type_die;
+/* Returns a hash value for X (which really is a die_struct).  */
+
+static hashval_t
+common_block_die_table_hash (const void *x)
+{
+  const_dw_die_ref d = (const_dw_die_ref) x;
+  return (hashval_t) d->decl_id ^ htab_hash_pointer (d->die_parent);
 }
 
-/* Generate a DIE to represent either a real live formal parameter decl or to
-   represent just the type of some formal parameter position in some function
-   type.
+/* Return nonzero if decl_id and die_parent of die_struct X is the same
+   as decl_id and die_parent of die_struct Y.  */
 
-   Note that this routine is a bit unusual because its argument may be a
-   ..._DECL node (i.e. either a PARM_DECL or perhaps a VAR_DECL which
-   represents an inlining of some PARM_DECL) or else some sort of a ..._TYPE
-   node.  If it's the former then this function is being called to output a
-   DIE to represent a formal parameter object (or some inlining thereof).  If
-   it's the latter, then this function is only being called to output a
-   DW_TAG_formal_parameter DIE to stand as a placeholder for some formal
-   argument type of some subprogram type.
-   If EMIT_NAME_P is true, name and source coordinate attributes
-   are emitted.  */
+static int
+common_block_die_table_eq (const void *x, const void *y)
+{
+  const_dw_die_ref d = (const_dw_die_ref) x;
+  const_dw_die_ref e = (const_dw_die_ref) y;
+  return d->decl_id == e->decl_id && d->die_parent == e->die_parent;
+}
 
-static dw_die_ref
-gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
-                         dw_die_ref context_die)
+/* Generate a DIE to represent a declared data object.
+   Either DECL or ORIGIN must be non-null.  */
+
+static void
+gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 {
-  tree node_or_origin = node ? node : origin;
+  HOST_WIDE_INT off;
+  tree com_decl;
+  tree decl_or_origin = decl ? decl : origin;
   tree ultimate_origin;
-  dw_die_ref parm_die
-    = new_die (DW_TAG_formal_parameter, context_die, node);
+  dw_die_ref var_die;
+  dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL;
+  dw_die_ref origin_die;
+  bool declaration = (DECL_EXTERNAL (decl_or_origin)
+                     || class_or_namespace_scope_p (context_die));
+  bool specialization_p = false;
 
-  switch (TREE_CODE_CLASS (TREE_CODE (node_or_origin)))
+  ultimate_origin = decl_ultimate_origin (decl_or_origin);
+  if (decl || ultimate_origin)
+    origin = ultimate_origin;
+  com_decl = fortran_common (decl_or_origin, &off);
+
+  /* Symbol in common gets emitted as a child of the common block, in the form
+     of a data member.  */
+  if (com_decl)
     {
-    case tcc_declaration:
-      ultimate_origin = decl_ultimate_origin (node_or_origin);
-      if (node || ultimate_origin)
-       origin = ultimate_origin;
-      if (origin != NULL)
-       add_abstract_origin_attribute (parm_die, origin);
-      else
+      dw_die_ref com_die;
+      dw_loc_list_ref loc;
+      die_node com_die_arg;
+
+      var_die = lookup_decl_die (decl_or_origin);
+      if (var_die)
        {
-         tree type = TREE_TYPE (node);
-         if (emit_name_p)
-           add_name_and_src_coords_attributes (parm_die, node);
-         if (decl_by_reference_p (node))
-           add_type_attribute (parm_die, TREE_TYPE (type), 0, 0,
-                               context_die);
-         else
-           add_type_attribute (parm_die, type,
-                               TREE_READONLY (node),
-                               TREE_THIS_VOLATILE (node),
-                               context_die);
-         if (DECL_ARTIFICIAL (node))
-           add_AT_flag (parm_die, DW_AT_artificial, 1);
+         if (get_AT (var_die, DW_AT_location) == NULL)
+           {
+             loc = loc_list_from_tree (com_decl, off ? 1 : 2);
+             if (loc)
+               {
+                 if (off)
+                   {
+                     /* Optimize the common case.  */
+                     if (single_element_loc_list_p (loc)
+                         && loc->expr->dw_loc_opc == DW_OP_addr
+                         && loc->expr->dw_loc_next == NULL
+                         && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr)
+                            == SYMBOL_REF)
+                       loc->expr->dw_loc_oprnd1.v.val_addr
+                         = plus_constant (loc->expr->dw_loc_oprnd1.v.val_addr, off);
+                       else
+                         loc_list_plus_const (loc, off);
+                   }
+                 add_AT_location_description (var_die, DW_AT_location, loc);
+                 remove_AT (var_die, DW_AT_declaration);
+               }
+           }
+         return;
        }
 
-      if (node && node != origin)
-        equate_decl_number_to_die (node, parm_die);
-      if (! DECL_ABSTRACT (node_or_origin))
-       add_location_or_const_value_attribute (parm_die, node_or_origin,
-                                              DW_AT_location);
-
-      break;
+      if (common_block_die_table == NULL)
+       common_block_die_table
+         = htab_create_ggc (10, common_block_die_table_hash,
+                            common_block_die_table_eq, NULL);
 
-    case tcc_type:
-      /* We were called with some kind of a ..._TYPE node.  */
-      add_type_attribute (parm_die, node_or_origin, 0, 0, context_die);
-      break;
+      com_die_arg.decl_id = DECL_UID (com_decl);
+      com_die_arg.die_parent = context_die;
+      com_die = (dw_die_ref) htab_find (common_block_die_table, &com_die_arg);
+      loc = loc_list_from_tree (com_decl, 2);
+      if (com_die == NULL)
+       {
+         const char *cnam
+           = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (com_decl));
+         void **slot;
 
-    default:
-      gcc_unreachable ();
+         com_die = new_die (DW_TAG_common_block, context_die, decl);
+         add_name_and_src_coords_attributes (com_die, com_decl);
+         if (loc)
+           {
+             add_AT_location_description (com_die, DW_AT_location, loc);
+             /* Avoid sharing the same loc descriptor between
+                DW_TAG_common_block and DW_TAG_variable.  */
+             loc = loc_list_from_tree (com_decl, 2);
+           }
+          else if (DECL_EXTERNAL (decl))
+           add_AT_flag (com_die, DW_AT_declaration, 1);
+         add_pubname_string (cnam, com_die); /* ??? needed? */
+         com_die->decl_id = DECL_UID (com_decl);
+         slot = htab_find_slot (common_block_die_table, com_die, INSERT);
+         *slot = (void *) com_die;
+       }
+      else if (get_AT (com_die, DW_AT_location) == NULL && loc)
+       {
+         add_AT_location_description (com_die, DW_AT_location, loc);
+         loc = loc_list_from_tree (com_decl, 2);
+         remove_AT (com_die, DW_AT_declaration);
+       }
+      var_die = new_die (DW_TAG_variable, com_die, decl);
+      add_name_and_src_coords_attributes (var_die, decl);
+      add_type_attribute (var_die, TREE_TYPE (decl), TREE_READONLY (decl),
+                         TREE_THIS_VOLATILE (decl), context_die);
+      add_AT_flag (var_die, DW_AT_external, 1);
+      if (loc)
+       {
+         if (off)
+           {
+             /* Optimize the common case.  */
+             if (single_element_loc_list_p (loc)
+                 && loc->expr->dw_loc_opc == DW_OP_addr
+                 && loc->expr->dw_loc_next == NULL
+                 && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
+               loc->expr->dw_loc_oprnd1.v.val_addr
+                 = plus_constant (loc->expr->dw_loc_oprnd1.v.val_addr, off);
+             else
+               loc_list_plus_const (loc, off);
+           }
+         add_AT_location_description (var_die, DW_AT_location, loc);
+       }
+      else if (DECL_EXTERNAL (decl))
+       add_AT_flag (var_die, DW_AT_declaration, 1);
+      equate_decl_number_to_die (decl, var_die);
+      return;
     }
 
-  return parm_die;
-}
-
-/* Generate and return a DW_TAG_GNU_formal_parameter_pack. Also generate
-   children DW_TAG_formal_parameter DIEs representing the arguments of the
-   parameter pack.
-
-   PARM_PACK must be a function parameter pack.
-   PACK_ARG is the first argument of the parameter pack. Its TREE_CHAIN
-   must point to the subsequent arguments of the function PACK_ARG belongs to.
-   SUBR_DIE is the DIE of the function PACK_ARG belongs to.
-   If NEXT_ARG is non NULL, *NEXT_ARG is set to the function argument
-   following the last one for which a DIE was generated.  */
-
-static dw_die_ref
-gen_formal_parameter_pack_die  (tree parm_pack,
-                               tree pack_arg,
-                               dw_die_ref subr_die,
-                               tree *next_arg)
-{
-  tree arg;
-  dw_die_ref parm_pack_die;
-
-  gcc_assert (parm_pack
-             && lang_hooks.function_parameter_pack_p (parm_pack)
-             && subr_die);
-
-  parm_pack_die = new_die (DW_TAG_GNU_formal_parameter_pack, subr_die, parm_pack);
-  add_src_coords_attributes (parm_pack_die, parm_pack);
-
-  for (arg = pack_arg; arg; arg = TREE_CHAIN (arg))
-    {
-      if (! lang_hooks.decls.function_parm_expanded_from_pack_p (arg,
-                                                                parm_pack))
-       break;
-      gen_formal_parameter_die (arg, NULL,
-                               false /* Don't emit name attribute.  */,
-                               parm_pack_die);
-    }
-  if (next_arg)
-    *next_arg = arg;
-  return parm_pack_die;
-}
+  /* If the compiler emitted a definition for the DECL declaration
+     and if we already emitted a DIE for it, don't emit a second
+     DIE for it again. Allow re-declarations of DECLs that are
+     inside functions, though.  */
+  if (old_die && declaration && !local_scope_p (context_die))
+    return;
 
-/* Generate a special type of DIE used as a stand-in for a trailing ellipsis
-   at the end of an (ANSI prototyped) formal parameters list.  */
+  /* For static data members, the declaration in the class is supposed
+     to have DW_TAG_member tag; the specification should still be
+     DW_TAG_variable referencing the DW_TAG_member DIE.  */
+  if (declaration && class_scope_p (context_die))
+    var_die = new_die (DW_TAG_member, context_die, decl);
+  else
+    var_die = new_die (DW_TAG_variable, context_die, decl);
 
-static void
-gen_unspecified_parameters_die (tree decl_or_type, dw_die_ref context_die)
-{
-  new_die (DW_TAG_unspecified_parameters, context_die, decl_or_type);
-}
+  origin_die = NULL;
+  if (origin != NULL)
+    origin_die = add_abstract_origin_attribute (var_die, origin);
 
-/* Generate a list of nameless DW_TAG_formal_parameter DIEs (and perhaps a
-   DW_TAG_unspecified_parameters DIE) to represent the types of the formal
-   parameters as specified in some function type specification (except for
-   those which appear as part of a function *definition*).  */
+  /* Loop unrolling can create multiple blocks that refer to the same
+     static variable, so we must test for the DW_AT_declaration flag.
 
-static void
-gen_formal_types_die (tree function_or_method_type, dw_die_ref context_die)
-{
-  tree link;
-  tree formal_type = NULL;
-  tree first_parm_type;
-  tree arg;
+     ??? Loop unrolling/reorder_blocks should perhaps be rewritten to
+     copy decls and set the DECL_ABSTRACT flag on them instead of
+     sharing them.
 
-  if (TREE_CODE (function_or_method_type) == FUNCTION_DECL)
+     ??? Duplicated blocks have been rewritten to use .debug_ranges.
+
+     ??? The declare_in_namespace support causes us to get two DIEs for one
+     variable, both of which are declarations.  We want to avoid considering
+     one to be a specification, so we must test that this DIE is not a
+     declaration.  */
+  else if (old_die && TREE_STATIC (decl) && ! declaration
+          && get_AT_flag (old_die, DW_AT_declaration) == 1)
     {
-      arg = DECL_ARGUMENTS (function_or_method_type);
-      function_or_method_type = TREE_TYPE (function_or_method_type);
-    }
-  else
-    arg = NULL_TREE;
+      /* This is a definition of a C++ class level static.  */
+      add_AT_specification (var_die, old_die);
+      specialization_p = true;
+      if (DECL_NAME (decl))
+       {
+         expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+         struct dwarf_file_data * file_index = lookup_filename (s.file);
 
-  first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
+         if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
+           add_AT_file (var_die, DW_AT_decl_file, file_index);
 
-  /* Make our first pass over the list of formal parameter types and output a
-     DW_TAG_formal_parameter DIE for each one.  */
-  for (link = first_parm_type; link; )
-    {
-      dw_die_ref parm_die;
+         if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
+           add_AT_unsigned (var_die, DW_AT_decl_line, s.line);
 
-      formal_type = TREE_VALUE (link);
-      if (formal_type == void_type_node)
-       break;
+         if (old_die->die_tag == DW_TAG_member)
+           add_linkage_name (var_die, decl);
+       }
+    }
+  else
+    add_name_and_src_coords_attributes (var_die, decl);
 
-      /* Output a (nameless) DIE to represent the formal parameter itself.  */
-      parm_die = gen_formal_parameter_die (formal_type, NULL,
-                                          true /* Emit name attribute.  */,
-                                          context_die);
-      if ((TREE_CODE (function_or_method_type) == METHOD_TYPE
-          && link == first_parm_type)
-         || (arg && DECL_ARTIFICIAL (arg)))
-       add_AT_flag (parm_die, DW_AT_artificial, 1);
+  if ((origin == NULL && !specialization_p)
+      || (origin != NULL
+         && !DECL_ABSTRACT (decl_or_origin)
+         && variably_modified_type_p (TREE_TYPE (decl_or_origin),
+                                      decl_function_context
+                                                       (decl_or_origin))))
+    {
+      tree type = TREE_TYPE (decl_or_origin);
 
-      link = TREE_CHAIN (link);
-      if (arg)
-       arg = TREE_CHAIN (arg);
+      if (decl_by_reference_p (decl_or_origin))
+       add_type_attribute (var_die, TREE_TYPE (type), 0, 0, context_die);
+      else
+       add_type_attribute (var_die, type, TREE_READONLY (decl_or_origin),
+                           TREE_THIS_VOLATILE (decl_or_origin), context_die);
     }
 
-  /* If this function type has an ellipsis, add a
-     DW_TAG_unspecified_parameters DIE to the end of the parameter list.  */
-  if (formal_type != void_type_node)
-    gen_unspecified_parameters_die (function_or_method_type, context_die);
+  if (origin == NULL && !specialization_p)
+    {
+      if (TREE_PUBLIC (decl))
+       add_AT_flag (var_die, DW_AT_external, 1);
 
-  /* Make our second (and final) pass over the list of formal parameter types
-     and output DIEs to represent those types (as necessary).  */
-  for (link = TYPE_ARG_TYPES (function_or_method_type);
-       link && TREE_VALUE (link);
-       link = TREE_CHAIN (link))
-    gen_type_die (TREE_VALUE (link), context_die);
-}
+      if (DECL_ARTIFICIAL (decl))
+       add_AT_flag (var_die, DW_AT_artificial, 1);
 
-/* We want to generate the DIE for TYPE so that we can generate the
-   die for MEMBER, which has been defined; we will need to refer back
-   to the member declaration nested within TYPE.  If we're trying to
-   generate minimal debug info for TYPE, processing TYPE won't do the
-   trick; we need to attach the member declaration by hand.  */
+      add_accessibility_attribute (var_die, decl);
+    }
 
-static void
-gen_type_die_for_member (tree type, tree member, dw_die_ref context_die)
-{
-  gen_type_die (type, context_die);
+  if (declaration)
+    add_AT_flag (var_die, DW_AT_declaration, 1);
 
-  /* If we're trying to avoid duplicate debug info, we may not have
-     emitted the member decl for this function.  Emit it now.  */
-  if (TYPE_STUB_DECL (type)
-      && TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
-      && ! lookup_decl_die (member))
-    {
-      dw_die_ref type_die;
-      gcc_assert (!decl_ultimate_origin (member));
+  if (decl && (DECL_ABSTRACT (decl) || declaration || old_die == NULL))
+    equate_decl_number_to_die (decl, var_die);
 
-      push_decl_scope (type);
-      type_die = lookup_type_die (type);
-      if (TREE_CODE (member) == FUNCTION_DECL)
-       gen_subprogram_die (member, type_die);
-      else if (TREE_CODE (member) == FIELD_DECL)
-       {
-         /* Ignore the nameless fields that are used to skip bits but handle
-            C++ anonymous unions and structs.  */
-         if (DECL_NAME (member) != NULL_TREE
-             || TREE_CODE (TREE_TYPE (member)) == UNION_TYPE
-             || TREE_CODE (TREE_TYPE (member)) == RECORD_TYPE)
-           {
-             gen_type_die (member_declared_type (member), type_die);
-             gen_field_die (member, type_die);
-           }
-       }
+  if (! declaration
+      && (! DECL_ABSTRACT (decl_or_origin)
+         /* Local static vars are shared between all clones/inlines,
+            so emit DW_AT_location on the abstract DIE if DECL_RTL is
+            already set.  */
+         || (TREE_CODE (decl_or_origin) == VAR_DECL
+             && TREE_STATIC (decl_or_origin)
+             && DECL_RTL_SET_P (decl_or_origin)))
+      /* When abstract origin already has DW_AT_location attribute, no need
+        to add it again.  */
+      && (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL))
+    {
+      if (TREE_CODE (decl_or_origin) == VAR_DECL && TREE_STATIC (decl_or_origin)
+          && !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl_or_origin)))
+       defer_location (decl_or_origin, var_die);
       else
-       gen_variable_die (member, NULL_TREE, type_die);
-
-      pop_decl_scope ();
+        add_location_or_const_value_attribute (var_die, decl_or_origin,
+                                              decl == NULL, DW_AT_location);
+      add_pubname (decl_or_origin, var_die);
     }
+  else
+    tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
 }
 
-/* Generate the DWARF2 info for the "abstract" instance of a function which we
-   may later generate inlined and/or out-of-line instances of.  */
+/* Generate a DIE to represent a named constant.  */
 
 static void
-dwarf2out_abstract_function (tree decl)
+gen_const_die (tree decl, dw_die_ref context_die)
 {
-  dw_die_ref old_die;
-  tree save_fn;
-  tree context;
-  int was_abstract;
-  htab_t old_decl_loc_table;
+  dw_die_ref const_die;
+  tree type = TREE_TYPE (decl);
 
-  /* Make sure we have the actual abstract inline, not a clone.  */
-  decl = DECL_ORIGIN (decl);
+  const_die = new_die (DW_TAG_constant, context_die, decl);
+  add_name_and_src_coords_attributes (const_die, decl);
+  add_type_attribute (const_die, type, 1, 0, context_die);
+  if (TREE_PUBLIC (decl))
+    add_AT_flag (const_die, DW_AT_external, 1);
+  if (DECL_ARTIFICIAL (decl))
+    add_AT_flag (const_die, DW_AT_artificial, 1);
+  tree_add_const_value_attribute_for_decl (const_die, decl);
+}
 
-  old_die = lookup_decl_die (decl);
-  if (old_die && get_AT (old_die, DW_AT_inline))
-    /* We've already generated the abstract instance.  */
-    return;
+/* Generate a DIE to represent a label identifier.  */
 
-  /* We can be called while recursively when seeing block defining inlined subroutine
-     DIE.  Be sure to not clobber the outer location table nor use it or we would
-     get locations in abstract instantces.  */
-  old_decl_loc_table = decl_loc_table;
-  decl_loc_table = NULL;
+static void
+gen_label_die (tree decl, dw_die_ref context_die)
+{
+  tree origin = decl_ultimate_origin (decl);
+  dw_die_ref lbl_die = new_die (DW_TAG_label, context_die, decl);
+  rtx insn;
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
-  /* Be sure we've emitted the in-class declaration DIE (if any) first, so
-     we don't get confused by DECL_ABSTRACT.  */
-  if (debug_info_level > DINFO_LEVEL_TERSE)
-    {
-      context = decl_class_context (decl);
-      if (context)
-       gen_type_die_for_member
-         (context, decl, decl_function_context (decl) ? NULL : comp_unit_die);
-    }
+  if (origin != NULL)
+    add_abstract_origin_attribute (lbl_die, origin);
+  else
+    add_name_and_src_coords_attributes (lbl_die, decl);
 
-  /* Pretend we've just finished compiling this function.  */
-  save_fn = current_function_decl;
-  current_function_decl = decl;
-  push_cfun (DECL_STRUCT_FUNCTION (decl));
+  if (DECL_ABSTRACT (decl))
+    equate_decl_number_to_die (decl, lbl_die);
+  else
+    {
+      insn = DECL_RTL_IF_SET (decl);
 
-  was_abstract = DECL_ABSTRACT (decl);
-  set_decl_abstract_flags (decl, 1);
-  dwarf2out_decl (decl);
-  if (! was_abstract)
-    set_decl_abstract_flags (decl, 0);
+      /* Deleted labels are programmer specified labels which have been
+        eliminated because of various optimizations.  We still emit them
+        here so that it is possible to put breakpoints on them.  */
+      if (insn
+         && (LABEL_P (insn)
+             || ((NOTE_P (insn)
+                  && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL))))
+       {
+         /* When optimization is enabled (via -O) some parts of the compiler
+            (e.g. jump.c and cse.c) may try to delete CODE_LABEL insns which
+            represent source-level labels which were explicitly declared by
+            the user.  This really shouldn't be happening though, so catch
+            it if it ever does happen.  */
+         gcc_assert (!INSN_DELETED_P (insn));
 
-  current_function_decl = save_fn;
-  decl_loc_table = old_decl_loc_table;
-  pop_cfun ();
+         ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
+         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
+       }
+      else if (insn
+              && NOTE_P (insn)
+              && NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL
+              && CODE_LABEL_NUMBER (insn) != -1)
+       {
+         ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER (insn));
+         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
+       }
+    }
 }
 
-/* Helper function of premark_used_types() which gets called through
-   htab_traverse.
-
-   Marks the DIE of a given type in *SLOT as perennial, so it never gets
-   marked as unused by prune_unused_types.  */
+/* A helper function for gen_inlined_subroutine_die.  Add source coordinate
+   attributes to the DIE for a block STMT, to describe where the inlined
+   function was called from.  This is similar to add_src_coords_attributes.  */
 
-static int
-premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
+static inline void
+add_call_src_coords_attributes (tree stmt, dw_die_ref die)
 {
-  tree type;
-  dw_die_ref die;
+  expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt));
 
-  type = (tree) *slot;
-  die = lookup_type_die (type);
-  if (die != NULL)
-    die->die_perennial_p = 1;
-  return 1;
+  if (dwarf_version >= 3 || !dwarf_strict)
+    {
+      add_AT_file (die, DW_AT_call_file, lookup_filename (s.file));
+      add_AT_unsigned (die, DW_AT_call_line, s.line);
+    }
 }
 
-/* Helper function of premark_types_used_by_global_vars which gets called
-   through htab_traverse.
-
-   Marks the DIE of a given type in *SLOT as perennial, so it never gets
-   marked as unused by prune_unused_types. The DIE of the type is marked
-   only if the global variable using the type will actually be emitted.  */
 
-static int
-premark_types_used_by_global_vars_helper (void **slot,
-                                         void *data ATTRIBUTE_UNUSED)
+/* A helper function for gen_lexical_block_die and gen_inlined_subroutine_die.
+   Add low_pc and high_pc attributes to the DIE for a block STMT.  */
+
+static inline void
+add_high_low_attributes (tree stmt, dw_die_ref die)
 {
-  struct types_used_by_vars_entry *entry;
-  dw_die_ref die;
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
-  entry = (struct types_used_by_vars_entry *) *slot;
-  gcc_assert (entry->type != NULL
-             && entry->var_decl != NULL);
-  die = lookup_type_die (entry->type);
-  if (die)
+  if (BLOCK_FRAGMENT_CHAIN (stmt)
+      && (dwarf_version >= 3 || !dwarf_strict))
     {
-      /* Ask cgraph if the global variable really is to be emitted.
-         If yes, then we'll keep the DIE of ENTRY->TYPE.  */
-      struct varpool_node *node = varpool_node (entry->var_decl);
-      if (node->needed)
+      tree chain;
+
+      if (inlined_function_outer_scope_p (stmt))
        {
-         die->die_perennial_p = 1;
-         /* Keep the parent DIEs as well.  */
-         while ((die = die->die_parent) && die->die_perennial_p == 0)
-           die->die_perennial_p = 1;
+         ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
+                                      BLOCK_NUMBER (stmt));
+         add_AT_lbl_id (die, DW_AT_entry_pc, label);
+       }
+
+      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
+
+      chain = BLOCK_FRAGMENT_CHAIN (stmt);
+      do
+       {
+         add_ranges (chain);
+         chain = BLOCK_FRAGMENT_CHAIN (chain);
        }
+      while (chain);
+      add_ranges (NULL);
+    }
+  else
+    {
+      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
+                                  BLOCK_NUMBER (stmt));
+      add_AT_lbl_id (die, DW_AT_low_pc, label);
+      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
+                                  BLOCK_NUMBER (stmt));
+      add_AT_lbl_id (die, DW_AT_high_pc, label);
     }
-  return 1;
 }
 
-/* Mark all members of used_types_hash as perennial.  */
+/* Generate a DIE for a lexical block.  */
 
 static void
-premark_used_types (void)
+gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth)
 {
-  if (cfun && cfun->used_types_hash)
-    htab_traverse (cfun->used_types_hash, premark_used_types_helper, NULL);
-}
+  dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
 
-/* Mark all members of types_used_by_vars_entry as perennial.  */
+  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);
+    }
 
-static void
-premark_types_used_by_global_vars (void)
-{
-  if (types_used_by_vars_hash)
-    htab_traverse (types_used_by_vars_hash,
-                  premark_types_used_by_global_vars_helper, NULL);
+  if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
+    add_high_low_attributes (stmt, stmt_die);
+
+  decls_for_scope (stmt, stmt_die, depth);
 }
 
-/* Generate a DIE to represent a declared function (either file-scope or
-   block-local).  */
+/* Generate a DIE for an inlined subprogram.  */
 
 static void
-gen_subprogram_die (tree decl, dw_die_ref context_die)
+gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die, int depth)
 {
-  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
-                    || class_or_namespace_scope_p (context_die));
+  tree decl;
 
-  premark_used_types ();
+  /* The instance of function that is effectively being inlined shall not
+     be abstract.  */
+  gcc_assert (! BLOCK_ABSTRACT (stmt));
 
-  /* It is possible to have both DECL_ABSTRACT and DECLARATION be true if we
-     started to generate the abstract instance of an inline, decided to output
-     its containing class, and proceeded to emit the declaration of the inline
-     from the member list for the class.  If so, DECLARATION takes priority;
-     we'll get back to the abstract instance when done with the class.  */
+  decl = block_ultimate_origin (stmt);
 
-  /* The class-scope declaration DIE must be the primary DIE.  */
-  if (origin && declaration && class_or_namespace_scope_p (context_die))
+  /* Emit info for the abstract instance first, if we haven't yet.  We
+     must emit this even if the block is abstract, otherwise when we
+     emit the block below (or elsewhere), we may end up trying to emit
+     a die whose origin die hasn't been emitted, and crashing.  */
+  dwarf2out_abstract_function (decl);
+
+  if (! BLOCK_ABSTRACT (stmt))
     {
-      origin = NULL;
-      gcc_assert (!old_die);
+      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);
+      add_call_src_coords_attributes (stmt, subr_die);
+
+      decls_for_scope (stmt, subr_die, depth);
+      current_function_has_inlines = 1;
     }
+}
 
-  /* Now that the C++ front end lazily declares artificial member fns, we
-     might need to retrofit the declaration into its class.  */
-  if (!declaration && !origin && !old_die
-      && DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))
-      && !class_or_namespace_scope_p (context_die)
-      && debug_info_level > DINFO_LEVEL_TERSE)
-    old_die = force_decl_die (decl);
+/* Generate a DIE for a field in a record, or structure.  */
 
-  if (origin != NULL)
-    {
-      gcc_assert (!declaration || local_scope_p (context_die));
+static void
+gen_field_die (tree decl, dw_die_ref context_die)
+{
+  dw_die_ref decl_die;
 
-      /* Fixup die_parent for the abstract instance of a nested
-        inline function.  */
-      if (old_die && old_die->die_parent == NULL)
-       add_child_die (context_die, old_die);
+  if (TREE_TYPE (decl) == error_mark_node)
+    return;
 
-      subr_die = new_die (DW_TAG_subprogram, context_die, decl);
-      add_abstract_origin_attribute (subr_die, origin);
-    }
-  else if (old_die)
+  decl_die = new_die (DW_TAG_member, context_die, decl);
+  add_name_and_src_coords_attributes (decl_die, decl);
+  add_type_attribute (decl_die, member_declared_type (decl),
+                     TREE_READONLY (decl), TREE_THIS_VOLATILE (decl),
+                     context_die);
+
+  if (DECL_BIT_FIELD_TYPE (decl))
     {
-      expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
-      struct dwarf_file_data * file_index = lookup_filename (s.file);
+      add_byte_size_attribute (decl_die, decl);
+      add_bit_size_attribute (decl_die, decl);
+      add_bit_offset_attribute (decl_die, decl);
+    }
 
-      if (!get_AT_flag (old_die, DW_AT_declaration)
-         /* We can have a normal definition following an inline one in the
-            case of redefinition of GNU C extern inlines.
-            It seems reasonable to use AT_specification in this case.  */
-         && !get_AT (old_die, DW_AT_inline))
-       {
-         /* Detect and ignore this case, where we are trying to output
-            something we have already output.  */
-         return;
-       }
+  if (TREE_CODE (DECL_FIELD_CONTEXT (decl)) != UNION_TYPE)
+    add_data_member_location_attribute (decl_die, decl);
 
-      /* If the definition comes from the same place as the declaration,
-        maybe use the old DIE.  We always want the DIE for this function
-        that has the *_pc attributes to be under comp_unit_die so the
-        debugger can find it.  We also need to do this for abstract
-        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)
-         && (DECL_ARTIFICIAL (decl)
-             || (get_AT_file (old_die, DW_AT_decl_file) == file_index
-                 && (get_AT_unsigned (old_die, DW_AT_decl_line)
-                     == (unsigned) s.line))))
-       {
-         subr_die = old_die;
+  if (DECL_ARTIFICIAL (decl))
+    add_AT_flag (decl_die, DW_AT_artificial, 1);
 
-         /* Clear out the declaration attribute and the formal parameters.
-            Do not remove all children, because it is possible that this
-            declaration die was forced using force_decl_die(). In such
-            cases die that forced declaration die (e.g. TAG_imported_module)
-            is one of the children that we do not want to remove.  */
-         remove_AT (subr_die, DW_AT_declaration);
-         remove_child_TAG (subr_die, DW_TAG_formal_parameter);
-       }
-      else
-       {
-         subr_die = new_die (DW_TAG_subprogram, context_die, decl);
-         add_AT_specification (subr_die, old_die);
-         if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
-           add_AT_file (subr_die, DW_AT_decl_file, file_index);
-         if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
-           add_AT_unsigned (subr_die, DW_AT_decl_line, s.line);
-       }
-    }
-  else
-    {
-      subr_die = new_die (DW_TAG_subprogram, context_die, decl);
+  add_accessibility_attribute (decl_die, decl);
 
-      if (TREE_PUBLIC (decl))
-       add_AT_flag (subr_die, DW_AT_external, 1);
+  /* Equate decl number to die, so that we can look up this decl later on.  */
+  equate_decl_number_to_die (decl, decl_die);
+}
 
-      add_name_and_src_coords_attributes (subr_die, decl);
-      if (debug_info_level > DINFO_LEVEL_TERSE)
-       {
-         add_prototyped_attribute (subr_die, TREE_TYPE (decl));
-         add_type_attribute (subr_die, TREE_TYPE (TREE_TYPE (decl)),
-                             0, 0, context_die);
-       }
+#if 0
+/* Don't generate either pointer_type DIEs or reference_type DIEs here.
+   Use modified_type_die instead.
+   We keep this code here just in case these types of DIEs may be needed to
+   represent certain things in other languages (e.g. Pascal) someday.  */
 
-      add_pure_or_virtual_attribute (subr_die, decl);
-      if (DECL_ARTIFICIAL (decl))
-       add_AT_flag (subr_die, DW_AT_artificial, 1);
+static void
+gen_pointer_type_die (tree type, dw_die_ref context_die)
+{
+  dw_die_ref ptr_die
+    = new_die (DW_TAG_pointer_type, scope_die_for (type, context_die), type);
 
-      if (TREE_PROTECTED (decl))
-       add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_protected);
-      else if (TREE_PRIVATE (decl))
-       add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_private);
-    }
+  equate_type_number_to_die (type, ptr_die);
+  add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
+  add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
+}
 
-  if (declaration)
-    {
-      if (!old_die || !get_AT (old_die, DW_AT_inline))
-       {
-         add_AT_flag (subr_die, DW_AT_declaration, 1);
+/* Don't generate either pointer_type DIEs or reference_type DIEs here.
+   Use modified_type_die instead.
+   We keep this code here just in case these types of DIEs may be needed to
+   represent certain things in other languages (e.g. Pascal) someday.  */
 
-         /* If this is an explicit function declaration then generate
-            a DW_AT_explicit attribute.  */
-         if (lang_hooks.decls.function_decl_explicit_p (decl)
-             && (dwarf_version >= 3 || !dwarf_strict))
-           add_AT_flag (subr_die, DW_AT_explicit, 1);
+static void
+gen_reference_type_die (tree type, dw_die_ref context_die)
+{
+  dw_die_ref ref_die, scope_die = scope_die_for (type, context_die);
+
+  if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4)
+    ref_die = new_die (DW_TAG_rvalue_reference_type, scope_die, type);
+  else
+    ref_die = new_die (DW_TAG_reference_type, scope_die, type);
+
+  equate_type_number_to_die (type, ref_die);
+  add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die);
+  add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
+}
+#endif
 
-         /* The first time we see a member function, it is in the context of
-            the class to which it belongs.  We make sure of this by emitting
-            the class first.  The next time is the definition, which is
-            handled above.  The two may come from the same source text.
+/* Generate a DIE for a pointer to a member type.  */
 
-            Note that force_decl_die() forces function declaration die. It is
-            later reused to represent definition.  */
-         equate_decl_number_to_die (decl, subr_die);
-       }
-    }
-  else if (DECL_ABSTRACT (decl))
-    {
-      if (DECL_DECLARED_INLINE_P (decl))
-       {
-         if (cgraph_function_possibly_inlined_p (decl))
-           add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
-         else
-           add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_not_inlined);
-       }
-      else
-       {
-         if (cgraph_function_possibly_inlined_p (decl))
-           add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
-         else
-           add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_not_inlined);
-       }
+static void
+gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die)
+{
+  dw_die_ref ptr_die
+    = new_die (DW_TAG_ptr_to_member_type,
+              scope_die_for (type, context_die), type);
 
-      if (DECL_DECLARED_INLINE_P (decl)
-         && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
-       add_AT_flag (subr_die, DW_AT_artificial, 1);
+  equate_type_number_to_die (type, ptr_die);
+  add_AT_die_ref (ptr_die, DW_AT_containing_type,
+                 lookup_type_die (TYPE_OFFSET_BASETYPE (type)));
+  add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
+}
 
-      equate_decl_number_to_die (decl, subr_die);
-    }
-  else if (!DECL_EXTERNAL (decl))
-    {
-      HOST_WIDE_INT cfa_fb_offset;
+typedef const char *dchar_p; /* For DEF_VEC_P.  */
+DEF_VEC_P(dchar_p);
+DEF_VEC_ALLOC_P(dchar_p,heap);
 
-      if (!old_die || !get_AT (old_die, DW_AT_inline))
-       equate_decl_number_to_die (decl, subr_die);
+static char *producer_string;
 
-      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);
+/* Return a heap allocated producer string including command line options
+   if -grecord-gcc-switches.  */
 
-         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);
-          */
-       }
+static char *
+gen_producer_string (void)
+{
+  size_t j;
+  VEC(dchar_p, heap) *switches = NULL;
+  const char *language_string = lang_hooks.name;
+  char *producer, *tail;
+  const char *p;
+  size_t len = dwarf_record_gcc_switches ? 0 : 3;
+  size_t plen = strlen (language_string) + 1 + strlen (version_string);
 
-#ifdef MIPS_DEBUGGING_INFO
-      /* Add a reference to the FDE for this routine.  */
-      add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde);
-#endif
+  for (j = 1; dwarf_record_gcc_switches && j < save_decoded_options_count; j++)
+    switch (save_decoded_options[j].opt_index)
+      {
+      case OPT_o:
+      case OPT_d:
+      case OPT_dumpbase:
+      case OPT_dumpdir:
+      case OPT_auxbase:
+      case OPT_auxbase_strip:
+      case OPT_quiet:
+      case OPT_version:
+      case OPT_v:
+      case OPT_w:
+      case OPT_L:
+      case OPT_D:
+      case OPT_I:
+      case OPT_U:
+      case OPT_SPECIAL_unknown:
+      case OPT_SPECIAL_ignore:
+      case OPT_SPECIAL_program_name:
+      case OPT_SPECIAL_input_file:
+      case OPT_grecord_gcc_switches:
+      case OPT_gno_record_gcc_switches:
+      case OPT__output_pch_:
+      case OPT_fdiagnostics_show_location_:
+      case OPT_fdiagnostics_show_option:
+      case OPT_fverbose_asm:
+      case OPT____:
+      case OPT__sysroot_:
+      case OPT_nostdinc:
+      case OPT_nostdinc__:
+       /* Ignore these.  */
+       continue;
+      default:
+        gcc_checking_assert (save_decoded_options[j].canonical_option[0][0]
+                            == '-');
+        switch (save_decoded_options[j].canonical_option[0][1])
+         {
+         case 'M':
+         case 'i':
+         case 'W':
+           continue;
+         case 'f':
+           if (strncmp (save_decoded_options[j].canonical_option[0] + 2,
+                        "dump", 4) == 0)
+             continue;
+           break;
+         default:
+           break;
+         }
+       VEC_safe_push (dchar_p, heap, switches,
+                      save_decoded_options[j].orig_option_with_args_text);
+       len += strlen (save_decoded_options[j].orig_option_with_args_text) + 1;
+       break;
+      }
 
-      cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
+  producer = XNEWVEC (char, plen + 1 + len + 1);
+  tail = producer;
+  sprintf (tail, "%s %s", language_string, version_string);
+  tail += plen;
 
-      /* We define the "frame base" as the function's CFA.  This is more
-        convenient for several reasons: (1) It's stable across the prologue
-        and epilogue, which makes it better than just a frame pointer,
-        (2) With dwarf3, there exists a one-byte encoding that allows us
-        to reference the .debug_frame data by proxy, but failing that,
-        (3) We can at least reuse the code inspection and interpretation
-        code that determines the CFA position at various points in the
-        function.  */
-      if (dwarf_version >= 3)
-       {
-         dw_loc_descr_ref op = new_loc_descr (DW_OP_call_frame_cfa, 0, 0);
-         add_AT_loc (subr_die, DW_AT_frame_base, op);
-       }
-      else
+  if (!dwarf_record_gcc_switches)
+    {
+#ifdef MIPS_DEBUGGING_INFO
+      /* The MIPS/SGI compilers place the 'cc' command line options in the
+        producer string.  The SGI debugger looks for -g, -g1, -g2, or -g3;
+        if they do not appear in the producer string, the debugger reaches
+        the conclusion that the object file is stripped and has no debugging
+        information.  To get the MIPS/SGI debugger to believe that there is
+        debugging information in the object file, we add a -g to the producer
+        string.  */
+      if (debug_info_level > DINFO_LEVEL_TERSE)
        {
-         dw_loc_list_ref list = convert_cfa_to_fb_loc_list (cfa_fb_offset);
-         if (list->dw_loc_next)
-           add_AT_loc_list (subr_die, DW_AT_frame_base, list);
-         else
-           add_AT_loc (subr_die, DW_AT_frame_base, list->expr);
+         memcpy (tail, " -g", 3);
+         tail += 3;
        }
+#endif
+    }
 
-      /* Compute a displacement from the "steady-state frame pointer" to
-        the CFA.  The former is what all stack slots and argument slots
-        will reference in the rtl; the later is what we've told the
-        debugger about.  We'll need to adjust all frame_base references
-        by this displacement.  */
-      compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
-
-      if (cfun->static_chain_decl)
-       add_AT_location_description (subr_die, DW_AT_static_link,
-                loc_list_from_tree (cfun->static_chain_decl, 2));
+  FOR_EACH_VEC_ELT (dchar_p, switches, j, p)
+    {
+      len = strlen (p);
+      *tail = ' ';
+      memcpy (tail + 1, p, len);
+      tail += len + 1;
     }
 
-  /* Generate child dies for template paramaters.  */
-  if (debug_info_level > DINFO_LEVEL_TERSE)
-    gen_generic_params_dies (decl);
+  *tail = '\0';
+  VEC_free (dchar_p, heap, switches);
+  return producer;
+}
 
-  /* Now output descriptions of the arguments for this function. This gets
-     (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list
-     for a FUNCTION_DECL doesn't indicate cases where there was a trailing
-     `...' at the end of the formal parameter list.  In order to find out if
-     there was a trailing ellipsis or not, we must instead look at the type
-     associated with the FUNCTION_DECL.  This will be a node of type
-     FUNCTION_TYPE. If the chain of type nodes hanging off of this
-     FUNCTION_TYPE node ends with a void_type_node then there should *not* be
-     an ellipsis at the end.  */
+/* Generate the DIE for the compilation unit.  */
 
-  /* In the case where we are describing a mere function declaration, all we
-     need to do here (and all we *can* do here) is to describe the *types* of
-     its formal parameters.  */
-  if (debug_info_level <= DINFO_LEVEL_TERSE)
-    ;
-  else if (declaration)
-    gen_formal_types_die (decl, subr_die);
-  else
-    {
-      /* Generate DIEs to represent all known formal parameters.  */
-      tree parm = DECL_ARGUMENTS (decl);
-      tree generic_decl = lang_hooks.decls.get_generic_function_decl (decl);
-      tree generic_decl_parm = generic_decl
-                               ? DECL_ARGUMENTS (generic_decl)
-                               : NULL;
+static dw_die_ref
+gen_compile_unit_die (const char *filename)
+{
+  dw_die_ref die;
+  const char *language_string = lang_hooks.name;
+  int language;
 
-      /* Now we want to walk the list of parameters of the function and
-        emit their relevant DIEs.
+  die = new_die (DW_TAG_compile_unit, NULL, NULL);
 
-        We consider the case of DECL being an instance of a generic function
-        as well as it being a normal function.
+  if (filename)
+    {
+      add_name_attribute (die, filename);
+      /* Don't add cwd for <built-in>.  */
+      if (!IS_ABSOLUTE_PATH (filename) && filename[0] != '<')
+       add_comp_dir_attribute (die);
+    }
 
-        If DECL is an instance of a generic function we walk the
-        parameters of the generic function declaration _and_ the parameters of
-        DECL itself. This is useful because we want to emit specific DIEs for
-        function parameter packs and those are declared as part of the
-        generic function declaration. In that particular case,
-        the parameter pack yields a DW_TAG_GNU_formal_parameter_pack DIE.
-        That DIE has children DIEs representing the set of arguments
-        of the pack. Note that the set of pack arguments can be empty.
-        In that case, the DW_TAG_GNU_formal_parameter_pack DIE will not have any
-        children DIE.
+  if (producer_string == NULL)
+    producer_string = gen_producer_string ();
+  add_AT_string (die, DW_AT_producer, producer_string);
 
-        Otherwise, we just consider the parameters of DECL.  */
-      while (generic_decl_parm || parm)
+  /* 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 (generic_decl_parm
-             && lang_hooks.function_parameter_pack_p (generic_decl_parm))
-           gen_formal_parameter_pack_die (generic_decl_parm,
-                                          parm, subr_die,
-                                          &parm);
-         else if (parm)
+         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
            {
-             gen_decl_die (parm, NULL, subr_die);
-             parm = TREE_CHAIN (parm);
+             /* Fall back to C.  */
+             common_lang = NULL;
+             break;
            }
-
-         if (generic_decl_parm)
-           generic_decl_parm = TREE_CHAIN (generic_decl_parm);
        }
 
-      /* Decide whether we need an unspecified_parameters DIE at the end.
-        There are 2 more cases to do this for: 1) the ansi ... declaration -
-        this is detectable when the end of the arg list is not a
-        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 (common_lang)
+       language_string = common_lang;
+    }
+
+  language = DW_LANG_C89;
+  if (strcmp (language_string, "GNU C++") == 0)
+    language = DW_LANG_C_plus_plus;
+  else if (strcmp (language_string, "GNU F77") == 0)
+    language = DW_LANG_Fortran77;
+  else if (strcmp (language_string, "GNU Pascal") == 0)
+    language = DW_LANG_Pascal83;
+  else if (dwarf_version >= 3 || !dwarf_strict)
+    {
+      if (strcmp (language_string, "GNU Ada") == 0)
+       language = DW_LANG_Ada95;
+      else if (strcmp (language_string, "GNU Fortran") == 0)
+       language = DW_LANG_Fortran95;
+      else if (strcmp (language_string, "GNU Java") == 0)
+       language = DW_LANG_Java;
+      else if (strcmp (language_string, "GNU Objective-C") == 0)
+       language = DW_LANG_ObjC;
+      else if (strcmp (language_string, "GNU Objective-C++") == 0)
+       language = DW_LANG_ObjC_plus_plus;
+      else if (dwarf_version >= 5 || !dwarf_strict)
        {
-         /* This is the prototyped case, check for....  */
-         if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node)
-           gen_unspecified_parameters_die (decl, subr_die);
+         if (strcmp (language_string, "GNU Go") == 0)
+           language = DW_LANG_Go;
        }
-      else if (DECL_INITIAL (decl) == NULL_TREE)
-       gen_unspecified_parameters_die (decl, subr_die);
     }
 
-  /* Output Dwarf info for all of the stuff within the body of the function
-     (if it has one - it may be just a declaration).  */
-  outer_scope = DECL_INITIAL (decl);
-
-  /* OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
-     a function.  This BLOCK actually represents the outermost binding contour
-     for the function, i.e. the contour in which the function's formal
-     parameters and labels get declared. Curiously, it appears that the front
-     end doesn't actually put the PARM_DECL nodes for the current function onto
-     the BLOCK_VARS list for this outer scope, but are strung off of the
-     DECL_ARGUMENTS list for the function instead.
+  add_AT_unsigned (die, DW_AT_language, language);
 
-     The BLOCK_VARS list for the `outer_scope' does provide us with a list of
-     the LABEL_DECL nodes for the function however, and we output DWARF info
-     for those in decls_for_scope.  Just within the `outer_scope' there will be
-     a BLOCK node representing the function's outermost pair of curly braces,
-     and any blocks used for the base and member initializers of a C++
-     constructor function.  */
-  if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK)
+  switch (language)
     {
-      /* 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);
-
-      current_function_has_inlines = 0;
-      decls_for_scope (outer_scope, subr_die, 0);
-
-#if 0 && defined (MIPS_DEBUGGING_INFO)
-      if (current_function_has_inlines)
-       {
-         add_AT_flag (subr_die, DW_AT_MIPS_has_inlines, 1);
-         if (! comp_unit_has_inlines)
-           {
-             add_AT_flag (comp_unit_die, DW_AT_MIPS_has_inlines, 1);
-             comp_unit_has_inlines = 1;
-           }
-       }
-#endif
+    case DW_LANG_Fortran77:
+    case DW_LANG_Fortran90:
+    case DW_LANG_Fortran95:
+      /* Fortran has case insensitive identifiers and the front-end
+        lowercases everything.  */
+      add_AT_unsigned (die, DW_AT_identifier_case, DW_ID_down_case);
+      break;
+    default:
+      /* The default DW_ID_case_sensitive doesn't need to be specified.  */
+      break;
     }
-  /* Add the calling convention attribute if requested.  */
-  add_calling_convention_attribute (subr_die, decl);
-
+  return die;
 }
 
-/* Returns a hash value for X (which really is a die_struct).  */
+/* Generate the DIE for a base class.  */
 
-static hashval_t
-common_block_die_table_hash (const void *x)
+static void
+gen_inheritance_die (tree binfo, tree access, dw_die_ref context_die)
 {
-  const_dw_die_ref d = (const_dw_die_ref) x;
-  return (hashval_t) d->decl_id ^ htab_hash_pointer (d->die_parent);
-}
+  dw_die_ref die = new_die (DW_TAG_inheritance, context_die, binfo);
 
-/* Return nonzero if decl_id and die_parent of die_struct X is the same
-   as decl_id and die_parent of die_struct Y.  */
+  add_type_attribute (die, BINFO_TYPE (binfo), 0, 0, context_die);
+  add_data_member_location_attribute (die, binfo);
 
-static int
-common_block_die_table_eq (const void *x, const void *y)
-{
-  const_dw_die_ref d = (const_dw_die_ref) x;
-  const_dw_die_ref e = (const_dw_die_ref) y;
-  return d->decl_id == e->decl_id && d->die_parent == e->die_parent;
+  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)
+    {
+      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 to represent a declared data object.
-   Either DECL or ORIGIN must be non-null.  */
+/* Generate a DIE for a class member.  */
 
 static void
-gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
+gen_member_die (tree type, dw_die_ref context_die)
 {
-  HOST_WIDE_INT off;
-  tree com_decl;
-  tree decl_or_origin = decl ? decl : origin;
-  tree ultimate_origin;
-  dw_die_ref var_die;
-  dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL;
-  dw_die_ref origin_die;
-  int declaration = (DECL_EXTERNAL (decl_or_origin)
-                    || class_or_namespace_scope_p (context_die));
+  tree member;
+  tree binfo = TYPE_BINFO (type);
+  dw_die_ref child;
 
-  ultimate_origin = decl_ultimate_origin (decl_or_origin);
-  if (decl || ultimate_origin)
-    origin = ultimate_origin;
-  com_decl = fortran_common (decl_or_origin, &off);
+  /* If this is not an incomplete type, output descriptions of each of its
+     members. Note that as we output the DIEs necessary to represent the
+     members of this record or union type, we will also be trying to output
+     DIEs to represent the *types* of those members. However the `type'
+     function (above) will specifically avoid generating type DIEs for member
+     types *within* the list of member DIEs for this (containing) type except
+     for those types (of members) which are explicitly marked as also being
+     members of this (containing) type themselves.  The g++ front- end can
+     force any given type to be treated as a member of some other (containing)
+     type by setting the TYPE_CONTEXT of the given (member) type to point to
+     the TREE node representing the appropriate (containing) type.  */
 
-  /* Symbol in common gets emitted as a child of the common block, in the form
-     of a data member.  */
-  if (com_decl)
+  /* First output info about the base classes.  */
+  if (binfo)
     {
-      dw_die_ref com_die;
-      dw_loc_list_ref loc;
-      die_node com_die_arg;
-
-      var_die = lookup_decl_die (decl_or_origin);
-      if (var_die)
-       {
-         if (get_AT (var_die, DW_AT_location) == NULL)
-           {
-             loc = loc_list_from_tree (com_decl, off ? 1 : 2);
-             if (loc)
-               {
-                 if (off)
-                   {
-                     /* Optimize the common case.  */
-                     if (single_element_loc_list_p (loc)
-                         && loc->expr->dw_loc_opc == DW_OP_addr
-                         && loc->expr->dw_loc_next == NULL
-                         && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr)
-                            == SYMBOL_REF)
-                       loc->expr->dw_loc_oprnd1.v.val_addr
-                         = plus_constant (loc->expr->dw_loc_oprnd1.v.val_addr, off);
-                       else
-                         loc_list_plus_const (loc, off);
-                   }
-                 add_AT_location_description (var_die, DW_AT_location, loc);
-                 remove_AT (var_die, DW_AT_declaration);
-               }
-           }
-         return;
-       }
+      VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (binfo);
+      int i;
+      tree base;
 
-      if (common_block_die_table == NULL)
-       common_block_die_table
-         = htab_create_ggc (10, common_block_die_table_hash,
-                            common_block_die_table_eq, NULL);
+      for (i = 0; BINFO_BASE_ITERATE (binfo, i, base); i++)
+       gen_inheritance_die (base,
+                            (accesses ? VEC_index (tree, accesses, i)
+                             : access_public_node), context_die);
+    }
 
-      com_die_arg.decl_id = DECL_UID (com_decl);
-      com_die_arg.die_parent = context_die;
-      com_die = (dw_die_ref) htab_find (common_block_die_table, &com_die_arg);
-      loc = loc_list_from_tree (com_decl, 2);
-      if (com_die == NULL)
-       {
-         const char *cnam
-           = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (com_decl));
-         void **slot;
+  /* Now output info about the data members and type members.  */
+  for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN (member))
+    {
+      /* If we thought we were generating minimal debug info for TYPE
+        and then changed our minds, some of the member declarations
+        may have already been defined.  Don't define them again, but
+        do put them in the right order.  */
 
-         com_die = new_die (DW_TAG_common_block, context_die, decl);
-         add_name_and_src_coords_attributes (com_die, com_decl);
-         if (loc)
-           {
-             add_AT_location_description (com_die, DW_AT_location, loc);
-             /* Avoid sharing the same loc descriptor between
-                DW_TAG_common_block and DW_TAG_variable.  */
-             loc = loc_list_from_tree (com_decl, 2);
-           }
-          else if (DECL_EXTERNAL (decl))
-           add_AT_flag (com_die, DW_AT_declaration, 1);
-         add_pubname_string (cnam, com_die); /* ??? needed? */
-         com_die->decl_id = DECL_UID (com_decl);
-         slot = htab_find_slot (common_block_die_table, com_die, INSERT);
-         *slot = (void *) com_die;
-       }
-      else if (get_AT (com_die, DW_AT_location) == NULL && loc)
-       {
-         add_AT_location_description (com_die, DW_AT_location, loc);
-         loc = loc_list_from_tree (com_decl, 2);
-         remove_AT (com_die, DW_AT_declaration);
-       }
-      var_die = new_die (DW_TAG_variable, com_die, decl);
-      add_name_and_src_coords_attributes (var_die, decl);
-      add_type_attribute (var_die, TREE_TYPE (decl), TREE_READONLY (decl),
-                         TREE_THIS_VOLATILE (decl), context_die);
-      add_AT_flag (var_die, DW_AT_external, 1);
-      if (loc)
-       {
-         if (off)
-           {
-             /* Optimize the common case.  */
-             if (single_element_loc_list_p (loc)
-                 && loc->expr->dw_loc_opc == DW_OP_addr
-                 && loc->expr->dw_loc_next == NULL
-                 && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
-               loc->expr->dw_loc_oprnd1.v.val_addr
-                 = plus_constant (loc->expr->dw_loc_oprnd1.v.val_addr, off);
-             else
-               loc_list_plus_const (loc, off);
-           }
-         add_AT_location_description (var_die, DW_AT_location, loc);
-       }
-      else if (DECL_EXTERNAL (decl))
-       add_AT_flag (var_die, DW_AT_declaration, 1);
-      equate_decl_number_to_die (decl, var_die);
-      return;
+      child = lookup_decl_die (member);
+      if (child)
+       splice_child_die (context_die, child);
+      else
+       gen_decl_die (member, NULL, context_die);
     }
 
-  /* If the compiler emitted a definition for the DECL declaration
-     and if we already emitted a DIE for it, don't emit a second
-     DIE for it again. Allow re-declarations of DECLs that are
-     inside functions, though.  */
-  if (old_die && declaration && !local_scope_p (context_die))
-    return;
+  /* Now output info about the function members (if any).  */
+  for (member = TYPE_METHODS (type); member; member = DECL_CHAIN (member))
+    {
+      /* Don't include clones in the member list.  */
+      if (DECL_ABSTRACT_ORIGIN (member))
+       continue;
 
-  /* For static data members, the declaration in the class is supposed
-     to have DW_TAG_member tag; the specification should still be
-     DW_TAG_variable referencing the DW_TAG_member DIE.  */
-  if (declaration && class_scope_p (context_die))
-    var_die = new_die (DW_TAG_member, context_die, decl);
-  else
-    var_die = new_die (DW_TAG_variable, context_die, decl);
+      child = lookup_decl_die (member);
+      if (child)
+       splice_child_die (context_die, child);
+      else
+       gen_decl_die (member, NULL, context_die);
+    }
+}
 
-  origin_die = NULL;
-  if (origin != NULL)
-    origin_die = add_abstract_origin_attribute (var_die, origin);
+/* Generate a DIE for a structure or union type.  If TYPE_DECL_SUPPRESS_DEBUG
+   is set, we pretend that the type was never defined, so we only get the
+   member DIEs needed by later specification DIEs.  */
 
-  /* Loop unrolling can create multiple blocks that refer to the same
-     static variable, so we must test for the DW_AT_declaration flag.
+static void
+gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
+                               enum debug_info_usage usage)
+{
+  dw_die_ref type_die = lookup_type_die (type);
+  dw_die_ref scope_die = 0;
+  int nested = 0;
+  int complete = (TYPE_SIZE (type)
+                 && (! TYPE_STUB_DECL (type)
+                     || ! TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))));
+  int ns_decl = (context_die && context_die->die_tag == DW_TAG_namespace);
+  complete = complete && should_emit_struct_debug (type, usage);
 
-     ??? Loop unrolling/reorder_blocks should perhaps be rewritten to
-     copy decls and set the DECL_ABSTRACT flag on them instead of
-     sharing them.
+  if (type_die && ! complete)
+    return;
 
-     ??? Duplicated blocks have been rewritten to use .debug_ranges.
+  if (TYPE_CONTEXT (type) != NULL_TREE
+      && (AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
+         || TREE_CODE (TYPE_CONTEXT (type)) == NAMESPACE_DECL))
+    nested = 1;
 
-     ??? The declare_in_namespace support causes us to get two DIEs for one
-     variable, both of which are declarations.  We want to avoid considering
-     one to be a specification, so we must test that this DIE is not a
-     declaration.  */
-  else if (old_die && TREE_STATIC (decl) && ! declaration
-          && get_AT_flag (old_die, DW_AT_declaration) == 1)
+  scope_die = scope_die_for (type, context_die);
+
+  if (! type_die || (nested && is_cu_die (scope_die)))
+    /* First occurrence of type or toplevel definition of nested class.  */
     {
-      /* This is a definition of a C++ class level static.  */
-      add_AT_specification (var_die, old_die);
-      if (DECL_NAME (decl))
+      dw_die_ref old_die = type_die;
+
+      type_die = new_die (TREE_CODE (type) == RECORD_TYPE
+                         ? record_type_tag (type) : DW_TAG_union_type,
+                         scope_die, type);
+      equate_type_number_to_die (type, type_die);
+      if (old_die)
+       add_AT_specification (type_die, old_die);
+      else
        {
-         expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
-         struct dwarf_file_data * file_index = lookup_filename (s.file);
-
-         if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
-           add_AT_file (var_die, DW_AT_decl_file, file_index);
-
-         if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
-           add_AT_unsigned (var_die, DW_AT_decl_line, s.line);
+         add_name_attribute (type_die, type_tag (type));
+         add_gnat_descriptive_type_attribute (type_die, type, context_die);
+         if (TYPE_ARTIFICIAL (type))
+           add_AT_flag (type_die, DW_AT_artificial, 1);
        }
     }
   else
-    {
-      tree type = TREE_TYPE (decl);
-
-      add_name_and_src_coords_attributes (var_die, decl);
-      if (decl_by_reference_p (decl))
-       add_type_attribute (var_die, TREE_TYPE (type), 0, 0, context_die);
-      else
-       add_type_attribute (var_die, type, TREE_READONLY (decl),
-                           TREE_THIS_VOLATILE (decl), context_die);
+    remove_AT (type_die, DW_AT_declaration);
 
-      if (TREE_PUBLIC (decl))
-       add_AT_flag (var_die, DW_AT_external, 1);
+  /* Generate child dies for template paramaters.  */
+  if (debug_info_level > DINFO_LEVEL_TERSE
+      && COMPLETE_TYPE_P (type))
+    schedule_generic_params_dies_gen (type);
 
-      if (DECL_ARTIFICIAL (decl))
-       add_AT_flag (var_die, DW_AT_artificial, 1);
+  /* If this type has been completed, then give it a byte_size attribute and
+     then give a list of members.  */
+  if (complete && !ns_decl)
+    {
+      /* Prevent infinite recursion in cases where the type of some member of
+        this type is expressed in terms of this type itself.  */
+      TREE_ASM_WRITTEN (type) = 1;
+      add_byte_size_attribute (type_die, type);
+      if (TYPE_STUB_DECL (type) != NULL_TREE)
+       {
+         add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
+         add_accessibility_attribute (type_die, TYPE_STUB_DECL (type));
+       }
 
-      if (TREE_PROTECTED (decl))
-       add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_protected);
-      else if (TREE_PRIVATE (decl))
-       add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_private);
-    }
+      /* If the first reference to this type was as the return type of an
+        inline function, then it may not have a parent.  Fix this now.  */
+      if (type_die->die_parent == NULL)
+       add_child_die (scope_die, type_die);
 
-  if (declaration)
-    add_AT_flag (var_die, DW_AT_declaration, 1);
+      push_decl_scope (type);
+      gen_member_die (type, type_die);
+      pop_decl_scope ();
 
-  if (decl && (DECL_ABSTRACT (decl) || declaration))
-    equate_decl_number_to_die (decl, var_die);
+      /* GNU extension: Record what type our vtable lives in.  */
+      if (TYPE_VFIELD (type))
+       {
+         tree vtype = DECL_FCONTEXT (TYPE_VFIELD (type));
 
-  if (! declaration
-      && (! DECL_ABSTRACT (decl_or_origin)
-         /* Local static vars are shared between all clones/inlines,
-            so emit DW_AT_location on the abstract DIE if DECL_RTL is
-            already set.  */
-         || (TREE_CODE (decl_or_origin) == VAR_DECL
-             && TREE_STATIC (decl_or_origin)
-             && DECL_RTL_SET_P (decl_or_origin)))
-      /* When abstract origin already has DW_AT_location attribute, no need
-        to add it again.  */
-      && (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL))
-    {
-      if (TREE_CODE (decl_or_origin) == VAR_DECL && TREE_STATIC (decl_or_origin)
-          && !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_pubname (decl_or_origin, var_die);
+         gen_type_die (vtype, context_die);
+         add_AT_die_ref (type_die, DW_AT_containing_type,
+                         lookup_type_die (vtype));
+       }
     }
   else
-    tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
+    {
+      add_AT_flag (type_die, DW_AT_declaration, 1);
+
+      /* We don't need to do this for function-local types.  */
+      if (TYPE_STUB_DECL (type)
+         && ! decl_function_context (TYPE_STUB_DECL (type)))
+       VEC_safe_push (tree, gc, incomplete_types, type);
+    }
+
+  if (get_AT (type_die, DW_AT_name))
+    add_pubtype (type, type_die);
 }
 
-/* Generate a DIE to represent a named constant.  */
+/* Generate a DIE for a subroutine _type_.  */
 
 static void
-gen_const_die (tree decl, dw_die_ref context_die)
+gen_subroutine_type_die (tree type, dw_die_ref context_die)
 {
-  dw_die_ref const_die;
-  tree type = TREE_TYPE (decl);
+  tree return_type = TREE_TYPE (type);
+  dw_die_ref subr_die
+    = new_die (DW_TAG_subroutine_type,
+              scope_die_for (type, context_die), type);
 
-  const_die = new_die (DW_TAG_constant, context_die, decl);
-  add_name_and_src_coords_attributes (const_die, decl);
-  add_type_attribute (const_die, type, 1, 0, context_die);
-  if (TREE_PUBLIC (decl))
-    add_AT_flag (const_die, DW_AT_external, 1);
-  if (DECL_ARTIFICIAL (decl))
-    add_AT_flag (const_die, DW_AT_artificial, 1);
-  tree_add_const_value_attribute_for_decl (const_die, decl);
+  equate_type_number_to_die (type, subr_die);
+  add_prototyped_attribute (subr_die, type);
+  add_type_attribute (subr_die, return_type, 0, 0, context_die);
+  gen_formal_types_die (type, subr_die);
+
+  if (get_AT (subr_die, DW_AT_name))
+    add_pubtype (type, subr_die);
 }
 
-/* Generate a DIE to represent a label identifier.  */
+/* Generate a DIE for a type definition.  */
 
 static void
-gen_label_die (tree decl, dw_die_ref context_die)
+gen_typedef_die (tree decl, dw_die_ref context_die)
 {
-  tree origin = decl_ultimate_origin (decl);
-  dw_die_ref lbl_die = new_die (DW_TAG_label, context_die, decl);
-  rtx insn;
-  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+  dw_die_ref type_die;
+  tree origin;
 
-  if (origin != NULL)
-    add_abstract_origin_attribute (lbl_die, origin);
-  else
-    add_name_and_src_coords_attributes (lbl_die, decl);
+  if (TREE_ASM_WRITTEN (decl))
+    return;
 
-  if (DECL_ABSTRACT (decl))
-    equate_decl_number_to_die (decl, lbl_die);
+  TREE_ASM_WRITTEN (decl) = 1;
+  type_die = new_die (DW_TAG_typedef, context_die, decl);
+  origin = decl_ultimate_origin (decl);
+  if (origin != NULL)
+    add_abstract_origin_attribute (type_die, origin);
   else
     {
-      insn = DECL_RTL_IF_SET (decl);
+      tree type;
 
-      /* Deleted labels are programmer specified labels which have been
-        eliminated because of various optimizations.  We still emit them
-        here so that it is possible to put breakpoints on them.  */
-      if (insn
-         && (LABEL_P (insn)
-             || ((NOTE_P (insn)
-                  && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL))))
+      add_name_and_src_coords_attributes (type_die, decl);
+      if (DECL_ORIGINAL_TYPE (decl))
        {
-         /* When optimization is enabled (via -O) some parts of the compiler
-            (e.g. jump.c and cse.c) may try to delete CODE_LABEL insns which
-            represent source-level labels which were explicitly declared by
-            the user.  This really shouldn't be happening though, so catch
-            it if it ever does happen.  */
-         gcc_assert (!INSN_DELETED_P (insn));
+         type = DECL_ORIGINAL_TYPE (decl);
 
-         ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
-         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
+         gcc_assert (type != TREE_TYPE (decl));
+         equate_type_number_to_die (TREE_TYPE (decl), type_die);
        }
-    }
-}
+      else
+       {
+         type = TREE_TYPE (decl);
 
-/* A helper function for gen_inlined_subroutine_die.  Add source coordinate
-   attributes to the DIE for a block STMT, to describe where the inlined
-   function was called from.  This is similar to add_src_coords_attributes.  */
+         if (is_naming_typedef_decl (TYPE_NAME (type)))
+           {
+             /* Here, we are in the case of decl being a typedef naming
+                an anonymous type, e.g:
+                    typedef struct {...} foo;
+                In that case TREE_TYPE (decl) is not a typedef variant
+                type and TYPE_NAME of the anonymous type is set to the
+                TYPE_DECL of the typedef. This construct is emitted by
+                the C++ FE.
+
+                TYPE is the anonymous struct named by the typedef
+                DECL. As we need the DW_AT_type attribute of the
+                DW_TAG_typedef to point to the DIE of TYPE, let's
+                generate that DIE right away. add_type_attribute
+                called below will then pick (via lookup_type_die) that
+                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);
+           }
+       }
 
-static inline void
-add_call_src_coords_attributes (tree stmt, dw_die_ref die)
-{
-  expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt));
+      add_type_attribute (type_die, type, TREE_READONLY (decl),
+                         TREE_THIS_VOLATILE (decl), context_die);
 
-  if (dwarf_version >= 3 || !dwarf_strict)
-    {
-      add_AT_file (die, DW_AT_call_file, lookup_filename (s.file));
-      add_AT_unsigned (die, DW_AT_call_line, s.line);
+      if (is_naming_typedef_decl (decl))
+       /* We want that all subsequent calls to lookup_type_die with
+          TYPE in argument yield the DW_TAG_typedef we have just
+          created.  */
+       equate_type_number_to_die (type, type_die);
+
+      add_accessibility_attribute (type_die, decl);
     }
-}
 
+  if (DECL_ABSTRACT (decl))
+    equate_decl_number_to_die (decl, type_die);
 
-/* A helper function for gen_lexical_block_die and gen_inlined_subroutine_die.
-   Add low_pc and high_pc attributes to the DIE for a block STMT.  */
+  if (get_AT (type_die, DW_AT_name))
+    add_pubtype (decl, type_die);
+}
 
-static inline void
-add_high_low_attributes (tree stmt, dw_die_ref die)
+/* Generate a DIE for a struct, class, enum or union type.  */
+
+static void
+gen_tagged_type_die (tree type,
+                    dw_die_ref context_die,
+                    enum debug_info_usage usage)
 {
-  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+  int need_pop;
 
-  if (BLOCK_FRAGMENT_CHAIN (stmt)
-      && (dwarf_version >= 3 || !dwarf_strict))
-    {
-      tree chain;
+  if (type == NULL_TREE
+      || !is_tagged_type (type))
+    return;
 
-      if (inlined_function_outer_scope_p (stmt))
-       {
-         ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
-                                      BLOCK_NUMBER (stmt));
-         add_AT_lbl_id (die, DW_AT_entry_pc, label);
-       }
+  /* If this is a nested type whose containing class hasn't been written
+     out yet, writing it out will cover this one, too.  This does not apply
+     to instantiations of member class templates; they need to be added to
+     the containing class as they are generated.  FIXME: This hurts the
+     idea of combining type decls from multiple TUs, since we can't predict
+     what set of template instantiations we'll get.  */
+  if (TYPE_CONTEXT (type)
+      && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
+      && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
+    {
+      gen_type_die_with_usage (TYPE_CONTEXT (type), context_die, usage);
 
-      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
+      if (TREE_ASM_WRITTEN (type))
+       return;
 
-      chain = BLOCK_FRAGMENT_CHAIN (stmt);
-      do
-       {
-         add_ranges (chain);
-         chain = BLOCK_FRAGMENT_CHAIN (chain);
-       }
-      while (chain);
-      add_ranges (NULL);
+      /* If that failed, attach ourselves to the stub.  */
+      push_decl_scope (TYPE_CONTEXT (type));
+      context_die = lookup_type_die (TYPE_CONTEXT (type));
+      need_pop = 1;
+    }
+  else if (TYPE_CONTEXT (type) != NULL_TREE
+          && (TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL))
+    {
+      /* If this type is local to a function that hasn't been written
+        out yet, use a NULL context for now; it will be fixed up in
+        decls_for_scope.  */
+      context_die = lookup_decl_die (TYPE_CONTEXT (type));
+      /* 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
     {
-      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
-                                  BLOCK_NUMBER (stmt));
-      add_AT_lbl_id (die, DW_AT_low_pc, label);
-      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
-                                  BLOCK_NUMBER (stmt));
-      add_AT_lbl_id (die, DW_AT_high_pc, label);
+      context_die = declare_in_namespace (type, context_die);
+      need_pop = 0;
     }
-}
-
-/* Generate a DIE for a lexical block.  */
 
-static void
-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 (TREE_CODE (type) == ENUMERAL_TYPE)
+    {
+      /* This might have been written out by the call to
+        declare_in_namespace.  */
+      if (!TREE_ASM_WRITTEN (type))
+       gen_enumeration_type_die (type, context_die);
+    }
+  else
+    gen_struct_or_union_type_die (type, context_die, usage);
 
-  if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
-    add_high_low_attributes (stmt, stmt_die);
+  if (need_pop)
+    pop_decl_scope ();
 
-  decls_for_scope (stmt, stmt_die, depth);
+  /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix
+     it up if it is ever completed.  gen_*_type_die will set it for us
+     when appropriate.  */
 }
 
-/* Generate a DIE for an inlined subprogram.  */
+/* Generate a type description DIE.  */
 
 static void
-gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die, int depth)
+gen_type_die_with_usage (tree type, dw_die_ref context_die,
+                        enum debug_info_usage usage)
 {
-  tree decl;
+  struct array_descr_info info;
 
-  /* The instance of function that is effectively being inlined shall not
-     be abstract.  */
-  gcc_assert (! BLOCK_ABSTRACT (stmt));
+  if (type == NULL_TREE || type == error_mark_node)
+    return;
 
-  decl = block_ultimate_origin (stmt);
+  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));
 
-  /* Emit info for the abstract instance first, if we haven't yet.  We
-     must emit this even if the block is abstract, otherwise when we
-     emit the block below (or elsewhere), we may end up trying to emit
-     a die whose origin die hasn't been emitted, and crashing.  */
-  dwarf2out_abstract_function (decl);
+  /* 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))
+    {
+      if (TREE_ASM_WRITTEN (type))
+       return;
+
+      /* Prevent broken recursion; we can't hand off to the same type.  */
+      gcc_assert (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) != type);
+
+      /* Use the DIE of the containing namespace as the parent DIE of
+         the type description DIE we want to generate.  */
+      if (DECL_FILE_SCOPE_P (TYPE_NAME (type))
+         || (DECL_CONTEXT (TYPE_NAME (type))
+             && TREE_CODE (DECL_CONTEXT (TYPE_NAME (type))) == NAMESPACE_DECL))
+       context_die = get_context_die (DECL_CONTEXT (TYPE_NAME (type)));
 
-  if (! BLOCK_ABSTRACT (stmt))
-    {
-      dw_die_ref subr_die
-       = new_die (DW_TAG_inlined_subroutine, context_die, stmt);
+      TREE_ASM_WRITTEN (type) = 1;
 
-      add_abstract_origin_attribute (subr_die, decl);
-      if (TREE_ASM_WRITTEN (stmt))
-        add_high_low_attributes (stmt, subr_die);
-      add_call_src_coords_attributes (stmt, subr_die);
+      gen_decl_die (TYPE_NAME (type), NULL, context_die);
+      return;
+    }
 
-      decls_for_scope (stmt, subr_die, depth);
-      current_function_has_inlines = 1;
+  /* If type is an anonymous tagged type named by a typedef, let's
+     generate debug info for the typedef.  */
+  if (is_naming_typedef_decl (TYPE_NAME (type)))
+    {
+      /* Use the DIE of the containing namespace as the parent DIE of
+         the type description DIE we want to generate.  */
+      if (DECL_CONTEXT (TYPE_NAME (type))
+         && TREE_CODE (DECL_CONTEXT (TYPE_NAME (type))) == NAMESPACE_DECL)
+       context_die = get_context_die (DECL_CONTEXT (TYPE_NAME (type)));
+      
+      gen_decl_die (TYPE_NAME (type), NULL, context_die);
+      return;
     }
-}
 
-/* Generate a DIE for a field in a record, or structure.  */
+  /* If this is an array type with hidden descriptor, handle it first.  */
+  if (!TREE_ASM_WRITTEN (type)
+      && lang_hooks.types.get_array_descr_info
+      && lang_hooks.types.get_array_descr_info (type, &info)
+      && (dwarf_version >= 3 || !dwarf_strict))
+    {
+      gen_descr_array_type_die (type, &info, context_die);
+      TREE_ASM_WRITTEN (type) = 1;
+      return;
+    }
 
-static void
-gen_field_die (tree decl, dw_die_ref context_die)
-{
-  dw_die_ref decl_die;
+  /* We are going to output a DIE to represent the unqualified version
+     of this type (i.e. without any const or volatile qualifiers) so
+     get the main variant (i.e. the unqualified version) of this type
+     now.  (Vectors are special because the debugging info is in the
+     cloned type itself).  */
+  if (TREE_CODE (type) != VECTOR_TYPE)
+    type = type_main_variant (type);
 
-  if (TREE_TYPE (decl) == error_mark_node)
+  if (TREE_ASM_WRITTEN (type))
     return;
 
-  decl_die = new_die (DW_TAG_member, context_die, decl);
-  add_name_and_src_coords_attributes (decl_die, decl);
-  add_type_attribute (decl_die, member_declared_type (decl),
-                     TREE_READONLY (decl), TREE_THIS_VOLATILE (decl),
-                     context_die);
-
-  if (DECL_BIT_FIELD_TYPE (decl))
+  switch (TREE_CODE (type))
     {
-      add_byte_size_attribute (decl_die, decl);
-      add_bit_size_attribute (decl_die, decl);
-      add_bit_offset_attribute (decl_die, decl);
-    }
+    case ERROR_MARK:
+      break;
 
-  if (TREE_CODE (DECL_FIELD_CONTEXT (decl)) != UNION_TYPE)
-    add_data_member_location_attribute (decl_die, decl);
+    case POINTER_TYPE:
+    case REFERENCE_TYPE:
+      /* We must set TREE_ASM_WRITTEN in case this is a recursive type.  This
+        ensures that the gen_type_die recursion will terminate even if the
+        type is recursive.  Recursive types are possible in Ada.  */
+      /* ??? We could perhaps do this for all types before the switch
+        statement.  */
+      TREE_ASM_WRITTEN (type) = 1;
 
-  if (DECL_ARTIFICIAL (decl))
-    add_AT_flag (decl_die, DW_AT_artificial, 1);
+      /* For these types, all that is required is that we output a DIE (or a
+        set of DIEs) to represent the "basis" type.  */
+      gen_type_die_with_usage (TREE_TYPE (type), context_die,
+                               DINFO_USAGE_IND_USE);
+      break;
 
-  if (TREE_PROTECTED (decl))
-    add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_protected);
-  else if (TREE_PRIVATE (decl))
-    add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_private);
+    case OFFSET_TYPE:
+      /* This code is used for C++ pointer-to-data-member types.
+        Output a description of the relevant class type.  */
+      gen_type_die_with_usage (TYPE_OFFSET_BASETYPE (type), context_die,
+                                       DINFO_USAGE_IND_USE);
 
-  /* Equate decl number to die, so that we can look up this decl later on.  */
-  equate_decl_number_to_die (decl, decl_die);
-}
+      /* Output a description of the type of the object pointed to.  */
+      gen_type_die_with_usage (TREE_TYPE (type), context_die,
+                                       DINFO_USAGE_IND_USE);
 
-#if 0
-/* Don't generate either pointer_type DIEs or reference_type DIEs here.
-   Use modified_type_die instead.
-   We keep this code here just in case these types of DIEs may be needed to
-   represent certain things in other languages (e.g. Pascal) someday.  */
+      /* Now output a DIE to represent this pointer-to-data-member type
+        itself.  */
+      gen_ptr_to_mbr_type_die (type, context_die);
+      break;
 
-static void
-gen_pointer_type_die (tree type, dw_die_ref context_die)
-{
-  dw_die_ref ptr_die
-    = new_die (DW_TAG_pointer_type, scope_die_for (type, context_die), type);
+    case FUNCTION_TYPE:
+      /* Force out return type (in case it wasn't forced out already).  */
+      gen_type_die_with_usage (TREE_TYPE (type), context_die,
+                                       DINFO_USAGE_DIR_USE);
+      gen_subroutine_type_die (type, context_die);
+      break;
 
-  equate_type_number_to_die (type, ptr_die);
-  add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
-  add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
-}
+    case METHOD_TYPE:
+      /* Force out return type (in case it wasn't forced out already).  */
+      gen_type_die_with_usage (TREE_TYPE (type), context_die,
+                                       DINFO_USAGE_DIR_USE);
+      gen_subroutine_type_die (type, context_die);
+      break;
 
-/* Don't generate either pointer_type DIEs or reference_type DIEs here.
-   Use modified_type_die instead.
-   We keep this code here just in case these types of DIEs may be needed to
-   represent certain things in other languages (e.g. Pascal) someday.  */
+    case ARRAY_TYPE:
+      gen_array_type_die (type, context_die);
+      break;
 
-static void
-gen_reference_type_die (tree type, dw_die_ref context_die)
-{
-  dw_die_ref ref_die, scope_die = scope_die_for (type, context_die);
+    case VECTOR_TYPE:
+      gen_array_type_die (type, context_die);
+      break;
 
-  if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4)
-    ref_die = new_die (DW_TAG_rvalue_reference_type, scope_die, type);
-  else
-    ref_die = new_die (DW_TAG_reference_type, scope_die, type);
+    case ENUMERAL_TYPE:
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      gen_tagged_type_die (type, context_die, usage);
+      return;
 
-  equate_type_number_to_die (type, ref_die);
-  add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die);
-  add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
-}
-#endif
+    case VOID_TYPE:
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case FIXED_POINT_TYPE:
+    case COMPLEX_TYPE:
+    case BOOLEAN_TYPE:
+      /* No DIEs needed for fundamental types.  */
+      break;
 
-/* Generate a DIE for a pointer to a member type.  */
+    case NULLPTR_TYPE:
+    case LANG_TYPE:
+      /* Just use DW_TAG_unspecified_type.  */
+      {
+        dw_die_ref type_die = lookup_type_die (type);
+        if (type_die == NULL)
+          {
+           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);
+            add_name_attribute (type_die, IDENTIFIER_POINTER (name));
+            equate_type_number_to_die (type, type_die);
+          }
+      }
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  TREE_ASM_WRITTEN (type) = 1;
+}
 
 static void
-gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die)
+gen_type_die (tree type, dw_die_ref context_die)
 {
-  dw_die_ref ptr_die
-    = new_die (DW_TAG_ptr_to_member_type,
-              scope_die_for (type, context_die), type);
-
-  equate_type_number_to_die (type, ptr_die);
-  add_AT_die_ref (ptr_die, DW_AT_containing_type,
-                 lookup_type_die (TYPE_OFFSET_BASETYPE (type)));
-  add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
+  gen_type_die_with_usage (type, context_die, DINFO_USAGE_DIR_USE);
 }
 
-/* Generate the DIE for the compilation unit.  */
+/* Generate a DW_TAG_lexical_block DIE followed by DIEs to represent all of the
+   things which are local to the given block.  */
 
-static dw_die_ref
-gen_compile_unit_die (const char *filename)
+static void
+gen_block_die (tree stmt, dw_die_ref context_die, int depth)
 {
-  dw_die_ref die;
-  char producer[250];
-  const char *language_string = lang_hooks.name;
-  int language;
+  int must_output_die = 0;
+  bool inlined_func;
 
-  die = new_die (DW_TAG_compile_unit, NULL, NULL);
+  /* Ignore blocks that are NULL.  */
+  if (stmt == NULL_TREE)
+    return;
 
-  if (filename)
-    {
-      add_name_attribute (die, filename);
-      /* Don't add cwd for <built-in>.  */
-      if (!IS_ABSOLUTE_PATH (filename) && filename[0] != '<')
-       add_comp_dir_attribute (die);
-    }
+  inlined_func = inlined_function_outer_scope_p (stmt);
 
-  sprintf (producer, "%s %s", language_string, version_string);
+  /* If the block is one fragment of a non-contiguous block, do not
+     process the variables, since they will have been done by the
+     origin block.  Do process subblocks.  */
+  if (BLOCK_FRAGMENT_ORIGIN (stmt))
+    {
+      tree sub;
 
-#ifdef MIPS_DEBUGGING_INFO
-  /* The MIPS/SGI compilers place the 'cc' command line options in the producer
-     string.  The SGI debugger looks for -g, -g1, -g2, or -g3; if they do
-     not appear in the producer string, the debugger reaches the conclusion
-     that the object file is stripped and has no debugging information.
-     To get the MIPS/SGI debugger to believe that there is debugging
-     information in the object file, we add a -g to the producer string.  */
-  if (debug_info_level > DINFO_LEVEL_TERSE)
-    strcat (producer, " -g");
-#endif
+      for (sub = BLOCK_SUBBLOCKS (stmt); sub; sub = BLOCK_CHAIN (sub))
+       gen_block_die (sub, context_die, depth + 1);
 
-  add_AT_string (die, DW_AT_producer, producer);
+      return;
+    }
 
-  language = DW_LANG_C89;
-  if (strcmp (language_string, "GNU C++") == 0)
-    language = DW_LANG_C_plus_plus;
-  else if (strcmp (language_string, "GNU F77") == 0)
-    language = DW_LANG_Fortran77;
-  else if (strcmp (language_string, "GNU Pascal") == 0)
-    language = DW_LANG_Pascal83;
-  else if (dwarf_version >= 3 || !dwarf_strict)
+  /* Determine if we need to output any Dwarf DIEs at all to represent this
+     block.  */
+  if (inlined_func)
+    /* The outer scopes for inlinings *must* always be represented.  We
+       generate DW_TAG_inlined_subroutine DIEs for them.  (See below.) */
+    must_output_die = 1;
+  else
     {
-      if (strcmp (language_string, "GNU Ada") == 0)
-       language = DW_LANG_Ada95;
-      else if (strcmp (language_string, "GNU Fortran") == 0)
-       language = DW_LANG_Fortran95;
-      else if (strcmp (language_string, "GNU Java") == 0)
-       language = DW_LANG_Java;
-      else if (strcmp (language_string, "GNU Objective-C") == 0)
-       language = DW_LANG_ObjC;
-      else if (strcmp (language_string, "GNU Objective-C++") == 0)
-       language = DW_LANG_ObjC_plus_plus;
+      /* Determine if this block directly contains any "significant"
+        local declarations which we will need to output DIEs for.  */
+      if (debug_info_level > DINFO_LEVEL_TERSE)
+       /* We are not in terse mode so *any* local declaration counts
+          as being a "significant" one.  */
+       must_output_die = ((BLOCK_VARS (stmt) != NULL
+                           || BLOCK_NUM_NONLOCALIZED_VARS (stmt))
+                          && (TREE_USED (stmt)
+                              || TREE_ASM_WRITTEN (stmt)
+                              || BLOCK_ABSTRACT (stmt)));
+      else if ((TREE_USED (stmt)
+               || TREE_ASM_WRITTEN (stmt)
+               || BLOCK_ABSTRACT (stmt))
+              && !dwarf2out_ignore_block (stmt))
+       must_output_die = 1;
     }
 
-  add_AT_unsigned (die, DW_AT_language, language);
-
-  switch (language)
+  /* It would be a waste of space to generate a Dwarf DW_TAG_lexical_block
+     DIE for any block which contains no significant local declarations at
+     all.  Rather, in such cases we just call `decls_for_scope' so that any
+     needed Dwarf info for any sub-blocks will get properly generated. Note
+     that in terse mode, our definition of what constitutes a "significant"
+     local declaration gets restricted to include only inlined function
+     instances and local (nested) function definitions.  */
+  if (must_output_die)
     {
-    case DW_LANG_Fortran77:
-    case DW_LANG_Fortran90:
-    case DW_LANG_Fortran95:
-      /* Fortran has case insensitive identifiers and the front-end
-        lowercases everything.  */
-      add_AT_unsigned (die, DW_AT_identifier_case, DW_ID_down_case);
-      break;
-    default:
-      /* The default DW_ID_case_sensitive doesn't need to be specified.  */
-      break;
+      if (inlined_func)
+       {
+         /* If STMT block is abstract, that means we have been called
+            indirectly from dwarf2out_abstract_function.
+            That function rightfully marks the descendent blocks (of
+            the abstract function it is dealing with) as being abstract,
+            precisely to prevent us from emitting any
+            DW_TAG_inlined_subroutine DIE as a descendent
+            of an abstract function instance. So in that case, we should
+            not call gen_inlined_subroutine_die.
+
+            Later though, when cgraph asks dwarf2out to emit info
+            for the concrete instance of the function decl into which
+            the concrete instance of STMT got inlined, the later will lead
+            to the generation of a DW_TAG_inlined_subroutine DIE.  */
+         if (! BLOCK_ABSTRACT (stmt))
+           gen_inlined_subroutine_die (stmt, context_die, depth);
+       }
+      else
+       gen_lexical_block_die (stmt, context_die, depth);
     }
-  return die;
+  else
+    decls_for_scope (stmt, context_die, depth);
 }
 
-/* Generate the DIE for a base class.  */
-
+/* Process variable DECL (or variable with origin ORIGIN) within
+   block STMT and add it to CONTEXT_DIE.  */
 static void
-gen_inheritance_die (tree binfo, tree access, dw_die_ref context_die)
+process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
 {
-  dw_die_ref die = new_die (DW_TAG_inheritance, context_die, binfo);
-
-  add_type_attribute (die, BINFO_TYPE (binfo), 0, 0, context_die);
-  add_data_member_location_attribute (die, binfo);
+  dw_die_ref die;
+  tree decl_or_origin = decl ? decl : origin;
 
-  if (BINFO_VIRTUAL_P (binfo))
-    add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
+  if (TREE_CODE (decl_or_origin) == FUNCTION_DECL)
+    die = lookup_decl_die (decl_or_origin);
+  else if (TREE_CODE (decl_or_origin) == TYPE_DECL
+           && TYPE_DECL_IS_STUB (decl_or_origin))
+    die = lookup_type_die (TREE_TYPE (decl_or_origin));
+  else
+    die = NULL;
 
-  if (access == access_public_node)
-    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);
+  if (die != NULL && die->die_parent == NULL)
+    add_child_die (context_die, die);
+  else if (TREE_CODE (decl_or_origin) == IMPORTED_DECL)
+    dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
+                                        stmt, context_die);
+  else
+    gen_decl_die (decl, origin, context_die);
 }
 
-/* Generate a DIE for a class member.  */
+/* Generate all of the decls declared within a given scope and (recursively)
+   all of its sub-blocks.  */
 
 static void
-gen_member_die (tree type, dw_die_ref context_die)
+decls_for_scope (tree stmt, dw_die_ref context_die, int depth)
 {
-  tree member;
-  tree binfo = TYPE_BINFO (type);
-  dw_die_ref child;
+  tree decl;
+  unsigned int i;
+  tree subblocks;
 
-  /* If this is not an incomplete type, output descriptions of each of its
-     members. Note that as we output the DIEs necessary to represent the
-     members of this record or union type, we will also be trying to output
-     DIEs to represent the *types* of those members. However the `type'
-     function (above) will specifically avoid generating type DIEs for member
-     types *within* the list of member DIEs for this (containing) type except
-     for those types (of members) which are explicitly marked as also being
-     members of this (containing) type themselves.  The g++ front- end can
-     force any given type to be treated as a member of some other (containing)
-     type by setting the TYPE_CONTEXT of the given (member) type to point to
-     the TREE node representing the appropriate (containing) type.  */
+  /* Ignore NULL blocks.  */
+  if (stmt == NULL_TREE)
+    return;
 
-  /* First output info about the base classes.  */
-  if (binfo)
-    {
-      VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (binfo);
-      int i;
-      tree base;
+  /* Output the DIEs to represent all of the data objects and typedefs
+     declared directly within this block but not within any nested
+     sub-blocks.  Also, nested function and tag DIEs have been
+     generated with a parent of NULL; fix that up now.  */
+  for (decl = BLOCK_VARS (stmt); decl != NULL; decl = DECL_CHAIN (decl))
+    process_scope_var (stmt, decl, NULL_TREE, context_die);
+  for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++)
+    process_scope_var (stmt, NULL, BLOCK_NONLOCALIZED_VAR (stmt, i),
+                      context_die);
 
-      for (i = 0; BINFO_BASE_ITERATE (binfo, i, base); i++)
-       gen_inheritance_die (base,
-                            (accesses ? VEC_index (tree, accesses, i)
-                             : access_public_node), context_die);
-    }
+  /* If we're at -g1, we're not interested in subblocks.  */
+  if (debug_info_level <= DINFO_LEVEL_TERSE)
+    return;
 
-  /* Now output info about the data members and type members.  */
-  for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
-    {
-      /* If we thought we were generating minimal debug info for TYPE
-        and then changed our minds, some of the member declarations
-        may have already been defined.  Don't define them again, but
-        do put them in the right order.  */
+  /* Output the DIEs to represent all sub-blocks (and the items declared
+     therein) of this block.  */
+  for (subblocks = BLOCK_SUBBLOCKS (stmt);
+       subblocks != NULL;
+       subblocks = BLOCK_CHAIN (subblocks))
+    gen_block_die (subblocks, context_die, depth + 1);
+}
 
-      child = lookup_decl_die (member);
-      if (child)
-       splice_child_die (context_die, child);
-      else
-       gen_decl_die (member, NULL, context_die);
-    }
+/* Is this a typedef we can avoid emitting?  */
 
-  /* Now output info about the function members (if any).  */
-  for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member))
-    {
-      /* Don't include clones in the member list.  */
-      if (DECL_ABSTRACT_ORIGIN (member))
-       continue;
+static inline int
+is_redundant_typedef (const_tree decl)
+{
+  if (TYPE_DECL_IS_STUB (decl))
+    return 1;
 
-      child = lookup_decl_die (member);
-      if (child)
-       splice_child_die (context_die, child);
-      else
-       gen_decl_die (member, NULL, context_die);
-    }
+  if (DECL_ARTIFICIAL (decl)
+      && DECL_CONTEXT (decl)
+      && is_tagged_type (DECL_CONTEXT (decl))
+      && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL
+      && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))))
+    /* Also ignore the artificial member typedef for the class name.  */
+    return 1;
+
+  return 0;
 }
 
-/* Generate a DIE for a structure or union type.  If TYPE_DECL_SUPPRESS_DEBUG
-   is set, we pretend that the type was never defined, so we only get the
-   member DIEs needed by later specification DIEs.  */
+/* Return TRUE if TYPE is a typedef that names a type for linkage
+   purposes. This kind of typedefs is produced by the C++ FE for
+   constructs like:
 
-static void
-gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
-                               enum debug_info_usage usage)
-{
-  dw_die_ref type_die = lookup_type_die (type);
-  dw_die_ref scope_die = 0;
-  int nested = 0;
-  int complete = (TYPE_SIZE (type)
-                 && (! TYPE_STUB_DECL (type)
-                     || ! TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))));
-  int ns_decl = (context_die && context_die->die_tag == DW_TAG_namespace);
-  complete = complete && should_emit_struct_debug (type, usage);
+   typedef struct {...} foo;
 
-  if (type_die && ! complete)
-    return;
+   In that case, there is no typedef variant type produced for foo.
+   Rather, the TREE_TYPE of the TYPE_DECL of foo is the anonymous
+   struct type.  */
 
-  if (TYPE_CONTEXT (type) != NULL_TREE
-      && (AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
-         || TREE_CODE (TYPE_CONTEXT (type)) == NAMESPACE_DECL))
-    nested = 1;
+static bool
+is_naming_typedef_decl (const_tree decl)
+{
+  if (decl == NULL_TREE
+      || TREE_CODE (decl) != TYPE_DECL
+      || !is_tagged_type (TREE_TYPE (decl))
+      || DECL_IS_BUILTIN (decl)
+      || is_redundant_typedef (decl)
+      /* It looks like Ada produces TYPE_DECLs that are very similar
+         to C++ naming typedefs but that have different
+         semantics. Let's be specific to c++ for now.  */
+      || !is_cxx ())
+    return FALSE;
 
-  scope_die = scope_die_for (type, context_die);
+  return (DECL_ORIGINAL_TYPE (decl) == NULL_TREE
+         && TYPE_NAME (TREE_TYPE (decl)) == decl
+         && (TYPE_STUB_DECL (TREE_TYPE (decl))
+             != TYPE_NAME (TREE_TYPE (decl))));
+}
 
-  if (! type_die || (nested && scope_die == comp_unit_die))
-    /* First occurrence of type or toplevel definition of nested class.  */
-    {
-      dw_die_ref old_die = type_die;
+/* Returns the DIE for a context.  */
 
-      type_die = new_die (TREE_CODE (type) == RECORD_TYPE
-                         ? record_type_tag (type) : DW_TAG_union_type,
-                         scope_die, type);
-      equate_type_number_to_die (type, type_die);
-      if (old_die)
-       add_AT_specification (type_die, old_die);
+static inline dw_die_ref
+get_context_die (tree context)
+{
+  if (context)
+    {
+      /* Find die that represents this context.  */
+      if (TYPE_P (context))
+       {
+         context = TYPE_MAIN_VARIANT (context);
+         return strip_naming_typedef (context, force_type_die (context));
+       }
       else
-       add_name_attribute (type_die, type_tag (type));
+       return force_decl_die (context);
     }
-  else
-    remove_AT (type_die, DW_AT_declaration);
+  return comp_unit_die ();
+}
 
-  /* Generate child dies for template paramaters.  */
-  if (debug_info_level > DINFO_LEVEL_TERSE
-      && COMPLETE_TYPE_P (type))
-    gen_generic_params_dies (type);
+/* Returns the DIE for decl.  A DIE will always be returned.  */
 
-  /* If this type has been completed, then give it a byte_size attribute and
-     then give a list of members.  */
-  if (complete && !ns_decl)
+static dw_die_ref
+force_decl_die (tree decl)
+{
+  dw_die_ref decl_die;
+  unsigned saved_external_flag;
+  tree save_fn = NULL_TREE;
+  decl_die = lookup_decl_die (decl);
+  if (!decl_die)
     {
-      /* Prevent infinite recursion in cases where the type of some member of
-        this type is expressed in terms of this type itself.  */
-      TREE_ASM_WRITTEN (type) = 1;
-      add_byte_size_attribute (type_die, type);
-      if (TYPE_STUB_DECL (type) != NULL_TREE)
-       add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
-
-      /* If the first reference to this type was as the return type of an
-        inline function, then it may not have a parent.  Fix this now.  */
-      if (type_die->die_parent == NULL)
-       add_child_die (scope_die, type_die);
+      dw_die_ref context_die = get_context_die (DECL_CONTEXT (decl));
 
-      push_decl_scope (type);
-      gen_member_die (type, type_die);
-      pop_decl_scope ();
+      decl_die = lookup_decl_die (decl);
+      if (decl_die)
+       return decl_die;
 
-      /* GNU extension: Record what type our vtable lives in.  */
-      if (TYPE_VFIELD (type))
+      switch (TREE_CODE (decl))
        {
-         tree vtype = DECL_FCONTEXT (TYPE_VFIELD (type));
+       case FUNCTION_DECL:
+         /* Clear current_function_decl, so that gen_subprogram_die thinks
+            that this is a declaration. At this point, we just want to force
+            declaration die.  */
+         save_fn = current_function_decl;
+         current_function_decl = NULL_TREE;
+         gen_subprogram_die (decl, context_die);
+         current_function_decl = save_fn;
+         break;
 
-         gen_type_die (vtype, context_die);
-         add_AT_die_ref (type_die, DW_AT_containing_type,
-                         lookup_type_die (vtype));
+       case VAR_DECL:
+         /* Set external flag to force declaration die. Restore it after
+          gen_decl_die() call.  */
+         saved_external_flag = DECL_EXTERNAL (decl);
+         DECL_EXTERNAL (decl) = 1;
+         gen_decl_die (decl, NULL, context_die);
+         DECL_EXTERNAL (decl) = saved_external_flag;
+         break;
+
+       case NAMESPACE_DECL:
+         if (dwarf_version >= 3 || !dwarf_strict)
+           dwarf2out_decl (decl);
+         else
+           /* DWARF2 has neither DW_TAG_module, nor DW_TAG_namespace.  */
+           decl_die = comp_unit_die ();
+         break;
+
+       case TRANSLATION_UNIT_DECL:
+         decl_die = comp_unit_die ();
+         break;
+
+       default:
+         gcc_unreachable ();
        }
-    }
-  else
-    {
-      add_AT_flag (type_die, DW_AT_declaration, 1);
 
-      /* We don't need to do this for function-local types.  */
-      if (TYPE_STUB_DECL (type)
-         && ! decl_function_context (TYPE_STUB_DECL (type)))
-       VEC_safe_push (tree, gc, incomplete_types, type);
+      /* We should be able to find the DIE now.  */
+      if (!decl_die)
+       decl_die = lookup_decl_die (decl);
+      gcc_assert (decl_die);
     }
 
-  if (get_AT (type_die, DW_AT_name))
-    add_pubtype (type, type_die);
+  return decl_die;
 }
 
-/* Generate a DIE for a subroutine _type_.  */
+/* Returns the DIE for TYPE, that must not be a base type.  A DIE is
+   always returned.  */
 
-static void
-gen_subroutine_type_die (tree type, dw_die_ref context_die)
+static dw_die_ref
+force_type_die (tree type)
 {
-  tree return_type = TREE_TYPE (type);
-  dw_die_ref subr_die
-    = new_die (DW_TAG_subroutine_type,
-              scope_die_for (type, context_die), type);
+  dw_die_ref type_die;
 
-  equate_type_number_to_die (type, subr_die);
-  add_prototyped_attribute (subr_die, type);
-  add_type_attribute (subr_die, return_type, 0, 0, context_die);
-  gen_formal_types_die (type, subr_die);
+  type_die = lookup_type_die (type);
+  if (!type_die)
+    {
+      dw_die_ref context_die = get_context_die (TYPE_CONTEXT (type));
 
-  if (get_AT (subr_die, DW_AT_name))
-    add_pubtype (type, subr_die);
+      type_die = modified_type_die (type, TYPE_READONLY (type),
+                                   TYPE_VOLATILE (type), context_die);
+      gcc_assert (type_die);
+    }
+  return type_die;
 }
 
-/* Generate a DIE for a type definition.  */
+/* Force out any required namespaces to be able to output DECL,
+   and return the new context_die for it, if it's changed.  */
 
-static void
-gen_typedef_die (tree decl, dw_die_ref context_die)
+static dw_die_ref
+setup_namespace_context (tree thing, dw_die_ref context_die)
 {
-  dw_die_ref type_die;
-  tree origin;
+  tree context = (DECL_P (thing)
+                 ? DECL_CONTEXT (thing) : TYPE_CONTEXT (thing));
+  if (context && TREE_CODE (context) == NAMESPACE_DECL)
+    /* Force out the namespace.  */
+    context_die = force_decl_die (context);
 
-  if (TREE_ASM_WRITTEN (decl))
-    return;
+  return context_die;
+}
 
-  TREE_ASM_WRITTEN (decl) = 1;
-  type_die = new_die (DW_TAG_typedef, context_die, decl);
-  origin = decl_ultimate_origin (decl);
-  if (origin != NULL)
-    add_abstract_origin_attribute (type_die, origin);
-  else
-    {
-      tree type;
+/* Emit a declaration DIE for THING (which is either a DECL or a tagged
+   type) within its namespace, if appropriate.
 
-      add_name_and_src_coords_attributes (type_die, decl);
-      if (DECL_ORIGINAL_TYPE (decl))
-       {
-         type = DECL_ORIGINAL_TYPE (decl);
+   For compatibility with older debuggers, namespace DIEs only contain
+   declarations; all definitions are emitted at CU scope.  */
 
-         gcc_assert (type != TREE_TYPE (decl));
-         equate_type_number_to_die (TREE_TYPE (decl), type_die);
-       }
-      else
-       type = TREE_TYPE (decl);
+static dw_die_ref
+declare_in_namespace (tree thing, dw_die_ref context_die)
+{
+  dw_die_ref ns_context;
 
-      add_type_attribute (type_die, type, TREE_READONLY (decl),
-                         TREE_THIS_VOLATILE (decl), context_die);
-    }
+  if (debug_info_level <= DINFO_LEVEL_TERSE)
+    return context_die;
 
-  if (DECL_ABSTRACT (decl))
-    equate_decl_number_to_die (decl, type_die);
+  /* If this decl is from an inlined function, then don't try to emit it in its
+     namespace, as we will get confused.  It would have already been emitted
+     when the abstract instance of the inline function was emitted anyways.  */
+  if (DECL_P (thing) && DECL_ABSTRACT_ORIGIN (thing))
+    return context_die;
 
-  if (get_AT (type_die, DW_AT_name))
-    add_pubtype (decl, type_die);
+  ns_context = setup_namespace_context (thing, context_die);
+
+  if (ns_context != context_die)
+    {
+      if (is_fortran ())
+       return ns_context;
+      if (DECL_P (thing))
+       gen_decl_die (thing, NULL, ns_context);
+      else
+       gen_type_die (thing, ns_context);
+    }
+  return context_die;
 }
 
-/* Generate a type description DIE.  */
+/* Generate a DIE for a namespace or namespace alias.  */
 
 static void
-gen_type_die_with_usage (tree type, dw_die_ref context_die,
-                               enum debug_info_usage usage)
+gen_namespace_die (tree decl, dw_die_ref context_die)
 {
-  int need_pop;
-  struct array_descr_info info;
-
-  if (type == NULL_TREE || type == error_mark_node)
-    return;
+  dw_die_ref namespace_die;
 
-  /* If TYPE is a typedef type variant, let's generate debug info
-     for the parent typedef which TYPE is a type of.  */
-  if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
-      && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+  /* Namespace aliases have a DECL_ABSTRACT_ORIGIN of the namespace
+     they are an alias of.  */
+  if (DECL_ABSTRACT_ORIGIN (decl) == NULL)
     {
-      if (TREE_ASM_WRITTEN (type))
-       return;
-
-      /* Prevent broken recursion; we can't hand off to the same type.  */
-      gcc_assert (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) != type);
-
-      /* Use the DIE of the containing namespace as the parent DIE of
-         the type description DIE we want to generate.  */
-      if (DECL_CONTEXT (TYPE_NAME (type))
-         && TREE_CODE (DECL_CONTEXT (TYPE_NAME (type))) == NAMESPACE_DECL)
-       context_die = get_context_die (DECL_CONTEXT (TYPE_NAME (type)));
-
-      TREE_ASM_WRITTEN (type) = 1;
-      gen_decl_die (TYPE_NAME (type), NULL, context_die);
-      return;
+      /* Output a real namespace or module.  */
+      context_die = setup_namespace_context (decl, comp_unit_die ());
+      namespace_die = new_die (is_fortran ()
+                              ? DW_TAG_module : DW_TAG_namespace,
+                              context_die, decl);
+      /* For Fortran modules defined in different CU don't add src coords.  */
+      if (namespace_die->die_tag == DW_TAG_module && DECL_EXTERNAL (decl))
+       {
+         const char *name = dwarf2_name (decl, 0);
+         if (name)
+           add_name_attribute (namespace_die, name);
+       }
+      else
+       add_name_and_src_coords_attributes (namespace_die, decl);
+      if (DECL_EXTERNAL (decl))
+       add_AT_flag (namespace_die, DW_AT_declaration, 1);
+      equate_decl_number_to_die (decl, namespace_die);
     }
-
-  /* If this is an array type with hidden descriptor, handle it first.  */
-  if (!TREE_ASM_WRITTEN (type)
-      && lang_hooks.types.get_array_descr_info
-      && lang_hooks.types.get_array_descr_info (type, &info)
-      && (dwarf_version >= 3 || !dwarf_strict))
+  else
     {
-      gen_descr_array_type_die (type, &info, context_die);
-      TREE_ASM_WRITTEN (type) = 1;
-      return;
-    }
-
-  /* We are going to output a DIE to represent the unqualified version
-     of this type (i.e. without any const or volatile qualifiers) so
-     get the main variant (i.e. the unqualified version) of this type
-     now.  (Vectors are special because the debugging info is in the
-     cloned type itself).  */
-  if (TREE_CODE (type) != VECTOR_TYPE)
-    type = type_main_variant (type);
-
-  if (TREE_ASM_WRITTEN (type))
-    return;
+      /* Output a namespace alias.  */
 
-  switch (TREE_CODE (type))
-    {
-    case ERROR_MARK:
-      break;
+      /* Force out the namespace we are an alias of, if necessary.  */
+      dw_die_ref origin_die
+       = force_decl_die (DECL_ABSTRACT_ORIGIN (decl));
 
-    case POINTER_TYPE:
-    case REFERENCE_TYPE:
-      /* We must set TREE_ASM_WRITTEN in case this is a recursive type.  This
-        ensures that the gen_type_die recursion will terminate even if the
-        type is recursive.  Recursive types are possible in Ada.  */
-      /* ??? We could perhaps do this for all types before the switch
-        statement.  */
-      TREE_ASM_WRITTEN (type) = 1;
+      if (DECL_FILE_SCOPE_P (decl)
+         || TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL)
+       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);
+      add_AT_die_ref (namespace_die, DW_AT_import, origin_die);
+      equate_decl_number_to_die (decl, namespace_die);
+    }
+}
 
-      /* For these types, all that is required is that we output a DIE (or a
-        set of DIEs) to represent the "basis" type.  */
-      gen_type_die_with_usage (TREE_TYPE (type), context_die,
-                               DINFO_USAGE_IND_USE);
-      break;
+/* Generate Dwarf debug information for a decl described by DECL.
+   The return value is currently only meaningful for PARM_DECLs,
+   for all other decls it returns NULL.  */
 
-    case OFFSET_TYPE:
-      /* This code is used for C++ pointer-to-data-member types.
-        Output a description of the relevant class type.  */
-      gen_type_die_with_usage (TYPE_OFFSET_BASETYPE (type), context_die,
-                                       DINFO_USAGE_IND_USE);
+static dw_die_ref
+gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
+{
+  tree decl_or_origin = decl ? decl : origin;
+  tree class_origin = NULL, ultimate_origin;
 
-      /* Output a description of the type of the object pointed to.  */
-      gen_type_die_with_usage (TREE_TYPE (type), context_die,
-                                       DINFO_USAGE_IND_USE);
+  if (DECL_P (decl_or_origin) && DECL_IGNORED_P (decl_or_origin))
+    return NULL;
 
-      /* Now output a DIE to represent this pointer-to-data-member type
-        itself.  */
-      gen_ptr_to_mbr_type_die (type, context_die);
+  switch (TREE_CODE (decl_or_origin))
+    {
+    case ERROR_MARK:
       break;
 
-    case FUNCTION_TYPE:
-      /* Force out return type (in case it wasn't forced out already).  */
-      gen_type_die_with_usage (TREE_TYPE (type), context_die,
-                                       DINFO_USAGE_DIR_USE);
-      gen_subroutine_type_die (type, context_die);
-      break;
+    case CONST_DECL:
+      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.  */
+         break;
+       }
 
-    case METHOD_TYPE:
-      /* Force out return type (in case it wasn't forced out already).  */
-      gen_type_die_with_usage (TREE_TYPE (type), context_die,
-                                       DINFO_USAGE_DIR_USE);
-      gen_subroutine_type_die (type, context_die);
-      break;
+      /* Emit its type.  */
+      gen_type_die (TREE_TYPE (decl), context_die);
 
-    case ARRAY_TYPE:
-      gen_array_type_die (type, context_die);
-      break;
+      /* And its containing namespace.  */
+      context_die = declare_in_namespace (decl, context_die);
 
-    case VECTOR_TYPE:
-      gen_array_type_die (type, context_die);
+      gen_const_die (decl, context_die);
       break;
 
-    case ENUMERAL_TYPE:
-    case RECORD_TYPE:
-    case UNION_TYPE:
-    case QUAL_UNION_TYPE:
-      /* If this is a nested type whose containing class hasn't been written
-        out yet, writing it out will cover this one, too.  This does not apply
-        to instantiations of member class templates; they need to be added to
-        the containing class as they are generated.  FIXME: This hurts the
-        idea of combining type decls from multiple TUs, since we can't predict
-        what set of template instantiations we'll get.  */
-      if (TYPE_CONTEXT (type)
-         && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
-         && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
-       {
-         gen_type_die_with_usage (TYPE_CONTEXT (type), context_die, usage);
+    case FUNCTION_DECL:
+      /* 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_FILE_SCOPE_P (decl_or_origin)
+         && (current_function_decl == NULL_TREE
+             || DECL_ARTIFICIAL (decl_or_origin)))
+       break;
 
-         if (TREE_ASM_WRITTEN (type))
-           return;
+#if 0
+      /* FIXME */
+      /* This doesn't work because the C frontend sets DECL_ABSTRACT_ORIGIN
+        on local redeclarations of global functions.  That seems broken.  */
+      if (current_function_decl != decl)
+       /* This is only a declaration.  */;
+#endif
 
-         /* If that failed, attach ourselves to the stub.  */
-         push_decl_scope (TYPE_CONTEXT (type));
-         context_die = lookup_type_die (TYPE_CONTEXT (type));
-         need_pop = 1;
-       }
-      else if (TYPE_CONTEXT (type) != NULL_TREE
-              && (TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL))
-       {
-         /* If this type is local to a function that hasn't been written
-            out yet, use a NULL context for now; it will be fixed up in
-            decls_for_scope.  */
-         context_die = lookup_decl_die (TYPE_CONTEXT (type));
-         need_pop = 0;
-       }
-      else
-       {
-         context_die = declare_in_namespace (type, context_die);
-         need_pop = 0;
-       }
+      /* If we're emitting a clone, emit info for the abstract instance.  */
+      if (origin || DECL_ORIGIN (decl) != decl)
+       dwarf2out_abstract_function (origin
+                                    ? DECL_ORIGIN (origin)
+                                    : DECL_ABSTRACT_ORIGIN (decl));
 
-      if (TREE_CODE (type) == ENUMERAL_TYPE)
+      /* If we're emitting an out-of-line copy of an inline function,
+        emit info for the abstract instance and set up to refer to it.  */
+      else if (cgraph_function_possibly_inlined_p (decl)
+              && ! DECL_ABSTRACT (decl)
+              && ! class_or_namespace_scope_p (context_die)
+              /* dwarf2out_abstract_function won't emit a die if this is just
+                 a declaration.  We must avoid setting DECL_ABSTRACT_ORIGIN in
+                 that case, because that works only if we have a die.  */
+              && DECL_INITIAL (decl) != NULL_TREE)
        {
-         /* This might have been written out by the call to
-            declare_in_namespace.  */
-         if (!TREE_ASM_WRITTEN (type))
-           gen_enumeration_type_die (type, context_die);
+         dwarf2out_abstract_function (decl);
+         set_decl_origin_self (decl);
        }
-      else
-       gen_struct_or_union_type_die (type, context_die, usage);
 
-      if (need_pop)
-       pop_decl_scope ();
-
-      /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix
-        it up if it is ever completed.  gen_*_type_die will set it for us
-        when appropriate.  */
-      return;
+      /* Otherwise we're emitting the primary DIE for this decl.  */
+      else if (debug_info_level > DINFO_LEVEL_TERSE)
+       {
+         /* Before we describe the FUNCTION_DECL itself, make sure that we
+            have its containing type.  */
+         if (!origin)
+           origin = decl_class_context (decl);
+         if (origin != NULL_TREE)
+           gen_type_die (origin, context_die);
 
-    case VOID_TYPE:
-    case INTEGER_TYPE:
-    case REAL_TYPE:
-    case FIXED_POINT_TYPE:
-    case COMPLEX_TYPE:
-    case BOOLEAN_TYPE:
-      /* No DIEs needed for fundamental types.  */
-      break;
+         /* And its return type.  */
+         gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die);
 
-    case LANG_TYPE:
-      /* Just use DW_TAG_unspecified_type.  */
-      {
-        dw_die_ref type_die = lookup_type_die (type);
-        if (type_die == NULL)
-          {
-           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);
-            add_name_attribute (type_die, IDENTIFIER_POINTER (name));
-            equate_type_number_to_die (type, type_die);
-          }
-      }
-      break;
+         /* And its virtual context.  */
+         if (DECL_VINDEX (decl) != NULL_TREE)
+           gen_type_die (DECL_CONTEXT (decl), context_die);
 
-    default:
-      gcc_unreachable ();
-    }
+         /* Make sure we have a member DIE for decl.  */
+         if (origin != NULL_TREE)
+           gen_type_die_for_member (origin, decl, context_die);
 
-  TREE_ASM_WRITTEN (type) = 1;
-}
+         /* And its containing namespace.  */
+         context_die = declare_in_namespace (decl, context_die);
+       }
 
-static void
-gen_type_die (tree type, dw_die_ref context_die)
-{
-  gen_type_die_with_usage (type, context_die, DINFO_USAGE_DIR_USE);
-}
+      /* Now output a DIE to represent the function itself.  */
+      if (decl)
+        gen_subprogram_die (decl, context_die);
+      break;
 
-/* Generate a DW_TAG_lexical_block DIE followed by DIEs to represent all of the
-   things which are local to the given block.  */
+    case TYPE_DECL:
+      /* If we are in terse mode, don't generate any DIEs to represent any
+        actual typedefs.  */
+      if (debug_info_level <= DINFO_LEVEL_TERSE)
+       break;
 
-static void
-gen_block_die (tree stmt, dw_die_ref context_die, int depth)
-{
-  int must_output_die = 0;
-  bool inlined_func;
+      /* In the special case of a TYPE_DECL node representing the declaration
+        of some type tag, if the given TYPE_DECL is marked as having been
+        instantiated from some other (original) TYPE_DECL node (e.g. one which
+        was generated within the original definition of an inline function) we
+        used to generate a special (abbreviated) DW_TAG_structure_type,
+        DW_TAG_union_type, or DW_TAG_enumeration_type DIE here.  But nothing
+        should be actually referencing those DIEs, as variable DIEs with that
+        type would be emitted already in the abstract origin, so it was always
+        removed during unused type prunning.  Don't add anything in this
+        case.  */
+      if (TYPE_DECL_IS_STUB (decl) && decl_ultimate_origin (decl) != NULL_TREE)
+       break;
 
-  /* Ignore blocks that are NULL.  */
-  if (stmt == NULL_TREE)
-    return;
+      if (is_redundant_typedef (decl))
+       gen_type_die (TREE_TYPE (decl), context_die);
+      else
+       /* Output a DIE to represent the typedef itself.  */
+       gen_typedef_die (decl, context_die);
+      break;
 
-  inlined_func = inlined_function_outer_scope_p (stmt);
+    case LABEL_DECL:
+      if (debug_info_level >= DINFO_LEVEL_NORMAL)
+       gen_label_die (decl, context_die);
+      break;
 
-  /* If the block is one fragment of a non-contiguous block, do not
-     process the variables, since they will have been done by the
-     origin block.  Do process subblocks.  */
-  if (BLOCK_FRAGMENT_ORIGIN (stmt))
-    {
-      tree sub;
+    case VAR_DECL:
+    case RESULT_DECL:
+      /* If we are in terse mode, don't generate any DIEs to represent any
+        variable declarations or definitions.  */
+      if (debug_info_level <= DINFO_LEVEL_TERSE)
+       break;
 
-      for (sub = BLOCK_SUBBLOCKS (stmt); sub; sub = BLOCK_CHAIN (sub))
-       gen_block_die (sub, context_die, depth + 1);
+      /* Output any DIEs that are needed to specify the type of this data
+        object.  */
+      if (decl_by_reference_p (decl_or_origin))
+       gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
+      else
+       gen_type_die (TREE_TYPE (decl_or_origin), context_die);
 
-      return;
-    }
+      /* And its containing type.  */
+      class_origin = decl_class_context (decl_or_origin);
+      if (class_origin != NULL_TREE)
+       gen_type_die_for_member (class_origin, decl_or_origin, context_die);
 
-  /* Determine if we need to output any Dwarf DIEs at all to represent this
-     block.  */
-  if (inlined_func)
-    /* The outer scopes for inlinings *must* always be represented.  We
-       generate DW_TAG_inlined_subroutine DIEs for them.  (See below.) */
-    must_output_die = 1;
-  else
-    {
-      /* Determine if this block directly contains any "significant"
-        local declarations which we will need to output DIEs for.  */
-      if (debug_info_level > DINFO_LEVEL_TERSE)
-       /* We are not in terse mode so *any* local declaration counts
-          as being a "significant" one.  */
-       must_output_die = ((BLOCK_VARS (stmt) != NULL
-                           || BLOCK_NUM_NONLOCALIZED_VARS (stmt))
-                          && (TREE_USED (stmt)
-                              || TREE_ASM_WRITTEN (stmt)
-                              || BLOCK_ABSTRACT (stmt)));
-      else if ((TREE_USED (stmt)
-               || TREE_ASM_WRITTEN (stmt)
-               || BLOCK_ABSTRACT (stmt))
-              && !dwarf2out_ignore_block (stmt))
-       must_output_die = 1;
-    }
+      /* And its containing namespace.  */
+      context_die = declare_in_namespace (decl_or_origin, context_die);
 
-  /* It would be a waste of space to generate a Dwarf DW_TAG_lexical_block
-     DIE for any block which contains no significant local declarations at
-     all.  Rather, in such cases we just call `decls_for_scope' so that any
-     needed Dwarf info for any sub-blocks will get properly generated. Note
-     that in terse mode, our definition of what constitutes a "significant"
-     local declaration gets restricted to include only inlined function
-     instances and local (nested) function definitions.  */
-  if (must_output_die)
-    {
-      if (inlined_func)
-       {
-         /* If STMT block is abstract, that means we have been called
-            indirectly from dwarf2out_abstract_function.
-            That function rightfully marks the descendent blocks (of
-            the abstract function it is dealing with) as being abstract,
-            precisely to prevent us from emitting any
-            DW_TAG_inlined_subroutine DIE as a descendent
-            of an abstract function instance. So in that case, we should
-            not call gen_inlined_subroutine_die.
+      /* Now output the DIE to represent the data object itself.  This gets
+        complicated because of the possibility that the VAR_DECL really
+        represents an inlined instance of a formal parameter for an inline
+        function.  */
+      ultimate_origin = decl_ultimate_origin (decl_or_origin);
+      if (ultimate_origin != NULL_TREE
+         && TREE_CODE (ultimate_origin) == PARM_DECL)
+       gen_formal_parameter_die (decl, origin,
+                                 true /* Emit name attribute.  */,
+                                 context_die);
+      else
+       gen_variable_die (decl, origin, context_die);
+      break;
 
-            Later though, when cgraph asks dwarf2out to emit info
-            for the concrete instance of the function decl into which
-            the concrete instance of STMT got inlined, the later will lead
-            to the generation of a DW_TAG_inlined_subroutine DIE.  */
-         if (! BLOCK_ABSTRACT (stmt))
-           gen_inlined_subroutine_die (stmt, context_die, depth);
+    case FIELD_DECL:
+      /* Ignore the nameless fields that are used to skip bits but handle C++
+        anonymous unions and structs.  */
+      if (DECL_NAME (decl) != NULL_TREE
+         || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
+         || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
+       {
+         gen_type_die (member_declared_type (decl), context_die);
+         gen_field_die (decl, context_die);
        }
+      break;
+
+    case PARM_DECL:
+      if (DECL_BY_REFERENCE (decl_or_origin))
+       gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
       else
-       gen_lexical_block_die (stmt, context_die, depth);
-    }
-  else
-    decls_for_scope (stmt, context_die, depth);
-}
+       gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+      return gen_formal_parameter_die (decl, origin,
+                                      true /* Emit name attribute.  */,
+                                      context_die);
 
-/* Process variable DECL (or variable with origin ORIGIN) within
-   block STMT and add it to CONTEXT_DIE.  */
-static void
-process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
-{
-  dw_die_ref die;
-  tree decl_or_origin = decl ? decl : origin;
+    case NAMESPACE_DECL:
+    case IMPORTED_DECL:
+      if (dwarf_version >= 3 || !dwarf_strict)
+       gen_namespace_die (decl, context_die);
+      break;
 
-  if (TREE_CODE (decl_or_origin) == FUNCTION_DECL)
-    die = lookup_decl_die (decl_or_origin);
-  else if (TREE_CODE (decl_or_origin) == TYPE_DECL
-           && TYPE_DECL_IS_STUB (decl_or_origin))
-    die = lookup_type_die (TREE_TYPE (decl_or_origin));
-  else
-    die = NULL;
+    default:
+      /* Probably some frontend-internal decl.  Assume we don't care.  */
+      gcc_assert ((int)TREE_CODE (decl) > NUM_TREE_CODES);
+      break;
+    }
 
-  if (die != NULL && die->die_parent == NULL)
-    add_child_die (context_die, die);
-  else if (TREE_CODE (decl_or_origin) == IMPORTED_DECL)
-    dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
-                                        stmt, context_die);
-  else
-    gen_decl_die (decl, origin, context_die);
+  return NULL;
 }
-
-/* Generate all of the decls declared within a given scope and (recursively)
-   all of its sub-blocks.  */
+\f
+/* Output debug information for global decl DECL.  Called from toplev.c after
+   compilation proper has finished.  */
 
 static void
-decls_for_scope (tree stmt, dw_die_ref context_die, int depth)
+dwarf2out_global_decl (tree decl)
 {
-  tree decl;
-  unsigned int i;
-  tree subblocks;
-
-  /* Ignore NULL blocks.  */
-  if (stmt == NULL_TREE)
-    return;
-
-  /* Output the DIEs to represent all of the data objects and typedefs
-     declared directly within this block but not within any nested
-     sub-blocks.  Also, nested function and tag DIEs have been
-     generated with a parent of NULL; fix that up now.  */
-  for (decl = BLOCK_VARS (stmt); decl != NULL; decl = TREE_CHAIN (decl))
-    process_scope_var (stmt, decl, NULL_TREE, context_die);
-  for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++)
-    process_scope_var (stmt, NULL, BLOCK_NONLOCALIZED_VAR (stmt, i),
-                      context_die);
-
-  /* If we're at -g1, we're not interested in subblocks.  */
-  if (debug_info_level <= DINFO_LEVEL_TERSE)
-    return;
-
-  /* Output the DIEs to represent all sub-blocks (and the items declared
-     therein) of this block.  */
-  for (subblocks = BLOCK_SUBBLOCKS (stmt);
-       subblocks != NULL;
-       subblocks = BLOCK_CHAIN (subblocks))
-    gen_block_die (subblocks, context_die, depth + 1);
+  /* Output DWARF2 information for file-scope tentative data object
+     declarations, file-scope (extern) function declarations (which
+     had no corresponding body) and file-scope tagged type declarations
+     and definitions which have not yet been forced out.  */
+  if (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
+    dwarf2out_decl (decl);
 }
 
-/* Is this a typedef we can avoid emitting?  */
-
-static inline int
-is_redundant_typedef (const_tree decl)
+/* Output debug information for type decl DECL.  Called from toplev.c
+   and from language front ends (to record built-in types).  */
+static void
+dwarf2out_type_decl (tree decl, int local)
 {
-  if (TYPE_DECL_IS_STUB (decl))
-    return 1;
-
-  if (DECL_ARTIFICIAL (decl)
-      && DECL_CONTEXT (decl)
-      && is_tagged_type (DECL_CONTEXT (decl))
-      && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL
-      && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))))
-    /* Also ignore the artificial member typedef for the class name.  */
-    return 1;
-
-  return 0;
+  if (!local)
+    dwarf2out_decl (decl);
 }
 
-/* Returns the DIE for a context.  */
-
-static inline dw_die_ref
-get_context_die (tree context)
+/* Output debug information for imported module or decl DECL.
+   NAME is non-NULL name in the lexical block if the decl has been renamed.
+   LEXICAL_BLOCK is the lexical block (which TREE_CODE is a BLOCK)
+   that DECL belongs to.
+   LEXICAL_BLOCK_DIE is the DIE of LEXICAL_BLOCK.  */
+static void
+dwarf2out_imported_module_or_decl_1 (tree decl,
+                                    tree name,
+                                    tree lexical_block,
+                                    dw_die_ref lexical_block_die)
 {
-  if (context)
+  expanded_location xloc;
+  dw_die_ref imported_die = NULL;
+  dw_die_ref at_import_die;
+
+  if (TREE_CODE (decl) == IMPORTED_DECL)
     {
-      /* Find die that represents this context.  */
-      if (TYPE_P (context))
-       return force_type_die (TYPE_MAIN_VARIANT (context));
-      else
-       return force_decl_die (context);
+      xloc = expand_location (DECL_SOURCE_LOCATION (decl));
+      decl = IMPORTED_DECL_ASSOCIATED_DECL (decl);
+      gcc_assert (decl);
     }
-  return comp_unit_die;
-}
-
-/* Returns the DIE for decl.  A DIE will always be returned.  */
+  else
+    xloc = expand_location (input_location);
 
-static dw_die_ref
-force_decl_die (tree decl)
-{
-  dw_die_ref decl_die;
-  unsigned saved_external_flag;
-  tree save_fn = NULL_TREE;
-  decl_die = lookup_decl_die (decl);
-  if (!decl_die)
+  if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
     {
-      dw_die_ref context_die = get_context_die (DECL_CONTEXT (decl));
-
-      decl_die = lookup_decl_die (decl);
-      if (decl_die)
-       return decl_die;
-
-      switch (TREE_CODE (decl))
+      at_import_die = force_type_die (TREE_TYPE (decl));
+      /* For namespace N { typedef void T; } using N::T; base_type_die
+        returns NULL, but DW_TAG_imported_declaration requires
+        the DW_AT_import tag.  Force creation of DW_TAG_typedef.  */
+      if (!at_import_die)
        {
-       case FUNCTION_DECL:
-         /* Clear current_function_decl, so that gen_subprogram_die thinks
-            that this is a declaration. At this point, we just want to force
-            declaration die.  */
-         save_fn = current_function_decl;
-         current_function_decl = NULL_TREE;
-         gen_subprogram_die (decl, context_die);
-         current_function_decl = save_fn;
-         break;
-
-       case VAR_DECL:
-         /* Set external flag to force declaration die. Restore it after
-          gen_decl_die() call.  */
-         saved_external_flag = DECL_EXTERNAL (decl);
-         DECL_EXTERNAL (decl) = 1;
-         gen_decl_die (decl, NULL, context_die);
-         DECL_EXTERNAL (decl) = saved_external_flag;
-         break;
-
-       case NAMESPACE_DECL:
-         if (dwarf_version >= 3 || !dwarf_strict)
-           dwarf2out_decl (decl);
-         else
-           /* DWARF2 has neither DW_TAG_module, nor DW_TAG_namespace.  */
-           decl_die = comp_unit_die;
-         break;
-
-       default:
-         gcc_unreachable ();
+         gcc_assert (TREE_CODE (decl) == TYPE_DECL);
+         gen_typedef_die (decl, get_context_die (DECL_CONTEXT (decl)));
+         at_import_die = lookup_type_die (TREE_TYPE (decl));
+         gcc_assert (at_import_die);
        }
-
-      /* We should be able to find the DIE now.  */
-      if (!decl_die)
-       decl_die = lookup_decl_die (decl);
-      gcc_assert (decl_die);
     }
+  else
+    {
+      at_import_die = lookup_decl_die (decl);
+      if (!at_import_die)
+       {
+         /* If we're trying to avoid duplicate debug info, we may not have
+            emitted the member decl for this field.  Emit it now.  */
+         if (TREE_CODE (decl) == FIELD_DECL)
+           {
+             tree type = DECL_CONTEXT (decl);
 
-  return decl_die;
-}
-
-/* Returns the DIE for TYPE, that must not be a base type.  A DIE is
-   always returned.  */
-
-static dw_die_ref
-force_type_die (tree type)
-{
-  dw_die_ref type_die;
+             if (TYPE_CONTEXT (type)
+                 && TYPE_P (TYPE_CONTEXT (type))
+                 && !should_emit_struct_debug (TYPE_CONTEXT (type),
+                                               DINFO_USAGE_DIR_USE))
+               return;
+             gen_type_die_for_member (type, decl,
+                                      get_context_die (TYPE_CONTEXT (type)));
+           }
+         at_import_die = force_decl_die (decl);
+       }
+    }
 
-  type_die = lookup_type_die (type);
-  if (!type_die)
+  if (TREE_CODE (decl) == NAMESPACE_DECL)
     {
-      dw_die_ref context_die = get_context_die (TYPE_CONTEXT (type));
-
-      type_die = modified_type_die (type, TYPE_READONLY (type),
-                                   TYPE_VOLATILE (type), context_die);
-      gcc_assert (type_die);
+      if (dwarf_version >= 3 || !dwarf_strict)
+       imported_die = new_die (DW_TAG_imported_module,
+                               lexical_block_die,
+                               lexical_block);
+      else
+       return;
     }
-  return type_die;
+  else
+    imported_die = new_die (DW_TAG_imported_declaration,
+                           lexical_block_die,
+                           lexical_block);
+
+  add_AT_file (imported_die, DW_AT_decl_file, lookup_filename (xloc.file));
+  add_AT_unsigned (imported_die, DW_AT_decl_line, xloc.line);
+  if (name)
+    add_AT_string (imported_die, DW_AT_name,
+                  IDENTIFIER_POINTER (name));
+  add_AT_die_ref (imported_die, DW_AT_import, at_import_die);
 }
 
-/* Force out any required namespaces to be able to output DECL,
-   and return the new context_die for it, if it's changed.  */
+/* Output debug information for imported module or decl DECL.
+   NAME is non-NULL name in context if the decl has been renamed.
+   CHILD is true if decl is one of the renamed decls as part of
+   importing whole module.  */
 
-static dw_die_ref
-setup_namespace_context (tree thing, dw_die_ref context_die)
+static void
+dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
+                                  bool child)
 {
-  tree context = (DECL_P (thing)
-                 ? DECL_CONTEXT (thing) : TYPE_CONTEXT (thing));
-  if (context && TREE_CODE (context) == NAMESPACE_DECL)
-    /* Force out the namespace.  */
-    context_die = force_decl_die (context);
-
-  return context_die;
-}
+  /* dw_die_ref at_import_die;  */
+  dw_die_ref scope_die;
 
-/* Emit a declaration DIE for THING (which is either a DECL or a tagged
-   type) within its namespace, if appropriate.
+  if (debug_info_level <= DINFO_LEVEL_TERSE)
+    return;
 
-   For compatibility with older debuggers, namespace DIEs only contain
-   declarations; all definitions are emitted at CU scope.  */
+  gcc_assert (decl);
 
-static dw_die_ref
-declare_in_namespace (tree thing, dw_die_ref context_die)
-{
-  dw_die_ref ns_context;
+  /* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs.
+     We need decl DIE for reference and scope die. First, get DIE for the decl
+     itself.  */
 
-  if (debug_info_level <= DINFO_LEVEL_TERSE)
-    return context_die;
+  /* Get the scope die for decl context. Use comp_unit_die for global module
+     or decl. If die is not found for non globals, force new die.  */
+  if (context
+      && TYPE_P (context)
+      && !should_emit_struct_debug (context, DINFO_USAGE_DIR_USE))
+    return;
 
-  /* If this decl is from an inlined function, then don't try to emit it in its
-     namespace, as we will get confused.  It would have already been emitted
-     when the abstract instance of the inline function was emitted anyways.  */
-  if (DECL_P (thing) && DECL_ABSTRACT_ORIGIN (thing))
-    return context_die;
+  if (!(dwarf_version >= 3 || !dwarf_strict))
+    return;
 
-  ns_context = setup_namespace_context (thing, context_die);
+  scope_die = get_context_die (context);
 
-  if (ns_context != context_die)
+  if (child)
     {
-      if (is_fortran ())
-       return ns_context;
-      if (DECL_P (thing))
-       gen_decl_die (thing, NULL, ns_context);
-      else
-       gen_type_die (thing, ns_context);
+      gcc_assert (scope_die->die_child);
+      gcc_assert (scope_die->die_child->die_tag == DW_TAG_imported_module);
+      gcc_assert (TREE_CODE (decl) != NAMESPACE_DECL);
+      scope_die = scope_die->die_child;
     }
-  return context_die;
+
+  /* OK, now we have DIEs for decl as well as scope. Emit imported die.  */
+  dwarf2out_imported_module_or_decl_1 (decl, name, context, scope_die);
+
 }
 
-/* Generate a DIE for a namespace or namespace alias.  */
+/* Write the debugging output for DECL.  */
 
-static void
-gen_namespace_die (tree decl, dw_die_ref context_die)
+void
+dwarf2out_decl (tree decl)
 {
-  dw_die_ref namespace_die;
+  dw_die_ref context_die = comp_unit_die ();
 
-  /* Namespace aliases have a DECL_ABSTRACT_ORIGIN of the namespace
-     they are an alias of.  */
-  if (DECL_ABSTRACT_ORIGIN (decl) == NULL)
-    {
-      /* Output a real namespace or module.  */
-      context_die = setup_namespace_context (decl, comp_unit_die);
-      namespace_die = new_die (is_fortran ()
-                              ? DW_TAG_module : DW_TAG_namespace,
-                              context_die, decl);
-      /* For Fortran modules defined in different CU don't add src coords.  */
-      if (namespace_die->die_tag == DW_TAG_module && DECL_EXTERNAL (decl))
-       {
-         const char *name = dwarf2_name (decl, 0);
-         if (name)
-           add_name_attribute (namespace_die, name);
-       }
-      else
-       add_name_and_src_coords_attributes (namespace_die, decl);
-      if (DECL_EXTERNAL (decl))
-       add_AT_flag (namespace_die, DW_AT_declaration, 1);
-      equate_decl_number_to_die (decl, namespace_die);
-    }
-  else
+  switch (TREE_CODE (decl))
     {
-      /* Output a namespace alias.  */
+    case ERROR_MARK:
+      return;
 
-      /* Force out the namespace we are an alias of, if necessary.  */
-      dw_die_ref origin_die
-       = force_decl_die (DECL_ABSTRACT_ORIGIN (decl));
+    case FUNCTION_DECL:
+      /* What we would really like to do here is to filter out all mere
+        file-scope declarations of file-scope functions which are never
+        referenced later within this translation unit (and keep all of ones
+        that *are* referenced later on) but we aren't clairvoyant, so we have
+        no idea which functions will be referenced in the future (i.e. later
+        on within the current translation unit). So here we just ignore all
+        file-scope function declarations which are not also definitions.  If
+        and when the debugger needs to know something about these functions,
+        it will have to hunt around and find the DWARF information associated
+        with the definition of the function.
 
-      if (DECL_CONTEXT (decl) == NULL_TREE
-         || TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL)
-       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);
-      add_AT_die_ref (namespace_die, DW_AT_import, origin_die);
-      equate_decl_number_to_die (decl, namespace_die);
-    }
-}
+        We can't just check DECL_EXTERNAL to find out which FUNCTION_DECL
+        nodes represent definitions and which ones represent mere
+        declarations.  We have to check DECL_INITIAL instead. That's because
+        the C front-end supports some weird semantics for "extern inline"
+        function definitions.  These can get inlined within the current
+        translation unit (and thus, we need to generate Dwarf info for their
+        abstract instances so that the Dwarf info for the concrete inlined
+        instances can have something to refer to) but the compiler never
+        generates any out-of-lines instances of such things (despite the fact
+        that they *are* definitions).
 
-/* Generate Dwarf debug information for a decl described by DECL.  */
+        The important point is that the C front-end marks these "extern
+        inline" functions as DECL_EXTERNAL, but we need to generate DWARF for
+        them anyway. Note that the C++ front-end also plays some similar games
+        for inline function definitions appearing within include files which
+        also contain `#pragma interface' pragmas.  */
+      if (DECL_INITIAL (decl) == NULL_TREE)
+       return;
 
-static void
-gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
-{
-  tree decl_or_origin = decl ? decl : origin;
-  tree class_origin = NULL, ultimate_origin;
+      /* If we're a nested function, initially use a parent of NULL; if we're
+        a plain function, this will be fixed up in decls_for_scope.  If
+        we're a method, it will be ignored, since we already have a DIE.  */
+      if (decl_function_context (decl)
+         /* But if we're in terse mode, we don't care about scope.  */
+         && debug_info_level > DINFO_LEVEL_TERSE)
+       context_die = NULL;
+      break;
 
-  if (DECL_P (decl_or_origin) && DECL_IGNORED_P (decl_or_origin))
-    return;
+    case VAR_DECL:
+      /* Ignore this VAR_DECL if it refers to a file-scope extern data object
+        declaration and if the declaration was never even referenced from
+        within this entire compilation unit.  We suppress these DIEs in
+        order to save space in the .debug section (by eliminating entries
+        which are probably useless).  Note that we must not suppress
+        block-local extern declarations (whether used or not) because that
+        would screw-up the debugger's name lookup mechanism and cause it to
+        miss things which really ought to be in scope at a given point.  */
+      if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
+       return;
 
-  switch (TREE_CODE (decl_or_origin))
-    {
-    case ERROR_MARK:
+      /* For local statics lookup proper context die.  */
+      if (TREE_STATIC (decl) && decl_function_context (decl))
+       context_die = lookup_decl_die (DECL_CONTEXT (decl));
+
+      /* If we are in terse mode, don't generate any DIEs to represent any
+        variable declarations or definitions.  */
+      if (debug_info_level <= DINFO_LEVEL_TERSE)
+       return;
       break;
 
     case CONST_DECL:
-      if (!is_fortran ())
-       {
-         /* The individual enumerators of an enum type get output when we output
-            the Dwarf representation of the relevant enum type itself.  */
-         break;
-       }
+      if (debug_info_level <= DINFO_LEVEL_TERSE)
+       return;
+      if (!is_fortran () && !is_ada ())
+       return;
+      if (TREE_STATIC (decl) && decl_function_context (decl))
+       context_die = lookup_decl_die (DECL_CONTEXT (decl));
+      break;
 
-      /* Emit its type.  */
-      gen_type_die (TREE_TYPE (decl), context_die);
+    case NAMESPACE_DECL:
+    case IMPORTED_DECL:
+      if (debug_info_level <= DINFO_LEVEL_TERSE)
+       return;
+      if (lookup_decl_die (decl) != NULL)
+       return;
+      break;
 
-      /* And its containing namespace.  */
-      context_die = declare_in_namespace (decl, context_die);
+    case TYPE_DECL:
+      /* Don't emit stubs for types unless they are needed by other DIEs.  */
+      if (TYPE_DECL_SUPPRESS_DEBUG (decl))
+       return;
+
+      /* 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))
+       return;
+
+      /* If we are in terse mode, don't generate any DIEs for types.  */
+      if (debug_info_level <= DINFO_LEVEL_TERSE)
+       return;
+
+      /* If we're a function-scope tag, initially use a parent of NULL;
+        this will be fixed up in decls_for_scope.  */
+      if (decl_function_context (decl))
+       context_die = NULL;
 
-      gen_const_die (decl, context_die);
       break;
 
-    case FUNCTION_DECL:
-      /* 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
-         && (current_function_decl == NULL_TREE
-             || DECL_ARTIFICIAL (decl_or_origin)))
-       break;
+    default:
+      return;
+    }
+
+  gen_decl_die (decl, NULL, context_die);
+}
+
+/* Write the debugging output for DECL.  */
+
+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
+   a lexical block.  */
+
+static void
+dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
+                      unsigned int blocknum)
+{
+  switch_to_section (current_function_section ());
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
+}
 
-#if 0
-      /* FIXME */
-      /* This doesn't work because the C frontend sets DECL_ABSTRACT_ORIGIN
-        on local redeclarations of global functions.  That seems broken.  */
-      if (current_function_decl != decl)
-       /* This is only a declaration.  */;
-#endif
+/* Output a marker (i.e. a label) for the end of the generated code for a
+   lexical block.  */
 
-      /* If we're emitting a clone, emit info for the abstract instance.  */
-      if (origin || DECL_ORIGIN (decl) != decl)
-       dwarf2out_abstract_function (origin
-                                    ? DECL_ORIGIN (origin)
-                                    : DECL_ABSTRACT_ORIGIN (decl));
+static void
+dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
+{
+  switch_to_section (current_function_section ());
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
+}
 
-      /* If we're emitting an out-of-line copy of an inline function,
-        emit info for the abstract instance and set up to refer to it.  */
-      else if (cgraph_function_possibly_inlined_p (decl)
-              && ! DECL_ABSTRACT (decl)
-              && ! class_or_namespace_scope_p (context_die)
-              /* dwarf2out_abstract_function won't emit a die if this is just
-                 a declaration.  We must avoid setting DECL_ABSTRACT_ORIGIN in
-                 that case, because that works only if we have a die.  */
-              && DECL_INITIAL (decl) != NULL_TREE)
-       {
-         dwarf2out_abstract_function (decl);
-         set_decl_origin_self (decl);
-       }
+/* Returns nonzero if it is appropriate not to emit any debugging
+   information for BLOCK, because it doesn't contain any instructions.
 
-      /* Otherwise we're emitting the primary DIE for this decl.  */
-      else if (debug_info_level > DINFO_LEVEL_TERSE)
-       {
-         /* Before we describe the FUNCTION_DECL itself, make sure that we
-            have described its return type.  */
-         gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die);
+   Don't allow this for blocks with nested functions or local classes
+   as we would end up with orphans, and in the presence of scheduling
+   we may end up calling them anyway.  */
 
-         /* And its virtual context.  */
-         if (DECL_VINDEX (decl) != NULL_TREE)
-           gen_type_die (DECL_CONTEXT (decl), context_die);
+static bool
+dwarf2out_ignore_block (const_tree block)
+{
+  tree decl;
+  unsigned int i;
 
-         /* And its containing type.  */
-         if (!origin)
-           origin = decl_class_context (decl);
-         if (origin != NULL_TREE)
-           gen_type_die_for_member (origin, decl, context_die);
+  for (decl = BLOCK_VARS (block); decl; decl = DECL_CHAIN (decl))
+    if (TREE_CODE (decl) == FUNCTION_DECL
+       || (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)))
+      return 0;
+  for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (block); i++)
+    {
+      decl = BLOCK_NONLOCALIZED_VAR (block, i);
+      if (TREE_CODE (decl) == FUNCTION_DECL
+         || (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)))
+      return 0;
+    }
 
-         /* And its containing namespace.  */
-         context_die = declare_in_namespace (decl, context_die);
-       }
+  return 1;
+}
 
-      /* Now output a DIE to represent the function itself.  */
-      if (decl)
-        gen_subprogram_die (decl, context_die);
-      break;
+/* Hash table routines for file_hash.  */
 
-    case TYPE_DECL:
-      /* If we are in terse mode, don't generate any DIEs to represent any
-        actual typedefs.  */
-      if (debug_info_level <= DINFO_LEVEL_TERSE)
-       break;
+static int
+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 filename_cmp (p1->filename, p2) == 0;
+}
 
-      /* In the special case of a TYPE_DECL node representing the declaration
-        of some type tag, if the given TYPE_DECL is marked as having been
-        instantiated from some other (original) TYPE_DECL node (e.g. one which
-        was generated within the original definition of an inline function) we
-        used to generate a special (abbreviated) DW_TAG_structure_type,
-        DW_TAG_union_type, or DW_TAG_enumeration_type DIE here.  But nothing
-        should be actually referencing those DIEs, as variable DIEs with that
-        type would be emitted already in the abstract origin, so it was always
-        removed during unused type prunning.  Don't add anything in this
-        case.  */
-      if (TYPE_DECL_IS_STUB (decl) && decl_ultimate_origin (decl) != NULL_TREE)
-       break;
+static hashval_t
+file_table_hash (const void *p_p)
+{
+  const struct dwarf_file_data *const p = (const struct dwarf_file_data *) p_p;
+  return htab_hash_string (p->filename);
+}
 
-      if (is_redundant_typedef (decl))
-       gen_type_die (TREE_TYPE (decl), context_die);
-      else
-       /* Output a DIE to represent the typedef itself.  */
-       gen_typedef_die (decl, context_die);
-      break;
+/* Lookup FILE_NAME (in the list of filenames that we know about here in
+   dwarf2out.c) and return its "index".  The index of each (known) filename is
+   just a unique number which is associated with only that one filename.  We
+   need such numbers for the sake of generating labels (in the .debug_sfnames
+   section) and references to those files numbers (in the .debug_srcinfo
+   and.debug_macinfo sections).  If the filename given as an argument is not
+   found in our current list, add it to the list and assign it the next
+   available unique index number.  In order to speed up searches, we remember
+   the index of the filename was looked up last.  This handles the majority of
+   all searches.  */
 
-    case LABEL_DECL:
-      if (debug_info_level >= DINFO_LEVEL_NORMAL)
-       gen_label_die (decl, context_die);
-      break;
+static struct dwarf_file_data *
+lookup_filename (const char *file_name)
+{
+  void ** slot;
+  struct dwarf_file_data * created;
 
-    case VAR_DECL:
-    case RESULT_DECL:
-      /* If we are in terse mode, don't generate any DIEs to represent any
-        variable declarations or definitions.  */
-      if (debug_info_level <= DINFO_LEVEL_TERSE)
-       break;
+  /* Check to see if the file name that was searched on the previous
+     call matches this file name.  If so, return the index.  */
+  if (file_table_last_lookup
+      && (file_name == file_table_last_lookup->filename
+         || filename_cmp (file_table_last_lookup->filename, file_name) == 0))
+    return file_table_last_lookup;
 
-      /* Output any DIEs that are needed to specify the type of this data
-        object.  */
-      if (decl_by_reference_p (decl_or_origin))
-       gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
-      else
-       gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+  /* Didn't match the previous lookup, search the table.  */
+  slot = htab_find_slot_with_hash (file_table, file_name,
+                                  htab_hash_string (file_name), INSERT);
+  if (*slot)
+    return (struct dwarf_file_data *) *slot;
 
-      /* And its containing type.  */
-      class_origin = decl_class_context (decl_or_origin);
-      if (class_origin != NULL_TREE)
-       gen_type_die_for_member (class_origin, decl_or_origin, context_die);
+  created = ggc_alloc_dwarf_file_data ();
+  created->filename = file_name;
+  created->emitted_number = 0;
+  *slot = created;
+  return created;
+}
 
-      /* And its containing namespace.  */
-      context_die = declare_in_namespace (decl_or_origin, context_die);
+/* If the assembler will construct the file table, then translate the compiler
+   internal file table number into the assembler file table number, and emit
+   a .file directive if we haven't already emitted one yet.  The file table
+   numbers are different because we prune debug info for unused variables and
+   types, which may include filenames.  */
 
-      /* Now output the DIE to represent the data object itself.  This gets
-        complicated because of the possibility that the VAR_DECL really
-        represents an inlined instance of a formal parameter for an inline
-        function.  */
-      ultimate_origin = decl_ultimate_origin (decl_or_origin);
-      if (ultimate_origin != NULL_TREE
-         && TREE_CODE (ultimate_origin) == PARM_DECL)
-       gen_formal_parameter_die (decl, origin,
-                                 true /* Emit name attribute.  */,
-                                 context_die);
+static int
+maybe_emit_file (struct dwarf_file_data * fd)
+{
+  if (! fd->emitted_number)
+    {
+      if (last_emitted_file)
+       fd->emitted_number = last_emitted_file->emitted_number + 1;
       else
-       gen_variable_die (decl, origin, context_die);
-      break;
+       fd->emitted_number = 1;
+      last_emitted_file = fd;
 
-    case FIELD_DECL:
-      /* Ignore the nameless fields that are used to skip bits but handle C++
-        anonymous unions and structs.  */
-      if (DECL_NAME (decl) != NULL_TREE
-         || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
-         || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
+      if (DWARF2_ASM_LINE_DEBUG_INFO)
        {
-         gen_type_die (member_declared_type (decl), context_die);
-         gen_field_die (decl, context_die);
+         fprintf (asm_out_file, "\t.file %u ", fd->emitted_number);
+         output_quoted_string (asm_out_file,
+                               remap_debug_filename (fd->filename));
+         fputc ('\n', asm_out_file);
        }
-      break;
-
-    case PARM_DECL:
-      if (DECL_BY_REFERENCE (decl_or_origin))
-       gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
-      else
-       gen_type_die (TREE_TYPE (decl_or_origin), context_die);
-      gen_formal_parameter_die (decl, origin,
-                               true /* Emit name attribute.  */,
-                               context_die);
-      break;
-
-    case NAMESPACE_DECL:
-    case IMPORTED_DECL:
-      if (dwarf_version >= 3 || !dwarf_strict)
-       gen_namespace_die (decl, context_die);
-      break;
-
-    default:
-      /* Probably some frontend-internal decl.  Assume we don't care.  */
-      gcc_assert ((int)TREE_CODE (decl) > NUM_TREE_CODES);
-      break;
     }
+
+  return fd->emitted_number;
 }
-\f
-/* Output debug information for global decl DECL.  Called from toplev.c after
-   compilation proper has finished.  */
+
+/* Schedule generation of a DW_AT_const_value attribute to DIE.
+   That generation should happen after function debug info has been
+   generated. The value of the attribute is the constant value of ARG.  */
 
 static void
-dwarf2out_global_decl (tree decl)
+append_entry_to_tmpl_value_parm_die_table (dw_die_ref die, tree arg)
 {
-  /* Output DWARF2 information for file-scope tentative data object
-     declarations, file-scope (extern) function declarations (which
-     had no corresponding body) and file-scope tagged type declarations
-     and definitions which have not yet been forced out.  */
-  if (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
-    dwarf2out_decl (decl);
+  die_arg_entry entry;
+
+  if (!die || !arg)
+    return;
+
+  if (!tmpl_value_parm_die_table)
+    tmpl_value_parm_die_table
+      = VEC_alloc (die_arg_entry, gc, 32);
+
+  entry.die = die;
+  entry.arg = arg;
+  VEC_safe_push (die_arg_entry, gc,
+                tmpl_value_parm_die_table,
+                &entry);
 }
 
-/* Output debug information for type decl DECL.  Called from toplev.c
-   and from language front ends (to record built-in types).  */
-static void
-dwarf2out_type_decl (tree decl, int local)
+/* Return TRUE if T is an instance of generic type, FALSE
+   otherwise.  */
+
+static bool
+generic_type_p (tree t)
 {
-  if (!local)
-    dwarf2out_decl (decl);
+  if (t == NULL_TREE || !TYPE_P (t))
+    return false;
+  return lang_hooks.get_innermost_generic_parms (t) != NULL_TREE;
 }
 
-/* Output debug information for imported module or decl DECL.
-   NAME is non-NULL name in the lexical block if the decl has been renamed.
-   LEXICAL_BLOCK is the lexical block (which TREE_CODE is a BLOCK)
-   that DECL belongs to.
-   LEXICAL_BLOCK_DIE is the DIE of LEXICAL_BLOCK.  */
+/* 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
-dwarf2out_imported_module_or_decl_1 (tree decl,
-                                    tree name,
-                                    tree lexical_block,
-                                    dw_die_ref lexical_block_die)
+schedule_generic_params_dies_gen (tree t)
 {
-  expanded_location xloc;
-  dw_die_ref imported_die = NULL;
-  dw_die_ref at_import_die;
+  if (!generic_type_p (t))
+    return;
 
-  if (TREE_CODE (decl) == IMPORTED_DECL)
-    {
-      xloc = expand_location (DECL_SOURCE_LOCATION (decl));
-      decl = IMPORTED_DECL_ASSOCIATED_DECL (decl);
-      gcc_assert (decl);
-    }
-  else
-    xloc = expand_location (input_location);
+  if (generic_type_instances == NULL)
+    generic_type_instances = VEC_alloc (tree, gc, 256);
 
-  if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
-    {
-      at_import_die = force_type_die (TREE_TYPE (decl));
-      /* For namespace N { typedef void T; } using N::T; base_type_die
-        returns NULL, but DW_TAG_imported_declaration requires
-        the DW_AT_import tag.  Force creation of DW_TAG_typedef.  */
-      if (!at_import_die)
-       {
-         gcc_assert (TREE_CODE (decl) == TYPE_DECL);
-         gen_typedef_die (decl, get_context_die (DECL_CONTEXT (decl)));
-         at_import_die = lookup_type_die (TREE_TYPE (decl));
-         gcc_assert (at_import_die);
-       }
-    }
-  else
-    {
-      at_import_die = lookup_decl_die (decl);
-      if (!at_import_die)
-       {
-         /* If we're trying to avoid duplicate debug info, we may not have
-            emitted the member decl for this field.  Emit it now.  */
-         if (TREE_CODE (decl) == FIELD_DECL)
-           {
-             tree type = DECL_CONTEXT (decl);
+  VEC_safe_push (tree, gc, generic_type_instances, t);
+}
 
-             if (TYPE_CONTEXT (type)
-                 && TYPE_P (TYPE_CONTEXT (type))
-                 && !should_emit_struct_debug (TYPE_CONTEXT (type),
-                                               DINFO_USAGE_DIR_USE))
-               return;
-             gen_type_die_for_member (type, decl,
-                                      get_context_die (TYPE_CONTEXT (type)));
-           }
-         at_import_die = force_decl_die (decl);
-       }
-    }
+/* 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.  */
 
-  if (TREE_CODE (decl) == NAMESPACE_DECL)
+static void
+gen_remaining_tmpl_value_param_die_attribute (void)
+{
+  if (tmpl_value_parm_die_table)
     {
-      if (dwarf_version >= 3 || !dwarf_strict)
-       imported_die = new_die (DW_TAG_imported_module,
-                               lexical_block_die,
-                               lexical_block);
-      else
-       return;
-    }
-  else
-    imported_die = new_die (DW_TAG_imported_declaration,
-                           lexical_block_die,
-                           lexical_block);
+      unsigned i;
+      die_arg_entry *e;
 
-  add_AT_file (imported_die, DW_AT_decl_file, lookup_filename (xloc.file));
-  add_AT_unsigned (imported_die, DW_AT_decl_line, xloc.line);
-  if (name)
-    add_AT_string (imported_die, DW_AT_name,
-                  IDENTIFIER_POINTER (name));
-  add_AT_die_ref (imported_die, DW_AT_import, at_import_die);
+      FOR_EACH_VEC_ELT (die_arg_entry, tmpl_value_parm_die_table, i, e)
+       tree_add_const_value_attribute (e->die, e->arg);
+    }
 }
 
-/* Output debug information for imported module or decl DECL.
-   NAME is non-NULL name in context if the decl has been renamed.
-   CHILD is true if decl is one of the renamed decls as part of
-   importing whole module.  */
+/* 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
-dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
-                                  bool child)
+gen_scheduled_generic_parms_dies (void)
 {
-  /* dw_die_ref at_import_die;  */
-  dw_die_ref scope_die;
+  unsigned i;
+  tree t;
 
-  if (debug_info_level <= DINFO_LEVEL_TERSE)
+  if (generic_type_instances == NULL)
     return;
+  
+  FOR_EACH_VEC_ELT (tree, generic_type_instances, i, t)
+    gen_generic_params_dies (t);
+}
 
-  gcc_assert (decl);
 
-  /* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs.
-     We need decl DIE for reference and scope die. First, get DIE for the decl
-     itself.  */
+/* Replace DW_AT_name for the decl with name.  */
 
-  /* Get the scope die for decl context. Use comp_unit_die for global module
-     or decl. If die is not found for non globals, force new die.  */
-  if (context
-      && TYPE_P (context)
-      && !should_emit_struct_debug (context, DINFO_USAGE_DIR_USE))
-    return;
+static void
+dwarf2out_set_name (tree decl, tree name)
+{
+  dw_die_ref die;
+  dw_attr_ref attr;
+  const char *dname;
 
-  if (!(dwarf_version >= 3 || !dwarf_strict))
+  die = TYPE_SYMTAB_DIE (decl);
+  if (!die)
     return;
 
-  scope_die = get_context_die (context);
+  dname = dwarf2_name (name, 0);
+  if (!dname)
+    return;
 
-  if (child)
+  attr = get_AT (die, DW_AT_name);
+  if (attr)
     {
-      gcc_assert (scope_die->die_child);
-      gcc_assert (scope_die->die_child->die_tag == DW_TAG_imported_module);
-      gcc_assert (TREE_CODE (decl) != NAMESPACE_DECL);
-      scope_die = scope_die->die_child;
-    }
+      struct indirect_string_node *node;
 
-  /* OK, now we have DIEs for decl as well as scope. Emit imported die.  */
-  dwarf2out_imported_module_or_decl_1 (decl, name, context, scope_die);
+      node = find_AT_string (dname);
+      /* replace the string.  */
+      attr->dw_attr_val.v.val_str = node;
+    }
 
+  else
+    add_name_attribute (die, dname);
 }
 
-/* Write the debugging output for DECL.  */
+/* 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.  */
 
-void
-dwarf2out_decl (tree decl)
+static void
+dwarf2out_var_location (rtx loc_note)
 {
-  dw_die_ref context_die = comp_unit_die;
+  char loclabel[MAX_ARTIFICIAL_LABEL_BYTES + 2];
+  struct var_loc_node *newloc;
+  rtx next_real, next_note;
+  static const char *last_label;
+  static const char *last_postcall_label;
+  static bool last_in_cold_section_p;
+  static rtx expected_next_loc_note;
+  tree decl;
+  bool var_loc_p;
 
-  switch (TREE_CODE (decl))
+  if (!NOTE_P (loc_note))
     {
-    case ERROR_MARK:
+      if (CALL_P (loc_note))
+       {
+         call_site_count++;
+         if (SIBLING_CALL_P (loc_note))
+           tail_call_site_count++;
+       }
       return;
+    }
 
-    case FUNCTION_DECL:
-      /* What we would really like to do here is to filter out all mere
-        file-scope declarations of file-scope functions which are never
-        referenced later within this translation unit (and keep all of ones
-        that *are* referenced later on) but we aren't clairvoyant, so we have
-        no idea which functions will be referenced in the future (i.e. later
-        on within the current translation unit). So here we just ignore all
-        file-scope function declarations which are not also definitions.  If
-        and when the debugger needs to know something about these functions,
-        it will have to hunt around and find the DWARF information associated
-        with the definition of the function.
-
-        We can't just check DECL_EXTERNAL to find out which FUNCTION_DECL
-        nodes represent definitions and which ones represent mere
-        declarations.  We have to check DECL_INITIAL instead. That's because
-        the C front-end supports some weird semantics for "extern inline"
-        function definitions.  These can get inlined within the current
-        translation unit (and thus, we need to generate Dwarf info for their
-        abstract instances so that the Dwarf info for the concrete inlined
-        instances can have something to refer to) but the compiler never
-        generates any out-of-lines instances of such things (despite the fact
-        that they *are* definitions).
-
-        The important point is that the C front-end marks these "extern
-        inline" functions as DECL_EXTERNAL, but we need to generate DWARF for
-        them anyway. Note that the C++ front-end also plays some similar games
-        for inline function definitions appearing within include files which
-        also contain `#pragma interface' pragmas.  */
-      if (DECL_INITIAL (decl) == NULL_TREE)
-       return;
-
-      /* If we're a nested function, initially use a parent of NULL; if we're
-        a plain function, this will be fixed up in decls_for_scope.  If
-        we're a method, it will be ignored, since we already have a DIE.  */
-      if (decl_function_context (decl)
-         /* But if we're in terse mode, we don't care about scope.  */
-         && debug_info_level > DINFO_LEVEL_TERSE)
-       context_die = NULL;
-      break;
-
-    case VAR_DECL:
-      /* Ignore this VAR_DECL if it refers to a file-scope extern data object
-        declaration and if the declaration was never even referenced from
-        within this entire compilation unit.  We suppress these DIEs in
-        order to save space in the .debug section (by eliminating entries
-        which are probably useless).  Note that we must not suppress
-        block-local extern declarations (whether used or not) because that
-        would screw-up the debugger's name lookup mechanism and cause it to
-        miss things which really ought to be in scope at a given point.  */
-      if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
-       return;
+  var_loc_p = NOTE_KIND (loc_note) == NOTE_INSN_VAR_LOCATION;
+  if (var_loc_p && !DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
+    return;
 
-      /* For local statics lookup proper context die.  */
-      if (TREE_STATIC (decl) && decl_function_context (decl))
-       context_die = lookup_decl_die (DECL_CONTEXT (decl));
+  /* Optimize processing a large consecutive sequence of location
+     notes so we don't spend too much time in next_real_insn.  If the
+     next insn is another location note, remember the next_real_insn
+     calculation for next time.  */
+  next_real = cached_next_real_insn;
+  if (next_real)
+    {
+      if (expected_next_loc_note != loc_note)
+       next_real = NULL_RTX;
+    }
 
-      /* If we are in terse mode, don't generate any DIEs to represent any
-        variable declarations or definitions.  */
-      if (debug_info_level <= DINFO_LEVEL_TERSE)
-       return;
-      break;
+  next_note = NEXT_INSN (loc_note);
+  if (! next_note
+      || INSN_DELETED_P (next_note)
+      || GET_CODE (next_note) != NOTE
+      || (NOTE_KIND (next_note) != NOTE_INSN_VAR_LOCATION
+         && NOTE_KIND (next_note) != NOTE_INSN_CALL_ARG_LOCATION))
+    next_note = NULL_RTX;
 
-    case CONST_DECL:
-      if (debug_info_level <= DINFO_LEVEL_TERSE)
-       return;
-      if (!is_fortran ())
-       return;
-      if (TREE_STATIC (decl) && decl_function_context (decl))
-       context_die = lookup_decl_die (DECL_CONTEXT (decl));
-      break;
+  if (! next_real)
+    next_real = next_real_insn (loc_note);
 
-    case NAMESPACE_DECL:
-    case IMPORTED_DECL:
-      if (debug_info_level <= DINFO_LEVEL_TERSE)
-       return;
-      if (lookup_decl_die (decl) != NULL)
-       return;
-      break;
+  if (next_note)
+    {
+      expected_next_loc_note = next_note;
+      cached_next_real_insn = next_real;
+    }
+  else
+    cached_next_real_insn = NULL_RTX;
 
-    case TYPE_DECL:
-      /* Don't emit stubs for types unless they are needed by other DIEs.  */
-      if (TYPE_DECL_SUPPRESS_DEBUG (decl))
-       return;
+  /* If there are no instructions which would be affected by this note,
+     don't do anything.  */
+  if (var_loc_p
+      && next_real == NULL_RTX
+      && !NOTE_DURING_CALL_P (loc_note))
+    return;
 
-      /* 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);
+  if (next_real == NULL_RTX)
+    next_real = get_last_insn ();
 
-         return;
-       }
+  /* If there were any real insns between note we processed last time
+     and this note (or if it is the first note), clear
+     last_{,postcall_}label so that they are not reused this time.  */
+  if (last_var_location_insn == NULL_RTX
+      || last_var_location_insn != next_real
+      || last_in_cold_section_p != in_cold_section_p)
+    {
+      last_label = NULL;
+      last_postcall_label = NULL;
+    }
 
-      /* If we are in terse mode, don't generate any DIEs for types.  */
-      if (debug_info_level <= DINFO_LEVEL_TERSE)
+  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 we're a function-scope tag, initially use a parent of NULL;
-        this will be fixed up in decls_for_scope.  */
-      if (decl_function_context (decl))
-       context_die = NULL;
-
-      break;
+  /* If there were no real insns between note we processed last time
+     and this note, use the label we emitted last time.  Otherwise
+     create a new label and emit it.  */
+  if (last_label == NULL)
+    {
+      ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num);
+      ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num);
+      loclabel_num++;
+      last_label = ggc_strdup (loclabel);
+    }
 
-    default:
-      return;
+  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
+    {
+      if (!last_postcall_label)
+       {
+         sprintf (loclabel, "%s-1", last_label);
+         last_postcall_label = ggc_strdup (loclabel);
+       }
+      newloc->label = last_postcall_label;
     }
 
-  gen_decl_die (decl, NULL, context_die);
+  last_var_location_insn = next_real;
+  last_in_cold_section_p = in_cold_section_p;
 }
 
-/* Write the debugging output for DECL.  */
+/* Note in one location list that text section has changed.  */
 
-static void
-dwarf2out_function_decl (tree decl)
+static int
+var_location_switch_text_section_1 (void **slot, void *data ATTRIBUTE_UNUSED)
 {
-  dwarf2out_decl (decl);
-
-  htab_empty (decl_loc_table);
+  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;
 }
 
-/* Output a marker (i.e. a label) for the beginning of the generated code for
-   a lexical block.  */
+/* Note in all location lists that text section has changed.  */
 
 static void
-dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
-                      unsigned int blocknum)
+var_location_switch_text_section (void)
 {
-  switch_to_section (current_function_section ());
-  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
+  if (decl_loc_table == NULL)
+    return;
+
+  htab_traverse (decl_loc_table, var_location_switch_text_section_1, NULL);
 }
 
-/* Output a marker (i.e. a label) for the end of the generated code for a
-   lexical block.  */
+/* Create a new line number table.  */
 
-static void
-dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
+static dw_line_info_table *
+new_line_info_table (void)
 {
-  switch_to_section (current_function_section ());
-  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
-}
+  dw_line_info_table *table;
 
-/* Returns nonzero if it is appropriate not to emit any debugging
-   information for BLOCK, because it doesn't contain any instructions.
+  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;
 
-   Don't allow this for blocks with nested functions or local classes
-   as we would end up with orphans, and in the presence of scheduling
-   we may end up calling them anyway.  */
+  return table;
+}
 
-static bool
-dwarf2out_ignore_block (const_tree block)
+/* 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)
 {
-  tree decl;
-  unsigned int i;
+  dw_line_info_table *table;
 
-  for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
-    if (TREE_CODE (decl) == FUNCTION_DECL
-       || (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)))
-      return 0;
-  for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (block); i++)
+  if (sec == text_section)
+    table = text_section_line_info;
+  else if (sec == cold_text_section)
     {
-      decl = BLOCK_NONLOCALIZED_VAR (block, i);
-      if (TREE_CODE (decl) == FUNCTION_DECL
-         || (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)))
-      return 0;
+      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;
 
-  return 1;
+      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);
+    }
+
+  if (DWARF2_ASM_LINE_DEBUG_INFO)
+    table->is_stmt = (cur_line_info_table
+                     ? cur_line_info_table->is_stmt
+                     : DWARF_LINE_DEFAULT_IS_STMT_START);
+  cur_line_info_table = table;
 }
 
-/* Hash table routines for file_hash.  */
 
-static int
-file_table_eq (const void *p1_p, const void *p2_p)
+/* 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
+   that hook is called.  Also compute have_multiple_function_sections here.  */
+
+static void
+dwarf2out_begin_function (tree fun)
 {
-  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;
+  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);
 }
 
-static hashval_t
-file_table_hash (const void *p_p)
+/* 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)
 {
-  const struct dwarf_file_data *const p = (const struct dwarf_file_data *) p_p;
-  return htab_hash_string (p->filename);
+  dw_line_info_entry e;
+  e.opcode = opcode;
+  e.val = val;
+  VEC_safe_push (dw_line_info_entry, gc, table->entries, &e);
 }
 
-/* Lookup FILE_NAME (in the list of filenames that we know about here in
-   dwarf2out.c) and return its "index".  The index of each (known) filename is
-   just a unique number which is associated with only that one filename.  We
-   need such numbers for the sake of generating labels (in the .debug_sfnames
-   section) and references to those files numbers (in the .debug_srcinfo
-   and.debug_macinfo sections).  If the filename given as an argument is not
-   found in our current list, add it to the list and assign it the next
-   available unique index number.  In order to speed up searches, we remember
-   the index of the filename was looked up last.  This handles the majority of
-   all searches.  */
+/* 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 struct dwarf_file_data *
-lookup_filename (const char *file_name)
+static void
+dwarf2out_source_line (unsigned int line, const char *filename,
+                       int discriminator, bool is_stmt)
 {
-  void ** slot;
-  struct dwarf_file_data * created;
+  unsigned int file_num;
+  dw_line_info_table *table;
 
-  /* Check to see if the file name that was searched on the previous
-     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))
-    return file_table_last_lookup;
+  if (debug_info_level < DINFO_LEVEL_NORMAL || line == 0)
+    return;
 
-  /* Didn't match the previous lookup, search the table.  */
-  slot = htab_find_slot_with_hash (file_table, file_name,
-                                  htab_hash_string (file_name), INSERT);
-  if (*slot)
-    return (struct dwarf_file_data *) *slot;
+  /* 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;
 
-  created = GGC_NEW (struct dwarf_file_data);
-  created->filename = file_name;
-  created->emitted_number = 0;
-  *slot = created;
-  return created;
-}
+  switch_to_section (current_function_section ());
 
-/* If the assembler will construct the file table, then translate the compiler
-   internal file table number into the assembler file table number, and emit
-   a .file directive if we haven't already emitted one yet.  The file table
-   numbers are different because we prune debug info for unused variables and
-   types, which may include filenames.  */
+  /* If requested, emit something human-readable.  */
+  if (flag_debug_asm)
+    fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START, filename, line);
 
-static int
-maybe_emit_file (struct dwarf_file_data * fd)
-{
-  if (! fd->emitted_number)
+  if (DWARF2_ASM_LINE_DEBUG_INFO)
     {
-      if (last_emitted_file)
-       fd->emitted_number = last_emitted_file->emitted_number + 1;
-      else
-       fd->emitted_number = 1;
-      last_emitted_file = fd;
+      /* Emit the .loc directive understood by GNU as.  */
+      /* "\t.loc %u %u 0 is_stmt %u discriminator %u",
+        file_num, line, is_stmt, discriminator */
+      fputs ("\t.loc ", asm_out_file);
+      fprint_ul (asm_out_file, file_num);
+      putc (' ', asm_out_file);
+      fprint_ul (asm_out_file, line);
+      putc (' ', asm_out_file);
+      putc ('0', asm_out_file);
 
-      if (DWARF2_ASM_LINE_DEBUG_INFO)
+      if (is_stmt != table->is_stmt)
        {
-         fprintf (asm_out_file, "\t.file %u ", fd->emitted_number);
-         output_quoted_string (asm_out_file,
-                               remap_debug_filename (fd->filename));
-         fputc ('\n', asm_out_file);
+         fputs (" is_stmt ", asm_out_file);
+         putc (is_stmt ? '1' : '0', asm_out_file);
+       }
+      if (SUPPORTS_DISCRIMINATOR && discriminator != 0)
+       {
+         gcc_assert (discriminator > 0);
+         fputs (" discriminator ", asm_out_file);
+         fprint_ul (asm_out_file, (unsigned long) discriminator);
        }
+      putc ('\n', asm_out_file);
     }
+  else
+    {
+      unsigned int label_num = ++line_info_label_num;
 
-  return fd->emitted_number;
-}
-
-/* Schedule generation of a DW_AT_const_value attribute to DIE.
-   That generation should happen after function debug info has been
-   generated. The value of the attribute is the constant value of ARG.  */
-
-static void
-append_entry_to_tmpl_value_parm_die_table (dw_die_ref die, tree arg)
-{
-  die_arg_entry entry;
-
-  if (!die || !arg)
-    return;
+      targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num);
 
-  if (!tmpl_value_parm_die_table)
-    tmpl_value_parm_die_table
-      = VEC_alloc (die_arg_entry, gc, 32);
+      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);
+    }
 
-  entry.die = die;
-  entry.arg = arg;
-  VEC_safe_push (die_arg_entry, gc,
-                tmpl_value_parm_die_table,
-                &entry);
+  table->file_num = file_num;
+  table->line_num = line;
+  table->discrim_num = discriminator;
+  table->is_stmt = is_stmt;
+  table->in_use = true;
 }
 
-/* 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.  */
+/* Record the beginning of a new source file.  */
 
 static void
-gen_remaining_tmpl_value_param_die_attribute (void)
+dwarf2out_start_source_file (unsigned int lineno, const char *filename)
 {
-  if (tmpl_value_parm_die_table)
+  if (flag_eliminate_dwarf2_dups && ! use_debug_types)
     {
-      unsigned i;
-      die_arg_entry *e;
+      /* 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);
+      add_AT_string (bincl_die, DW_AT_name, remap_debug_filename (filename));
+    }
 
-      for (i = 0;
-           VEC_iterate (die_arg_entry, tmpl_value_parm_die_table, i, e);
-           i++)
-       tree_add_const_value_attribute (e->die, e->arg);
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+    {
+      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);
     }
 }
 
-
-/* Replace DW_AT_name for the decl with name.  */
+/* Record the end of a source file.  */
 
 static void
-dwarf2out_set_name (tree decl, tree name)
+dwarf2out_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED)
 {
-  dw_die_ref die;
-  dw_attr_ref attr;
-  const char *dname;
-
-  die = TYPE_SYMTAB_DIE (decl);
-  if (!die)
-    return;
-
-  dname = dwarf2_name (name, 0);
-  if (!dname)
-    return;
+  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);
 
-  attr = get_AT (die, DW_AT_name);
-  if (attr)
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
     {
-      struct indirect_string_node *node;
-
-      node = find_AT_string (dname);
-      /* replace the string.  */
-      attr->dw_attr_val.v.val_str = node;
+      macinfo_entry e;
+      e.code = DW_MACINFO_end_file;
+      e.lineno = lineno;
+      e.info = NULL;
+      VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
     }
-
-  else
-    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 from debug_define in toplev.c.  The `buffer' parameter contains
+   the tail part of the directive line, i.e. the part which is past the
+   initial whitespace, #, whitespace, directive-name, whitespace part.  */
 
 static void
-dwarf2out_direct_call (tree targ)
+dwarf2out_define (unsigned int lineno ATTRIBUTE_UNUSED,
+                 const char *buffer ATTRIBUTE_UNUSED)
 {
-  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;
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+    {
+      macinfo_entry e;
+      /* Insert a dummy first entry to be able to optimize the whole
+        predefined macro block using DW_MACRO_GNU_transparent_include.  */
+      if (VEC_empty (macinfo_entry, macinfo_table) && lineno == 0)
+       {
+         e.code = 0;
+         e.lineno = 0;
+         e.info = NULL;
+         VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
+       }
+      e.code = DW_MACINFO_define;
+      e.lineno = lineno;
+      e.info = xstrdup (buffer);;
+      VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
+    }
+}
 
-  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);
+/* Called from debug_undef in toplev.c.  The `buffer' parameter contains
+   the tail part of the directive line, i.e. the part which is past the
+   initial whitespace, #, whitespace, directive-name, whitespace part.  */
 
-  /* 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);
+static void
+dwarf2out_undef (unsigned int lineno ATTRIBUTE_UNUSED,
+                const char *buffer ATTRIBUTE_UNUSED)
+{
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+    {
+      macinfo_entry e;
+      /* Insert a dummy first entry to be able to optimize the whole
+        predefined macro block using DW_MACRO_GNU_transparent_include.  */
+      if (VEC_empty (macinfo_entry, macinfo_table) && lineno == 0)
+       {
+         e.code = 0;
+         e.lineno = 0;
+         e.info = NULL;
+         VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
+       }
+      e.code = DW_MACINFO_undef;
+      e.lineno = lineno;
+      e.info = xstrdup (buffer);
+      VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
+    }
 }
 
-/* Returns a hash value for X (which really is a struct vcall_insn).  */
+/* Routines to manipulate hash table of CUs.  */
 
 static hashval_t
-vcall_insn_table_hash (const void *x)
+htab_macinfo_hash (const void *of)
 {
-  return (hashval_t) ((const struct vcall_insn *) x)->insn_uid;
-}
+  const macinfo_entry *const entry =
+    (const macinfo_entry *) of;
 
-/* Return nonzero if insn_uid of struct vcall_insn *X is the same as
-   insnd_uid of *Y.  */
+  return htab_hash_string (entry->info);
+}
 
 static int
-vcall_insn_table_eq (const void *x, const void *y)
+htab_macinfo_eq (const void *of1, const void *of2)
 {
-  return (((const struct vcall_insn *) x)->insn_uid
-          == ((const struct vcall_insn *) y)->insn_uid);
+  const macinfo_entry *const entry1 = (const macinfo_entry *) of1;
+  const macinfo_entry *const entry2 = (const macinfo_entry *) of2;
+
+  return !strcmp (entry1->info, entry2->info);
 }
 
-/* Associate VTABLE_SLOT with INSN_UID in the VCALL_INSN_TABLE.  */
+/* Output a single .debug_macinfo entry.  */
 
 static void
-store_vcall_insn (unsigned int vtable_slot, int insn_uid)
+output_macinfo_op (macinfo_entry *ref)
 {
-  struct vcall_insn *item = GGC_NEW (struct vcall_insn);
-  struct vcall_insn **slot;
+  int file_num;
+  size_t len;
+  struct indirect_string_node *node;
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+  struct dwarf_file_data *fd;
 
-  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;
+  switch (ref->code)
+    {
+    case DW_MACINFO_start_file:
+      fd = lookup_filename (ref->info);
+      if (fd->filename == ref->info)
+       fd->filename = ggc_strdup (fd->filename);
+      file_num = maybe_emit_file (fd);
+      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:
+    case DW_MACINFO_undef:
+      len = strlen (ref->info) + 1;
+      if (!dwarf_strict
+         && len > DWARF_OFFSET_SIZE
+         && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
+         && (debug_str_section->common.flags & SECTION_MERGE) != 0)
+       {
+         ref->code = ref->code == DW_MACINFO_define
+                     ? DW_MACRO_GNU_define_indirect
+                     : DW_MACRO_GNU_undef_indirect;
+         output_macinfo_op (ref);
+         return;
+       }
+      dw2_asm_output_data (1, ref->code,
+                          ref->code == DW_MACINFO_define
+                          ? "Define macro" : "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;
+    case DW_MACRO_GNU_define_indirect:
+    case DW_MACRO_GNU_undef_indirect:
+      node = find_AT_string (ref->info);
+      if (node->form != DW_FORM_strp)
+       {
+         char label[32];
+         ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+         ++dw2_string_counter;
+         node->label = xstrdup (label);
+         node->form = DW_FORM_strp;
+       }
+      dw2_asm_output_data (1, ref->code,
+                          ref->code == DW_MACRO_GNU_define_indirect
+                          ? "Define macro indirect"
+                          : "Undefine macro indirect");
+      dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
+                                  (unsigned long) ref->lineno);
+      dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+                            debug_str_section, "The macro: \"%s\"",
+                            ref->info);
+      break;
+    case DW_MACRO_GNU_transparent_include:
+      dw2_asm_output_data (1, ref->code, "Transparent include");
+      ASM_GENERATE_INTERNAL_LABEL (label,
+                                  DEBUG_MACRO_SECTION_LABEL, ref->lineno);
+      dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL);
+      break;
+    default:
+      fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n",
+              ASM_COMMENT_START, (unsigned long) ref->code);
+      break;
+    }
 }
 
-/* Return the VTABLE_SLOT associated with INSN_UID.  */
+/* Attempt to make a sequence of define/undef macinfo ops shareable with
+   other compilation unit .debug_macinfo sections.  IDX is the first
+   index of a define/undef, return the number of ops that should be
+   emitted in a comdat .debug_macinfo section and emit
+   a DW_MACRO_GNU_transparent_include entry referencing it.
+   If the define/undef entry should be emitted normally, return 0.  */
 
-static unsigned int
-lookup_vcall_insn (unsigned int insn_uid)
+static unsigned
+optimize_macinfo_range (unsigned int idx, VEC (macinfo_entry, gc) *files,
+                       htab_t *macinfo_htab)
 {
-  struct vcall_insn item;
-  struct vcall_insn *p;
+  macinfo_entry *first, *second, *cur, *inc;
+  char linebuf[sizeof (HOST_WIDE_INT) * 3 + 1];
+  unsigned char checksum[16];
+  struct md5_ctx ctx;
+  char *grp_name, *tail;
+  const char *base;
+  unsigned int i, count, encoded_filename_len, linebuf_len;
+  void **slot;
 
-  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;
-}
+  first = VEC_index (macinfo_entry, macinfo_table, idx);
+  second = VEC_index (macinfo_entry, macinfo_table, idx + 1);
 
+  /* Optimize only if there are at least two consecutive define/undef ops,
+     and either all of them are before first DW_MACINFO_start_file
+     with lineno 0 (i.e. predefined macro block), or all of them are
+     in some included header file.  */
+  if (second->code != DW_MACINFO_define && second->code != DW_MACINFO_undef)
+    return 0;
+  if (VEC_empty (macinfo_entry, files))
+    {
+      if (first->lineno != 0 || second->lineno != 0)
+       return 0;
+    }
+  else if (first->lineno == 0)
+    return 0;
 
-/* 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.  */
+  /* Find the last define/undef entry that can be grouped together
+     with first and at the same time compute md5 checksum of their
+     codes, linenumbers and strings.  */
+  md5_init_ctx (&ctx);
+  for (i = idx; VEC_iterate (macinfo_entry, macinfo_table, i, cur); i++)
+    if (cur->code != DW_MACINFO_define && cur->code != DW_MACINFO_undef)
+      break;
+    else if (first->lineno == 0 && cur->lineno != 0)
+      break;
+    else
+      {
+       unsigned char code = cur->code;
+       md5_process_bytes (&code, 1, &ctx);
+       checksum_uleb128 (cur->lineno, &ctx);
+       md5_process_bytes (cur->info, strlen (cur->info) + 1, &ctx);
+      }
+  md5_finish_ctx (&ctx, checksum);
+  count = i - idx;
 
-static void
-dwarf2out_virtual_call_token (tree addr, int insn_uid)
-{
-  if (is_cxx() && TREE_CODE (addr) == OBJ_TYPE_REF)
+  /* From the containing include filename (if any) pick up just
+     usable characters from its basename.  */
+  if (first->lineno == 0)
+    base = "";
+  else
+    base = lbasename (VEC_last (macinfo_entry, files)->info);
+  for (encoded_filename_len = 0, i = 0; base[i]; i++)
+    if (ISIDNUM (base[i]) || base[i] == '.')
+      encoded_filename_len++;
+  /* Count . at the end.  */
+  if (encoded_filename_len)
+    encoded_filename_len++;
+
+  sprintf (linebuf, HOST_WIDE_INT_PRINT_UNSIGNED, first->lineno);
+  linebuf_len = strlen (linebuf);
+
+  /* The group name format is: wmN.[<encoded filename>.]<lineno>.<md5sum>  */
+  grp_name = XNEWVEC (char, 4 + encoded_filename_len + linebuf_len + 1
+                     + 16 * 2 + 1);
+  memcpy (grp_name, DWARF_OFFSET_SIZE == 4 ? "wm4." : "wm8.", 4);
+  tail = grp_name + 4;
+  if (encoded_filename_len)
+    {
+      for (i = 0; base[i]; i++)
+       if (ISIDNUM (base[i]) || base[i] == '.')
+         *tail++ = base[i];
+      *tail++ = '.';
+    }
+  memcpy (tail, linebuf, linebuf_len);
+  tail += linebuf_len;
+  *tail++ = '.';
+  for (i = 0; i < 16; i++)
+    sprintf (tail + i * 2, "%02x", checksum[i] & 0xff);
+
+  /* Construct a macinfo_entry for DW_MACRO_GNU_transparent_include
+     in the empty vector entry before the first define/undef.  */
+  inc = VEC_index (macinfo_entry, macinfo_table, idx - 1);
+  inc->code = DW_MACRO_GNU_transparent_include;
+  inc->lineno = 0;
+  inc->info = grp_name;
+  if (*macinfo_htab == NULL)
+    *macinfo_htab = htab_create (10, htab_macinfo_hash, htab_macinfo_eq, NULL);
+  /* Avoid emitting duplicates.  */
+  slot = htab_find_slot (*macinfo_htab, inc, INSERT);
+  if (*slot != NULL)
+    {
+      free (CONST_CAST (char *, inc->info));
+      inc->code = 0;
+      inc->info = NULL;
+      /* If such an entry has been used before, just emit
+        a DW_MACRO_GNU_transparent_include op.  */
+      inc = (macinfo_entry *) *slot;
+      output_macinfo_op (inc);
+      /* And clear all macinfo_entry in the range to avoid emitting them
+        in the second pass.  */
+      for (i = idx;
+          VEC_iterate (macinfo_entry, macinfo_table, i, cur)
+          && i < idx + count;
+          i++)
+       {
+         cur->code = 0;
+         free (CONST_CAST (char *, cur->info));
+         cur->info = NULL;
+       }
+    }
+  else
     {
-      tree token = OBJ_TYPE_REF_TOKEN (addr);
-      if (TREE_CODE (token) == INTEGER_CST)
-        store_vcall_insn (TREE_INT_CST_LOW (token), insn_uid);
+      *slot = inc;
+      inc->lineno = htab_elements (*macinfo_htab);
+      output_macinfo_op (inc);
     }
+  return count;
 }
 
-/* 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.  */
+/* Output macinfo section(s).  */
 
 static void
-dwarf2out_copy_call_info (rtx old_insn, rtx new_insn)
+output_macinfo (void)
 {
-  unsigned int vtable_slot = lookup_vcall_insn (INSN_UID (old_insn));
+  unsigned i;
+  unsigned long length = VEC_length (macinfo_entry, macinfo_table);
+  macinfo_entry *ref;
+  VEC (macinfo_entry, gc) *files = NULL;
+  htab_t macinfo_htab = NULL;
 
-  if (vtable_slot != (unsigned int) -1)
-    store_vcall_insn (vtable_slot, INSN_UID (new_insn));
-}
+  if (! length)
+    return;
 
-/* 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.  */
+  /* output_macinfo* uses these interchangeably.  */
+  gcc_assert ((int) DW_MACINFO_define == (int) DW_MACRO_GNU_define
+             && (int) DW_MACINFO_undef == (int) DW_MACRO_GNU_undef
+             && (int) DW_MACINFO_start_file == (int) DW_MACRO_GNU_start_file
+             && (int) DW_MACINFO_end_file == (int) DW_MACRO_GNU_end_file);
 
-static void
-dwarf2out_virtual_call (int insn_uid)
-{
-  unsigned int vtable_slot = lookup_vcall_insn (insn_uid);
-  vcall_entry e;
+  /* For .debug_macro emit the section header.  */
+  if (!dwarf_strict)
+    {
+      dw2_asm_output_data (2, 4, "DWARF macro version number");
+      if (DWARF_OFFSET_SIZE == 8)
+       dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present");
+      else
+       dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present");
+      dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_line_section_label,
+                            debug_line_section, NULL);
+    }
+
+  /* In the first loop, it emits the primary .debug_macinfo section
+     and after each emitted op the macinfo_entry is cleared.
+     If a longer range of define/undef ops can be optimized using
+     DW_MACRO_GNU_transparent_include, the
+     DW_MACRO_GNU_transparent_include op is emitted and kept in
+     the vector before the first define/undef in the range and the
+     whole range of define/undef ops is not emitted and kept.  */
+  for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++)
+    {
+      switch (ref->code)
+       {
+       case DW_MACINFO_start_file:
+         VEC_safe_push (macinfo_entry, gc, files, ref);
+         break;
+       case DW_MACINFO_end_file:
+         if (!VEC_empty (macinfo_entry, files))
+           {
+             macinfo_entry *file = VEC_last (macinfo_entry, files);
+             free (CONST_CAST (char *, file->info));
+             VEC_pop (macinfo_entry, files);
+           }
+         break;
+       case DW_MACINFO_define:
+       case DW_MACINFO_undef:
+         if (!dwarf_strict
+             && HAVE_COMDAT_GROUP
+             && VEC_length (macinfo_entry, files) != 1
+             && i > 0
+             && i + 1 < length
+             && VEC_index (macinfo_entry, macinfo_table, i - 1)->code == 0)
+           {
+             unsigned count = optimize_macinfo_range (i, files, &macinfo_htab);
+             if (count)
+               {
+                 i += count - 1;
+                 continue;
+               }
+           }
+         break;
+       case 0:
+         /* A dummy entry may be inserted at the beginning to be able
+            to optimize the whole block of predefined macros.  */
+         if (i == 0)
+           continue;
+       default:
+         break;
+       }
+      output_macinfo_op (ref);
+      /* For DW_MACINFO_start_file ref->info has been copied into files
+        vector.  */
+      if (ref->code != DW_MACINFO_start_file)
+       free (CONST_CAST (char *, ref->info));
+      ref->info = NULL;
+      ref->code = 0;
+    }
 
-  if (vtable_slot == (unsigned int) -1)
+  if (macinfo_htab == NULL)
     return;
 
-  e.poc_label_num = poc_label_num++;
-  e.vtable_slot = vtable_slot;
-  VEC_safe_push (vcall_entry, gc, vcall_table, &e);
+  htab_delete (macinfo_htab);
 
-  /* 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);
+  /* If any DW_MACRO_GNU_transparent_include were used, on those
+     DW_MACRO_GNU_transparent_include entries terminate the
+     current chain and switch to a new comdat .debug_macinfo
+     section and emit the define/undef entries within it.  */
+  for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++)
+    switch (ref->code)
+      {
+      case 0:
+       continue;
+      case DW_MACRO_GNU_transparent_include:
+       {
+         char label[MAX_ARTIFICIAL_LABEL_BYTES];
+         tree comdat_key = get_identifier (ref->info);
+         /* Terminate the previous .debug_macinfo section.  */
+         dw2_asm_output_data (1, 0, "End compilation unit");
+         targetm.asm_out.named_section (DEBUG_MACRO_SECTION,
+                                        SECTION_DEBUG
+                                        | SECTION_LINKONCE,
+                                        comdat_key);
+         ASM_GENERATE_INTERNAL_LABEL (label,
+                                      DEBUG_MACRO_SECTION_LABEL,
+                                      ref->lineno);
+         ASM_OUTPUT_LABEL (asm_out_file, label);
+         ref->code = 0;
+         free (CONST_CAST (char *, ref->info));
+         ref->info = NULL;
+         dw2_asm_output_data (2, 4, "DWARF macro version number");
+         if (DWARF_OFFSET_SIZE == 8)
+           dw2_asm_output_data (1, 1, "Flags: 64-bit");
+         else
+           dw2_asm_output_data (1, 0, "Flags: 32-bit");
+       }
+       break;
+      case DW_MACINFO_define:
+      case DW_MACINFO_undef:
+       output_macinfo_op (ref);
+       ref->code = 0;
+       free (CONST_CAST (char *, ref->info));
+       ref->info = NULL;
+       break;
+      default:
+       gcc_unreachable ();
+      }
 }
 
-/* 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.  */
+/* Set up for Dwarf output at the start of compilation.  */
 
 static void
-dwarf2out_var_location (rtx loc_note)
+dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
 {
-  char loclabel[MAX_ARTIFICIAL_LABEL_BYTES + 2];
-  struct var_loc_node *newloc;
-  rtx next_real;
-  static const char *last_label;
-  static const char *last_postcall_label;
-  static bool last_in_cold_section_p;
-  tree decl;
+  /* Allocate the file_table.  */
+  file_table = htab_create_ggc (50, file_table_hash,
+                               file_table_eq, NULL);
 
-  if (!DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
-    return;
+  /* Allocate the decl_die_table.  */
+  decl_die_table = htab_create_ggc (10, decl_die_table_hash,
+                                   decl_die_table_eq, NULL);
 
-  next_real = next_real_insn (loc_note);
-  /* If there are no instructions which would be affected by this note,
-     don't do anything.  */
-  if (next_real == NULL_RTX)
-    return;
+  /* Allocate the decl_loc_table.  */
+  decl_loc_table = htab_create_ggc (10, decl_loc_table_hash,
+                                   decl_loc_table_eq, NULL);
 
-  /* If there were any real insns between note we processed last time
-     and this note (or if it is the first note), clear
-     last_{,postcall_}label so that they are not reused this time.  */
-  if (last_var_location_insn == NULL_RTX
-      || last_var_location_insn != next_real
-      || last_in_cold_section_p != in_cold_section_p)
-    {
-      last_label = NULL;
-      last_postcall_label = NULL;
-    }
+  /* 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);
 
-  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;
+  /* Allocate the initial hunk of the decl_scope_table.  */
+  decl_scope_table = VEC_alloc (tree, gc, 256);
 
-  /* If there were no real insns between note we processed last time
-     and this note, use the label we emitted last time.  Otherwise
-     create a new label and emit it.  */
-  if (last_label == NULL)
-    {
-      ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num);
-      ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num);
-      loclabel_num++;
-      last_label = ggc_strdup (loclabel);
-    }
+  /* Allocate the initial hunk of the abbrev_die_table.  */
+  abbrev_die_table = ggc_alloc_cleared_vec_dw_die_ref
+    (ABBREV_DIE_TABLE_INCREMENT);
+  abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
+  /* Zero-th entry is allocated, but unused.  */
+  abbrev_die_table_in_use = 1;
 
-  if (!NOTE_DURING_CALL_P (loc_note))
-    newloc->label = last_label;
-  else
-    {
-      if (!last_postcall_label)
-       {
-         sprintf (loclabel, "%s-1", last_label);
-         last_postcall_label = ggc_strdup (loclabel);
-       }
-      newloc->label = last_postcall_label;
-    }
+  /* Allocate the pubtypes and pubnames vectors.  */
+  pubname_table = VEC_alloc (pubname_entry, gc, 32);
+  pubtype_table = VEC_alloc (pubname_entry, gc, 32);
 
-  last_var_location_insn = next_real;
-  last_in_cold_section_p = in_cold_section_p;
+  incomplete_types = VEC_alloc (tree, gc, 64);
+
+  used_rtx_array = VEC_alloc (rtx, gc, 32);
+
+  debug_info_section = get_section (DEBUG_INFO_SECTION,
+                                   SECTION_DEBUG, NULL);
+  debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+                                     SECTION_DEBUG, NULL);
+  debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
+                                      SECTION_DEBUG, NULL);
+  debug_macinfo_section = get_section (dwarf_strict
+                                      ? DEBUG_MACINFO_SECTION
+                                      : DEBUG_MACRO_SECTION,
+                                      SECTION_DEBUG, NULL);
+  debug_line_section = get_section (DEBUG_LINE_SECTION,
+                                   SECTION_DEBUG, NULL);
+  debug_loc_section = get_section (DEBUG_LOC_SECTION,
+                                  SECTION_DEBUG, NULL);
+  debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
+                                       SECTION_DEBUG, NULL);
+  debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
+                                       SECTION_DEBUG, NULL);
+  debug_str_section = get_section (DEBUG_STR_SECTION,
+                                  DEBUG_STR_SECTION_FLAGS, NULL);
+  debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
+                                     SECTION_DEBUG, NULL);
+  debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+                                    SECTION_DEBUG, NULL);
+
+  ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
+                              DEBUG_ABBREV_SECTION_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label,
+                              COLD_TEXT_SECTION_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (cold_end_label, COLD_END_LABEL, 0);
+
+  ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
+                              DEBUG_INFO_SECTION_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
+                              DEBUG_LINE_SECTION_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
+                              DEBUG_RANGES_SECTION_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
+                              dwarf_strict
+                              ? DEBUG_MACINFO_SECTION_LABEL
+                              : DEBUG_MACRO_SECTION_LABEL, 0);
+
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+    macinfo_table = VEC_alloc (macinfo_entry, gc, 64);
+
+  switch_to_section (text_section);
+  ASM_OUTPUT_LABEL (asm_out_file, 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;
 }
 
-/* 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
-   that hook is called.  Also compute have_multiple_function_sections here.  */
+/* Called before cgraph_optimize starts outputtting functions, variables
+   and toplevel asms into assembly.  */
 
 static void
-dwarf2out_begin_function (tree fun)
+dwarf2out_assembly_start (void)
 {
-  if (function_section (fun) != text_section)
-    have_multiple_function_sections = true;
-
-  dwarf2out_note_section_used ();
+  if (HAVE_GAS_CFI_SECTIONS_DIRECTIVE
+      && dwarf2out_do_cfi_asm ()
+      && (!(flag_unwind_tables || flag_exceptions)
+         || targetm_common.except_unwind_info (&global_options) != UI_DWARF2))
+    fprintf (asm_out_file, "\t.cfi_sections\t.debug_frame\n");
 }
 
-/* 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.  */
+/* A helper function for dwarf2out_finish called through
+   htab_traverse.  Emit one queued .debug_str string.  */
 
-static void
-dwarf2out_source_line (unsigned int line, const char *filename,
-                       int discriminator, bool is_stmt)
+static int
+output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
 {
-  static bool last_is_stmt = true;
+  struct indirect_string_node *node = (struct indirect_string_node *) *h;
 
-  if (debug_info_level >= DINFO_LEVEL_NORMAL
-      && line != 0)
+  if (node->form == DW_FORM_strp)
     {
-      int file_num = maybe_emit_file (lookup_filename (filename));
-
-      switch_to_section (current_function_section ());
+      switch_to_section (debug_str_section);
+      ASM_OUTPUT_LABEL (asm_out_file, node->label);
+      assemble_string (node->str, strlen (node->str) + 1);
+    }
 
-      /* If requested, emit something human-readable.  */
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START,
-                filename, line);
+  return 1;
+}
 
-      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);
+#if ENABLE_ASSERT_CHECKING
+/* Verify that all marks are clear.  */
 
-         /* 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)));
-           }
+static void
+verify_marks_clear (dw_die_ref die)
+{
+  dw_die_ref c;
 
-         /* 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;
+  gcc_assert (! die->die_mark);
+  FOR_EACH_CHILD (die, c, verify_marks_clear (c));
+}
+#endif /* ENABLE_ASSERT_CHECKING */
 
-         targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL,
-                                    line_info_table_in_use);
+/* Clear the marks for a die and its children.
+   Be cool if the mark isn't set.  */
 
-         /* 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));
-           }
+static void
+prune_unmark_dies (dw_die_ref die)
+{
+  dw_die_ref c;
 
-         /* 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;
-       }
-    }
+  if (die->die_mark)
+    die->die_mark = 0;
+  FOR_EACH_CHILD (die, c, prune_unmark_dies (c));
 }
 
-/* Record the beginning of a new source file.  */
+/* Given DIE that we're marking as used, find any other dies
+   it references as attributes and mark them as used.  */
 
 static void
-dwarf2out_start_source_file (unsigned int lineno, const char *filename)
+prune_unused_types_walk_attribs (dw_die_ref die)
 {
-  if (flag_eliminate_dwarf2_dups && dwarf_version < 4)
-    {
-      /* 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);
-      add_AT_string (bincl_die, DW_AT_name, remap_debug_filename (filename));
-    }
+  dw_attr_ref a;
+  unsigned ix;
 
-  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
     {
-      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);
+      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 (! 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);
+       }
+      /* Set the string's refcount to 0 so that prune_unused_types_mark
+        accounts properly for it.  */
+      if (AT_class (a) == dw_val_class_str)
+       a->dw_attr_val.v.val_str->refcount = 0;
     }
 }
 
-/* Record the end of a source file.  */
+/* Mark the generic parameters and arguments children DIEs of DIE.  */
 
 static void
-dwarf2out_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED)
+prune_unused_types_mark_generic_parms_dies (dw_die_ref die)
 {
-  if (flag_eliminate_dwarf2_dups && dwarf_version < 4)
-    /* Record the end of the file for break_out_includes.  */
-    new_die (DW_TAG_GNU_EINCL, comp_unit_die, NULL);
+  dw_die_ref c;
 
-  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+  if (die == NULL || die->die_child == NULL)
+    return;
+  c = die->die_child;
+  do
     {
-      switch_to_section (debug_macinfo_section);
-      dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
-    }
+      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);
 }
 
-/* Called from debug_define in toplev.c.  The `buffer' parameter contains
-   the tail part of the directive line, i.e. the part which is past the
-   initial whitespace, #, whitespace, directive-name, whitespace part.  */
+/* Mark DIE as being used.  If DOKIDS is true, then walk down
+   to DIE's children.  */
 
 static void
-dwarf2out_define (unsigned int lineno ATTRIBUTE_UNUSED,
-                 const char *buffer ATTRIBUTE_UNUSED)
+prune_unused_types_mark (dw_die_ref die, int dokids)
 {
-  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+  dw_die_ref c;
+
+  if (die->die_mark == 0)
     {
-      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");
-    }
-}
+      /* 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);
 
-/* Called from debug_undef in toplev.c.  The `buffer' parameter contains
-   the tail part of the directive line, i.e. the part which is past the
-   initial whitespace, #, whitespace, directive-name, whitespace part.  */
+      /* We also have to mark its parents as used.
+        (But we don't want to mark our parents' kids due to this.)  */
+      if (die->die_parent)
+       prune_unused_types_mark (die->die_parent, 0);
 
-static void
-dwarf2out_undef (unsigned int lineno ATTRIBUTE_UNUSED,
-                const char *buffer ATTRIBUTE_UNUSED)
-{
-  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+      /* Mark any referenced nodes.  */
+      prune_unused_types_walk_attribs (die);
+
+      /* If this node is a specification,
+        also mark the definition, if it exists.  */
+      if (get_AT_flag (die, DW_AT_declaration) && die->die_definition)
+       prune_unused_types_mark (die->die_definition, 1);
+    }
+
+  if (dokids && die->die_mark != 2)
     {
-      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");
+      /* We need to walk the children, but haven't done so yet.
+        Remember that we've walked the kids.  */
+      die->die_mark = 2;
+
+      /* If this is an array type, we need to make sure our
+        kids get marked, even if they're types.  If we're
+        breaking out types into comdat sections, do this
+        for all type definitions.  */
+      if (die->die_tag == DW_TAG_array_type
+          || (use_debug_types
+              && is_type_die (die) && ! is_declaration_die (die)))
+       FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1));
+      else
+       FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
     }
 }
 
-/* Set up for Dwarf output at the start of compilation.  */
+/* For local classes, look if any static member functions were emitted
+   and if so, mark them.  */
 
 static void
-dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
+prune_unused_types_walk_local_classes (dw_die_ref die)
 {
-  /* Allocate the file_table.  */
-  file_table = htab_create_ggc (50, file_table_hash,
-                               file_table_eq, NULL);
+  dw_die_ref c;
 
-  /* Allocate the decl_die_table.  */
-  decl_die_table = htab_create_ggc (10, decl_die_table_hash,
-                                   decl_die_table_eq, NULL);
+  if (die->die_mark == 2)
+    return;
 
-  /* Allocate the decl_loc_table.  */
-  decl_loc_table = htab_create_ggc (10, decl_loc_table_hash,
-                                   decl_loc_table_eq, NULL);
+  switch (die->die_tag)
+    {
+    case DW_TAG_structure_type:
+    case DW_TAG_union_type:
+    case DW_TAG_class_type:
+      break;
 
-  /* Allocate the initial hunk of the decl_scope_table.  */
-  decl_scope_table = VEC_alloc (tree, gc, 256);
+    case DW_TAG_subprogram:
+      if (!get_AT_flag (die, DW_AT_declaration)
+         || die->die_definition != NULL)
+       prune_unused_types_mark (die, 1);
+      return;
 
-  /* Allocate the initial hunk of the abbrev_die_table.  */
-  abbrev_die_table = GGC_CNEWVEC (dw_die_ref, ABBREV_DIE_TABLE_INCREMENT);
-  abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
-  /* Zero-th entry is allocated, but unused.  */
-  abbrev_die_table_in_use = 1;
+    default:
+      return;
+    }
 
-  /* Allocate the initial hunk of the line_info_table.  */
-  line_info_table = GGC_CNEWVEC (dw_line_info_entry, LINE_INFO_TABLE_INCREMENT);
-  line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
+  /* Mark children.  */
+  FOR_EACH_CHILD (die, c, prune_unused_types_walk_local_classes (c));
+}
 
-  /* Zero-th entry is allocated, but unused.  */
-  line_info_table_in_use = 1;
+/* Walk the tree DIE and mark types that we actually use.  */
 
-  /* Allocate the pubtypes and pubnames vectors.  */
-  pubname_table = VEC_alloc (pubname_entry, gc, 32);
-  pubtype_table = VEC_alloc (pubname_entry, gc, 32);
+static void
+prune_unused_types_walk (dw_die_ref die)
+{
+  dw_die_ref c;
 
-  /* 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);
+  /* Don't do anything if this node is already marked and
+     children have been marked as well.  */
+  if (die->die_mark == 2)
+    return;
 
-  /* 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);
+  switch (die->die_tag)
+    {
+    case DW_TAG_structure_type:
+    case DW_TAG_union_type:
+    case DW_TAG_class_type:
+      if (die->die_perennial_p)
+       break;
 
-  incomplete_types = VEC_alloc (tree, gc, 64);
+      for (c = die->die_parent; c; c = c->die_parent)
+       if (c->die_tag == DW_TAG_subprogram)
+         break;
 
-  used_rtx_array = VEC_alloc (rtx, gc, 32);
+      /* Finding used static member functions inside of classes
+        is needed just for local classes, because for other classes
+        static member function DIEs with DW_AT_specification
+        are emitted outside of the DW_TAG_*_type.  If we ever change
+        it, we'd need to call this even for non-local classes.  */
+      if (c)
+       prune_unused_types_walk_local_classes (die);
 
-  debug_info_section = get_section (DEBUG_INFO_SECTION,
-                                   SECTION_DEBUG, NULL);
-  debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
-                                     SECTION_DEBUG, NULL);
-  debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
-                                      SECTION_DEBUG, NULL);
-  debug_macinfo_section = get_section (DEBUG_MACINFO_SECTION,
-                                      SECTION_DEBUG, NULL);
-  debug_line_section = get_section (DEBUG_LINE_SECTION,
-                                   SECTION_DEBUG, NULL);
-  debug_loc_section = get_section (DEBUG_LOC_SECTION,
-                                  SECTION_DEBUG, NULL);
-  debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
-                                       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,
-                                     SECTION_DEBUG, NULL);
-  debug_frame_section = get_section (DEBUG_FRAME_SECTION,
-                                    SECTION_DEBUG, NULL);
+      /* It's a type node --- don't mark it.  */
+      return;
+
+    case DW_TAG_const_type:
+    case DW_TAG_packed_type:
+    case DW_TAG_pointer_type:
+    case DW_TAG_reference_type:
+    case DW_TAG_rvalue_reference_type:
+    case DW_TAG_volatile_type:
+    case DW_TAG_typedef:
+    case DW_TAG_array_type:
+    case DW_TAG_interface_type:
+    case DW_TAG_friend:
+    case DW_TAG_variant_part:
+    case DW_TAG_enumeration_type:
+    case DW_TAG_subroutine_type:
+    case DW_TAG_string_type:
+    case DW_TAG_set_type:
+    case DW_TAG_subrange_type:
+    case DW_TAG_ptr_to_member_type:
+    case DW_TAG_file_type:
+      if (die->die_perennial_p)
+       break;
 
-  ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
-                              DEBUG_ABBREV_SECTION_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label,
-                              COLD_TEXT_SECTION_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (cold_end_label, COLD_END_LABEL, 0);
+      /* It's a type node --- don't mark it.  */
+      return;
 
-  ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
-                              DEBUG_INFO_SECTION_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
-                              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);
+    default:
+      /* Mark everything else.  */
+      break;
+  }
 
-  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+  if (die->die_mark == 0)
     {
-      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);
-    }
+      die->die_mark = 1;
 
-  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);
+      /* Now, mark any dies referenced from here.  */
+      prune_unused_types_walk_attribs (die);
     }
 
+  die->die_mark = 2;
+
+  /* Mark children.  */
+  FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
 }
 
-/* Called before cgraph_optimize starts outputtting functions, variables
-   and toplevel asms into assembly.  */
+/* Increment the string counts on strings referred to from DIE's
+   attributes.  */
 
 static void
-dwarf2out_assembly_start (void)
+prune_unused_types_update_strings (dw_die_ref die)
 {
-  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");
-    }
+  dw_attr_ref a;
+  unsigned 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;
+       s->refcount++;
+       /* Avoid unnecessarily putting strings that are used less than
+          twice in the hash table.  */
+       if (s->refcount
+           == ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) ? 1 : 2))
+         {
+           void ** slot;
+           slot = htab_find_slot_with_hash (debug_str_hash, s->str,
+                                            htab_hash_string (s->str),
+                                            INSERT);
+           gcc_assert (*slot == NULL);
+           *slot = s;
+         }
+      }
 }
 
-/* A helper function for dwarf2out_finish called through
-   htab_traverse.  Emit one queued .debug_str string.  */
+/* Remove from the tree DIE any dies that aren't marked.  */
 
-static int
-output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
+static void
+prune_unused_types_prune (dw_die_ref die)
 {
-  struct indirect_string_node *node = (struct indirect_string_node *) *h;
+  dw_die_ref c;
 
-  if (node->label && node->refcount)
-    {
-      switch_to_section (debug_str_section);
-      ASM_OUTPUT_LABEL (asm_out_file, node->label);
-      assemble_string (node->str, strlen (node->str) + 1);
-    }
+  gcc_assert (die->die_mark);
+  prune_unused_types_update_strings (die);
 
-  return 1;
+  if (! die->die_child)
+    return;
+
+  c = die->die_child;
+  do {
+    dw_die_ref prev = c;
+    for (c = c->die_sib; ! c->die_mark; c = c->die_sib)
+      if (c == die->die_child)
+       {
+         /* No marked children between 'prev' and the end of the list.  */
+         if (prev == c)
+           /* No marked children at all.  */
+           die->die_child = NULL;
+         else
+           {
+             prev->die_sib = c->die_sib;
+             die->die_child = prev;
+           }
+         return;
+       }
+
+    if (c != prev->die_sib)
+      prev->die_sib = c;
+    prune_unused_types_prune (c);
+  } while (c != die->die_child);
 }
 
-#if ENABLE_ASSERT_CHECKING
-/* Verify that all marks are clear.  */
+/* Remove dies representing declarations that we never use.  */
 
 static void
-verify_marks_clear (dw_die_ref die)
+prune_unused_types (void)
 {
-  dw_die_ref c;
+  unsigned int i;
+  limbo_die_node *node;
+  comdat_type_node *ctnode;
+  pubname_ref pub;
+  dw_die_ref base_type;
 
-  gcc_assert (! die->die_mark);
-  FOR_EACH_CHILD (die, c, verify_marks_clear (c));
-}
+#if ENABLE_ASSERT_CHECKING
+  /* All the marks should already be clear.  */
+  verify_marks_clear (comp_unit_die ());
+  for (node = limbo_die_list; node; node = node->next)
+    verify_marks_clear (node->die);
+  for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+    verify_marks_clear (ctnode->root_die);
 #endif /* ENABLE_ASSERT_CHECKING */
 
-/* Clear the marks for a die and its children.
-   Be cool if the mark isn't set.  */
+  /* Mark types that are used in global variables.  */
+  premark_types_used_by_global_vars ();
 
-static void
-prune_unmark_dies (dw_die_ref die)
-{
-  dw_die_ref c;
+  /* Set the mark on nodes that are actually used.  */
+  prune_unused_types_walk (comp_unit_die ());
+  for (node = limbo_die_list; node; node = node->next)
+    prune_unused_types_walk (node->die);
+  for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+    {
+      prune_unused_types_walk (ctnode->root_die);
+      prune_unused_types_mark (ctnode->type_die, 1);
+    }
 
-  if (die->die_mark)
-    die->die_mark = 0;
-  FOR_EACH_CHILD (die, c, prune_unmark_dies (c));
-}
+  /* Also set the mark on nodes referenced from the
+     pubname_table.  */
+  FOR_EACH_VEC_ELT (pubname_entry, pubname_table, i, pub)
+    prune_unused_types_mark (pub->die, 1);
+  for (i = 0; VEC_iterate (dw_die_ref, base_types, i, base_type); i++)
+    prune_unused_types_mark (base_type, 1);
 
-/* Given DIE that we're marking as used, find any other dies
-   it references as attributes and mark them as used.  */
+  if (debug_str_hash)
+    htab_empty (debug_str_hash);
+  prune_unused_types_prune (comp_unit_die ());
+  for (node = limbo_die_list; node; node = node->next)
+    prune_unused_types_prune (node->die);
+  for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+    prune_unused_types_prune (ctnode->root_die);
 
-static void
-prune_unused_types_walk_attribs (dw_die_ref die)
-{
-  dw_attr_ref a;
-  unsigned ix;
+  /* Leave the marks clear.  */
+  prune_unmark_dies (comp_unit_die ());
+  for (node = limbo_die_list; node; node = node->next)
+    prune_unmark_dies (node->die);
+  for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+    prune_unmark_dies (ctnode->root_die);
+}
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+/* Set the parameter to true if there are any relative pathnames in
+   the file table.  */
+static int
+file_table_relative_p (void ** slot, void *param)
+{
+  bool *p = (bool *) param;
+  struct dwarf_file_data *d = (struct dwarf_file_data *) *slot;
+  if (!IS_ABSOLUTE_PATH (d->filename))
     {
-      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
-              || a->dw_attr == DW_AT_specification
-              || a->dw_attr_val.v.val_die_ref.die->die_id.die_type_node == NULL)
-           prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
-       }
-      /* Set the string's refcount to 0 so that prune_unused_types_mark
-        accounts properly for it.  */
-      if (AT_class (a) == dw_val_class_str)
-       a->dw_attr_val.v.val_str->refcount = 0;
+      *p = true;
+      return 0;
     }
+  return 1;
 }
 
+/* Routines to manipulate hash table of comdat type units.  */
 
-/* Mark DIE as being used.  If DOKIDS is true, then walk down
-   to DIE's children.  */
+static hashval_t
+htab_ct_hash (const void *of)
+{
+  hashval_t h;
+  const comdat_type_node *const type_node = (const comdat_type_node *) of;
 
-static void
-prune_unused_types_mark (dw_die_ref die, int dokids)
+  memcpy (&h, type_node->signature, sizeof (h));
+  return h;
+}
+
+static int
+htab_ct_eq (const void *of1, const void *of2)
 {
-  dw_die_ref c;
+  const comdat_type_node *const type_node_1 = (const comdat_type_node *) of1;
+  const comdat_type_node *const type_node_2 = (const comdat_type_node *) of2;
 
-  if (die->die_mark == 0)
-    {
-      /* We haven't done this node yet.  Mark it as used.  */
-      die->die_mark = 1;
+  return (! memcmp (type_node_1->signature, type_node_2->signature,
+                    DWARF_TYPE_SIGNATURE_SIZE));
+}
 
-      /* We also have to mark its parents as used.
-        (But we don't want to mark our parents' kids due to this.)  */
-      if (die->die_parent)
-       prune_unused_types_mark (die->die_parent, 0);
+/* Move a DW_AT_{,MIPS_}linkage_name attribute just added to dw_die_ref
+   to the location it would have been added, should we know its
+   DECL_ASSEMBLER_NAME when we added other attributes.  This will
+   probably improve compactness of debug info, removing equivalent
+   abbrevs, and hide any differences caused by deferring the
+   computation of the assembler name, triggered by e.g. PCH.  */
 
-      /* Mark any referenced nodes.  */
-      prune_unused_types_walk_attribs (die);
+static inline void
+move_linkage_attr (dw_die_ref die)
+{
+  unsigned ix = VEC_length (dw_attr_node, die->die_attr);
+  dw_attr_node linkage = *VEC_index (dw_attr_node, die->die_attr, ix - 1);
+
+  gcc_assert (linkage.dw_attr == DW_AT_linkage_name
+             || linkage.dw_attr == DW_AT_MIPS_linkage_name);
 
-      /* If this node is a specification,
-        also mark the definition, if it exists.  */
-      if (get_AT_flag (die, DW_AT_declaration) && die->die_definition)
-       prune_unused_types_mark (die->die_definition, 1);
+  while (--ix > 0)
+    {
+      dw_attr_node *prev = VEC_index (dw_attr_node, die->die_attr, ix - 1);
+
+      if (prev->dw_attr == DW_AT_decl_line || prev->dw_attr == DW_AT_name)
+       break;
     }
 
-  if (dokids && die->die_mark != 2)
+  if (ix != VEC_length (dw_attr_node, die->die_attr) - 1)
     {
-      /* We need to walk the children, but haven't done so yet.
-        Remember that we've walked the kids.  */
-      die->die_mark = 2;
-
-      /* If this is an array type, we need to make sure our
-        kids get marked, even if they're types.  If we're
-        breaking out types into comdat sections, do this
-        for all type definitions.  */
-      if (die->die_tag == DW_TAG_array_type
-          || (dwarf_version >= 4
-              && is_type_die (die) && ! is_declaration_die (die)))
-       FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1));
-      else
-       FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
+      VEC_pop (dw_attr_node, die->die_attr);
+      VEC_quick_insert (dw_attr_node, die->die_attr, ix, &linkage);
     }
 }
 
-/* For local classes, look if any static member functions were emitted
-   and if so, mark them.  */
+/* Helper function for resolve_addr, mark DW_TAG_base_type nodes
+   referenced from typed stack ops and count how often they are used.  */
 
 static void
-prune_unused_types_walk_local_classes (dw_die_ref die)
+mark_base_types (dw_loc_descr_ref loc)
 {
-  dw_die_ref c;
-
-  if (die->die_mark == 2)
-    return;
+  dw_die_ref base_type = NULL;
 
-  switch (die->die_tag)
+  for (; loc; loc = loc->dw_loc_next)
     {
-    case DW_TAG_structure_type:
-    case DW_TAG_union_type:
-    case DW_TAG_class_type:
-      break;
-
-    case DW_TAG_subprogram:
-      if (!get_AT_flag (die, DW_AT_declaration)
-         || die->die_definition != NULL)
-       prune_unused_types_mark (die, 1);
-      return;
-
-    default:
-      return;
+      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_convert:
+       case DW_OP_GNU_reinterpret:
+         if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const)
+           continue;
+         /* FALLTHRU */
+       case DW_OP_GNU_const_type:
+         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;
+       }
     }
+}
 
-  /* Mark children.  */
-  FOR_EACH_CHILD (die, c, prune_unused_types_walk_local_classes (c));
+/* 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;
 }
 
-/* Walk the tree DIE and mark types that we actually use.  */
+/* 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
-prune_unused_types_walk (dw_die_ref die)
+move_marked_base_types (void)
 {
-  dw_die_ref c;
+  unsigned int i;
+  dw_die_ref base_type, die, c;
 
-  /* Don't do anything if this node is already marked and
-     children have been marked as well.  */
-  if (die->die_mark == 2)
+  if (VEC_empty (dw_die_ref, base_types))
     return;
 
-  switch (die->die_tag)
+  /* 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
     {
-    case DW_TAG_structure_type:
-    case DW_TAG_union_type:
-    case DW_TAG_class_type:
-      if (die->die_perennial_p)
-       break;
-
-      for (c = die->die_parent; c; c = c->die_parent)
-       if (c->die_tag == DW_TAG_subprogram)
-         break;
-
-      /* Finding used static member functions inside of classes
-        is needed just for local classes, because for other classes
-        static member function DIEs with DW_AT_specification
-        are emitted outside of the DW_TAG_*_type.  If we ever change
-        it, we'd need to call this even for non-local classes.  */
-      if (c)
-       prune_unused_types_walk_local_classes (die);
-
-      /* It's a type node --- don't mark it.  */
-      return;
-
-    case DW_TAG_const_type:
-    case DW_TAG_packed_type:
-    case DW_TAG_pointer_type:
-    case DW_TAG_reference_type:
-    case DW_TAG_rvalue_reference_type:
-    case DW_TAG_volatile_type:
-    case DW_TAG_typedef:
-    case DW_TAG_array_type:
-    case DW_TAG_interface_type:
-    case DW_TAG_friend:
-    case DW_TAG_variant_part:
-    case DW_TAG_enumeration_type:
-    case DW_TAG_subroutine_type:
-    case DW_TAG_string_type:
-    case DW_TAG_set_type:
-    case DW_TAG_subrange_type:
-    case DW_TAG_ptr_to_member_type:
-    case DW_TAG_file_type:
-      if (die->die_perennial_p)
-       break;
+      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;
+    }
+}
 
-      /* It's a type node --- don't mark it.  */
-      return;
+/* 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.  */
 
-    default:
-      /* Mark everything else.  */
-      break;
-  }
+static int
+resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED)
+{
+  rtx rtl = *addr;
 
-  if (die->die_mark == 0)
+  if (GET_CODE (rtl) == CONST_STRING)
     {
-      die->die_mark = 1;
+      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;
+    }
 
-      /* Now, mark any dies referenced from here.  */
-      prune_unused_types_walk_attribs (die);
+  if (GET_CODE (rtl) == SYMBOL_REF
+      && 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;
     }
 
-  die->die_mark = 2;
+  if (GET_CODE (rtl) == CONST
+      && for_each_rtx (&XEXP (rtl, 0), resolve_one_addr, NULL))
+    return 1;
 
-  /* Mark children.  */
-  FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
+  return 0;
 }
 
-/* Increment the string counts on strings referred to from DIE's
-   attributes.  */
+/* Helper function for resolve_addr, handle one location
+   expression, return false if at least one CONST_STRING or SYMBOL_REF in
+   the location list couldn't be resolved.  */
 
-static void
-prune_unused_types_update_strings (dw_die_ref die)
+static bool
+resolve_addr_in_expr (dw_loc_descr_ref loc)
 {
-  dw_attr_ref a;
-  unsigned ix;
-
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    if (AT_class (a) == dw_val_class_str)
+  dw_loc_descr_ref keep = NULL;
+  for (; loc; loc = loc->dw_loc_next)
+    switch (loc->dw_loc_opc)
       {
-       struct indirect_string_node *s = a->dw_attr_val.v.val_str;
-       s->refcount++;
-       /* Avoid unnecessarily putting strings that are used less than
-          twice in the hash table.  */
-       if (s->refcount
-           == ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) ? 1 : 2))
+      case DW_OP_addr:
+       if (resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
+         return false;
+       break;
+      case DW_OP_const4u:
+      case DW_OP_const8u:
+       if (loc->dtprel
+           && resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
+         return false;
+       break;
+      case DW_OP_plus_uconst:
+       if (size_of_loc_descr (loc)
+           > size_of_int_loc_descriptor (loc->dw_loc_oprnd1.v.val_unsigned)
+             + 1
+           && loc->dw_loc_oprnd1.v.val_unsigned > 0)
          {
-           void ** slot;
-           slot = htab_find_slot_with_hash (debug_str_hash, s->str,
-                                            htab_hash_string (s->str),
-                                            INSERT);
-           gcc_assert (*slot == NULL);
-           *slot = s;
+           dw_loc_descr_ref repl
+             = int_loc_descriptor (loc->dw_loc_oprnd1.v.val_unsigned);
+           add_loc_descr (&repl, new_loc_descr (DW_OP_plus, 0, 0));
+           add_loc_descr (&repl, loc->dw_loc_next);
+           *loc = *repl;
+         }
+       break;
+      case DW_OP_implicit_value:
+       if (loc->dw_loc_oprnd2.val_class == dw_val_class_addr
+           && resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr, NULL))
+         return false;
+       break;
+      case DW_OP_GNU_implicit_pointer:
+      case DW_OP_GNU_parameter_ref:
+       if (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;
+         }
+       break;
+      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:
+       while (loc->dw_loc_next
+              && loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_convert)
+         {
+           dw_die_ref base1, base2;
+           unsigned enc1, enc2, size1, size2;
+           if (loc->dw_loc_opc == DW_OP_GNU_regval_type
+               || loc->dw_loc_opc == DW_OP_GNU_deref_type)
+             base1 = loc->dw_loc_oprnd2.v.val_die_ref.die;
+           else if (loc->dw_loc_oprnd1.val_class
+                    == dw_val_class_unsigned_const)
+             break;
+           else
+             base1 = loc->dw_loc_oprnd1.v.val_die_ref.die;
+           if (loc->dw_loc_next->dw_loc_oprnd1.val_class
+               == dw_val_class_unsigned_const)
+             break;
+           base2 = loc->dw_loc_next->dw_loc_oprnd1.v.val_die_ref.die;
+           gcc_assert (base1->die_tag == DW_TAG_base_type
+                       && base2->die_tag == DW_TAG_base_type);
+           enc1 = get_AT_unsigned (base1, DW_AT_encoding);
+           enc2 = get_AT_unsigned (base2, DW_AT_encoding);
+           size1 = get_AT_unsigned (base1, DW_AT_byte_size);
+           size2 = get_AT_unsigned (base2, DW_AT_byte_size);
+           if (size1 == size2
+               && (((enc1 == DW_ATE_unsigned || enc1 == DW_ATE_signed)
+                    && (enc2 == DW_ATE_unsigned || enc2 == DW_ATE_signed)
+                    && loc != keep)
+                   || enc1 == enc2))
+             {
+               /* Optimize away next DW_OP_GNU_convert after
+                  adjusting LOC's base type die reference.  */
+               if (loc->dw_loc_opc == DW_OP_GNU_regval_type
+                   || loc->dw_loc_opc == DW_OP_GNU_deref_type)
+                 loc->dw_loc_oprnd2.v.val_die_ref.die = base2;
+               else
+                 loc->dw_loc_oprnd1.v.val_die_ref.die = base2;
+               loc->dw_loc_next = loc->dw_loc_next->dw_loc_next;
+               continue;
+             }
+           /* Don't change integer DW_OP_GNU_convert after e.g. floating
+              point typed stack entry.  */
+           else if (enc1 != DW_ATE_unsigned && enc1 != DW_ATE_signed)
+             keep = loc->dw_loc_next;
+           break;
          }
+       break;
+      default:
+       break;
       }
+  return true;
 }
 
-/* Remove from the tree DIE any dies that aren't marked.  */
+/* Resolve DW_OP_addr and DW_AT_const_value CONST_STRING arguments to
+   an address in .rodata section if the string literal is emitted there,
+   or remove the containing location list or replace DW_AT_const_value
+   with DW_AT_location and empty location expression, if it isn't found
+   in .rodata.  Similarly for SYMBOL_REFs, keep only those that refer
+   to something that has been emitted in the current CU.  */
 
 static void
-prune_unused_types_prune (dw_die_ref die)
+resolve_addr (dw_die_ref die)
 {
   dw_die_ref c;
+  dw_attr_ref a;
+  dw_loc_list_ref *curr, *start, loc;
+  unsigned ix;
 
-  gcc_assert (die->die_mark);
-  prune_unused_types_update_strings (die);
-
-  if (! die->die_child)
-    return;
-
-  c = die->die_child;
-  do {
-    dw_die_ref prev = c;
-    for (c = c->die_sib; ! c->die_mark; c = c->die_sib)
-      if (c == die->die_child)
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
+    switch (AT_class (a))
+      {
+      case dw_val_class_loc_list:
+       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)
+         {
+           /* 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)
+             {
+               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
+                 {
+                   mark_base_types ((*curr)->expr);
+                   curr = &(*curr)->dw_loc_next;
+                 }
+             }
+           if (loc == *start)
+             loc->resolved_addr = 1;
+           else
+             {
+               loc->replaced = 1;
+               loc->dw_loc_next = *start;
+             }
+         }
+       if (!*start)
+         {
+           remove_AT (die, a->dw_attr);
+           ix--;
+         }
+       break;
+      case dw_val_class_loc:
        {
-         /* No marked children between 'prev' and the end of the list.  */
-         if (prev == c)
-           /* No marked children at all.  */
-           die->die_child = NULL;
-         else
+         dw_loc_descr_ref l = AT_loc (a);
+         /* For -gdwarf-2 don't attempt to optimize
+            DW_AT_data_member_location containing
+            DW_OP_plus_uconst - older consumers might
+            rely on it being that op instead of a more complex,
+            but shorter, location description.  */
+         if ((dwarf_version > 2
+              || a->dw_attr != DW_AT_data_member_location
+              || l == NULL
+              || l->dw_loc_opc != DW_OP_plus_uconst
+              || l->dw_loc_next != NULL)
+             && !resolve_addr_in_expr (l))
            {
-             prev->die_sib = c->die_sib;
-             die->die_child = prev;
+             remove_AT (die, a->dw_attr);
+             ix--;
            }
-         return;
+         else
+           mark_base_types (l);
        }
+       break;
+      case dw_val_class_addr:
+       if (a->dw_attr == DW_AT_const_value
+           && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL))
+         {
+           remove_AT (die, a->dw_attr);
+           ix--;
+         }
+       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;
+      }
 
-    if (c != prev->die_sib)
-      prev->die_sib = c;
-    prune_unused_types_prune (c);
-  } 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;
+  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.  */
 
-/* Remove dies representing declarations that we never use.  */
+/* Iteratively hash operands of LOC opcode.  */
 
-static void
-prune_unused_types (void)
+static inline hashval_t
+hash_loc_operands (dw_loc_descr_ref loc, hashval_t hash)
 {
-  unsigned int i;
-  limbo_die_node *node;
-  comdat_type_node *ctnode;
-  pubname_ref pub;
-  dcall_entry *dcall;
-
-#if ENABLE_ASSERT_CHECKING
-  /* All the marks should already be clear.  */
-  verify_marks_clear (comp_unit_die);
-  for (node = limbo_die_list; node; node = node->next)
-    verify_marks_clear (node->die);
-  for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
-    verify_marks_clear (ctnode->root_die);
-#endif /* ENABLE_ASSERT_CHECKING */
-
-  /* Mark types that are used in global variables.  */
-  premark_types_used_by_global_vars ();
+  dw_val_ref val1 = &loc->dw_loc_oprnd1;
+  dw_val_ref val2 = &loc->dw_loc_oprnd2;
 
-  /* Set the mark on nodes that are actually used.  */
-  prune_unused_types_walk (comp_unit_die);
-  for (node = limbo_die_list; node; node = node->next)
-    prune_unused_types_walk (node->die);
-  for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+  switch (loc->dw_loc_opc)
     {
-      prune_unused_types_walk (ctnode->root_die);
-      prune_unused_types_mark (ctnode->type_die, 1);
-    }
-
-  /* Also set the mark on nodes referenced from the
-     pubname_table or arange_table.  */
-  for (i = 0; VEC_iterate (pubname_entry, pubname_table, i, pub); i++)
-    prune_unused_types_mark (pub->die, 1);
-  for (i = 0; i < arange_table_in_use; i++)
-    prune_unused_types_mark (arange_table[i], 1);
+    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;
 
-  /* 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);
+       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;
 
-  /* 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)
-    htab_empty (debug_str_hash);
-  prune_unused_types_prune (comp_unit_die);
-  for (node = limbo_die_list; node; node = node->next)
-    prune_unused_types_prune (node->die);
-  for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
-    prune_unused_types_prune (ctnode->root_die);
+           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:
+      if (val1->val_class == dw_val_class_unsigned_const)
+       {
+         hash = iterative_hash_object (val1->v.val_unsigned, hash);
+         break;
+       }
+      /* FALLTHRU */
+    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;
 
-  /* Leave the marks clear.  */
-  prune_unmark_dies (comp_unit_die);
-  for (node = limbo_die_list; node; node = node->next)
-    prune_unmark_dies (node->die);
-  for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
-    prune_unmark_dies (ctnode->root_die);
-}
+             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;
 
-/* Set the parameter to true if there are any relative pathnames in
-   the file table.  */
-static int
-file_table_relative_p (void ** slot, void *param)
-{
-  bool *p = (bool *) param;
-  struct dwarf_file_data *d = (struct dwarf_file_data *) *slot;
-  if (!IS_ABSOLUTE_PATH (d->filename))
-    {
-      *p = true;
-      return 0;
+    default:
+      /* Other codes have no operands.  */
+      break;
     }
-  return 1;
-}
-
-/* Routines to manipulate hash table of comdat type units.  */
-
-static hashval_t
-htab_ct_hash (const void *of)
-{
-  hashval_t h;
-  const comdat_type_node *const type_node = (const comdat_type_node *) of;
-
-  memcpy (&h, type_node->signature, sizeof (h));
-  return h;
-}
-
-static int
-htab_ct_eq (const void *of1, const void *of2)
-{
-  const comdat_type_node *const type_node_1 = (const comdat_type_node *) of1;
-  const comdat_type_node *const type_node_2 = (const comdat_type_node *) of2;
-
-  return (! memcmp (type_node_1->signature, type_node_2->signature,
-                    DWARF_TYPE_SIGNATURE_SIZE));
+  return hash;
 }
 
-/* Move a DW_AT_{,MIPS_}linkage_name attribute just added to dw_die_ref
-   to the location it would have been added, should we know its
-   DECL_ASSEMBLER_NAME when we added other attributes.  This will
-   probably improve compactness of debug info, removing equivalent
-   abbrevs, and hide any differences caused by deferring the
-   computation of the assembler name, triggered by e.g. PCH.  */
+/* Iteratively hash the whole DWARF location expression LOC.  */
 
-static inline void
-move_linkage_attr (dw_die_ref die)
+static inline hashval_t
+hash_locs (dw_loc_descr_ref loc, hashval_t hash)
 {
-  unsigned ix = VEC_length (dw_attr_node, die->die_attr);
-  dw_attr_node linkage = *VEC_index (dw_attr_node, die->die_attr, ix - 1);
-
-  gcc_assert (linkage.dw_attr == AT_linkage_name);
+  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);
 
-  while (--ix > 0)
+  for (l = loc; l != NULL; l = l->dw_loc_next)
     {
-      dw_attr_node *prev = VEC_index (dw_attr_node, die->die_attr, ix - 1);
-
-      if (prev->dw_attr == DW_AT_decl_line || prev->dw_attr == DW_AT_name)
-       break;
+      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;
+}
 
-  if (ix != VEC_length (dw_attr_node, die->die_attr) - 1)
+/* 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)
     {
-      VEC_pop (dw_attr_node, die->die_attr);
-      VEC_quick_insert (dw_attr_node, die->die_attr, ix, &linkage);
+      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;
 }
 
-/* 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.  */
+/* Return true if X and Y opcodes have the same operands.  */
 
-static int
-resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED)
+static inline bool
+compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y)
 {
-  rtx rtl = *addr;
+  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;
 
-  if (GET_CODE (rtl) == CONST_STRING)
+  switch (x->dw_loc_opc)
     {
-      size_t len = strlen (XSTR (rtl, 0)) + 1;
-      tree t = build_string (len, XSTR (rtl, 0));
-      tree tlen = build_int_cst (NULL_TREE, len - 1);
-      TREE_TYPE (t)
-       = build_array_type (char_type_node, build_index_type (tlen));
-      rtl = lookup_constant_def (t);
-      if (!rtl || !MEM_P (rtl))
-       return 1;
-      rtl = XEXP (rtl, 0);
-      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
-      *addr = rtl;
-      return 0;
+    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:
+      if (valx1->val_class != valy1->val_class)
+       return false;
+      if (valx1->val_class == dw_val_class_unsigned_const)
+       return valx1->v.val_unsigned == valy1->v.val_unsigned;
+      return valx1->v.val_die_ref.die == valy1->v.val_die_ref.die;
+    case DW_OP_GNU_parameter_ref:
+      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;
+    default:
+      /* Other codes have no operands.  */
+      return true;
     }
+}
 
-  if (GET_CODE (rtl) == SYMBOL_REF
-      && SYMBOL_REF_DECL (rtl)
-      && !TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl)))
-    return 1;
+/* Return true if DWARF location expressions X and Y are the same.  */
 
-  if (GET_CODE (rtl) == CONST
-      && for_each_rtx (&XEXP (rtl, 0), resolve_one_addr, NULL))
-    return 1;
+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 0;
+/* 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;
 }
 
-/* Helper function for resolve_addr, handle one location
-   expression, return false if at least one CONST_STRING or SYMBOL_REF in
-   the location list couldn't be resolved.  */
+/* Return 1 if location lists X and Y are the same.  */
 
-static bool
-resolve_addr_in_expr (dw_loc_descr_ref loc)
+static int
+loc_list_eq (const void *x, const void *y)
 {
-  for (; loc; loc = loc->dw_loc_next)
-    if ((loc->dw_loc_opc == DW_OP_addr
-        && resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
-       || (loc->dw_loc_opc == DW_OP_implicit_value
-           && loc->dw_loc_oprnd2.val_class == dw_val_class_addr
-           && resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr, NULL)))
-      return false;
-  return true;
+  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;
 }
 
-/* Resolve DW_OP_addr and DW_AT_const_value CONST_STRING arguments to
-   an address in .rodata section if the string literal is emitted there,
-   or remove the containing location list or replace DW_AT_const_value
-   with DW_AT_location and empty location expression, if it isn't found
-   in .rodata.  Similarly for SYMBOL_REFs, keep only those that refer
-   to something that has been emitted in the current CU.  */
+/* Recursively optimize location lists referenced from DIE
+   children and share them whenever possible.  */
 
 static void
-resolve_addr (dw_die_ref die)
+optimize_location_lists_1 (dw_die_ref die, htab_t htab)
 {
   dw_die_ref c;
   dw_attr_ref a;
-  dw_loc_list_ref *curr;
   unsigned ix;
+  void **slot;
 
-  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
-    switch (AT_class (a))
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
+    if (AT_class (a) == dw_val_class_loc_list)
       {
-      case dw_val_class_loc_list:
-       curr = AT_loc_list_ptr (a);
-       while (*curr)
-         {
-           if (!resolve_addr_in_expr ((*curr)->expr))
-             {
-               dw_loc_list_ref next = (*curr)->dw_loc_next;
-               if (next && (*curr)->ll_symbol)
-                 {
-                   gcc_assert (!next->ll_symbol);
-                   next->ll_symbol = (*curr)->ll_symbol;
-                 }
-               *curr = next;
-             }
-           else
-             curr = &(*curr)->dw_loc_next;
-         }
-       if (!AT_loc_list (a))
-         {
-           remove_AT (die, a->dw_attr);
-           ix--;
-         }
-       break;
-      case dw_val_class_loc:
-       if (!resolve_addr_in_expr (AT_loc (a)))
-         {
-           remove_AT (die, a->dw_attr);
-           ix--;
-         }
-       break;
-      case dw_val_class_addr:
-       if (a->dw_attr == DW_AT_const_value
-           && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL))
-         {
-           remove_AT (die, a->dw_attr);
-           ix--;
-         }
-       break;
-      default:
-       break;
+       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, resolve_addr (c));
+  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.  */
 
@@ -21749,22 +22423,31 @@ 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;
 
+  /* PCH might result in DW_AT_producer string being restored from the
+     header compilation, fix it up if needed.  */
+  dw_attr_ref producer = get_AT (comp_unit_die (), DW_AT_producer);
+  if (strcmp (AT_string (producer), producer_string) != 0)
+    {
+      struct indirect_string_node *node = find_AT_string (producer_string);
+      producer->dw_attr_val.v.val_str = node;
+    }
+
+  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++)
@@ -21772,6 +22455,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);
     }
 
@@ -21782,20 +22466,20 @@ 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)
        {
          dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
 
-         if (origin)
+         if (origin && origin->die_parent)
            add_child_die (origin->die_parent, die);
-         else if (die == comp_unit_die)
+         else if (is_cu_die (die))
            ;
-         else if (errorcount > 0 || sorrycount > 0)
+         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
@@ -21825,22 +22509,28 @@ 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)
     {
       tree decl = node->created_for;
       if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
        {
-         add_AT_string (node->die, AT_linkage_name,
-                        IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+         add_linkage_attr (node->die, decl);
          move_linkage_attr (node->die);
        }
     }
@@ -21856,13 +22546,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
@@ -21874,7 +22564,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
@@ -21884,7 +22574,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)
@@ -21893,84 +22583,73 @@ 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;
+      unsigned fde_idx;
+      dw_fde_ref fde;
       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++)
+      FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde)
        {
-         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 (),
+                  dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
+                  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.  */
@@ -21999,16 +22678,32 @@ 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);
-  output_abbrev_section ();
+  if (abbrev_die_table_in_use != 1)
+    {
+      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);
     }
@@ -22019,28 +22714,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))
-    {
-      switch_to_section (debug_dcall_section);
-      output_dcall_table ();
-    }
-  if (!VEC_empty (vcall_entry, vcall_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_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.  */
@@ -22051,69 +22758,31 @@ dwarf2out_finish (const char *filename)
       output_ranges ();
     }
 
+  /* 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");
+    }
+
   /* Output the source line correspondence table.  We must do this
      even if there is no line information.  Otherwise, on an empty
      translation unit, we will generate a present, but empty,
      .debug_info section.  IRIX 6.5 `nm' will then complain when
      examining the file.  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 ();
-    }
-
-  /* Have to end the macro section.  */
-  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
-    {
-      switch_to_section (debug_macinfo_section);
-      dw2_asm_output_data (1, 0, "End compilation unit");
-    }
+    output_line_info ();
 
   /* If we emitted any DW_FORM_strp form attribute, output the string
      table too.  */
   if (debug_str_hash)
     htab_traverse (debug_str_hash, output_indirect_string, NULL);
 }
-#else
-
-/* This should never be used, but its address is needed for comparisons.  */
-const struct gcc_debug_hooks dwarf2_debug_hooks =
-{
-  0,           /* init */
-  0,           /* finish */
-  0,           /* assembly_start */
-  0,           /* define */
-  0,           /* undef */
-  0,           /* start_source_file */
-  0,           /* end_source_file */
-  0,           /* begin_block */
-  0,           /* end_block */
-  0,           /* ignore_block */
-  0,           /* source_line */
-  0,           /* begin_prologue */
-  0,           /* end_prologue */
-  0,           /* end_epilogue */
-  0,           /* begin_function */
-  0,           /* end_function */
-  0,           /* function_decl */
-  0,           /* global_decl */
-  0,           /* type_decl */
-  0,           /* imported_module_or_decl */
-  0,           /* deferred_inline_function */
-  0,           /* outlining_inline_function */
-  0,           /* label */
-  0,           /* handle_pch */
-  0,           /* var_location */
-  0,           /* switch_text_section */
-  0,           /* direct_call */
-  0,           /* virtual_call_token */
-  0,           /* copy_call_info */
-  0,           /* virtual_call */
-  0,           /* set_name */
-  0            /* start_end_main_source_file */
-};
-
-#endif /* DWARF2_DEBUGGING_INFO */
 
 #include "gt-dwarf2out.h"