OSDN Git Service

* ira-conflicts.c: Use fputs or putc instead of fprintf
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index 0dfe4f6..62459e2 100644 (file)
@@ -163,7 +163,7 @@ dwarf2out_do_cfi_asm (void)
 #endif
   if (!flag_dwarf2_cfi_asm || !dwarf2out_do_frame ())
     return false;
-  if (saved_do_cfi_asm || !eh_personality_libfunc)
+  if (saved_do_cfi_asm)
     return true;
   if (!HAVE_GAS_CFI_PERSONALITY_DIRECTIVE)
     return false;
@@ -407,6 +407,10 @@ struct GTY(()) indirect_string_node {
 
 static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
 
+/* True if the compilation unit has location entries that reference
+   debug strings.  */
+static GTY(()) bool debug_str_hash_forced = false;
+
 static GTY(()) int dw2_string_counter;
 static GTY(()) unsigned long dwarf2out_cfi_label_num;
 
@@ -4142,15 +4146,6 @@ enum dw_val_class
   dw_val_class_file
 };
 
-/* Describe a double word constant value.  */
-/* ??? Every instance of long_long in the code really means CONST_DOUBLE.  */
-
-typedef struct GTY(()) dw_long_long_struct {
-  unsigned long hi;
-  unsigned long low;
-}
-dw_long_long_const;
-
 /* Describe a floating point constant value, or a vector constant value.  */
 
 typedef struct GTY(()) dw_vec_struct {
@@ -4173,7 +4168,7 @@ typedef struct GTY(()) dw_val_struct {
       dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
       HOST_WIDE_INT GTY ((default)) val_int;
       unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
-      dw_long_long_const GTY ((tag ("dw_val_class_long_long"))) val_long_long;
+      rtx GTY ((tag ("dw_val_class_long_long"))) val_long_long;
       dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
       struct dw_val_die_union
        {
@@ -4528,6 +4523,10 @@ dwarf_stack_op_name (unsigned int op)
       return "DW_OP_call4";
     case DW_OP_call_ref:
       return "DW_OP_call_ref";
+    case DW_OP_implicit_value:
+      return "DW_OP_implicit_value";
+    case DW_OP_stack_value:
+      return "DW_OP_stack_value";
     case DW_OP_form_tls_address:
       return "DW_OP_form_tls_address";
     case DW_OP_call_frame_cfa:
@@ -4738,6 +4737,10 @@ size_of_loc_descr (dw_loc_descr_ref loc)
     case DW_OP_call_ref:
       size += DWARF2_ADDR_SIZE;
       break;
+    case DW_OP_implicit_value:
+      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned)
+             + loc->dw_loc_oprnd1.v.val_unsigned;
+      break;
     default:
       break;
     }
@@ -4773,6 +4776,10 @@ size_of_locs (dw_loc_descr_ref loc)
   return size;
 }
 
+#ifdef DWARF2_DEBUGGING_INFO
+static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
+#endif
+
 /* Output location description stack opcode's operands (if any).  */
 
 static void
@@ -4794,7 +4801,7 @@ output_loc_operands (dw_loc_descr_ref loc)
       break;
     case DW_OP_const8u:
     case DW_OP_const8s:
-      gcc_assert (HOST_BITS_PER_LONG >= 64);
+      gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
       dw2_asm_output_data (8, val1->v.val_int, NULL);
       break;
     case DW_OP_skip:
@@ -4808,6 +4815,60 @@ output_loc_operands (dw_loc_descr_ref loc)
        dw2_asm_output_data (2, offset, NULL);
       }
       break;
+    case DW_OP_implicit_value:
+      dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+      switch (val2->val_class)
+       {
+       case dw_val_class_const:
+         dw2_asm_output_data (val1->v.val_unsigned, val2->v.val_int, NULL);
+         break;
+       case dw_val_class_vec:
+         {
+           unsigned int elt_size = val2->v.val_vec.elt_size;
+           unsigned int len = val2->v.val_vec.length;
+           unsigned int i;
+           unsigned char *p;
+
+           if (elt_size > sizeof (HOST_WIDE_INT))
+             {
+               elt_size /= 2;
+               len *= 2;
+             }
+           for (i = 0, p = val2->v.val_vec.array;
+                i < len;
+                i++, p += elt_size)
+             dw2_asm_output_data (elt_size, extract_int (p, elt_size),
+                                  "fp or vector constant word %u", i);
+         }
+         break;
+       case dw_val_class_long_long:
+         {
+           unsigned HOST_WIDE_INT first, second;
+
+           if (WORDS_BIG_ENDIAN)
+             {
+               first = CONST_DOUBLE_HIGH (val2->v.val_long_long);
+               second = CONST_DOUBLE_LOW (val2->v.val_long_long);
+             }
+           else
+             {
+               first = CONST_DOUBLE_LOW (val2->v.val_long_long);
+               second = CONST_DOUBLE_HIGH (val2->v.val_long_long);
+             }
+           dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
+                                first, "long long constant");
+           dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
+                                second, NULL);
+         }
+         break;
+       case dw_val_class_addr:
+         gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE);
+         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val2->v.val_addr, NULL);
+         break;
+       default:
+         gcc_unreachable ();
+       }
+      break;
 #else
     case DW_OP_const2u:
     case DW_OP_const2s:
