OSDN Git Service

PR debug/44104
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index 25b5fdc..70dbd8e 100644 (file)
@@ -1,6 +1,7 @@
 /* Output Dwarf2 format symbol table information from GCC.
    Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
    Contributed by Gary Funck (gary@intrepid.com).
    Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
    Extensively modified by Jason Merrill (jason@cygnus.com).
@@ -78,7 +79,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "dwarf2out.h"
 #include "dwarf2asm.h"
 #include "toplev.h"
-#include "varray.h"
 #include "ggc.h"
 #include "md5.h"
 #include "tm_p.h"
@@ -91,6 +91,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "input.h"
 #include "gimple.h"
 #include "tree-pass.h"
+#include "tree-flow.h"
 
 #ifdef DWARF2_DEBUGGING_INFO
 static void dwarf2out_source_line (unsigned int, const char *, int, bool);
@@ -804,7 +805,7 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi)
 
       /* Emit the state save.  */
       emit_cfa_remember = false;
-      cfi_remember = new_cfi (); 
+      cfi_remember = new_cfi ();
       cfi_remember->dw_cfi_opc = DW_CFA_remember_state;
       add_fde_cfi (label, cfi_remember);
     }
@@ -1039,10 +1040,10 @@ def_cfa_1 (const char *label, dw_cfa_location *loc_p)
 
   cfi = new_cfi ();
 
-  if (loc.reg == old_cfa.reg && !loc.indirect)
+  if (loc.reg == old_cfa.reg && !loc.indirect && !old_cfa.indirect)
     {
       /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, indicating
-        the CFA register did not change but the offset did.  The data 
+        the CFA register did not change but the offset did.  The data
         factoring for DW_CFA_def_cfa_offset_sf happens in output_cfi, or
         in the assembler via the .cfi_def_cfa_offset directive.  */
       if (loc.offset < 0)
@@ -1055,7 +1056,8 @@ def_cfa_1 (const char *label, dw_cfa_location *loc_p)
 #ifndef MIPS_DEBUGGING_INFO  /* SGI dbx thinks this means no offset.  */
   else if (loc.offset == old_cfa.offset
           && old_cfa.reg != INVALID_REGNUM
-          && !loc.indirect)
+          && !loc.indirect
+          && !old_cfa.indirect)
     {
       /* Construct a "DW_CFA_def_cfa_register <register>" instruction,
         indicating the CFA register has changed to <register> but the
@@ -1114,8 +1116,8 @@ reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT
       && sreg == INVALID_REGNUM)
     {
       cfi->dw_cfi_opc = DW_CFA_expression;
-      cfi->dw_cfi_oprnd2.dw_cfi_reg_num = reg;
-      cfi->dw_cfi_oprnd1.dw_cfi_loc
+      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+      cfi->dw_cfi_oprnd2.dw_cfi_loc
        = build_cfa_aligned_loc (offset, fde->stack_realignment);
     }
   else if (sreg == INVALID_REGNUM)
@@ -1524,10 +1526,10 @@ dwarf2out_args_size (const char *label, HOST_WIDE_INT size)
   add_fde_cfi (label, cfi);
 }
 
-/* Adjust args_size based on stack adjustment OFFSET.  */
+/* Record a stack adjustment of OFFSET bytes.  */
 
 static void
-dwarf2out_args_size_adjust (HOST_WIDE_INT offset, const char *label)
+dwarf2out_stack_adjust (HOST_WIDE_INT offset, const char *label)
 {
   if (cfa.reg == STACK_POINTER_REGNUM)
     cfa.offset += offset;
@@ -1535,6 +1537,9 @@ dwarf2out_args_size_adjust (HOST_WIDE_INT offset, const char *label)
   if (cfa_store.reg == STACK_POINTER_REGNUM)
     cfa_store.offset += offset;
 
+  if (ACCUMULATE_OUTGOING_ARGS)
+    return;
+
 #ifndef STACK_GROWS_DOWNWARD
   offset = -offset;
 #endif
@@ -1549,11 +1554,11 @@ dwarf2out_args_size_adjust (HOST_WIDE_INT offset, const char *label)
 }
 
 /* Check INSN to see if it looks like a push or a stack adjustment, and
-   make a note of it if it does.  EH uses this information to find out how
-   much extra space it needs to pop off the stack.  */
+   make a note of it if it does.  EH uses this information to find out
+   how much extra space it needs to pop off the stack.  */
 
 static void
-dwarf2out_stack_adjust (rtx insn, bool after_p)
+dwarf2out_notice_stack_adjust (rtx insn, bool after_p)
 {
   HOST_WIDE_INT offset;
   const char *label;
@@ -1637,7 +1642,7 @@ dwarf2out_stack_adjust (rtx insn, bool after_p)
     return;
 
   label = dwarf2out_cfi_label (false);
-  dwarf2out_args_size_adjust (offset, label);
+  dwarf2out_stack_adjust (offset, label);
 }
 
 #endif
@@ -1882,7 +1887,7 @@ dwarf2out_frame_debug_cfa_offset (rtx set, const char *label)
   addr = XEXP (set, 0);
   gcc_assert (MEM_P (addr));
   addr = XEXP (addr, 0);
-  
+
   /* As documented, only consider extremely simple addresses.  */
   switch (GET_CODE (addr))
     {
@@ -2156,15 +2161,7 @@ dwarf2out_frame_debug_cfa_restore (rtx reg, const char *label)
                && cfa.indirect == 0
                && cfa.reg != HARD_FRAME_POINTER_REGNUM
   effects: Use DW_CFA_def_cfa_expression to define cfa
-          cfa.reg == fde->drap_reg
-
-  Rule 20:
-  (set reg fde->drap_reg)
-  constraints: fde->vdrap_reg == INVALID_REGNUM
-  effects: fde->vdrap_reg = reg.
-  (set mem fde->drap_reg)
-  constraints: fde->drap_reg_saved == 1
-  effects: none.  */
+          cfa.reg == fde->drap_reg  */
 
 static void
 dwarf2out_frame_debug_expr (rtx expr, const char *label)
@@ -2206,8 +2203,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
              && (!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 (!ACCUMULATE_OUTGOING_ARGS
-                  && GET_CODE (elem) == SET
+         else if (GET_CODE (elem) == SET
                   && par_index != 0
                   && !RTX_FRAME_RELATED_P (elem))
            {
@@ -2216,7 +2212,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
              HOST_WIDE_INT offset = stack_adjust_offset (elem, args_size, 0);
 
              if (offset != 0)
-               dwarf2out_args_size_adjust (offset, label);
+               dwarf2out_stack_adjust (offset, label);
            }
        }
       return;
@@ -2236,24 +2232,6 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
 
   fde = current_fde ();
 
-  if (REG_P (src)
-      && fde
-      && fde->drap_reg == REGNO (src)
-      && (fde->drap_reg_saved
-         || REG_P (dest)))
-    {
-      /* Rule 20 */
-      /* If we are saving dynamic realign argument pointer to a
-        register, the destination is virtual dynamic realign
-        argument pointer.  It may be used to access argument.  */
-      if (REG_P (dest))
-       {
-         gcc_assert (fde->vdrap_reg == INVALID_REGNUM);
-         fde->vdrap_reg = REGNO (dest);
-       }
-      return;
-    }
-
   switch (GET_CODE (dest))
     {
     case REG:
@@ -2709,10 +2687,13 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
   if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn))
     flush_queued_reg_saves ();
 
-  if (! RTX_FRAME_RELATED_P (insn))
+  if (!RTX_FRAME_RELATED_P (insn))
     {
+      /* ??? This should be done unconditionally since stack adjustments
+        matter if the stack pointer is not the CFA register anymore but
+        is still used to save registers.  */
       if (!ACCUMULATE_OUTGOING_ARGS)
-       dwarf2out_stack_adjust (insn, after_p);
+       dwarf2out_notice_stack_adjust (insn, after_p);
       return;
     }
 
@@ -2775,6 +2756,21 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
        handled_one = true;
        break;
 
+      case REG_CFA_SET_VDRAP:
+       n = XEXP (note, 0);
+       if (REG_P (n))
+         {
+           dw_fde_ref fde = current_fde ();
+           if (fde)
+             {
+               gcc_assert (fde->vdrap_reg == INVALID_REGNUM);
+               if (REG_P (n))
+                 fde->vdrap_reg = REGNO (n);
+             }
+         }
+       handled_one = true;
+       break;
+
       default:
        break;
       }
@@ -2870,7 +2866,7 @@ dwarf2out_begin_epilogue (rtx insn)
 void
 dwarf2out_frame_debug_restore_state (void)
 {
-  dw_cfi_ref cfi = new_cfi (); 
+  dw_cfi_ref cfi = new_cfi ();
   const char *label = dwarf2out_cfi_label (false);
 
   cfi->dw_cfi_opc = DW_CFA_restore_state;
@@ -2916,6 +2912,7 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
     case DW_CFA_same_value:
     case DW_CFA_def_cfa_register:
     case DW_CFA_register:
+    case DW_CFA_expression:
       return dw_cfi_oprnd_reg_num;
 
     case DW_CFA_def_cfa_offset:
@@ -2924,7 +2921,6 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
       return dw_cfi_oprnd_offset;
 
     case DW_CFA_def_cfa_expression:
-    case DW_CFA_expression:
       return dw_cfi_oprnd_loc;
 
     default:
@@ -2951,6 +2947,9 @@ dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
     case DW_CFA_register:
       return dw_cfi_oprnd_reg_num;
 
+    case DW_CFA_expression:
+      return dw_cfi_oprnd_loc;
+
     default:
       return dw_cfi_oprnd_unused;
     }
@@ -3053,7 +3052,7 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
     {
       r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
       dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
-                          "DW_CFA_offset, column 0x%lx", r);
+                          "DW_CFA_offset, column %#lx", r);
       off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
       dw2_asm_output_data_uleb128 (off, NULL);
     }
