diff mbox

wide-int, C++ front end

Message ID E2C6331E-1CDC-48FC-ADB5-42623433F232@comcast.net
State New
Headers show

Commit Message

Mike Stump Nov. 23, 2013, 7:20 p.m. UTC
Richi has asked the we break the wide-int patch so that the individual port and front end maintainers can review their parts without have to go through the entire patch.    This patch covers the C++ front end.

Ok?
cp:
	* call.c: Include wide-int.h.
	(type_passed_as): Use INT_CST_LT instead of INT_CST_LT_UNSIGNED.
	(convert_for_arg_passing): Likewise.
	* class.c: Include wide-int.h.
	(end_of_class): Use INT_CST_LT instead of INT_CST_LT_UNSIGNED.
	(include_empty_classes): Likewise
	* cvt.c: Include wide-int.h.
	(ignore_overflows): Use wide_int_to_tree.
	* decl.c: Include wide-int.h.
	(check_array_designated_initializer): Use wide-int interfaces.
	(finish_enum_value_list): Use signop.
	(build_enumerator): Use wide-int interfaces.
	* init.c: Include wide-int.h.
	(build_new_1): Use wide-int interfaces.
	* mangle.c: Include wide-int.h.
	(write_integer_cst): Use wide-int interfaces.
	(write_array_type): Likewise.
	* tree.c: Include wide-int.h.
	(cp_tree_equal): Use wide-int interfaces.
	* typeck2.c: Include wide-int.h.
	(process_init_constructor_array): Use wide-int interfaces.

Comments

Jason Merrill Nov. 24, 2013, 2 a.m. UTC | #1
On 11/23/2013 02:20 PM, Mike Stump wrote:
> @@ -2605,8 +2606,7 @@ cp_tree_equal (tree t1, tree t2)
>     switch (code1)
>       {
>       case INTEGER_CST:
> -      return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
> -	&& TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
> +      return wi::to_widest (t1) == wi::to_widest (t2);

Why not use wi::eq_p like you do in the C front end?

Jason
Richard Sandiford Nov. 25, 2013, 8:05 p.m. UTC | #2
Jason Merrill <jason@redhat.com> writes:
> On 11/23/2013 02:20 PM, Mike Stump wrote:
>> @@ -2605,8 +2606,7 @@ cp_tree_equal (tree t1, tree t2)
>>     switch (code1)
>>       {
>>       case INTEGER_CST:
>> -      return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
>> -	&& TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
>> +      return wi::to_widest (t1) == wi::to_widest (t2);
>
> Why not use wi::eq_p like you do in the C front end?

Thanks for noticing the difference.  I think c_tree_equal should change
to use to_widest too.

wi::eq_p (t1, t2) asserts that t1 and t2 are the same precision and
ignores signedness; it just tests whether they are the same bitstring.
wi::to_widest (t1) == wi::to_widest (t2) compares them as logical numbers,
taking sign into account and allowing different types.  I think that's
what the original TREE_INT_CST_LOW and TREE_INT_CST_HIGH tests did too.

Richard
Jason Merrill Nov. 25, 2013, 9:06 p.m. UTC | #3
On 11/25/2013 03:05 PM, Richard Sandiford wrote:
> wi::eq_p (t1, t2) asserts that t1 and t2 are the same precision and
> ignores signedness; it just tests whether they are the same bitstring.
> wi::to_widest (t1) == wi::to_widest (t2) compares them as logical numbers,
> taking sign into account and allowing different types.  I think that's
> what the original TREE_INT_CST_LOW and TREE_INT_CST_HIGH tests did too.

That seems reasonable, though I don't think allowing different types is 
actually a goal.  In most cases the type is required to be the same by 
the context.

Jason
Richard Biener Nov. 26, 2013, 9:34 a.m. UTC | #4
On Mon, Nov 25, 2013 at 9:05 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Jason Merrill <jason@redhat.com> writes:
>> On 11/23/2013 02:20 PM, Mike Stump wrote:
>>> @@ -2605,8 +2606,7 @@ cp_tree_equal (tree t1, tree t2)
>>>     switch (code1)
>>>       {
>>>       case INTEGER_CST:
>>> -      return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
>>> -    && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
>>> +      return wi::to_widest (t1) == wi::to_widest (t2);
>>
>> Why not use wi::eq_p like you do in the C front end?
>
> Thanks for noticing the difference.  I think c_tree_equal should change
> to use to_widest too.
>
> wi::eq_p (t1, t2) asserts that t1 and t2 are the same precision and
> ignores signedness; it just tests whether they are the same bitstring.
> wi::to_widest (t1) == wi::to_widest (t2) compares them as logical numbers,
> taking sign into account and allowing different types.  I think that's
> what the original TREE_INT_CST_LOW and TREE_INT_CST_HIGH tests did too.

Though in this case (comparing two INTEGER_CSTs) it would be better
to use a tree abstraction - thus tree_int_cst_equal.  It saves us from
making the decision on what to map this in wide-int to multiple times.

Note that tree_int_cst_equal tests for "same constant value" - in tree
terms this includes sign information and thus requires to_widest.

Richard.

> Richard
diff mbox

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index c529c16..00ebed4 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -41,6 +41,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-objc.h"
 #include "timevar.h"
 #include "cgraph.h"
+#include "wide-int.h"
 
 /* The various kinds of conversion.  */
 
@@ -6495,8 +6496,7 @@  type_passed_as (tree type)
   else if (targetm.calls.promote_prototypes (type)
 	   && INTEGRAL_TYPE_P (type)
 	   && COMPLETE_TYPE_P (type)
-	   && INT_CST_LT_UNSIGNED (TYPE_SIZE (type),
-				   TYPE_SIZE (integer_type_node)))
+	   && INT_CST_LT (TYPE_SIZE (type), TYPE_SIZE (integer_type_node)))
     type = integer_type_node;
 
   return type;
@@ -6536,8 +6536,7 @@  convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
   else if (targetm.calls.promote_prototypes (type)
 	   && INTEGRAL_TYPE_P (type)
 	   && COMPLETE_TYPE_P (type)
-	   && INT_CST_LT_UNSIGNED (TYPE_SIZE (type),
-				   TYPE_SIZE (integer_type_node)))
+	   && INT_CST_LT (TYPE_SIZE (type), TYPE_SIZE (integer_type_node)))
     val = cp_perform_integral_promotions (val, complain);
   if ((complain & tf_warning)
       && warn_suggest_attribute_format)
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 00fec27..027d235 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -42,6 +42,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "hash-table.h"
 #include "gimple.h"
 #include "gimplify.h"
+#include "wide-int.h"
 
 /* The number of nested classes being processed.  If we are not in the
    scope of any class, this is zero.  */
@@ -5831,7 +5832,7 @@  end_of_class (tree t, int include_virtuals_p)
 	continue;
 
       offset = end_of_base (base_binfo);
-      if (INT_CST_LT_UNSIGNED (result, offset))
+      if (INT_CST_LT (result, offset))
 	result = offset;
     }
 