@@ -4817,6 +4878,7 @@ output_loc_operands (dw_loc_descr_ref loc)
     case DW_OP_const8s:
     case DW_OP_skip:
     case DW_OP_bra:
+    case DW_OP_implicit_value:
       /* We currently don't make any attempt to make sure these are
         aligned properly like we do for the main unwind info, so
         don't support emitting things larger than a byte if we're
@@ -4948,6 +5010,7 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
   switch (loc->dw_loc_opc)
     {
     case DW_OP_addr:
+    case DW_OP_implicit_value:
       /* We cannot output addresses in .cfi_escape, only bytes.  */
       gcc_unreachable ();
 
@@ -4974,7 +5037,7 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
 
     case DW_OP_const8u:
     case DW_OP_const8s:
-      gcc_assert (HOST_BITS_PER_LONG >= 64);
+      gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
       fputc (',', asm_out_file);
       dw2_asm_output_data_raw (8, val1->v.val_int);
       break;
@@ -5719,8 +5782,7 @@ static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
 static inline HOST_WIDE_INT AT_int (dw_attr_ref);
 static void add_AT_unsigned (dw_die_ref, enum dwarf_attribute, unsigned HOST_WIDE_INT);
 static inline unsigned HOST_WIDE_INT AT_unsigned (dw_attr_ref);
-static void add_AT_long_long (dw_die_ref, enum dwarf_attribute, unsigned long,
-                             unsigned long);
+static void add_AT_long_long (dw_die_ref, enum dwarf_attribute, rtx);
 static inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int,
                               unsigned int, unsigned char *);
 static hashval_t debug_str_do_hash (const void *);
@@ -5852,7 +5914,8 @@ static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode,
                                            enum var_init_status);
 static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
                                               enum var_init_status);
-static dw_loc_descr_ref loc_descriptor (rtx, enum var_init_status);
+static dw_loc_descr_ref loc_descriptor (rtx, enum machine_mode mode,
+                                       enum var_init_status);
 static dw_loc_descr_ref loc_descriptor_from_tree_1 (tree, int);
 static dw_loc_descr_ref loc_descriptor_from_tree (tree);
 static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
@@ -5866,7 +5929,6 @@ static void add_AT_location_description   (dw_die_ref, enum dwarf_attribute,
 static void add_data_member_location_attribute (dw_die_ref, tree);
 static void add_const_value_attribute (dw_die_ref, rtx);
 static void insert_int (HOST_WIDE_INT, unsigned, unsigned char *);
-static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
 static void insert_float (const_rtx, unsigned char *);
 static rtx rtl_for_decl_location (tree);
 static void add_location_or_const_value_attribute (dw_die_ref, tree,
@@ -6652,14 +6714,13 @@ AT_unsigned (dw_attr_ref a)
 
 static inline void
 add_AT_long_long (dw_die_ref die, enum dwarf_attribute attr_kind,
-                 long unsigned int val_hi, long unsigned int val_low)
+                 rtx val_const_double)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_long_long;
-  attr.dw_attr_val.v.val_long_long.hi = val_hi;
-  attr.dw_attr_val.v.val_long_long.low = val_low;
+  attr.dw_attr_val.v.val_long_long = val_const_double;
   add_dwarf_attr (die, &attr);
 }
 
@@ -6694,6 +6755,8 @@ debug_str_eq (const void *x1, const void *x2)
                 (const char *)x2) == 0;
 }
 
+/* Add STR to the indirect string hash table.  */
+
 static struct indirect_string_node *
 find_AT_string (const char *str)
 {
@@ -6736,6 +6799,37 @@ add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str)
   add_dwarf_attr (die, &attr);
 }
 
+/* Create a label for an indirect string node, ensuring it is going to
+   be output, unless its reference count goes down to zero.  */
+
+static inline void
+gen_label_for_indirect_string (struct indirect_string_node *node)
+{
+  char label[32];
+
+  if (node->label)
+    return;
+
+  ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+  ++dw2_string_counter;
+  node->label = xstrdup (label);
+}
+
+/* Create a SYMBOL_REF rtx whose value is the initial address of a
+   debug string STR.  */
+
+static inline rtx
+get_debug_string_label (const char *str)
+{
+  struct indirect_string_node *node = find_AT_string (str);
+
+  debug_str_hash_forced = true;
+
+  gen_label_for_indirect_string (node);
+
+  return gen_rtx_SYMBOL_REF (Pmode, node->label);
+}
+
 static inline const char *
 AT_string (dw_attr_ref a)
 {
@@ -6751,7 +6845,6 @@ AT_string_form (dw_attr_ref a)
 {
   struct indirect_string_node *node;
   unsigned int len;
-  char label[32];
 
   gcc_assert (a && AT_class (a) == dw_val_class_str);
 
@@ -6774,9 +6867,7 @@ AT_string_form (dw_attr_ref a)
       && (len - DWARF_OFFSET_SIZE) * node->refcount <= len))
     return node->form = DW_FORM_string;
 
-  ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
-  ++dw2_string_counter;
-  node->label = xstrdup (label);
+  gen_label_for_indirect_string (node);
 
   return node->form = DW_FORM_strp;
 }
@@ -7489,9 +7580,10 @@ print_die (dw_die_ref die, FILE *outfile)
          fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, AT_unsigned (a));
          break;
        case dw_val_class_long_long:
-         fprintf (outfile, "constant (%lu,%lu)",
-                  a->dw_attr_val.v.val_long_long.hi,
-                  a->dw_attr_val.v.val_long_long.low);
+         fprintf (outfile, "constant (" HOST_WIDE_INT_PRINT_UNSIGNED
+                           "," HOST_WIDE_INT_PRINT_UNSIGNED ")",
+                  CONST_DOUBLE_HIGH (a->dw_attr_val.v.val_long_long),
+                  CONST_DOUBLE_LOW (a->dw_attr_val.v.val_long_long));
          break;
        case dw_val_class_vec:
          fprintf (outfile, "floating-point or vector constant");
@@ -7648,7 +7740,8 @@ attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
       CHECKSUM (at->dw_attr_val.v.val_unsigned);
       break;
     case dw_val_class_long_long:
-      CHECKSUM (at->dw_attr_val.v.val_long_long);
+      CHECKSUM (CONST_DOUBLE_HIGH (at->dw_attr_val.v.val_long_long));
+      CHECKSUM (CONST_DOUBLE_LOW (at->dw_attr_val.v.val_long_long));
       break;
     case dw_val_class_vec:
       CHECKSUM (at->dw_attr_val.v.val_vec);
@@ -7748,8 +7841,10 @@ same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
     case dw_val_class_unsigned_const:
       return v1->v.val_unsigned == v2->v.val_unsigned;
     case dw_val_class_long_long:
-      return v1->v.val_long_long.hi == v2->v.val_long_long.hi
-            && v1->v.val_long_long.low == v2->v.val_long_long.low;
+      return CONST_DOUBLE_HIGH (v1->v.val_long_long)
+            == CONST_DOUBLE_HIGH (v2->v.val_long_long)
+            && CONST_DOUBLE_LOW (v1->v.val_long_long)
+               == CONST_DOUBLE_LOW (v2->v.val_long_long);
     case dw_val_class_vec:
       if (v1->v.val_vec.length != v2->v.val_vec.length
          || v1->v.val_vec.elt_size != v2->v.val_vec.elt_size)
@@ -8358,7 +8453,7 @@ size_of_die (dw_die_ref die)
          size += constant_size (AT_unsigned (a));
          break;
        case dw_val_class_long_long:
-         size += 1 + 2*HOST_BITS_PER_LONG/HOST_BITS_PER_CHAR; /* block */
+         size += 1 + 2*HOST_BITS_PER_WIDE_INT/HOST_BITS_PER_CHAR; /* block */
          break;
        case dw_val_class_vec:
          size += constant_size (a->dw_attr_val.v.val_vec.length
@@ -8840,23 +8935,24 @@ output_die (dw_die_ref die)
            unsigned HOST_WIDE_INT first, second;
 
            dw2_asm_output_data (1,
-                                2 * HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+                                2 * HOST_BITS_PER_WIDE_INT
+                                / HOST_BITS_PER_CHAR,
                                 "%s", name);
 
            if (WORDS_BIG_ENDIAN)
              {
-               first = a->dw_attr_val.v.val_long_long.hi;
-               second = a->dw_attr_val.v.val_long_long.low;
+               first = CONST_DOUBLE_HIGH (a->dw_attr_val.v.val_long_long);
+               second = CONST_DOUBLE_LOW (a->dw_attr_val.v.val_long_long);
              }
            else
              {
-               first = a->dw_attr_val.v.val_long_long.low;
-               second = a->dw_attr_val.v.val_long_long.hi;
+               first = CONST_DOUBLE_LOW (a->dw_attr_val.v.val_long_long);
+               second = CONST_DOUBLE_HIGH (a->dw_attr_val.v.val_long_long);
              }
 
-           dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+           dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
                                 first, "long long constant");
-           dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+           dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
                                 second, NULL);
          }
          break;
@@ -10922,6 +11018,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
 {
   dw_loc_descr_ref mem_loc_result = NULL;
   enum dwarf_location_atom op;
+  dw_loc_descr_ref op0, op1;
 
   /* Note that for a dynamically sized array, the location we will generate a
      description of here will be the lowest numbered location which is
@@ -10947,6 +11044,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
         legitimate to make the Dwarf info refer to the whole register which
         contains the given subreg.  */
       rtl = XEXP (rtl, 0);
+      if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE)
+       break;
 
       /* ... fall through ...  */
 
@@ -10978,6 +11077,29 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
        }
       break;
 
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      if (op0 == 0)
+       break;
+      else
+       {
+         int shift = DWARF2_ADDR_SIZE
+                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+         shift *= BITS_PER_UNIT;
+         if (GET_CODE (rtl) == SIGN_EXTEND)
+           op = DW_OP_shra;
+         else
+           op = DW_OP_shr;
+         mem_loc_result = op0;
+         add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
+         add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
+         add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
+         add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+       }
+      break;
+
     case MEM:
       mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
                                           VAR_INIT_STATUS_INITIALIZED);
@@ -11022,6 +11144,27 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
            return 0;
        }
 