@@ -3061,7 +3060,7 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
     {
       r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
       dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
-                          "DW_CFA_restore, column 0x%lx", r);
+                          "DW_CFA_restore, column %#lx", r);
     }
   else
     {
@@ -3253,7 +3252,7 @@ output_cfi_directive (dw_cfi_ref cfi)
       break;
 
     case DW_CFA_GNU_args_size:
-      fprintf (asm_out_file, "\t.cfi_escape 0x%x,", DW_CFA_GNU_args_size);
+      fprintf (asm_out_file, "\t.cfi_escape %#x,", DW_CFA_GNU_args_size);
       dw2_asm_output_data_uleb128_raw (cfi->dw_cfi_oprnd1.dw_cfi_offset);
       if (flag_debug_asm)
        fprintf (asm_out_file, "\t%s args_size "HOST_WIDE_INT_PRINT_DEC,
@@ -3267,7 +3266,7 @@ output_cfi_directive (dw_cfi_ref cfi)
 
     case DW_CFA_def_cfa_expression:
     case DW_CFA_expression:
-      fprintf (asm_out_file, "\t.cfi_escape 0x%x,", cfi->dw_cfi_opc);
+      fprintf (asm_out_file, "\t.cfi_escape %#x,", cfi->dw_cfi_opc);
       output_cfa_loc_raw (cfi);
       fputc ('\n', asm_out_file);
       break;
@@ -3773,6 +3772,11 @@ output_call_frame_info (int for_eh)
     }
 
   dw2_asm_output_nstring (augmentation, -1, "CIE Augmentation");
+  if (dw_cie_version >= 4)
+    {
+      dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "CIE Address Size");
+      dw2_asm_output_data (1, 0, "CIE Segment Size");
+    }
   dw2_asm_output_data_uleb128 (1, "CIE Code Alignment Factor");
   dw2_asm_output_data_sleb128 (DWARF_CIE_DATA_ALIGNMENT,
                               "CIE Data Alignment Factor");
@@ -3865,7 +3869,7 @@ dwarf2out_do_cfi_startproc (bool second)
       if (enc & DW_EH_PE_indirect)
        ref = dw2_force_const_mem (ref, true);
 
-      fprintf (asm_out_file, "\t.cfi_personality 0x%x,", enc);
+      fprintf (asm_out_file, "\t.cfi_personality %#x,", enc);
       output_addr_const (asm_out_file, ref);
       fputc ('\n', asm_out_file);
     }
@@ -3883,7 +3887,7 @@ dwarf2out_do_cfi_startproc (bool second)
       if (enc & DW_EH_PE_indirect)
        ref = dw2_force_const_mem (ref, true);
 
-      fprintf (asm_out_file, "\t.cfi_lsda 0x%x,", enc);
+      fprintf (asm_out_file, "\t.cfi_lsda %#x,", enc);
       output_addr_const (asm_out_file, ref);
       fputc ('\n', asm_out_file);
     }
@@ -4781,6 +4785,10 @@ size_of_loc_descr (dw_loc_descr_ref loc)
     case DW_OP_piece:
       size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
       break;
+    case DW_OP_bit_piece:
+      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+      size += size_of_uleb128 (loc->dw_loc_oprnd2.v.val_unsigned);
+      break;
     case DW_OP_deref_size:
     case DW_OP_xderef_size:
       size += 1;
@@ -5005,6 +5013,10 @@ output_loc_operands (dw_loc_descr_ref loc)
     case DW_OP_piece:
       dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
       break;
+    case DW_OP_bit_piece:
+      dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+      dw2_asm_output_data_uleb128 (val2->v.val_unsigned, NULL);
+      break;
     case DW_OP_deref_size:
     case DW_OP_xderef_size:
       dw2_asm_output_data (1, val1->v.val_int, NULL);
@@ -5120,6 +5132,12 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
       dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
       break;
 
+    case DW_OP_bit_piece:
+      fputc (',', asm_out_file);
+      dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
+      dw2_asm_output_data_uleb128_raw (val2->v.val_unsigned);
+      break;
+
     case DW_OP_consts:
     case DW_OP_breg0:
     case DW_OP_breg1:
@@ -5177,7 +5195,7 @@ output_loc_sequence_raw (dw_loc_descr_ref loc)
   while (1)
     {
       /* Output the opcode.  */
-      fprintf (asm_out_file, "0x%x", loc->dw_loc_opc);
+      fprintf (asm_out_file, "%#x", loc->dw_loc_opc);
       output_loc_operands_raw (loc);
 
       if (!loc->dw_loc_next)
@@ -5198,10 +5216,14 @@ output_cfa_loc (dw_cfi_ref cfi)
   unsigned long size;
 
   if (cfi->dw_cfi_opc == DW_CFA_expression)
-    dw2_asm_output_data (1, cfi->dw_cfi_oprnd2.dw_cfi_reg_num, NULL);
+    {
+      dw2_asm_output_data (1, cfi->dw_cfi_oprnd1.dw_cfi_reg_num, NULL);
+      loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
+    }
+  else
+    loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
 
   /* Output the size of the block.  */
-  loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
   size = size_of_locs (loc);
   dw2_asm_output_data_uleb128 (size, NULL);
 
@@ -5218,10 +5240,14 @@ output_cfa_loc_raw (dw_cfi_ref cfi)
   unsigned long size;
 
   if (cfi->dw_cfi_opc == DW_CFA_expression)
-    fprintf (asm_out_file, "0x%x,", cfi->dw_cfi_oprnd2.dw_cfi_reg_num);
+    {
+      fprintf (asm_out_file, "%#x,", cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+      loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
+    }
+  else
+    loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
 
   /* Output the size of the block.  */
-  loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
   size = size_of_locs (loc);
   dw2_asm_output_data_uleb128_raw (size);
   fputc (',', asm_out_file);
@@ -5404,6 +5430,7 @@ static void dwarf2out_define (unsigned int, const char *);
 static void dwarf2out_undef (unsigned int, const char *);
 static void dwarf2out_start_source_file (unsigned, const char *);
 static void dwarf2out_end_source_file (unsigned);
+static void dwarf2out_function_decl (tree);
 static void dwarf2out_begin_block (unsigned, unsigned);
 static void dwarf2out_end_block (unsigned, unsigned);
 static bool dwarf2out_ignore_block (const_tree);
@@ -5441,7 +5468,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   dwarf2out_end_epilogue,
   dwarf2out_begin_function,
   debug_nothing_int,           /* end_function */
-  dwarf2out_decl,              /* function_decl */
+  dwarf2out_function_decl,     /* function_decl */
   dwarf2out_global_decl,
   dwarf2out_type_decl,         /* type_decl */
   dwarf2out_imported_module_or_decl,
@@ -5682,6 +5709,11 @@ skeleton_chain_node;
    is not made available by the GCC front-end.  */
 #define        DWARF_LINE_DEFAULT_IS_STMT_START 1
 
+/* Maximum number of operations per instruction bundle.  */
+#ifndef DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN
+#define DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN 1
+#endif
+
 #ifdef DWARF2_DEBUGGING_INFO
 /* This location is used by calc_die_sizes() to keep track
    the offset of each DIE within the .debug_info section.  */
@@ -5698,8 +5730,7 @@ static GTY(()) comdat_type_node *comdat_type_list;
 static GTY(()) limbo_die_node *limbo_die_list;
 
 /* A list of DIEs for which we may have to generate
-   DW_AT_MIPS_linkage_name once their DECL_ASSEMBLER_NAMEs are
-   set.  */
+   DW_AT_{,MIPS_}linkage_name once their DECL_ASSEMBLER_NAMEs are set.  */
 static GTY(()) limbo_die_node *deferred_asm_name;
 
 /* Filenames referenced by this compilation unit.  */
@@ -5723,9 +5754,16 @@ DEF_VEC_ALLOC_O(die_arg_entry,gc);
 
 /* Node of the variable location list.  */
 struct GTY ((chain_next ("%h.next"))) var_loc_node {
-  rtx GTY (()) var_loc_note;
+  /* Either NOTE_INSN_VAR_LOCATION, or, for SRA optimized variables,
+     EXPR_LIST chain.  For small bitsizes, bitsize is encoded
+     in mode of the EXPR_LIST node and first EXPR_LIST operand
+     is either NOTE_INSN_VAR_LOCATION for a piece with a known
+     location or NULL for padding.  For larger bitsizes,
+     mode is 0 and first operand is a CONCAT with bitsize
+     as first CONCAT operand and NOTE_INSN_VAR_LOCATION resp.
+     NULL as second operand.  */
+  rtx GTY (()) loc;
   const char * GTY (()) label;
-  const char * GTY (()) section_label;
   struct var_loc_node * GTY (()) next;
 };
 
@@ -5733,8 +5771,12 @@ struct GTY ((chain_next ("%h.next"))) var_loc_node {
 struct GTY (()) var_loc_list_def {
   struct var_loc_node * GTY (()) first;
 
-  /* Do not mark the last element of the chained list because
-     it is marked through the chain.  */
+  /* Pointer to the last but one or last element of the
+     chained list.  If the list is empty, both first and
+     last are NULL, if the list contains just one node
+     or the last node certainly is not redundant, it points
+     to the last node, otherwise points to the last but one.
+     Do not mark it for GC because it is marked through the chain.  */
   struct var_loc_node * GTY ((skip ("%h"))) last;
 
   /* DECL_UID of the variable decl.  */
@@ -5958,9 +6000,7 @@ static const char *get_AT_string (dw_die_ref, enum dwarf_attribute);
 static int get_AT_flag (dw_die_ref, enum dwarf_attribute);
 static unsigned get_AT_unsigned (dw_die_ref, enum dwarf_attribute);
 static inline dw_die_ref get_AT_ref (dw_die_ref, enum dwarf_attribute);
-static bool is_c_family (void);
 static bool is_cxx (void);
-static bool is_java (void);
 static bool is_fortran (void);
 static bool is_ada (void);
 static void remove_AT (dw_die_ref, enum dwarf_attribute);
@@ -5978,7 +6018,7 @@ static hashval_t decl_loc_table_hash (const void *);
 static int decl_loc_table_eq (const void *, const void *);
 static var_loc_list *lookup_decl_loc (const_tree);
 static void equate_decl_number_to_die (tree, dw_die_ref);
-static void add_var_loc_to_decl (tree, struct var_loc_node *);
+static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *);
 static void print_spaces (FILE *);
 static void print_die (dw_die_ref, FILE *);
 static void print_dwarf_line_table (FILE *);
@@ -6057,7 +6097,8 @@ static void add_arange (tree, dw_die_ref);
 static void output_aranges (void);
 static unsigned int add_ranges_num (int);
 static unsigned int add_ranges (const_tree);
-static unsigned int add_ranges_by_labels (const char *, const char *);
+static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
+                                 bool *);
 static void output_ranges (void);
 static void output_line_info (void);
 static void output_file_names (void);
@@ -6098,6 +6139,7 @@ static void add_AT_location_description   (dw_die_ref, enum dwarf_attribute,
 static void add_data_member_location_attribute (dw_die_ref, tree);
 static bool add_const_value_attribute (dw_die_ref, rtx);
 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,
@@ -6172,10 +6214,7 @@ static void gen_generic_params_dies (tree);
 static void splice_child_die (dw_die_ref, dw_die_ref);
 static int file_info_cmp (const void *, const void *);
 static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
-                                    const char *, const char *, unsigned);
-static void add_loc_descr_to_loc_list (dw_loc_list_ref *, dw_loc_descr_ref,
-                                      const char *, const char *,
-                                      const char *);
+                                    const char *, const char *);
 static void output_loc_list (dw_loc_list_ref);
 static char *gen_internal_sym (const char *);
 
@@ -6266,6 +6305,12 @@ static void gen_remaining_tmpl_value_param_die_attribute (void);
 #define DEBUG_MACINFO_SECTION_LABEL     "Ldebug_macinfo"
 #endif
 
+/* Mangled name attribute to use.  This used to be a vendor extension
+   until DWARF 4 standardized it.  */
+#define AT_linkage_name \
+  (dwarf_version >= 4 ? DW_AT_linkage_name : DW_AT_MIPS_linkage_name)
+
+
 /* Definitions of defaults for formats and names of various special
    (artificial) labels which may be generated within this file (when the -g
    options is used and DWARF2_DEBUGGING_INFO is in effect.
@@ -7209,6 +7254,13 @@ AT_loc_list (dw_attr_ref a)
   return a->dw_attr_val.v.val_loc_list;
 }
 
+static inline dw_loc_list_ref *
+AT_loc_list_ptr (dw_attr_ref a)
+{
+  gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
+  return &a->dw_attr_val.v.val_loc_list;
+}
+
 /* Add an address constant attribute value to a DIE.  */
 
 static inline void
@@ -7432,18 +7484,6 @@ get_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind)
   return a ? AT_file (a) : NULL;
 }
 
