OSDN Git Service

Fix for PR c++/43327
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index ec5298c..3ca61c3 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).
@@ -2159,15 +2160,7 @@ dwarf2out_frame_debug_cfa_restore (rtx reg, const char *label)
                && cfa.indirect == 0
                && cfa.reg != HARD_FRAME_POINTER_REGNUM
   effects: Use DW_CFA_def_cfa_expression to define cfa
-          cfa.reg == fde->drap_reg
-
-  Rule 20:
-  (set reg fde->drap_reg)
-  constraints: fde->vdrap_reg == INVALID_REGNUM
-  effects: fde->vdrap_reg = reg.
-  (set mem fde->drap_reg)
-  constraints: fde->drap_reg_saved == 1
-  effects: none.  */
+          cfa.reg == fde->drap_reg  */
 
 static void
 dwarf2out_frame_debug_expr (rtx expr, const char *label)
@@ -2238,24 +2231,6 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
 
   fde = current_fde ();
 
-  if (REG_P (src)
-      && fde
-      && fde->drap_reg == REGNO (src)
-      && (fde->drap_reg_saved
-         || REG_P (dest)))
-    {
-      /* Rule 20 */
-      /* If we are saving dynamic realign argument pointer to a
-        register, the destination is virtual dynamic realign
-        argument pointer.  It may be used to access argument.  */
-      if (REG_P (dest))
-       {
-         gcc_assert (fde->vdrap_reg == INVALID_REGNUM);
-         fde->vdrap_reg = REGNO (dest);
-       }
-      return;
-    }
-
   switch (GET_CODE (dest))
     {
     case REG:
@@ -2780,6 +2755,21 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
        handled_one = true;
        break;
 
+      case REG_CFA_SET_VDRAP:
+       n = XEXP (note, 0);
+       if (REG_P (n))
+         {
+           dw_fde_ref fde = current_fde ();
+           if (fde)
+             {
+               gcc_assert (fde->vdrap_reg == INVALID_REGNUM);
+               if (REG_P (n))
+                 fde->vdrap_reg = REGNO (n);
+             }
+         }
+       handled_one = true;
+       break;
+
       default:
        break;
       }
@@ -5983,7 +5973,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);
 static void print_spaces (FILE *);
 static void print_die (dw_die_ref, FILE *);
 static void print_dwarf_line_table (FILE *);
@@ -6062,7 +6052,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);
@@ -6177,10 +6168,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 *);
 
@@ -7214,6 +7202,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
@@ -7757,12 +7752,13 @@ equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
 
 /* Add a variable location node to the linked list for DECL.  */
 
-static void
-add_var_loc_to_decl (tree decl, struct var_loc_node *loc)
+static struct var_loc_node *
+add_var_loc_to_decl (tree decl, rtx loc_note)
 {
   unsigned int decl_id = DECL_UID (decl);
   var_loc_list *temp;
   void **slot;
+  struct var_loc_node *loc = NULL;
 
   slot = htab_find_slot_with_hash (decl_loc_table, decl, decl_id, INSERT);
   if (*slot == NULL)
@@ -7780,25 +7776,27 @@ add_var_loc_to_decl (tree decl, struct var_loc_node *loc)
         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_LOC (loc_note)))
          || ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note)
-              != NOTE_VAR_LOCATION_STATUS (loc->var_loc_note))
+              != NOTE_VAR_LOCATION_STATUS (loc_note))
              && ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note)
                   == VAR_INIT_STATUS_UNINITIALIZED)
-                 || (NOTE_VAR_LOCATION_STATUS (loc->var_loc_note)
+                 || (NOTE_VAR_LOCATION_STATUS (loc_note)
                      == VAR_INIT_STATUS_UNINITIALIZED))))
        {
          /* Add LOC to the end of list and update LAST.  */
+         loc = GGC_CNEW (struct var_loc_node);
          temp->last->next = loc;
          temp->last = loc;
        }
     }
-  /* Do not add empty location to the beginning of the list.  */
-  else if (NOTE_VAR_LOCATION_LOC (loc->var_loc_note) != NULL_RTX)
+  else
     {
+      loc = GGC_CNEW (struct var_loc_node);
       temp->first = loc;
       temp->last = loc;
     }
+  return loc;
 }
 \f
 /* Keep track of the number of spaces used to indent the
@@ -10302,12 +10300,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);
 
@@ -10315,27 +10312,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.  */
@@ -11028,10 +11016,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)
     {
@@ -11048,7 +11038,12 @@ 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
@@ -12730,13 +12725,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);
     }
 
@@ -12820,6 +12819,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;
 
@@ -12989,7 +13004,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:
@@ -13003,34 +13036,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)
        {
@@ -13128,7 +13133,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;
 
@@ -13170,6 +13175,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;
@@ -13222,32 +13245,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));
+               }
            }
        }
 