+      if (GET_CODE (rtl) == SYMBOL_REF
+         && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
+       {
+         dw_loc_descr_ref temp;
+
+         /* If this is not defined, we have no way to emit the data.  */
+         if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
+           break;
+
+         temp = new_loc_descr (DW_OP_addr, 0, 0);
+         temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
+         temp->dw_loc_oprnd1.v.val_addr = rtl;
+         temp->dtprel = true;
+
+         mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
+         add_loc_descr (&mem_loc_result, temp);
+
+         break;
+       }
+
+    symref:
       mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
       mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
       mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
@@ -11076,10 +11219,22 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
 
     /* If a pseudo-reg is optimized away, it is possible for it to
        be replaced with a MEM containing a multiply or shift.  */
+    case MINUS:
+      op = DW_OP_minus;
+      goto do_binop;
+
     case MULT:
       op = DW_OP_mul;
       goto do_binop;
 
+    case DIV:
+      op = DW_OP_div;
+      goto do_binop;
+
+    case MOD:
+      op = DW_OP_mod;
+      goto do_binop;
+
     case ASHIFT:
       op = DW_OP_shl;
       goto do_binop;
@@ -11092,21 +11247,54 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       op = DW_OP_shr;
       goto do_binop;
 
+    case AND:
+      op = DW_OP_and;
+      goto do_binop;
+
+    case IOR:
+      op = DW_OP_or;
+      goto do_binop;
+
+    case XOR:
+      op = DW_OP_xor;
+      goto do_binop;
+
     do_binop:
-      {
-       dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
-                                                  VAR_INIT_STATUS_INITIALIZED);
-       dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
-                                                  VAR_INIT_STATUS_INITIALIZED);
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
 
-       if (op0 == 0 || op1 == 0)
-         break;
+      if (op0 == 0 || op1 == 0)
+       break;
+
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      break;
+
+    case NOT:
+      op = DW_OP_not;
+      goto do_unop;
+
+    case ABS:
+      op = DW_OP_abs;
+      goto do_unop;
 
-       mem_loc_result = op0;
-       add_loc_descr (&mem_loc_result, op1);
-       add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+    case NEG:
+      op = DW_OP_neg;
+      goto do_unop;
+
+    do_unop:
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+
+      if (op0 == 0)
        break;
-      }
+
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      break;
 
     case CONST_INT:
       mem_loc_result = int_loc_descriptor (INTVAL (rtl));
@@ -11117,14 +11305,287 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
                                                   VAR_INIT_STATUS_INITIALIZED);
       break;
 