-/* Return TRUE if the language is C or C++.  */
-
-static inline bool
-is_c_family (void)
-{
-  unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
-
-  return (lang == DW_LANG_C || lang == DW_LANG_C89 || lang == DW_LANG_ObjC
-         || lang == DW_LANG_C99
-         || lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus);
-}
-
 /* Return TRUE if the language is C++.  */
 
 static inline bool
@@ -7466,16 +7506,6 @@ is_fortran (void)
          || lang == DW_LANG_Fortran95);
 }
 
-/* Return TRUE if the language is Java.  */
-
-static inline bool
-is_java (void)
-{
-  unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
-
-  return lang == DW_LANG_Java;
-}
-
 /* Return TRUE if the language is Ada.  */
 
 static inline bool
@@ -7750,15 +7780,175 @@ equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
   decl_die->decl_id = decl_id;
 }
 
-/* Add a variable location node to the linked list for DECL.  */
+/* Return how many bits covers PIECE EXPR_LIST.  */
+
+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));
+}
+
+/* Return pointer to the location of location note in PIECE EXPR_LIST.  */
+
+static rtx *
+decl_piece_varloc_ptr (rtx piece)
+{
+  if ((int) GET_MODE (piece))
+    return &XEXP (piece, 0);
+  else
+    return &XEXP (XEXP (piece, 0), 1);
+}
+
+/* Create an EXPR_LIST for location note LOC_NOTE covering BITSIZE bits.
+   Next is the chain of following piece nodes.  */
+
+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);
+}
+
+/* Return rtx that should be stored into loc field for
+   LOC_NOTE and BITPOS/BITSIZE.  */
+
+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;
+}
+
+/* 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
-add_var_loc_to_decl (tree decl, struct var_loc_node *loc)
+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)
 {
-  unsigned int decl_id = DECL_UID (decl);
+  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)
+    {
+      *dest = decl_piece_node (*decl_piece_varloc_ptr (*src),
+                              decl_piece_bitsize (*src), NULL_RTX);
+      dest = &XEXP (*dest, 1);
+      src = &XEXP (*src, 1);
+    }
+}
+
+/* Add a variable location node to the linked list for DECL.  */
+
+static struct var_loc_node *
+add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
+{
+  unsigned int decl_id;
   var_loc_list *temp;
   void **slot;
+  struct var_loc_node *loc = NULL;
+  HOST_WIDE_INT bitsize = -1, bitpos = -1;
+
+  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;
+       }
+    }
 
+  decl_id = DECL_UID (decl);
   slot = htab_find_slot_with_hash (decl_loc_table, decl, decl_id, INSERT);
   if (*slot == NULL)
     {
@@ -7771,29 +7961,110 @@ add_var_loc_to_decl (tree decl, struct var_loc_node *loc)
 
   if (temp->last)
     {
+      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);
+             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 ((!rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->last->var_loc_note),
-                        NOTE_VAR_LOCATION_LOC (loc->var_loc_note)))
-         || ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note)
-              != NOTE_VAR_LOCATION_STATUS (loc->var_loc_note))
-             && ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note)
+      if (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->var_loc_note)
+                 || (NOTE_VAR_LOCATION_STATUS (loc_note)
                      == VAR_INIT_STATUS_UNINITIALIZED))))
        {
-         /* Add LOC to the end of list and update LAST.  */
-         temp->last->next = loc;
-         temp->last = loc;
+         /* Add LOC to the end of list and update LAST.  If the last
+            element of the list has been removed above, reuse its
+            memory for the new node, otherwise allocate a new one.  */
+         if (unused)
+           {
+             loc = unused;
+             memset (loc, '\0', sizeof (*loc));
+           }
+         else
+           loc = GGC_CNEW (struct var_loc_node);
+         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);
     }
-  /* Do not add empty location to the beginning of the list.  */
-  else if (NOTE_VAR_LOCATION_LOC (loc->var_loc_note) != NULL_RTX)
+  else
     {
+      loc = GGC_CNEW (struct var_loc_node);
       temp->first = loc;
       temp->last = loc;
+      loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
     }
+  return loc;
 }
 \f
 /* Keep track of the number of spaces used to indent the
@@ -8250,6 +8521,7 @@ attr_checksum_ordered (enum dwarf_tag tag, dw_attr_ref at,
       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))
@@ -8964,6 +9236,7 @@ is_type_die (dw_die_ref die)
     case DW_TAG_enumeration_type:
     case DW_TAG_pointer_type:
     case DW_TAG_reference_type:
+    case DW_TAG_rvalue_reference_type:
     case DW_TAG_string_type:
     case DW_TAG_structure_type:
     case DW_TAG_subroutine_type:
@@ -9001,6 +9274,7 @@ is_comdat_die (dw_die_ref c)
 
   if (c->die_tag == DW_TAG_pointer_type
       || c->die_tag == DW_TAG_reference_type
+      || c->die_tag == DW_TAG_rvalue_reference_type
       || c->die_tag == DW_TAG_const_type
       || c->die_tag == DW_TAG_volatile_type)
     {
@@ -9249,6 +9523,7 @@ should_move_die_to_comdat (dw_die_ref die)
     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:
@@ -9332,6 +9607,7 @@ clone_as_declaration (dw_die_ref die)
         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;
@@ -9605,7 +9881,7 @@ htab_decl_del (void *what)
   free (entry);
 }
 
-/* Copy DIE and its ancestors, up to, but not including, the compile unit 
+/* 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.  */
@@ -9906,7 +10182,10 @@ size_of_die (dw_die_ref die)
            unsigned long lsize = size_of_locs (AT_loc (a));
 
            /* Block length.  */
-           size += constant_size (lsize);
+           if (dwarf_version >= 4)
+             size += size_of_uleb128 (lsize);
+           else
+             size += constant_size (lsize);
            size += lsize;
          }
          break;
@@ -9934,7 +10213,16 @@ size_of_die (dw_die_ref die)
                    * a->dw_attr_val.v.val_vec.elt_size; /* block */
          break;
        case dw_val_class_flag:
-         size += 1;
+         if (dwarf_version >= 4)
+           /* Currently all add_AT_flag calls pass in 1 as last argument,
+              so DW_FORM_flag_present can be used.  If that ever changes,
+              we'll need to use DW_FORM_flag and have some optimization
+              in build_abbrev_table that will change those to
+              DW_FORM_flag_present if it is set to 1 in all DIEs using
+              the same abbrev entry.  */
+           gcc_assert (a->dw_attr_val.v.val_flag == 1);
+         else
+           size += 1;
          break;
        case dw_val_class_die_ref:
          if (AT_ref_external (a))
@@ -10128,8 +10416,11 @@ value_format (dw_attr_ref a)
          gcc_unreachable ();
        }
     case dw_val_class_range_list:
-    case dw_val_class_offset:
     case dw_val_class_loc_list:
+      if (dwarf_version >= 4)
+       return DW_FORM_sec_offset;
+      /* FALLTHRU */
+    case dw_val_class_offset:
       switch (DWARF_OFFSET_SIZE)
        {
        case 4:
@@ -10140,6 +10431,8 @@ value_format (dw_attr_ref a)
          gcc_unreachable ();
        }
     case dw_val_class_loc:
+      if (dwarf_version >= 4)
+       return DW_FORM_exprloc;
       switch (constant_size (size_of_locs (AT_loc (a))))
        {
        case 1:
@@ -10192,6 +10485,17 @@ value_format (dw_attr_ref a)
          gcc_unreachable ();
        }
     case dw_val_class_flag:
+      if (dwarf_version >= 4)
+       {
+         /* Currently all add_AT_flag calls pass in 1 as last argument,
+            so DW_FORM_flag_present can be used.  If that ever changes,
+            we'll need to use DW_FORM_flag and have some optimization
+            in build_abbrev_table that will change those to
+            DW_FORM_flag_present if it is set to 1 in all DIEs using
+            the same abbrev entry.  */
+         gcc_assert (a->dw_attr_val.v.val_flag == 1);
+         return DW_FORM_flag_present;
+       }
       return DW_FORM_flag;
     case dw_val_class_die_ref:
       if (AT_ref_external (a))
@@ -10204,7 +10508,7 @@ value_format (dw_attr_ref a)
       return DW_FORM_addr;
     case dw_val_class_lineptr:
     case dw_val_class_macptr:
-      return DW_FORM_data;
+      return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
     case dw_val_class_str:
       return AT_string_form (a);
     case dw_val_class_file:
@@ -10297,12 +10601,11 @@ output_die_symbol (dw_die_ref die)
 }
 
 /* Return a new location list, given the begin and end range, and the
-   expression. gensym tells us whether to generate a new internal symbol for
-   this location list node, which is done for the head of the list only.  */
+   expression.  */
 
 static inline dw_loc_list_ref
 new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
-             const char *section, unsigned int gensym)
+             const char *section)
 {
   dw_loc_list_ref retlist = GGC_CNEW (dw_loc_list_node);
 
@@ -10310,27 +10613,18 @@ new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
   retlist->end = end;
   retlist->expr = expr;
   retlist->section = section;
-  if (gensym)
-    retlist->ll_symbol = gen_internal_sym ("LLST");
 
   return retlist;
 }
 
-/* Add a location description expression to a location list.  */
+/* Generate a new internal symbol for this location list node, if it
+   hasn't got one yet.  */
 
 static inline void
-add_loc_descr_to_loc_list (dw_loc_list_ref *list_head, dw_loc_descr_ref descr,
-                          const char *begin, const char *end,
-                          const char *section)
+gen_llsym (dw_loc_list_ref list)
 {
-  dw_loc_list_ref *d;
-
-  /* Find the end of the chain.  */
-  for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
-    ;
-
-  /* Add a new location list node to the list.  */
-  *d = new_loc_list (descr, begin, end, section, 0);
+  gcc_assert (!list->ll_symbol);
+  list->ll_symbol = gen_internal_sym ("LLST");
 }
 
 /* Output the location list given to us.  */