@@ -5841,7 +5842,7 @@  end_of_class (tree t, int include_virtuals_p)
 	 vec_safe_iterate (vbases, i, &base_binfo); i++)
       {
 	offset = end_of_base (base_binfo);
-	if (INT_CST_LT_UNSIGNED (result, offset))
+	if (INT_CST_LT (result, offset))
 	  result = offset;
       }
 
@@ -5921,7 +5922,7 @@  include_empty_classes (record_layout_info rli)
 		      CLASSTYPE_AS_BASE (rli->t) != NULL_TREE);
   rli_size = rli_size_unit_so_far (rli);
   if (TREE_CODE (rli_size) == INTEGER_CST
-      && INT_CST_LT_UNSIGNED (rli_size, eoc))
+      && INT_CST_LT (rli_size, eoc))
     {
       if (!abi_version_at_least (2))
 	/* In version 1 of the ABI, the size of a class that ends with
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 5264c5d..6d0e341 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -36,6 +36,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "convert.h"
 #include "decl.h"
 #include "target.h"
+#include "wide-int.h"
 
 static tree cp_convert_to_pointer (tree, tree, tsubst_flags_t);
 static tree convert_to_pointer_force (tree, tree, tsubst_flags_t);
@@ -582,9 +583,7 @@  ignore_overflows (tree expr, tree orig)
     {
       gcc_assert (!TREE_OVERFLOW (orig));
       /* Ensure constant sharing.  */
-      expr = build_int_cst_wide (TREE_TYPE (expr),
-				 TREE_INT_CST_LOW (expr),
-				 TREE_INT_CST_HIGH (expr));
+      expr = wide_int_to_tree (TREE_TYPE (expr), expr);
     }
   return expr;
 }
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 500c81f..babfc88 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -59,6 +59,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "splay-tree.h"
 #include "plugin.h"
 #include "cgraph.h"
