]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/dwarf2out.c
Merge in trunk.
[thirdparty/gcc.git] / gcc / dwarf2out.c
index 2b584a58853138f89190f01a4523c97bd8d74267..641cbb570792e48d714e76b289dd02fb9c94f1a6 100644 (file)
@@ -357,6 +357,16 @@ dump_struct_debug (tree type, enum debug_info_usage usage,
 
 #endif
 
+/* Get the number of HOST_WIDE_INTs needed to represent the precision
+   of the number.  */
+
+static unsigned int
+get_full_len (const wide_int &op)
+{
+  return ((op.get_precision () + HOST_BITS_PER_WIDE_INT - 1)
+         / HOST_BITS_PER_WIDE_INT);
+}
+
 static bool
 should_emit_struct_debug (tree type, enum debug_info_usage usage)
 {
@@ -1392,6 +1402,9 @@ dw_val_equal_p (dw_val_node *a, dw_val_node *b)
       return (a->v.val_double.high == b->v.val_double.high
              && a->v.val_double.low == b->v.val_double.low);
 
+    case dw_val_class_wide_int:
+      return *a->v.val_wide == *b->v.val_wide;
+
     case dw_val_class_vec:
       {
        size_t a_len = a->v.val_vec.elt_size * a->v.val_vec.length;
@@ -1648,6 +1661,10 @@ size_of_loc_descr (dw_loc_descr_ref loc)
          case dw_val_class_const_double:
            size += HOST_BITS_PER_DOUBLE_INT / BITS_PER_UNIT;
            break;
+         case dw_val_class_wide_int:
+           size += (get_full_len (*loc->dw_loc_oprnd2.v.val_wide)
+                    * HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT);
+           break;
          default:
            gcc_unreachable ();
          }
@@ -1825,6 +1842,20 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
                                 second, NULL);
          }
          break;
+       case dw_val_class_wide_int:
+         {
+           int i;
+           int len = get_full_len (*val2->v.val_wide);
+           if (WORDS_BIG_ENDIAN)
+             for (i = len; i >= 0; --i)
+               dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
+                                    val2->v.val_wide->elt (i), NULL);
+           else
+             for (i = 0; i < len; ++i)
+               dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
+                                    val2->v.val_wide->elt (i), 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);
@@ -2034,6 +2065,21 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
              dw2_asm_output_data (l, second, NULL);
            }
            break;
+         case dw_val_class_wide_int:
+           {
+             int i;
+             int len = get_full_len (*val2->v.val_wide);
+             l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
+
+             dw2_asm_output_data (1, len * l, NULL);
+             if (WORDS_BIG_ENDIAN)
+               for (i = len; i >= 0; --i)
+                 dw2_asm_output_data (l, val2->v.val_wide->elt (i), NULL);
+             else
+               for (i = 0; i < len; ++i)
+                 dw2_asm_output_data (l, val2->v.val_wide->elt (i), NULL);
+           }
+           break;
          default:
            gcc_unreachable ();
          }
@@ -3126,7 +3172,7 @@ static void add_AT_location_description   (dw_die_ref, enum dwarf_attribute,
 static void add_data_member_location_attribute (dw_die_ref, tree);
 static bool add_const_value_attribute (dw_die_ref, rtx);
 static void insert_int (HOST_WIDE_INT, unsigned, unsigned char *);
-static void insert_double (double_int, unsigned char *);
+static void insert_wide_int (const wide_int &, unsigned char *, int);
 static void insert_float (const_rtx, unsigned char *);
 static rtx rtl_for_decl_location (tree);
 static bool add_location_or_const_value_attribute (dw_die_ref, tree, bool,
@@ -3758,6 +3804,21 @@ AT_unsigned (dw_attr_ref a)
   return a->dw_attr_val.v.val_unsigned;
 }
 
+/* Add an unsigned wide integer attribute value to a DIE.  */
+
+static inline void
+add_AT_wide (dw_die_ref die, enum dwarf_attribute attr_kind,
+            const wide_int& w)
+{
+  dw_attr_node attr;
+
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_wide_int;
+  attr.dw_attr_val.v.val_wide = ggc_alloc_cleared_wide_int ();
+  *attr.dw_attr_val.v.val_wide = w;
+  add_dwarf_attr (die, &attr);
+}
+
 /* Add an unsigned double integer attribute value to a DIE.  */
 
 static inline void
@@ -5332,6 +5393,21 @@ print_die (dw_die_ref die, FILE *outfile)
                   a->dw_attr_val.v.val_double.high,
                   a->dw_attr_val.v.val_double.low);
          break;