@@ -10411,7 +10705,7 @@ output_die (dw_die_ref die)
   if (dwarf_version < 4 && die->die_id.die_symbol)
     output_die_symbol (die);
 
-  dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (0x%lx) %s)",
+  dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
                               (unsigned long)die->die_offset,
                               dwarf_tag_name (die->die_tag));
 
@@ -10446,7 +10740,10 @@ output_die (dw_die_ref die)
          size = size_of_locs (AT_loc (a));
 
          /* Output the block length for this list of location operations.  */
-         dw2_asm_output_data (constant_size (size), size, "%s", name);
+         if (dwarf_version >= 4)
+           dw2_asm_output_data_uleb128 (size, "%s", name);
+         else
+           dw2_asm_output_data (constant_size (size), size, "%s", name);
 
          output_loc_sequence (AT_loc (a));
          break;
@@ -10514,6 +10811,20 @@ output_die (dw_die_ref die)
          }
 
        case dw_val_class_flag:
+         if (dwarf_version >= 4)
+           {
+             /* Currently all add_AT_flag calls pass in 1 as last argument,
+                so DW_FORM_flag_present can be used.  If that ever changes,
+                we'll need to use DW_FORM_flag and have some optimization
+                in build_abbrev_table that will change those to
+                DW_FORM_flag_present if it is set to 1 in all DIEs using
+                the same abbrev entry.  */
+             gcc_assert (AT_flag (a) == 1);
+             if (flag_debug_asm)
+               fprintf (asm_out_file, "\t\t\t%s %s\n",
+                        ASM_COMMENT_START, name);
+             break;
+           }
          dw2_asm_output_data (1, AT_flag (a), "%s", name);
          break;
 
@@ -10626,7 +10937,7 @@ output_die (dw_die_ref die)
 
   /* Add null byte to terminate sibling list.  */
   if (die->die_child != NULL)
-    dw2_asm_output_data (1, 0, "end of children of DIE 0x%lx",
+    dw2_asm_output_data (1, 0, "end of children of DIE %#lx",
                         (unsigned long) die->die_offset);
 }
 
@@ -10638,11 +10949,6 @@ output_compilation_unit_header (void)
 {
   int ver = dwarf_version;
 
-  /* Don't mark the output as DWARF-4 until we make full use of the
-     version 4 extensions, and gdb supports them.  For now, -gdwarf-4
-     selects only a few extensions from the DWARF-4 spec.  */
-  if (ver > 3)
-    ver = 3;
   if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
     dw2_asm_output_data (4, 0xffffffff,
       "Initial length escape value indicating 64-bit DWARF extension");
@@ -11023,10 +11329,12 @@ add_ranges (const_tree block)
 /* Add a new entry to .debug_ranges corresponding to a pair of
    labels.  */
 
-static unsigned int
-add_ranges_by_labels (const char *begin, const char *end)
+static void
+add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
+                     bool *added)
 {
   unsigned int in_use = ranges_by_label_in_use;
+  unsigned int offset;
 
   if (in_use == ranges_by_label_allocated)
     {
@@ -11043,14 +11351,19 @@ add_ranges_by_labels (const char *begin, const char *end)
   ranges_by_label[in_use].end = end;
   ranges_by_label_in_use = in_use + 1;
 
-  return add_ranges_num (-(int)in_use - 1);
+  offset = add_ranges_num (-(int)in_use - 1);
+  if (!*added)
+    {
+      add_AT_range_list (die, DW_AT_ranges, offset);
+      *added = true;
+    }
 }
 
 static void
 output_ranges (void)
 {
   unsigned i;
-  static const char *const start_fmt = "Offset 0x%x";
+  static const char *const start_fmt = "Offset %#x";
   const char *fmt = start_fmt;
 
   for (i = 0; i < ranges_table_in_use; i++)
@@ -11392,7 +11705,7 @@ output_file_names (void)
     dw2_asm_output_nstring (dirs[i].path,
                            dirs[i].length
                             - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
-                           "Directory Entry: 0x%x", i + idx_offset);
+                           "Directory Entry: %#x", i + idx_offset);
 
   dw2_asm_output_data (1, 0, "End directory table");
 
@@ -11428,7 +11741,7 @@ output_file_names (void)
                files[file_idx].path + dirs[dir_idx].length, ver);
 
       dw2_asm_output_nstring
-       (filebuf, -1, "File Entry: 0x%x", (unsigned) i + 1);
+       (filebuf, -1, "File Entry: %#x", (unsigned) i + 1);
 
       /* Include directory index.  */
       dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
@@ -11446,7 +11759,7 @@ output_file_names (void)
         NULL);
 #else
       dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
-                             "File Entry: 0x%x", (unsigned) i + 1);
+                             "File Entry: %#x", (unsigned) i + 1);
 
       /* Include directory index.  */
       dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
@@ -11482,12 +11795,6 @@ output_line_info (void)
   unsigned long function;
   int ver = dwarf_version;
 
-  /* Don't mark the output as DWARF-4 until we make full use of the
-     version 4 extensions, and gdb supports them.  For now, -gdwarf-4
-     selects only a few extensions from the DWARF-4 spec.  */
-  if (ver > 3)
-    ver = 3;
-
   ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (p1, LN_PROLOG_AS_LABEL, 0);
@@ -11515,6 +11822,9 @@ output_line_info (void)
   dw2_asm_output_data (1, 1,
                       "Minimum Instruction Length");
 
+  if (ver >= 4)
+    dw2_asm_output_data (1, DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN,
+                        "Maximum Operations Per Instruction");
   dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START,
                       "Default is_stmt_start flag");
   dw2_asm_output_data (1, DWARF_LINE_BASE,
@@ -11540,7 +11850,7 @@ output_line_info (void)
          break;
        }
 
-      dw2_asm_output_data (1, n_op_args, "opcode: 0x%x has %d args",
+      dw2_asm_output_data (1, n_op_args, "opcode: %#x has %d args",
                           opc, n_op_args);
     }
 
@@ -11985,10 +12295,6 @@ base_type_die (tree type)
 
   base_type_result = new_die (DW_TAG_base_type, comp_unit_die, type);
 
-  /* This probably indicates a bug.  */
-  if (! TYPE_NAME (type))
-    add_name_attribute (base_type_result, "__unknown__");
-
   add_AT_unsigned (base_type_result, DW_AT_byte_size,
                   int_size_in_bytes (type));
   add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
@@ -12106,6 +12412,21 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
                          ((is_const_type ? TYPE_QUAL_CONST : 0)
                           | (is_volatile_type ? TYPE_QUAL_VOLATILE : 0)));
 
+  if (qualified_type == sizetype
+      && TYPE_NAME (qualified_type)
+      && TREE_CODE (TYPE_NAME (qualified_type)) == TYPE_DECL)
+    {
+#ifdef ENABLE_CHECKING
+      gcc_assert (TREE_CODE (TREE_TYPE (TYPE_NAME (qualified_type)))
+                 == INTEGER_TYPE
+                 && TYPE_PRECISION (TREE_TYPE (TYPE_NAME (qualified_type)))
+                    == TYPE_PRECISION (qualified_type)
+                 && TYPE_UNSIGNED (TREE_TYPE (TYPE_NAME (qualified_type)))
+                    == TYPE_UNSIGNED (qualified_type));
+#endif
+      qualified_type = TREE_TYPE (TYPE_NAME (qualified_type));
+    }
+
   /* If we do, then we can just use its DIE, if it exists.  */
   if (qualified_type)
     {
@@ -12117,7 +12438,8 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
   name = qualified_type ? TYPE_NAME (qualified_type) : NULL;
 
   /* Handle C typedef types.  */
-  if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name))
+  if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name)
+      && !DECL_ARTIFICIAL (name))
     {
       tree dtype = TREE_TYPE (name);
 
@@ -12162,7 +12484,11 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
     }
   else if (code == REFERENCE_TYPE)
     {
-      mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die, type);
+      if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4)
+       mod_type_die = new_die (DW_TAG_rvalue_reference_type, comp_unit_die,
+                               type);
+      else
+       mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die, type);
       add_AT_unsigned (mod_type_die, DW_AT_byte_size,
                       simple_type_size_in_bits (type) / BITS_PER_UNIT);
       item_type = TREE_TYPE (type);
@@ -12217,6 +12543,9 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
        name = DECL_NAME (name);
       add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
     }
+  /* This probably indicates a bug.  */
+  else if (mod_type_die && mod_type_die->die_tag == DW_TAG_base_type)
+    add_name_attribute (mod_type_die, "__unknown__");
 
   if (qualified_type)
     equate_type_number_to_die (qualified_type, mod_type_die);
@@ -12725,13 +13054,17 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset,
          return new_loc_descr (DW_OP_fbreg, offset, 0);
        }
     }