+    case EQ:
+      op = DW_OP_eq;
+      goto do_scompare;
+
+    case GE:
+      op = DW_OP_ge;
+      goto do_scompare;
+
+    case GT:
+      op = DW_OP_gt;
+      goto do_scompare;
+
+    case LE:
+      op = DW_OP_le;
+      goto do_scompare;
+
+    case LT:
+      op = DW_OP_lt;
+      goto do_scompare;
+
+    case NE:
+      op = DW_OP_ne;
+      goto do_scompare;
+
+    do_scompare:
+      if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
+         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+         || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+       break;
+
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+
+      if (op0 == 0 || op1 == 0)
+       break;
+
+      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+       {
+         int shift = DWARF2_ADDR_SIZE
+                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+         shift *= BITS_PER_UNIT;
+         add_loc_descr (&op0, int_loc_descriptor (shift));
+         add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+         if (CONST_INT_P (XEXP (rtl, 1)))
+           op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift);
+         else
+           {
+             add_loc_descr (&op1, int_loc_descriptor (shift));
+             add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+           }
+       }
+
+    do_compare:
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      if (STORE_FLAG_VALUE != 1)
+       {
+         add_loc_descr (&mem_loc_result,
+                        int_loc_descriptor (STORE_FLAG_VALUE));
+         add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
+       }
+      break;
+
+    case GEU:
+      op = DW_OP_ge;
+      goto do_ucompare;
+
+    case GTU:
+      op = DW_OP_gt;
+      goto do_ucompare;
+
+    case LEU:
+      op = DW_OP_le;
+      goto do_ucompare;
+
+    case LTU:
+      op = DW_OP_lt;
+      goto do_ucompare;
+
+    do_ucompare:
+      if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
+         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+         || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+       break;
+
+      op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+      op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                               VAR_INIT_STATUS_INITIALIZED);
+
+      if (op0 == 0 || op1 == 0)
+       break;
+
+      if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+       {
+         HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0)));
+         add_loc_descr (&op0, int_loc_descriptor (mask));
+         add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+         if (CONST_INT_P (XEXP (rtl, 1)))
+           op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask);
+         else
+           {
+             add_loc_descr (&op1, int_loc_descriptor (mask));
+             add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
+           }
+       }
+      else
+       {
+         HOST_WIDE_INT bias = 1;
+         bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
+         add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+         if (CONST_INT_P (XEXP (rtl, 1)))
+           op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias
+                                     + INTVAL (XEXP (rtl, 1)));
+         else
+           add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+       }
+      goto do_compare;
+
+    case SMIN:
+    case SMAX:
+    case UMIN:
+    case UMAX:
+      if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
+         || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+         || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+       break;
+
+      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;
+
+      add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
+      add_loc_descr (&op1, new_loc_descr (DW_OP_swap, 0, 0));
+      add_loc_descr (&op1, new_loc_descr (DW_OP_over, 0, 0));
+      if (GET_CODE (rtl) == UMIN || GET_CODE (rtl) == UMAX)
+       {
+         if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+           {
+             HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0)));
+             add_loc_descr (&op0, int_loc_descriptor (mask));
+             add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+             add_loc_descr (&op1, int_loc_descriptor (mask));
+             add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
+           }
+         else
+           {
+             HOST_WIDE_INT bias = 1;
+             bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
+             add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+             add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+           }
+       }
+      else if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+       {
+         int shift = DWARF2_ADDR_SIZE
+                     - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+         shift *= BITS_PER_UNIT;
+         add_loc_descr (&op0, int_loc_descriptor (shift));
+         add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+         add_loc_descr (&op1, int_loc_descriptor (shift));
+         add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+       }
+
+      if (GET_CODE (rtl) == SMIN || GET_CODE (rtl) == UMIN)
+       op = DW_OP_lt;
+      else
+       op = DW_OP_gt;
+      mem_loc_result = op0;
+      add_loc_descr (&mem_loc_result, op1);
+      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+      {
+       dw_loc_descr_ref bra_node, drop_node;
+
+       bra_node = new_loc_descr (DW_OP_bra, 0, 0);
+       add_loc_descr (&mem_loc_result, bra_node);
+       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_swap, 0, 0));
+       drop_node = new_loc_descr (DW_OP_drop, 0, 0);
+       add_loc_descr (&mem_loc_result, drop_node);
+       bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+       bra_node->dw_loc_oprnd1.v.val_loc = drop_node;
+      }
+      break;
+
+    case ZERO_EXTRACT:
+    case SIGN_EXTRACT:
+      if (CONST_INT_P (XEXP (rtl, 1))
+         && CONST_INT_P (XEXP (rtl, 2))
+         && ((unsigned) INTVAL (XEXP (rtl, 1))
+             + (unsigned) INTVAL (XEXP (rtl, 2))
+             <= GET_MODE_BITSIZE (GET_MODE (rtl)))
+         && GET_MODE_BITSIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE
+         && GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0))) <= DWARF2_ADDR_SIZE)
+       {
+         int shift, size;
+         op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                                   VAR_INIT_STATUS_INITIALIZED);
+         if (op0 == 0)
+           break;
+         if (GET_CODE (rtl) == SIGN_EXTRACT)
+           op = DW_OP_shra;
+         else
+           op = DW_OP_shr;
+         mem_loc_result = op0;
+         size = INTVAL (XEXP (rtl, 1));
+         shift = INTVAL (XEXP (rtl, 2));
+         if (BITS_BIG_ENDIAN)
+           shift = GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0)))
+                   - shift - size;
+         add_loc_descr (&mem_loc_result,
+                        int_loc_descriptor (DWARF2_ADDR_SIZE - shift - size));
+         add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
+         add_loc_descr (&mem_loc_result,
+                        int_loc_descriptor (DWARF2_ADDR_SIZE - size));
+         add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+       }
+      break;
+
+    case COMPARE:
+    case IF_THEN_ELSE:
+    case ROTATE:
+    case ROTATERT:
+    case TRUNCATE:
+      /* In theory, we could implement the above.  */
+      /* DWARF cannot represent the unsigned compare operations
+        natively.  */
+    case SS_MULT:
+    case US_MULT:
+    case SS_DIV:
+    case US_DIV:
+    case UDIV:
+    case UMOD:
+    case UNORDERED:
+    case ORDERED:
+    case UNEQ:
+    case UNGE:
+    case UNLE:
+    case UNLT:
+    case LTGT:
+    case FLOAT_EXTEND:
+    case FLOAT_TRUNCATE:
+    case FLOAT:
+    case UNSIGNED_FLOAT:
+    case FIX:
+    case UNSIGNED_FIX:
+    case FRACT_CONVERT:
+    case UNSIGNED_FRACT_CONVERT:
+    case SAT_FRACT:
+    case UNSIGNED_SAT_FRACT:
+    case SQRT:
+    case BSWAP:
+    case FFS:
+    case CLZ:
+    case CTZ:
+    case POPCOUNT:
+    case PARITY:
+    case ASM_OPERANDS:
     case UNSPEC:
       /* If delegitimize_address couldn't do anything with the UNSPEC, we
         can't express it in the debug info.  This can happen e.g. with some
         TLS UNSPECs.  */
       break;
 
+    case CONST_STRING:
+      rtl = get_debug_string_label (XSTR (rtl, 0));
+      goto symref;
+
     default:
+#ifdef ENABLE_CHECKING
+      print_rtl (stderr, rtl);
       gcc_unreachable ();