+       case dw_val_class_wide_int:
+         {
+           int i = a->dw_attr_val.v.val_wide->get_len ();
+           fprintf (outfile, "constant (");
+           gcc_assert (i > 0);
+           if (a->dw_attr_val.v.val_wide->elt (i) == 0)
+             fprintf (outfile, "0x");
+           fprintf (outfile, HOST_WIDE_INT_PRINT_HEX,
+                    a->dw_attr_val.v.val_wide->elt (--i));
+           while (-- i >= 0)
+             fprintf (outfile, HOST_WIDE_INT_PRINT_PADDED_HEX,
+                      a->dw_attr_val.v.val_wide->elt (i));
+           fprintf (outfile, ")");
+           break;
+         }
        case dw_val_class_vec:
          fprintf (outfile, "floating-point or vector constant");
          break;
@@ -5505,6 +5581,9 @@ attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
     case dw_val_class_const_double:
       CHECKSUM (at->dw_attr_val.v.val_double);
       break;
+    case dw_val_class_wide_int:
+      CHECKSUM (*at->dw_attr_val.v.val_wide);
+      break;
     case dw_val_class_vec:
       CHECKSUM_BLOCK (at->dw_attr_val.v.val_vec.array,
                      (at->dw_attr_val.v.val_vec.length
@@ -5782,6 +5861,12 @@ attr_checksum_ordered (enum dwarf_tag tag, dw_attr_ref at,
       CHECKSUM (at->dw_attr_val.v.val_double);
       break;
 
+    case dw_val_class_wide_int:
+      CHECKSUM_ULEB128 (DW_FORM_block);
+      CHECKSUM_ULEB128 (sizeof (*at->dw_attr_val.v.val_wide));
+      CHECKSUM (*at->dw_attr_val.v.val_wide);
+      break;
+
     case dw_val_class_vec:
       CHECKSUM_ULEB128 (DW_FORM_block);
       CHECKSUM_ULEB128 (at->dw_attr_val.v.val_vec.length
@@ -6264,6 +6349,8 @@ same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
     case dw_val_class_const_double:
       return v1->v.val_double.high == v2->v.val_double.high
             && v1->v.val_double.low == v2->v.val_double.low;
+    case dw_val_class_wide_int:
+      return *v1->v.val_wide == *v2->v.val_wide;
     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)
@@ -7797,6 +7884,13 @@ size_of_die (dw_die_ref die)
          if (HOST_BITS_PER_WIDE_INT >= 64)
            size++; /* block */
          break;
+       case dw_val_class_wide_int:
+         size += (get_full_len (*a->dw_attr_val.v.val_wide)
+                  * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
+         if (get_full_len (*a->dw_attr_val.v.val_wide) * HOST_BITS_PER_WIDE_INT
+             > 64)
+           size++; /* block */
+         break;
        case dw_val_class_vec:
          size += constant_size (a->dw_attr_val.v.val_vec.length
                                 * a->dw_attr_val.v.val_vec.elt_size)
@@ -8166,6 +8260,20 @@ value_format (dw_attr_ref a)
        default:
          return DW_FORM_block1;
        }
+    case dw_val_class_wide_int:
+      switch (get_full_len (*a->dw_attr_val.v.val_wide) * HOST_BITS_PER_WIDE_INT)
+       {
+       case 8:
+         return DW_FORM_data1;
+       case 16:
+         return DW_FORM_data2;
+       case 32:
+         return DW_FORM_data4;
+       case 64:
+         return DW_FORM_data8;
+       default:
+         return DW_FORM_block1;
+       }
     case dw_val_class_vec:
       switch (constant_size (a->dw_attr_val.v.val_vec.length
                             * a->dw_attr_val.v.val_vec.elt_size))
@@ -8605,6 +8713,32 @@ output_die (dw_die_ref die)
          }
          break;
 
+       case dw_val_class_wide_int:
+         {
+           int i;
+           int len = get_full_len (*a->dw_attr_val.v.val_wide);
+           int l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
+           if (len * HOST_BITS_PER_WIDE_INT > 64)
+             dw2_asm_output_data (1, get_full_len (*a->dw_attr_val.v.val_wide) * l,
+                                  NULL);
+
+           if (WORDS_BIG_ENDIAN)
+             for (i = len; i >= 0; --i)
+               {
+                 dw2_asm_output_data (l, a->dw_attr_val.v.val_wide->elt (i),
+                                      name);
+                 name = NULL;
+               }
+           else
+             for (i = 0; i < len; ++i)
+               {
+                 dw2_asm_output_data (l, a->dw_attr_val.v.val_wide->elt (i),
+                                      name);
+                 name = NULL;
+               }
+         }
+         break;
+
        case dw_val_class_vec:
          {
            unsigned int elt_size = a->dw_attr_val.v.val_vec.elt_size;
@@ -10300,19 +10434,19 @@ simple_type_size_in_bits (const_tree type)
     return TYPE_ALIGN (type);
 }
 
-/* Similarly, but return a double_int instead of UHWI.  */
+/* Similarly, but return an offset_int instead of UHWI.  */
 
-static inline double_int
-double_int_type_size_in_bits (const_tree type)
+static inline offset_int
+offset_int_type_size_in_bits (const_tree type)
 {
   if (TREE_CODE (type) == ERROR_MARK)
-    return double_int::from_uhwi (BITS_PER_WORD);
+    return BITS_PER_WORD;
   else if (TYPE_SIZE (type) == NULL_TREE)
-    return double_int_zero;
+    return 0;
   else if (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
-    return tree_to_double_int (TYPE_SIZE (type));
+    return wi::to_offset (TYPE_SIZE (type));
   else
-    return double_int::from_uhwi (TYPE_ALIGN (type));
+    return TYPE_ALIGN (type);
 }
 
 /*  Given a pointer to a tree node for a subrange type, return a pointer
@@ -11799,9 +11933,7 @@ clz_loc_descriptor (rtx rtl, enum machine_mode mode,
   rtx msb;
 
   if (GET_MODE_CLASS (mode) != MODE_INT
-      || GET_MODE (XEXP (rtl, 0)) != mode
-      || (GET_CODE (rtl) == CLZ
-         && GET_MODE_BITSIZE (mode) > HOST_BITS_PER_DOUBLE_INT))
+      || GET_MODE (XEXP (rtl, 0)) != mode)
     return NULL;
 
   op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
@@ -11845,9 +11977,9 @@ clz_loc_descriptor (rtx rtl, enum machine_mode mode,
     msb = GEN_INT ((unsigned HOST_WIDE_INT) 1
                   << (GET_MODE_BITSIZE (mode) - 1));
   else
-    msb = immed_double_const (0, (unsigned HOST_WIDE_INT) 1
-                                 << (GET_MODE_BITSIZE (mode)
-                                     - HOST_BITS_PER_WIDE_INT - 1), mode);
+    msb = immed_wide_int_const
+      (wi::set_bit_in_zero (GET_MODE_PRECISION (mode) - 1,
+                           GET_MODE_PRECISION (mode)), mode);
   if (GET_CODE (msb) == CONST_INT && INTVAL (msb) < 0)
     tmp = new_loc_descr (HOST_BITS_PER_WIDE_INT == 32
                         ? DW_OP_const4u : HOST_BITS_PER_WIDE_INT == 64
@@ -12773,10 +12905,15 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
        {
          dw_die_ref type_die;
 
-         /* Note that a CONST_DOUBLE rtx could represent either an integer
-            or a floating-point constant.  A CONST_DOUBLE is used whenever
-            the constant requires more than one word in order to be
-            adequately represented.  We output CONST_DOUBLEs as blocks.  */
+         /* Note that if TARGET_SUPPORTS_WIDE_INT == 0, a
+            CONST_DOUBLE rtx could represent either an large integer
+            or a floating-point constant.  If
+            TARGET_SUPPORTS_WIDE_INT != 0, the value is always a
+            floating point constant.
+
+            When it is an integer, a CONST_DOUBLE is used whenever
+            the constant requires 2 HWIs to be adequately
+            represented.  We output CONST_DOUBLEs as blocks.  */
          if (mode == VOIDmode
              || (GET_MODE (rtl) == VOIDmode
                  && GET_MODE_BITSIZE (mode) != HOST_BITS_PER_DOUBLE_INT))
@@ -12789,7 +12926,16 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
          mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
          mem_loc_result->dw_loc_oprnd1.v.val_die_ref.die = type_die;
          mem_loc_result->dw_loc_oprnd1.v.val_die_ref.external = 0;
-         if (SCALAR_FLOAT_MODE_P (mode))
+#if TARGET_SUPPORTS_WIDE_INT == 0
+         if (!SCALAR_FLOAT_MODE_P (mode))
+           {
+             mem_loc_result->dw_loc_oprnd2.val_class
+               = dw_val_class_const_double;
+             mem_loc_result->dw_loc_oprnd2.v.val_double
+               = rtx_to_double_int (rtl);
+           }
+         else
+#endif
            {
              unsigned int length = GET_MODE_SIZE (mode);
              unsigned char *array
@@ -12801,13 +12947,26 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
              mem_loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
              mem_loc_result->dw_loc_oprnd2.v.val_vec.array = array;
            }
-         else
-           {
-             mem_loc_result->dw_loc_oprnd2.val_class
-               = dw_val_class_const_double;
-             mem_loc_result->dw_loc_oprnd2.v.val_double
-               = rtx_to_double_int (rtl);
-           }
+       }
+      break;
+
+    case CONST_WIDE_INT:
+      if (!dwarf_strict)
+       {
+         dw_die_ref type_die;
+
+         type_die = base_type_for_mode (mode,
+                                        GET_MODE_CLASS (mode) == MODE_INT);
+         if (type_die == NULL)
+           return NULL;
+         mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0, 0);
+         mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+         mem_loc_result->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+         mem_loc_result->dw_loc_oprnd1.v.val_die_ref.external = 0;
+         mem_loc_result->dw_loc_oprnd2.val_class
+           = dw_val_class_wide_int;
+         mem_loc_result->dw_loc_oprnd2.v.val_wide = ggc_alloc_cleared_wide_int ();
+         *mem_loc_result->dw_loc_oprnd2.v.val_wide = std::make_pair (rtl, mode);
        }
       break;
 
@@ -13278,7 +13437,15 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
             adequately represented.  We output CONST_DOUBLEs as blocks.  */
          loc_result = new_loc_descr (DW_OP_implicit_value,
                                      GET_MODE_SIZE (mode), 0);
-         if (SCALAR_FLOAT_MODE_P (mode))
+#if TARGET_SUPPORTS_WIDE_INT == 0
+         if (!SCALAR_FLOAT_MODE_P (mode))
+           {
+             loc_result->dw_loc_oprnd2.val_class = dw_val_class_const_double;
+             loc_result->dw_loc_oprnd2.v.val_double
+               = rtx_to_double_int (rtl);
+           }
+         else
+#endif
            {
              unsigned int length = GET_MODE_SIZE (mode);
              unsigned char *array
@@ -13290,12 +13457,20 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
              loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
              loc_result->dw_loc_oprnd2.v.val_vec.array = array;
            }
-         else
-           {
-             loc_result->dw_loc_oprnd2.val_class = dw_val_class_const_double;
-             loc_result->dw_loc_oprnd2.v.val_double
-               = rtx_to_double_int (rtl);
-           }
+       }
+      break;
+
+    case CONST_WIDE_INT:
+      if (mode == VOIDmode)
+       mode = GET_MODE (rtl);
+
+      if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
+       {
+         loc_result = new_loc_descr (DW_OP_implicit_value,
+                                     GET_MODE_SIZE (mode), 0);
+         loc_result->dw_loc_oprnd2.val_class = dw_val_class_wide_int;
+         loc_result->dw_loc_oprnd2.v.val_wide = ggc_alloc_cleared_wide_int ();
+         *loc_result->dw_loc_oprnd2.v.val_wide = std::make_pair (rtl, mode);
        }
       break;
 