-  else if (fde
-          && fde->drap_reg != INVALID_REGNUM
+  else if (!optimize
+          && fde
           && (fde->drap_reg == REGNO (reg)
               || fde->vdrap_reg == REGNO (reg)))
     {
       /* Use cfa+offset to represent the location of arguments passed
-        on stack when drap is used to align stack.  */
+        on the stack when drap is used to align stack.
+        Only do this when not optimizing, for optimized code var-tracking
+        is supposed to track where the arguments live and the register
+        used as vdrap or drap in some spot might be used for something
+        else in other part of the routine.  */
       return new_loc_descr (DW_OP_fbreg, offset, 0);
     }
 
@@ -12815,6 +13148,22 @@ const_ok_for_output_1 (rtx *rtlp, void *data ATTRIBUTE_UNUSED)
 {
   rtx rtl = *rtlp;
 
+  if (GET_CODE (rtl) == UNSPEC)
+    {
+      /* If delegitimize_address couldn't do anything with the UNSPEC, assume
+        we can't express it in the debug info.  */
+#ifdef ENABLE_CHECKING
+      inform (current_function_decl
+             ? DECL_SOURCE_LOCATION (current_function_decl)
+             : UNKNOWN_LOCATION,
+             "non-delegitimized UNSPEC %d found in variable location",
+             XINT (rtl, 1));
+#endif
+      expansion_failed (NULL_TREE, rtl,
+                       "UNSPEC hasn't been delegitimized.\n");
+      return 1;
+    }
+
   if (GET_CODE (rtl) != SYMBOL_REF)
     return 0;
 
@@ -12984,7 +13333,25 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       if (mem_loc_result == NULL)
        mem_loc_result = tls_mem_loc_descriptor (rtl);
       if (mem_loc_result != 0)
-       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
+       {
+         if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE)
+           {
+             expansion_failed (NULL_TREE, rtl, "DWARF address size mismatch");
+             return 0;
+           }
+         else if (GET_MODE_SIZE (GET_MODE (rtl)) == DWARF2_ADDR_SIZE)
+           add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
+         else
+           add_loc_descr (&mem_loc_result,
+                          new_loc_descr (DW_OP_deref_size,
+                                         GET_MODE_SIZE (GET_MODE (rtl)), 0));
+       }
+      else
+       {
+         rtx new_rtl = avoid_constant_pool_reference (rtl);
+         if (new_rtl != rtl)
+           return mem_loc_descriptor (new_rtl, mode, initialized);
+       }
       break;
 
     case LO_SUM:
@@ -12998,34 +13365,6 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
         pool.  */
     case CONST:
     case SYMBOL_REF:
-      /* Alternatively, the symbol in the constant pool might be referenced
-        by a different symbol.  */
-      if (GET_CODE (rtl) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (rtl))
-       {
-         bool marked;
-         rtx tmp = get_pool_constant_mark (rtl, &marked);
-
-         if (GET_CODE (tmp) == SYMBOL_REF)
-           {
-             rtl = tmp;
-             if (CONSTANT_POOL_ADDRESS_P (tmp))
-               get_pool_constant_mark (tmp, &marked);
-             else
-               marked = true;
-           }
-
-         /* If all references to this pool constant were optimized away,
-            it was not output and thus we can't represent it.
-            FIXME: might try to use DW_OP_const_value here, though
-            DW_OP_piece complicates it.  */
-         if (!marked)
-           {
-             expansion_failed (NULL_TREE, rtl,
-                               "Constant was removed from constant pool.\n");
-             return 0;
-           }
-       }
-
       if (GET_CODE (rtl) == SYMBOL_REF
          && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
        {
@@ -13123,7 +13462,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       op = DW_OP_div;
       goto do_binop;
 
-    case MOD:
+    case UMOD:
       op = DW_OP_mod;
       goto do_binop;
 
@@ -13165,6 +13504,24 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
       break;
 
+    case MOD:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+
+      if (op0 == 0 || op1 == 0)
+       break;
+
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_over, 0, 0));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_over, 0, 0));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_div, 0, 0));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_minus, 0, 0));
+      break;
+
     case NOT:
       op = DW_OP_not;
       goto do_unop;
@@ -13217,32 +13574,72 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       goto do_scompare;
 
     do_scompare:
-      if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
-         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
-         || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+      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));
 
-      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
-      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
+         if (op_mode == VOIDmode)
+           op_mode = GET_MODE (XEXP (rtl, 1));
+         if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT)
+           break;
 
-      if (op0 == 0 || op1 == 0)
-       break;
+         op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                                   VAR_INIT_STATUS_INITIALIZED);
+         op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                                   VAR_INIT_STATUS_INITIALIZED);
 
-      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
-       {
-         int shift = DWARF2_ADDR_SIZE
-                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
-         shift *= BITS_PER_UNIT;
-         add_loc_descr (&op0, int_loc_descriptor (shift));
-         add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
-         if (CONST_INT_P (XEXP (rtl, 1)))
-           op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift);
-         else
+         if (op0 == 0 || op1 == 0)
+           break;
+
+         if (op_mode != VOIDmode
+             && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
            {
-             add_loc_descr (&op1, int_loc_descriptor (shift));
-             add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+             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));
+               }
            }
        }
 
@@ -13275,42 +13672,72 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       goto do_ucompare;
 
     do_ucompare:
-      if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
-         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
-         || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+      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));
 
-      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
-      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                               VAR_INIT_STATUS_INITIALIZED);
+         if (op_mode == VOIDmode)
+           op_mode = GET_MODE (XEXP (rtl, 1));
+         if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT)
+           break;
 
-      if (op0 == 0 || op1 == 0)
-       break;
+         op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                                   VAR_INIT_STATUS_INITIALIZED);
+         op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                                   VAR_INIT_STATUS_INITIALIZED);
 
-      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
-       {
-         HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0)));
-         add_loc_descr (&op0, int_loc_descriptor (mask));
-         add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
-         if (CONST_INT_P (XEXP (rtl, 1)))
-           op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask);
-         else
+         if (op0 == 0 || op1 == 0)
+           break;
+
+         if (op_mode != VOIDmode
+             && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
            {
-             add_loc_descr (&op1, int_loc_descriptor (mask));
-             add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
+             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));
+           {
+             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;
 
@@ -13436,8 +13863,18 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
     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 UMOD:
     case UNORDERED:
     case ORDERED:
     case UNEQ:
@@ -13464,6 +13901,10 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
     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
@@ -13589,6 +14030,12 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
                                       initialized);
       if (loc_result == NULL)
        loc_result = tls_mem_loc_descriptor (rtl);
+      if (loc_result == NULL)
+       {
+         rtx new_rtl = avoid_constant_pool_reference (rtl);
+         if (new_rtl != rtl)
+           loc_result = loc_descriptor (new_rtl, mode, initialized);
+       }
       break;
 
     case CONCAT:
@@ -13602,10 +14049,12 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
 
     case VAR_LOCATION:
       /* Single part.  */
-      if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
+      if (GET_CODE (PAT_VAR_LOCATION_LOC (rtl)) != PARALLEL)
        {
-         loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), mode,
-                                      initialized);
+         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;
        }
 
@@ -13648,15 +14097,17 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
       break;
 
     case CONST_DOUBLE:
+      if (mode == VOIDmode)
+       mode = GET_MODE (rtl);
+
       if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
        {
+         gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
+
          /* Note that a CONST_DOUBLE rtx could represent either an integer
             or a floating-point constant.  A CONST_DOUBLE is used whenever
             the constant requires more than one word in order to be
             adequately represented.  We output CONST_DOUBLEs as blocks.  */
-         if (GET_MODE (rtl) != VOIDmode)
-           mode = GET_MODE (rtl);
-
          loc_result = new_loc_descr (DW_OP_implicit_value,
                                      GET_MODE_SIZE (mode), 0);
          if (SCALAR_FLOAT_MODE_P (mode))
@@ -13673,15 +14124,16 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
          else
            {
              loc_result->dw_loc_oprnd2.val_class = dw_val_class_const_double;
-             loc_result->dw_loc_oprnd2.v.val_double.high
-               = CONST_DOUBLE_HIGH (rtl);
-             loc_result->dw_loc_oprnd2.v.val_double.low
-               = CONST_DOUBLE_LOW (rtl);
+             loc_result->dw_loc_oprnd2.v.val_double
+               = rtx_to_double_int (rtl);
            }
        }
       break;
 
     case CONST_VECTOR:
+      if (mode == VOIDmode)
+       mode = GET_MODE (rtl);
+
       if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
        {
          unsigned int elt_size = GET_MODE_UNIT_SIZE (GET_MODE (rtl));
@@ -13690,46 +14142,21 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
          unsigned int i;
          unsigned char *p;
 
-         mode = GET_MODE (rtl);
+         gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
          switch (GET_MODE_CLASS (mode))
            {
            case MODE_VECTOR_INT:
              for (i = 0, p = array; i < length; i++, p += elt_size)
                {
                  rtx elt = CONST_VECTOR_ELT (rtl, i);
-                 HOST_WIDE_INT lo, hi;
-
-                 switch (GET_CODE (elt))
-                   {
-                   case CONST_INT:
-                     lo = INTVAL (elt);
-                     hi = -(lo < 0);
-                     break;
-
-                   case CONST_DOUBLE:
-                     lo = CONST_DOUBLE_LOW (elt);
-                     hi = CONST_DOUBLE_HIGH (elt);
-                     break;
-
-                   default:
-                     gcc_unreachable ();
-                   }
+                 double_int val = rtx_to_double_int (elt);
 
                  if (elt_size <= sizeof (HOST_WIDE_INT))
-                   insert_int (lo, elt_size, p);
+                   insert_int (double_int_to_shwi (val), elt_size, p);
                  else
                    {
-                     unsigned char *p0 = p;
-                     unsigned char *p1 = p + sizeof (HOST_WIDE_INT);
-
                      gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
-                     if (WORDS_BIG_ENDIAN)
-                       {
-                         p0 = p1;
-                         p1 = p;
-                       }
-                     insert_int (lo, sizeof (HOST_WIDE_INT), p0);
-                     insert_int (hi, sizeof (HOST_WIDE_INT), p1);
+                     insert_double (val, p);
                    }
                }
              break;
@@ -13772,10 +14199,10 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
       if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
          && (dwarf_version >= 4 || !dwarf_strict))
        {
-         loc_result = new_loc_descr (DW_OP_implicit_value,
-                                     DWARF2_ADDR_SIZE, 0);
-         loc_result->dw_loc_oprnd2.val_class = dw_val_class_addr;
-         loc_result->dw_loc_oprnd2.v.val_addr = rtl;
+         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;
@@ -13837,14 +14264,6 @@ decl_by_reference_p (tree decl)
          && DECL_BY_REFERENCE (decl));
 }
 
-/* Return single element location list containing loc descr REF.  */
-
-static dw_loc_list_ref
-single_element_loc_list (dw_loc_descr_ref ref)
-{
-  return new_loc_list (ref, NULL, NULL, NULL, 0);
-}
-
 /* Helper function for dw_loc_list.  Compute proper Dwarf location descriptor
    for VARLOC.  */
 
@@ -13860,23 +14279,38 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address,
     {
       gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
       /* Single part.  */
-      if (GET_CODE (XEXP (varloc, 1)) != PARALLEL)
+      if (GET_CODE (PAT_VAR_LOCATION_LOC (varloc)) != PARALLEL)
        {
-         varloc = XEXP (XEXP (varloc, 1), 0);
+         varloc = PAT_VAR_LOCATION_LOC (varloc);
+         if (GET_CODE (varloc) == EXPR_LIST)
+           varloc = XEXP (varloc, 0);
          mode = GET_MODE (varloc);
          if (MEM_P (varloc))
            {
-             varloc = XEXP (varloc, 0);
-             have_address = 1;
+             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);
+               }
            }
-         descr = mem_loc_descriptor (varloc, mode, initialized);
+         else
+           descr = mem_loc_descriptor (varloc, mode, initialized);
        }
       else
        return 0;
     }
   else
     {
-      descr = loc_descriptor (varloc, DECL_MODE (loc), initialized);
+      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;
     }
 
@@ -13926,20 +14360,140 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address,
   return descr;
 }
 