@@ -13280,42 +13343,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;
 
@@ -13441,8 +13534,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:
@@ -13469,6 +13572,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
@@ -13594,6 +13701,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:
@@ -13653,15 +13766,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))
@@ -13687,6 +13802,9 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
       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));
@@ -13695,7 +13813,7 @@ 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:
@@ -13777,10 +13895,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;
@@ -13842,14 +13960,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.  */
 
@@ -13871,10 +13981,19 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address,
          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;
@@ -13931,20 +14050,21 @@ 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.  */
+/* 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.
@@ -13957,26 +14077,9 @@ 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)
+  for (node = loc_list->first; node->next; node = node->next)
     if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
       {
        /* The variable has a location between NODE->LABEL and
@@ -13984,28 +14087,46 @@ dw_loc_list (var_loc_list * loc_list, tree decl, int want_address)
        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 (descr)
+         {
+           *listp = new_loc_list (descr, node->label, node->next->label,
+                                  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);
-       }
-
       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);
+      if (descr)
+       {
+         if (!current_function_decl)
+           endname = text_end_label;
+         else
+           {
+             ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+                                          current_function_funcdef_no);
+             endname = ggc_strdup (label_id);
+           }
+
+         *listp = new_loc_list (descr, node->label, endname, secname);
+         listp = &(*listp)->dw_loc_next;
+       }
     }
+
+  /* Try to avoid the overhead of a location list emitting a location
+     expression instead, but only if we didn't have more than one
+     location entry in the first place.  If some entries were not
+     representable, we don't want to pretend a single entry that was
+     applies to the entire scope in which the variable is
+     available.  */
+  if (list && loc_list->first->next)
+    gen_llsym (list);
+
   return list;
 }
 
@@ -14015,7 +14136,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.  */
@@ -14315,9 +14437,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;
          }
@@ -14496,6 +14618,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;
 
@@ -14507,8 +14631,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;
@@ -14728,7 +14869,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;
 }
@@ -15230,10 +15371,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)))
@@ -15243,9 +15394,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
@@ -15623,10 +15774,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)
@@ -15722,15 +15870,18 @@ 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 == loc_list->last
+      && NOTE_VAR_LOCATION (loc_list->first->var_loc_note)
+      && NOTE_VAR_LOCATION_LOC (loc_list->first->var_loc_note))
     {
       struct var_loc_node *node;
 
       node = loc_list->first;
-      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->var_loc_note);
+      if (GET_CODE (rtl) != PARALLEL)
+       rtl = XEXP (rtl, 0);
       if ((CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
          && add_const_value_attribute (die, rtl))
         return true;
@@ -16017,8 +16168,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;
@@ -16039,14 +16189,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;
 }
@@ -16133,6 +16285,8 @@ add_comp_dir_attribute (dw_die_ref die)
 static void
 add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree bound)
 {
+  int want_address = 2;
+
   switch (TREE_CODE (bound))
     {
     case ERROR_MARK:
@@ -16182,7 +16336,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
@@ -16190,14 +16343,13 @@ 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;
+       want_address = 0;
       }
+      /* FALLTHRU */
 
     default:
       {
@@ -16207,10 +16359,16 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
        dw_die_ref ctx, decl_die;
        dw_loc_list_ref list;
 
-       list = loc_list_from_tree (bound, 2);
+       list = loc_list_from_tree (bound, want_address);
        if (list == NULL)
          break;
 
+       if (single_element_loc_list_p (list))
+         {
+           add_AT_loc (subrange_die, bound_attr, list->expr);
+           break;
+         }
+
        if (current_function_decl == 0)
          ctx = comp_unit_die;
        else
@@ -16219,11 +16377,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;
       }
@@ -16476,7 +16630,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)));
     }
@@ -17106,7 +17261,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.  */
@@ -17226,14 +17383,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
@@ -17396,7 +17555,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;
@@ -17949,15 +18109,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
@@ -19003,10 +19164,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);
@@ -19278,7 +19435,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;
@@ -19324,7 +19481,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.  */
@@ -19423,9 +19582,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);
@@ -20111,7 +20270,11 @@ dwarf2out_var_location (rtx loc_note)
   if (next_real == NULL_RTX)
     return;
 
-  newloc = GGC_CNEW (struct var_loc_node);
+  decl = NOTE_VAR_LOCATION_DECL (loc_note);
+  newloc = add_var_loc_to_decl (decl, loc_note);
+  if (newloc == NULL)
+    return;
+
   /* If there were no real insns between note we processed last time
      and this note, use the label we emitted last time.  */
   if (last_var_location_insn == NULL_RTX
@@ -20146,8 +20309,6 @@ dwarf2out_var_location (rtx loc_note)
 
   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
@@ -20978,28 +21139,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:
@@ -21180,6 +21361,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
@@ -21189,12 +21371,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++)
        {
@@ -21203,18 +21385,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.  */