@@ -13311,6 +13486,7 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
            ggc_alloc_atomic (length * elt_size);
          unsigned int i;
          unsigned char *p;
+         enum machine_mode imode = GET_MODE_INNER (mode);
 
          gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
          switch (GET_MODE_CLASS (mode))
@@ -13319,15 +13495,7 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
              for (i = 0, p = array; i < length; i++, p += elt_size)
                {
                  rtx elt = CONST_VECTOR_ELT (rtl, i);
-                 double_int val = rtx_to_double_int (elt);
-
-                 if (elt_size <= sizeof (HOST_WIDE_INT))
-                   insert_int (val.to_shwi (), elt_size, p);
-                 else
-                   {
-                     gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
-                     insert_double (val, p);
-                   }
+                 insert_wide_int (std::make_pair (elt, imode), p, elt_size);
                }
              break;
 
@@ -14649,15 +14817,10 @@ simple_decl_align_in_bits (const_tree decl)
 
 /* Return the result of rounding T up to ALIGN.  */
 
-static inline double_int
-round_up_to_align (double_int t, unsigned int align)
+static inline offset_int
+round_up_to_align (const offset_int &t, unsigned int align)
 {
-  double_int alignd = double_int::from_uhwi (align);
-  t += alignd;
-  t += double_int_minus_one;
-  t = t.div (alignd, true, TRUNC_DIV_EXPR);
-  t *= alignd;
-  return t;
+  return wi::udiv_trunc (t + align - 1, align) * align;
 }
 
 /* Given a pointer to a FIELD_DECL, compute and return the byte offset of the
@@ -14670,9 +14833,9 @@ round_up_to_align (double_int t, unsigned int align)
 static HOST_WIDE_INT
 field_byte_offset (const_tree decl)
 {
-  double_int object_offset_in_bits;
-  double_int object_offset_in_bytes;
-  double_int bitpos_int;
+  offset_int object_offset_in_bits;
+  offset_int object_offset_in_bytes;
+  offset_int bitpos_int;
 
   if (TREE_CODE (decl) == ERROR_MARK)
     return 0;
@@ -14685,21 +14848,21 @@ field_byte_offset (const_tree decl)
   if (TREE_CODE (bit_position (decl)) != INTEGER_CST)
     return 0;
 
-  bitpos_int = tree_to_double_int (bit_position (decl));
+  bitpos_int = wi::to_offset (bit_position (decl));
 
 #ifdef PCC_BITFIELD_TYPE_MATTERS
   if (PCC_BITFIELD_TYPE_MATTERS)
     {
       tree type;
       tree field_size_tree;
-      double_int deepest_bitpos;
-      double_int field_size_in_bits;
+      offset_int deepest_bitpos;
+      offset_int field_size_in_bits;
       unsigned int type_align_in_bits;
       unsigned int decl_align_in_bits;
-      double_int type_size_in_bits;
+      offset_int type_size_in_bits;
 
       type = field_type (decl);
-      type_size_in_bits = double_int_type_size_in_bits (type);
+      type_size_in_bits = offset_int_type_size_in_bits (type);
       type_align_in_bits = simple_type_align_in_bits (type);
 
       field_size_tree = DECL_SIZE (decl);
@@ -14711,7 +14874,7 @@ field_byte_offset (const_tree decl)
 
       /* If the size of the field is not constant, use the type size.  */
       if (TREE_CODE (field_size_tree) == INTEGER_CST)