-/* Return dwarf representation of location list representing for
-   LOC_LIST of DECL.  WANT_ADDRESS has the same meaning as in
-   loc_list_from_tree function.  */
+/* 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)
+{
+  if ((bitsize % BITS_PER_UNIT) == 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, 0);
+  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);
+         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)
+       {
+         *descr_tail = new_loc_descr_op_bit_piece (bitsize);
+         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);
+      if (*descr_tail == NULL)
+       return NULL;
+    }
+  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)
+dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
 {
   const char *endname, *secname;
-  dw_loc_list_ref list;
   rtx varloc;
   enum var_init_status initialized;
   struct var_loc_node *node;
   dw_loc_descr_ref descr;
   char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
+  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.
@@ -13952,55 +14506,59 @@ dw_loc_list (var_loc_list * loc_list, tree decl, int want_address)
      This means we have to special case the last node, and generate
      a range of [last location start, end of function label].  */
 
-  node = loc_list->first;
   secname = secname_for_decl (decl);
 
-  if (NOTE_VAR_LOCATION_LOC (node->var_loc_note))
-    initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-  else
-    initialized = VAR_INIT_STATUS_INITIALIZED;
-  varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-  descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
-
-  if (loc_list && loc_list->first != loc_list->last)
-    list = new_loc_list (descr, node->label, node->next->label, secname, 1);
-  else
-    return single_element_loc_list (descr);
-  node = node->next;
-
-  if (!node)
-    return NULL;
-
-  for (; node->next; node = node->next)
-    if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
+  for (node = loc_list->first; node; node = node->next)
+    if (GET_CODE (node->loc) == EXPR_LIST
+       || NOTE_VAR_LOCATION_LOC (node->loc) != NULL_RTX)
       {
-       /* The variable has a location between NODE->LABEL and
-          NODE->NEXT->LABEL.  */
-       initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-       varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-       descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
-       add_loc_descr_to_loc_list (&list, descr,
-                                  node->label, node->next->label, secname);
+       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);
+             }
+
+           *listp = new_loc_list (descr, node->label, endname, secname);
+           listp = &(*listp)->dw_loc_next;
+         }
       }
 
-  /* If the variable has a location at the last label
-     it keeps its location until the end of function.  */
-  if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
-    {
-      if (!current_function_decl)
-       endname = text_end_label;
-      else
-       {
-         ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
-                                      current_function_funcdef_no);
-         endname = ggc_strdup (label_id);
-       }
+  /* 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);
 
-      initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-      varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-      descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
-      add_loc_descr_to_loc_list (&list, descr, node->label, endname, secname);
-    }
   return list;
 }
 
@@ -14010,7 +14568,8 @@ dw_loc_list (var_loc_list * loc_list, tree decl, int want_address)
 static bool
 single_element_loc_list_p (dw_loc_list_ref list)
 {
-  return (!list->dw_loc_next && !list->begin && !list->end);
+  gcc_assert (!list->dw_loc_next || list->ll_symbol);
+  return !list->ll_symbol;
 }
 
 /* To each location in list LIST add loc descr REF.  */
@@ -14044,7 +14603,7 @@ add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref)
 
    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.  
+   and merging them that will need some additional work.
    Adding that will improve quality of debug info especially for SRA-ed
    structures.  */
 
@@ -14310,9 +14869,9 @@ loc_list_from_tree (tree loc, int want_address)
        rtx rtl;
        var_loc_list *loc_list = lookup_decl_loc (loc);
 
-       if (loc_list && loc_list->first
-           && (list_ret = dw_loc_list (loc_list, loc, want_address)))
+       if (loc_list && loc_list->first)
          {
+           list_ret = dw_loc_list (loc_list, loc, want_address);
            have_address = want_address != 0;
            break;
          }
@@ -14432,7 +14991,7 @@ loc_list_from_tree (tree loc, int want_address)
        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); 
+         loc_list_plus_const (list_ret, bytepos);
 
        have_address = 1;
        break;
@@ -14491,6 +15050,8 @@ loc_list_from_tree (tree loc, int want_address)
     case CEIL_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case TRUNC_DIV_EXPR:
+      if (TYPE_UNSIGNED (TREE_TYPE (loc)))
+       return 0;
       op = DW_OP_div;
       goto do_binop;
 
@@ -14502,8 +15063,25 @@ loc_list_from_tree (tree loc, int want_address)
     case CEIL_MOD_EXPR:
     case ROUND_MOD_EXPR:
     case TRUNC_MOD_EXPR:
-      op = DW_OP_mod;
-      goto do_binop;
+      if (TYPE_UNSIGNED (TREE_TYPE (loc)))
+       {
+         op = DW_OP_mod;
+         goto do_binop;
+       }
+      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+      list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0);
+      if (list_ret == 0 || list_ret1 == 0)
+       return 0;
+
+      add_loc_list (&list_ret, list_ret1);
+      if (list_ret == 0)
+       return 0;
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_over, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_over, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_div, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_mul, 0, 0));
+      add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_minus, 0, 0));
+      break;
 
     case MULT_EXPR:
       op = DW_OP_mul;
@@ -14723,7 +15301,7 @@ loc_list_from_tree (tree loc, int want_address)
        add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0));
     }
   if (ret)
-    list_ret = single_element_loc_list (ret);
+    list_ret = new_loc_list (ret, NULL, NULL, NULL);
 
   return list_ret;
 }
@@ -15041,11 +15619,11 @@ add_data_member_location_attribute (dw_die_ref die, tree decl)
       else
        {
          enum dwarf_location_atom op;
-         
+
          /* The DWARF2 standard says that we should assume that the structure
             address is already on the stack, so we can specify a structure
             field address by using DW_OP_plus_uconst.  */
-         
+
 #ifdef MIPS_DEBUGGING_INFO
          /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst
             operator correctly.  It works only if we leave the offset on the
@@ -15054,7 +15632,7 @@ add_data_member_location_attribute (dw_die_ref die, tree decl)
 #else
          op = DW_OP_plus_uconst;
 #endif
-         
+
          loc_descr = new_loc_descr (op, offset, 0);
        }
     }
@@ -15092,6 +15670,24 @@ extract_int (const unsigned char *src, unsigned int size)
   return val;
 }
 
+/* Writes double_int values to dw_vec_const array.  */
+
+static void
+insert_double (double_int val, unsigned char *dest)
+{
+  unsigned char *p0 = dest;
+  unsigned char *p1 = dest + sizeof (HOST_WIDE_INT);
+
+  if (WORDS_BIG_ENDIAN)
+    {
+      p0 = p1;
+      p1 = dest;
+    }
+
+  insert_int ((HOST_WIDE_INT) val.low, sizeof (HOST_WIDE_INT), p0);
+  insert_int ((HOST_WIDE_INT) val.high, sizeof (HOST_WIDE_INT), p1);
+}
+
 /* Writes floating point values to dw_vec_const array.  */
 
 static void
@@ -15171,39 +15767,14 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
            for (i = 0, p = array; i < length; i++, p += elt_size)
              {
                rtx elt = CONST_VECTOR_ELT (rtl, i);
-               HOST_WIDE_INT lo, hi;
-
-               switch (GET_CODE (elt))
-                 {
-                 case CONST_INT:
-                   lo = INTVAL (elt);
-                   hi = -(lo < 0);
-                   break;
-
-                 case CONST_DOUBLE:
-                   lo = CONST_DOUBLE_LOW (elt);
-                   hi = CONST_DOUBLE_HIGH (elt);
-                   break;
-
-                 default:
-                   gcc_unreachable ();
-                 }
+               double_int val = rtx_to_double_int (elt);
 
                if (elt_size <= sizeof (HOST_WIDE_INT))
-                 insert_int (lo, elt_size, p);
+                 insert_int (double_int_to_shwi (val), elt_size, p);
                else
                  {
-                   unsigned char *p0 = p;
-                   unsigned char *p1 = p + sizeof (HOST_WIDE_INT);
-
                    gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
-                   if (WORDS_BIG_ENDIAN)
-                     {
-                       p0 = p1;
-                       p1 = p;
-                     }
-                   insert_int (lo, sizeof (HOST_WIDE_INT), p0);
-                   insert_int (hi, sizeof (HOST_WIDE_INT), p1);
+                   insert_double (val, p);
                  }
              }
            break;
@@ -15225,10 +15796,20 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
       return true;
 
     case CONST_STRING:
-      resolve_one_addr (&rtl, NULL);
-      add_AT_addr (die, DW_AT_const_value, rtl);
-      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
-      return true;
+      if (dwarf_version >= 4 || !dwarf_strict)
+       {
+         dw_loc_descr_ref loc_result;
+         resolve_one_addr (&rtl, NULL);
+       rtl_addr:
+         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
+         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
+         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+         add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
+         add_AT_loc (die, DW_AT_location, loc_result);
+         VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+         return true;
+       }
+      return false;
 
     case CONST:
       if (CONSTANT_P (XEXP (rtl, 0)))
@@ -15238,9 +15819,9 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
       if (!const_ok_for_output (rtl))
        return false;
     case LABEL_REF:
-      add_AT_addr (die, DW_AT_const_value, rtl);
-      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
-      return true;
+      if (dwarf_version >= 4 || !dwarf_strict)
+       goto rtl_addr;
+      return false;
 
     case PLUS:
       /* In cases where an inlined instance of an inline function is passed
@@ -15618,10 +16199,7 @@ rtl_for_decl_location (tree decl)
       && !DECL_HARD_REGISTER (decl)
       && DECL_MODE (decl) != VOIDmode)
     {
-      rtl = DECL_RTL (decl);
-      /* Reset DECL_RTL back, as various parts of the compiler expects
-        DECL_RTL set meaning it is actually going to be output.  */
-      SET_DECL_RTL (decl, NULL);
+      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)
@@ -15717,16 +16295,19 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
      a constant value.  That way we are better to use add_const_value_attribute
      rather than expanding constant value equivalent.  */
   loc_list = lookup_decl_loc (decl);
-  if (loc_list && loc_list->first && loc_list->first == loc_list->last)
+  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))
     {
       struct var_loc_node *node;
 
       node = loc_list->first;
-      NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-      rtl = NOTE_VAR_LOCATION (node->var_loc_note);
-      if (GET_CODE (rtl) == VAR_LOCATION
-         && GET_CODE (XEXP (rtl, 1)) != PARALLEL)
-       rtl = XEXP (XEXP (rtl, 1), 0);
+      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;
@@ -16013,8 +16594,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
        if (!cfa_equal_p (&last_cfa, &next_cfa))
          {
            *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
-                                      start_label, last_label, section,
-                                      list == NULL);
+                                      start_label, last_label, section);
 
            list_tail = &(*list_tail)->dw_loc_next;
            last_cfa = next_cfa;
@@ -16035,14 +16615,16 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
   if (!cfa_equal_p (&last_cfa, &next_cfa))
     {
       *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
-                                start_label, last_label, section,
-                                list == NULL);
+                                start_label, last_label, section);
       list_tail = &(*list_tail)->dw_loc_next;
       start_label = last_label;
     }
+
   *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
-                            start_label, fde->dw_fde_end, section,
-                            list == NULL);
+                            start_label, fde->dw_fde_end, section);
+
+  if (list && list->dw_loc_next)
+    gen_llsym (list);
 
   return list;
 }