+#else
+      break;
+#endif
     }
 
   if (mem_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
@@ -11140,8 +11601,10 @@ static dw_loc_descr_ref
 concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
 {
   dw_loc_descr_ref cc_loc_result = NULL;
-  dw_loc_descr_ref x0_ref = loc_descriptor (x0, VAR_INIT_STATUS_INITIALIZED);
-  dw_loc_descr_ref x1_ref = loc_descriptor (x1, VAR_INIT_STATUS_INITIALIZED);
+  dw_loc_descr_ref x0_ref
+    = loc_descriptor (x0, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+  dw_loc_descr_ref x1_ref
+    = loc_descriptor (x1, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
 
   if (x0_ref == 0 || x1_ref == 0)
     return 0;
@@ -11173,7 +11636,7 @@ concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
       dw_loc_descr_ref ref;
       rtx x = XVECEXP (concatn, 0, i);
 
-      ref = loc_descriptor (x, VAR_INIT_STATUS_INITIALIZED);
+      ref = loc_descriptor (x, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
       if (ref == NULL)
        return NULL;
 
@@ -11193,10 +11656,15 @@ concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
    memory location we provide a Dwarf postfix expression describing how to
    generate the (dynamic) address of the object onto the address stack.
 
+   MODE is mode of the decl if this loc_descriptor is going to be used in
+   .debug_loc section where DW_OP_stack_value and DW_OP_implicit_value are
+   allowed, VOIDmode otherwise.
+
    If we don't know how to describe it, return 0.  */
 
 static dw_loc_descr_ref
-loc_descriptor (rtx rtl, enum var_init_status initialized)
+loc_descriptor (rtx rtl, enum machine_mode mode,
+               enum var_init_status initialized)
 {
   dw_loc_descr_ref loc_result = NULL;
 
@@ -11208,14 +11676,18 @@ loc_descriptor (rtx rtl, enum var_init_status initialized)
         up an entire register.  For now, just assume that it is
         legitimate to make the Dwarf info refer to the whole register which
         contains the given subreg.  */
-      rtl = SUBREG_REG (rtl);
-
-      /* ... fall through ...  */
+      loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized);
+      break;
 
     case REG:
       loc_result = reg_loc_descriptor (rtl, initialized);
       break;
 
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
+      loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
+      break;
+
     case MEM:
       loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
                                       initialized);
@@ -11236,7 +11708,8 @@ loc_descriptor (rtx rtl, enum var_init_status initialized)
       /* Single part.  */
       if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
        {
-         loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), initialized);
+         loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), mode,
+                                      initialized);
          break;
        }
 
@@ -11252,7 +11725,7 @@ loc_descriptor (rtx rtl, enum var_init_status initialized)
 
        /* Create the first one, so we have something to add to.  */
        loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
-                                    initialized);
+                                    VOIDmode, initialized);
        if (loc_result == NULL)
          return NULL;
        mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
@@ -11262,7 +11735,7 @@ loc_descriptor (rtx rtl, enum var_init_status initialized)
            dw_loc_descr_ref temp;
 
            temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
-                                  initialized);
+                                  VOIDmode, initialized);
            if (temp == NULL)
              return NULL;
            add_loc_descr (&loc_result, temp);
@@ -11272,8 +11745,206 @@ loc_descriptor (rtx rtl, enum var_init_status initialized)
       }
       break;
 