-       field_size_in_bits = tree_to_double_int (field_size_tree);
+       field_size_in_bits = wi::to_offset (field_size_tree);
       else
        field_size_in_bits = type_size_in_bits;
 
@@ -14775,7 +14938,7 @@ field_byte_offset (const_tree decl)
       object_offset_in_bits
        = round_up_to_align (object_offset_in_bits, type_align_in_bits);
 
-      if (object_offset_in_bits.ugt (bitpos_int))
+      if (wi::gtu_p (object_offset_in_bits, bitpos_int))
        {
          object_offset_in_bits = deepest_bitpos - type_size_in_bits;
 
@@ -14789,8 +14952,7 @@ field_byte_offset (const_tree decl)
     object_offset_in_bits = bitpos_int;
 
   object_offset_in_bytes
-    = object_offset_in_bits.div (double_int::from_uhwi (BITS_PER_UNIT),
-                                true, TRUNC_DIV_EXPR);
+    = wi::lrshift (object_offset_in_bits, LOG2_BITS_PER_UNIT);
   return object_offset_in_bytes.to_shwi ();
 }
 \f
@@ -14966,22 +15128,36 @@ extract_int (const unsigned char *src, unsigned int size)
   return val;
 }
 
-/* Writes double_int values to dw_vec_const array.  */
+/* Writes wide_int values to dw_vec_const array.  */
 
 static void