@@ -16123,6 +16705,43 @@ add_comp_dir_attribute (dw_die_ref die)
     add_AT_string (die, DW_AT_comp_dir, remap_debug_filename (wd));
 }
 
+/* Return the default for DW_AT_lower_bound, or -1 if there is not any
+   default.  */
+
+static int
+lower_bound_default (void)
+{
+  switch (get_AT_unsigned (comp_unit_die, DW_AT_language))
+    {
+    case DW_LANG_C:
+    case DW_LANG_C89:
+    case DW_LANG_C99:
+    case DW_LANG_C_plus_plus:
+    case DW_LANG_ObjC:
+    case DW_LANG_ObjC_plus_plus:
+    case DW_LANG_Java:
+      return 0;
+    case DW_LANG_Fortran77:
+    case DW_LANG_Fortran90:
+    case DW_LANG_Fortran95:
+      return 1;
+    case DW_LANG_UPC:
+    case DW_LANG_D:
+    case DW_LANG_Python:
+      return dwarf_version >= 4 ? 0 : -1;
+    case DW_LANG_Ada95:
+    case DW_LANG_Ada83:
+    case DW_LANG_Cobol74:
+    case DW_LANG_Cobol85:
+    case DW_LANG_Pascal83:
+    case DW_LANG_Modula2:
+    case DW_LANG_PLI:
+      return dwarf_version >= 4 ? 1 : -1;
+    default:
+      return -1;
+    }
+}
+
 /* Given a tree node describing an array bound (either lower or upper) output
    a representation for that bound.  */
 
@@ -16138,11 +16757,13 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
     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
-           && (((is_c_family () || is_java ()) && integer_zerop (bound))
-               || (is_fortran () && integer_onep (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
@@ -16178,7 +16799,6 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
     case RESULT_DECL:
       {
        dw_die_ref decl_die = lookup_decl_die (bound);
-       dw_loc_list_ref loc;
 
        /* ??? Can this happen, or should the variable have been bound
           first?  Probably it can, since I imagine that we try to create
@@ -16186,14 +16806,12 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
           the list, and won't have created a forward reference to a
           later parameter.  */
        if (decl_die != NULL)
-         add_AT_die_ref (subrange_die, bound_attr, decl_die);
-       else
          {
-           loc = loc_list_from_tree (bound, 0);
-           add_AT_location_description (subrange_die, bound_attr, loc);
+           add_AT_die_ref (subrange_die, bound_attr, decl_die);
+           break;
          }
-       break;
       }
+      /* FALLTHRU */
 
     default:
       {
@@ -16204,6 +16822,20 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
        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;
 
@@ -16215,11 +16847,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
        decl_die = new_die (DW_TAG_variable, ctx, bound);
        add_AT_flag (decl_die, DW_AT_artificial, 1);
        add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
-       if (list->dw_loc_next)
-         add_AT_loc_list (decl_die, DW_AT_location, list);
-       else
-         add_AT_loc (decl_die, DW_AT_location, list->expr);
-
+       add_AT_location_description (decl_die, DW_AT_location, list);
        add_AT_die_ref (subrange_die, bound_attr, decl_die);
        break;
       }
@@ -16472,7 +17100,8 @@ add_pure_or_virtual_attribute (dw_die_ref die, tree func_decl)
                                   0));
 
       /* GNU extension: Record what type this method came from originally.  */
-      if (debug_info_level > DINFO_LEVEL_TERSE)
+      if (debug_info_level > DINFO_LEVEL_TERSE
+         && DECL_CONTEXT (func_decl))
        add_AT_die_ref (die, DW_AT_containing_type,
                        lookup_type_die (DECL_CONTEXT (func_decl)));
     }
@@ -16509,8 +17138,7 @@ add_name_and_src_coords_attributes (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))
-         && !is_fortran ())
+         && !(TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl)))
        {
          /* Defer until we have an assembler name set.  */
          if (!DECL_ASSEMBLER_NAME_SET_P (decl))
@@ -16524,7 +17152,7 @@ add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
              deferred_asm_name = asm_name;
            }
          else if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
-           add_AT_string (die, DW_AT_MIPS_linkage_name,
+           add_AT_string (die, AT_linkage_name,
                           IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
        }
     }
@@ -16890,7 +17518,7 @@ gen_array_type_die (tree type, dw_die_ref context_die)
     add_subscript_info (array_die, type, collapse_nested_arrays);
 
   /* Add representation of the type of the elements of this array type and
-     emit the corresponding DIE if we haven't done it already.  */  
+     emit the corresponding DIE if we haven't done it already.  */
   element_type = TREE_TYPE (type);
   if (collapse_nested_arrays)
     while (TREE_CODE (element_type) == ARRAY_TYPE)
@@ -17042,11 +17670,11 @@ gen_descr_array_type_die (tree type, struct array_descr_info *info,
       if (info->dimen[dim].lower_bound)
        {
          /* If it is the default value, omit it.  */
-         if ((is_c_family () || is_java ())
-             && integer_zerop (info->dimen[dim].lower_bound))
-           ;
-         else if (is_fortran ()
-                  && integer_onep (info->dimen[dim].lower_bound))
+         int dflt;
+
+         if (host_integerp (info->dimen[dim].lower_bound, 0)
+             && (dflt = lower_bound_default ()) != -1
+             && tree_low_cst (info->dimen[dim].lower_bound, 0) == dflt)
            ;
          else
            add_descr_info_field (subrange_die, DW_AT_lower_bound,
@@ -17102,7 +17730,9 @@ retry_incomplete_types (void)
   int i;
 
   for (i = VEC_length (tree, incomplete_types) - 1; i >= 0; i--)
-    gen_type_die (VEC_index (tree, incomplete_types, i), comp_unit_die);
+    if (should_emit_struct_debug (VEC_index (tree, incomplete_types, i),
+                                 DINFO_USAGE_DIR_USE))
+      gen_type_die (VEC_index (tree, incomplete_types, i), comp_unit_die);
 }
 
 /* Determine what tag to use for a record type.  */
@@ -17147,6 +17777,9 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die)
                          scope_die_for (type, context_die), type);
       equate_type_number_to_die (type, type_die);
       add_name_attribute (type_die, type_tag (type));
+      if ((dwarf_version >= 4 || !dwarf_strict)
+         && ENUM_IS_SCOPED (type))
+       add_AT_flag (type_die, DW_AT_enum_class, 1);
     }
   else if (! TYPE_SIZE (type))
     return type_die;