+#include "wide-int.h"
 
 /* Possible cases of bad specifiers type used by bad_specifiers. */
 enum bad_spec_place {
@@ -4811,7 +4812,7 @@  check_array_designated_initializer (constructor_elt *ce,
       if (TREE_CODE (ce->index) == INTEGER_CST)
 	{
 	  /* A C99 designator is OK if it matches the current index.  */
-	  if (TREE_INT_CST_LOW (ce->index) == index)
+	  if (wi::eq_p (ce->index, index))
 	    return true;
 	  else
 	    sorry ("non-trivial designated initializers not supported");
@@ -12661,9 +12662,9 @@  finish_enum_value_list (tree enumtype)
 	 enumeration.  We must do this before the type of MINNODE and
 	 MAXNODE are transformed, since tree_int_cst_min_precision relies
 	 on the TREE_TYPE of the value it is passed.  */
-      bool unsignedp = tree_int_cst_sgn (minnode) >= 0;
-      int lowprec = tree_int_cst_min_precision (minnode, unsignedp);
-      int highprec = tree_int_cst_min_precision (maxnode, unsignedp);
+      signop sgn = tree_int_cst_sgn (minnode) >= 0 ? UNSIGNED : SIGNED;
+      int lowprec = tree_int_cst_min_precision (minnode, sgn);
+      int highprec = tree_int_cst_min_precision (maxnode, sgn);
       int precision = MAX (lowprec, highprec);
       unsigned int itk;
       bool use_short_enum;
@@ -12695,7 +12696,7 @@  finish_enum_value_list (tree enumtype)
           underlying_type = integer_types[itk];
           if (underlying_type != NULL_TREE
 	      && TYPE_PRECISION (underlying_type) >= precision
-              && TYPE_UNSIGNED (underlying_type) == unsignedp)
+              && TYPE_SIGN (underlying_type) == sgn)
             break;
         }
       if (itk == itk_none)
@@ -12742,12 +12743,11 @@  finish_enum_value_list (tree enumtype)
 	= build_distinct_type_copy (underlying_type);
       TYPE_PRECISION (ENUM_UNDERLYING_TYPE (enumtype)) = precision;
       set_min_and_max_values_for_integral_type
-        (ENUM_UNDERLYING_TYPE (enumtype), precision, unsignedp);
+        (ENUM_UNDERLYING_TYPE (enumtype), precision, sgn);
 
       /* If -fstrict-enums, still constrain TYPE_MIN/MAX_VALUE.  */
       if (flag_strict_enums)
-	set_min_and_max_values_for_integral_type (enumtype, precision,
-						  unsignedp);
+	set_min_and_max_values_for_integral_type (enumtype, precision, sgn);
     }
   else
     underlying_type = ENUM_UNDERLYING_TYPE (enumtype);