+    case CONST_INT:
+      if (mode != VOIDmode && mode != BLKmode && dwarf_version >= 4)
+        {
+          HOST_WIDE_INT i = INTVAL (rtl);
+          int litsize;
+          if (i >= 0)
+            {
+              if (i <= 31)
+               litsize = 1;
+             else if (i <= 0xff)
+               litsize = 2;
+             else if (i <= 0xffff)
+               litsize = 3;
+             else if (HOST_BITS_PER_WIDE_INT == 32
+                      || i <= 0xffffffff)
+               litsize = 5;
+             else
+               litsize = 1 + size_of_uleb128 ((unsigned HOST_WIDE_INT) i);
+           }
+         else
+           {
+             if (i >= -0x80)
+               litsize = 2;
+             else if (i >= -0x8000)
+               litsize = 3;
+             else if (HOST_BITS_PER_WIDE_INT == 32
+                      || i >= -0x80000000)
+               litsize = 5;
+             else
+               litsize = 1 + size_of_sleb128 (i);
+           }
+         /* Determine if DW_OP_stack_value or DW_OP_implicit_value
+            is more compact.  For DW_OP_stack_value we need:
+            litsize + 1 (DW_OP_stack_value) + 1 (DW_OP_bit_size)
+            + 1 (mode size)
+            and for DW_OP_implicit_value:
+            1 (DW_OP_implicit_value) + 1 (length) + mode_size.  */
+         if (DWARF2_ADDR_SIZE >= GET_MODE_SIZE (mode)
+             && litsize + 1 + 1 + 1 < 1 + 1 + GET_MODE_SIZE (mode))
+           {
+             loc_result = int_loc_descriptor (i);
+             add_loc_descr (&loc_result,
+                            new_loc_descr (DW_OP_stack_value, 0, 0));
+             add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+             return loc_result;
+           }
+
+         loc_result = new_loc_descr (DW_OP_implicit_value,
+                                     GET_MODE_SIZE (mode), 0);
+         loc_result->dw_loc_oprnd2.val_class = dw_val_class_const;
+         loc_result->dw_loc_oprnd2.v.val_int = i;
+       }
+      break;
+
+    case CONST_DOUBLE:
+      if (mode != VOIDmode && dwarf_version >= 4)
+       {
+         /* 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))
+           {
+             unsigned int length = GET_MODE_SIZE (mode);
+             unsigned char *array = GGC_NEWVEC (unsigned char, length);
+
+             insert_float (rtl, array);
+             loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+             loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4;
+             loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
+             loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+           }
+         else
+           {
+             loc_result->dw_loc_oprnd2.val_class = dw_val_class_long_long;
+             loc_result->dw_loc_oprnd2.v.val_long_long = rtl;
+           }
+       }
+      break;
+
+    case CONST_VECTOR:
+      if (mode != VOIDmode && dwarf_version >= 4)
+       {
+         unsigned int elt_size = GET_MODE_UNIT_SIZE (GET_MODE (rtl));
+         unsigned int length = CONST_VECTOR_NUNITS (rtl);
+         unsigned char *array = GGC_NEWVEC (unsigned char, length * elt_size);
+         unsigned int i;
+         unsigned char *p;
+
+         mode = GET_MODE (rtl);
+         switch (GET_MODE_CLASS (mode))
+           {
+           case MODE_VECTOR_INT:
+             for (i = 0, p = array; i < length; i++, p += elt_size)
+               {
+                 rtx elt = CONST_VECTOR_ELT (rtl, i);
+                 HOST_WIDE_INT lo, hi;
+
+                 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 ();
+                   }
+
+                 if (elt_size <= sizeof (HOST_WIDE_INT))
+                   insert_int (lo, elt_size, p);
+                 else
+                   {
+                     unsigned char *p0 = p;
+                     unsigned char *p1 = p + sizeof (HOST_WIDE_INT);
+
+                     gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
+                     if (WORDS_BIG_ENDIAN)
+                       {
+                         p0 = p1;
+                         p1 = p;
+                       }
+                     insert_int (lo, sizeof (HOST_WIDE_INT), p0);
+                     insert_int (hi, sizeof (HOST_WIDE_INT), p1);
+                   }
+               }
+             break;
+
+           case MODE_VECTOR_FLOAT:
+             for (i = 0, p = array; i < length; i++, p += elt_size)
+               {
+                 rtx elt = CONST_VECTOR_ELT (rtl, i);
+                 insert_float (elt, p);
+               }
+             break;
+
+           default:
+             gcc_unreachable ();
+           }
+
+         loc_result = new_loc_descr (DW_OP_implicit_value,
+                                     length * elt_size, 0);
+         loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+         loc_result->dw_loc_oprnd2.v.val_vec.length = length;
+         loc_result->dw_loc_oprnd2.v.val_vec.elt_size = elt_size;
+         loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+       }
+      break;
+
+    case CONST:
+      if (mode == VOIDmode
+         || GET_CODE (XEXP (rtl, 0)) == CONST_INT
+         || GET_CODE (XEXP (rtl, 0)) == CONST_DOUBLE
+         || GET_CODE (XEXP (rtl, 0)) == CONST_VECTOR)
+       {
+         loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
+         break;
+       }
+      /* FALLTHROUGH */
+    case SYMBOL_REF:
+      if (GET_CODE (rtl) == SYMBOL_REF
+         && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
+       break;
+    case LABEL_REF:
+      if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
+         && dwarf_version >= 4)
+       {
+         loc_result = new_loc_descr (DW_OP_implicit_value,
+                                     DWARF2_ADDR_SIZE, 0);
+         loc_result->dw_loc_oprnd2.val_class = dw_val_class_addr;
+         loc_result->dw_loc_oprnd2.v.val_addr = rtl;
+         VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+       }
+      break;
+
     default:
-      gcc_unreachable ();
+      if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE (rtl) == mode
+         && GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE
+         && dwarf_version >= 4)
+       {
+         /* Value expression.  */
+         loc_result = mem_loc_descriptor (rtl, VOIDmode, initialized);
+         if (loc_result)
+           {
+             add_loc_descr (&loc_result,
+                            new_loc_descr (DW_OP_stack_value, 0, 0));
+             add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+           }
+       }
+      break;
     }
 
   return loc_result;
@@ -11416,7 +12087,8 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
 
            /* Certain constructs can only be represented at top-level.  */
            if (want_address == 2)
-             return loc_descriptor (rtl, VAR_INIT_STATUS_INITIALIZED);
+             return loc_descriptor (rtl, VOIDmode,
+                                    VAR_INIT_STATUS_INITIALIZED);
 
            mode = GET_MODE (rtl);
            if (MEM_P (rtl))
@@ -12131,13 +12803,7 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
            add_AT_vec (die, DW_AT_const_value, length / 4, 4, array);
          }
        else
-         {
-           /* ??? We really should be using HOST_WIDE_INT throughout.  */
-           gcc_assert (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT);
-
-           add_AT_long_long (die, DW_AT_const_value,
-                             CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
-         }
+         add_AT_long_long (die, DW_AT_const_value, rtl);
       }
       break;
 
@@ -12213,9 +12879,18 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
       add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0));
       break;
 
+    case CONST:
+      if (CONSTANT_P (XEXP (rtl, 0)))
+       {
+         add_const_value_attribute (die, XEXP (rtl, 0));
+         return;
+       }
+      /* FALLTHROUGH */
     case SYMBOL_REF:
+      if (GET_CODE (rtl) == SYMBOL_REF
+         && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
+       break;
     case LABEL_REF:
-    case CONST:
       add_AT_addr (die, DW_AT_const_value, rtl);
       VEC_safe_push (rtx, gc, used_rtx_array, rtl);
       break;
@@ -12761,7 +13436,8 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
       else
        initialized = VAR_INIT_STATUS_INITIALIZED;
 
-      descr = loc_by_reference (loc_descriptor (varloc, initialized), decl);
+      descr = loc_by_reference (loc_descriptor (varloc, DECL_MODE (decl),
+                                               initialized), decl);
       list = new_loc_list (descr, node->label, node->next->label, secname, 1);
       node = node->next;
 
@@ -12773,8 +13449,8 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
            enum var_init_status initialized =
              NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
            varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-           descr = loc_by_reference (loc_descriptor (varloc, initialized),
-                                     decl);
+           descr = loc_by_reference (loc_descriptor (varloc, DECL_MODE (decl),
+                                     initialized), decl);
            add_loc_descr_to_loc_list (&list, descr,
                                       node->label, node->next->label, secname);
          }