@@ -17222,14 +17855,16 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
                          dw_die_ref context_die)
 {
   tree node_or_origin = node ? node : origin;
+  tree ultimate_origin;
   dw_die_ref parm_die
     = new_die (DW_TAG_formal_parameter, context_die, node);
 
   switch (TREE_CODE_CLASS (TREE_CODE (node_or_origin)))
     {
     case tcc_declaration:
-      if (!origin)
-        origin = decl_ultimate_origin (node);
+      ultimate_origin = decl_ultimate_origin (node_or_origin);
+      if (node || ultimate_origin)
+       origin = ultimate_origin;
       if (origin != NULL)
        add_abstract_origin_attribute (parm_die, origin);
       else
@@ -17392,7 +18027,8 @@ gen_type_die_for_member (tree type, tree member, dw_die_ref context_die)
 
   /* If we're trying to avoid duplicate debug info, we may not have
      emitted the member decl for this function.  Emit it now.  */
-  if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
+  if (TYPE_STUB_DECL (type)
+      && TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
       && ! lookup_decl_die (member))
     {
       dw_die_ref type_die;
@@ -17430,7 +18066,7 @@ dwarf2out_abstract_function (tree decl)
   dw_die_ref old_die;
   tree save_fn;
   tree context;
-  int was_abstract = DECL_ABSTRACT (decl);
+  int was_abstract;
   htab_t old_decl_loc_table;
 
   /* Make sure we have the actual abstract inline, not a clone.  */
@@ -17462,6 +18098,7 @@ dwarf2out_abstract_function (tree decl)
   current_function_decl = decl;
   push_cfun (DECL_STRUCT_FUNCTION (decl));
 
+  was_abstract = DECL_ABSTRACT (decl);
   set_decl_abstract_flags (decl, 1);
   dwarf2out_decl (decl);
   if (! was_abstract)
@@ -17835,7 +18472,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
         of the pack. Note that the set of pack arguments can be empty.
         In that case, the DW_TAG_GNU_formal_parameter_pack DIE will not have any
         children DIE.
-       
+
         Otherwise, we just consider the parameters of DECL.  */
       while (generic_decl_parm || parm)
        {
@@ -17944,15 +18581,16 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   HOST_WIDE_INT off;
   tree com_decl;
   tree decl_or_origin = decl ? decl : origin;
+  tree ultimate_origin;
   dw_die_ref var_die;
   dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL;
   dw_die_ref origin_die;
   int declaration = (DECL_EXTERNAL (decl_or_origin)
                     || class_or_namespace_scope_p (context_die));
 
-  if (!origin)
-    origin = decl_ultimate_origin (decl);
-
+  ultimate_origin = decl_ultimate_origin (decl_or_origin);
+  if (decl || ultimate_origin)
+    origin = ultimate_origin;
   com_decl = fortran_common (decl_or_origin, &off);
 
   /* Symbol in common gets emitted as a child of the common block, in the form
@@ -18057,9 +18695,9 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 
   /* If the compiler emitted a definition for the DECL declaration
      and if we already emitted a DIE for it, don't emit a second
-     DIE for it again.  */
-  if (old_die
-      && declaration)
+     DIE for it again. Allow re-declarations of DECLs that are
+     inside functions, though.  */
+  if (old_die && declaration && !local_scope_p (context_die))
     return;
 
   /* For static data members, the declaration in the class is supposed
@@ -18387,8 +19025,12 @@ gen_pointer_type_die (tree type, dw_die_ref context_die)
 static void
 gen_reference_type_die (tree type, dw_die_ref context_die)
 {
-  dw_die_ref ref_die
-    = new_die (DW_TAG_reference_type, scope_die_for (type, context_die), type);
+  dw_die_ref ref_die, scope_die = scope_die_for (type, context_die);
+
+  if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4)
+    ref_die = new_die (DW_TAG_rvalue_reference_type, scope_die, type);
+  else
+    ref_die = new_die (DW_TAG_reference_type, scope_die, type);
 
   equate_type_number_to_die (type, ref_die);
   add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die);
@@ -18468,6 +19110,20 @@ gen_compile_unit_die (const char *filename)
     }
 
   add_AT_unsigned (die, DW_AT_language, language);
+
+  switch (language)
+    {
+    case DW_LANG_Fortran77:
+    case DW_LANG_Fortran90:
+    case DW_LANG_Fortran95:
+      /* Fortran has case insensitive identifiers and the front-end
+        lowercases everything.  */
+      add_AT_unsigned (die, DW_AT_identifier_case, DW_ID_down_case);
+      break;
+    default:
+      /* The default DW_ID_case_sensitive doesn't need to be specified.  */
+      break;
+    }
   return die;
 }
 
@@ -18888,7 +19544,19 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
       break;
 
     case LANG_TYPE:
-      /* No Dwarf representation currently defined.  */
+      /* 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:
@@ -18998,10 +19666,6 @@ process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
 {
   dw_die_ref die;
   tree decl_or_origin = decl ? decl : origin;
-  tree ultimate_origin = origin ? decl_ultimate_origin (origin) : NULL;
-
-  if (ultimate_origin)
-    origin = ultimate_origin;
 
   if (TREE_CODE (decl_or_origin) == FUNCTION_DECL)
     die = lookup_decl_die (decl_or_origin);
@@ -19273,7 +19937,7 @@ static void
 gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
 {
   tree decl_or_origin = decl ? decl : origin;
-  tree class_origin = NULL;
+  tree class_origin = NULL, ultimate_origin;
 
   if (DECL_P (decl_or_origin) && DECL_IGNORED_P (decl_or_origin))
     return;
@@ -19319,7 +19983,9 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
 
       /* If we're emitting a clone, emit info for the abstract instance.  */
       if (origin || DECL_ORIGIN (decl) != decl)
-       dwarf2out_abstract_function (origin ? origin : DECL_ABSTRACT_ORIGIN (decl));
+       dwarf2out_abstract_function (origin
+                                    ? DECL_ORIGIN (origin)
+                                    : DECL_ABSTRACT_ORIGIN (decl));
 
       /* If we're emitting an out-of-line copy of an inline function,
         emit info for the abstract instance and set up to refer to it.  */
@@ -19418,9 +20084,9 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
         complicated because of the possibility that the VAR_DECL really
         represents an inlined instance of a formal parameter for an inline
         function.  */
-      if (!origin)
-        origin = decl_ultimate_origin (decl);
-      if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
+      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);
@@ -19512,10 +20178,7 @@ dwarf2out_imported_module_or_decl_1 (tree decl,
 
   if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
     {
-      if (is_base_type (TREE_TYPE (decl)))
-       at_import_die = base_type_die (TREE_TYPE (decl));
-      else
-       at_import_die = force_type_die (TREE_TYPE (decl));
+      at_import_die = force_type_die (TREE_TYPE (decl));
       /* For namespace N { typedef void T; } using N::T; base_type_die
         returns NULL, but DW_TAG_imported_declaration requires
         the DW_AT_import tag.  Force creation of DW_TAG_typedef.  */
@@ -19746,6 +20409,16 @@ dwarf2out_decl (tree decl)
   gen_decl_die (decl, NULL, context_die);
 }
 
+/* Write the debugging output for DECL.  */
+
+static void
+dwarf2out_function_decl (tree decl)
+{
+  dwarf2out_decl (decl);
+
+  htab_empty (decl_loc_table);
+}
+
 /* Output a marker (i.e. a label) for the beginning of the generated code for
    a lexical block.  */
 
@@ -19923,7 +20596,7 @@ gen_remaining_tmpl_value_param_die_attribute (void)
 
 
 /* Replace DW_AT_name for the decl with name.  */
+
 static void
 dwarf2out_set_name (tree decl, tree name)
 {
@@ -20106,21 +20779,34 @@ dwarf2out_var_location (rtx loc_note)
   if (next_real == NULL_RTX)
     return;
 
-  newloc = GGC_CNEW (struct var_loc_node);
-  /* If there were no real insns between note we processed last time
-     and this note, use the label we emitted last time.  */
+  /* If there were any real insns between note we processed last time
+     and this note (or if it is the first note), clear
+     last_{,postcall_}label so that they are not reused this time.  */
   if (last_var_location_insn == NULL_RTX
       || last_var_location_insn != next_real
       || last_in_cold_section_p != in_cold_section_p)
     {
+      last_label = NULL;
+      last_postcall_label = NULL;
+    }
+
+  decl = NOTE_VAR_LOCATION_DECL (loc_note);
+  newloc = add_var_loc_to_decl (decl, loc_note,
+                               NOTE_DURING_CALL_P (loc_note)
+                               ? last_postcall_label : last_label);
+  if (newloc == NULL)
+    return;
+
+  /* If there were no real insns between note we processed last time
+     and this note, use the label we emitted last time.  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);
-      last_postcall_label = NULL;
     }
-  newloc->var_loc_note = loc_note;
-  newloc->next = NULL;
 
   if (!NOTE_DURING_CALL_P (loc_note))
     newloc->label = last_label;
@@ -20134,15 +20820,8 @@ dwarf2out_var_location (rtx loc_note)
       newloc->label = last_postcall_label;
     }
 
-  if (cfun && in_cold_section_p)
-    newloc->section_label = crtl->subsections.cold_section_label;
-  else
-    newloc->section_label = text_section_label;
-
   last_var_location_insn = next_real;
   last_in_cold_section_p = in_cold_section_p;
-  decl = NOTE_VAR_LOCATION_DECL (loc_note);
-  add_var_loc_to_decl (decl, newloc);
 }
 
 /* We need to reset the locations at the beginning of each
@@ -20153,8 +20832,6 @@ dwarf2out_var_location (rtx loc_note)
 static void
 dwarf2out_begin_function (tree fun)
 {
-  htab_empty (decl_loc_table);
-
   if (function_section (fun) != text_section)
     have_multiple_function_sections = true;
 
@@ -20578,7 +21255,7 @@ prune_unused_types_mark (dw_die_ref die, int dokids)
         breaking out types into comdat sections, do this
         for all type definitions.  */
       if (die->die_tag == DW_TAG_array_type
-          || (dwarf_version >= 4 
+          || (dwarf_version >= 4
               && is_type_die (die) && ! is_declaration_die (die)))
        FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1));
       else
@@ -20657,6 +21334,7 @@ prune_unused_types_walk (dw_die_ref die)
     case DW_TAG_packed_type:
     case DW_TAG_pointer_type:
     case DW_TAG_reference_type:
+    case DW_TAG_rvalue_reference_type:
     case DW_TAG_volatile_type:
     case DW_TAG_typedef:
     case DW_TAG_array_type:
@@ -20876,7 +21554,7 @@ htab_ct_eq (const void *of1, const void *of2)
                     DWARF_TYPE_SIGNATURE_SIZE));
 }
 
-/* Move a DW_AT_MIPS_linkage_name attribute just added to dw_die_ref
+/* 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
@@ -20889,7 +21567,7 @@ move_linkage_attr (dw_die_ref die)
   unsigned ix = VEC_length (dw_attr_node, die->die_attr);
   dw_attr_node linkage = *VEC_index (dw_attr_node, die->die_attr, ix - 1);
 
-  gcc_assert (linkage.dw_attr == DW_AT_MIPS_linkage_name);
+  gcc_assert (linkage.dw_attr == AT_linkage_name);
 
   while (--ix > 0)
     {
@@ -20973,28 +21651,48 @@ resolve_addr (dw_die_ref die)
 {
   dw_die_ref c;
   dw_attr_ref a;
-  dw_loc_list_ref curr;
+  dw_loc_list_ref *curr;
   unsigned ix;
 
   for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
     switch (AT_class (a))
       {
       case dw_val_class_loc_list:
-       for (curr = AT_loc_list (a); curr != NULL; curr = curr->dw_loc_next)
-         if (!resolve_addr_in_expr (curr->expr))
-           curr->expr = NULL;
+       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)))
-         a->dw_attr_val.v.val_loc = NULL;
+         {
+           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))
          {
-           a->dw_attr = DW_AT_location;
-           a->dw_attr_val.val_class = dw_val_class_loc;
-           a->dw_attr_val.v.val_loc = NULL;
+           remove_AT (die, a->dw_attr);
+           ix--;
          }
        break;
       default:
@@ -21103,7 +21801,7 @@ dwarf2out_finish (const char *filename)
       tree decl = node->created_for;
       if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
        {
-         add_AT_string (node->die, DW_AT_MIPS_linkage_name,
+         add_AT_string (node->die, AT_linkage_name,
                         IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
          move_linkage_attr (node->die);
        }
@@ -21175,6 +21873,7 @@ dwarf2out_finish (const char *filename)
   else
     {
       unsigned fde_idx = 0;
+      bool range_list_added = false;
 
       /* We need to give .debug_loc and .debug_ranges an appropriate
         "base address".  Use zero so that these addresses become
@@ -21184,12 +21883,12 @@ dwarf2out_finish (const char *filename)
       add_AT_addr (comp_unit_die, DW_AT_low_pc, const0_rtx);
       add_AT_addr (comp_unit_die, DW_AT_entry_pc, const0_rtx);
 
-      add_AT_range_list (comp_unit_die, DW_AT_ranges,
-                        add_ranges_by_labels (text_section_label,
-                                              text_end_label));
-      if (flag_reorder_blocks_and_partition)
-       add_ranges_by_labels (cold_text_section_label,
-                             cold_end_label);
+      if (text_section_used)
+       add_ranges_by_labels (comp_unit_die, text_section_label,
+                             text_end_label, &range_list_added);
+      if (flag_reorder_blocks_and_partition && cold_text_section_used)
+       add_ranges_by_labels (comp_unit_die, cold_text_section_label,
+                             cold_end_label, &range_list_added);
 
       for (fde_idx = 0; fde_idx < fde_table_in_use; fde_idx++)
        {
@@ -21198,18 +21897,23 @@ dwarf2out_finish (const char *filename)
          if (fde->dw_fde_switched_sections)
            {
              if (!fde->in_std_section)
-               add_ranges_by_labels (fde->dw_fde_hot_section_label,
-                                     fde->dw_fde_hot_section_end_label);
+               add_ranges_by_labels (comp_unit_die,
+                                     fde->dw_fde_hot_section_label,
+                                     fde->dw_fde_hot_section_end_label,
+                                     &range_list_added);
              if (!fde->cold_in_std_section)
-               add_ranges_by_labels (fde->dw_fde_unlikely_section_label,
-                                     fde->dw_fde_unlikely_section_end_label);
+               add_ranges_by_labels (comp_unit_die,
+                                     fde->dw_fde_unlikely_section_label,
+                                     fde->dw_fde_unlikely_section_end_label,
+                                     &range_list_added);
            }
          else if (!fde->in_std_section)
-           add_ranges_by_labels (fde->dw_fde_begin,
-                                 fde->dw_fde_end);
+           add_ranges_by_labels (comp_unit_die, fde->dw_fde_begin,
+                                 fde->dw_fde_end, &range_list_added);
        }
 
-      add_ranges (NULL);
+      if (range_list_added)
+       add_ranges (NULL);
     }
 
   /* Output location list section if necessary.  */