-insert_double (double_int val, unsigned char *dest)
+insert_wide_int (const wide_int &val, unsigned char *dest, int elt_size)
 {
-  unsigned char *p0 = dest;
-  unsigned char *p1 = dest + sizeof (HOST_WIDE_INT);
+  int i;
 
-  if (WORDS_BIG_ENDIAN)
+  if (elt_size <= HOST_BITS_PER_WIDE_INT/BITS_PER_UNIT)
     {
-      p0 = p1;
-      p1 = dest;
+      insert_int ((HOST_WIDE_INT) val.elt (0), elt_size, dest);
+      return;
     }
 
-  insert_int ((HOST_WIDE_INT) val.low, sizeof (HOST_WIDE_INT), p0);
-  insert_int ((HOST_WIDE_INT) val.high, sizeof (HOST_WIDE_INT), p1);
+  /* We'd have to extend this code to support odd sizes.  */
+  gcc_assert (elt_size % (HOST_BITS_PER_WIDE_INT/BITS_PER_UNIT) == 0);
+
+  int n = elt_size / (HOST_BITS_PER_WIDE_INT/BITS_PER_UNIT);
+
+  if (WORDS_BIG_ENDIAN)
+    for (i = n - 1; i >= 0; i--)
+      {
+       insert_int ((HOST_WIDE_INT) val.elt (i), sizeof (HOST_WIDE_INT), dest);
+       dest += sizeof (HOST_WIDE_INT);
+      }
+  else
+    for (i = 0; i < n; i++)
+      {
+       insert_int ((HOST_WIDE_INT) val.elt (i), sizeof (HOST_WIDE_INT), dest);
+       dest += sizeof (HOST_WIDE_INT);
+      }
 }
 
 /* Writes floating point values to dw_vec_const array.  */