@@ -12871,14 +12871,14 @@  build_enumerator (tree name, tree value, tree enumtype, location_t loc)
 		value = error_mark_node;
 	      else
 		{
-		  double_int di = TREE_INT_CST (prev_value)
-				  .add_with_sign (double_int_one,
-						  false, &overflowed);
+		  tree type = TREE_TYPE (prev_value);
+		  signop sgn = TYPE_SIGN (type);
+		  widest_int wi = wi::add (wi::to_widest (prev_value), 1, sgn,
+					   &overflowed);
 		  if (!overflowed)
 		    {
-		      tree type = TREE_TYPE (prev_value);
-		      bool pos = TYPE_UNSIGNED (type) || !di.is_negative ();
-		      if (!double_int_fits_to_tree_p (type, di))
+		      bool pos = !wi::neg_p (wi, sgn);
+		      if (!wi::fits_to_tree_p (wi, type))
 			{
 			  unsigned int itk;
 			  for (itk = itk_int; itk != itk_none; itk++)
@@ -12886,7 +12886,7 @@  build_enumerator (tree name, tree value, tree enumtype, location_t loc)
 			      type = integer_types[itk];
 			      if (type != NULL_TREE
 				  && (pos || !TYPE_UNSIGNED (type))
-				  && double_int_fits_to_tree_p (type, di))
+				  && wi::fits_to_tree_p (wi, type))
 				break;
 			    }
 			  if (type && cxx_dialect < cxx11
@@ -12898,7 +12898,7 @@  incremented enumerator value is too large for %<long%>");
 		      if (type == NULL_TREE)
 			overflowed = true;
 		      else
-			value = double_int_to_tree (type, di);
+			value = wide_int_to_tree (type, wi);
 		    }
 
 		  if (overflowed)
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index fd43a4f..7b6f4e2 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -32,6 +32,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "gimple.h"
 #include "gimplify.h"
+#include "wide-int.h"
 
 static bool begin_init_stmts (tree *, tree *);
 static tree finish_init_stmts (bool, tree, tree);
@@ -2246,10 +2247,10 @@  build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
   /* For arrays, a bounds checks on the NELTS parameter. */
   tree outer_nelts_check = NULL_TREE;
   bool outer_nelts_from_type = false;
-  double_int inner_nelts_count = double_int_one;
+  offset_int inner_nelts_count = 1;
   tree alloc_call, alloc_expr;
   /* Size of the inner array elements. */
-  double_int inner_size;
+  offset_int inner_size;
   /* The address returned by the call to "operator new".  This node is
      a VAR_DECL and is therefore reusable.  */
   tree alloc_node;
@@ -2304,9 +2305,8 @@  build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
       if (TREE_CODE (inner_nelts_cst) == INTEGER_CST)
 	{
 	  bool overflow;
-	  double_int result = TREE_INT_CST (inner_nelts_cst)
-			      .mul_with_sign (inner_nelts_count,
-					      false, &overflow);
+	  offset_int result = wi::mul (wi::to_offset (inner_nelts_cst),
+				       inner_nelts_count, SIGNED, &overflow);
 	  if (overflow)
 	    {
 	      if (complain & tf_error)
@@ -2408,42 +2408,40 @@  build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
     {
       /* Maximum available size in bytes.  Half of the address space
 	 minus the cookie size.  */
-      double_int max_size
-	= double_int_one.llshift (TYPE_PRECISION (sizetype) - 1,
-				  HOST_BITS_PER_DOUBLE_INT);
+      offset_int max_size
+	= wi::set_bit_in_zero <offset_int> (TYPE_PRECISION (sizetype) - 1);
       /* Maximum number of outer elements which can be allocated. */
-      double_int max_outer_nelts;
+      offset_int max_outer_nelts;
       tree max_outer_nelts_tree;
 
       gcc_assert (TREE_CODE (size) == INTEGER_CST);
       cookie_size = targetm.cxx.get_cookie_size (elt_type);
       gcc_assert (TREE_CODE (cookie_size) == INTEGER_CST);
-      gcc_checking_assert (TREE_INT_CST (cookie_size).ult (max_size));
+      gcc_checking_assert (wi::ltu_p (wi::to_offset (cookie_size), max_size));
       /* Unconditionally subtract the cookie size.  This decreases the
 	 maximum object size and is safe even if we choose not to use
 	 a cookie after all.  */
-      max_size -= TREE_INT_CST (cookie_size);
+      max_size -= wi::to_offset (cookie_size);
       bool overflow;
-      inner_size = TREE_INT_CST (size)
-		   .mul_with_sign (inner_nelts_count, false, &overflow);
-      if (overflow || inner_size.ugt (max_size))
+      inner_size = wi::mul (wi::to_offset (size), inner_nelts_count, SIGNED,
+			    &overflow);
+      if (overflow || wi::gtu_p (inner_size, max_size))
 	{
 	  if (complain & tf_error)
 	    error ("size of array is too large");
 	  return error_mark_node;
 	}
-      max_outer_nelts = max_size.udiv (inner_size, TRUNC_DIV_EXPR);
+
+      max_outer_nelts = wi::udiv_trunc (max_size, inner_size);
       /* Only keep the top-most seven bits, to simplify encoding the
 	 constant in the instruction stream.  */
       {
-	unsigned shift = HOST_BITS_PER_DOUBLE_INT - 7
-	  - (max_outer_nelts.high ? clz_hwi (max_outer_nelts.high)
-	     : (HOST_BITS_PER_WIDE_INT + clz_hwi (max_outer_nelts.low)));
-	max_outer_nelts
-	  = max_outer_nelts.lrshift (shift, HOST_BITS_PER_DOUBLE_INT)
-	    .llshift (shift, HOST_BITS_PER_DOUBLE_INT);
+	unsigned shift = (max_outer_nelts.get_precision ()) - 7
+	  - wi::clz (max_outer_nelts);
+	max_outer_nelts = wi::lshift (wi::lrshift (max_outer_nelts, shift),
+				      shift);
       }
-      max_outer_nelts_tree = double_int_to_tree (sizetype, max_outer_nelts);
+      max_outer_nelts_tree = wide_int_to_tree (sizetype, max_outer_nelts);
 
       size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
       outer_nelts_check = fold_build2 (LE_EXPR, boolean_type_node,
@@ -2524,7 +2522,7 @@  build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
 	      cookie_size = NULL_TREE;
 	      /* No size arithmetic necessary, so the size check is
 		 not needed. */
-	      if (outer_nelts_check != NULL && inner_size.is_one ())
+	      if (outer_nelts_check != NULL && inner_size == 1)
 		outer_nelts_check = NULL_TREE;
 	    }
 	  /* Perform the overflow check.  */
@@ -2569,7 +2567,7 @@  build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
 	      cookie_size = NULL_TREE;
 	      /* No size arithmetic necessary, so the size check is
 		 not needed. */
-	      if (outer_nelts_check != NULL && inner_size.is_one ())
+	      if (outer_nelts_check != NULL && inner_size == 1)
 		outer_nelts_check = NULL_TREE;
 	    }
 
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 8a24d6c..31f78c7 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -57,6 +57,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "target.h"
 #include "cgraph.h"
+#include "wide-int.h"
 
 /* Debugging support.  */
 
@@ -1504,8 +1505,8 @@  static inline void
 write_integer_cst (const tree cst)
 {
   int sign = tree_int_cst_sgn (cst);
-
-  if (TREE_INT_CST_HIGH (cst) + (sign < 0))
+  widest_int abs_value = wi::abs (wi::to_widest (cst));
+  if (!wi::fits_uhwi_p (abs_value))
     {
       /* A bignum. We do this in chunks, each of which fits in a
 	 HOST_WIDE_INT.  */
@@ -1531,8 +1532,7 @@  write_integer_cst (const tree cst)
 
       type = c_common_signed_or_unsigned_type (1, TREE_TYPE (cst));
       base = build_int_cstu (type, chunk);
-      n = build_int_cst_wide (type,
-			      TREE_INT_CST_LOW (cst), TREE_INT_CST_HIGH (cst));
+      n = wide_int_to_tree (type, cst);
 
       if (sign < 0)
 	{
@@ -1559,14 +1559,9 @@  write_integer_cst (const tree cst)
   else
     {
       /* A small num.  */
-      unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (cst);
-
       if (sign < 0)
-	{
-	  write_char ('n');
-	  low = -low;
-	}
-      write_unsigned_number (low);
+	write_char ('n');
+      write_unsigned_number (abs_value.to_uhwi ());
     }
 }
 
@@ -3225,12 +3220,12 @@  write_array_type (const tree type)
 	{
 	  /* The ABI specifies that we should mangle the number of
 	     elements in the array, not the largest allowed index.  */
-	  double_int dmax = tree_to_double_int (max) + double_int_one;
+	  offset_int wmax = wi::to_offset (max) + 1;
 	  /* Truncate the result - this will mangle [0, SIZE_INT_MAX]
 	     number of elements as zero.  */
-	  dmax = dmax.zext (TYPE_PRECISION (TREE_TYPE (max)));
-	  gcc_assert (dmax.fits_uhwi ());
-	  write_unsigned_number (dmax.low);
+	  wmax = wi::zext (wmax, TYPE_PRECISION (TREE_TYPE (max)));
+	  gcc_assert (wi::fits_uhwi_p (wmax));
+	  write_unsigned_number (wmax.to_uhwi ());
 	}
       else
 	{
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index a990a79..2e3b586 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -36,6 +36,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "gimplify.h"
 #include "hash-table.h"
+#include "wide-int.h"
 
 static tree bot_manip (tree *, int *, void *);
 static tree bot_replace (tree *, int *, void *);
@@ -2605,8 +2606,7 @@  cp_tree_equal (tree t1, tree t2)
   switch (code1)
     {
     case INTEGER_CST:
-      return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
-	&& TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
+      return wi::to_widest (t1) == wi::to_widest (t2);
 
     case REAL_CST:
       return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 0f3b01d..5040226 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -36,6 +36,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "cp-tree.h"
 #include "flags.h"
 #include "diagnostic-core.h"
+#include "wide-int.h"
 
 static tree
 process_init_constructor (tree type, tree init, tsubst_flags_t complain);
@@ -1122,12 +1123,10 @@  process_init_constructor_array (tree type, tree init,
     {
       tree domain = TYPE_DOMAIN (type);
       if (domain && TREE_CONSTANT (TYPE_MAX_VALUE (domain)))
-	len = (tree_to_double_int (TYPE_MAX_VALUE (domain))
-	       - tree_to_double_int (TYPE_MIN_VALUE (domain))
-	       + double_int_one)
-	      .ext (TYPE_PRECISION (TREE_TYPE (domain)),
-		    TYPE_UNSIGNED (TREE_TYPE (domain)))
-	      .low;
+	len = wi::ext (wi::to_offset (TYPE_MAX_VALUE (domain))
+		       - wi::to_offset (TYPE_MIN_VALUE (domain)) + 1,
+		       TYPE_PRECISION (TREE_TYPE (domain)),
+		       TYPE_SIGN (TREE_TYPE (domain))).to_uhwi ();
       else
 	unbounded = true;  /* Take as many as there are.  */
     }