@@ -12796,7 +13472,9 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
                                           current_function_funcdef_no);
              endname = ggc_strdup (label_id);
            }
-         descr = loc_by_reference (loc_descriptor (varloc, initialized),
+         descr = loc_by_reference (loc_descriptor (varloc,
+                                                   DECL_MODE (decl),
+                                                   initialized),
                                    decl);
          add_loc_descr_to_loc_list (&list, descr,
                                     node->label, endname, secname);
@@ -12825,7 +13503,17 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
       enum var_init_status status;
       node = loc_list->first;
       status = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-      descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note), status);
+      rtl = NOTE_VAR_LOCATION (node->var_loc_note);
+      if (GET_CODE (rtl) == VAR_LOCATION
+         && GET_CODE (XEXP (rtl, 1)) != PARALLEL)
+       rtl = XEXP (XEXP (rtl, 1), 0);
+      if (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
+       {
+         add_const_value_attribute (die, rtl);
+         return;
+       }
+      descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note),
+                             DECL_MODE (decl), status);
       if (descr)
        {
          descr = loc_by_reference (descr, decl);
@@ -16898,10 +17586,11 @@ dwarf2out_set_name (tree decl, tree name)
 static void
 dwarf2out_var_location (rtx loc_note)
 {
-  char loclabel[MAX_ARTIFICIAL_LABEL_BYTES];
+  char loclabel[MAX_ARTIFICIAL_LABEL_BYTES + 2];
   struct var_loc_node *newloc;
   rtx next_real;
   static const char *last_label;
+  static const char *last_postcall_label;
   static bool last_in_cold_section_p;
   tree decl;
 
@@ -16917,27 +17606,38 @@ dwarf2out_var_location (rtx loc_note)
   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 (last_var_location_insn != NULL_RTX
-      && last_var_location_insn == next_real
-      && last_in_cold_section_p == in_cold_section_p)
-    newloc->label = last_label;
-  else
+  if (last_var_location_insn == NULL_RTX
+      || last_var_location_insn != next_real
+      || last_in_cold_section_p != in_cold_section_p)
     {
       ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num);
       ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num);
       loclabel_num++;
-      newloc->label = ggc_strdup (loclabel);
+      last_label = ggc_strdup (loclabel);
+      if (!NOTE_DURING_CALL_P (loc_note))
+       last_postcall_label = NULL;
     }
   newloc->var_loc_note = loc_note;
   newloc->next = NULL;
 
+  if (!NOTE_DURING_CALL_P (loc_note))
+    newloc->label = last_label;
+  else
+    {
+      if (!last_postcall_label)
+       {
+         sprintf (loclabel, "%s-1", last_label);
+         last_postcall_label = ggc_strdup (loclabel);
+       }
+      newloc->label = last_postcall_label;
+    }
+
   if (cfun && in_cold_section_p)
     newloc->section_label = crtl->subsections.cold_section_label;
   else
     newloc->section_label = text_section_label;
 
   last_var_location_insn = next_real;
-  last_label = newloc->label;
   last_in_cold_section_p = in_cold_section_p;
   decl = NOTE_VAR_LOCATION_DECL (loc_note);
   add_var_loc_to_decl (decl, newloc);
@@ -17242,14 +17942,14 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
 }
 
 /* A helper function for dwarf2out_finish called through
-   ht_forall.  Emit one queued .debug_str string.  */
+   htab_traverse.  Emit one queued .debug_str string.  */
 
 static int
 output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
 {
   struct indirect_string_node *node = (struct indirect_string_node *) *h;
 
-  if (node->form == DW_FORM_strp)
+  if (node->label && node->refcount)
     {
       switch_to_section (debug_str_section);
       ASM_OUTPUT_LABEL (asm_out_file, node->label);
@@ -17527,6 +18227,20 @@ prune_unused_types_prune (dw_die_ref die)
   } while (c != die->die_child);
 }
 
+/* A helper function for dwarf2out_finish called through
+   htab_traverse.  Clear .debug_str strings that we haven't already
+   decided to emit.  */
+
+static int
+prune_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
+{
+  struct indirect_string_node *node = (struct indirect_string_node *) *h;
+
+  if (!node->label || !node->refcount)
+    htab_clear_slot (debug_str_hash, h);
+
+  return 1;
+}
 
 /* Remove dies representing declarations that we never use.  */
 
@@ -17557,7 +18271,9 @@ prune_unused_types (void)
     prune_unused_types_mark (arange_table[i], 1);
 
   /* Get rid of nodes that aren't marked; and update the string counts.  */
-  if (debug_str_hash)
+  if (debug_str_hash && debug_str_hash_forced)
+    htab_traverse (debug_str_hash, prune_indirect_string, NULL);
+  else if (debug_str_hash)
     htab_empty (debug_str_hash);
   prune_unused_types_prune (comp_unit_die);
   for (node = limbo_die_list; node; node = node->next)