@@ -15026,6 +15202,11 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
       }
       return true;
 
+    case CONST_WIDE_INT:
+      add_AT_wide (die, DW_AT_const_value,
+                  std::make_pair (rtl, GET_MODE (rtl)));
+      return true;
+
     case CONST_DOUBLE:
       /* Note that a CONST_DOUBLE rtx could represent either an integer or a
         floating-point constant.  A CONST_DOUBLE is used whenever the
@@ -15034,7 +15215,10 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
       {
        enum machine_mode mode = GET_MODE (rtl);
 
-       if (SCALAR_FLOAT_MODE_P (mode))
+       if (TARGET_SUPPORTS_WIDE_INT == 0 && !SCALAR_FLOAT_MODE_P (mode))
+         add_AT_double (die, DW_AT_const_value,
+                        CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
+       else
          {
            unsigned int length = GET_MODE_SIZE (mode);
            unsigned char *array = (unsigned char *) ggc_alloc_atomic (length);
@@ -15042,9 +15226,6 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
            insert_float (rtl, array);
            add_AT_vec (die, DW_AT_const_value, length / 4, 4, array);
          }
-       else
-         add_AT_double (die, DW_AT_const_value,
-                        CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
       }
       return true;
 
@@ -15057,6 +15238,7 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
          (length * elt_size);
        unsigned int i;
        unsigned char *p;
+       enum machine_mode imode = GET_MODE_INNER (mode);
 
        switch (GET_MODE_CLASS (mode))
          {
@@ -15064,15 +15246,7 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
            for (i = 0, p = array; i < length; i++, p += elt_size)
              {
                rtx elt = CONST_VECTOR_ELT (rtl, i);
-               double_int val = rtx_to_double_int (elt);
-
-               if (elt_size <= sizeof (HOST_WIDE_INT))
-                 insert_int (val.to_shwi (), elt_size, p);
-               else
-                 {
-                   gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
-                   insert_double (val, p);
-                 }
+               insert_wide_int (std::make_pair (elt, imode), p, elt_size);
              }
            break;
 
@@ -16208,13 +16382,11 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
            add_AT_unsigned (subrange_die, bound_attr,
                             TREE_INT_CST_LOW (bound) & mask);
          }
-       else if (prec == HOST_BITS_PER_WIDE_INT
-                || TREE_INT_CST_HIGH (bound) == 0)
+       else if (prec == HOST_BITS_PER_WIDE_INT || tree_fits_uhwi_p (bound))
          add_AT_unsigned (subrange_die, bound_attr,
                           TREE_INT_CST_LOW (bound));
        else
-         add_AT_double (subrange_die, bound_attr, TREE_INT_CST_HIGH (bound),
-                        TREE_INT_CST_LOW (bound));
+         add_AT_wide (subrange_die, bound_attr, bound);
       }
       break;
 
@@ -17372,8 +17544,7 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die)
          else
            /* Enumeration constants may be wider than HOST_WIDE_INT.  Handle
               that here.  */
-           add_AT_double (enum_die, DW_AT_const_value,
-                          TREE_INT_CST_HIGH (value), TREE_INT_CST_LOW (value));
+           add_AT_wide (enum_die, DW_AT_const_value, value);
        }
 
       add_gnat_descriptive_type_attribute (type_die, type, context_die);
@@ -23514,6 +23685,9 @@ hash_loc_operands (dw_loc_descr_ref loc, hashval_t hash)
          hash = iterative_hash_object (val2->v.val_double.low, hash);
          hash = iterative_hash_object (val2->v.val_double.high, hash);
          break;
+       case dw_val_class_wide_int:
+         hash = iterative_hash_object (*val2->v.val_wide, hash);
+         break;
        case dw_val_class_addr:
          hash = iterative_hash_rtx (val2->v.val_addr, hash);
          break;
@@ -23603,6 +23777,9 @@ hash_loc_operands (dw_loc_descr_ref loc, hashval_t hash)
            hash = iterative_hash_object (val2->v.val_double.low, hash);
            hash = iterative_hash_object (val2->v.val_double.high, hash);
            break;
+         case dw_val_class_wide_int:
+           hash = iterative_hash_object (*val2->v.val_wide, hash);
+           break;
          default:
            gcc_unreachable ();
          }
@@ -23751,6 +23928,8 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y)
        case dw_val_class_const_double:
          return valx2->v.val_double.low == valy2->v.val_double.low
                 && valx2->v.val_double.high == valy2->v.val_double.high;
+       case dw_val_class_wide_int:
+         return *valx2->v.val_wide == *valy2->v.val_wide;
        case dw_val_class_addr:
          return rtx_equal_p (valx2->v.val_addr, valy2->v.val_addr);
        default:
@@ -23794,6 +23973,8 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y)
        case dw_val_class_const_double:
          return valx2->v.val_double.low == valy2->v.val_double.low
                 && valx2->v.val_double.high == valy2->v.val_double.high;
+       case dw_val_class_wide_int:
+         return *valx2->v.val_wide == *valy2->v.val_wide;
        default:
          gcc_unreachable ();
        }